alist/server/handles/label_file_binding.go

251 lines
6.1 KiB
Go

package handles
import (
"errors"
"fmt"
"github.com/alist-org/alist/v3/internal/db"
"github.com/alist-org/alist/v3/internal/model"
"github.com/alist-org/alist/v3/internal/op"
"github.com/alist-org/alist/v3/server/common"
"github.com/gin-gonic/gin"
"net/url"
"strconv"
"strings"
)
type DelLabelFileBinDingReq struct {
FileName string `json:"file_name"`
LabelId string `json:"label_id"`
}
type pageResp[T any] struct {
Content []T `json:"content"`
Total int64 `json:"total"`
}
type restoreLabelBindingsReq struct {
KeepIDs bool `json:"keep_ids"`
Override bool `json:"override"`
Bindings []model.LabelFileBinding `json:"bindings"`
}
func GetLabelByFileName(c *gin.Context) {
fileName := c.Query("file_name")
if fileName == "" {
common.ErrorResp(c, errors.New("file_name must not empty"), 400)
return
}
decodedFileName, err := url.QueryUnescape(fileName)
if err != nil {
common.ErrorResp(c, errors.New("invalid file_name"), 400)
return
}
fmt.Println(">>> 原始 fileName:", fileName)
fmt.Println(">>> 解码后 fileName:", decodedFileName)
userObj, ok := c.Value("user").(*model.User)
if !ok {
common.ErrorStrResp(c, "user invalid", 401)
return
}
labels, err := op.GetLabelByFileName(userObj.ID, decodedFileName)
if err != nil {
common.ErrorResp(c, err, 500, true)
return
}
common.SuccessResp(c, labels)
}
func CreateLabelFileBinDing(c *gin.Context) {
var req op.CreateLabelFileBinDingReq
if err := c.ShouldBind(&req); err != nil {
common.ErrorResp(c, err, 400)
return
}
if req.IsDir == true {
common.ErrorStrResp(c, "Unable to bind folder", 400)
return
}
userObj, ok := c.Value("user").(*model.User)
if !ok {
common.ErrorStrResp(c, "user invalid", 401)
return
}
if err := op.CreateLabelFileBinDing(req, userObj.ID); err != nil {
common.ErrorResp(c, err, 500, true)
return
} else {
common.SuccessResp(c, gin.H{
"msg": "添加成功!",
})
}
}
func DelLabelByFileName(c *gin.Context) {
var req DelLabelFileBinDingReq
if err := c.ShouldBind(&req); err != nil {
common.ErrorResp(c, err, 400)
return
}
userObj, ok := c.Value("user").(*model.User)
if !ok {
common.ErrorStrResp(c, "user invalid", 401)
return
}
labelId, err := strconv.ParseUint(req.LabelId, 10, 64)
if err != nil {
common.ErrorResp(c, fmt.Errorf("invalid label ID '%s': %v", req.LabelId, err), 500, true)
return
}
if err = db.DelLabelFileBinDingById(uint(labelId), userObj.ID, req.FileName); err != nil {
common.ErrorResp(c, err, 500, true)
return
}
common.SuccessResp(c)
}
func GetFileByLabel(c *gin.Context) {
labelId := c.Query("label_id")
if labelId == "" {
common.ErrorResp(c, errors.New("file_name must not empty"), 400)
return
}
userObj, ok := c.Value("user").(*model.User)
if !ok {
common.ErrorStrResp(c, "user invalid", 401)
return
}
fileList, err := op.GetFileByLabel(userObj.ID, labelId)
if err != nil {
common.ErrorResp(c, err, 500, true)
return
}
common.SuccessResp(c, fileList)
}
func ListLabelFileBinding(c *gin.Context) {
userObj, ok := c.Value("user").(*model.User)
if !ok {
common.ErrorStrResp(c, "user invalid", 401)
return
}
pageStr := c.DefaultQuery("page", "1")
sizeStr := c.DefaultQuery("page_size", "50")
page, err := strconv.Atoi(pageStr)
if err != nil || page <= 0 {
page = 1
}
pageSize, err := strconv.Atoi(sizeStr)
if err != nil || pageSize <= 0 || pageSize > 200 {
pageSize = 50
}
fileName := c.Query("file_name")
labelIDStr := c.Query("label_id")
var labelIDs []uint
if labelIDStr != "" {
parts := strings.Split(labelIDStr, ",")
for _, p := range parts {
if p == "" {
continue
}
id64, err := strconv.ParseUint(strings.TrimSpace(p), 10, 64)
if err != nil {
common.ErrorResp(c, fmt.Errorf("invalid label_id '%s': %v", p, err), 400)
return
}
labelIDs = append(labelIDs, uint(id64))
}
}
list, total, err := db.ListLabelFileBinDing(userObj.ID, labelIDs, fileName, page, pageSize)
if err != nil {
common.ErrorResp(c, err, 500, true)
return
}
common.SuccessResp(c, pageResp[model.LabelFileBinding]{
Content: list,
Total: total,
})
}
func RestoreLabelFileBinding(c *gin.Context) {
var req restoreLabelBindingsReq
if err := c.ShouldBindJSON(&req); err != nil {
common.ErrorResp(c, err, 400)
return
}
if len(req.Bindings) == 0 {
common.ErrorStrResp(c, "empty bindings", 400)
return
}
if u, ok := c.Value("user").(*model.User); ok {
for i := range req.Bindings {
if req.Bindings[i].UserId == 0 {
req.Bindings[i].UserId = u.ID
}
}
}
for i := range req.Bindings {
b := req.Bindings[i]
if b.UserId == 0 || b.LabelId == 0 || strings.TrimSpace(b.FileName) == "" {
common.ErrorStrResp(c, "invalid binding: user_id/label_id/file_name required", 400)
return
}
}
if err := op.RestoreLabelFileBindings(req.Bindings, req.KeepIDs, req.Override); err != nil {
common.ErrorResp(c, err, 500, true)
return
}
common.SuccessResp(c, gin.H{
"msg": fmt.Sprintf("restored %d rows", len(req.Bindings)),
})
}
func CreateLabelFileBinDingBatch(c *gin.Context) {
var req struct {
Items []op.CreateLabelFileBinDingReq `json:"items" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil || len(req.Items) == 0 {
common.ErrorResp(c, err, 400)
return
}
userObj, ok := c.Value("user").(*model.User)
if !ok {
common.ErrorStrResp(c, "user invalid", 401)
return
}
type perResult struct {
Name string `json:"name"`
Ok bool `json:"ok"`
ErrMsg string `json:"errMsg,omitempty"`
}
results := make([]perResult, 0, len(req.Items))
succeed := 0
for _, item := range req.Items {
if item.IsDir {
results = append(results, perResult{Name: item.Name, Ok: false, ErrMsg: "Unable to bind folder"})
continue
}
if err := op.CreateLabelFileBinDing(item, userObj.ID); err != nil {
results = append(results, perResult{Name: item.Name, Ok: false, ErrMsg: err.Error()})
continue
}
succeed++
results = append(results, perResult{Name: item.Name, Ok: true})
}
common.SuccessResp(c, gin.H{
"total": len(req.Items),
"succeed": succeed,
"failed": len(req.Items) - succeed,
"results": results,
})
}