gohorsejobs/backend/internal/router/router.go
Tiago Yamamoto b2284921ea feat: add Cloudflare and cPanel admin routes
Cloudflare Cache Management:
- GET /api/v1/admin/cloudflare/zones
- POST /api/v1/admin/cloudflare/cache/purge-all
- POST /api/v1/admin/cloudflare/cache/purge-urls
- POST /api/v1/admin/cloudflare/cache/purge-tags
- POST /api/v1/admin/cloudflare/cache/purge-hosts

cPanel Email Management:
- GET /api/v1/admin/cpanel/emails
- POST /api/v1/admin/cpanel/emails
- DELETE /api/v1/admin/cpanel/emails/{email}
- PUT /api/v1/admin/cpanel/emails/{email}/password
- PUT /api/v1/admin/cpanel/emails/{email}/quota

All routes protected by JWT auth middleware.
Added CLOUDFLARE_* and CPANEL_* env vars to .env.example
2025-12-14 10:11:36 -03:00

172 lines
7.4 KiB
Go
Executable file

package router
import (
"log"
"net/http"
"os"
"time"
"github.com/rede5/gohorsejobs/backend/internal/api/middleware"
"github.com/rede5/gohorsejobs/backend/internal/database"
"github.com/rede5/gohorsejobs/backend/internal/handlers"
"github.com/rede5/gohorsejobs/backend/internal/infrastructure/persistence/postgres"
"github.com/rede5/gohorsejobs/backend/internal/infrastructure/storage"
"github.com/rede5/gohorsejobs/backend/internal/services"
// Core Imports
apiHandlers "github.com/rede5/gohorsejobs/backend/internal/api/handlers"
authUC "github.com/rede5/gohorsejobs/backend/internal/core/usecases/auth"
tenantUC "github.com/rede5/gohorsejobs/backend/internal/core/usecases/tenant"
userUC "github.com/rede5/gohorsejobs/backend/internal/core/usecases/user"
authInfra "github.com/rede5/gohorsejobs/backend/internal/infrastructure/auth"
legacyMiddleware "github.com/rede5/gohorsejobs/backend/internal/middleware"
// Admin Imports
"github.com/rede5/gohorsejobs/backend/internal/admin/cloudflare"
"github.com/rede5/gohorsejobs/backend/internal/admin/cpanel"
_ "github.com/rede5/gohorsejobs/backend/docs" // Import generated docs
httpSwagger "github.com/swaggo/http-swagger/v2"
)
func NewRouter() http.Handler {
mux := http.NewServeMux()
// Initialize Services
jobService := services.NewJobService(database.DB)
applicationService := services.NewApplicationService(database.DB)
// --- CORE ARCHITECTURE INITIALIZATION ---
// Infrastructure
// Infrastructure,
userRepo := postgres.NewUserRepository(database.DB)
companyRepo := postgres.NewCompanyRepository(database.DB)
jwtSecret := os.Getenv("JWT_SECRET")
if jwtSecret == "" {
// Fallback for dev, but really should be in env
jwtSecret = "default-dev-secret-do-not-use-in-prod"
}
authService := authInfra.NewJWTService(jwtSecret, "todai-jobs")
// UseCases
loginUC := authUC.NewLoginUseCase(userRepo, authService)
createCompanyUC := tenantUC.NewCreateCompanyUseCase(companyRepo, userRepo, authService)
listCompaniesUC := tenantUC.NewListCompaniesUseCase(companyRepo)
createUserUC := userUC.NewCreateUserUseCase(userRepo, authService)
listUsersUC := userUC.NewListUsersUseCase(userRepo)
deleteUserUC := userUC.NewDeleteUserUseCase(userRepo)
// Handlers & Middleware
coreHandlers := apiHandlers.NewCoreHandlers(loginUC, createCompanyUC, createUserUC, listUsersUC, deleteUserUC, listCompaniesUC)
authMiddleware := middleware.NewMiddleware(authService)
// Initialize Legacy Handlers
jobHandler := handlers.NewJobHandler(jobService)
applicationHandler := handlers.NewApplicationHandler(applicationService)
// Initialize Admin Handlers
cloudflareHandler := cloudflare.NewHandler()
cpanelHandler := cpanel.NewHandler()
// --- ROOT ROUTE ---
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/" {
http.NotFound(w, r)
return
}
// Get client IP
clientIP := r.Header.Get("X-Forwarded-For")
if clientIP == "" {
clientIP = r.Header.Get("X-Real-IP")
}
if clientIP == "" {
clientIP = r.RemoteAddr
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
response := `{
"message": "🐴 GoHorseJobs API is running!",
"ip": "` + clientIP + `",
"docs": "/docs",
"health": "/health",
"version": "1.0.0"
}`
w.Write([]byte(response))
})
mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("OK"))
})
// --- CORE ROUTES ---
// Public
mux.HandleFunc("POST /api/v1/auth/login", coreHandlers.Login)
mux.HandleFunc("POST /api/v1/companies", coreHandlers.CreateCompany)
mux.HandleFunc("GET /api/v1/companies", coreHandlers.ListCompanies)
// Protected
// Note: In Go 1.22+, we can wrap specific patterns. Or we can just wrap the handler.
// For simplicity, we wrap the handler function.
mux.Handle("POST /api/v1/users", authMiddleware.HeaderAuthGuard(http.HandlerFunc(coreHandlers.CreateUser)))
mux.Handle("GET /api/v1/users", authMiddleware.HeaderAuthGuard(http.HandlerFunc(coreHandlers.ListUsers)))
mux.Handle("DELETE /api/v1/users/{id}", authMiddleware.HeaderAuthGuard(http.HandlerFunc(coreHandlers.DeleteUser)))
// Job Routes
mux.HandleFunc("GET /jobs", jobHandler.GetJobs)
mux.HandleFunc("POST /jobs", jobHandler.CreateJob)
mux.HandleFunc("GET /jobs/{id}", jobHandler.GetJobByID)
mux.HandleFunc("PUT /jobs/{id}", jobHandler.UpdateJob)
mux.HandleFunc("DELETE /jobs/{id}", jobHandler.DeleteJob)
// Application Routes
mux.HandleFunc("POST /applications", applicationHandler.CreateApplication)
mux.HandleFunc("GET /applications", applicationHandler.GetApplications)
mux.HandleFunc("GET /applications/{id}", applicationHandler.GetApplicationByID)
mux.HandleFunc("PUT /applications/{id}/status", applicationHandler.UpdateApplicationStatus)
// --- STORAGE ROUTES ---
// Initialize S3 Storage (optional - graceful degradation if not configured)
s3Storage, err := storage.NewS3Storage()
if err != nil {
log.Printf("Warning: S3 storage not available: %v", err)
} else {
storageHandler := handlers.NewStorageHandler(s3Storage)
mux.Handle("POST /api/v1/storage/upload-url", authMiddleware.HeaderAuthGuard(http.HandlerFunc(storageHandler.GenerateUploadURL)))
mux.Handle("POST /api/v1/storage/download-url", authMiddleware.HeaderAuthGuard(http.HandlerFunc(storageHandler.GenerateDownloadURL)))
mux.Handle("DELETE /api/v1/storage/files", authMiddleware.HeaderAuthGuard(http.HandlerFunc(storageHandler.DeleteFile)))
log.Println("S3 storage routes registered successfully")
}
// --- ADMIN ROUTES (Protected - SuperAdmin only) ---
// Cloudflare Cache Management
mux.Handle("GET /api/v1/admin/cloudflare/zones", authMiddleware.HeaderAuthGuard(http.HandlerFunc(cloudflareHandler.GetZones)))
mux.Handle("POST /api/v1/admin/cloudflare/cache/purge-all", authMiddleware.HeaderAuthGuard(http.HandlerFunc(cloudflareHandler.PurgeAll)))
mux.Handle("POST /api/v1/admin/cloudflare/cache/purge-urls", authMiddleware.HeaderAuthGuard(http.HandlerFunc(cloudflareHandler.PurgeByURLs)))
mux.Handle("POST /api/v1/admin/cloudflare/cache/purge-tags", authMiddleware.HeaderAuthGuard(http.HandlerFunc(cloudflareHandler.PurgeByTags)))
mux.Handle("POST /api/v1/admin/cloudflare/cache/purge-hosts", authMiddleware.HeaderAuthGuard(http.HandlerFunc(cloudflareHandler.PurgeByHosts)))
// cPanel Email Management
mux.Handle("GET /api/v1/admin/cpanel/emails", authMiddleware.HeaderAuthGuard(http.HandlerFunc(cpanelHandler.ListEmails)))
mux.Handle("POST /api/v1/admin/cpanel/emails", authMiddleware.HeaderAuthGuard(http.HandlerFunc(cpanelHandler.CreateEmail)))
mux.Handle("DELETE /api/v1/admin/cpanel/emails/{email}", authMiddleware.HeaderAuthGuard(http.HandlerFunc(cpanelHandler.DeleteEmail)))
mux.Handle("PUT /api/v1/admin/cpanel/emails/{email}/password", authMiddleware.HeaderAuthGuard(http.HandlerFunc(cpanelHandler.ChangePassword)))
mux.Handle("PUT /api/v1/admin/cpanel/emails/{email}/quota", authMiddleware.HeaderAuthGuard(http.HandlerFunc(cpanelHandler.UpdateQuota)))
log.Println("Admin routes (Cloudflare, cPanel) registered successfully")
// Swagger Route - available at /docs
mux.HandleFunc("/docs/", httpSwagger.WrapHandler)
// Apply middleware chain: Security Headers -> Rate Limiting -> CORS -> Router
// Order matters: outer middleware runs first
var handler http.Handler = mux
handler = middleware.CORSMiddleware(handler)
handler = legacyMiddleware.RateLimitMiddleware(100, time.Minute)(handler) // 100 req/min per IP
handler = legacyMiddleware.SecurityHeadersMiddleware(handler)
return handler
}