refactor(handlers): update all handlers for Echo v5 compatibility

Update all handler functions to use *echo.Context (pointer) instead of echo.Context (value) as required by Echo v5.

Changes across all handler files:
- analytics.go: Update handler signatures
- auth.go: Update authentication handler signatures
- book_matching.go: Update matching handler signatures
- collections.go: Update collection handler signatures
- collections_preview_test.go: Update test signatures
- commonhandlers.go: Update common handler signatures
- conflicts.go: Update conflict handler signatures
- context.go: Update context handler signatures
- dashboard.go: Update dashboard handler signatures
- devices.go: Update device handler signatures
- jobs.go: Update job handler signatures
- kobo.go: Update Kobo handler signatures
- koreader.go: Update Koreader handler signatures
- library.go: Update library handler signatures
- matching.go: Update matching handler signatures
- media.go: Update media handler signatures
- opds.go: Update OPDS handler signatures
- progress.go: Update progress handler signatures
- queue.go: Update queue handler signatures
- refresh_token.go: Update token handler signatures
- scanner.go: Update scanner handler signatures
- sidecar.go: Update sidecar handler signatures
- sync.go: Update sync handler signatures
- system_settings.go: Update settings handler signatures
- websocket.go: Update WebSocket handler signatures

All handlers now properly implement Echo v5's pointer-based context pattern.
This change is necessary for type safety and compatibility with Echo v5's
improved context handling and WebSocket support.
This commit is contained in:
2026-03-06 14:00:28 -05:00
parent 784326e2c4
commit 1e05470fbb
25 changed files with 213 additions and 213 deletions
+4 -4
View File
@@ -10,7 +10,7 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
"github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgtype" "github.com/jackc/pgx/v5/pgtype"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v5"
) )
type AnalyticsHandler struct { type AnalyticsHandler struct {
@@ -67,7 +67,7 @@ type PopularBook struct {
LastRead string `json:"last_read"` LastRead string `json:"last_read"`
} }
func (h *AnalyticsHandler) GetReadingStats(c echo.Context) error { func (h *AnalyticsHandler) GetReadingStats(c *echo.Context) error {
user := c.Get("user").(database.Users) user := c.Get("user").(database.Users)
startDate := c.QueryParam("start_date") startDate := c.QueryParam("start_date")
@@ -205,7 +205,7 @@ func (h *AnalyticsHandler) calculateMostActiveDay(history []database.GetUserRead
return mostActive return mostActive
} }
func (h *AnalyticsHandler) GetDeviceUsage(c echo.Context) error { func (h *AnalyticsHandler) GetDeviceUsage(c *echo.Context) error {
user := c.Get("user").(database.Users) user := c.Get("user").(database.Users)
ctx := context.Background() ctx := context.Background()
@@ -243,7 +243,7 @@ func (h *AnalyticsHandler) GetDeviceUsage(c echo.Context) error {
}) })
} }
func (h *AnalyticsHandler) GetPopularBooks(c echo.Context) error { func (h *AnalyticsHandler) GetPopularBooks(c *echo.Context) error {
user := c.Get("user").(database.Users) user := c.Get("user").(database.Users)
limit := c.QueryParam("limit") limit := c.QueryParam("limit")
+13 -13
View File
@@ -16,7 +16,7 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
"github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgtype" "github.com/jackc/pgx/v5/pgtype"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v5"
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
) )
@@ -95,7 +95,7 @@ type AdminUpdateUserRequest struct {
} }
// Register handles POST /api/auth/register // Register handles POST /api/auth/register
func (h *AuthHandler) Register(c echo.Context) error { func (h *AuthHandler) Register(c *echo.Context) error {
email := c.FormValue("email") email := c.FormValue("email")
username := c.FormValue("username") username := c.FormValue("username")
password := c.FormValue("password") password := c.FormValue("password")
@@ -300,7 +300,7 @@ window.location.href = '/dashboard';
} }
// Login handles POST /api/auth/login // Login handles POST /api/auth/login
func (h *AuthHandler) Login(c echo.Context) error { func (h *AuthHandler) Login(c *echo.Context) error {
login := c.FormValue("login") login := c.FormValue("login")
password := c.FormValue("password") password := c.FormValue("password")
@@ -452,7 +452,7 @@ window.location.href = '%s';
} }
// GetProfile handles GET /api/auth/profile // GetProfile handles GET /api/auth/profile
func (h *AuthHandler) GetProfile(c echo.Context) error { func (h *AuthHandler) GetProfile(c *echo.Context) error {
user := MustGetAuthenticatedUser(c) user := MustGetAuthenticatedUser(c)
firstName := "" firstName := ""
@@ -475,7 +475,7 @@ func (h *AuthHandler) GetProfile(c echo.Context) error {
// UpdateProfile handles PUT /api/auth/profile (self-edit) and PUT /api/auth/profile/:id (admin edit) // UpdateProfile handles PUT /api/auth/profile (self-edit) and PUT /api/auth/profile/:id (admin edit)
// Combined handler for both self-service and admin profile updates // Combined handler for both self-service and admin profile updates
func (h *AuthHandler) UpdateProfile(c echo.Context) error { func (h *AuthHandler) UpdateProfile(c *echo.Context) error {
currentUser := MustGetAuthenticatedUser(c) currentUser := MustGetAuthenticatedUser(c)
// Determine target user: URL param (admin mode) or current user (self-edit) // Determine target user: URL param (admin mode) or current user (self-edit)
@@ -603,7 +603,7 @@ func (h *AuthHandler) UpdateProfile(c echo.Context) error {
} }
// ListUsers handles GET /api/auth/users // ListUsers handles GET /api/auth/users
func (h *AuthHandler) ListUsers(c echo.Context) error { func (h *AuthHandler) ListUsers(c *echo.Context) error {
users, err := h.db.ListUsers(c.Request().Context()) users, err := h.db.ListUsers(c.Request().Context())
if err != nil { if err != nil {
return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()}) return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
@@ -641,7 +641,7 @@ type UpdateThemeRequest struct {
} }
// UpdateTheme handles PUT /api/auth/theme // UpdateTheme handles PUT /api/auth/theme
func (h *AuthHandler) UpdateTheme(c echo.Context) error { func (h *AuthHandler) UpdateTheme(c *echo.Context) error {
user := MustGetAuthenticatedUser(c) user := MustGetAuthenticatedUser(c)
var req UpdateThemeRequest var req UpdateThemeRequest
@@ -668,7 +668,7 @@ type UpdateUsernameRequest struct {
} }
// UpdateUsername handles PUT /api/auth/username // UpdateUsername handles PUT /api/auth/username
func (h *AuthHandler) UpdateUsername(c echo.Context) error { func (h *AuthHandler) UpdateUsername(c *echo.Context) error {
user := MustGetAuthenticatedUser(c) user := MustGetAuthenticatedUser(c)
var req UpdateUsernameRequest var req UpdateUsernameRequest
@@ -702,7 +702,7 @@ type UpdateEmailRequest struct {
} }
// UpdateEmail handles PUT /api/auth/email // UpdateEmail handles PUT /api/auth/email
func (h *AuthHandler) UpdateEmail(c echo.Context) error { func (h *AuthHandler) UpdateEmail(c *echo.Context) error {
user := MustGetAuthenticatedUser(c) user := MustGetAuthenticatedUser(c)
var req UpdateEmailRequest var req UpdateEmailRequest
@@ -739,7 +739,7 @@ type UpdatePasswordRequest struct {
// UpdatePassword handles PUT /api/auth/password (self-change) and PUT /api/auth/password/:id (admin reset) // UpdatePassword handles PUT /api/auth/password (self-change) and PUT /api/auth/password/:id (admin reset)
// Combined handler for both self-service password change and admin password reset // Combined handler for both self-service password change and admin password reset
func (h *AuthHandler) UpdatePassword(c echo.Context) error { func (h *AuthHandler) UpdatePassword(c *echo.Context) error {
currentUser := MustGetAuthenticatedUser(c) currentUser := MustGetAuthenticatedUser(c)
// Determine target user: URL param (admin mode) or current user (self-change) // Determine target user: URL param (admin mode) or current user (self-change)
@@ -820,7 +820,7 @@ func (h *AuthHandler) UpdatePassword(c echo.Context) error {
// DeleteUser handles DELETE /api/auth/profile (self-deletion) and DELETE /api/auth/profile/:id (admin deletion) // DeleteUser handles DELETE /api/auth/profile (self-deletion) and DELETE /api/auth/profile/:id (admin deletion)
// Combined handler for both self-deletion and admin deletion of users // Combined handler for both self-deletion and admin deletion of users
func (h *AuthHandler) DeleteUser(c echo.Context) error { func (h *AuthHandler) DeleteUser(c *echo.Context) error {
currentUser := MustGetAuthenticatedUser(c) currentUser := MustGetAuthenticatedUser(c)
// Get target user ID from URL param (admin mode) or use current user (self-deletion) // Get target user ID from URL param (admin mode) or use current user (self-deletion)
@@ -912,7 +912,7 @@ type UpdateUserMaxDevicesRequest struct {
} }
// UpdateUserMaxDevices handles PUT /api/auth/users/:id/max-devices (admin only) // UpdateUserMaxDevices handles PUT /api/auth/users/:id/max-devices (admin only)
func (h *AuthHandler) UpdateUserMaxDevices(c echo.Context) error { func (h *AuthHandler) UpdateUserMaxDevices(c *echo.Context) error {
userID := c.Param("id") userID := c.Param("id")
if userID == "" { if userID == "" {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "user id required"}) return c.JSON(http.StatusBadRequest, map[string]string{"error": "user id required"})
@@ -949,7 +949,7 @@ func (h *AuthHandler) UpdateUserMaxDevices(c echo.Context) error {
// AdminMiddleware checks if the user has admin role // AdminMiddleware checks if the user has admin role
func AdminMiddleware(next echo.HandlerFunc) echo.HandlerFunc { func AdminMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error { return func(c *echo.Context) error {
userRole, exists := c.Get("user_role").(string) userRole, exists := c.Get("user_role").(string)
if !exists || userRole != "admin" { if !exists || userRole != "admin" {
return c.JSON(http.StatusForbidden, map[string]string{"error": "admin access required"}) return c.JSON(http.StatusForbidden, map[string]string{"error": "admin access required"})
+12 -12
View File
@@ -9,7 +9,7 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
"github.com/jackc/pgx/v5/pgtype" "github.com/jackc/pgx/v5/pgtype"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v5"
) )
// Book matching service (added to Handler struct in scanner.go initialization) // Book matching service (added to Handler struct in scanner.go initialization)
@@ -40,7 +40,7 @@ func toFloat8(f float64) pgtype.Float8 {
} }
// QueryBooks handles POST /api/sync/books/query // QueryBooks handles POST /api/sync/books/query
func (h *Handler) QueryBooks(c echo.Context) error { func (h *Handler) QueryBooks(c *echo.Context) error {
matchingService := h.getMatchingService() matchingService := h.getMatchingService()
var req services.BookQueryRequest var req services.BookQueryRequest
@@ -61,7 +61,7 @@ func (h *Handler) QueryBooks(c echo.Context) error {
} }
// LinkBook handles POST /api/sync/link-book // LinkBook handles POST /api/sync/link-book
func (h *Handler) LinkBook(c echo.Context) error { func (h *Handler) LinkBook(c *echo.Context) error {
matchingService := h.getMatchingService() matchingService := h.getMatchingService()
var req services.LinkBookRequest var req services.LinkBookRequest
@@ -101,7 +101,7 @@ func (h *Handler) LinkBook(c echo.Context) error {
} }
// GetUnlinkedBooks handles GET /api/sync/unlinked-books // GetUnlinkedBooks handles GET /api/sync/unlinked-books
func (h *Handler) GetUnlinkedBooks(c echo.Context) error { func (h *Handler) GetUnlinkedBooks(c *echo.Context) error {
matchingService := h.getMatchingService() matchingService := h.getMatchingService()
deviceIDStr := c.Param("deviceId") deviceIDStr := c.Param("deviceId")
@@ -126,7 +126,7 @@ func (h *Handler) GetUnlinkedBooks(c echo.Context) error {
} }
// GetDeviceFileAliases handles GET /api/devices/:id/file-aliases // GetDeviceFileAliases handles GET /api/devices/:id/file-aliases
func (h *Handler) GetDeviceFileAliases(c echo.Context) error { func (h *Handler) GetDeviceFileAliases(c *echo.Context) error {
deviceIDStr := c.Param("id") deviceIDStr := c.Param("id")
deviceID, err := uuid.Parse(deviceIDStr) deviceID, err := uuid.Parse(deviceIDStr)
if err != nil { if err != nil {
@@ -172,7 +172,7 @@ func (h *Handler) GetDeviceFileAliases(c echo.Context) error {
} }
// BulkLinkBooks handles POST /api/sync/bulk-link-books // BulkLinkBooks handles POST /api/sync/bulk-link-books
func (h *Handler) BulkLinkBooks(c echo.Context) error { func (h *Handler) BulkLinkBooks(c *echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
var req BulkLinkBooksRequest var req BulkLinkBooksRequest
@@ -250,7 +250,7 @@ func (h *Handler) BulkLinkBooks(c echo.Context) error {
} }
// AutoLinkBooks handles POST /api/sync/auto-link-books // AutoLinkBooks handles POST /api/sync/auto-link-books
func (h *Handler) AutoLinkBooks(c echo.Context) error { func (h *Handler) AutoLinkBooks(c *echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
matchingService := h.getMatchingService() matchingService := h.getMatchingService()
@@ -326,7 +326,7 @@ func (h *Handler) AutoLinkBooks(c echo.Context) error {
} }
// GetUnlinkedBookSuggestions handles GET /api/sync/unlinked-books/:id/suggestions // GetUnlinkedBookSuggestions handles GET /api/sync/unlinked-books/:id/suggestions
func (h *Handler) GetUnlinkedBookSuggestions(c echo.Context) error { func (h *Handler) GetUnlinkedBookSuggestions(c *echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
matchingService := h.getMatchingService() matchingService := h.getMatchingService()
@@ -366,7 +366,7 @@ func (h *Handler) GetUnlinkedBookSuggestions(c echo.Context) error {
} }
// CreateDeviceFileAlias handles POST /api/devices/:id/file-aliases // CreateDeviceFileAlias handles POST /api/devices/:id/file-aliases
func (h *Handler) CreateDeviceFileAlias(c echo.Context) error { func (h *Handler) CreateDeviceFileAlias(c *echo.Context) error {
deviceIDStr := c.Param("id") deviceIDStr := c.Param("id")
deviceID, err := uuid.Parse(deviceIDStr) deviceID, err := uuid.Parse(deviceIDStr)
if err != nil { if err != nil {
@@ -421,7 +421,7 @@ func (h *Handler) CreateDeviceFileAlias(c echo.Context) error {
} }
// UpdateDeviceFileAlias handles PUT /api/devices/:id/file-aliases/:aliasId // UpdateDeviceFileAlias handles PUT /api/devices/:id/file-aliases/:aliasId
func (h *Handler) UpdateDeviceFileAlias(c echo.Context) error { func (h *Handler) UpdateDeviceFileAlias(c *echo.Context) error {
aliasIDStr := c.Param("aliasId") aliasIDStr := c.Param("aliasId")
aliasID, err := uuid.Parse(aliasIDStr) aliasID, err := uuid.Parse(aliasIDStr)
if err != nil { if err != nil {
@@ -488,7 +488,7 @@ func (h *Handler) UpdateDeviceFileAlias(c echo.Context) error {
} }
// DeleteDeviceFileAlias handles DELETE /api/devices/:id/file-aliases/:aliasId // DeleteDeviceFileAlias handles DELETE /api/devices/:id/file-aliases/:aliasId
func (h *Handler) DeleteDeviceFileAlias(c echo.Context) error { func (h *Handler) DeleteDeviceFileAlias(c *echo.Context) error {
aliasIDStr := c.Param("aliasId") aliasIDStr := c.Param("aliasId")
aliasID, err := uuid.Parse(aliasIDStr) aliasID, err := uuid.Parse(aliasIDStr)
if err != nil { if err != nil {
@@ -510,7 +510,7 @@ func (h *Handler) DeleteDeviceFileAlias(c echo.Context) error {
} }
// GetBookMatches handles GET /api/books/match // GetBookMatches handles GET /api/books/match
func (h *Handler) GetBookMatches(c echo.Context) error { func (h *Handler) GetBookMatches(c *echo.Context) error {
matchingService := h.getMatchingService() matchingService := h.getMatchingService()
// Get query parameters // Get query parameters
+22 -22
View File
@@ -15,7 +15,7 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
"github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgtype" "github.com/jackc/pgx/v5/pgtype"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v5"
) )
type CollectionHandler struct { type CollectionHandler struct {
@@ -86,7 +86,7 @@ type SectionData struct {
Priority int `json:"priority"` Priority int `json:"priority"`
} }
func (h *CollectionHandler) CreateCollection(c echo.Context) error { func (h *CollectionHandler) CreateCollection(c *echo.Context) error {
user := c.Get("user").(database.Users) user := c.Get("user").(database.Users)
userUUID := uuid.UUID(user.ID.Bytes) userUUID := uuid.UUID(user.ID.Bytes)
@@ -134,7 +134,7 @@ func (h *CollectionHandler) CreateCollection(c echo.Context) error {
return c.JSON(http.StatusCreated, response) return c.JSON(http.StatusCreated, response)
} }
func (h *CollectionHandler) GetCollections(c echo.Context) error { func (h *CollectionHandler) GetCollections(c *echo.Context) error {
includeAuto := c.QueryParam("include_auto") == "true" includeAuto := c.QueryParam("include_auto") == "true"
sortBy := c.QueryParam("sort_by") sortBy := c.QueryParam("sort_by")
@@ -185,7 +185,7 @@ func (h *CollectionHandler) GetCollections(c echo.Context) error {
}) })
} }
func (h *CollectionHandler) GetCollection(c echo.Context) error { func (h *CollectionHandler) GetCollection(c *echo.Context) error {
collectionID, err := uuid.Parse(c.Param("id")) collectionID, err := uuid.Parse(c.Param("id"))
if err != nil { if err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid collection id"}) return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid collection id"})
@@ -231,7 +231,7 @@ func (h *CollectionHandler) GetCollection(c echo.Context) error {
}) })
} }
func (h *CollectionHandler) UpdateCollection(c echo.Context) error { func (h *CollectionHandler) UpdateCollection(c *echo.Context) error {
collectionID, err := uuid.Parse(c.Param("id")) collectionID, err := uuid.Parse(c.Param("id"))
if err != nil { if err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid collection id"}) return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid collection id"})
@@ -279,7 +279,7 @@ func (h *CollectionHandler) UpdateCollection(c echo.Context) error {
return c.JSON(http.StatusCreated, response) return c.JSON(http.StatusCreated, response)
} }
func (h *CollectionHandler) DeleteCollection(c echo.Context) error { func (h *CollectionHandler) DeleteCollection(c *echo.Context) error {
collectionID, err := uuid.Parse(c.Param("id")) collectionID, err := uuid.Parse(c.Param("id"))
if err != nil { if err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid collection id"}) return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid collection id"})
@@ -298,7 +298,7 @@ func (h *CollectionHandler) DeleteCollection(c echo.Context) error {
return c.NoContent(http.StatusNoContent) return c.NoContent(http.StatusNoContent)
} }
func (h *CollectionHandler) AddBooks(c echo.Context) error { func (h *CollectionHandler) AddBooks(c *echo.Context) error {
collectionID, err := uuid.Parse(c.Param("id")) collectionID, err := uuid.Parse(c.Param("id"))
if err != nil { if err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid collection id"}) return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid collection id"})
@@ -345,7 +345,7 @@ func (h *CollectionHandler) AddBooks(c echo.Context) error {
return c.NoContent(http.StatusNoContent) return c.NoContent(http.StatusNoContent)
} }
func (h *CollectionHandler) RemoveBook(c echo.Context) error { func (h *CollectionHandler) RemoveBook(c *echo.Context) error {
collectionID, err := uuid.Parse(c.Param("id")) collectionID, err := uuid.Parse(c.Param("id"))
if err != nil { if err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid collection id"}) return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid collection id"})
@@ -385,7 +385,7 @@ type BulkRemoveBooksRequest struct {
BookIDs []string `json:"book_ids" validate:"required"` BookIDs []string `json:"book_ids" validate:"required"`
} }
func (h *CollectionHandler) BulkRemoveBooks(c echo.Context) error { func (h *CollectionHandler) BulkRemoveBooks(c *echo.Context) error {
collectionID, err := uuid.Parse(c.Param("id")) collectionID, err := uuid.Parse(c.Param("id"))
if err != nil { if err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid collection id"}) return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid collection id"})
@@ -436,7 +436,7 @@ func (h *CollectionHandler) BulkRemoveBooks(c echo.Context) error {
}) })
} }
func (h *CollectionHandler) GetDeviceMappings(c echo.Context) error { func (h *CollectionHandler) GetDeviceMappings(c *echo.Context) error {
deviceID, err := uuid.Parse(c.Param("id")) deviceID, err := uuid.Parse(c.Param("id"))
if err != nil { if err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid device id"}) return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid device id"})
@@ -475,7 +475,7 @@ func (h *CollectionHandler) GetDeviceMappings(c echo.Context) error {
}) })
} }
func (h *CollectionHandler) CreateDeviceMapping(c echo.Context) error { func (h *CollectionHandler) CreateDeviceMapping(c *echo.Context) error {
deviceID, err := uuid.Parse(c.Param("id")) deviceID, err := uuid.Parse(c.Param("id"))
if err != nil { if err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid device id"}) return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid device id"})
@@ -515,7 +515,7 @@ func (h *CollectionHandler) CreateDeviceMapping(c echo.Context) error {
}) })
} }
func (h *CollectionHandler) UpdateDeviceMapping(c echo.Context) error { func (h *CollectionHandler) UpdateDeviceMapping(c *echo.Context) error {
mappingID, err := uuid.Parse(c.Param("mappingId")) mappingID, err := uuid.Parse(c.Param("mappingId"))
if err != nil { if err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid mapping id"}) return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid mapping id"})
@@ -549,7 +549,7 @@ func (h *CollectionHandler) UpdateDeviceMapping(c echo.Context) error {
}) })
} }
func (h *CollectionHandler) DeleteDeviceMapping(c echo.Context) error { func (h *CollectionHandler) DeleteDeviceMapping(c *echo.Context) error {
mappingID, err := uuid.Parse(c.Param("mappingId")) mappingID, err := uuid.Parse(c.Param("mappingId"))
if err != nil { if err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid mapping id"}) return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid mapping id"})
@@ -563,7 +563,7 @@ func (h *CollectionHandler) DeleteDeviceMapping(c echo.Context) error {
return c.NoContent(http.StatusNoContent) return c.NoContent(http.StatusNoContent)
} }
func (h *CollectionHandler) GetBookCollections(c echo.Context) error { func (h *CollectionHandler) GetBookCollections(c *echo.Context) error {
bookID, err := uuid.Parse(c.Param("id")) bookID, err := uuid.Parse(c.Param("id"))
if err != nil { if err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid book id"}) return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid book id"})
@@ -607,25 +607,25 @@ func textToString(t pgtype.Text) string {
return "" return ""
} }
func (h *CollectionHandler) GetCollectionsData(c echo.Context) ([]database.Collections, error) { func (h *CollectionHandler) GetCollectionsData(c *echo.Context) ([]database.Collections, error) {
user := c.Get("user").(database.Users) user := c.Get("user").(database.Users)
userUUID := uuid.UUID(user.ID.Bytes) userUUID := uuid.UUID(user.ID.Bytes)
return h.collectionService.GetUserCollections(c.Request().Context(), userUUID) return h.collectionService.GetUserCollections(c.Request().Context(), userUUID)
} }
func (h *CollectionHandler) GetCollectionData(c echo.Context, collectionID uuid.UUID) (database.Collections, error) { func (h *CollectionHandler) GetCollectionData(c *echo.Context, collectionID uuid.UUID) (database.Collections, error) {
return h.collectionService.GetCollection(c.Request().Context(), collectionID) return h.collectionService.GetCollection(c.Request().Context(), collectionID)
} }
func (h *CollectionHandler) GetCollectionBooksData(c echo.Context, collectionID uuid.UUID) ([]database.GetCollectionItemsRow, error) { func (h *CollectionHandler) GetCollectionBooksData(c *echo.Context, collectionID uuid.UUID) ([]database.GetCollectionItemsRow, error) {
return h.collectionService.GetCollectionBooks(c.Request().Context(), collectionID) return h.collectionService.GetCollectionBooks(c.Request().Context(), collectionID)
} }
func (h *CollectionHandler) GetDeviceMappingsData(c echo.Context, deviceID uuid.UUID) ([]database.GetDeviceShelfMappingsRow, error) { func (h *CollectionHandler) GetDeviceMappingsData(c *echo.Context, deviceID uuid.UUID) ([]database.GetDeviceShelfMappingsRow, error) {
return h.collectionService.GetDeviceShelfMappings(c.Request().Context(), deviceID) return h.collectionService.GetDeviceShelfMappings(c.Request().Context(), deviceID)
} }
func (h *CollectionHandler) GetUserCollectionsList(c echo.Context) ([]database.Collections, error) { func (h *CollectionHandler) GetUserCollectionsList(c *echo.Context) ([]database.Collections, error) {
user := c.Get("user").(database.Users) user := c.Get("user").(database.Users)
userUUID := uuid.UUID(user.ID.Bytes) userUUID := uuid.UUID(user.ID.Bytes)
return h.collectionService.GetUserCollections(c.Request().Context(), userUUID) return h.collectionService.GetUserCollections(c.Request().Context(), userUUID)
@@ -643,7 +643,7 @@ type BookMatch struct {
MatchReason string `json:"match_reason"` MatchReason string `json:"match_reason"`
} }
func (h *CollectionHandler) TestRules(c echo.Context) error { func (h *CollectionHandler) TestRules(c *echo.Context) error {
var req TestRulesRequest var req TestRulesRequest
if err := c.Bind(&req); err != nil { if err := c.Bind(&req); err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid request"}) return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid request"})
@@ -771,7 +771,7 @@ func (h *CollectionHandler) compareValues(itemValue, operator, ruleValue string)
// POST /api/collections/bulk-add-books // POST /api/collections/bulk-add-books
// Bulk add books to multiple collections // Bulk add books to multiple collections
func (h *CollectionHandler) HandleBulkAddBooks(c echo.Context) error { func (h *CollectionHandler) HandleBulkAddBooks(c *echo.Context) error {
user := c.Get("user").(database.Users) user := c.Get("user").(database.Users)
userUUID := uuid.UUID(user.ID.Bytes) userUUID := uuid.UUID(user.ID.Bytes)
@@ -867,7 +867,7 @@ func (h *CollectionHandler) HandleBulkAddBooks(c echo.Context) error {
}) })
} }
func (h *CollectionHandler) PreviewCollection(c echo.Context) error { func (h *CollectionHandler) PreviewCollection(c *echo.Context) error {
user := c.Get("user") user := c.Get("user")
if user == nil { if user == nil {
return c.JSON(http.StatusUnauthorized, map[string]string{"error": "unauthorized"}) return c.JSON(http.StatusUnauthorized, map[string]string{"error": "unauthorized"})
@@ -11,7 +11,7 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
"github.com/jackc/pgx/v5/pgtype" "github.com/jackc/pgx/v5/pgtype"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v5"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
+1 -1
View File
@@ -9,7 +9,7 @@ import (
"sync" "sync"
"time" "time"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v5"
) )
type Handler struct { type Handler struct {
+9 -9
View File
@@ -11,7 +11,7 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
"github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgtype" "github.com/jackc/pgx/v5/pgtype"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v5"
) )
type ConflictHandler struct { type ConflictHandler struct {
@@ -64,7 +64,7 @@ type ConflictResolveResponse struct {
DevicesSynced []string `json:"devices_synced"` DevicesSynced []string `json:"devices_synced"`
} }
func (h *ConflictHandler) GetConflictsData(c echo.Context) ([]ConflictDetailResponse, int, int, error) { func (h *ConflictHandler) GetConflictsData(c *echo.Context) ([]ConflictDetailResponse, int, int, error) {
user := c.Get("user").(database.Users) user := c.Get("user").(database.Users)
status := c.QueryParam("status") status := c.QueryParam("status")
@@ -126,7 +126,7 @@ func (h *ConflictHandler) GetConflictsData(c echo.Context) ([]ConflictDetailResp
return response, len(response), unresolvedCount, nil return response, len(response), unresolvedCount, nil
} }
func (h *ConflictHandler) ListConflicts(c echo.Context) error { func (h *ConflictHandler) ListConflicts(c *echo.Context) error {
conflicts, total, unresolved, err := h.GetConflictsData(c) conflicts, total, unresolved, err := h.GetConflictsData(c)
if err != nil { if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "failed to list conflicts") return echo.NewHTTPError(http.StatusInternalServerError, "failed to list conflicts")
@@ -139,7 +139,7 @@ func (h *ConflictHandler) ListConflicts(c echo.Context) error {
}) })
} }
func (h *ConflictHandler) GetConflict(c echo.Context) error { func (h *ConflictHandler) GetConflict(c *echo.Context) error {
user := c.Get("user").(database.Users) user := c.Get("user").(database.Users)
conflictID, err := uuid.Parse(c.Param("id")) conflictID, err := uuid.Parse(c.Param("id"))
@@ -194,7 +194,7 @@ func (h *ConflictHandler) GetConflict(c echo.Context) error {
return c.JSON(http.StatusOK, detail) return c.JSON(http.StatusOK, detail)
} }
func (h *ConflictHandler) ResolveConflict(c echo.Context) error { func (h *ConflictHandler) ResolveConflict(c *echo.Context) error {
user := c.Get("user").(database.Users) user := c.Get("user").(database.Users)
conflictID, err := uuid.Parse(c.Param("id")) conflictID, err := uuid.Parse(c.Param("id"))
@@ -365,7 +365,7 @@ func (h *ConflictHandler) notifyDevicesOfResolution(mediaItemID pgtype.UUID, dat
return synced return synced
} }
func (h *ConflictHandler) DeleteConflict(c echo.Context) error { func (h *ConflictHandler) DeleteConflict(c *echo.Context) error {
user := c.Get("user").(database.Users) user := c.Get("user").(database.Users)
conflictID, err := uuid.Parse(c.Param("id")) conflictID, err := uuid.Parse(c.Param("id"))
@@ -393,7 +393,7 @@ func (h *ConflictHandler) DeleteConflict(c echo.Context) error {
return c.NoContent(http.StatusNoContent) return c.NoContent(http.StatusNoContent)
} }
func (h *ConflictHandler) DismissAllResolved(c echo.Context) error { func (h *ConflictHandler) DismissAllResolved(c *echo.Context) error {
user := c.Get("user").(database.Users) user := c.Get("user").(database.Users)
conflicts, err := h.db.ListSyncConflictsByUser(context.Background(), user.ID) conflicts, err := h.db.ListSyncConflictsByUser(context.Background(), user.ID)
@@ -435,7 +435,7 @@ type ConflictResult struct {
Winner string `json:"winner,omitempty"` Winner string `json:"winner,omitempty"`
} }
func (h *ConflictHandler) BulkResolveConflicts(c echo.Context) error { func (h *ConflictHandler) BulkResolveConflicts(c *echo.Context) error {
user := c.Get("user").(database.Users) user := c.Get("user").(database.Users)
var req BulkResolveRequest var req BulkResolveRequest
@@ -694,7 +694,7 @@ func (h *ConflictHandler) applyResolution(mediaItemID pgtype.UUID, userID pgtype
return err return err
} }
func (h *ConflictHandler) BulkDismissConflicts(c echo.Context) error { func (h *ConflictHandler) BulkDismissConflicts(c *echo.Context) error {
user := c.Get("user").(database.Users) user := c.Get("user").(database.Users)
var req struct { var req struct {
+3 -3
View File
@@ -4,12 +4,12 @@ import (
"bookhoard/internal/database" "bookhoard/internal/database"
"net/http" "net/http"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v5"
) )
// GetAuthenticatedUser safely retrieves the authenticated user from context // GetAuthenticatedUser safely retrieves the authenticated user from context
// Returns an error if the user is not found in context or type assertion fails // Returns an error if the user is not found in context or type assertion fails
func GetAuthenticatedUser(c echo.Context) (database.Users, error) { func GetAuthenticatedUser(c *echo.Context) (database.Users, error) {
user, ok := c.Get("user").(database.Users) user, ok := c.Get("user").(database.Users)
if !ok { if !ok {
return database.Users{}, echo.NewHTTPError(http.StatusInternalServerError, "authentication context error") return database.Users{}, echo.NewHTTPError(http.StatusInternalServerError, "authentication context error")
@@ -20,7 +20,7 @@ func GetAuthenticatedUser(c echo.Context) (database.Users, error) {
// MustGetAuthenticatedUser gets user or panics // MustGetAuthenticatedUser gets user or panics
// Only use this after authentication middleware has verified the user // Only use this after authentication middleware has verified the user
// Panicking here indicates a serious bug in the middleware chain // Panicking here indicates a serious bug in the middleware chain
func MustGetAuthenticatedUser(c echo.Context) database.Users { func MustGetAuthenticatedUser(c *echo.Context) database.Users {
user, err := GetAuthenticatedUser(c) user, err := GetAuthenticatedUser(c)
if err != nil { if err != nil {
panic(err) // Should never happen if authentication middleware is working correctly panic(err) // Should never happen if authentication middleware is working correctly
+5 -5
View File
@@ -10,7 +10,7 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
"github.com/jackc/pgx/v5/pgtype" "github.com/jackc/pgx/v5/pgtype"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v5"
) )
type DashboardHandler struct { type DashboardHandler struct {
@@ -25,7 +25,7 @@ func NewDashboardHandler(db *database.Queries) *DashboardHandler {
} }
} }
func (h *DashboardHandler) GetSections(c echo.Context) error { func (h *DashboardHandler) GetSections(c *echo.Context) error {
user := c.Get("user").(database.Users) user := c.Get("user").(database.Users)
userUUID := uuid.UUID(user.ID.Bytes) userUUID := uuid.UUID(user.ID.Bytes)
@@ -67,7 +67,7 @@ func (h *DashboardHandler) GetSections(c echo.Context) error {
return c.JSON(http.StatusOK, map[string]interface{}{"sections": sectionData}) return c.JSON(http.StatusOK, map[string]interface{}{"sections": sectionData})
} }
func (h *DashboardHandler) UpdatePreferences(c echo.Context) error { func (h *DashboardHandler) UpdatePreferences(c *echo.Context) error {
user := c.Get("user").(database.Users) user := c.Get("user").(database.Users)
userUUID := uuid.UUID(user.ID.Bytes) userUUID := uuid.UUID(user.ID.Bytes)
@@ -107,7 +107,7 @@ func (h *DashboardHandler) UpdatePreferences(c echo.Context) error {
return c.JSON(http.StatusOK, prefs) return c.JSON(http.StatusOK, prefs)
} }
func (h *DashboardHandler) RestoreSystemCollection(c echo.Context) error { func (h *DashboardHandler) RestoreSystemCollection(c *echo.Context) error {
user := c.Get("user").(database.Users) user := c.Get("user").(database.Users)
userUUID := uuid.UUID(user.ID.Bytes) userUUID := uuid.UUID(user.ID.Bytes)
@@ -196,7 +196,7 @@ func getViewAllURL(collectionID string, libraryID string) string {
return "" return ""
} }
func (h *DashboardHandler) GetPreferences(c echo.Context) error { func (h *DashboardHandler) GetPreferences(c *echo.Context) error {
user := c.Get("user").(database.Users) user := c.Get("user").(database.Users)
userUUID := uuid.UUID(user.ID.Bytes) userUUID := uuid.UUID(user.ID.Bytes)
libraryID := c.QueryParam("library_id") libraryID := c.QueryParam("library_id")
+13 -13
View File
@@ -12,7 +12,7 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
"github.com/jackc/pgx/v5/pgtype" "github.com/jackc/pgx/v5/pgtype"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v5"
"github.com/skip2/go-qrcode" "github.com/skip2/go-qrcode"
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
) )
@@ -104,7 +104,7 @@ type PendingRegistration struct {
var pendingRegistrations = make(map[string]*PendingRegistration) var pendingRegistrations = make(map[string]*PendingRegistration)
func (h *DeviceHandler) InitiateRegistration(c echo.Context) error { func (h *DeviceHandler) InitiateRegistration(c *echo.Context) error {
req := DeviceRegistrationRequest{} req := DeviceRegistrationRequest{}
if err := c.Bind(&req); err != nil { if err := c.Bind(&req); err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid request format"}) return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid request format"})
@@ -157,7 +157,7 @@ func (h *DeviceHandler) InitiateRegistration(c echo.Context) error {
return c.JSON(http.StatusCreated, response) return c.JSON(http.StatusCreated, response)
} }
func (h *DeviceHandler) CheckRegistrationStatus(c echo.Context) error { func (h *DeviceHandler) CheckRegistrationStatus(c *echo.Context) error {
req := DeviceAuthStatusRequest{} req := DeviceAuthStatusRequest{}
if err := c.Bind(&req); err != nil { if err := c.Bind(&req); err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid request format"}) return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid request format"})
@@ -230,7 +230,7 @@ func (h *DeviceHandler) CheckRegistrationStatus(c echo.Context) error {
}) })
} }
func (h *DeviceHandler) ListDevices(c echo.Context) error { func (h *DeviceHandler) ListDevices(c *echo.Context) error {
userID := c.Get("user_id").(string) userID := c.Get("user_id").(string)
userUUID, err := uuid.Parse(userID) userUUID, err := uuid.Parse(userID)
if err != nil { if err != nil {
@@ -274,7 +274,7 @@ func (h *DeviceHandler) ListDevices(c echo.Context) error {
}) })
} }
func (h *DeviceHandler) GetDevicesData(c echo.Context) ([]DeviceInfo, error) { func (h *DeviceHandler) GetDevicesData(c *echo.Context) ([]DeviceInfo, error) {
userID := c.Get("user_id").(string) userID := c.Get("user_id").(string)
userUUID, err := uuid.Parse(userID) userUUID, err := uuid.Parse(userID)
if err != nil { if err != nil {
@@ -315,7 +315,7 @@ func (h *DeviceHandler) GetDevicesData(c echo.Context) ([]DeviceInfo, error) {
return deviceList, nil return deviceList, nil
} }
func (h *DeviceHandler) GetDevice(c echo.Context) error { func (h *DeviceHandler) GetDevice(c *echo.Context) error {
userID := c.Get("user_id") userID := c.Get("user_id")
if userID == nil { if userID == nil {
return c.JSON(http.StatusUnauthorized, map[string]string{"error": "unauthorized"}) return c.JSON(http.StatusUnauthorized, map[string]string{"error": "unauthorized"})
@@ -363,7 +363,7 @@ func (h *DeviceHandler) GetDevice(c echo.Context) error {
}) })
} }
func (h *DeviceHandler) UpdateDevice(c echo.Context) error { func (h *DeviceHandler) UpdateDevice(c *echo.Context) error {
userID := c.Get("user_id").(string) userID := c.Get("user_id").(string)
userUUID, err := uuid.Parse(userID) userUUID, err := uuid.Parse(userID)
if err != nil { if err != nil {
@@ -458,7 +458,7 @@ func (h *DeviceHandler) UpdateDevice(c echo.Context) error {
}) })
} }
func (h *DeviceHandler) DeleteDevice(c echo.Context) error { func (h *DeviceHandler) DeleteDevice(c *echo.Context) error {
userID := c.Get("user_id").(string) userID := c.Get("user_id").(string)
userUUID, err := uuid.Parse(userID) userUUID, err := uuid.Parse(userID)
if err != nil { if err != nil {
@@ -488,7 +488,7 @@ func (h *DeviceHandler) DeleteDevice(c echo.Context) error {
return c.NoContent(http.StatusNoContent) return c.NoContent(http.StatusNoContent)
} }
func (h *DeviceHandler) RegenerateDeviceToken(c echo.Context) error { func (h *DeviceHandler) RegenerateDeviceToken(c *echo.Context) error {
// Verify JWT authentication // Verify JWT authentication
userID := c.Get("user_id").(string) userID := c.Get("user_id").(string)
userUUID, err := uuid.Parse(userID) userUUID, err := uuid.Parse(userID)
@@ -573,7 +573,7 @@ func (h *DeviceHandler) RegenerateDeviceToken(c echo.Context) error {
}) })
} }
func (h *DeviceHandler) ApproveDevice(c echo.Context) error { func (h *DeviceHandler) ApproveDevice(c *echo.Context) error {
userID := c.Get("user_id").(string) userID := c.Get("user_id").(string)
userUUID, err := uuid.Parse(userID) userUUID, err := uuid.Parse(userID)
if err != nil { if err != nil {
@@ -603,7 +603,7 @@ func (h *DeviceHandler) ApproveDevice(c echo.Context) error {
}) })
} }
func (h *DeviceHandler) RejectDevice(c echo.Context) error { func (h *DeviceHandler) RejectDevice(c *echo.Context) error {
registrationID := c.Param("registration_id") registrationID := c.Param("registration_id")
_, exists := pendingRegistrations[registrationID] _, exists := pendingRegistrations[registrationID]
@@ -618,7 +618,7 @@ func (h *DeviceHandler) RejectDevice(c echo.Context) error {
}) })
} }
func (h *DeviceHandler) GetPendingRegistrationsData(c echo.Context) ([]map[string]interface{}, error) { func (h *DeviceHandler) GetPendingRegistrationsData(c *echo.Context) ([]map[string]interface{}, error) {
userID := c.Get("user_id").(string) userID := c.Get("user_id").(string)
userUUID, err := uuid.Parse(userID) userUUID, err := uuid.Parse(userID)
if err != nil { if err != nil {
@@ -643,7 +643,7 @@ func (h *DeviceHandler) GetPendingRegistrationsData(c echo.Context) ([]map[strin
return registrations, nil return registrations, nil
} }
func (h *DeviceHandler) ListPendingRegistrations(c echo.Context) error { func (h *DeviceHandler) ListPendingRegistrations(c *echo.Context) error {
userID := c.Get("user_id").(string) userID := c.Get("user_id").(string)
userUUID, err := uuid.Parse(userID) userUUID, err := uuid.Parse(userID)
if err != nil { if err != nil {
+3 -3
View File
@@ -4,7 +4,7 @@ import (
"net/http" "net/http"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v5"
"bookhoard/internal/database" "bookhoard/internal/database"
"bookhoard/internal/services" "bookhoard/internal/services"
@@ -23,7 +23,7 @@ func NewJobsHandler(db *database.Queries, worker *services.Worker) *JobsHandler
} }
// CreateJob creates a new job based on type // CreateJob creates a new job based on type
func (h *JobsHandler) CreateJob(c echo.Context) error { func (h *JobsHandler) CreateJob(c *echo.Context) error {
var req struct { var req struct {
Type string `json:"type"` Type string `json:"type"`
Params map[string]interface{} `json:"params"` Params map[string]interface{} `json:"params"`
@@ -73,7 +73,7 @@ func (h *JobsHandler) CreateJob(c echo.Context) error {
} }
// GetJobStatus returns the status of a specific job // GetJobStatus returns the status of a specific job
func (h *JobsHandler) GetJobStatus(c echo.Context) error { func (h *JobsHandler) GetJobStatus(c *echo.Context) error {
jobID := c.Param("jobId") jobID := c.Param("jobId")
result, exists := h.worker.GetJobStatus(jobID) result, exists := h.worker.GetJobStatus(jobID)
+11 -11
View File
@@ -14,7 +14,7 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
"github.com/jackc/pgx/v5/pgtype" "github.com/jackc/pgx/v5/pgtype"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v5"
) )
type KoboHandler struct { type KoboHandler struct {
@@ -28,7 +28,7 @@ func NewKoboHandler(db *database.Queries, connManager *wsync.ConnectionManager)
// mapContentIdToBookhoardUUID maps Kobo ContentId to Bookhoard UUID with multiple fallback strategies // mapContentIdToBookhoardUUID maps Kobo ContentId to Bookhoard UUID with multiple fallback strategies
// Enhanced Kobo Sync - ContentId Mapping Logic // Enhanced Kobo Sync - ContentId Mapping Logic
func (h *KoboHandler) mapContentIdToBookhoardUUID(ctx echo.Context, contentId string, deviceID uuid.UUID) (uuid.UUID, error, string) { func (h *KoboHandler) mapContentIdToBookhoardUUID(ctx *echo.Context, contentId string, deviceID uuid.UUID) (uuid.UUID, error, string) {
// Step 1: Try direct ContentId lookup in device_catalogs table // Step 1: Try direct ContentId lookup in device_catalogs table
catalog, err := h.db.GetDeviceCatalogByKoboContentId(ctx.Request().Context(), contentId) catalog, err := h.db.GetDeviceCatalogByKoboContentId(ctx.Request().Context(), contentId)
if err == nil && catalog.ID.Valid { if err == nil && catalog.ID.Valid {
@@ -82,7 +82,7 @@ func (h *KoboHandler) mapContentIdToBookhoardUUID(ctx echo.Context, contentId st
// mapBookhoardUUIDToKoboContentId maps Bookhoard UUID to Kobo ContentId // mapBookhoardUUIDToKoboContentId maps Bookhoard UUID to Kobo ContentId
// Creates new entry in device_catalogs if not exists // Creates new entry in device_catalogs if not exists
func (h *KoboHandler) mapBookhoardUUIDToKoboContentId(c echo.Context, bookhoardUUID uuid.UUID, deviceID uuid.UUID) (string, error) { func (h *KoboHandler) mapBookhoardUUIDToKoboContentId(c *echo.Context, bookhoardUUID uuid.UUID, deviceID uuid.UUID) (string, error) {
// Check if catalog entry already exists // Check if catalog entry already exists
catalog, err := h.db.GetDeviceCatalogByBookhoardUUID(c.Request().Context(), database.GetDeviceCatalogByBookhoardUUIDParams{ catalog, err := h.db.GetDeviceCatalogByBookhoardUUID(c.Request().Context(), database.GetDeviceCatalogByBookhoardUUIDParams{
DeviceID: pgtype.UUID{Bytes: deviceID, Valid: true}, DeviceID: pgtype.UUID{Bytes: deviceID, Valid: true},
@@ -136,7 +136,7 @@ func (h *KoboHandler) mapBookhoardUUIDToKoboContentId(c echo.Context, bookhoardU
} }
// getCollectionMetadataForBook retrieves collection names for a book // getCollectionMetadataForBook retrieves collection names for a book
func (h *KoboHandler) getCollectionMetadataForBook(c echo.Context, bookhoardUUID uuid.UUID, deviceID uuid.UUID) ([]string, error) { func (h *KoboHandler) getCollectionMetadataForBook(c *echo.Context, bookhoardUUID uuid.UUID, deviceID uuid.UUID) ([]string, error) {
device := c.Get("device").(database.Devices) device := c.Get("device").(database.Devices)
pgDeviceID := pgtype.UUID{Bytes: device.ID.Bytes, Valid: true} pgDeviceID := pgtype.UUID{Bytes: device.ID.Bytes, Valid: true}
@@ -269,7 +269,7 @@ type KoboAnalyticsTest struct {
PercentRead float64 `json:"PercentRead"` PercentRead float64 `json:"PercentRead"`
} }
func (h *KoboHandler) Initialization(c echo.Context) error { func (h *KoboHandler) Initialization(c *echo.Context) error {
device := c.Get("device").(database.Devices) device := c.Get("device").(database.Devices)
userID := device.UserID.Bytes userID := device.UserID.Bytes
deviceID := device.ID.Bytes deviceID := device.ID.Bytes
@@ -379,11 +379,11 @@ func (h *KoboHandler) Initialization(c echo.Context) error {
}) })
} }
func (h *KoboHandler) LibrarySync(c echo.Context) error { func (h *KoboHandler) LibrarySync(c *echo.Context) error {
return h.Initialization(c) return h.Initialization(c)
} }
func (h *KoboHandler) Markup(c echo.Context) error { func (h *KoboHandler) Markup(c *echo.Context) error {
device := c.Get("device").(database.Devices) device := c.Get("device").(database.Devices)
userID := device.UserID.Bytes userID := device.UserID.Bytes
deviceID := device.ID.Bytes deviceID := device.ID.Bytes
@@ -521,7 +521,7 @@ func (h *KoboHandler) Markup(c echo.Context) error {
return c.JSON(http.StatusOK, response) return c.JSON(http.StatusOK, response)
} }
func (h *KoboHandler) Bookmark(c echo.Context) error { func (h *KoboHandler) Bookmark(c *echo.Context) error {
device := c.Get("device").(database.Devices) device := c.Get("device").(database.Devices)
userID := device.UserID.Bytes userID := device.UserID.Bytes
deviceID := device.ID.Bytes deviceID := device.ID.Bytes
@@ -590,7 +590,7 @@ func (h *KoboHandler) Bookmark(c echo.Context) error {
}) })
} }
func (h *KoboHandler) AnalyticsGettests(c echo.Context) error { func (h *KoboHandler) AnalyticsGettests(c *echo.Context) error {
device := c.Get("device").(database.Devices) device := c.Get("device").(database.Devices)
userID := device.UserID.Bytes userID := device.UserID.Bytes
deviceID := device.ID.Bytes deviceID := device.ID.Bytes
@@ -649,7 +649,7 @@ func (h *KoboHandler) AnalyticsGettests(c echo.Context) error {
}) })
} }
func parseKoboDeviceHeader(c echo.Context) (KoboDeviceInfo, error) { func parseKoboDeviceHeader(c *echo.Context) (KoboDeviceInfo, error) {
deviceHeader := c.Request().Header.Get("x-kobo-device") deviceHeader := c.Request().Header.Get("x-kobo-device")
if deviceHeader == "" { if deviceHeader == "" {
return KoboDeviceInfo{}, fmt.Errorf("missing x-kobo-device header") return KoboDeviceInfo{}, fmt.Errorf("missing x-kobo-device header")
@@ -663,7 +663,7 @@ func parseKoboDeviceHeader(c echo.Context) (KoboDeviceInfo, error) {
return device, nil return device, nil
} }
func (h *KoboHandler) SyncFromServer(c echo.Context) error { func (h *KoboHandler) SyncFromServer(c *echo.Context) error {
device := c.Get("device").(database.Devices) device := c.Get("device").(database.Devices)
userID := device.UserID.Bytes userID := device.UserID.Bytes
deviceID := device.ID.Bytes deviceID := device.ID.Bytes
+10 -10
View File
@@ -11,7 +11,7 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
"github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgtype" "github.com/jackc/pgx/v5/pgtype"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v5"
) )
type KOReaderHandler struct { type KOReaderHandler struct {
@@ -153,7 +153,7 @@ type KOReaderLibraryBook struct {
LastModified string `json:"last_modified"` LastModified string `json:"last_modified"`
} }
func (h *KOReaderHandler) SyncProgress(c echo.Context) error { func (h *KOReaderHandler) SyncProgress(c *echo.Context) error {
device := c.Get("device").(database.Devices) device := c.Get("device").(database.Devices)
userID := device.UserID.Bytes userID := device.UserID.Bytes
@@ -223,7 +223,7 @@ func (h *KOReaderHandler) SyncProgress(c echo.Context) error {
}) })
} }
func (h *KOReaderHandler) resolveBookToMediaItem(c echo.Context, deviceID pgtype.UUID, userID pgtype.UUID, book KOReaderBookProgress) (pgtype.UUID, float64) { func (h *KOReaderHandler) resolveBookToMediaItem(c *echo.Context, deviceID pgtype.UUID, userID pgtype.UUID, book KOReaderBookProgress) (pgtype.UUID, float64) {
ctx := c.Request().Context() ctx := c.Request().Context()
// Priority 1: UUID provided (highest confidence - 1.0) // Priority 1: UUID provided (highest confidence - 1.0)
@@ -307,7 +307,7 @@ func (h *KOReaderHandler) resolveBookToMediaItem(c echo.Context, deviceID pgtype
return pgtype.UUID{}, 0.0 return pgtype.UUID{}, 0.0
} }
func (h *KOReaderHandler) createDeviceFileAlias(c echo.Context, deviceID pgtype.UUID, mediaItemID pgtype.UUID, book KOReaderBookProgress) { func (h *KOReaderHandler) createDeviceFileAlias(c *echo.Context, deviceID pgtype.UUID, mediaItemID pgtype.UUID, book KOReaderBookProgress) {
ctx := c.Request().Context() ctx := c.Request().Context()
if book.FilePath == "" { if book.FilePath == "" {
@@ -341,7 +341,7 @@ func (h *KOReaderHandler) createDeviceFileAlias(c echo.Context, deviceID pgtype.
} }
} }
func (h *KOReaderHandler) handleCheckpointSync(c echo.Context, device database.Devices, userID pgtype.UUID, req KOReaderProgressRequest) error { func (h *KOReaderHandler) handleCheckpointSync(c *echo.Context, device database.Devices, userID pgtype.UUID, req KOReaderProgressRequest) error {
booksEnqueued := 0 booksEnqueued := 0
for _, book := range req.Books { for _, book := range req.Books {
@@ -371,7 +371,7 @@ func (h *KOReaderHandler) handleCheckpointSync(c echo.Context, device database.D
}) })
} }
func (h *KOReaderHandler) enqueueProgressForBook(c echo.Context, deviceID pgtype.UUID, userID pgtype.UUID, mediaItemID pgtype.UUID, book KOReaderBookProgress) error { func (h *KOReaderHandler) enqueueProgressForBook(c *echo.Context, deviceID pgtype.UUID, userID pgtype.UUID, mediaItemID pgtype.UUID, book KOReaderBookProgress) error {
if h.queue == nil { if h.queue == nil {
return fmt.Errorf("sync queue not available") return fmt.Errorf("sync queue not available")
} }
@@ -393,7 +393,7 @@ func (h *KOReaderHandler) enqueueProgressForBook(c echo.Context, deviceID pgtype
return h.queue.EnqueueProgress(update) return h.queue.EnqueueProgress(update)
} }
func (h *KOReaderHandler) updateProgressForBook(c echo.Context, userID pgtype.UUID, mediaItemID pgtype.UUID, book KOReaderBookProgress) error { func (h *KOReaderHandler) updateProgressForBook(c *echo.Context, userID pgtype.UUID, mediaItemID pgtype.UUID, book KOReaderBookProgress) error {
ctx := c.Request().Context() ctx := c.Request().Context()
existingProgress, err := h.db.GetReadingProgress(ctx, database.GetReadingProgressParams{ existingProgress, err := h.db.GetReadingProgress(ctx, database.GetReadingProgressParams{
@@ -557,7 +557,7 @@ func (h *KOReaderHandler) updateProgressForBook(c echo.Context, userID pgtype.UU
return err return err
} }
func (h *KOReaderHandler) GetMetadata(c echo.Context) error { func (h *KOReaderHandler) GetMetadata(c *echo.Context) error {
device := c.Get("device").(database.Devices) device := c.Get("device").(database.Devices)
userID := device.UserID.Bytes userID := device.UserID.Bytes
@@ -667,7 +667,7 @@ func (h *KOReaderHandler) GetMetadata(c echo.Context) error {
return c.JSON(http.StatusOK, metadata) return c.JSON(http.StatusOK, metadata)
} }
func (h *KOReaderHandler) GetLibrary(c echo.Context) error { func (h *KOReaderHandler) GetLibrary(c *echo.Context) error {
device := c.Get("device").(database.Devices) device := c.Get("device").(database.Devices)
userID := device.UserID.Bytes userID := device.UserID.Bytes
@@ -731,7 +731,7 @@ func (h *KOReaderHandler) GetLibrary(c echo.Context) error {
}) })
} }
func (h *KOReaderHandler) SyncBookmarks(c echo.Context) error { func (h *KOReaderHandler) SyncBookmarks(c *echo.Context) error {
device := c.Get("device").(database.Devices) device := c.Get("device").(database.Devices)
userID := device.UserID.Bytes userID := device.UserID.Bytes
+14 -14
View File
@@ -11,7 +11,7 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
"github.com/jackc/pgx/v5/pgtype" "github.com/jackc/pgx/v5/pgtype"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v5"
) )
type LibraryHandler struct { type LibraryHandler struct {
@@ -48,7 +48,7 @@ type SetLibraryVisibilityRequest struct {
} }
// GetLibraryTypes retrieves all available library types // GetLibraryTypes retrieves all available library types
func (h *LibraryHandler) GetLibraryTypes(c echo.Context) error { func (h *LibraryHandler) GetLibraryTypes(c *echo.Context) error {
types, err := h.libraryService.GetLibraryTypes(c.Request().Context()) types, err := h.libraryService.GetLibraryTypes(c.Request().Context())
if err != nil { if err != nil {
return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()}) return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
@@ -57,7 +57,7 @@ func (h *LibraryHandler) GetLibraryTypes(c echo.Context) error {
} }
// CreateLibrary creates a new library // CreateLibrary creates a new library
func (h *LibraryHandler) CreateLibrary(c echo.Context) error { func (h *LibraryHandler) CreateLibrary(c *echo.Context) error {
user := c.Get("user").(database.Users) user := c.Get("user").(database.Users)
userUUID := user.ID.Bytes userUUID := user.ID.Bytes
@@ -84,7 +84,7 @@ func (h *LibraryHandler) CreateLibrary(c echo.Context) error {
} }
// GetLibrary retrieves a specific library // GetLibrary retrieves a specific library
func (h *LibraryHandler) GetLibrary(c echo.Context) error { func (h *LibraryHandler) GetLibrary(c *echo.Context) error {
libraryID, err := parseUUID(c.Param("id")) libraryID, err := parseUUID(c.Param("id"))
if err != nil { if err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid library id"}) return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid library id"})
@@ -99,7 +99,7 @@ func (h *LibraryHandler) GetLibrary(c echo.Context) error {
} }
// ListLibraries retrieves all libraries (admin only) // ListLibraries retrieves all libraries (admin only)
func (h *LibraryHandler) ListLibraries(c echo.Context) error { func (h *LibraryHandler) ListLibraries(c *echo.Context) error {
libraries, err := h.libraryService.ListLibraries(c.Request().Context()) libraries, err := h.libraryService.ListLibraries(c.Request().Context())
if err != nil { if err != nil {
return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()}) return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
@@ -109,7 +109,7 @@ func (h *LibraryHandler) ListLibraries(c echo.Context) error {
} }
// GetUserVisibleLibraries retrieves libraries visible to the current user // GetUserVisibleLibraries retrieves libraries visible to the current user
func (h *LibraryHandler) GetUserVisibleLibraries(c echo.Context) error { func (h *LibraryHandler) GetUserVisibleLibraries(c *echo.Context) error {
user := MustGetAuthenticatedUser(c) user := MustGetAuthenticatedUser(c)
libraries, err := h.libraryService.GetUserVisibleLibraries(c.Request().Context(), user.ID) libraries, err := h.libraryService.GetUserVisibleLibraries(c.Request().Context(), user.ID)
@@ -121,7 +121,7 @@ func (h *LibraryHandler) GetUserVisibleLibraries(c echo.Context) error {
} }
// UpdateLibrary updates an existing library // UpdateLibrary updates an existing library
func (h *LibraryHandler) UpdateLibrary(c echo.Context) error { func (h *LibraryHandler) UpdateLibrary(c *echo.Context) error {
libraryID, err := parseUUID(c.Param("id")) libraryID, err := parseUUID(c.Param("id"))
if err != nil { if err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid library id"}) return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid library id"})
@@ -149,7 +149,7 @@ func (h *LibraryHandler) UpdateLibrary(c echo.Context) error {
} }
// DeleteLibrary deletes a library // DeleteLibrary deletes a library
func (h *LibraryHandler) DeleteLibrary(c echo.Context) error { func (h *LibraryHandler) DeleteLibrary(c *echo.Context) error {
libraryID, err := parseUUID(c.Param("id")) libraryID, err := parseUUID(c.Param("id"))
if err != nil { if err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid library id"}) return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid library id"})
@@ -164,7 +164,7 @@ func (h *LibraryHandler) DeleteLibrary(c echo.Context) error {
} }
// AddLibraryFolder adds a folder to a library // AddLibraryFolder adds a folder to a library
func (h *LibraryHandler) AddLibraryFolder(c echo.Context) error { func (h *LibraryHandler) AddLibraryFolder(c *echo.Context) error {
libraryID, err := parseUUID(c.Param("id")) libraryID, err := parseUUID(c.Param("id"))
if err != nil { if err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid library id"}) return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid library id"})
@@ -213,7 +213,7 @@ func (h *LibraryHandler) AddLibraryFolder(c echo.Context) error {
} }
// GetLibraryFolders retrieves all folders for a library // GetLibraryFolders retrieves all folders for a library
func (h *LibraryHandler) GetLibraryFolders(c echo.Context) error { func (h *LibraryHandler) GetLibraryFolders(c *echo.Context) error {
libraryID, err := parseUUID(c.Param("id")) libraryID, err := parseUUID(c.Param("id"))
if err != nil { if err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid library id"}) return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid library id"})
@@ -228,7 +228,7 @@ func (h *LibraryHandler) GetLibraryFolders(c echo.Context) error {
} }
// DeleteLibraryFolder removes a folder from a library // DeleteLibraryFolder removes a folder from a library
func (h *LibraryHandler) DeleteLibraryFolder(c echo.Context) error { func (h *LibraryHandler) DeleteLibraryFolder(c *echo.Context) error {
libraryID, err := parseUUID(c.Param("id")) libraryID, err := parseUUID(c.Param("id"))
if err != nil { if err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid library id"}) return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid library id"})
@@ -251,7 +251,7 @@ func (h *LibraryHandler) DeleteLibraryFolder(c echo.Context) error {
} }
// BrowseDirectories returns directory listings for folder browser UI // BrowseDirectories returns directory listings for folder browser UI
func (h *LibraryHandler) BrowseDirectories(c echo.Context) error { func (h *LibraryHandler) BrowseDirectories(c *echo.Context) error {
path := c.QueryParam("path") path := c.QueryParam("path")
if path == "" { if path == "" {
path = "/" // Start from root path = "/" // Start from root
@@ -270,7 +270,7 @@ func (h *LibraryHandler) BrowseDirectories(c echo.Context) error {
} }
// SetLibraryVisibility sets library visibility for a user // SetLibraryVisibility sets library visibility for a user
func (h *LibraryHandler) SetLibraryVisibility(c echo.Context) error { func (h *LibraryHandler) SetLibraryVisibility(c *echo.Context) error {
user := c.Get("user").(database.Users) user := c.Get("user").(database.Users)
var req SetLibraryVisibilityRequest var req SetLibraryVisibilityRequest
@@ -300,7 +300,7 @@ func (h *LibraryHandler) SetLibraryVisibility(c echo.Context) error {
} }
// GetLibraryStats retrieves statistics for a library // GetLibraryStats retrieves statistics for a library
func (h *LibraryHandler) GetLibraryStats(c echo.Context) error { func (h *LibraryHandler) GetLibraryStats(c *echo.Context) error {
libraryID, err := parseUUID(c.Param("id")) libraryID, err := parseUUID(c.Param("id"))
if err != nil { if err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid library id"}) return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid library id"})
+12 -12
View File
@@ -10,7 +10,7 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
"github.com/jackc/pgx/v5/pgtype" "github.com/jackc/pgx/v5/pgtype"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v5"
) )
// MatchingHandler handles book matching, linking, and file alias operations // MatchingHandler handles book matching, linking, and file alias operations
@@ -33,7 +33,7 @@ func (mh *MatchingHandler) getMatchingService() *services.BookMatchingService {
} }
// QueryBooks handles POST /api/sync/books/query // QueryBooks handles POST /api/sync/books/query
func (mh *MatchingHandler) QueryBooks(c echo.Context) error { func (mh *MatchingHandler) QueryBooks(c *echo.Context) error {
matchingService := mh.getMatchingService() matchingService := mh.getMatchingService()
var req services.BookQueryRequest var req services.BookQueryRequest
@@ -54,7 +54,7 @@ func (mh *MatchingHandler) QueryBooks(c echo.Context) error {
} }
// LinkBook handles POST /api/devices/:deviceId/sync/link-book // LinkBook handles POST /api/devices/:deviceId/sync/link-book
func (mh *MatchingHandler) LinkBook(c echo.Context) error { func (mh *MatchingHandler) LinkBook(c *echo.Context) error {
matchingService := mh.getMatchingService() matchingService := mh.getMatchingService()
var req services.LinkBookRequest var req services.LinkBookRequest
@@ -93,7 +93,7 @@ func (mh *MatchingHandler) LinkBook(c echo.Context) error {
} }
// GetUnlinkedBooks handles GET /api/devices/:deviceId/sync/unlinked-books // GetUnlinkedBooks handles GET /api/devices/:deviceId/sync/unlinked-books
func (mh *MatchingHandler) GetUnlinkedBooks(c echo.Context) error { func (mh *MatchingHandler) GetUnlinkedBooks(c *echo.Context) error {
matchingService := mh.getMatchingService() matchingService := mh.getMatchingService()
deviceIDStr := c.Param("deviceId") deviceIDStr := c.Param("deviceId")
@@ -118,7 +118,7 @@ func (mh *MatchingHandler) GetUnlinkedBooks(c echo.Context) error {
} }
// GetDeviceFileAliases handles GET /api/devices/:id/file-aliases // GetDeviceFileAliases handles GET /api/devices/:id/file-aliases
func (mh *MatchingHandler) GetDeviceFileAliases(c echo.Context) error { func (mh *MatchingHandler) GetDeviceFileAliases(c *echo.Context) error {
deviceIDStr := c.Param("id") deviceIDStr := c.Param("id")
deviceID, err := uuid.Parse(deviceIDStr) deviceID, err := uuid.Parse(deviceIDStr)
if err != nil { if err != nil {
@@ -163,7 +163,7 @@ func (mh *MatchingHandler) GetDeviceFileAliases(c echo.Context) error {
} }
// CreateDeviceFileAlias handles POST /api/devices/:id/file-aliases // CreateDeviceFileAlias handles POST /api/devices/:id/file-aliases
func (mh *MatchingHandler) CreateDeviceFileAlias(c echo.Context) error { func (mh *MatchingHandler) CreateDeviceFileAlias(c *echo.Context) error {
deviceIDStr := c.Param("id") deviceIDStr := c.Param("id")
deviceID, err := uuid.Parse(deviceIDStr) deviceID, err := uuid.Parse(deviceIDStr)
if err != nil { if err != nil {
@@ -218,7 +218,7 @@ func (mh *MatchingHandler) CreateDeviceFileAlias(c echo.Context) error {
} }
// UpdateDeviceFileAlias handles PUT /api/devices/:id/file-aliases/:aliasId // UpdateDeviceFileAlias handles PUT /api/devices/:id/file-aliases/:aliasId
func (mh *MatchingHandler) UpdateDeviceFileAlias(c echo.Context) error { func (mh *MatchingHandler) UpdateDeviceFileAlias(c *echo.Context) error {
aliasIDStr := c.Param("aliasId") aliasIDStr := c.Param("aliasId")
aliasID, err := uuid.Parse(aliasIDStr) aliasID, err := uuid.Parse(aliasIDStr)
if err != nil { if err != nil {
@@ -284,7 +284,7 @@ func (mh *MatchingHandler) UpdateDeviceFileAlias(c echo.Context) error {
} }
// DeleteDeviceFileAlias handles DELETE /api/devices/:id/file-aliases/:aliasId // DeleteDeviceFileAlias handles DELETE /api/devices/:id/file-aliases/:aliasId
func (mh *MatchingHandler) DeleteDeviceFileAlias(c echo.Context) error { func (mh *MatchingHandler) DeleteDeviceFileAlias(c *echo.Context) error {
aliasIDStr := c.Param("aliasId") aliasIDStr := c.Param("aliasId")
aliasID, err := uuid.Parse(aliasIDStr) aliasID, err := uuid.Parse(aliasIDStr)
if err != nil { if err != nil {
@@ -306,7 +306,7 @@ func (mh *MatchingHandler) DeleteDeviceFileAlias(c echo.Context) error {
} }
// GetBookMatches handles GET /api/books/match // GetBookMatches handles GET /api/books/match
func (mh *MatchingHandler) GetBookMatches(c echo.Context) error { func (mh *MatchingHandler) GetBookMatches(c *echo.Context) error {
matchingService := mh.getMatchingService() matchingService := mh.getMatchingService()
identifiers := c.QueryParams()["identifier"] identifiers := c.QueryParams()["identifier"]
@@ -345,7 +345,7 @@ func (mh *MatchingHandler) GetBookMatches(c echo.Context) error {
} }
// BulkLinkBooks handles POST /api/sync/bulk-link-books // BulkLinkBooks handles POST /api/sync/bulk-link-books
func (mh *MatchingHandler) BulkLinkBooks(c echo.Context) error { func (mh *MatchingHandler) BulkLinkBooks(c *echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
var req BulkLinkBooksRequest var req BulkLinkBooksRequest
@@ -423,7 +423,7 @@ func (mh *MatchingHandler) BulkLinkBooks(c echo.Context) error {
} }
// AutoLinkBooks handles POST /api/sync/auto-link-books // AutoLinkBooks handles POST /api/sync/auto-link-books
func (mh *MatchingHandler) AutoLinkBooks(c echo.Context) error { func (mh *MatchingHandler) AutoLinkBooks(c *echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
matchingService := mh.getMatchingService() matchingService := mh.getMatchingService()
@@ -499,7 +499,7 @@ func (mh *MatchingHandler) AutoLinkBooks(c echo.Context) error {
} }
// GetUnlinkedBookSuggestions handles GET /api/sync/unlinked-books/:id/suggestions // GetUnlinkedBookSuggestions handles GET /api/sync/unlinked-books/:id/suggestions
func (mh *MatchingHandler) GetUnlinkedBookSuggestions(c echo.Context) error { func (mh *MatchingHandler) GetUnlinkedBookSuggestions(c *echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
matchingService := mh.getMatchingService() matchingService := mh.getMatchingService()
+33 -33
View File
@@ -18,7 +18,7 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
"github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgtype" "github.com/jackc/pgx/v5/pgtype"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v5"
) )
// CreateMediaItemRequest represents the request for creating a media item // CreateMediaItemRequest represents the request for creating a media item
@@ -104,7 +104,7 @@ func NewMediaHandler(db *database.Queries, libraryService *services.LibraryServi
return mh return mh
} }
func (h *MediaHandler) DownloadBook(c echo.Context) error { func (h *MediaHandler) DownloadBook(c *echo.Context) error {
bookUUID, err := uuid.Parse(c.Param("uuid")) bookUUID, err := uuid.Parse(c.Param("uuid"))
if err != nil { if err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid book UUID"}) return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid book UUID"})
@@ -159,7 +159,7 @@ type AddToShelfRequest struct {
ShelfPosition int `json:"shelf_position"` ShelfPosition int `json:"shelf_position"`
} }
func (h *MediaHandler) AddToShelf(c echo.Context) error { func (h *MediaHandler) AddToShelf(c *echo.Context) error {
deviceUUID, err := uuid.Parse(c.Param("id")) deviceUUID, err := uuid.Parse(c.Param("id"))
if err != nil { if err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid device ID"}) return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid device ID"})
@@ -204,7 +204,7 @@ func (h *MediaHandler) AddToShelf(c echo.Context) error {
}) })
} }
func (h *MediaHandler) GetShelf(c echo.Context) error { func (h *MediaHandler) GetShelf(c *echo.Context) error {
deviceUUID, err := uuid.Parse(c.Param("id")) deviceUUID, err := uuid.Parse(c.Param("id"))
if err != nil { if err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid device ID"}) return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid device ID"})
@@ -287,7 +287,7 @@ func (h *MediaHandler) GetShelf(c echo.Context) error {
}) })
} }
func (h *MediaHandler) RemoveFromShelf(c echo.Context) error { func (h *MediaHandler) RemoveFromShelf(c *echo.Context) error {
deviceUUID, err := uuid.Parse(c.Param("id")) deviceUUID, err := uuid.Parse(c.Param("id"))
if err != nil { if err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid device ID"}) return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid device ID"})
@@ -316,7 +316,7 @@ func (h *MediaHandler) RemoveFromShelf(c echo.Context) error {
}) })
} }
func (h *MediaHandler) ClearShelf(c echo.Context) error { func (h *MediaHandler) ClearShelf(c *echo.Context) error {
deviceUUID, err := uuid.Parse(c.Param("id")) deviceUUID, err := uuid.Parse(c.Param("id"))
if err != nil { if err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid device ID"}) return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid device ID"})
@@ -351,7 +351,7 @@ func (h *MediaHandler) ClearShelf(c echo.Context) error {
// POST /api/media-items/bulk-delete // POST /api/media-items/bulk-delete
// Bulk delete media items // Bulk delete media items
func (h *MediaHandler) HandleBulkDelete(c echo.Context) error { func (h *MediaHandler) HandleBulkDelete(c *echo.Context) error {
var req struct { var req struct {
MediaItemIDs []string `json:"media_item_ids" validate:"required"` MediaItemIDs []string `json:"media_item_ids" validate:"required"`
} }
@@ -425,7 +425,7 @@ func (h *MediaHandler) HandleBulkDelete(c echo.Context) error {
// POST /api/media-items/bulk-update // POST /api/media-items/bulk-update
// Bulk update media item metadata // Bulk update media item metadata
func (h *MediaHandler) HandleBulkUpdate(c echo.Context) error { func (h *MediaHandler) HandleBulkUpdate(c *echo.Context) error {
var req struct { var req struct {
MediaItemUpdates []struct { MediaItemUpdates []struct {
MediaItemID string `json:"media_item_id" validate:"required"` MediaItemID string `json:"media_item_id" validate:"required"`
@@ -553,7 +553,7 @@ func (h *MediaHandler) HandleBulkUpdate(c echo.Context) error {
} }
// ListMediaItems handles GET /api/media-items // ListMediaItems handles GET /api/media-items
func (mh *MediaHandler) ListMediaItems(c echo.Context) error { func (mh *MediaHandler) ListMediaItems(c *echo.Context) error {
libraryID := c.QueryParam("library_id") libraryID := c.QueryParam("library_id")
sort := c.QueryParam("sort") sort := c.QueryParam("sort")
limit, _ := strconv.Atoi(c.QueryParam("limit")) limit, _ := strconv.Atoi(c.QueryParam("limit"))
@@ -658,7 +658,7 @@ func (mh *MediaHandler) ListMediaItems(c echo.Context) error {
} }
// GetMediaItem handles GET /api/media-items/:id // GetMediaItem handles GET /api/media-items/:id
func (mh *MediaHandler) GetMediaItem(c echo.Context) error { func (mh *MediaHandler) GetMediaItem(c *echo.Context) error {
mediaID := c.Param("id") mediaID := c.Param("id")
mediaUUID, err := uuid.Parse(mediaID) mediaUUID, err := uuid.Parse(mediaID)
if err != nil { if err != nil {
@@ -703,7 +703,7 @@ func (mh *MediaHandler) GetMediaItem(c echo.Context) error {
} }
// ListMediaItemsFiltered handles GET /api/media-items/filtered // ListMediaItemsFiltered handles GET /api/media-items/filtered
func (mh *MediaHandler) ListMediaItemsFiltered(c echo.Context) error { func (mh *MediaHandler) ListMediaItemsFiltered(c *echo.Context) error {
userID := c.Get("user_id").(string) userID := c.Get("user_id").(string)
libraryID := c.QueryParam("library_id") libraryID := c.QueryParam("library_id")
sort := c.QueryParam("sort") sort := c.QueryParam("sort")
@@ -766,7 +766,7 @@ func (mh *MediaHandler) ListMediaItemsFiltered(c echo.Context) error {
} }
// CreateMediaRating handles POST /api/media-items/:id/rating // CreateMediaRating handles POST /api/media-items/:id/rating
func (mh *MediaHandler) CreateMediaRating(c echo.Context) error { func (mh *MediaHandler) CreateMediaRating(c *echo.Context) error {
userID := c.Get("user_id").(string) userID := c.Get("user_id").(string)
userUUID, err := uuid.Parse(userID) userUUID, err := uuid.Parse(userID)
if err != nil { if err != nil {
@@ -802,7 +802,7 @@ func (mh *MediaHandler) CreateMediaRating(c echo.Context) error {
} }
// GetMediaRating handles GET /api/media-items/:id/rating // GetMediaRating handles GET /api/media-items/:id/rating
func (mh *MediaHandler) GetMediaRating(c echo.Context) error { func (mh *MediaHandler) GetMediaRating(c *echo.Context) error {
userID := c.Get("user_id").(string) userID := c.Get("user_id").(string)
userUUID, err := uuid.Parse(userID) userUUID, err := uuid.Parse(userID)
if err != nil { if err != nil {
@@ -830,12 +830,12 @@ func (mh *MediaHandler) GetMediaRating(c echo.Context) error {
} }
// UpdateMediaRating handles PUT /api/media-items/:id/rating // UpdateMediaRating handles PUT /api/media-items/:id/rating
func (mh *MediaHandler) UpdateMediaRating(c echo.Context) error { func (mh *MediaHandler) UpdateMediaRating(c *echo.Context) error {
return mh.CreateMediaRating(c) return mh.CreateMediaRating(c)
} }
// DeleteMediaRating handles DELETE /api/media-items/:id/rating // DeleteMediaRating handles DELETE /api/media-items/:id/rating
func (mh *MediaHandler) DeleteMediaRating(c echo.Context) error { func (mh *MediaHandler) DeleteMediaRating(c *echo.Context) error {
userID := c.Get("user_id").(string) userID := c.Get("user_id").(string)
userUUID, err := uuid.Parse(userID) userUUID, err := uuid.Parse(userID)
if err != nil { if err != nil {
@@ -860,7 +860,7 @@ func (mh *MediaHandler) DeleteMediaRating(c echo.Context) error {
} }
// GetMediaReadingProgress handles GET /api/media-items/:id/progress // GetMediaReadingProgress handles GET /api/media-items/:id/progress
func (mh *MediaHandler) GetMediaReadingProgress(c echo.Context) error { func (mh *MediaHandler) GetMediaReadingProgress(c *echo.Context) error {
userID := c.Get("user_id").(string) userID := c.Get("user_id").(string)
userUUID, err := uuid.Parse(userID) userUUID, err := uuid.Parse(userID)
if err != nil { if err != nil {
@@ -891,7 +891,7 @@ func (mh *MediaHandler) GetMediaReadingProgress(c echo.Context) error {
} }
// UpdateMediaReadingProgress handles PUT /api/media-items/:id/progress // UpdateMediaReadingProgress handles PUT /api/media-items/:id/progress
func (mh *MediaHandler) UpdateMediaReadingProgress(c echo.Context) error { func (mh *MediaHandler) UpdateMediaReadingProgress(c *echo.Context) error {
userID := c.Get("user_id").(string) userID := c.Get("user_id").(string)
userUUID, err := uuid.Parse(userID) userUUID, err := uuid.Parse(userID)
if err != nil { if err != nil {
@@ -929,7 +929,7 @@ func (mh *MediaHandler) UpdateMediaReadingProgress(c echo.Context) error {
} }
// DeleteMediaReadingProgress handles DELETE /api/media-items/:id/progress // DeleteMediaReadingProgress handles DELETE /api/media-items/:id/progress
func (mh *MediaHandler) DeleteMediaReadingProgress(c echo.Context) error { func (mh *MediaHandler) DeleteMediaReadingProgress(c *echo.Context) error {
userID := c.Get("user_id").(string) userID := c.Get("user_id").(string)
userUUID, err := uuid.Parse(userID) userUUID, err := uuid.Parse(userID)
if err != nil { if err != nil {
@@ -954,7 +954,7 @@ func (mh *MediaHandler) DeleteMediaReadingProgress(c echo.Context) error {
} }
// CreateMediaItem handles POST /api/media-items (admin only) // CreateMediaItem handles POST /api/media-items (admin only)
func (mh *MediaHandler) CreateMediaItem(c echo.Context) error { func (mh *MediaHandler) CreateMediaItem(c *echo.Context) error {
user := MustGetAuthenticatedUser(c) user := MustGetAuthenticatedUser(c)
if user.Role != "admin" { if user.Role != "admin" {
@@ -1045,7 +1045,7 @@ func (mh *MediaHandler) CreateMediaItem(c echo.Context) error {
} }
// UpdateMediaItem handles PUT /api/media-items/:id (admin only) // UpdateMediaItem handles PUT /api/media-items/:id (admin only)
func (mh *MediaHandler) UpdateMediaItem(c echo.Context) error { func (mh *MediaHandler) UpdateMediaItem(c *echo.Context) error {
user := MustGetAuthenticatedUser(c) user := MustGetAuthenticatedUser(c)
if user.Role != "admin" { if user.Role != "admin" {
@@ -1114,7 +1114,7 @@ func (mh *MediaHandler) UpdateMediaItem(c echo.Context) error {
} }
// DeleteMediaItem handles DELETE /api/media-items/:id (admin only) // DeleteMediaItem handles DELETE /api/media-items/:id (admin only)
func (mh *MediaHandler) DeleteMediaItem(c echo.Context) error { func (mh *MediaHandler) DeleteMediaItem(c *echo.Context) error {
user := MustGetAuthenticatedUser(c) user := MustGetAuthenticatedUser(c)
if user.Role != "admin" { if user.Role != "admin" {
@@ -1136,7 +1136,7 @@ func (mh *MediaHandler) DeleteMediaItem(c echo.Context) error {
} }
// GetMediaNotes handles GET /api/media-items/:id/notes // GetMediaNotes handles GET /api/media-items/:id/notes
func (mh *MediaHandler) GetMediaNotes(c echo.Context) error { func (mh *MediaHandler) GetMediaNotes(c *echo.Context) error {
userID := c.Get("user_id").(string) userID := c.Get("user_id").(string)
userUUID, err := uuid.Parse(userID) userUUID, err := uuid.Parse(userID)
if err != nil { if err != nil {
@@ -1161,7 +1161,7 @@ func (mh *MediaHandler) GetMediaNotes(c echo.Context) error {
} }
// CreateMediaNote handles POST /api/media-items/:id/notes // CreateMediaNote handles POST /api/media-items/:id/notes
func (mh *MediaHandler) CreateMediaNote(c echo.Context) error { func (mh *MediaHandler) CreateMediaNote(c *echo.Context) error {
userID := c.Get("user_id").(string) userID := c.Get("user_id").(string)
userUUID, err := uuid.Parse(userID) userUUID, err := uuid.Parse(userID)
if err != nil { if err != nil {
@@ -1196,7 +1196,7 @@ func (mh *MediaHandler) CreateMediaNote(c echo.Context) error {
} }
// GetMediaNote handles GET /api/media-items/:id/notes/:noteId // GetMediaNote handles GET /api/media-items/:id/notes/:noteId
func (mh *MediaHandler) GetMediaNote(c echo.Context) error { func (mh *MediaHandler) GetMediaNote(c *echo.Context) error {
noteID := c.Param("noteId") noteID := c.Param("noteId")
noteUUID, err := uuid.Parse(noteID) noteUUID, err := uuid.Parse(noteID)
if err != nil { if err != nil {
@@ -1215,7 +1215,7 @@ func (mh *MediaHandler) GetMediaNote(c echo.Context) error {
} }
// UpdateMediaNote handles PUT /api/media-items/:id/notes/:noteId // UpdateMediaNote handles PUT /api/media-items/:id/notes/:noteId
func (mh *MediaHandler) UpdateMediaNote(c echo.Context) error { func (mh *MediaHandler) UpdateMediaNote(c *echo.Context) error {
noteID := c.Param("noteId") noteID := c.Param("noteId")
noteUUID, err := uuid.Parse(noteID) noteUUID, err := uuid.Parse(noteID)
if err != nil { if err != nil {
@@ -1243,7 +1243,7 @@ func (mh *MediaHandler) UpdateMediaNote(c echo.Context) error {
} }
// DeleteMediaNote handles DELETE /api/media-items/:id/notes/:noteId // DeleteMediaNote handles DELETE /api/media-items/:id/notes/:noteId
func (mh *MediaHandler) DeleteMediaNote(c echo.Context) error { func (mh *MediaHandler) DeleteMediaNote(c *echo.Context) error {
noteID := c.Param("noteId") noteID := c.Param("noteId")
noteUUID, err := uuid.Parse(noteID) noteUUID, err := uuid.Parse(noteID)
if err != nil { if err != nil {
@@ -1259,7 +1259,7 @@ func (mh *MediaHandler) DeleteMediaNote(c echo.Context) error {
} }
// GetMediaHighlights handles GET /api/media-items/:id/highlights // GetMediaHighlights handles GET /api/media-items/:id/highlights
func (mh *MediaHandler) GetMediaHighlights(c echo.Context) error { func (mh *MediaHandler) GetMediaHighlights(c *echo.Context) error {
userID := c.Get("user_id").(string) userID := c.Get("user_id").(string)
userUUID, err := uuid.Parse(userID) userUUID, err := uuid.Parse(userID)
if err != nil { if err != nil {
@@ -1284,7 +1284,7 @@ func (mh *MediaHandler) GetMediaHighlights(c echo.Context) error {
} }
// CreateMediaHighlight handles POST /api/media-items/:id/highlights // CreateMediaHighlight handles POST /api/media-items/:id/highlights
func (mh *MediaHandler) CreateMediaHighlight(c echo.Context) error { func (mh *MediaHandler) CreateMediaHighlight(c *echo.Context) error {
userID := c.Get("user_id").(string) userID := c.Get("user_id").(string)
userUUID, err := uuid.Parse(userID) userUUID, err := uuid.Parse(userID)
if err != nil { if err != nil {
@@ -1336,7 +1336,7 @@ func (mh *MediaHandler) CreateMediaHighlight(c echo.Context) error {
} }
// GetMediaHighlight handles GET /api/media-items/:id/highlights/:highlightId // GetMediaHighlight handles GET /api/media-items/:id/highlights/:highlightId
func (mh *MediaHandler) GetMediaHighlight(c echo.Context) error { func (mh *MediaHandler) GetMediaHighlight(c *echo.Context) error {
highlightID := c.Param("highlightId") highlightID := c.Param("highlightId")
highlightUUID, err := uuid.Parse(highlightID) highlightUUID, err := uuid.Parse(highlightID)
if err != nil { if err != nil {
@@ -1355,7 +1355,7 @@ func (mh *MediaHandler) GetMediaHighlight(c echo.Context) error {
} }
// UpdateMediaHighlight handles PUT /api/media-items/:id/highlights/:highlightId // UpdateMediaHighlight handles PUT /api/media-items/:id/highlights/:highlightId
func (mh *MediaHandler) UpdateMediaHighlight(c echo.Context) error { func (mh *MediaHandler) UpdateMediaHighlight(c *echo.Context) error {
highlightID := c.Param("highlightId") highlightID := c.Param("highlightId")
highlightUUID, err := uuid.Parse(highlightID) highlightUUID, err := uuid.Parse(highlightID)
if err != nil { if err != nil {
@@ -1400,7 +1400,7 @@ func (mh *MediaHandler) UpdateMediaHighlight(c echo.Context) error {
} }
// DeleteMediaHighlight handles DELETE /api/media-items/:id/highlights/:highlightId // DeleteMediaHighlight handles DELETE /api/media-items/:id/highlights/:highlightId
func (mh *MediaHandler) DeleteMediaHighlight(c echo.Context) error { func (mh *MediaHandler) DeleteMediaHighlight(c *echo.Context) error {
highlightID := c.Param("highlightId") highlightID := c.Param("highlightId")
highlightUUID, err := uuid.Parse(highlightID) highlightUUID, err := uuid.Parse(highlightID)
if err != nil { if err != nil {
@@ -1416,7 +1416,7 @@ func (mh *MediaHandler) DeleteMediaHighlight(c echo.Context) error {
} }
// SearchMediaItems handles GET /api/media-items/search // SearchMediaItems handles GET /api/media-items/search
func (mh *MediaHandler) SearchMediaItems(c echo.Context) error { func (mh *MediaHandler) SearchMediaItems(c *echo.Context) error {
query := c.QueryParam("q") query := c.QueryParam("q")
// Safely get user from context // Safely get user from context
@@ -1510,7 +1510,7 @@ func (mh *MediaHandler) getFullFilePath(ctx context.Context, libraryID pgtype.UU
// ServeFile serves files (covers or books) via /uploads/library-{id}/path // ServeFile serves files (covers or books) via /uploads/library-{id}/path
// Requires JWT authentication // Requires JWT authentication
func (mh *MediaHandler) ServeFile(c echo.Context) error { func (mh *MediaHandler) ServeFile(c *echo.Context) error {
// URL format: /uploads/library-{libraryID}/{relativePath} // URL format: /uploads/library-{libraryID}/{relativePath}
// Get library ID directly from route parameter // Get library ID directly from route parameter
libraryIDStr := c.Param("id") libraryIDStr := c.Param("id")
+9 -9
View File
@@ -17,7 +17,7 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
"github.com/jackc/pgx/v5/pgtype" "github.com/jackc/pgx/v5/pgtype"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v5"
) )
type OPDSHandler struct { type OPDSHandler struct {
@@ -39,7 +39,7 @@ func NewOPDSHandler(db *database.Queries, libraryService *services.LibraryServic
} }
// Helper function to get base URLs from system config // Helper function to get base URLs from system config
func (h *OPDSHandler) getBaseURLs(c echo.Context) (string, string, error) { func (h *OPDSHandler) getBaseURLs(c *echo.Context) (string, string, error) {
baseURL, err := h.db.GetSystemConfig(c.Request().Context(), "base_url") baseURL, err := h.db.GetSystemConfig(c.Request().Context(), "base_url")
if err != nil { if err != nil {
return "", "", fmt.Errorf("failed to get base_url from config: %w", err) return "", "", fmt.Errorf("failed to get base_url from config: %w", err)
@@ -54,7 +54,7 @@ func (h *OPDSHandler) getBaseURLs(c echo.Context) (string, string, error) {
} }
// GetDeviceCatalog returns the OPDS catalog feed for a device // GetDeviceCatalog returns the OPDS catalog feed for a device
func (h *OPDSHandler) GetDeviceCatalog(c echo.Context) error { func (h *OPDSHandler) GetDeviceCatalog(c *echo.Context) error {
deviceID := c.Param("deviceId") deviceID := c.Param("deviceId")
page := c.QueryParam("page") page := c.QueryParam("page")
@@ -218,7 +218,7 @@ func (h *OPDSHandler) GetDeviceCatalog(c echo.Context) error {
} }
// SearchDeviceCatalog searches the OPDS catalog for a device // SearchDeviceCatalog searches the OPDS catalog for a device
func (h *OPDSHandler) SearchDeviceCatalog(c echo.Context) error { func (h *OPDSHandler) SearchDeviceCatalog(c *echo.Context) error {
deviceID := c.Param("deviceId") deviceID := c.Param("deviceId")
query := c.QueryParam("q") query := c.QueryParam("q")
@@ -335,7 +335,7 @@ func (h *OPDSHandler) SearchDeviceCatalog(c echo.Context) error {
} }
// DownloadBook downloads a book with optional format conversion // DownloadBook downloads a book with optional format conversion
func (h *OPDSHandler) DownloadBook(c echo.Context) error { func (h *OPDSHandler) DownloadBook(c *echo.Context) error {
deviceID := c.Param("deviceId") deviceID := c.Param("deviceId")
bookID := c.Param("bookId") bookID := c.Param("bookId")
format := c.QueryParam("format") // epub, kepub, pdf, cbz format := c.QueryParam("format") // epub, kepub, pdf, cbz
@@ -488,7 +488,7 @@ func (h *OPDSHandler) DownloadBook(c echo.Context) error {
} }
// GetCoverImage serves a book's cover image // GetCoverImage serves a book's cover image
func (h *OPDSHandler) GetCoverImage(c echo.Context) error { func (h *OPDSHandler) GetCoverImage(c *echo.Context) error {
deviceID := c.Param("deviceId") deviceID := c.Param("deviceId")
bookID := c.Param("bookId") bookID := c.Param("bookId")
@@ -578,7 +578,7 @@ func (h *OPDSHandler) GetCoverImage(c echo.Context) error {
} }
// GetDeviceNavigation returns the OPDS navigation feed for a device // GetDeviceNavigation returns the OPDS navigation feed for a device
func (h *OPDSHandler) GetDeviceNavigation(c echo.Context) error { func (h *OPDSHandler) GetDeviceNavigation(c *echo.Context) error {
deviceID := c.Param("deviceId") deviceID := c.Param("deviceId")
// Get base URLs // Get base URLs
@@ -629,7 +629,7 @@ func (h *OPDSHandler) GetDeviceNavigation(c echo.Context) error {
} }
// ListFormats lists available formats for a book // ListFormats lists available formats for a book
func (h *OPDSHandler) ListFormats(c echo.Context) error { func (h *OPDSHandler) ListFormats(c *echo.Context) error {
deviceID := c.Param("deviceId") deviceID := c.Param("deviceId")
bookID := c.Param("bookId") bookID := c.Param("bookId")
@@ -755,7 +755,7 @@ func (h *OPDSHandler) ListFormats(c echo.Context) error {
} }
// RegisterOPDS registers a device for OPDS access // RegisterOPDS registers a device for OPDS access
func (h *OPDSHandler) RegisterOPDS(c echo.Context) error { func (h *OPDSHandler) RegisterOPDS(c *echo.Context) error {
deviceID := c.Param("deviceId") deviceID := c.Param("deviceId")
// Parse device ID // Parse device ID
+6 -6
View File
@@ -12,7 +12,7 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
"github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgtype" "github.com/jackc/pgx/v5/pgtype"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v5"
) )
// getDeviceIcon returns an emoji icon for device type // getDeviceIcon returns an emoji icon for device type
@@ -30,7 +30,7 @@ func getDeviceIcon(deviceType string) string {
} }
// GetUniversalProgress retrieves progress with all location references // GetUniversalProgress retrieves progress with all location references
func (h *Handler) GetUniversalProgress(c echo.Context) error { func (h *Handler) GetUniversalProgress(c *echo.Context) error {
user := MustGetAuthenticatedUser(c) user := MustGetAuthenticatedUser(c)
mediaItemID, err := uuid.Parse(c.Param("id")) mediaItemID, err := uuid.Parse(c.Param("id"))
@@ -96,7 +96,7 @@ func (h *Handler) GetUniversalProgress(c echo.Context) error {
} }
// UpdateUniversalProgress updates progress with automatic conversion // UpdateUniversalProgress updates progress with automatic conversion
func (h *Handler) UpdateUniversalProgress(c echo.Context) error { func (h *Handler) UpdateUniversalProgress(c *echo.Context) error {
user := MustGetAuthenticatedUser(c) user := MustGetAuthenticatedUser(c)
mediaItemID, err := uuid.Parse(c.Param("id")) mediaItemID, err := uuid.Parse(c.Param("id"))
@@ -212,7 +212,7 @@ func (h *Handler) UpdateUniversalProgress(c echo.Context) error {
} }
// GetProgressHistory retrieves reading session history // GetProgressHistory retrieves reading session history
func (h *Handler) GetProgressHistory(c echo.Context) error { func (h *Handler) GetProgressHistory(c *echo.Context) error {
user := MustGetAuthenticatedUser(c) user := MustGetAuthenticatedUser(c)
mediaItemID, err := uuid.Parse(c.Param("id")) mediaItemID, err := uuid.Parse(c.Param("id"))
@@ -263,7 +263,7 @@ type ProgressWithMedia struct {
} }
// GetAllProgress retrieves all progress for a user with sync source info // GetAllProgress retrieves all progress for a user with sync source info
func (h *Handler) GetAllProgress(c echo.Context) error { func (h *Handler) GetAllProgress(c *echo.Context) error {
user := MustGetAuthenticatedUser(c) user := MustGetAuthenticatedUser(c)
progressList := []ProgressWithMedia{} progressList := []ProgressWithMedia{}
@@ -330,7 +330,7 @@ func (h *Handler) GetAllProgress(c echo.Context) error {
}) })
} }
func (h *Handler) GetAllProgressData(c echo.Context) ([]ProgressWithMedia, error) { func (h *Handler) GetAllProgressData(c *echo.Context) ([]ProgressWithMedia, error) {
user := MustGetAuthenticatedUser(c) user := MustGetAuthenticatedUser(c)
progressList := []ProgressWithMedia{} progressList := []ProgressWithMedia{}
+8 -8
View File
@@ -8,7 +8,7 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
"github.com/jackc/pgx/v5/pgtype" "github.com/jackc/pgx/v5/pgtype"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v5"
) )
type QueueHandler struct { type QueueHandler struct {
@@ -50,7 +50,7 @@ type QueueItemResponse struct {
ProcessedAt *string `json:"processed_at,omitempty"` ProcessedAt *string `json:"processed_at,omitempty"`
} }
func (h *QueueHandler) GetDeviceQueueStats(c echo.Context) error { func (h *QueueHandler) GetDeviceQueueStats(c *echo.Context) error {
user := MustGetAuthenticatedUser(c) user := MustGetAuthenticatedUser(c)
deviceID, err := uuid.Parse(c.Param("device_id")) deviceID, err := uuid.Parse(c.Param("device_id"))
@@ -81,7 +81,7 @@ func (h *QueueHandler) GetDeviceQueueStats(c echo.Context) error {
}) })
} }
func (h *QueueHandler) ListDeviceQueueItems(c echo.Context) error { func (h *QueueHandler) ListDeviceQueueItems(c *echo.Context) error {
user := MustGetAuthenticatedUser(c) user := MustGetAuthenticatedUser(c)
deviceID, err := uuid.Parse(c.Param("device_id")) deviceID, err := uuid.Parse(c.Param("device_id"))
@@ -146,7 +146,7 @@ func (h *QueueHandler) ListDeviceQueueItems(c echo.Context) error {
}) })
} }
func (h *QueueHandler) GetQueueData(c echo.Context) ([]QueueItemResponse, error) { func (h *QueueHandler) GetQueueData(c *echo.Context) ([]QueueItemResponse, error) {
user := MustGetAuthenticatedUser(c) user := MustGetAuthenticatedUser(c)
if user.Role != "admin" { if user.Role != "admin" {
@@ -196,7 +196,7 @@ func (h *QueueHandler) GetQueueData(c echo.Context) ([]QueueItemResponse, error)
return response, nil return response, nil
} }
func (h *QueueHandler) ListAllQueueItems(c echo.Context) error { func (h *QueueHandler) ListAllQueueItems(c *echo.Context) error {
response, err := h.GetQueueData(c) response, err := h.GetQueueData(c)
if err != nil { if err != nil {
return err return err
@@ -208,7 +208,7 @@ func (h *QueueHandler) ListAllQueueItems(c echo.Context) error {
}) })
} }
func (h *QueueHandler) RetryQueueItem(c echo.Context) error { func (h *QueueHandler) RetryQueueItem(c *echo.Context) error {
user := MustGetAuthenticatedUser(c) user := MustGetAuthenticatedUser(c)
itemID, err := uuid.Parse(c.Param("item_id")) itemID, err := uuid.Parse(c.Param("item_id"))
@@ -249,7 +249,7 @@ func (h *QueueHandler) RetryQueueItem(c echo.Context) error {
}) })
} }
func (h *QueueHandler) DeleteQueueItem(c echo.Context) error { func (h *QueueHandler) DeleteQueueItem(c *echo.Context) error {
user := MustGetAuthenticatedUser(c) user := MustGetAuthenticatedUser(c)
itemID, err := uuid.Parse(c.Param("item_id")) itemID, err := uuid.Parse(c.Param("item_id"))
@@ -279,7 +279,7 @@ func (h *QueueHandler) DeleteQueueItem(c echo.Context) error {
return c.NoContent(http.StatusNoContent) return c.NoContent(http.StatusNoContent)
} }
func (h *QueueHandler) ClearDeviceQueue(c echo.Context) error { func (h *QueueHandler) ClearDeviceQueue(c *echo.Context) error {
user := MustGetAuthenticatedUser(c) user := MustGetAuthenticatedUser(c)
deviceID, err := uuid.Parse(c.Param("device_id")) deviceID, err := uuid.Parse(c.Param("device_id"))
+3 -3
View File
@@ -10,7 +10,7 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
"github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgtype" "github.com/jackc/pgx/v5/pgtype"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v5"
) )
const ( const (
@@ -36,7 +36,7 @@ type RefreshTokenResponse struct {
} }
// RefreshAccessToken handles POST /api/auth/refresh // RefreshAccessToken handles POST /api/auth/refresh
func (h *AuthHandler) RefreshAccessToken(c echo.Context) error { func (h *AuthHandler) RefreshAccessToken(c *echo.Context) error {
var req RefreshTokenRequest var req RefreshTokenRequest
if err := c.Bind(&req); err != nil { if err := c.Bind(&req); err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid request"}) return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid request"})
@@ -76,7 +76,7 @@ func (h *AuthHandler) RefreshAccessToken(c echo.Context) error {
} }
// Logout handles POST /api/auth/logout // Logout handles POST /api/auth/logout
func (h *AuthHandler) Logout(c echo.Context) error { func (h *AuthHandler) Logout(c *echo.Context) error {
var req RefreshTokenRequest var req RefreshTokenRequest
if err := c.Bind(&req); err != nil { if err := c.Bind(&req); err != nil {
return c.JSON(http.StatusOK, map[string]string{"message": "logged out successfully"}) return c.JSON(http.StatusOK, map[string]string{"message": "logged out successfully"})
+8 -8
View File
@@ -8,7 +8,7 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
"github.com/jackc/pgx/v5/pgtype" "github.com/jackc/pgx/v5/pgtype"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v5"
) )
const ( const (
@@ -30,7 +30,7 @@ type ScanLibraryRequest struct {
} }
// ScanLibrary handles POST /api/scanner/scan (now runs in background) // ScanLibrary handles POST /api/scanner/scan (now runs in background)
func (h *Handler) ScanLibrary(c echo.Context) error { func (h *Handler) ScanLibrary(c *echo.Context) error {
var req ScanLibraryRequest var req ScanLibraryRequest
// Check if scan_request is set in context (from library scan route) // Check if scan_request is set in context (from library scan route)
@@ -112,7 +112,7 @@ func (h *Handler) ScanLibrary(c echo.Context) error {
} }
// StartScanner handles POST /api/scanner/start // StartScanner handles POST /api/scanner/start
func (h *Handler) StartScanner(c echo.Context) error { func (h *Handler) StartScanner(c *echo.Context) error {
h.mu.Lock() h.mu.Lock()
defer h.mu.Unlock() defer h.mu.Unlock()
@@ -146,7 +146,7 @@ func (h *Handler) StartScanner(c echo.Context) error {
} }
// StopScanner handles POST /api/scanner/stop // StopScanner handles POST /api/scanner/stop
func (h *Handler) StopScanner(c echo.Context) error { func (h *Handler) StopScanner(c *echo.Context) error {
h.mu.Lock() h.mu.Lock()
defer h.mu.Unlock() defer h.mu.Unlock()
@@ -157,7 +157,7 @@ func (h *Handler) StopScanner(c echo.Context) error {
} }
// GetScanStatus handles GET /api/scanner/status/:jobId // GetScanStatus handles GET /api/scanner/status/:jobId
func (h *Handler) GetScanStatus(c echo.Context) error { func (h *Handler) GetScanStatus(c *echo.Context) error {
jobID := c.Param("jobId") jobID := c.Param("jobId")
result, exists := h.worker.GetJobStatus(jobID) result, exists := h.worker.GetJobStatus(jobID)
@@ -238,7 +238,7 @@ func (h *Handler) StopWatchModeForLibrary(libraryID pgtype.UUID) error {
} }
// StartWatchMode handles POST /api/scanner/watch/start // StartWatchMode handles POST /api/scanner/watch/start
func (h *Handler) StartWatchMode(c echo.Context) error { func (h *Handler) StartWatchMode(c *echo.Context) error {
userID := c.Get("user_id").(string) userID := c.Get("user_id").(string)
userUUID, err := uuid.Parse(userID) userUUID, err := uuid.Parse(userID)
if err != nil { if err != nil {
@@ -272,7 +272,7 @@ func (h *Handler) StartWatchMode(c echo.Context) error {
} }
// StopWatchMode handles POST /api/scanner/watch/stop // StopWatchMode handles POST /api/scanner/watch/stop
func (h *Handler) StopWatchMode(c echo.Context) error { func (h *Handler) StopWatchMode(c *echo.Context) error {
var req struct { var req struct {
LibraryID string `json:"library_id"` LibraryID string `json:"library_id"`
} }
@@ -300,7 +300,7 @@ func (h *Handler) StopWatchMode(c echo.Context) error {
} }
// GetWatchModeStatus handles GET /api/scanner/watch/status // GetWatchModeStatus handles GET /api/scanner/watch/status
func (h *Handler) GetWatchModeStatus(c echo.Context) error { func (h *Handler) GetWatchModeStatus(c *echo.Context) error {
h.mu.Lock() h.mu.Lock()
defer h.mu.Unlock() defer h.mu.Unlock()
+5 -5
View File
@@ -9,7 +9,7 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
"github.com/jackc/pgx/v5/pgtype" "github.com/jackc/pgx/v5/pgtype"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v5"
) )
type SidecarHandler struct { type SidecarHandler struct {
@@ -56,7 +56,7 @@ type SidecarCollection struct {
// GetSidecarConfig generates and returns sidecar configuration for a device // GetSidecarConfig generates and returns sidecar configuration for a device
// GET /api/devices/:device_id/sidecar // GET /api/devices/:device_id/sidecar
func (h *SidecarHandler) GetSidecarConfig(c echo.Context) error { func (h *SidecarHandler) GetSidecarConfig(c *echo.Context) error {
deviceID, err := uuid.Parse(c.Param("device_id")) deviceID, err := uuid.Parse(c.Param("device_id"))
if err != nil { if err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{ return c.JSON(http.StatusBadRequest, map[string]string{
@@ -189,7 +189,7 @@ func (h *SidecarHandler) GetSidecarConfig(c echo.Context) error {
// DownloadSidecarConfig generates a .bookhoard.json file for device setup // DownloadSidecarConfig generates a .bookhoard.json file for device setup
// GET /api/devices/:device_id/sidecar/download // GET /api/devices/:device_id/sidecar/download
func (h *SidecarHandler) DownloadSidecarConfig(c echo.Context) error { func (h *SidecarHandler) DownloadSidecarConfig(c *echo.Context) error {
deviceID, err := uuid.Parse(c.Param("device_id")) deviceID, err := uuid.Parse(c.Param("device_id"))
if err != nil { if err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{ return c.JSON(http.StatusBadRequest, map[string]string{
@@ -333,7 +333,7 @@ func (h *SidecarHandler) DownloadSidecarConfig(c echo.Context) error {
// GetSystemConfiguration returns system-wide configuration // GetSystemConfiguration returns system-wide configuration
// GET /api/system/config // GET /api/system/config
func (h *SidecarHandler) GetSystemConfiguration(c echo.Context) error { func (h *SidecarHandler) GetSystemConfiguration(c *echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
// Get all system config // Get all system config
@@ -355,7 +355,7 @@ func (h *SidecarHandler) GetSystemConfiguration(c echo.Context) error {
// UpdateSystemConfiguration updates system-wide configuration // UpdateSystemConfiguration updates system-wide configuration
// PUT /api/system/config // PUT /api/system/config
func (h *SidecarHandler) UpdateSystemConfiguration(c echo.Context) error { func (h *SidecarHandler) UpdateSystemConfiguration(c *echo.Context) error {
user := c.Get("user") user := c.Get("user")
if user == nil { if user == nil {
return c.JSON(http.StatusUnauthorized, map[string]string{ return c.JSON(http.StatusUnauthorized, map[string]string{
+3 -3
View File
@@ -7,7 +7,7 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
"github.com/jackc/pgx/v5/pgtype" "github.com/jackc/pgx/v5/pgtype"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v5"
) )
type SyncHandler struct { type SyncHandler struct {
@@ -52,7 +52,7 @@ type LinkBookResponse struct {
// GetUnlinkedBooks returns all unlinked books for a user's devices // GetUnlinkedBooks returns all unlinked books for a user's devices
// GET /api/sync/unlinked-books // GET /api/sync/unlinked-books
func (h *SyncHandler) GetUnlinkedBooks(c echo.Context) error { func (h *SyncHandler) GetUnlinkedBooks(c *echo.Context) error {
// Get user from context (assuming auth middleware sets this) // Get user from context (assuming auth middleware sets this)
user := c.Get("user") user := c.Get("user")
if user == nil { if user == nil {
@@ -105,7 +105,7 @@ func (h *SyncHandler) GetUnlinkedBooks(c echo.Context) error {
// LinkBook manually links an unlinked book to a media item // LinkBook manually links an unlinked book to a media item
// POST /api/sync/link-book // POST /api/sync/link-book
func (h *SyncHandler) LinkBook(c echo.Context) error { func (h *SyncHandler) LinkBook(c *echo.Context) error {
var req LinkBookRequest var req LinkBookRequest
if err := c.Bind(&req); err != nil { if err := c.Bind(&req); err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{ return c.JSON(http.StatusBadRequest, map[string]string{
+3 -3
View File
@@ -6,7 +6,7 @@ import (
"strconv" "strconv"
"github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v5"
) )
type SystemSettingsHandler struct { type SystemSettingsHandler struct {
@@ -30,7 +30,7 @@ type ScanSettingsResponse struct {
Message string `json:"message,omitempty"` Message string `json:"message,omitempty"`
} }
func (h *SystemSettingsHandler) UpdateScanSettings(c echo.Context) error { func (h *SystemSettingsHandler) UpdateScanSettings(c *echo.Context) error {
var req UpdateScanSettingsRequest var req UpdateScanSettingsRequest
if err := c.Bind(&req); err != nil { if err := c.Bind(&req); err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid request"}) return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid request"})
@@ -71,7 +71,7 @@ func (h *SystemSettingsHandler) UpdateScanSettings(c echo.Context) error {
}) })
} }
func (h *SystemSettingsHandler) GetScanSettings(c echo.Context) error { func (h *SystemSettingsHandler) GetScanSettings(c *echo.Context) error {
scanFrequencySetting, err := h.db.GetSystemSetting(c.Request().Context(), "scan_poll_interval_seconds") scanFrequencySetting, err := h.db.GetSystemSetting(c.Request().Context(), "scan_poll_interval_seconds")
if err != nil { if err != nil {
if err == pgx.ErrNoRows { if err == pgx.ErrNoRows {
+2 -2
View File
@@ -13,7 +13,7 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
"github.com/jackc/pgx/v5/pgtype" "github.com/jackc/pgx/v5/pgtype"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v5"
) )
var upgrader = websocket.Upgrader{ var upgrader = websocket.Upgrader{
@@ -54,7 +54,7 @@ type ClientInfo struct {
IsDevice bool IsDevice bool
} }
func (h *WSHandler) HandleWebSocket(c echo.Context) error { func (h *WSHandler) HandleWebSocket(c *echo.Context) error {
token := c.QueryParam("token") token := c.QueryParam("token")
if token == "" { if token == "" {
return c.JSON(http.StatusUnauthorized, map[string]string{"error": "token required"}) return c.JSON(http.StatusUnauthorized, map[string]string{"error": "token required"})