diff --git a/internal/router/collections.go b/internal/router/collections.go new file mode 100644 index 0000000..5dc6206 --- /dev/null +++ b/internal/router/collections.go @@ -0,0 +1,30 @@ +package router + +func registerCollectionsRoutes(cfg *Config) { + e := cfg.Echo + + // JWT middleware for protected routes + jwtMiddleware := createJWTMiddleware(cfg) + protected := e.Group("/api", jwtMiddleware) + + // Collections API routes + collections := protected.Group("/collections") + collections.GET("", cfg.CollectionHandler.GetCollections) + collections.POST("", cfg.CollectionHandler.CreateCollection) + collections.GET("/:id", cfg.CollectionHandler.GetCollection) + collections.PUT("/:id", cfg.CollectionHandler.UpdateCollection) + collections.DELETE("/:id", cfg.CollectionHandler.DeleteCollection) + collections.GET("/:id/books", cfg.CollectionHandler.GetBookCollections) + collections.POST("/:id/books", cfg.CollectionHandler.AddBooks) + collections.DELETE("/:id/books/:bookId", cfg.CollectionHandler.RemoveBook) + collections.POST("/:id/books/bulk-remove", cfg.CollectionHandler.BulkRemoveBooks) + collections.POST("/bulk-add-books", cfg.CollectionHandler.HandleBulkAddBooks) + collections.POST("/test-rules", cfg.CollectionHandler.TestRules) + + // Device shelf mapping routes + deviceCollections := protected.Group("/devices/:id/collections") + deviceCollections.GET("", cfg.CollectionHandler.GetDeviceMappings) + deviceCollections.POST("", cfg.CollectionHandler.CreateDeviceMapping) + deviceCollections.PUT("/:collectionId", cfg.CollectionHandler.UpdateDeviceMapping) + deviceCollections.DELETE("/:collectionId", cfg.CollectionHandler.DeleteDeviceMapping) +} diff --git a/internal/router/matching.go b/internal/router/matching.go new file mode 100644 index 0000000..27fdb97 --- /dev/null +++ b/internal/router/matching.go @@ -0,0 +1,20 @@ +package router + +func registerMatchingRoutes(cfg *Config) { + e := cfg.Echo + + // JWT middleware for protected routes + jwtMiddleware := createJWTMiddleware(cfg) + protected := e.Group("/api", jwtMiddleware) + + // Book matching and linking routes (all authenticated users) + protected.POST("/devices/:deviceId/sync/link-book", cfg.MatchingHandler.LinkBook) + protected.GET("/devices/:deviceId/sync/unlinked-books", cfg.MatchingHandler.GetUnlinkedBooks) + + // File alias routes (all authenticated users) + protected.GET("/devices/:id/file-aliases", cfg.MatchingHandler.GetDeviceFileAliases) + protected.POST("/devices/:id/file-aliases", cfg.MatchingHandler.CreateDeviceFileAlias) + protected.PUT("/devices/:id/file-aliases/:aliasId", cfg.MatchingHandler.UpdateDeviceFileAlias) + protected.DELETE("/devices/:id/file-aliases/:aliasId", cfg.MatchingHandler.DeleteDeviceFileAlias) + protected.GET("/books/match", cfg.MatchingHandler.GetBookMatches) +} diff --git a/internal/router/media.go b/internal/router/media.go index 0725010..501ade6 100644 --- a/internal/router/media.go +++ b/internal/router/media.go @@ -9,23 +9,55 @@ func registerMediaRoutes(cfg *Config) { // JWT middleware for protected routes jwtMiddleware := createJWTMiddleware(cfg) - protected := e.Group("/api", jwtMiddleware) + admin := protected.Group("", handlers.AdminMiddleware) - // Media item handler - mediaHandler := handlers.NewMediaHandler(cfg.Queries) + // Media item routes (all authenticated users) + protected.GET("/media-items", cfg.MediaHandler.ListMediaItems) + protected.GET("/media-items/filtered", cfg.MediaHandler.ListMediaItemsFiltered) + protected.GET("/media-items/:id", cfg.MediaHandler.GetMediaItem) + + // Media rating routes (all authenticated users) + protected.POST("/media-items/:id/rating", cfg.MediaHandler.CreateMediaRating) + protected.GET("/media-items/:id/rating", cfg.MediaHandler.GetMediaRating) + protected.PUT("/media-items/:id/rating", cfg.MediaHandler.UpdateMediaRating) + protected.DELETE("/media-items/:id/rating", cfg.MediaHandler.DeleteMediaRating) + + // Legacy progress routes (all authenticated users) + protected.GET("/media-items/:id/progress", cfg.MediaHandler.GetMediaReadingProgress) + protected.PUT("/media-items/:id/progress", cfg.MediaHandler.UpdateMediaReadingProgress) + protected.DELETE("/media-items/:id/progress", cfg.MediaHandler.DeleteMediaReadingProgress) + + // Notes routes (all authenticated users) + protected.GET("/media-items/:id/notes", cfg.MediaHandler.GetMediaNotes) + protected.POST("/media-items/:id/notes", cfg.MediaHandler.CreateMediaNote) + protected.GET("/media-items/:id/notes/:noteId", cfg.MediaHandler.GetMediaNote) + protected.PUT("/media-items/:id/notes/:noteId", cfg.MediaHandler.UpdateMediaNote) + protected.DELETE("/media-items/:id/notes/:noteId", cfg.MediaHandler.DeleteMediaNote) + + // Highlights routes (all authenticated users) + protected.GET("/media-items/:id/highlights", cfg.MediaHandler.GetMediaHighlights) + protected.POST("/media-items/:id/highlights", cfg.MediaHandler.CreateMediaHighlight) + protected.GET("/media-items/:id/highlights/:highlightId", cfg.MediaHandler.GetMediaHighlight) + protected.PUT("/media-items/:id/highlights/:highlightId", cfg.MediaHandler.UpdateMediaHighlight) + protected.DELETE("/media-items/:id/highlights/:highlightId", cfg.MediaHandler.DeleteMediaHighlight) + + // Admin-only media routes + admin.POST("/media-items", cfg.MediaHandler.CreateMediaItem) + admin.PUT("/media-items/:id", cfg.MediaHandler.UpdateMediaItem) + admin.DELETE("/media-items/:id", cfg.MediaHandler.DeleteMediaItem) // Download route (public) - e.GET("/api/books/:uuid/download", mediaHandler.DownloadBook) + e.GET("/api/books/:uuid/download", cfg.MediaHandler.DownloadBook) // Shelf management (protected) - protected.POST("/devices/:id/shelves", mediaHandler.AddToShelf) - protected.GET("/devices/:id/shelves", mediaHandler.GetShelf) - protected.DELETE("/devices/:id/shelves", mediaHandler.RemoveFromShelf) - protected.DELETE("/devices/:id/shelves/clear", mediaHandler.ClearShelf) + protected.POST("/devices/:id/shelves", cfg.MediaHandler.AddToShelf) + protected.GET("/devices/:id/shelves", cfg.MediaHandler.GetShelf) + protected.DELETE("/devices/:id/shelves", cfg.MediaHandler.RemoveFromShelf) + protected.DELETE("/devices/:id/shelves/clear", cfg.MediaHandler.ClearShelf) // Bulk book operations (protected) books := protected.Group("/books") - books.POST("/bulk-delete", mediaHandler.HandleBulkDelete) - books.POST("/bulk-update", mediaHandler.HandleBulkUpdate) + books.POST("/bulk-delete", cfg.MediaHandler.HandleBulkDelete) + books.POST("/bulk-update", cfg.MediaHandler.HandleBulkUpdate) } diff --git a/internal/router/progress.go b/internal/router/progress.go new file mode 100644 index 0000000..48372a0 --- /dev/null +++ b/internal/router/progress.go @@ -0,0 +1,18 @@ +package router + +import ( + "bookhoard/internal/handlers" +) + +func registerProgressRoutes(cfg *Config, ebookHandler *handlers.Handler) { + e := cfg.Echo + + // JWT middleware for protected routes + jwtMiddleware := createJWTMiddleware(cfg) + protected := e.Group("/api", jwtMiddleware) + + // Universal Progress routes (Phase 1) + protected.GET("/progress/:id", ebookHandler.GetUniversalProgress) + protected.POST("/progress/:id", ebookHandler.UpdateUniversalProgress) + protected.GET("/progress/:id/history", ebookHandler.GetProgressHistory) +} diff --git a/internal/router/router.go b/internal/router/router.go index 69b5e8b..6c7ccfc 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -38,11 +38,15 @@ type Config struct { AuthHandler *handlers.AuthHandler LibraryHandler *handlers.LibraryHandler DeviceHandler *handlers.DeviceHandler + MediaHandler *handlers.MediaHandler + SearchHandler *handlers.SearchHandler + MatchingHandler *handlers.MatchingHandler KOReaderHandler *handlers.KOReaderHandler WSHandler *handlers.WSHandler ConflictHandler *handlers.ConflictHandler AnalyticsHandler *handlers.AnalyticsHandler QueueHandler *handlers.QueueHandler + CollectionHandler *handlers.CollectionHandler OPDSHandler *handlers.OPDSHandler ConnManager *sync.ConnectionManager QueueProcessor *sync.SyncQueueProcessor @@ -110,14 +114,16 @@ func RegisterRoutes(cfg *Config) *handlers.Handler { // Register core application routes (collections, devices, media, etc.) - ONCE jwtMiddleware := createJWTMiddleware(cfg) protected := e.Group("/api", jwtMiddleware) - ebookHandler := handlers.SetupRoutes(protected, cfg.Queries, cfg.ConnManager) // Register route groups registerAuthRoutes(cfg, rateLimitMiddleware) registerLibraryRoutes(cfg) registerDeviceRoutes(cfg) registerSyncRoutes(cfg) + registerCollectionsRoutes(cfg) registerMediaRoutes(cfg) + registerSearchRoutes(cfg) + registerMatchingRoutes(cfg) registerConflictRoutes(cfg) registerAnalyticsRoutes(cfg) registerQueueRoutes(cfg) @@ -126,6 +132,12 @@ func RegisterRoutes(cfg *Config) *handlers.Handler { registerFrontendRoutes(cfg) registerDocumentationRoutes(cfg) + // Create ebook handler for scanner routes and progress routes + ebookHandler := handlers.SetupRoutes(protected, cfg.Queries, cfg.ConnManager) + + // Register progress routes with actual handler + registerProgressRoutes(cfg, ebookHandler) + // Register scanner routes (admin only) admin := protected.Group("", handlers.AdminMiddleware) registerScannerRoutes(admin, ebookHandler) diff --git a/internal/router/search.go b/internal/router/search.go new file mode 100644 index 0000000..80489cb --- /dev/null +++ b/internal/router/search.go @@ -0,0 +1,13 @@ +package router + +func registerSearchRoutes(cfg *Config) { + e := cfg.Echo + + // JWT middleware for protected routes + jwtMiddleware := createJWTMiddleware(cfg) + protected := e.Group("/api", jwtMiddleware) + + // Search and query endpoints (all authenticated users) + protected.GET("/media-items/search", cfg.MediaHandler.SearchMediaItems) + protected.POST("/sync/books/query", cfg.MatchingHandler.QueryBooks) +}