Add PDF reports, file uploads, admin auth, and comprehensive tests
Features: - PDF service for generating task reports with ReportLab-style formatting - Storage service for file uploads (local and S3-compatible) - Admin authentication middleware with JWT support - Admin user model and repository Infrastructure: - Updated Docker configuration for admin panel builds - Email service enhancements for task notifications - Updated router with admin and file upload routes - Environment configuration updates Tests: - Unit tests for handlers (auth, residence, task) - Unit tests for models (user, residence, task) - Unit tests for repositories (user, residence, task) - Unit tests for services (residence, task) - Integration test setup - Test utilities for mocking database and services Database: - Admin user seed data - Updated test data seeds 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/treytartt/mycrib-api/internal/admin"
|
||||
"github.com/treytartt/mycrib-api/internal/config"
|
||||
"github.com/treytartt/mycrib-api/internal/handlers"
|
||||
"github.com/treytartt/mycrib-api/internal/middleware"
|
||||
@@ -21,11 +22,13 @@ const Version = "2.0.0"
|
||||
|
||||
// Dependencies holds all dependencies needed by the router
|
||||
type Dependencies struct {
|
||||
DB *gorm.DB
|
||||
Cache *services.CacheService
|
||||
Config *config.Config
|
||||
EmailService *services.EmailService
|
||||
PushClient interface{} // *push.GorushClient - optional
|
||||
DB *gorm.DB
|
||||
Cache *services.CacheService
|
||||
Config *config.Config
|
||||
EmailService *services.EmailService
|
||||
PDFService *services.PDFService
|
||||
PushClient interface{} // *push.GorushClient - optional
|
||||
StorageService *services.StorageService
|
||||
}
|
||||
|
||||
// SetupRouter creates and configures the Gin router
|
||||
@@ -49,6 +52,11 @@ func SetupRouter(deps *Dependencies) *gin.Engine {
|
||||
// Health check endpoint (no auth required)
|
||||
r.GET("/api/health/", healthCheck)
|
||||
|
||||
// Serve static files from uploads directory
|
||||
if cfg.Storage.UploadDir != "" {
|
||||
r.Static("/uploads", cfg.Storage.UploadDir)
|
||||
}
|
||||
|
||||
// Initialize repositories
|
||||
userRepo := repositories.NewUserRepository(deps.DB)
|
||||
residenceRepo := repositories.NewResidenceRepository(deps.DB)
|
||||
@@ -70,6 +78,7 @@ func SetupRouter(deps *Dependencies) *gin.Engine {
|
||||
authService := services.NewAuthService(userRepo, cfg)
|
||||
userService := services.NewUserService(userRepo)
|
||||
residenceService := services.NewResidenceService(residenceRepo, userRepo, cfg)
|
||||
residenceService.SetTaskRepository(taskRepo) // Wire up task repo for statistics
|
||||
taskService := services.NewTaskService(taskRepo, residenceRepo)
|
||||
contractorService := services.NewContractorService(contractorRepo, residenceRepo)
|
||||
documentService := services.NewDocumentService(documentRepo, residenceRepo)
|
||||
@@ -86,14 +95,31 @@ func SetupRouter(deps *Dependencies) *gin.Engine {
|
||||
// Initialize handlers
|
||||
authHandler := handlers.NewAuthHandler(authService, deps.EmailService, deps.Cache)
|
||||
userHandler := handlers.NewUserHandler(userService)
|
||||
residenceHandler := handlers.NewResidenceHandler(residenceService)
|
||||
taskHandler := handlers.NewTaskHandler(taskService)
|
||||
residenceHandler := handlers.NewResidenceHandler(residenceService, deps.PDFService, deps.EmailService)
|
||||
taskHandler := handlers.NewTaskHandler(taskService, deps.StorageService)
|
||||
contractorHandler := handlers.NewContractorHandler(contractorService)
|
||||
documentHandler := handlers.NewDocumentHandler(documentService)
|
||||
documentHandler := handlers.NewDocumentHandler(documentService, deps.StorageService)
|
||||
notificationHandler := handlers.NewNotificationHandler(notificationService)
|
||||
subscriptionHandler := handlers.NewSubscriptionHandler(subscriptionService)
|
||||
staticDataHandler := handlers.NewStaticDataHandler(residenceService, taskService, contractorService)
|
||||
|
||||
// Initialize upload handler (if storage service is available)
|
||||
var uploadHandler *handlers.UploadHandler
|
||||
if deps.StorageService != nil {
|
||||
uploadHandler = handlers.NewUploadHandler(deps.StorageService)
|
||||
}
|
||||
|
||||
// Set up admin routes (separate auth system)
|
||||
adminDeps := &admin.Dependencies{
|
||||
EmailService: deps.EmailService,
|
||||
}
|
||||
if deps.PushClient != nil {
|
||||
if gc, ok := deps.PushClient.(*push.GorushClient); ok {
|
||||
adminDeps.PushClient = gc
|
||||
}
|
||||
}
|
||||
admin.SetupRoutes(r, deps.DB, cfg, adminDeps)
|
||||
|
||||
// API group
|
||||
api := r.Group("/api")
|
||||
{
|
||||
@@ -115,6 +141,11 @@ func SetupRouter(deps *Dependencies) *gin.Engine {
|
||||
setupNotificationRoutes(protected, notificationHandler)
|
||||
setupSubscriptionRoutes(protected, subscriptionHandler)
|
||||
setupUserRoutes(protected, userHandler)
|
||||
|
||||
// Upload routes (only if storage service is configured)
|
||||
if uploadHandler != nil {
|
||||
setupUploadRoutes(protected, uploadHandler)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,6 +256,7 @@ func setupTaskRoutes(api *gin.RouterGroup, taskHandler *handlers.TaskHandler) {
|
||||
tasks.POST("/:id/uncancel/", taskHandler.UncancelTask)
|
||||
tasks.POST("/:id/archive/", taskHandler.ArchiveTask)
|
||||
tasks.POST("/:id/unarchive/", taskHandler.UnarchiveTask)
|
||||
tasks.GET("/:id/completions/", taskHandler.GetTaskCompletions)
|
||||
}
|
||||
|
||||
// Task Completions
|
||||
@@ -311,3 +343,14 @@ func setupUserRoutes(api *gin.RouterGroup, userHandler *handlers.UserHandler) {
|
||||
users.GET("/profiles/", userHandler.ListProfiles)
|
||||
}
|
||||
}
|
||||
|
||||
// setupUploadRoutes configures file upload routes
|
||||
func setupUploadRoutes(api *gin.RouterGroup, uploadHandler *handlers.UploadHandler) {
|
||||
uploads := api.Group("/uploads")
|
||||
{
|
||||
uploads.POST("/image/", uploadHandler.UploadImage)
|
||||
uploads.POST("/document/", uploadHandler.UploadDocument)
|
||||
uploads.POST("/completion/", uploadHandler.UploadCompletion)
|
||||
uploads.DELETE("/", uploadHandler.DeleteFile)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user