package routes import ( "lost-and-found/internal/controllers" "lost-and-found/internal/middleware" "github.com/gin-gonic/gin" "go.uber.org/zap" "gorm.io/gorm" ) // SetupRoutes configures all application routes func SetupRoutes(router *gin.Engine, db *gorm.DB, logger *zap.Logger) { // Initialize controllers authController := controllers.NewAuthController(db, logger) userController := controllers.NewUserController(db) itemController := controllers.NewItemController(db) lostItemController := controllers.NewLostItemController(db) claimController := controllers.NewClaimController(db) matchController := controllers.NewMatchController(db) categoryController := controllers.NewCategoryController(db) archiveController := controllers.NewArchiveController(db) adminController := controllers.NewAdminController(db) reportController := controllers.NewReportController(db) uploadController := controllers.NewUploadController(db) managerController := controllers.NewManagerController(db) roleController := controllers.NewRoleController(db) notificationController := controllers.NewNotificationController(db) aiController := controllers.NewAIController(db) // API group api := router.Group("/api") { // ========================================== // 1. Public Routes (No Auth) // ========================================== api.POST("/register", authController.Register) api.POST("/login", authController.Login) api.POST("/refresh-token", authController.RefreshToken) api.GET("/categories", categoryController.GetAllCategories) api.GET("/categories/:id", categoryController.GetCategoryByID) // Optional Auth for Items (Public can view, Manager sees details) itemsGroup := api.Group("/items") itemsGroup.Use(middleware.OptionalJWTMiddleware(db)) { itemsGroup.GET("", itemController.GetAllItems) itemsGroup.GET("/:id", itemController.GetItemByID) } // ========================================== // 2. Authenticated Routes (Basic User Access) // ========================================== // Middleware: Cek Token Valid & User Active authenticated := api.Group("") authenticated.Use(middleware.JWTMiddleware(db)) { authenticated.POST("/ai/chat", aiController.Chat) authenticated.GET("/ai/history", aiController.GetHistory) authenticated.DELETE("/ai/history", aiController.ClearHistory) // Profile (Siapapun yang login bisa akses ini) authenticated.GET("/me", authController.GetMe) authenticated.GET("/user/profile", userController.GetProfile) authenticated.PUT("/user/profile", userController.UpdateProfile) authenticated.POST("/user/change-password", userController.ChangePassword) authenticated.GET("/user/stats", userController.GetStats) authenticated.POST("/lost-items/:id/direct-claim", lostItemController.DirectClaimToOwner) authenticated.POST("/user/lost-items/:id/direct-claim", lostItemController.DirectClaimToOwner) authenticated.POST("/claims/:id/respond", claimController.UserApproveClaim) authenticated.POST("/claims/:id/complete", claimController.UserConfirmCompletion) // --- User Features (Permission: item:create) --- authenticated.POST("/items", middleware.RequirePermission("item:create"), itemController.CreateItem) authenticated.GET("/user/items", middleware.RequirePermission("item:read"), itemController.GetItemsByReporter) // --- Lost Items (Permission: item:create) --- // Asumsi: Hak akses lapor kehilangan sama dengan lapor temuan authenticated.POST("/lost-items", middleware.RequirePermission("item:create"), lostItemController.CreateLostItem) authenticated.GET("/user/lost-items", lostItemController.GetLostItemsByUser) authenticated.GET("/lost-items", lostItemController.GetAllLostItems) authenticated.GET("/lost-items/:id", lostItemController.GetLostItemByID) authenticated.PUT("/lost-items/:id", lostItemController.UpdateLostItem) authenticated.PATCH("/lost-items/:id/status", lostItemController.UpdateLostItemStatus) // ✅ FIX: Delete Lost Item menggunakan controller yang benar authenticated.DELETE("/lost-items/:id", middleware.RequirePermission("lost_item:delete"), // Permission baru lostItemController.DeleteLostItem) // --- Claims (Permission: claim:create) --- authenticated.POST("/claims", middleware.RequirePermission("claim:create"), middleware.IdempotencyMiddleware(), // Prevent double submit claimController.CreateClaim) authenticated.GET("/user/claims", middleware.RequirePermission("claim:read"), claimController.GetClaimsByUser) // ✅ FIX: Tambahkan endpoint update dan delete claim user authenticated.PUT("/claims/:id", middleware.RequirePermission("claim:create"), // User boleh edit claim sendiri claimController.UpdateClaim) authenticated.DELETE("/claims/:id", middleware.RequirePermission("claim:create"), // User boleh delete claim sendiri claimController.DeleteClaim) // --- Matching --- authenticated.GET("/lost-items/:id/matches", matchController.GetMatchesForLostItem) authenticated.POST("/lost-items/:id/find-similar", matchController.FindSimilarItems) // --- Notifications --- authenticated.GET("/notifications", notificationController.GetUserNotifications) authenticated.PATCH("/notifications/:id/read", notificationController.MarkAsRead) authenticated.PATCH("/notifications/read-all", notificationController.MarkAllAsRead) authenticated.POST("/user/claims/:id/respond", claimController.UserApproveClaim) authenticated.POST("/user/claims/:id/complete", claimController.UserConfirmCompletion) // --- Uploads --- upload := authenticated.Group("/upload") { upload.POST("/item-image", uploadController.UploadItemImage) upload.POST("/claim-proof", uploadController.UploadClaimProof) upload.POST("/multiple", uploadController.UploadMultipleImages) upload.DELETE("/delete", uploadController.DeleteImage) upload.GET("/info", uploadController.GetImageInfo) } } // ========================================== // 3. Protected Management Routes (Permission Based) // ========================================== // Area ini menggantikan Group Manager/Admin yang lama. // Sekarang dikelompokkan berdasarkan FITUR, bukan ROLE. management := api.Group("") management.Use(middleware.JWTMiddleware(db)) { // --- ITEM MANAGEMENT (Permission: item:update, item:delete) --- management.PUT("/items/:id", middleware.RequirePermission("item:update"), itemController.UpdateItem) management.PATCH("/items/:id/status", middleware.RequirePermission("item:update"), itemController.UpdateItemStatus) management.DELETE("/items/:id", middleware.RequirePermission("item:delete"), itemController.DeleteItem) management.GET("/items/:id/revisions", middleware.RequirePermission("item:verify"), itemController.GetItemRevisionHistory) management.GET("/items/:id/matches", middleware.RequirePermission("item:verify"), matchController.GetMatchesForItem) // --- CLAIM VERIFICATION (Permission: claim:approve, claim:reject) --- management.GET("/claims", middleware.RequirePermission("claim:read"), // Manager view all claims claimController.GetAllClaims) management.GET("/claims/:id", middleware.RequirePermission("claim:read"), claimController.GetClaimByID) management.POST("/claims/:id/verify", middleware.RequirePermission("claim:approve"), middleware.IdempotencyMiddleware(), claimController.VerifyClaim) management.GET("/claims/:id/verification", middleware.RequirePermission("claim:read"), claimController.GetClaimVerification) // ✅ FIX: Ganti endpoint CloseClaim -> CloseCase management.POST("/claims/:id/close", middleware.RequirePermission("claim:approve"), claimController.CloseCase) // ✅ FIX: Ganti endpoint ReopenClaim -> ReopenCase management.POST("/claims/:id/reopen", middleware.RequirePermission("claim:approve"), claimController.ReopenCase) // ✅ FIX: Ganti endpoint CancelApproval -> CancelClaimApproval management.POST("/claims/:id/cancel-approval", middleware.RequirePermission("claim:approve"), claimController.CancelClaimApproval) // --- ARCHIVES (Permission: item:read - for historical data) --- management.GET("/archives", middleware.RequirePermission("item:read"), archiveController.GetAllArchives) management.GET("/archives/:id", middleware.RequirePermission("item:read"), archiveController.GetArchiveByID) management.GET("/archives/stats", middleware.RequirePermission("item:read"), archiveController.GetArchiveStats) // --- REPORTS (Permission: report:export) --- management.POST("/reports/export", middleware.RequirePermission("report:export"), reportController.ExportReport) // --- DASHBOARD (Permission: user:read - as proxy for dashboard access) --- management.GET("/manager/dashboard", middleware.RequirePermission("item:verify"), managerController.GetDashboardStats) management.GET("/admin/dashboard", middleware.RequirePermission("user:read"), adminController.GetDashboardStats) // --- USER MANAGEMENT (Permission: user:read, user:update, user:block) --- // Biasa dilakukan oleh Admin management.GET("/admin/users", middleware.RequirePermission("user:read"), userController.GetAllUsers) management.GET("/admin/users/:id", middleware.RequirePermission("user:read"), userController.GetUserByID) management.PATCH("/admin/users/:id/role", middleware.RequirePermission("user:update"), userController.UpdateUserRole) management.POST("/admin/users/:id/block", middleware.RequirePermission("user:block"), userController.BlockUser) management.POST("/admin/users/:id/unblock", middleware.RequirePermission("user:block"), userController.UnblockUser) management.DELETE("/admin/users/:id", middleware.RequirePermission("user:block"), // Menggunakan permission block untuk delete userController.DeleteUser) // --- AUDIT LOGS (Permission: user:read - biasanya Admin) --- management.GET("/admin/audit-logs", middleware.RequirePermission("user:read"), adminController.GetAuditLogs) // --- CATEGORY MANAGEMENT (Permission: item:update - Admin Only usually) --- // Note: Anda mungkin perlu menambahkan permission 'category:create' di seed.sql // Untuk sekarang kita gunakan 'item:update' atau 'user:update' sebagai proxy management.POST("/categories", middleware.RequirePermission("user:update"), categoryController.CreateCategory) management.PUT("/categories/:id", middleware.RequirePermission("user:update"), categoryController.UpdateCategory) management.DELETE("/categories/:id", middleware.RequirePermission("user:update"), categoryController.DeleteCategory) // ✅ Endpoint baru untuk test Procedure SQL management.POST("/admin/archive/trigger", middleware.RequireRole("admin"), // Hanya admin adminController.TriggerAutoArchive) management.GET("/admin/dashboard/fast", middleware.RequireRole("admin", "manager"), adminController.GetFastDashboardStats) management.GET("/admin/roles", middleware.RequireRole("admin"), roleController.GetRoles) management.GET("/admin/permissions", middleware.RequireRole("admin"), roleController.GetPermissions) management.POST("/admin/roles", middleware.RequireRole("admin"), roleController.CreateRole) management.PUT("/admin/roles/:id", middleware.RequireRole("admin"), roleController.UpdateRole) management.DELETE("/admin/roles/:id", middleware.RequireRole("admin"), roleController.DeleteRole) } } }