Feat: re-save shared folder to user's space
This commit is contained in:
parent
b1a9943b0c
commit
f5d79b1f94
10 changed files with 51 additions and 60 deletions
|
@ -60,7 +60,7 @@ func (folder *Folder) GetChildFolder() ([]Folder, error) {
|
||||||
func GetRecursiveChildFolder(dirs []uint, uid uint, includeSelf bool) ([]Folder, error) {
|
func GetRecursiveChildFolder(dirs []uint, uid uint, includeSelf bool) ([]Folder, error) {
|
||||||
folders := make([]Folder, 0, len(dirs))
|
folders := make([]Folder, 0, len(dirs))
|
||||||
var err error
|
var err error
|
||||||
// SQLite 下使用递归查询
|
|
||||||
var parFolders []Folder
|
var parFolders []Folder
|
||||||
result := DB.Where("owner_id = ? and id in (?)", uid, dirs).Find(&parFolders)
|
result := DB.Where("owner_id = ? and id in (?)", uid, dirs).Find(&parFolders)
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
|
@ -139,6 +139,7 @@ func (folder *Folder) MoveOrCopyFileTo(files []uint, dstFolder *Folder, isCopy b
|
||||||
for _, oldFile := range originFiles {
|
for _, oldFile := range originFiles {
|
||||||
oldFile.Model = gorm.Model{}
|
oldFile.Model = gorm.Model{}
|
||||||
oldFile.FolderID = dstFolder.ID
|
oldFile.FolderID = dstFolder.ID
|
||||||
|
oldFile.UserID = dstFolder.OwnerID
|
||||||
|
|
||||||
if err := DB.Create(&oldFile).Error; err != nil {
|
if err := DB.Create(&oldFile).Error; err != nil {
|
||||||
return copiedSize, err
|
return copiedSize, err
|
||||||
|
@ -203,6 +204,7 @@ func (folder *Folder) CopyFolderTo(folderID uint, dstFolder *Folder) (size uint6
|
||||||
oldID := folder.ID
|
oldID := folder.ID
|
||||||
folder.Model = gorm.Model{}
|
folder.Model = gorm.Model{}
|
||||||
folder.ParentID = &newID
|
folder.ParentID = &newID
|
||||||
|
folder.OwnerID = dstFolder.OwnerID
|
||||||
if err = DB.Create(&folder).Error; err != nil {
|
if err = DB.Create(&folder).Error; err != nil {
|
||||||
return size, err
|
return size, err
|
||||||
}
|
}
|
||||||
|
@ -225,7 +227,7 @@ func (folder *Folder) CopyFolderTo(folderID uint, dstFolder *Folder) (size uint6
|
||||||
for _, oldFile := range originFiles {
|
for _, oldFile := range originFiles {
|
||||||
oldFile.Model = gorm.Model{}
|
oldFile.Model = gorm.Model{}
|
||||||
oldFile.FolderID = newIDCache[oldFile.FolderID]
|
oldFile.FolderID = newIDCache[oldFile.FolderID]
|
||||||
|
oldFile.UserID = dstFolder.OwnerID
|
||||||
if err := DB.Create(&oldFile).Error; err != nil {
|
if err := DB.Create(&oldFile).Error; err != nil {
|
||||||
return size, err
|
return size, err
|
||||||
}
|
}
|
||||||
|
@ -262,40 +264,6 @@ func (folder *Folder) Rename(new string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CopyChildFrom 将给定文件和拷贝至自身,并更改所有者ID
|
|
||||||
func (folder *Folder) CopyChildFrom(folders []Folder, files []File) error {
|
|
||||||
// 开启事务
|
|
||||||
tx := DB.Begin()
|
|
||||||
defer func() {
|
|
||||||
if r := recover(); r != nil {
|
|
||||||
tx.Rollback()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
// 记录文件父目录对应复制的新目录ID
|
|
||||||
var newParent = make(map[uint]uint, len(folders))
|
|
||||||
|
|
||||||
// TODO 复制目录结构
|
|
||||||
|
|
||||||
// 复制子文件
|
|
||||||
for _, file := range files {
|
|
||||||
file.ID = 0
|
|
||||||
file.UserID = folder.OwnerID
|
|
||||||
if newParentID, ok := newParent[file.FolderID]; ok {
|
|
||||||
file.FolderID = newParentID
|
|
||||||
} else {
|
|
||||||
file.FolderID = folder.ID
|
|
||||||
}
|
|
||||||
if err := tx.Create(&file).Error; err != nil {
|
|
||||||
tx.Rollback()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return tx.Commit().Error
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
实现 FileInfo.FileInfo 接口
|
实现 FileInfo.FileInfo 接口
|
||||||
TODO 测试
|
TODO 测试
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"github.com/HFO4/cloudreve/pkg/util"
|
"github.com/HFO4/cloudreve/pkg/util"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/jinzhu/gorm"
|
"github.com/jinzhu/gorm"
|
||||||
|
"math"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -170,7 +171,7 @@ func (share *Share) DownloadBy(user *User, c *gin.Context) error {
|
||||||
// Purchase 使用积分购买分享
|
// Purchase 使用积分购买分享
|
||||||
func (share *Share) Purchase(user *User) error {
|
func (share *Share) Purchase(user *User) error {
|
||||||
// 不需要付积分
|
// 不需要付积分
|
||||||
if share.Score == 0 || user.Group.OptionsSerialized.ShareFreeEnabled {
|
if share.Score == 0 || user.Group.OptionsSerialized.ShareFreeEnabled || user.ID == share.UserID {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,6 +180,10 @@ func (share *Share) Purchase(user *User) error {
|
||||||
return errors.New("积分不足")
|
return errors.New("积分不足")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scoreRate := GetIntSetting("share_score_rate", 100)
|
||||||
|
gainedScore := int(math.Ceil(float64(share.Score*scoreRate) / 100))
|
||||||
|
share.GetCreator().AddScore(gainedScore)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -108,6 +108,13 @@ func (user *User) PayScore(score int) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddScore 增加积分
|
||||||
|
// todo 测试
|
||||||
|
func (user *User) AddScore(score int) {
|
||||||
|
user.Score += score
|
||||||
|
DB.Model(user).UpdateColumn("score", gorm.Expr("score + ?", score))
|
||||||
|
}
|
||||||
|
|
||||||
// IncreaseStorageWithoutCheck 忽略可用容量,增加用户已用容量
|
// IncreaseStorageWithoutCheck 忽略可用容量,增加用户已用容量
|
||||||
func (user *User) IncreaseStorageWithoutCheck(size uint64) {
|
func (user *User) IncreaseStorageWithoutCheck(size uint64) {
|
||||||
if size == 0 {
|
if size == 0 {
|
||||||
|
|
|
@ -13,7 +13,7 @@ var (
|
||||||
ErrIllegalObjectName = errors.New("目标名称非法")
|
ErrIllegalObjectName = errors.New("目标名称非法")
|
||||||
ErrClientCanceled = errors.New("客户端取消操作")
|
ErrClientCanceled = errors.New("客户端取消操作")
|
||||||
ErrInsertFileRecord = serializer.NewError(serializer.CodeDBError, "无法插入文件记录", nil)
|
ErrInsertFileRecord = serializer.NewError(serializer.CodeDBError, "无法插入文件记录", nil)
|
||||||
ErrFileExisted = serializer.NewError(serializer.CodeObjectExist, "同名文件已存在", nil)
|
ErrFileExisted = serializer.NewError(serializer.CodeObjectExist, "同名文件或目录已存在", nil)
|
||||||
ErrFolderExisted = serializer.NewError(serializer.CodeObjectExist, "同名目录已存在", nil)
|
ErrFolderExisted = serializer.NewError(serializer.CodeObjectExist, "同名目录已存在", nil)
|
||||||
ErrPathNotExist = serializer.NewError(404, "路径不存在", nil)
|
ErrPathNotExist = serializer.NewError(404, "路径不存在", nil)
|
||||||
ErrObjectNotExist = serializer.NewError(404, "文件不存在", nil)
|
ErrObjectNotExist = serializer.NewError(404, "文件不存在", nil)
|
||||||
|
|
|
@ -76,6 +76,8 @@ type FileSystem struct {
|
||||||
FileTarget []model.File
|
FileTarget []model.File
|
||||||
// 当前正在处理的目录对象
|
// 当前正在处理的目录对象
|
||||||
DirTarget []model.Folder
|
DirTarget []model.Folder
|
||||||
|
// 相对根目录
|
||||||
|
Root *model.Folder
|
||||||
|
|
||||||
/*
|
/*
|
||||||
钩子函数
|
钩子函数
|
||||||
|
@ -107,6 +109,7 @@ func (fs *FileSystem) reset() {
|
||||||
fs.Policy = nil
|
fs.Policy = nil
|
||||||
fs.Hooks = nil
|
fs.Hooks = nil
|
||||||
fs.Handler = nil
|
fs.Handler = nil
|
||||||
|
fs.Root = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewFileSystem 初始化一个文件系统
|
// NewFileSystem 初始化一个文件系统
|
||||||
|
|
|
@ -377,22 +377,24 @@ func (fs *FileSystem) SaveTo(ctx context.Context, path string) error {
|
||||||
return ErrPathNotExist
|
return ErrPathNotExist
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO 列目录
|
var (
|
||||||
|
totalSize uint64
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
// 计算要复制的总大小
|
if len(fs.DirTarget) > 0 {
|
||||||
var totalSize uint64
|
totalSize, err = fs.DirTarget[0].CopyFolderTo(fs.DirTarget[0].ID, folder)
|
||||||
for _, file := range fs.FileTarget {
|
} else {
|
||||||
totalSize += file.Size
|
parent := model.Folder{
|
||||||
|
OwnerID: fs.FileTarget[0].UserID,
|
||||||
|
}
|
||||||
|
parent.ID = fs.FileTarget[0].FolderID
|
||||||
|
totalSize, err = parent.MoveOrCopyFileTo([]uint{fs.FileTarget[0].ID}, folder, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 扣除用户容量
|
// 扣除用户容量
|
||||||
if !fs.User.IncreaseStorage(totalSize) {
|
fs.User.IncreaseStorageWithoutCheck(totalSize)
|
||||||
return ErrInsufficientCapacity
|
|
||||||
}
|
|
||||||
|
|
||||||
err := folder.CopyChildFrom(fs.DirTarget, fs.FileTarget)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fs.User.DeductionStorage(totalSize)
|
|
||||||
return ErrFileExisted.WithError(err)
|
return ErrFileExisted.WithError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,9 +23,9 @@ func (fs *FileSystem) IsPathExist(path string) (bool, *model.Folder) {
|
||||||
// TODO:测试新增
|
// TODO:测试新增
|
||||||
var currentFolder *model.Folder
|
var currentFolder *model.Folder
|
||||||
|
|
||||||
// 如果已设定目录对象,则从给定目录向下遍历
|
// 如果已设定跟目录对象,则从给定目录向下遍历
|
||||||
if len(fs.DirTarget) > 0 {
|
if fs.Root != nil {
|
||||||
currentFolder = &fs.DirTarget[0]
|
currentFolder = fs.Root
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, folderName := range pathList {
|
for _, folderName := range pathList {
|
||||||
|
|
|
@ -47,6 +47,7 @@ func BuildShareResponse(share *model.Share, unlocked bool) Share {
|
||||||
CreateDate: share.CreatedAt.Format("2006-01-02 15:04:05"),
|
CreateDate: share.CreatedAt.Format("2006-01-02 15:04:05"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 未解锁时只返回基本信息
|
||||||
if !unlocked {
|
if !unlocked {
|
||||||
return resp
|
return resp
|
||||||
}
|
}
|
||||||
|
|
|
@ -133,9 +133,9 @@ func (service *SingleFileService) CreateDocPreviewSession(ctx context.Context, c
|
||||||
fs.SetTargetFile(&[]model.File{*file})
|
fs.SetTargetFile(&[]model.File{*file})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果上下文中已有Folder对象,则重设目标
|
// 重设根目录
|
||||||
if folder, ok := ctx.Value(fsctx.FolderModelCtx).(*model.Folder); ok {
|
if folder, ok := ctx.Value(fsctx.FolderModelCtx).(*model.Folder); ok {
|
||||||
fs.SetTargetDir(&[]model.Folder{*folder})
|
fs.Root = folder
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取文件临时下载地址
|
// 获取文件临时下载地址
|
||||||
|
@ -233,9 +233,9 @@ func (service *SingleFileService) PreviewContent(ctx context.Context, c *gin.Con
|
||||||
fs.SetTargetFile(&[]model.File{*file})
|
fs.SetTargetFile(&[]model.File{*file})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果上下文中已有Folder对象,则重设目标
|
// 如果上下文中已有Folder对象,则重设根目录
|
||||||
if folder, ok := ctx.Value(fsctx.FolderModelCtx).(*model.Folder); ok {
|
if folder, ok := ctx.Value(fsctx.FolderModelCtx).(*model.Folder); ok {
|
||||||
fs.SetTargetDir(&[]model.Folder{*folder})
|
fs.Root = folder
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取文件预览响应
|
// 获取文件预览响应
|
||||||
|
|
|
@ -50,8 +50,8 @@ func (service *ShareGetService) Get(c *gin.Context) serializer.Response {
|
||||||
share.Viewed()
|
share.Viewed()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果已经下载过,不需要付积分
|
// 如果已经下载过或者是自己的分享,不需要付积分
|
||||||
if share.WasDownloadedBy(user, c) {
|
if share.UserID == user.ID || share.WasDownloadedBy(user, c) {
|
||||||
share.Score = 0
|
share.Score = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,6 +81,11 @@ func (service *ShareService) CreateDownloadSession(c *gin.Context) serializer.Re
|
||||||
return serializer.Err(serializer.CodePolicyNotAllowed, "源文件不存在", err)
|
return serializer.Err(serializer.CodePolicyNotAllowed, "源文件不存在", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 重设根目录
|
||||||
|
if share.IsDir {
|
||||||
|
fs.Root = &fs.DirTarget[0]
|
||||||
|
}
|
||||||
|
|
||||||
// 取得下载地址
|
// 取得下载地址
|
||||||
downloadURL, err := fs.GetDownloadURL(context.Background(), service.Path, "download_timeout")
|
downloadURL, err := fs.GetDownloadURL(context.Background(), service.Path, "download_timeout")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -189,8 +194,8 @@ func (service *ShareService) List(c *gin.Context) serializer.Response {
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
// 重设根目录
|
// 重设根目录
|
||||||
fs.SetTargetDir(&[]model.Folder{*share.GetSource().(*model.Folder)})
|
fs.Root = share.GetSource().(*model.Folder)
|
||||||
fs.DirTarget[0].Name = "/"
|
fs.Root.Name = "/"
|
||||||
|
|
||||||
// 分享Key上下文
|
// 分享Key上下文
|
||||||
ctx = context.WithValue(ctx, fsctx.ShareKeyCtx, hashid.HashID(share.ID, hashid.ShareID))
|
ctx = context.WithValue(ctx, fsctx.ShareKeyCtx, hashid.HashID(share.ID, hashid.ShareID))
|
||||||
|
|
Loading…
Add table
Reference in a new issue