From c5754181f6c57f0c261610b83691d658983a7075 Mon Sep 17 00:00:00 2001 From: Joakim Date: Tue, 23 Sep 2025 22:04:54 +0200 Subject: [PATCH] Add position validation and position-only update support to collection item API --- internal/api/handlers.go | 127 ++++++++++++++++++++++++++++++++++----- 1 file changed, 113 insertions(+), 14 deletions(-) diff --git a/internal/api/handlers.go b/internal/api/handlers.go index bcacb5d..d373ac5 100644 --- a/internal/api/handlers.go +++ b/internal/api/handlers.go @@ -1051,23 +1051,122 @@ func (h *ContentHandler) UpdateCollectionItem(w http.ResponseWriter, r *http.Req var updatedItem interface{} var err error + // Validate position bounds if position update is requested + if req.Position > 0 { + var maxPos int64 + switch h.database.GetDBType() { + case "sqlite3": + result, err := h.database.GetSQLiteQueries().GetMaxPosition(context.Background(), sqlite.GetMaxPositionParams{ + CollectionID: collectionID, + SiteID: siteID, + }) + if err != nil { + http.Error(w, "Failed to get max position", http.StatusInternalServerError) + return + } + // Convert interface{} to int64 + switch v := result.(type) { + case int64: + maxPos = v + case int: + maxPos = int64(v) + default: + maxPos = 0 + } + case "postgresql": + result, err := h.database.GetPostgreSQLQueries().GetMaxPosition(context.Background(), postgresql.GetMaxPositionParams{ + CollectionID: collectionID, + SiteID: siteID, + }) + if err != nil { + http.Error(w, "Failed to get max position", http.StatusInternalServerError) + return + } + // Convert interface{} to int64 + switch v := result.(type) { + case int64: + maxPos = v + case int32: + maxPos = int64(v) + case int: + maxPos = int64(v) + default: + maxPos = 0 + } + } + + // Check if position is valid (1-based, within bounds) + if int64(req.Position) > maxPos { + http.Error(w, fmt.Sprintf("Invalid position: %d exceeds max position %d", req.Position, maxPos), http.StatusBadRequest) + return + } + } + switch h.database.GetDBType() { case "sqlite3": - updatedItem, err = h.database.GetSQLiteQueries().UpdateCollectionItem(context.Background(), sqlite.UpdateCollectionItemParams{ - ItemID: itemID, - CollectionID: collectionID, - SiteID: siteID, - HtmlContent: req.HTMLContent, - LastEditedBy: req.UpdatedBy, - }) + // Update position if provided + if req.Position > 0 { + err = h.database.GetSQLiteQueries().UpdateCollectionItemPosition(context.Background(), sqlite.UpdateCollectionItemPositionParams{ + ItemID: itemID, + CollectionID: collectionID, + SiteID: siteID, + Position: int64(req.Position), + }) + if err != nil { + http.Error(w, fmt.Sprintf("Failed to update position: %v", err), http.StatusInternalServerError) + return + } + } + + // If only position update (no html_content), just get the updated item + if req.HTMLContent == "" { + updatedItem, err = h.database.GetSQLiteQueries().GetCollectionItem(context.Background(), sqlite.GetCollectionItemParams{ + ItemID: itemID, + CollectionID: collectionID, + SiteID: siteID, + }) + } else { + // Update content and metadata + updatedItem, err = h.database.GetSQLiteQueries().UpdateCollectionItem(context.Background(), sqlite.UpdateCollectionItemParams{ + ItemID: itemID, + CollectionID: collectionID, + SiteID: siteID, + HtmlContent: req.HTMLContent, + LastEditedBy: req.UpdatedBy, + }) + } case "postgresql": - updatedItem, err = h.database.GetPostgreSQLQueries().UpdateCollectionItem(context.Background(), postgresql.UpdateCollectionItemParams{ - ItemID: itemID, - CollectionID: collectionID, - SiteID: siteID, - HtmlContent: req.HTMLContent, - LastEditedBy: req.UpdatedBy, - }) + // Update position if provided + if req.Position > 0 { + err = h.database.GetPostgreSQLQueries().UpdateCollectionItemPosition(context.Background(), postgresql.UpdateCollectionItemPositionParams{ + ItemID: itemID, + CollectionID: collectionID, + SiteID: siteID, + Position: int32(req.Position), + }) + if err != nil { + http.Error(w, fmt.Sprintf("Failed to update position: %v", err), http.StatusInternalServerError) + return + } + } + + // If only position update (no html_content), just get the updated item + if req.HTMLContent == "" { + updatedItem, err = h.database.GetPostgreSQLQueries().GetCollectionItem(context.Background(), postgresql.GetCollectionItemParams{ + ItemID: itemID, + CollectionID: collectionID, + SiteID: siteID, + }) + } else { + // Update content and metadata + updatedItem, err = h.database.GetPostgreSQLQueries().UpdateCollectionItem(context.Background(), postgresql.UpdateCollectionItemParams{ + ItemID: itemID, + CollectionID: collectionID, + SiteID: siteID, + HtmlContent: req.HTMLContent, + LastEditedBy: req.UpdatedBy, + }) + } default: http.Error(w, "Unsupported database type", http.StatusInternalServerError) return