package server import ( "fmt" "net/http" "strings" "git.javil.eu/jacob1123/budgeteer" "git.javil.eu/jacob1123/budgeteer/bcrypt" "git.javil.eu/jacob1123/budgeteer/postgres" "github.com/labstack/echo/v4" "github.com/labstack/echo/v4/middleware" ) // Handler handles incoming requests. type Handler struct { Service *postgres.Database TokenVerifier budgeteer.TokenVerifier CredentialsVerifier *bcrypt.Verifier StaticFS http.FileSystem } // Serve starts the http server. func (h *Handler) Serve() { router := echo.New() h.LoadRoutes(router) if err := router.Start(":1323"); err != nil { panic(err) } } // LoadRoutes initializes all the routes. func (h *Handler) LoadRoutes(router *echo.Echo) { router.Use(middleware.Logger()) router.Use(enableCachingForStaticFiles()) router.Use(middleware.StaticWithConfig(middleware.StaticConfig{ Filesystem: h.StaticFS, HTML5: true, })) api := router.Group("/api/v1") anonymous := api.Group("/user") anonymous.POST("/login", h.loginPost) anonymous.POST("/register", h.registerPost) authenticated := api.Group("") { authenticated.Use(h.verifyLoginWithForbidden) account := authenticated.Group("/account") account.GET("/:accountid/transactions", h.transactionsForAccount) account.POST("/:accountid/reconcile", h.reconcileTransactions) account.POST("/:accountid", h.editAccount) category := authenticated.Group("/category") category.POST("/new", h.newCategory) categoryGroup := authenticated.Group("/category-group") categoryGroup.POST("/new", h.newCategoryGroup) budget := authenticated.Group("/budget") budget.POST("/new", h.newBudget) budget.GET("/:budgetid", h.budget) budget.GET("/:budgetid/:year/:month", h.budgetingForMonth) budget.POST("/:budgetid/category/:categoryid/:year/:month", h.setCategoryAssignment) budget.GET("/:budgetid/autocomplete/payees", h.autocompletePayee) budget.GET("/:budgetid/autocomplete/accounts", h.autocompleteAccounts) budget.GET("/:budgetid/autocomplete/categories", h.autocompleteCategories) budget.GET("/:budgetid/problematic-transactions", h.problematicTransactions) budget.POST("/:budgetid/filtered-transactions", h.filteredTransactions) budget.DELETE("/:budgetid", h.deleteBudget) budget.POST("/:budgetid/import/ynab", h.importYNAB) budget.POST("/:budgetid/export/ynab/transactions", h.exportYNABTransactions) budget.POST("/:budgetid/export/ynab/assignments", h.exportYNABAssignments) budget.POST("/:budgetid/settings/clear", h.clearBudget) transaction := authenticated.Group("/transaction") transaction.POST("/new", h.newTransaction) transaction.POST("/:transactionid", h.updateTransaction) authenticated.GET("/admin/clear-database", h.clearDatabase) } api.Any("/*", h.notFound) } func (h *Handler) notFound(c echo.Context) error { fmt.Println("not found?") return echo.NewHTTPError(http.StatusNotImplemented, "not found") } func enableCachingForStaticFiles() echo.MiddlewareFunc { return func(next echo.HandlerFunc) echo.HandlerFunc { return func(c echo.Context) error { if strings.HasPrefix(c.Path(), "/static/") { c.Response().Header().Set("Cache-Control", "max-age=86400") } return next(c) } } }