Merge branch 'cloudreve:master' into master

pull/1784/head
Darren Yu 2 years ago committed by GitHub
commit 44801553c6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -173,3 +173,5 @@ require (
sigs.k8s.io/yaml v1.2.0 // indirect sigs.k8s.io/yaml v1.2.0 // indirect
) )
replace github.com/gomodule/redigo v2.0.0+incompatible => github.com/gomodule/redigo v1.8.9

@ -362,8 +362,8 @@ github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0= github.com/gomodule/redigo v1.8.9 h1:Sl3u+2BI/kk+VEatbj0scLdrFhjPmbxOc1myhDP41ws=
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/gomodule/redigo v1.8.9/go.mod h1:7ArFNvsTjH8GMMzB4uy1snslv2BwmginuMs06a1uzZE=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=

@ -18,7 +18,8 @@ type Folder struct {
OwnerID uint `gorm:"index:owner_id"` OwnerID uint `gorm:"index:owner_id"`
// 数据库忽略字段 // 数据库忽略字段
Position string `gorm:"-"` Position string `gorm:"-"`
WebdavDstName string `gorm:"-"`
} }
// Create 创建目录 // Create 创建目录
@ -169,6 +170,11 @@ func (folder *Folder) MoveOrCopyFileTo(files []uint, dstFolder *Folder, isCopy b
oldFile.FolderID = dstFolder.ID oldFile.FolderID = dstFolder.ID
oldFile.UserID = dstFolder.OwnerID oldFile.UserID = dstFolder.OwnerID
// webdav目标名重置
if dstFolder.WebdavDstName != "" {
oldFile.Name = dstFolder.WebdavDstName
}
if err := DB.Create(&oldFile).Error; err != nil { if err := DB.Create(&oldFile).Error; err != nil {
return copiedSize, err return copiedSize, err
} }
@ -177,6 +183,14 @@ func (folder *Folder) MoveOrCopyFileTo(files []uint, dstFolder *Folder, isCopy b
} }
} else { } else {
var updates = map[string]interface{}{
"folder_id": dstFolder.ID,
}
// webdav目标名重置
if dstFolder.WebdavDstName != "" {
updates["name"] = dstFolder.WebdavDstName
}
// 更改顶级要移动文件的父目录指向 // 更改顶级要移动文件的父目录指向
err := DB.Model(File{}).Where( err := DB.Model(File{}).Where(
"id in (?) and user_id = ? and folder_id = ?", "id in (?) and user_id = ? and folder_id = ?",
@ -184,9 +198,7 @@ func (folder *Folder) MoveOrCopyFileTo(files []uint, dstFolder *Folder, isCopy b
folder.OwnerID, folder.OwnerID,
folder.ID, folder.ID,
). ).
Update(map[string]interface{}{ Update(updates).
"folder_id": dstFolder.ID,
}).
Error Error
if err != nil { if err != nil {
return 0, err return 0, err
@ -221,6 +233,10 @@ func (folder *Folder) CopyFolderTo(folderID uint, dstFolder *Folder) (size uint6
// 顶级目录直接指向新的目的目录 // 顶级目录直接指向新的目的目录
if folder.ID == folderID { if folder.ID == folderID {
newID = dstFolder.ID newID = dstFolder.ID
// webdav目标名重置
if dstFolder.WebdavDstName != "" {
folder.Name = dstFolder.WebdavDstName
}
} else if IDCache, ok := newIDCache[*folder.ParentID]; ok { } else if IDCache, ok := newIDCache[*folder.ParentID]; ok {
newID = IDCache newID = IDCache
} else { } else {
@ -282,15 +298,21 @@ func (folder *Folder) MoveFolderTo(dirs []uint, dstFolder *Folder) error {
return errors.New("cannot move a folder into itself") 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( err := DB.Model(Folder{}).Where(
"id in (?) and owner_id = ? and parent_id = ?", "id in (?) and owner_id = ? and parent_id = ?",
dirs, dirs,
folder.OwnerID, folder.OwnerID,
folder.ID, folder.ID,
).Update(map[string]interface{}{ ).Update(updates).Error
"parent_id": dstFolder.ID,
}).Error
return err return err

@ -21,6 +21,7 @@ func Init() {
10, 10,
conf.RedisConfig.Network, conf.RedisConfig.Network,
conf.RedisConfig.Server, conf.RedisConfig.Server,
conf.RedisConfig.User,
conf.RedisConfig.Password, conf.RedisConfig.Password,
conf.RedisConfig.DB, conf.RedisConfig.DB,
) )

@ -44,7 +44,7 @@ func deserializer(value []byte) (interface{}, error) {
} }
// NewRedisStore 创建新的redis存储 // NewRedisStore 创建新的redis存储
func NewRedisStore(size int, network, address, password, database string) *RedisStore { func NewRedisStore(size int, network, address, user, password, database string) *RedisStore {
return &RedisStore{ return &RedisStore{
pool: &redis.Pool{ pool: &redis.Pool{
MaxIdle: size, MaxIdle: size,
@ -63,6 +63,7 @@ func NewRedisStore(size int, network, address, password, database string) *Redis
network, network,
address, address,
redis.DialDatabase(db), redis.DialDatabase(db),
redis.DialUsername(user),
redis.DialPassword(password), redis.DialPassword(password),
) )
if err != nil { if err != nil {

@ -13,7 +13,7 @@ import (
func TestNewRedisStore(t *testing.T) { func TestNewRedisStore(t *testing.T) {
asserts := assert.New(t) asserts := assert.New(t)
store := NewRedisStore(10, "tcp", "", "", "0") store := NewRedisStore(10, "tcp", "", "", "", "0")
asserts.NotNil(store) asserts.NotNil(store)
asserts.Panics(func() { asserts.Panics(func() {

@ -53,6 +53,7 @@ type slave struct {
type redis struct { type redis struct {
Network string Network string
Server string Server string
User string
Password string Password string
DB string DB string
} }

@ -35,4 +35,6 @@ const (
CancelFuncCtx CancelFuncCtx
// 文件在从机节点中的路径 // 文件在从机节点中的路径
SlaveSrcPath SlaveSrcPath
// Webdav目标名称
WebdavDstName
) )

@ -69,6 +69,11 @@ func (fs *FileSystem) Copy(ctx context.Context, dirs, files []uint, src, dst str
// 记录复制的文件的总容量 // 记录复制的文件的总容量
var newUsedStorage uint64 var newUsedStorage uint64
// 设置webdav目标名
if dstName, ok := ctx.Value(fsctx.WebdavDstName).(string); ok {
dstFolder.WebdavDstName = dstName
}
// 复制目录 // 复制目录
if len(dirs) > 0 { if len(dirs) > 0 {
subFileSizes, err := srcFolder.CopyFolderTo(dirs[0], dstFolder) subFileSizes, err := srcFolder.CopyFolderTo(dirs[0], dstFolder)
@ -103,6 +108,11 @@ func (fs *FileSystem) Move(ctx context.Context, dirs, files []uint, src, dst str
return ErrPathNotExist return ErrPathNotExist
} }
// 设置webdav目标名
if dstName, ok := ctx.Value(fsctx.WebdavDstName).(string); ok {
dstFolder.WebdavDstName = dstName
}
// 处理目录及子文件移动 // 处理目录及子文件移动
err := srcFolder.MoveFolderTo(dirs, dstFolder) err := srcFolder.MoveFolderTo(dirs, dstFolder)
if err != nil { if err != nil {

@ -67,9 +67,8 @@ func (f *FfmpegGenerator) Generate(ctx context.Context, file io.Reader, src, nam
// Invoke ffmpeg // Invoke ffmpeg
scaleOpt := fmt.Sprintf("scale=%s:%s:force_original_aspect_ratio=decrease", options["thumb_width"], options["thumb_height"]) scaleOpt := fmt.Sprintf("scale=%s:%s:force_original_aspect_ratio=decrease", options["thumb_width"], options["thumb_height"])
inputFormat := filepath.Ext(name)[1:]
cmd := exec.CommandContext(ctx, cmd := exec.CommandContext(ctx,
ffmpegOpts["thumb_ffmpeg_path"], "-ss", ffmpegOpts["thumb_ffmpeg_seek"], "-f", inputFormat, "-i", tempInputPath, ffmpegOpts["thumb_ffmpeg_path"], "-ss", ffmpegOpts["thumb_ffmpeg_seek"], "-i", tempInputPath,
"-vf", scaleOpt, "-vframes", "1", tempOutputPath) "-vf", scaleOpt, "-vframes", "1", tempOutputPath)
// Redirect IO // Redirect IO

@ -9,9 +9,12 @@ import (
"net/http" "net/http"
"path" "path"
"path/filepath" "path/filepath"
"strconv"
"time"
model "github.com/cloudreve/Cloudreve/v3/models" model "github.com/cloudreve/Cloudreve/v3/models"
"github.com/cloudreve/Cloudreve/v3/pkg/filesystem" "github.com/cloudreve/Cloudreve/v3/pkg/filesystem"
"github.com/cloudreve/Cloudreve/v3/pkg/filesystem/fsctx"
) )
// slashClean is equivalent to but slightly more efficient than // slashClean is equivalent to but slightly more efficient than
@ -23,6 +26,31 @@ func slashClean(name string) string {
return path.Clean(name) 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. // moveFiles moves files and/or directories from src to dst.
// //
// See section 9.9.4 for when various HTTP status codes apply. // See section 9.9.4 for when various HTTP status codes apply.
@ -44,20 +72,17 @@ func moveFiles(ctx context.Context, fs *filesystem.FileSystem, src FileInfo, dst
} }
} }
// 判断是否需要移动 // 判断是否需要移动
if src.GetPosition() != path.Dir(dst) { if src.GetPosition() != path.Dir(dst) {
err = fs.Move( err = fs.Move(
ctx, context.WithValue(ctx, fsctx.WebdavDstName, path.Base(dst)),
folderIDs, folderIDs,
fileIDs, fileIDs,
src.GetPosition(), src.GetPosition(),
path.Dir(dst), path.Dir(dst),
) )
} } else if src.GetName() != path.Base(dst) {
// 判断是否需要重命名
// 判断是否需要重命名
if err == nil && src.GetName() != path.Base(dst) {
err = fs.Rename( err = fs.Rename(
ctx, ctx,
folderIDs, folderIDs,
@ -81,7 +106,6 @@ func copyFiles(ctx context.Context, fs *filesystem.FileSystem, src FileInfo, dst
} }
recursion++ recursion++
var ( var (
fileIDs []uint fileIDs []uint
folderIDs []uint folderIDs []uint
@ -100,7 +124,7 @@ func copyFiles(ctx context.Context, fs *filesystem.FileSystem, src FileInfo, dst
} }
err = fs.Copy( err = fs.Copy(
ctx, context.WithValue(ctx, fsctx.WebdavDstName, path.Base(dst)),
folderIDs, folderIDs,
fileIDs, fileIDs,
src.GetPosition(), src.GetPosition(),

@ -49,7 +49,7 @@ func (file *FileDeadProps) Patch(proppatches []Proppatch) ([]Propstat, error) {
var modtimeUnix int64 var modtimeUnix int64
modtimeUnix, err = strconv.ParseInt(string(prop.InnerXML), 10, 64) modtimeUnix, err = strconv.ParseInt(string(prop.InnerXML), 10, 64)
if err == nil { if err == nil {
err = model.DB.Model(file).UpdateColumn("updated_at", time.Unix(modtimeUnix, 0)).Error err = model.DB.Model(file.File).UpdateColumn("updated_at", time.Unix(modtimeUnix, 0)).Error
} }
} }
} }
@ -78,7 +78,7 @@ func (folder *FolderDeadProps) Patch(proppatches []Proppatch) ([]Propstat, error
var modtimeUnix int64 var modtimeUnix int64
modtimeUnix, err = strconv.ParseInt(string(prop.InnerXML), 10, 64) modtimeUnix, err = strconv.ParseInt(string(prop.InnerXML), 10, 64)
if err == nil { if err == nil {
err = model.DB.Model(folder).UpdateColumn("updated_at", time.Unix(modtimeUnix, 0)).Error err = model.DB.Model(folder.Folder).UpdateColumn("updated_at", time.Unix(modtimeUnix, 0)).Error
} }
} }
} }

@ -496,7 +496,16 @@ func (h *Handler) handleCopyMove(w http.ResponseWriter, r *http.Request, fs *fil
return http.StatusBadRequest, errInvalidDepth 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只包含源文件 // windows下某些情况下网盘根目录下Office保存文件时附带的锁token只包含源文件
@ -515,7 +524,16 @@ func (h *Handler) handleCopyMove(w http.ResponseWriter, r *http.Request, fs *fil
return http.StatusBadRequest, errInvalidDepth 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 // OK

Loading…
Cancel
Save