budgit/internal/routes/routes.go
2026-01-15 01:06:55 +00:00

149 lines
6.6 KiB
Go

package routes
import (
"io/fs"
"net/http"
"git.juancwu.dev/juancwu/budgit/assets"
"git.juancwu.dev/juancwu/budgit/internal/app"
"git.juancwu.dev/juancwu/budgit/internal/handler"
"git.juancwu.dev/juancwu/budgit/internal/middleware"
)
func SetupRoutes(a *app.App) http.Handler {
auth := handler.NewAuthHandler(a.AuthService, a.InviteService)
home := handler.NewHomeHandler()
dashboard := handler.NewDashboardHandler(a.SpaceService, a.ExpenseService)
space := handler.NewSpaceHandler(a.SpaceService, a.TagService, a.ShoppingListService, a.ExpenseService, a.InviteService, a.EventBus)
mux := http.NewServeMux()
// ====================================================================================
// PUBLIC ROUTES
// ====================================================================================
// Static
sub, _ := fs.Sub(assets.AssetsFS, ".")
mux.Handle("GET /assets/", http.StripPrefix("/assets/", http.FileServer(http.FS(sub))))
// Home
mux.HandleFunc("GET /{$}", home.HomePage)
mux.HandleFunc("GET /forbidden", home.ForbiddenPage)
// Auth pages
authRateLimiter := middleware.RateLimitAuth()
mux.HandleFunc("GET /auth", middleware.RequireGuest(auth.AuthPage))
mux.HandleFunc("GET /auth/password", middleware.RequireGuest(auth.PasswordPage))
// Token Verifications
mux.HandleFunc("GET /auth/magic-link/{token}", auth.VerifyMagicLink)
// Auth Actions
mux.HandleFunc("POST /auth/magic-link", authRateLimiter(middleware.RequireGuest(auth.SendMagicLink)))
mux.HandleFunc("POST /auth/logout", authRateLimiter(auth.Logout))
// ====================================================================================
// PRIVATE ROUTES
// ====================================================================================
mux.HandleFunc("GET /auth/onboarding", middleware.RequireAuth(auth.OnboardingPage))
mux.HandleFunc("POST /auth/onboarding", authRateLimiter(middleware.RequireAuth(auth.CompleteOnboarding)))
mux.HandleFunc("GET /app/dashboard", middleware.RequireAuth(dashboard.DashboardPage))
// Space routes
spaceDashboardHandler := middleware.RequireAuth(space.DashboardPage)
spaceDashboardWithAccess := middleware.RequireSpaceAccess(a.SpaceService)(spaceDashboardHandler)
mux.Handle("GET /app/spaces/{spaceID}", spaceDashboardWithAccess)
// SSE
streamHandler := middleware.RequireAuth(space.StreamEvents)
streamWithAccess := middleware.RequireSpaceAccess(a.SpaceService)(streamHandler)
mux.Handle("GET /app/spaces/{spaceID}/stream", streamWithAccess)
listsPageHandler := middleware.RequireAuth(space.ListsPage)
listsPageWithAccess := middleware.RequireSpaceAccess(a.SpaceService)(listsPageHandler)
mux.Handle("GET /app/spaces/{spaceID}/lists", listsPageWithAccess)
createListHandler := middleware.RequireAuth(space.CreateList)
createListWithAccess := middleware.RequireSpaceAccess(a.SpaceService)(createListHandler)
mux.Handle("POST /app/spaces/{spaceID}/lists", createListWithAccess)
listPageHandler := middleware.RequireAuth(space.ListPage)
listPageWithAccess := middleware.RequireSpaceAccess(a.SpaceService)(listPageHandler)
mux.Handle("GET /app/spaces/{spaceID}/lists/{listID}", listPageWithAccess)
addItemHandler := middleware.RequireAuth(space.AddItemToList)
addItemWithAccess := middleware.RequireSpaceAccess(a.SpaceService)(addItemHandler)
mux.Handle("POST /app/spaces/{spaceID}/lists/{listID}/items", addItemWithAccess)
toggleItemHandler := middleware.RequireAuth(space.ToggleItem)
toggleItemWithAccess := middleware.RequireSpaceAccess(a.SpaceService)(toggleItemHandler)
mux.Handle("PATCH /app/spaces/{spaceID}/lists/{listID}/items/{itemID}", toggleItemWithAccess)
deleteItemHandler := middleware.RequireAuth(space.DeleteItem)
deleteItemWithAccess := middleware.RequireSpaceAccess(a.SpaceService)(deleteItemHandler)
mux.Handle("DELETE /app/spaces/{spaceID}/lists/{listID}/items/{itemID}", deleteItemWithAccess)
// Tag routes
tagsPageHandler := middleware.RequireAuth(space.TagsPage)
tagsPageWithAccess := middleware.RequireSpaceAccess(a.SpaceService)(tagsPageHandler)
mux.Handle("GET /app/spaces/{spaceID}/tags", tagsPageWithAccess)
createTagHandler := middleware.RequireAuth(space.CreateTag)
createTagWithAccess := middleware.RequireSpaceAccess(a.SpaceService)(createTagHandler)
mux.Handle("POST /app/spaces/{spaceID}/tags", createTagWithAccess)
deleteTagHandler := middleware.RequireAuth(space.DeleteTag)
deleteTagWithAccess := middleware.RequireSpaceAccess(a.SpaceService)(deleteTagHandler)
mux.Handle("DELETE /app/spaces/{spaceID}/tags/{tagID}", deleteTagWithAccess)
// Expense routes
expensesPageHandler := middleware.RequireAuth(space.ExpensesPage)
expensesPageWithAccess := middleware.RequireSpaceAccess(a.SpaceService)(expensesPageHandler)
mux.Handle("GET /app/spaces/{spaceID}/expenses", expensesPageWithAccess)
createExpenseHandler := middleware.RequireAuth(space.CreateExpense)
createExpenseWithAccess := middleware.RequireSpaceAccess(a.SpaceService)(createExpenseHandler)
mux.Handle("POST /app/spaces/{spaceID}/expenses", createExpenseWithAccess)
// Component routes (HTMX updates)
balanceCardHandler := middleware.RequireAuth(space.GetBalanceCard)
balanceCardWithAccess := middleware.RequireSpaceAccess(a.SpaceService)(balanceCardHandler)
mux.Handle("GET /app/spaces/{spaceID}/components/balance", balanceCardWithAccess)
expensesListHandler := middleware.RequireAuth(space.GetExpensesList)
expensesListWithAccess := middleware.RequireSpaceAccess(a.SpaceService)(expensesListHandler)
mux.Handle("GET /app/spaces/{spaceID}/components/expenses", expensesListWithAccess)
shoppingListItemsHandler := middleware.RequireAuth(space.GetShoppingListItems)
shoppingListItemsWithAccess := middleware.RequireSpaceAccess(a.SpaceService)(shoppingListItemsHandler)
mux.Handle("GET /app/spaces/{spaceID}/lists/{listID}/items", shoppingListItemsWithAccess)
listsComponentHandler := middleware.RequireAuth(space.GetLists)
listsComponentWithAccess := middleware.RequireSpaceAccess(a.SpaceService)(listsComponentHandler)
mux.Handle("GET /app/spaces/{spaceID}/components/lists", listsComponentWithAccess)
// Invite routes
createInviteHandler := middleware.RequireAuth(space.CreateInvite)
createInviteWithAccess := middleware.RequireSpaceAccess(a.SpaceService)(createInviteHandler)
mux.Handle("POST /app/spaces/{spaceID}/invites", createInviteWithAccess)
mux.HandleFunc("GET /join/{token}", space.JoinSpace)
// 404
mux.HandleFunc("/{path...}", home.NotFoundPage)
// Global middlewares
handler := middleware.Chain(
mux,
middleware.Config(a.Cfg),
middleware.RequestLogging,
middleware.CSRFProtection,
middleware.AuthMiddleware(a.AuthService, a.UserService, a.ProfileService),
middleware.WithURLPath,
)
return handler
}