Add preview endpoint for custom section builder and rule evaluation: Handler Implementation (internal/handlers/collections.go): - PreviewCollection method: Evaluates filter rules and returns matching items without saving * Accepts library_id, rules array, manual_book_ids array, and limit * Evaluates rules against all library items using collectionService.EvaluateRules * Adds manually selected books to results * Deduplicates manual books (avoids adding same book twice) * Applies limit (default: 20, max: 100) * Returns array of BookInfo with matching items - Helper function: mediaItemsToListMediaItemsRow * Converts database.MediaItems to database.ListMediaItemsRow * Required for EvaluateRules which expects ListMediaItemsRow type Route Registration (internal/router/collections.go): - POST /api/collections/preview - Protected by JWT middleware - Part of collections API group Why This Endpoint is Necessary: - Allows users to see what books match their filter rules BEFORE saving - Avoids creating incorrect collections - Enables testing different rule combinations quickly - Reuses existing service logic (collectionService.EvaluateRules) - Client-side preview would require downloading entire library (10,000+ books) - Would duplicate 500+ lines of rule evaluation logic in TypeScript - Would create maintenance nightmare keeping Go and TypeScript in sync Bruno Test (bruno/collections/preview-collection.bru): - Tests POST /api/collections/preview endpoint - Validates status 200 response - Validates items array in response - Example request with genre filter rule This endpoint is required for both the web UI Custom Section Builder and future mobile apps.
32 lines
1.5 KiB
Go
32 lines
1.5 KiB
Go
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)
|
|
collections.POST("/preview", cfg.CollectionHandler.PreviewCollection)
|
|
|
|
// 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)
|
|
}
|