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
webdav支持复制和移动的同时重命名
  • Loading branch information
WeidiDeng committed Jul 13, 2023
commit 9df8848ca52de75d613f7530476bda936d9f587a
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 @@
OwnerID uint `gorm:"index:owner_id"`

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

// Create 创建目录
Expand Down Expand Up @@ -169,6 +170,11 @@
oldFile.FolderID = dstFolder.ID
oldFile.UserID = dstFolder.OwnerID

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

Check warning on line 176 in models/folder.go

View check run for this annotation

Codecov / codecov/patch

models/folder.go#L175-L176

Added lines #L175 - L176 were not covered by tests

if err := DB.Create(&oldFile).Error; err != nil {
return copiedSize, err
}
Expand All @@ -177,16 +183,22 @@
}

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

Check warning on line 192 in models/folder.go

View check run for this annotation

Codecov / codecov/patch

models/folder.go#L191-L192

Added lines #L191 - L192 were not covered by tests

// 更改顶级要移动文件的父目录指向
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 @@
// 顶级目录直接指向新的目的目录
if folder.ID == folderID {
newID = dstFolder.ID
// webdav目标名重置
if dstFolder.WebdavDstName != "" {
folder.Name = dstFolder.WebdavDstName
}

Check warning on line 239 in models/folder.go

View check run for this annotation

Codecov / codecov/patch

models/folder.go#L238-L239

Added lines #L238 - L239 were not covered by tests
} else if IDCache, ok := newIDCache[*folder.ParentID]; ok {
newID = IDCache
} else {
Expand Down Expand Up @@ -282,15 +298,21 @@
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
}

Check warning on line 307 in models/folder.go

View check run for this annotation

Codecov / codecov/patch

models/folder.go#L306-L307

Added lines #L306 - L307 were not covered by tests

// 更改顶级要移动目录的父目录指向
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 @@
// 记录复制的文件的总容量
var newUsedStorage uint64

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

Check warning on line 75 in pkg/filesystem/manage.go

View check run for this annotation

Codecov / codecov/patch

pkg/filesystem/manage.go#L74-L75

Added lines #L74 - L75 were not covered by tests

// 复制目录
if len(dirs) > 0 {
subFileSizes, err := srcFolder.CopyFolderTo(dirs[0], dstFolder)
Expand Down Expand Up @@ -103,6 +108,11 @@
return ErrPathNotExist
}

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

Check warning on line 114 in pkg/filesystem/manage.go

View check run for this annotation

Codecov / codecov/patch

pkg/filesystem/manage.go#L113-L114

Added lines #L113 - L114 were not covered by tests

// 处理目录及子文件移动
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
Loading