Add library-based scanning and media item endpoints
- Add POST /api/libraries/:id/scan endpoint for admin library scanning - Add GET /api/libraries/:id/media-items endpoint for library media items - Move /api/libraries/types to public endpoint (no auth required) - Update ScanEbooks handler to support library_id parameter
This commit is contained in:
+20
-4
@@ -115,6 +115,13 @@ func main() {
|
||||
|
||||
// Protected routes
|
||||
protected := e.Group("/api", jwtMiddleware)
|
||||
|
||||
// Setup ebook handler routes first (so we can use it for library scan)
|
||||
h := handlers.SetupRoutes(protected, queries)
|
||||
|
||||
// Public library types endpoint (no authentication required)
|
||||
e.GET("/api/libraries/types", libraryHandler.GetLibraryTypes)
|
||||
|
||||
protected.GET("/auth/profile", authHandler.GetProfile)
|
||||
protected.PUT("/auth/profile", authHandler.UpdateProfile)
|
||||
protected.POST("/auth/refresh", authHandler.RefreshAccessToken)
|
||||
@@ -126,7 +133,6 @@ func main() {
|
||||
|
||||
// Library management routes
|
||||
library := protected.Group("/libraries")
|
||||
library.GET("/types", libraryHandler.GetLibraryTypes)
|
||||
|
||||
// Admin-only library routes
|
||||
adminLibrary := library.Group("", handlers.AdminMiddleware)
|
||||
@@ -139,6 +145,19 @@ func main() {
|
||||
adminLibrary.GET("/:id/folders", libraryHandler.GetLibraryFolders)
|
||||
adminLibrary.DELETE("/:id/folders", libraryHandler.DeleteLibraryFolder)
|
||||
adminLibrary.GET("/:id/stats", libraryHandler.GetLibraryStats)
|
||||
adminLibrary.POST("/:id/scan", func(c echo.Context) error {
|
||||
libraryID := c.Param("id")
|
||||
scanReq := map[string]interface{}{
|
||||
"library_id": libraryID,
|
||||
}
|
||||
c.Set("scan_request", scanReq)
|
||||
return h.ScanEbooks(c)
|
||||
})
|
||||
adminLibrary.GET("/:id/media-items", func(c echo.Context) error {
|
||||
libraryID := c.Param("id")
|
||||
c.QueryParams().Set("library_id", libraryID)
|
||||
return h.ListMediaItems(c)
|
||||
})
|
||||
|
||||
// User library visibility control
|
||||
protected.POST("/libraries/visibility", libraryHandler.SetLibraryVisibility)
|
||||
@@ -173,9 +192,6 @@ func main() {
|
||||
// Static files
|
||||
e.Static("/static", "web/static")
|
||||
|
||||
// Routes
|
||||
h := handlers.SetupRoutes(protected, queries)
|
||||
|
||||
// Start scheduler for auto-scanning
|
||||
go h.StartScheduler()
|
||||
defer h.StopScheduler()
|
||||
|
||||
@@ -124,12 +124,22 @@ func SetupRoutes(g *echo.Group, db *database.Queries) *Handler {
|
||||
// ScanEbooksRequest represents the request for scanning ebooks
|
||||
type ScanEbooksRequest struct {
|
||||
FolderPaths []string `json:"folder_paths,omitempty"`
|
||||
LibraryID string `json:"library_id,omitempty"`
|
||||
}
|
||||
|
||||
// ScanEbooks handles POST /api/scanner/scan (now runs in background)
|
||||
func (h *Handler) ScanEbooks(c echo.Context) error {
|
||||
var req ScanEbooksRequest
|
||||
if err := c.Bind(&req); err != nil {
|
||||
|
||||
// Check if scan_request is set in context (from library scan route)
|
||||
if scanReq, ok := c.Get("scan_request").(map[string]interface{}); ok {
|
||||
if libraryID, ok := scanReq["library_id"].(string); ok {
|
||||
req.LibraryID = libraryID
|
||||
}
|
||||
}
|
||||
|
||||
// Bind request body if provided (for direct scanner/scan calls)
|
||||
if err := c.Bind(&req); err != nil && req.LibraryID == "" {
|
||||
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid request"})
|
||||
}
|
||||
|
||||
@@ -142,14 +152,33 @@ func (h *Handler) ScanEbooks(c echo.Context) error {
|
||||
|
||||
var folderPaths []string
|
||||
|
||||
// If folder paths provided in request, use them
|
||||
// Otherwise, use user's saved folders
|
||||
if len(req.FolderPaths) > 0 {
|
||||
// If library_id is provided, fetch folders from library
|
||||
if req.LibraryID != "" {
|
||||
libraryUUID, err := uuid.Parse(req.LibraryID)
|
||||
if err != nil {
|
||||
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid library id"})
|
||||
}
|
||||
|
||||
// Fetch library folders from database
|
||||
libraryFolders, err := h.db.GetLibraryFolders(c.Request().Context(), pgtype.UUID{Bytes: [16]byte(libraryUUID), Valid: true})
|
||||
if err != nil {
|
||||
return c.JSON(http.StatusNotFound, map[string]string{"error": "library not found or has no folders"})
|
||||
}
|
||||
|
||||
// Extract folder paths
|
||||
for _, folder := range libraryFolders {
|
||||
folderPaths = append(folderPaths, folder.FolderPath)
|
||||
}
|
||||
|
||||
if len(folderPaths) == 0 {
|
||||
return c.JSON(http.StatusBadRequest, map[string]string{"error": "library has no folders configured"})
|
||||
}
|
||||
} else if len(req.FolderPaths) > 0 {
|
||||
// Use folder paths from request
|
||||
folderPaths = req.FolderPaths
|
||||
} else {
|
||||
// TODO: Replace with library-based folder scanning
|
||||
// For now, require folder paths in request
|
||||
return c.JSON(http.StatusBadRequest, map[string]string{"error": "folder_paths required for scanning"})
|
||||
// Neither library_id nor folder_paths provided
|
||||
return c.JSON(http.StatusBadRequest, map[string]string{"error": "either library_id or folder_paths required for scanning"})
|
||||
}
|
||||
|
||||
jobID := uuid.New().String()
|
||||
@@ -158,7 +187,7 @@ func (h *Handler) ScanEbooks(c echo.Context) error {
|
||||
ID: jobID,
|
||||
Type: services.JobTypeScan,
|
||||
Params: map[string]interface{}{
|
||||
"library_id": userID,
|
||||
"library_id": req.LibraryID,
|
||||
"folders": folderPaths,
|
||||
"admin_id": userUUID.String(),
|
||||
"db": h.db,
|
||||
|
||||
Reference in New Issue
Block a user