mirror of
https://github.com/rjNemo/rentease.git
synced 2026-06-06 02:36:49 +00:00
Refactor service (#14)
* add comments to main file * create health check handler health check * use naming convention for booking handler * use naming convention for hamndlers naming convention * clean up
This commit is contained in:
parent
e9fcb8dd49
commit
ac10e65097
9 changed files with 81 additions and 64 deletions
|
|
@ -6,6 +6,7 @@ type Service struct {
|
|||
secret string
|
||||
admin string
|
||||
adminSecret string
|
||||
apiKey string
|
||||
}
|
||||
|
||||
type ProviderIndex struct {
|
||||
|
|
@ -13,17 +14,22 @@ type ProviderIndex struct {
|
|||
Providers []string
|
||||
}
|
||||
|
||||
func NewService(secret, admin, adminSecret string) (*Service, error) {
|
||||
if secret == "" || admin == "" || adminSecret == "" {
|
||||
func NewService(secret, admin, adminSecret, apiKey string) (*Service, error) {
|
||||
if secret == "" || admin == "" || adminSecret == "" || apiKey == "" {
|
||||
return nil, errors.New("error building Auth service. Verify your env variables")
|
||||
}
|
||||
return &Service{
|
||||
secret,
|
||||
admin,
|
||||
adminSecret,
|
||||
apiKey,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (as *Service) Authenticate(email, password string) bool {
|
||||
return email == as.admin && password == as.adminSecret
|
||||
}
|
||||
|
||||
func (as *Service) ValidateApiKey(key string) bool {
|
||||
return key == as.apiKey
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,7 +52,6 @@ func NewService(ctx context.Context, credJson string, opts ...Option) (*Service,
|
|||
return &Service{Service: srv}, nil
|
||||
}
|
||||
|
||||
// TODO: implement create event, list events in a period, delete event
|
||||
func (s *Service) Create(from, to time.Time) (*calendar.Event, error) {
|
||||
l := s.CalendarList.List()
|
||||
r, e := l.Do()
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import (
|
|||
myTime "github.com/rjNemo/rentease/pkg/time"
|
||||
)
|
||||
|
||||
func handleListBookingPage(bs *booking.Service, hc *config.Host) echo.HandlerFunc {
|
||||
func handleBookingListPage(bs *booking.Service, hc *config.Host) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
bookings := bs.All()
|
||||
|
||||
|
|
@ -42,22 +42,22 @@ func handleListBookingPage(bs *booking.Service, hc *config.Host) echo.HandlerFun
|
|||
}
|
||||
}
|
||||
|
||||
func handleNewBookingPage(hc *config.Host) echo.HandlerFunc {
|
||||
func handleBookingCreatePage(hc *config.Host) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
return renderTempl(c, http.StatusOK, view.NewBooking(hc.Platforms))
|
||||
}
|
||||
}
|
||||
|
||||
func handleCreateBooking(bs *booking.Service) echo.HandlerFunc {
|
||||
func handleBookingCreate(bs *booking.Service) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
type NewBooking struct {
|
||||
From time.Time `json:"from"`
|
||||
To time.Time `json:"to"`
|
||||
ExternalId *string `form:"external_id"`
|
||||
Name string `form:"name"`
|
||||
PhoneNumber string `form:"phone_number"`
|
||||
Email string `form:"email"`
|
||||
Platform string `form:"platform"`
|
||||
ExternalId *string `form:"external_id"`
|
||||
CustomerNumber int `form:"customer_number"`
|
||||
PlatformFees float64 `form:"platform_fees"`
|
||||
}
|
||||
|
|
@ -77,6 +77,7 @@ func handleCreateBooking(bs *booking.Service) echo.HandlerFunc {
|
|||
nb.ExternalId = nil
|
||||
}
|
||||
b := bs.Create(nb.From, nb.To, nb.Name, nb.PhoneNumber, nb.Email, nb.Platform, nb.CustomerNumber, nb.PlatformFees, nb.ExternalId)
|
||||
// sync the calendar
|
||||
return c.Redirect(http.StatusSeeOther, fmt.Sprintf("%s/%d", constant.RouteBooking, b.Id))
|
||||
}
|
||||
}
|
||||
|
|
@ -135,7 +136,7 @@ func handleBookingPage(bs *booking.Service, hc *config.Host) echo.HandlerFunc {
|
|||
}
|
||||
}
|
||||
|
||||
func handleUpdateBooking(bs *booking.Service, hc *config.Host) echo.HandlerFunc {
|
||||
func handleBookingUpdate(bs *booking.Service, hc *config.Host) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
type UpdateBooking struct {
|
||||
From time.Time `json:"from"`
|
||||
|
|
@ -244,7 +245,7 @@ func handleCreateItem(bs *booking.Service) echo.HandlerFunc {
|
|||
}
|
||||
}
|
||||
|
||||
func handlePayItem(bs *booking.Service) echo.HandlerFunc {
|
||||
func handleItemPay(bs *booking.Service) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
itemIdStr := c.Param("id")
|
||||
itemId, err := strconv.Atoi(itemIdStr)
|
||||
|
|
@ -266,7 +267,7 @@ func handlePayItem(bs *booking.Service) echo.HandlerFunc {
|
|||
}
|
||||
}
|
||||
|
||||
func handleUpdateItem(bs *booking.Service) echo.HandlerFunc {
|
||||
func handleItemUpdate(bs *booking.Service) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
type updateItem struct {
|
||||
Item string `form:"item"`
|
||||
|
|
@ -298,7 +299,7 @@ func handleUpdateItem(bs *booking.Service) echo.HandlerFunc {
|
|||
}
|
||||
}
|
||||
|
||||
func handleCancelBooking(bs *booking.Service) echo.HandlerFunc {
|
||||
func handleBookingCancel(bs *booking.Service) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
idStr := c.Param("id")
|
||||
id, err := strconv.Atoi(idStr)
|
||||
|
|
|
|||
13
internal/server/handle_health.go
Normal file
13
internal/server/handle_health.go
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
)
|
||||
|
||||
func handleHealthCheck() echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
return c.String(http.StatusOK, "healthy")
|
||||
}
|
||||
}
|
||||
|
|
@ -13,7 +13,7 @@ import (
|
|||
"github.com/rjNemo/rentease/internal/pdf"
|
||||
)
|
||||
|
||||
func handleCreateInvoicePdf(bs *booking.Service, ps *pdf.PdfService, hc *config.Host) echo.HandlerFunc {
|
||||
func handlePdfCreateInvoice(bs *booking.Service, ps *pdf.PdfService, hc *config.Host) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
idStr := c.Param("id")
|
||||
id, err := strconv.Atoi(idStr)
|
||||
|
|
@ -31,7 +31,7 @@ func handleCreateInvoicePdf(bs *booking.Service, ps *pdf.PdfService, hc *config.
|
|||
}
|
||||
}
|
||||
|
||||
func handleCreateReportPdf(bs *booking.Service, ps *pdf.PdfService) echo.HandlerFunc {
|
||||
func handlePdfCreateReport(bs *booking.Service, ps *pdf.PdfService) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
period := c.QueryParam("period")
|
||||
if !u.Contains([]string{"month", "year"}, period) {
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ func handleReportsPage() echo.HandlerFunc {
|
|||
}
|
||||
}
|
||||
|
||||
func handleComputeReport(bs *booking.Service, hc *config.Host) echo.HandlerFunc {
|
||||
func handleReportCompute(bs *booking.Service, hc *config.Host) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
period := c.FormValue("period")
|
||||
if !u.Contains([]string{"month", "year"}, period) {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import (
|
|||
|
||||
func (s Server) MountHandlers() {
|
||||
// public
|
||||
s.Router.GET("/health", handleHealthCheck())
|
||||
s.Router.GET("/debug/pprof/*", echo.WrapHandler(http.DefaultServeMux))
|
||||
s.Router.GET("/", handleLoginPage())
|
||||
s.Router.POST("/", handleLogin(s.as))
|
||||
|
|
@ -18,25 +19,25 @@ func (s Server) MountHandlers() {
|
|||
api.Use(middleware.KeyAuthWithConfig(middleware.KeyAuthConfig{
|
||||
KeyLookup: "header:api-key",
|
||||
Validator: func(key string, c echo.Context) (bool, error) {
|
||||
return key == s.apiKey, nil
|
||||
return s.as.ValidateApiKey(key), nil
|
||||
},
|
||||
}))
|
||||
api.POST("/sync", handleSync(s.bs))
|
||||
// admin
|
||||
g := s.Router.Group("")
|
||||
g.Use(MakeAuthMiddleware())
|
||||
g.GET("/bookings", handleListBookingPage(s.bs, s.hc))
|
||||
g.GET("/bookings/new", handleNewBookingPage(s.hc))
|
||||
g.POST("/bookings/new", handleCreateBooking(s.bs))
|
||||
g.GET("/bookings", handleBookingListPage(s.bs, s.hc))
|
||||
g.GET("/bookings/new", handleBookingCreatePage(s.hc))
|
||||
g.POST("/bookings/new", handleBookingCreate(s.bs))
|
||||
g.GET("/bookings/:id", handleBookingPage(s.bs, s.hc))
|
||||
g.PUT("/bookings/:id", handleUpdateBooking(s.bs, s.hc))
|
||||
g.PATCH("/bookings/:id/cancel", handleCancelBooking(s.bs))
|
||||
g.PUT("/bookings/:id", handleBookingUpdate(s.bs, s.hc))
|
||||
g.PATCH("/bookings/:id/cancel", handleBookingCancel(s.bs))
|
||||
g.POST("/bookings/:id/items", handleCreateItem(s.bs))
|
||||
g.POST("/items/:id", handlePayItem(s.bs))
|
||||
g.PUT("/items/:id", handleUpdateItem(s.bs))
|
||||
g.POST("/items/:id", handleItemPay(s.bs))
|
||||
g.PUT("/items/:id", handleItemUpdate(s.bs))
|
||||
g.GET("/items/:id", handleLineItemForm(s.bs))
|
||||
g.GET("/bookings/pdf/:id", handleCreateInvoicePdf(s.bs, s.ps, s.hc))
|
||||
g.GET("/bookings/pdf/:id", handlePdfCreateInvoice(s.bs, s.ps, s.hc))
|
||||
g.GET("/reports", handleReportsPage())
|
||||
g.GET("/reports/do", handleComputeReport(s.bs, s.hc))
|
||||
g.GET("/reports/pdf", handleCreateReportPdf(s.bs, s.ps))
|
||||
g.GET("/reports/do", handleReportCompute(s.bs, s.hc))
|
||||
g.GET("/reports/pdf", handlePdfCreateReport(s.bs, s.ps))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,15 +25,13 @@ import (
|
|||
)
|
||||
|
||||
type Server struct {
|
||||
Router *echo.Echo
|
||||
bs *booking.Service
|
||||
as *auth.Service
|
||||
ps *pdf.PdfService
|
||||
cs *calendar.Service
|
||||
hc *config.Host
|
||||
addr string
|
||||
secretKey string
|
||||
apiKey string
|
||||
Router *echo.Echo
|
||||
bs *booking.Service
|
||||
as *auth.Service
|
||||
ps *pdf.PdfService
|
||||
cs *calendar.Service
|
||||
hc *config.Host
|
||||
addr string
|
||||
}
|
||||
|
||||
type options struct {
|
||||
|
|
@ -41,7 +39,6 @@ type options struct {
|
|||
fs *embed.FS
|
||||
debug *bool
|
||||
secretKey *string
|
||||
apiKey *string
|
||||
origins []string
|
||||
}
|
||||
|
||||
|
|
@ -85,13 +82,6 @@ func WithOrigins(origins []string) Option {
|
|||
}
|
||||
}
|
||||
|
||||
func WithApiKey(apiKey string) Option {
|
||||
return func(o *options) error {
|
||||
o.apiKey = &apiKey
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func New(bs *booking.Service, as *auth.Service, ps *pdf.PdfService, cs *calendar.Service, hc *config.Host, opts ...Option) (*Server, error) {
|
||||
option := new(options)
|
||||
for _, opt := range opts {
|
||||
|
|
@ -102,15 +92,13 @@ func New(bs *booking.Service, as *auth.Service, ps *pdf.PdfService, cs *calendar
|
|||
}
|
||||
|
||||
s := &Server{
|
||||
Router: NewRouter(*option.fs, *option.debug, *option.secretKey, option.origins),
|
||||
bs: bs,
|
||||
as: as,
|
||||
ps: ps,
|
||||
cs: cs,
|
||||
hc: hc,
|
||||
addr: fmt.Sprintf("0.0.0.0:%d", *option.port),
|
||||
secretKey: *option.secretKey,
|
||||
apiKey: *option.apiKey,
|
||||
Router: NewRouter(*option.fs, *option.debug, *option.secretKey, option.origins),
|
||||
bs: bs,
|
||||
as: as,
|
||||
ps: ps,
|
||||
cs: cs,
|
||||
hc: hc,
|
||||
addr: fmt.Sprintf("0.0.0.0:%d", *option.port),
|
||||
}
|
||||
|
||||
s.MountHandlers()
|
||||
|
|
|
|||
35
main.go
35
main.go
|
|
@ -40,25 +40,29 @@ func run(c context.Context, getEnv func(string) string) error {
|
|||
ctx, cancel := signal.NotifyContext(c, os.Interrupt)
|
||||
defer cancel()
|
||||
|
||||
// init sentry
|
||||
if err := sentry.Init(sentry.ClientOptions{
|
||||
Dsn: getEnv("SENTRY_DSN"),
|
||||
EnableTracing: true,
|
||||
TracesSampleRate: 1.0,
|
||||
ProfilesSampleRate: 1.0,
|
||||
}); err != nil {
|
||||
return fmt.Errorf("error initializing sentry: %s", err)
|
||||
return fmt.Errorf("error initializing sentry %s", err)
|
||||
}
|
||||
|
||||
// init database
|
||||
db, err := gorm.Open(postgres.Open(getEnv("DATABASE_URL")), &gorm.Config{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("error connecting to the database %s", err)
|
||||
}
|
||||
|
||||
// build booking service
|
||||
err = db.AutoMigrate(&booking.Booking{}, &booking.BookingRequest{}, &booking.Item{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("error migrating the database %s", err)
|
||||
}
|
||||
|
||||
// build pdf service
|
||||
ps, err := pdf.NewPdfService(
|
||||
getEnv("HTMLDOCS_PROJECT_ID"),
|
||||
getEnv("HTMLDOCS_REPORT_PROJECT_ID"),
|
||||
|
|
@ -69,23 +73,29 @@ func run(c context.Context, getEnv func(string) string) error {
|
|||
return fmt.Errorf("error starting pdf service %s", err)
|
||||
}
|
||||
|
||||
as, err := auth.NewService(getEnv("SESSION_SECRET"), getEnv("ADMIN"), getEnv("ADMIN_SECRET"))
|
||||
// build authentication service
|
||||
as, err := auth.NewService(
|
||||
getEnv("SESSION_SECRET"),
|
||||
getEnv("ADMIN"),
|
||||
getEnv("ADMIN_SECRET"),
|
||||
getEnv("API_KEY"),
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error starting auth service %s", err)
|
||||
}
|
||||
|
||||
creds := os.Getenv("CALENDAR_CREDENTIALS")
|
||||
t2Id := os.Getenv("CALENDAR_ID_T2")
|
||||
t3Id := os.Getenv("CALENDAR_ID_T3")
|
||||
|
||||
cs, err := calendar.NewService(ctx, creds,
|
||||
calendar.WithCalendar("T2", t2Id),
|
||||
calendar.WithCalendar("T3", t3Id),
|
||||
// build calendar service
|
||||
cs, err := calendar.NewService(
|
||||
ctx,
|
||||
getEnv("CALENDAR_CREDENTIALS"),
|
||||
calendar.WithCalendar("T2", getEnv("CALENDAR_ID_T2")),
|
||||
calendar.WithCalendar("T3", getEnv("CALENDAR_ID_T3")),
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatalf("cannot build calendar service: %s", err)
|
||||
log.Fatalf("error starting calendar service %s", err)
|
||||
}
|
||||
|
||||
// starting server
|
||||
p := getEnv("PORT")
|
||||
port, err := strconv.Atoi(p)
|
||||
if err != nil {
|
||||
|
|
@ -96,16 +106,15 @@ func run(c context.Context, getEnv func(string) string) error {
|
|||
origins := strings.Split(ogs, ",")
|
||||
|
||||
srv, err := server.New(
|
||||
booking.NewService(db),
|
||||
booking.NewService(db), // TODO: should validate the booking service building
|
||||
as,
|
||||
ps,
|
||||
cs,
|
||||
config.NewHost(),
|
||||
config.NewHost(), // TODO: move to the database at some point
|
||||
server.WithPort(port),
|
||||
server.WithFileSystem(static),
|
||||
server.WithDebug(strings.ToLower(getEnv("DEBUG")) == "true"),
|
||||
server.WithSecretKey(getEnv("SECRET_KEY")),
|
||||
server.WithApiKey(getEnv("API_KEY")),
|
||||
server.WithOrigins(origins),
|
||||
)
|
||||
if err != nil {
|
||||
|
|
|
|||
Loading…
Reference in a new issue