diff --git a/server/handles/fsmanage.go b/server/handles/fsmanage.go index 92a20ae410e..bd4938503ce 100644 --- a/server/handles/fsmanage.go +++ b/server/handles/fsmanage.go @@ -351,6 +351,105 @@ func FsRemove(c *gin.Context) { common.SuccessResp(c) } +type RemoveEmptyDirectoryReq struct { + SrcDir string `json:"src_dir"` +} + +func FsRemoveEmptyDirectory(c *gin.Context) { + var req RemoveEmptyDirectoryReq + if err := c.ShouldBind(&req); err != nil { + common.ErrorResp(c, err, 400) + return + } + + user := c.MustGet("user").(*model.User) + if !user.CanRemove() { + common.ErrorResp(c, errs.PermissionDenied, 403) + return + } + srcDir, err := user.JoinPath(req.SrcDir) + 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) + // record the parent file + fileParentMap := make(map[model.Obj]model.Obj) + // removing files + removingFiles := generic.NewQueue[model.Obj]() + // removed files + removedFiles := make(map[string]bool) + for _, file := range rootFiles { + if !file.IsDir() { + continue + } + removingFiles.Push(file) + filePathMap[file] = srcDir + } + + for !removingFiles.IsEmpty() { + + removingFile := removingFiles.Pop() + removingFilePath := fmt.Sprintf("%s/%s", filePathMap[removingFile], removingFile.GetName()) + + if removedFiles[removingFilePath] { + continue + } + + subFiles, err := fs.List(c, removingFilePath, &fs.ListArgs{Refresh: true}) + if err != nil { + common.ErrorResp(c, err, 500) + return + } + + if len(subFiles) == 0 { + // remove empty directory + err = fs.Remove(c, removingFilePath) + removedFiles[removingFilePath] = true + if err != nil { + common.ErrorResp(c, err, 500) + return + } + // recheck parent folder + parentFile, exist := fileParentMap[removingFile] + if exist { + removingFiles.Push(parentFile) + } + + } else { + // recursive remove + for _, subFile := range subFiles { + if !subFile.IsDir() { + continue + } + removingFiles.Push(subFile) + filePathMap[subFile] = removingFilePath + fileParentMap[subFile] = removingFile + } + } + + } + + common.SuccessResp(c) +} + // Link return real link, just for proxy program, it may contain cookie, so just allowed for admin func Link(c *gin.Context) { var req MkdirOrLinkReq diff --git a/server/router.go b/server/router.go index f4246266a6f..59b841be514 100644 --- a/server/router.go +++ b/server/router.go @@ -131,6 +131,7 @@ func _fs(g *gin.RouterGroup) { g.POST("/recursive_move", handles.FsRecursiveMove) g.POST("/copy", handles.FsCopy) g.POST("/remove", handles.FsRemove) + g.POST("/remove_empty_directory", handles.FsRemoveEmptyDirectory) g.PUT("/put", middlewares.FsUp, handles.FsStream) g.PUT("/form", middlewares.FsUp, handles.FsForm) g.POST("/link", middlewares.AuthAdmin, handles.Link)