- Fix type assertion panics in library.go (lines 58, 109, 237) Changed from *database.Users to database.Users to match JWT middleware - Fix ISBN type mismatch in ebook.go (lines 249, 308) Changed from pgtype.Text to string to match database schema - Fix ISBN type mismatch in ebook_scanner.go (line 421) Changed from pgtype.Text to string to match database schema These changes fix 500 errors in library creation and ebook operations.
288 lines
8.7 KiB
Go
288 lines
8.7 KiB
Go
package handlers
|
|
|
|
import (
|
|
"bookmann/internal/database"
|
|
"bookmann/internal/services"
|
|
"net/http"
|
|
"os"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/jackc/pgx/v5/pgtype"
|
|
"github.com/labstack/echo/v4"
|
|
)
|
|
|
|
type LibraryHandler struct {
|
|
db *database.Queries
|
|
libraryService *services.LibraryService
|
|
}
|
|
|
|
func NewLibraryHandler(db *database.Queries) *LibraryHandler {
|
|
return &LibraryHandler{
|
|
db: db,
|
|
libraryService: services.NewLibraryService(db),
|
|
}
|
|
}
|
|
|
|
// Request/Response types
|
|
type CreateLibraryRequest struct {
|
|
Name string `json:"name" validate:"required"`
|
|
Description string `json:"description"`
|
|
Type string `json:"type" validate:"required"`
|
|
}
|
|
|
|
type UpdateLibraryRequest struct {
|
|
Name string `json:"name" validate:"required"`
|
|
Description string `json:"description"`
|
|
}
|
|
|
|
type AddLibraryFolderRequest struct {
|
|
FolderPath string `json:"folder_path" validate:"required"`
|
|
}
|
|
|
|
type SetLibraryVisibilityRequest struct {
|
|
LibraryID string `json:"library_id" validate:"required"`
|
|
IsVisible bool `json:"is_visible"`
|
|
}
|
|
|
|
// GetLibraryTypes retrieves all available library types
|
|
func (h *LibraryHandler) GetLibraryTypes(c echo.Context) error {
|
|
types, err := h.libraryService.GetLibraryTypes(c.Request().Context())
|
|
if err != nil {
|
|
return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
|
}
|
|
return c.JSON(http.StatusOK, types)
|
|
}
|
|
|
|
// CreateLibrary creates a new library
|
|
func (h *LibraryHandler) CreateLibrary(c echo.Context) error {
|
|
user := c.Get("user").(database.Users)
|
|
|
|
var req CreateLibraryRequest
|
|
if err := c.Bind(&req); err != nil {
|
|
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid request"})
|
|
}
|
|
if err := c.Validate(&req); err != nil {
|
|
return c.JSON(http.StatusBadRequest, map[string]string{"error": err.Error()})
|
|
}
|
|
|
|
library, err := h.libraryService.CreateLibrary(
|
|
c.Request().Context(),
|
|
req.Name,
|
|
req.Description,
|
|
req.Type,
|
|
user.ID,
|
|
)
|
|
if err != nil {
|
|
return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
|
}
|
|
|
|
return c.JSON(http.StatusCreated, library)
|
|
}
|
|
|
|
// GetLibrary retrieves a specific library
|
|
func (h *LibraryHandler) GetLibrary(c echo.Context) error {
|
|
libraryID, err := parseUUID(c.Param("id"))
|
|
if err != nil {
|
|
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid library id"})
|
|
}
|
|
|
|
library, err := h.libraryService.GetLibrary(c.Request().Context(), libraryID)
|
|
if err != nil {
|
|
return c.JSON(http.StatusNotFound, map[string]string{"error": "library not found"})
|
|
}
|
|
|
|
return c.JSON(http.StatusOK, library)
|
|
}
|
|
|
|
// ListLibraries retrieves all libraries (admin only)
|
|
func (h *LibraryHandler) ListLibraries(c echo.Context) error {
|
|
libraries, err := h.libraryService.ListLibraries(c.Request().Context())
|
|
if err != nil {
|
|
return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
|
}
|
|
|
|
return c.JSON(http.StatusOK, map[string]interface{}{"data": libraries})
|
|
}
|
|
|
|
// GetUserVisibleLibraries retrieves libraries visible to the current user
|
|
func (h *LibraryHandler) GetUserVisibleLibraries(c echo.Context) error {
|
|
user := c.Get("user").(database.Users)
|
|
|
|
libraries, err := h.libraryService.GetUserVisibleLibraries(c.Request().Context(), user.ID)
|
|
if err != nil {
|
|
return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
|
}
|
|
|
|
return c.JSON(http.StatusOK, libraries)
|
|
}
|
|
|
|
// UpdateLibrary updates an existing library
|
|
func (h *LibraryHandler) UpdateLibrary(c echo.Context) error {
|
|
libraryID, err := parseUUID(c.Param("id"))
|
|
if err != nil {
|
|
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid library id"})
|
|
}
|
|
|
|
var req UpdateLibraryRequest
|
|
if err := c.Bind(&req); err != nil {
|
|
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid request"})
|
|
}
|
|
if err := c.Validate(&req); err != nil {
|
|
return c.JSON(http.StatusBadRequest, map[string]string{"error": err.Error()})
|
|
}
|
|
|
|
library, err := h.libraryService.UpdateLibrary(
|
|
c.Request().Context(),
|
|
libraryID,
|
|
req.Name,
|
|
req.Description,
|
|
)
|
|
if err != nil {
|
|
return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
|
}
|
|
|
|
return c.JSON(http.StatusOK, library)
|
|
}
|
|
|
|
// DeleteLibrary deletes a library
|
|
func (h *LibraryHandler) DeleteLibrary(c echo.Context) error {
|
|
libraryID, err := parseUUID(c.Param("id"))
|
|
if err != nil {
|
|
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid library id"})
|
|
}
|
|
|
|
err = h.libraryService.DeleteLibrary(c.Request().Context(), libraryID)
|
|
if err != nil {
|
|
return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
|
}
|
|
|
|
return c.NoContent(http.StatusNoContent)
|
|
}
|
|
|
|
// AddLibraryFolder adds a folder to a library
|
|
func (h *LibraryHandler) AddLibraryFolder(c echo.Context) error {
|
|
libraryID, err := parseUUID(c.Param("id"))
|
|
if err != nil {
|
|
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid library id"})
|
|
}
|
|
|
|
var req AddLibraryFolderRequest
|
|
if err := c.Bind(&req); err != nil {
|
|
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid request"})
|
|
}
|
|
if err := c.Validate(&req); err != nil {
|
|
return c.JSON(http.StatusBadRequest, map[string]string{"error": err.Error()})
|
|
}
|
|
|
|
// Validate that folder path exists and is accessible
|
|
if _, err := os.Stat(req.FolderPath); os.IsNotExist(err) {
|
|
return c.JSON(http.StatusBadRequest, map[string]string{"error": "folder path does not exist"})
|
|
}
|
|
if err != nil {
|
|
return c.JSON(http.StatusBadRequest, map[string]string{"error": "folder is not accessible"})
|
|
}
|
|
|
|
folder, err := h.libraryService.AddLibraryFolder(
|
|
c.Request().Context(),
|
|
libraryID,
|
|
req.FolderPath,
|
|
)
|
|
if err != nil {
|
|
return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
|
}
|
|
|
|
return c.JSON(http.StatusCreated, folder)
|
|
}
|
|
|
|
// GetLibraryFolders retrieves all folders for a library
|
|
func (h *LibraryHandler) GetLibraryFolders(c echo.Context) error {
|
|
libraryID, err := parseUUID(c.Param("id"))
|
|
if err != nil {
|
|
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid library id"})
|
|
}
|
|
|
|
folders, err := h.libraryService.GetLibraryFolders(c.Request().Context(), libraryID)
|
|
if err != nil {
|
|
return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
|
}
|
|
|
|
return c.JSON(http.StatusOK, folders)
|
|
}
|
|
|
|
// DeleteLibraryFolder removes a folder from a library
|
|
func (h *LibraryHandler) DeleteLibraryFolder(c echo.Context) error {
|
|
libraryID, err := parseUUID(c.Param("id"))
|
|
if err != nil {
|
|
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid library id"})
|
|
}
|
|
|
|
var req AddLibraryFolderRequest // reuse same structure for folder_path
|
|
if err := c.Bind(&req); err != nil {
|
|
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid request"})
|
|
}
|
|
if err := c.Validate(&req); err != nil {
|
|
return c.JSON(http.StatusBadRequest, map[string]string{"error": err.Error()})
|
|
}
|
|
|
|
err = h.libraryService.DeleteLibraryFolder(c.Request().Context(), libraryID, req.FolderPath)
|
|
if err != nil {
|
|
return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
|
}
|
|
|
|
return c.NoContent(http.StatusNoContent)
|
|
}
|
|
|
|
// SetLibraryVisibility sets library visibility for a user
|
|
func (h *LibraryHandler) SetLibraryVisibility(c echo.Context) error {
|
|
user := c.Get("user").(database.Users)
|
|
|
|
var req SetLibraryVisibilityRequest
|
|
if err := c.Bind(&req); err != nil {
|
|
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid request"})
|
|
}
|
|
if err := c.Validate(&req); err != nil {
|
|
return c.JSON(http.StatusBadRequest, map[string]string{"error": err.Error()})
|
|
}
|
|
|
|
libraryID, err := parseUUID(req.LibraryID)
|
|
if err != nil {
|
|
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid library id"})
|
|
}
|
|
|
|
visibility, err := h.libraryService.SetLibraryVisibility(
|
|
c.Request().Context(),
|
|
user.ID,
|
|
libraryID,
|
|
req.IsVisible,
|
|
)
|
|
if err != nil {
|
|
return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
|
}
|
|
|
|
return c.JSON(http.StatusOK, visibility)
|
|
}
|
|
|
|
// GetLibraryStats retrieves statistics for a library
|
|
func (h *LibraryHandler) GetLibraryStats(c echo.Context) error {
|
|
libraryID, err := parseUUID(c.Param("id"))
|
|
if err != nil {
|
|
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid library id"})
|
|
}
|
|
|
|
stats, err := h.libraryService.GetLibraryStats(c.Request().Context(), libraryID)
|
|
if err != nil {
|
|
return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
|
}
|
|
|
|
return c.JSON(http.StatusOK, stats)
|
|
}
|
|
|
|
// Helper function
|
|
func parseUUID(uuidStr string) (pgtype.UUID, error) {
|
|
parsedUUID, err := uuid.Parse(uuidStr)
|
|
if err != nil {
|
|
return pgtype.UUID{}, err
|
|
}
|
|
return pgtype.UUID{Bytes: [16]byte(parsedUUID), Valid: true}, nil
|
|
}
|