package api import ( "RenewCMS/api/handlers/article" "RenewCMS/api/handlers/auth" "RenewCMS/api/handlers/frontend" "RenewCMS/api/handlers/image" "RenewCMS/api/middleware" "RenewCMS/internal/infrastructure/config" "encoding/json" "net/http" "github.com/MadAppGang/httplog" "github.com/go-chi/chi/v5" chimiddleware "github.com/go-chi/chi/v5/middleware" "github.com/go-chi/cors" "github.com/go-chi/jwtauth/v5" ) func enableLoggingIfDev(r *chi.Mux, routerName string, environment string) { if environment == "development" { r.Use(httplog.LoggerWithName(routerName)) } } func GetHelloWorld(w http.ResponseWriter, _ *http.Request) { msg, _ := json.Marshal(map[string]string{"message": "Hello World"}) _, _ = w.Write(msg) } func NewArticleRouter(container *UseCases) http.Handler { r := chi.NewRouter() articleHandler := article.NewHandler(container.CreateArticleUseCase, container.GetArticleUseCase, container.ListArticlesUseCase, container.DeleteArticleUseCase, container.UpdateArticleUseCase, container.GetUserUseCase) imageHandler := image.NewHandler(container.CreateImageUseCase, container.GetArticleUseCase, container.UpdateArticleUseCase) r.Group(func(r chi.Router) { r.Get("/", articleHandler.ListArticles) r.Get("/{id}", articleHandler.GetArticle) }) r.Group(func(r chi.Router) { r.Use(jwtauth.Authenticator(container.Token)) r.Use(middleware.RequireCurrentToken(container.GetUserUseCase)) r.Use(middleware.RequireVerifiedUser(container.GetUserUseCase)) r.Post("/", articleHandler.PostArticle) r.Delete("/{id}", articleHandler.DeleteArticle) r.Patch("/{id}", articleHandler.UpdateArticleBody) r.Patch("/{id}/publish", articleHandler.PublishArticle) r.Patch("/{id}/unpublish", articleHandler.UnpublishArticle) r.Post("/{id}/image", imageHandler.PostImage) }) return r } func NewAuthRouter(container *UseCases, isProduction bool) http.Handler { r := chi.NewRouter() authHandler := auth.NewHandler(container.Token, container.GetUserUseCase, container.ListUsersUseCase, container.CreateUserUseCase, container.AuthenticateUserUseCase, container.VerifyUserUseCase, container.CancelRegistrationUseCase, container.RequestPasswordResetUseCase, container.ResetPasswordUseCase, isProduction) r.Post("/register", authHandler.Register) r.Post("/login", authHandler.Login) r.Post("/logout", authHandler.Logout) r.Post("/password-reset", authHandler.RequestPasswordReset) r.Post("/password-reset/confirm", authHandler.ResetPassword) r.Group(func(r chi.Router) { r.Use(jwtauth.Verifier(container.Token)) r.Use(jwtauth.Authenticator(container.Token)) r.Use(middleware.RequireCurrentToken(container.GetUserUseCase)) r.Post("/verify", authHandler.Verify) r.Delete("/register", authHandler.CancelRegistration) }) return r } func InitBackendRoutes(container *UseCases, settings config.Settings) *chi.Mux { r := chi.NewRouter() enableLoggingIfDev(r, "backend", settings.Environment) r.Use(chimiddleware.GetHead) r.Use(middleware.JsonContentTypeMiddleware) r.Get("/", GetHelloWorld) r.Group(func(r chi.Router) { r.Use(jwtauth.Verifier(container.Token)) r.Mount("/article", NewArticleRouter(container)) }) r.Mount("/auth", NewAuthRouter(container, settings.IsProduction())) return r } func InitFrontendRoutes(environment string) *chi.Mux { r := chi.NewRouter() enableLoggingIfDev(r, "frontend", environment) r.Mount("/", frontend.NewFrontendRouter()) return r } func GetHealth(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Content-Type", "text/plain; charset=utf-8") _, _ = w.Write([]byte("ok")) } func enableCorsIfConfigured(r *chi.Mux, origins []string) { if len(origins) == 0 { return } r.Use(cors.Handler(cors.Options{ AllowedOrigins: origins, AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}, AllowedHeaders: []string{"Accept", "Authorization", "Content-Type", "X-CSRF-Token"}, ExposedHeaders: []string{"Link"}, AllowCredentials: false, MaxAge: 300, })) } func InitRoutes(container *UseCases, settings config.Settings) *chi.Mux { backend := InitBackendRoutes(container, settings) frontend := InitFrontendRoutes(settings.Environment) apiRouter := chi.NewRouter() enableCorsIfConfigured(apiRouter, settings.CorsAllowedOrigins) apiRouter.Use(chimiddleware.GetHead) apiRouter.Get("/healthz", GetHealth) apiRouter.Mount("/v1", backend) apiRouter.Mount("/", frontend) return apiRouter }