Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

webdav支持复制和移动的同时重命名 #1774

Merged
merged 1 commit into from
Jul 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 29 additions & 7 deletions models/folder.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ type Folder struct {
OwnerID uint `gorm:"index:owner_id"`

// 数据库忽略字段
Position string `gorm:"-"`
Position string `gorm:"-"`
WebdavDstName string `gorm:"-"`
}

// Create 创建目录
Expand Down Expand Up @@ -169,6 +170,11 @@ func (folder *Folder) MoveOrCopyFileTo(files []uint, dstFolder *Folder, isCopy b
oldFile.FolderID = dstFolder.ID
oldFile.UserID = dstFolder.OwnerID

// webdav目标名重置
if dstFolder.WebdavDstName != "" {
oldFile.Name = dstFolder.WebdavDstName
}

if err := DB.Create(&oldFile).Error; err != nil {
return copiedSize, err
}
Expand All @@ -177,16 +183,22 @@ func (folder *Folder) MoveOrCopyFileTo(files []uint, dstFolder *Folder, isCopy b
}

} else {
var updates = map[string]interface{}{
"folder_id": dstFolder.ID,
}
// webdav目标名重置
if dstFolder.WebdavDstName != "" {
updates["name"] = dstFolder.WebdavDstName
}

// 更改顶级要移动文件的父目录指向
err := DB.Model(File{}).Where(
"id in (?) and user_id = ? and folder_id = ?",
files,
folder.OwnerID,
folder.ID,
).
Update(map[string]interface{}{
"folder_id": dstFolder.ID,
}).
Update(updates).
Error
if err != nil {
return 0, err
Expand Down Expand Up @@ -221,6 +233,10 @@ func (folder *Folder) CopyFolderTo(folderID uint, dstFolder *Folder) (size uint6
// 顶级目录直接指向新的目的目录
if folder.ID == folderID {
newID = dstFolder.ID
// webdav目标名重置
if dstFolder.WebdavDstName != "" {
folder.Name = dstFolder.WebdavDstName
}
} else if IDCache, ok := newIDCache[*folder.ParentID]; ok {
newID = IDCache
} else {
Expand Down Expand Up @@ -282,15 +298,21 @@ func (folder *Folder) MoveFolderTo(dirs []uint, dstFolder *Folder) error {
return errors.New("cannot move a folder into itself")
}

var updates = map[string]interface{}{
"parent_id": dstFolder.ID,
}
// webdav目标名重置
if dstFolder.WebdavDstName != "" {
updates["name"] = dstFolder.WebdavDstName
}

// 更改顶级要移动目录的父目录指向
err := DB.Model(Folder{}).Where(
"id in (?) and owner_id = ? and parent_id = ?",
dirs,
folder.OwnerID,
folder.ID,
).Update(map[string]interface{}{
"parent_id": dstFolder.ID,
}).Error
).Update(updates).Error

return err

Expand Down
2 changes: 2 additions & 0 deletions pkg/filesystem/fsctx/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,6 @@ const (
CancelFuncCtx
// 文件在从机节点中的路径
SlaveSrcPath
// Webdav目标名称
WebdavDstName
)
10 changes: 10 additions & 0 deletions pkg/filesystem/manage.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ func (fs *FileSystem) Copy(ctx context.Context, dirs, files []uint, src, dst str
// 记录复制的文件的总容量
var newUsedStorage uint64

// 设置webdav目标名
if dstName, ok := ctx.Value(fsctx.WebdavDstName).(string); ok {
dstFolder.WebdavDstName = dstName
}

// 复制目录
if len(dirs) > 0 {
subFileSizes, err := srcFolder.CopyFolderTo(dirs[0], dstFolder)
Expand Down Expand Up @@ -103,6 +108,11 @@ func (fs *FileSystem) Move(ctx context.Context, dirs, files []uint, src, dst str
return ErrPathNotExist
}

// 设置webdav目标名
if dstName, ok := ctx.Value(fsctx.WebdavDstName).(string); ok {
dstFolder.WebdavDstName = dstName
}

// 处理目录及子文件移动
err := srcFolder.MoveFolderTo(dirs, dstFolder)
if err != nil {
Expand Down
40 changes: 32 additions & 8 deletions pkg/webdav/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@ import (
"net/http"
"path"
"path/filepath"
"strconv"
"time"

model "github.com/cloudreve/Cloudreve/v3/models"
"github.com/cloudreve/Cloudreve/v3/pkg/filesystem"
"github.com/cloudreve/Cloudreve/v3/pkg/filesystem/fsctx"
)

// slashClean is equivalent to but slightly more efficient than
Expand All @@ -23,6 +26,31 @@ func slashClean(name string) string {
return path.Clean(name)
}

// 更新Copy或Move后的修改时间
func updateCopyMoveModtime(req *http.Request, fs *filesystem.FileSystem, dst string) error {
var modtime time.Time
if timeVal := req.Header.Get("X-OC-Mtime"); timeVal != "" {
timeUnix, err := strconv.ParseInt(timeVal, 10, 64)
if err == nil {
modtime = time.Unix(timeUnix, 0)
}
}

if modtime.IsZero() {
return nil
}

ok, fi := isPathExist(req.Context(), fs, dst)
if !ok {
return nil
}

if fi.IsDir() {
return model.DB.Model(fi.(*model.Folder)).UpdateColumn("updated_at", modtime).Error
}
return model.DB.Model(fi.(*model.File)).UpdateColumn("updated_at", modtime).Error
}

// moveFiles moves files and/or directories from src to dst.
//
// See section 9.9.4 for when various HTTP status codes apply.
Expand All @@ -44,20 +72,17 @@ func moveFiles(ctx context.Context, fs *filesystem.FileSystem, src FileInfo, dst
}
}


// 判断是否需要移动
if src.GetPosition() != path.Dir(dst) {
err = fs.Move(
ctx,
context.WithValue(ctx, fsctx.WebdavDstName, path.Base(dst)),
folderIDs,
fileIDs,
src.GetPosition(),
path.Dir(dst),
)
}

// 判断是否需要重命名
if err == nil && src.GetName() != path.Base(dst) {
} else if src.GetName() != path.Base(dst) {
// 判断是否需要重命名
err = fs.Rename(
ctx,
folderIDs,
Expand All @@ -81,7 +106,6 @@ func copyFiles(ctx context.Context, fs *filesystem.FileSystem, src FileInfo, dst
}
recursion++


var (
fileIDs []uint
folderIDs []uint
Expand All @@ -100,7 +124,7 @@ func copyFiles(ctx context.Context, fs *filesystem.FileSystem, src FileInfo, dst
}

err = fs.Copy(
ctx,
context.WithValue(ctx, fsctx.WebdavDstName, path.Base(dst)),
folderIDs,
fileIDs,
src.GetPosition(),
Expand Down
22 changes: 20 additions & 2 deletions pkg/webdav/webdav.go
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,16 @@ func (h *Handler) handleCopyMove(w http.ResponseWriter, r *http.Request, fs *fil
return http.StatusBadRequest, errInvalidDepth
}
}
return copyFiles(ctx, fs, target, dst, r.Header.Get("Overwrite") != "F", depth, 0)
status, err = copyFiles(ctx, fs, target, dst, r.Header.Get("Overwrite") != "F", depth, 0)
if err != nil {
return status, err
}

err = updateCopyMoveModtime(r, fs, dst)
if err != nil {
return http.StatusInternalServerError, err
}
return status, nil
}

// windows下,某些情况下(网盘根目录下)Office保存文件时附带的锁token只包含源文件,
Expand All @@ -515,7 +524,16 @@ func (h *Handler) handleCopyMove(w http.ResponseWriter, r *http.Request, fs *fil
return http.StatusBadRequest, errInvalidDepth
}
}
return moveFiles(ctx, fs, target, dst, r.Header.Get("Overwrite") == "T")
status, err = moveFiles(ctx, fs, target, dst, r.Header.Get("Overwrite") == "T")
if err != nil {
return status, err
}

err = updateCopyMoveModtime(r, fs, dst)
if err != nil {
return http.StatusInternalServerError, err
}
return status, nil
}

// OK
Expand Down