mirror of https://github.com/Xhofe/alist
				
				
				
			
		
			
				
	
	
		
			212 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Go
		
	
	
			
		
		
	
	
			212 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Go
		
	
	
| package handles
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"regexp"
 | |
| 
 | |
| 	"github.com/alist-org/alist/v3/internal/errs"
 | |
| 	"github.com/alist-org/alist/v3/internal/fs"
 | |
| 	"github.com/alist-org/alist/v3/internal/model"
 | |
| 	"github.com/alist-org/alist/v3/internal/op"
 | |
| 	"github.com/alist-org/alist/v3/pkg/generic"
 | |
| 	"github.com/alist-org/alist/v3/server/common"
 | |
| 	"github.com/gin-gonic/gin"
 | |
| 	"github.com/pkg/errors"
 | |
| )
 | |
| 
 | |
| type BatchRenameReq struct {
 | |
| 	SrcDir        string `json:"src_dir"`
 | |
| 	RenameObjects []struct {
 | |
| 		SrcName string `json:"src_name"`
 | |
| 		NewName string `json:"new_name"`
 | |
| 	} `json:"rename_objects"`
 | |
| }
 | |
| 
 | |
| func FsBatchRename(c *gin.Context) {
 | |
| 	var req BatchRenameReq
 | |
| 	if err := c.ShouldBind(&req); err != nil {
 | |
| 		common.ErrorResp(c, err, 400)
 | |
| 		return
 | |
| 	}
 | |
| 	user := c.MustGet("user").(*model.User)
 | |
| 	if !user.CanRename() {
 | |
| 		common.ErrorResp(c, errs.PermissionDenied, 403)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	reqPath, err := user.JoinPath(req.SrcDir)
 | |
| 	if err != nil {
 | |
| 		common.ErrorResp(c, err, 403)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	meta, err := op.GetNearestMeta(reqPath)
 | |
| 	if err != nil {
 | |
| 		if !errors.Is(errors.Cause(err), errs.MetaNotFound) {
 | |
| 			common.ErrorResp(c, err, 500, true)
 | |
| 			return
 | |
| 		}
 | |
| 	}
 | |
| 	c.Set("meta", meta)
 | |
| 	for _, renameObject := range req.RenameObjects {
 | |
| 		if renameObject.SrcName == "" || renameObject.NewName == "" {
 | |
| 			continue
 | |
| 		}
 | |
| 		filePath := fmt.Sprintf("%s/%s", reqPath, renameObject.SrcName)
 | |
| 		if err := fs.Rename(c, filePath, renameObject.NewName); err != nil {
 | |
| 			common.ErrorResp(c, err, 500)
 | |
| 			return
 | |
| 		}
 | |
| 	}
 | |
| 	common.SuccessResp(c)
 | |
| }
 | |
| 
 | |
| type RecursiveMoveReq struct {
 | |
| 	SrcDir string `json:"src_dir"`
 | |
| 	DstDir string `json:"dst_dir"`
 | |
| }
 | |
| 
 | |
| func FsRecursiveMove(c *gin.Context) {
 | |
| 	var req RecursiveMoveReq
 | |
| 	if err := c.ShouldBind(&req); err != nil {
 | |
| 		common.ErrorResp(c, err, 400)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	user := c.MustGet("user").(*model.User)
 | |
| 	if !user.CanMove() {
 | |
| 		common.ErrorResp(c, errs.PermissionDenied, 403)
 | |
| 		return
 | |
| 	}
 | |
| 	srcDir, err := user.JoinPath(req.SrcDir)
 | |
| 	if err != nil {
 | |
| 		common.ErrorResp(c, err, 403)
 | |
| 		return
 | |
| 	}
 | |
| 	dstDir, err := user.JoinPath(req.DstDir)
 | |
| 	if err != nil {
 | |
| 		common.ErrorResp(c, err, 403)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	meta, err := op.GetNearestMeta(srcDir)
 | |
| 	if err != nil {
 | |
| 		if !errors.Is(errors.Cause(err), errs.MetaNotFound) {
 | |
| 			common.ErrorResp(c, err, 500, true)
 | |
| 			return
 | |
| 		}
 | |
| 	}
 | |
| 	c.Set("meta", meta)
 | |
| 
 | |
| 	rootFiles, err := fs.List(c, srcDir, &fs.ListArgs{})
 | |
| 	if err != nil {
 | |
| 		common.ErrorResp(c, err, 500)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	// record the file path
 | |
| 	filePathMap := make(map[model.Obj]string)
 | |
| 	movingFiles := generic.NewQueue[model.Obj]()
 | |
| 	for _, file := range rootFiles {
 | |
| 		movingFiles.Push(file)
 | |
| 		filePathMap[file] = srcDir
 | |
| 	}
 | |
| 
 | |
| 	for !movingFiles.IsEmpty() {
 | |
| 
 | |
| 		movingFile := movingFiles.Pop()
 | |
| 		movingFilePath := filePathMap[movingFile]
 | |
| 		movingFileName := fmt.Sprintf("%s/%s", movingFilePath, movingFile.GetName())
 | |
| 		if movingFile.IsDir() {
 | |
| 			// directory, recursive move
 | |
| 			subFilePath := movingFileName
 | |
| 			subFiles, err := fs.List(c, movingFileName, &fs.ListArgs{Refresh: true})
 | |
| 			if err != nil {
 | |
| 				common.ErrorResp(c, err, 500)
 | |
| 				return
 | |
| 			}
 | |
| 			for _, subFile := range subFiles {
 | |
| 				movingFiles.Push(subFile)
 | |
| 				filePathMap[subFile] = subFilePath
 | |
| 			}
 | |
| 		} else {
 | |
| 
 | |
| 			if movingFilePath == dstDir {
 | |
| 				// same directory, don't move
 | |
| 				continue
 | |
| 			}
 | |
| 
 | |
| 			// move
 | |
| 			err := fs.Move(c, movingFileName, dstDir, movingFiles.IsEmpty())
 | |
| 			if err != nil {
 | |
| 				common.ErrorResp(c, err, 500)
 | |
| 				return
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 	}
 | |
| 
 | |
| 	common.SuccessResp(c)
 | |
| }
 | |
| 
 | |
| type RegexRenameReq struct {
 | |
| 	SrcDir       string `json:"src_dir"`
 | |
| 	SrcNameRegex string `json:"src_name_regex"`
 | |
| 	NewNameRegex string `json:"new_name_regex"`
 | |
| }
 | |
| 
 | |
| func FsRegexRename(c *gin.Context) {
 | |
| 	var req RegexRenameReq
 | |
| 	if err := c.ShouldBind(&req); err != nil {
 | |
| 		common.ErrorResp(c, err, 400)
 | |
| 		return
 | |
| 	}
 | |
| 	user := c.MustGet("user").(*model.User)
 | |
| 	if !user.CanRename() {
 | |
| 		common.ErrorResp(c, errs.PermissionDenied, 403)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	reqPath, err := user.JoinPath(req.SrcDir)
 | |
| 	if err != nil {
 | |
| 		common.ErrorResp(c, err, 403)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	meta, err := op.GetNearestMeta(reqPath)
 | |
| 	if err != nil {
 | |
| 		if !errors.Is(errors.Cause(err), errs.MetaNotFound) {
 | |
| 			common.ErrorResp(c, err, 500, true)
 | |
| 			return
 | |
| 		}
 | |
| 	}
 | |
| 	c.Set("meta", meta)
 | |
| 
 | |
| 	srcRegexp, err := regexp.Compile(req.SrcNameRegex)
 | |
| 	if err != nil {
 | |
| 		common.ErrorResp(c, err, 500)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	files, err := fs.List(c, reqPath, &fs.ListArgs{})
 | |
| 	if err != nil {
 | |
| 		common.ErrorResp(c, err, 500)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	for _, file := range files {
 | |
| 
 | |
| 		if srcRegexp.MatchString(file.GetName()) {
 | |
| 			filePath := fmt.Sprintf("%s/%s", reqPath, file.GetName())
 | |
| 			newFileName := srcRegexp.ReplaceAllString(file.GetName(), req.NewNameRegex)
 | |
| 			if err := fs.Rename(c, filePath, newFileName); err != nil {
 | |
| 				common.ErrorResp(c, err, 500)
 | |
| 				return
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 	}
 | |
| 
 | |
| 	common.SuccessResp(c)
 | |
| }
 |