From adf7f3deeb823eb2c8ec362d8ff49ef65256d01f Mon Sep 17 00:00:00 2001 From: HFO4 <912394456@qq.com> Date: Mon, 2 Dec 2019 14:47:55 +0800 Subject: [PATCH] Fix: handler move files in top levels --- models/file.go | 9 ++- models/folder.go | 134 +++++++++++++++++++++++++++--------- models/init.go | 2 +- pkg/filesystem/path.go | 4 +- service/explorer/objects.go | 4 +- 5 files changed, 115 insertions(+), 38 deletions(-) diff --git a/models/file.go b/models/file.go index 5bd2121..160437e 100644 --- a/models/file.go +++ b/models/file.go @@ -131,6 +131,13 @@ func DeleteFileByIDs(ids []uint) error { func GetRecursiveByPaths(paths []string, uid uint) ([]File, error) { files := make([]File, 0, len(paths)) search := util.BuildRegexp(paths, "^", "/", "|") - result := DB.Where("(user_id = ? and dir REGEXP ?) or dir in (?)", uid, search, paths).Find(&files) + result := DB.Where("(user_id = ? and dir REGEXP ?) or (user_id = ? and dir in (?))", uid, search, uid, paths).Find(&files) + return files, result.Error +} + +// GetFilesByParentIDs 根据父目录ID查找文件 +func GetFilesByParentIDs(ids []uint, uid uint) ([]File, error) { + files := make([]File, 0, len(ids)) + result := DB.Where("user_id = ? and folder_id in (?)", uid, ids).Find(&files) return files, result.Error } diff --git a/models/folder.go b/models/folder.go index 73d2c6d..0888ca6 100644 --- a/models/folder.go +++ b/models/folder.go @@ -42,12 +42,63 @@ func (folder *Folder) GetChildFolder() ([]Folder, error) { return folders, result.Error } -// GetRecursiveChildFolder 查找所有递归子目录 -func GetRecursiveChildFolder(dirs []string, uid uint) ([]Folder, error) { +// GetRecursiveChildFolder 查找所有递归子目录,包括自身 +func GetRecursiveChildFolder(dirs []string, uid uint, includeSelf bool) ([]Folder, error) { folders := make([]Folder, 0, len(dirs)) - search := util.BuildRegexp(dirs, "^", "/", "|") - result := DB.Where("(owner_id = ? and position_absolute REGEXP ?) or position_absolute in (?)", uid, search, dirs).Find(&folders) - return folders, result.Error + var err error + if conf.DatabaseConfig.Type == "mysql" { + + // MySQL 下使用正则查询 + search := util.BuildRegexp(dirs, "^", "/", "|") + result := DB.Where("(owner_id = ? and position_absolute REGEXP ?) or (owner_id = ? and position_absolute in (?))", uid, search, uid, dirs).Find(&folders) + err = result.Error + + } else { + + // SQLite 下使用递归查询 + var parFolders []Folder + result := DB.Where("owner_id = ? and position_absolute in (?)", uid, dirs).Find(&parFolders) + if result.Error != nil { + return folders, err + } + + // 整理父目录的ID + var parentIDs = make([]uint, 0, len(parFolders)) + for _, folder := range parFolders { + parentIDs = append(parentIDs, folder.ID) + } + + if includeSelf { + // 合并至最终结果 + folders = append(folders, parFolders...) + } + parFolders = []Folder{} + + // 递归查询子目录,最大递归65535次 + for i := 0; i < 65535; i++ { + + result = DB.Where("owner_id = ? and parent_id in (?)", uid, parentIDs).Find(&parFolders) + + // 查询结束条件 + if len(parFolders) == 0 { + break + } + + // 整理父目录的ID + parentIDs = make([]uint, 0, len(parFolders)) + for _, folder := range parFolders { + parentIDs = append(parentIDs, folder.ID) + } + + // 合并至最终结果 + folders = append(folders, parFolders...) + parFolders = []Folder{} + + } + + } + + return folders, err } // DeleteFolderByIDs 根据给定ID批量删除目录记录 @@ -60,10 +111,10 @@ func DeleteFolderByIDs(ids []uint) error { // return path.Join(folder.Position,folder.Name) //} -// MoveFileTo 将此目录下的文件递归移动至dstFolder +// MoveFileTo 将此目录下的文件移动至dstFolder func (folder *Folder) MoveFileTo(files []string, dstFolder *Folder) error { // 更改顶级要移动文件的父目录指向 - err := DB.Model(File{}).Where("dir in (?) and user_id = ?", folder.PositionAbsolute, folder.OwnerID). + err := DB.Model(File{}).Where("name in (?) and user_id = ? and dir = ?", files, folder.OwnerID, folder.PositionAbsolute). Update(map[string]interface{}{ "folder_id": dstFolder.ID, "dir": dstFolder.PositionAbsolute, @@ -78,10 +129,25 @@ func (folder *Folder) MoveFileTo(files []string, dstFolder *Folder) error { // MoveFolderTo 将此目录下的目录移动至dstFolder func (folder *Folder) MoveFolderTo(dirs []string, dstFolder *Folder) error { - // 生成全局路径 + // 生成绝对路径 fullDirs := make([]string, len(dirs)) for i := 0; i < len(dirs); i++ { - fullDirs[i] = path.Join(folder.PositionAbsolute, dirs[i]) + fullDirs[i] = path.Join( + folder.PositionAbsolute, + path.Base(dirs[i]), + ) + } + + var subFolders = make([][]Folder, len(fullDirs)) + + // 更新被移动的目录递归的子目录和文件 + for key, parentDir := range fullDirs { + // 检索被移动的目录的所有子目录 + toBeMoved, err := GetRecursiveChildFolder([]string{parentDir}, folder.OwnerID, true) + if err != nil { + return err + } + subFolders[key] = toBeMoved } // 更改顶级要移动目录的父目录指向 @@ -90,41 +156,45 @@ func (folder *Folder) MoveFolderTo(dirs []string, dstFolder *Folder) error { "parent_id": dstFolder.ID, "position": dstFolder.PositionAbsolute, "position_absolute": gorm.Expr(util.BuildConcat("?", "name", conf.DatabaseConfig.Type), util.FillSlash(dstFolder.PositionAbsolute)), - }). - Error + }).Error if err != nil { return err } - // 更新被移动的目录递归的子目录 - for _, parentDir := range fullDirs { - toBeMoved, err := GetRecursiveChildFolder([]string{parentDir}, folder.OwnerID) - if err != nil { - return err - } - // TODO 找到更好的修改办法 - for _, subFolder := range toBeMoved { - newPosition := path.Join(dstFolder.PositionAbsolute, strings.Replace(subFolder.Position, folder.Position, "", 1)) - DB.Model(&subFolder).Updates(map[string]interface{}{ - "position": newPosition, - "position_absolute": path.Join(newPosition, subFolder.Name), - }) - } - } + // 更新被移动的目录递归的子目录和文件 + for _, toBeMoved := range subFolders { - // 更新被移动的目录递归的子文件 - for _, parentDir := range fullDirs { - toBeMoved, err := GetRecursiveByPaths([]string{parentDir}, folder.OwnerID) + // TODO 找到更好的修改办法 + + for key, subFolder := range toBeMoved { + // 每个分组的第一个目录已经变更指向,直接跳过 + if key > 0 { + newPosition := path.Join(dstFolder.PositionAbsolute, strings.Replace(subFolder.Position, folder.Position, "", 1)) + DB.Model(&subFolder).Updates(map[string]interface{}{ + "position": newPosition, + "position_absolute": path.Join(newPosition, subFolder.Name), + }) + } + } + + // 抽离所有子目录的ID + var subFolderIDs = make([]uint, len(toBeMoved)) + for key, subFolder := range toBeMoved { + subFolderIDs[key] = subFolder.ID + } + + // 获取子目录下的所有子文件 + toBeMovedFile, err := GetFilesByParentIDs(subFolderIDs, folder.OwnerID) if err != nil { return err } - // TODO 找到更好的修改办法 - for _, subFile := range toBeMoved { - newPosition := path.Join(dstFolder.PositionAbsolute, strings.Replace(subFile.Dir, folder.Position, "", 1)) + for _, subFile := range toBeMovedFile { + newPosition := path.Join(dstFolder.PositionAbsolute, strings.Replace(subFile.Dir, folder.PositionAbsolute, "", 1)) DB.Model(&subFile).Updates(map[string]interface{}{ "dir": newPosition, }) } + } return nil diff --git a/models/init.go b/models/init.go index b6c98ff..c782745 100644 --- a/models/init.go +++ b/models/init.go @@ -29,7 +29,7 @@ func Init() { db, err = gorm.Open("sqlite3", ":memory:") } else { if conf.DatabaseConfig.Type == "UNSET" { - // 未指定数据库时,使用Sqlite + // 未指定数据库时,使用SQLite db, err = gorm.Open("sqlite3", "cloudreve.db") } else { db, err = gorm.Open(conf.DatabaseConfig.Type, fmt.Sprintf("%s:%s@(%s)/%s?charset=utf8&parseTime=True&loc=Local", diff --git a/pkg/filesystem/path.go b/pkg/filesystem/path.go index eef312b..7daa0bd 100644 --- a/pkg/filesystem/path.go +++ b/pkg/filesystem/path.go @@ -35,7 +35,7 @@ func (fs *FileSystem) Move(ctx context.Context, dirs, files []string, src, dst s return ErrPathNotExist } - // 处理目录移动 + // 处理目录及子文件移动 err := srcFolder.MoveFolderTo(dirs, dstFolder) if err != nil { return serializer.NewError(serializer.CodeDBError, "操作失败,可能有重名冲突", err) @@ -134,7 +134,7 @@ func (fs *FileSystem) Delete(ctx context.Context, dirs, files []string) error { // ListDeleteDirs 递归列出要删除目录,及目录下所有文件 func (fs *FileSystem) ListDeleteDirs(ctx context.Context, dirs []string) error { // 列出所有递归子目录 - folders, err := model.GetRecursiveChildFolder(dirs, fs.User.ID) + folders, err := model.GetRecursiveChildFolder(dirs, fs.User.ID, true) if err != nil { return ErrDBListObjects.WithError(err) } diff --git a/service/explorer/objects.go b/service/explorer/objects.go index 33792ab..191c3e5 100644 --- a/service/explorer/objects.go +++ b/service/explorer/objects.go @@ -16,8 +16,8 @@ type ItemMoveService struct { // ItemService 处理多文件/目录相关服务 type ItemService struct { - Items []string `json:"items" binding:"exists"` - Dirs []string `json:"dirs" binding:"exists"` + Items []string `json:"items" binding:"exists,dive,ne=/"` + Dirs []string `json:"dirs" binding:"exists,dive,ne=/"` } // Delete 删除对象