feat(api): add library_id filtering to collections endpoints
Add optional library_id query parameter support to GetCollections and GetCollection API handlers for library-scoped book filtering. GetCollections (GET /api/collections?library_id=X): - When library_id is provided, include per-library book_count in the response by querying GetCollectionItemsForDashboard for each collection - When omitted, returns all collections as before (backward compatible) - Added BookCount field to CollectionResponse struct GetCollection (GET /api/collections/:id?library_id=X): - System collections (non-empty QueryType): uses DashboardService to fetch library-scoped sections, matching the existing SSR handler logic - User collections: uses GetCollectionItemsForDashboard for library-filtered results, excluding soft-deleted items - When library_id is omitted, returns all books as before
This commit is contained in:
@@ -138,6 +138,7 @@ func (h *CollectionHandler) CreateCollection(c *echo.Context) error {
|
||||
func (h *CollectionHandler) GetCollections(c *echo.Context) error {
|
||||
includeAuto := c.QueryParam("include_auto") == "true"
|
||||
sortBy := c.QueryParam("sort_by")
|
||||
libraryID := c.QueryParam("library_id")
|
||||
|
||||
collections, err := h.GetCollectionsData(c)
|
||||
if err != nil {
|
||||
@@ -152,6 +153,7 @@ func (h *CollectionHandler) GetCollections(c *echo.Context) error {
|
||||
Icon string `json:"icon"`
|
||||
AutoAssignRules json.RawMessage `json:"auto_assign_rules"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
BookCount int `json:"book_count"`
|
||||
}
|
||||
|
||||
response := make([]CollectionResponse, 0, len(collections))
|
||||
@@ -159,6 +161,26 @@ func (h *CollectionHandler) GetCollections(c *echo.Context) error {
|
||||
if !includeAuto && len(col.AutoAssignRules) > 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
bookCount := 0
|
||||
if libraryID != "" {
|
||||
libUUID, libErr := uuid.Parse(libraryID)
|
||||
if libErr == nil {
|
||||
items, countErr := h.db.GetCollectionItemsForDashboard(c.Request().Context(), database.GetCollectionItemsForDashboardParams{
|
||||
CollectionID: pgtype.UUID{Bytes: col.ID.Bytes, Valid: true},
|
||||
LibraryID: pgtype.UUID{Bytes: libUUID, Valid: true},
|
||||
Limit: 10000,
|
||||
})
|
||||
if countErr == nil {
|
||||
for _, item := range items {
|
||||
if !item.Excluded.Valid || !item.Excluded.Bool {
|
||||
bookCount++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
response = append(response, CollectionResponse{
|
||||
ID: col.ID.Bytes,
|
||||
Name: col.Name,
|
||||
@@ -167,6 +189,7 @@ func (h *CollectionHandler) GetCollections(c *echo.Context) error {
|
||||
Icon: textToString(col.Icon),
|
||||
AutoAssignRules: col.AutoAssignRules,
|
||||
CreatedAt: col.CreatedAt.Time.String(),
|
||||
BookCount: bookCount,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -197,19 +220,83 @@ func (h *CollectionHandler) GetCollection(c *echo.Context) error {
|
||||
return c.JSON(http.StatusNotFound, map[string]string{"error": "collection not found"})
|
||||
}
|
||||
|
||||
books, err := h.GetCollectionBooksData(c, collectionID)
|
||||
if err != nil {
|
||||
return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
||||
}
|
||||
libraryID := c.QueryParam("library_id")
|
||||
var bookList []BookInfo
|
||||
|
||||
bookList := make([]BookInfo, 0, len(books))
|
||||
for _, book := range books {
|
||||
bookList = append(bookList, BookInfo{
|
||||
MediaItemID: uuid.UUID(book.MediaItemID.Bytes).String(),
|
||||
Title: book.Title,
|
||||
Author: textToString(book.Author),
|
||||
CoverImagePath: utils.ResolveMediaURL(book.LibraryID, book.CoverImagePath),
|
||||
})
|
||||
if libraryID != "" && collection.QueryType.Valid && collection.QueryType.String != "" {
|
||||
libUUID, libErr := uuid.Parse(libraryID)
|
||||
if libErr != nil {
|
||||
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid library_id"})
|
||||
}
|
||||
user := c.Get("user").(database.Users)
|
||||
userUUID := uuid.UUID(user.ID.Bytes)
|
||||
dashboardSvc := services.NewDashboardService(h.db)
|
||||
sections, secErr := dashboardSvc.GetDashboardSections(c.Request().Context(), userUUID, libUUID, 1000, []string{}, []string{})
|
||||
if secErr != nil {
|
||||
return c.JSON(http.StatusInternalServerError, map[string]string{"error": secErr.Error()})
|
||||
}
|
||||
for _, section := range sections {
|
||||
if section.CollectionID == collectionID {
|
||||
bookCards := make([]BookInfo, len(section.Items))
|
||||
for i, item := range section.Items {
|
||||
itemUUID, _ := uuid.FromBytes(item.ID.Bytes[0:16])
|
||||
bookCards[i] = BookInfo{
|
||||
MediaItemID: itemUUID.String(),
|
||||
Title: item.Title,
|
||||
Author: textToString(item.Author),
|
||||
CoverImagePath: utils.ResolveMediaURL(item.LibraryID, item.CoverImagePath),
|
||||
}
|
||||
}
|
||||
bookList = bookCards
|
||||
break
|
||||
}
|
||||
}
|
||||
} else if libraryID != "" {
|
||||
libUUID, libErr := uuid.Parse(libraryID)
|
||||
if libErr != nil {
|
||||
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid library_id"})
|
||||
}
|
||||
collItems, collErr := h.db.GetCollectionItemsForDashboard(c.Request().Context(),
|
||||
database.GetCollectionItemsForDashboardParams{
|
||||
CollectionID: pgtype.UUID{Bytes: collectionID, Valid: true},
|
||||
LibraryID: pgtype.UUID{Bytes: libUUID, Valid: true},
|
||||
Limit: 10000,
|
||||
})
|
||||
if collErr != nil {
|
||||
bookList = []BookInfo{}
|
||||
} else {
|
||||
var validItems []database.GetCollectionItemsForDashboardRow
|
||||
for _, item := range collItems {
|
||||
if !item.Excluded.Valid || !item.Excluded.Bool {
|
||||
validItems = append(validItems, item)
|
||||
}
|
||||
}
|
||||
bookCards := make([]BookInfo, len(validItems))
|
||||
for i, item := range validItems {
|
||||
itemUUID, _ := uuid.FromBytes(item.ID.Bytes[0:16])
|
||||
bookCards[i] = BookInfo{
|
||||
MediaItemID: itemUUID.String(),
|
||||
Title: item.Title,
|
||||
Author: textToString(item.Author),
|
||||
CoverImagePath: utils.ResolveMediaURL(item.LibraryID, item.CoverImagePath),
|
||||
}
|
||||
}
|
||||
bookList = bookCards
|
||||
}
|
||||
} else {
|
||||
books, booksErr := h.GetCollectionBooksData(c, collectionID)
|
||||
if booksErr != nil {
|
||||
return c.JSON(http.StatusInternalServerError, map[string]string{"error": booksErr.Error()})
|
||||
}
|
||||
bookList = make([]BookInfo, 0, len(books))
|
||||
for _, book := range books {
|
||||
bookList = append(bookList, BookInfo{
|
||||
MediaItemID: uuid.UUID(book.MediaItemID.Bytes).String(),
|
||||
Title: book.Title,
|
||||
Author: textToString(book.Author),
|
||||
CoverImagePath: utils.ResolveMediaURL(book.LibraryID, book.CoverImagePath),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
var viewSettings map[string]interface{}
|
||||
|
||||
Reference in New Issue
Block a user