Collections: allow to drag and drop to change book position

This commit is contained in:
2026-04-12 01:44:25 +02:00
parent d2fe3bf34f
commit 178c688203
15 changed files with 328 additions and 12 deletions

View File

@@ -0,0 +1,106 @@
package routes
import (
"errors"
"net/http"
"strconv"
"git.artlef.fr/bibliomane/internal/appcontext"
"git.artlef.fr/bibliomane/internal/dto"
"git.artlef.fr/bibliomane/internal/i18nresource"
"git.artlef.fr/bibliomane/internal/model"
"git.artlef.fr/bibliomane/internal/myvalidator"
"git.artlef.fr/bibliomane/internal/query"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
func PostCollectionChangePositionHandler(ac appcontext.AppContext) {
collectionId, err := strconv.ParseUint(ac.C.Param("id"), 10, 64)
if err != nil {
ac.C.JSON(http.StatusBadRequest, gin.H{"error": err})
return
}
user, err := ac.GetAuthenticatedUser()
if err != nil {
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
return
}
var collection model.Collection
err = ac.Db.First(&collection, collectionId).Error
if err != nil {
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
return
}
if collection.UserID != user.ID {
err := myvalidator.HttpError{
StatusCode: http.StatusUnauthorized,
Err: errors.New(i18nresource.GetTranslatedMessage(&ac, "Unauthorized")),
}
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
return
}
var collectionBookPosition dto.CollectionItemPosition
err = ac.C.ShouldBindJSON(&collectionBookPosition)
if err != nil {
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
return
}
var item model.CollectionItem
err = ac.Db.First(&item, collectionBookPosition.ItemID).Error
if err != nil {
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
return
}
if collection.ID != item.CollectionID {
err := myvalidator.HttpError{
StatusCode: http.StatusInternalServerError,
Err: errors.New(i18nresource.GetTranslatedMessage(&ac, "ItemDoesNotBelongToCollection")),
}
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
return
}
count, err := query.FetchCollectionBooksCount(ac.Db, user.ID, item.CollectionID)
if err != nil {
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
return
}
newPosition := collectionBookPosition.Position
if int64(newPosition) > count {
newPosition = uint(count)
}
if item.Position == collectionBookPosition.Position {
//nothing to do
ac.C.String(http.StatusOK, "Success")
return
}
lowerPosition := item.Position + 1
higherPosition := item.Position - 1
operationToDo := ""
if item.Position < collectionBookPosition.Position {
higherPosition = collectionBookPosition.Position
operationToDo = "position - 1"
} else {
lowerPosition = collectionBookPosition.Position
operationToDo = "position + 1"
}
q := ac.Db.Model(&model.CollectionItem{})
q = q.Where("collection_id = ? AND position BETWEEN ? AND ?", collection.ID, lowerPosition, higherPosition)
err = q.UpdateColumn("position", gorm.Expr(operationToDo)).Error
if err != nil {
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
return
}
item.Position = collectionBookPosition.Position
ac.Db.Save(&item)
ac.C.String(http.StatusOK, "Success")
}