diff --git a/assets b/assets index 88c1133..b90a49b 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 88c1133306e2e9692b015db9aac57be20b269a53 +Subproject commit b90a49ba5d809e3042bce801ac28fb7cde74c878 diff --git a/pkg/filesystem/file.go b/pkg/filesystem/file.go index aee0afe..df9107f 100644 --- a/pkg/filesystem/file.go +++ b/pkg/filesystem/file.go @@ -62,10 +62,10 @@ func (fs *FileSystem) AddFile(ctx context.Context, parent *model.Folder) (*model UserID: fs.User.ID, Size: file.GetSize(), FolderID: parent.ID, - PolicyID: fs.User.Policy.ID, + PolicyID: fs.Policy.ID, } - if fs.User.Policy.IsThumbExist(file.GetFileName()) { + if fs.Policy.IsThumbExist(file.GetFileName()) { newFile.PicInfo = "1,1" } @@ -350,7 +350,7 @@ func (fs *FileSystem) resetPolicyToFirstFile(ctx context.Context) error { } // Search 搜索文件 -func (fs *FileSystem) Search(ctx context.Context, keywords ...interface{}) ([]Object, error) { +func (fs *FileSystem) Search(ctx context.Context, keywords ...interface{}) ([]serializer.Object, error) { files, _ := model.GetFilesByKeywords(fs.User.ID, keywords...) fs.SetTargetFile(&files) diff --git a/pkg/filesystem/filesystem.go b/pkg/filesystem/filesystem.go index 9ca9d48..8e45ccd 100644 --- a/pkg/filesystem/filesystem.go +++ b/pkg/filesystem/filesystem.go @@ -104,6 +104,8 @@ func (fs *FileSystem) reset() { func NewFileSystem(user *model.User) (*FileSystem, error) { fs := getEmptyFS() fs.User = user + fs.Policy = &fs.User.Policy + // 分配存储策略适配器 err := fs.DispatchHandler() @@ -132,16 +134,11 @@ func NewAnonymousFileSystem() (*FileSystem, error) { // DispatchHandler 根据存储策略分配文件适配器 func (fs *FileSystem) DispatchHandler() error { - var policyType string - var currentPolicy *model.Policy + currentPolicy := fs.Policy + policyType := currentPolicy.Type - if fs.Policy == nil { - // 如果没有具体指定,就是用用户当前存储策略 - policyType = fs.User.Policy.Type - currentPolicy = &fs.User.Policy - } else { - policyType = fs.Policy.Type - currentPolicy = fs.Policy + if currentPolicy == nil { + return ErrUnknownPolicyType } switch policyType { @@ -241,7 +238,7 @@ func NewFileSystemFromCallback(c *gin.Context) (*FileSystem, error) { // SwitchToSlaveHandler 将负责上传的 Handler 切换为从机节点 func (fs *FileSystem) SwitchToSlaveHandler(node cluster.Node) { - fs.Handler = slaveinmaster.NewDriver(node, fs.Handler, &fs.User.Policy) + fs.Handler = slaveinmaster.NewDriver(node, fs.Handler, fs.Policy) } // SwitchToShadowHandler 将负责上传的 Handler 切换为从机节点转存使用的影子处理器 diff --git a/pkg/filesystem/hooks.go b/pkg/filesystem/hooks.go index 3b5755d..e9eec53 100644 --- a/pkg/filesystem/hooks.go +++ b/pkg/filesystem/hooks.go @@ -119,7 +119,6 @@ func HookResetPolicy(ctx context.Context, fs *FileSystem) error { } fs.Policy = originFile.GetPolicy() - fs.User.Policy = *fs.Policy return fs.DispatchHandler() } @@ -317,7 +316,7 @@ func GenericAfterUpload(ctx context.Context, fs *FileSystem) error { fs.SetTargetFile(&[]model.File{*file}) // 异步尝试生成缩略图 - if fs.User.Policy.IsThumbGenerateNeeded() { + if fs.Policy.IsThumbGenerateNeeded() { fs.recycleLock.Lock() go func() { defer fs.recycleLock.Unlock() diff --git a/pkg/filesystem/manage.go b/pkg/filesystem/manage.go index e5d2e67..528df08 100644 --- a/pkg/filesystem/manage.go +++ b/pkg/filesystem/manage.go @@ -5,7 +5,6 @@ import ( "fmt" "path" "strings" - "time" model "github.com/cloudreve/Cloudreve/v3/models" "github.com/cloudreve/Cloudreve/v3/pkg/filesystem/fsctx" @@ -19,18 +18,6 @@ import ( ================= */ -// Object 文件或者目录 -type Object struct { - ID string `json:"id"` - Name string `json:"name"` - Path string `json:"path"` - Pic string `json:"pic"` - Size uint64 `json:"size"` - Type string `json:"type"` - Date time.Time `json:"date"` - Key string `json:"key,omitempty"` -} - // Rename 重命名对象 func (fs *FileSystem) Rename(ctx context.Context, dir, file []uint, new string) (err error) { // 验证新名字 @@ -266,7 +253,7 @@ func (fs *FileSystem) ListDeleteFiles(ctx context.Context, ids []uint) error { // pathProcessor为最终对象路径的处理钩子。 // 有些情况下(如在分享页面列对象)时, // 路径需要截取掉被分享目录路径之前的部分。 -func (fs *FileSystem) List(ctx context.Context, dirPath string, pathProcessor func(string) string) ([]Object, error) { +func (fs *FileSystem) List(ctx context.Context, dirPath string, pathProcessor func(string) string) ([]serializer.Object, error) { // 获取父目录 isExist, folder := fs.IsPathExist(dirPath) if !isExist { @@ -289,7 +276,7 @@ func (fs *FileSystem) List(ctx context.Context, dirPath string, pathProcessor fu // ListPhysical 列出存储策略中的外部目录 // TODO:测试 -func (fs *FileSystem) ListPhysical(ctx context.Context, dirPath string) ([]Object, error) { +func (fs *FileSystem) ListPhysical(ctx context.Context, dirPath string) ([]serializer.Object, error) { if err := fs.DispatchHandler(); fs.Policy == nil || err != nil { return nil, ErrUnknownPolicyType } @@ -319,7 +306,7 @@ func (fs *FileSystem) ListPhysical(ctx context.Context, dirPath string) ([]Objec return fs.listObjects(ctx, dirPath, nil, folders, nil), nil } -func (fs *FileSystem) listObjects(ctx context.Context, parent string, files []model.File, folders []model.Folder, pathProcessor func(string) string) []Object { +func (fs *FileSystem) listObjects(ctx context.Context, parent string, files []model.File, folders []model.Folder, pathProcessor func(string) string) []serializer.Object { // 分享文件的ID shareKey := "" if key, ok := ctx.Value(fsctx.ShareKeyCtx).(string); ok { @@ -327,7 +314,7 @@ func (fs *FileSystem) listObjects(ctx context.Context, parent string, files []mo } // 汇总处理结果 - objects := make([]Object, 0, len(files)+len(folders)) + objects := make([]serializer.Object, 0, len(files)+len(folders)) // 所有对象的父目录 var processedPath string @@ -343,7 +330,7 @@ func (fs *FileSystem) listObjects(ctx context.Context, parent string, files []mo } } - objects = append(objects, Object{ + objects = append(objects, serializer.Object{ ID: hashid.HashID(subFolder.ID, hashid.FolderID), Name: subFolder.Name, Path: processedPath, @@ -363,14 +350,15 @@ func (fs *FileSystem) listObjects(ctx context.Context, parent string, files []mo } } - newFile := Object{ - ID: hashid.HashID(file.ID, hashid.FileID), - Name: file.Name, - Path: processedPath, - Pic: file.PicInfo, - Size: file.Size, - Type: "file", - Date: file.CreatedAt, + newFile := serializer.Object{ + ID: hashid.HashID(file.ID, hashid.FileID), + Name: file.Name, + Path: processedPath, + Pic: file.PicInfo, + Size: file.Size, + Type: "file", + Date: file.CreatedAt, + SourceEnabled: file.GetPolicy().IsOriginLinkEnable, } if shareKey != "" { newFile.Key = shareKey diff --git a/pkg/filesystem/upload.go b/pkg/filesystem/upload.go index e2b092a..6286b03 100644 --- a/pkg/filesystem/upload.go +++ b/pkg/filesystem/upload.go @@ -81,11 +81,11 @@ func (fs *FileSystem) Upload(ctx context.Context, file FileHeader) (err error) { func (fs *FileSystem) GenerateSavePath(ctx context.Context, file FileHeader) string { if fs.User.Model.ID != 0 { return path.Join( - fs.User.Policy.GeneratePath( + fs.Policy.GeneratePath( fs.User.Model.ID, file.GetVirtualPath(), ), - fs.User.Policy.GenerateFileName( + fs.Policy.GenerateFileName( fs.User.Model.ID, file.GetFileName(), ), @@ -155,15 +155,15 @@ func (fs *FileSystem) GetUploadToken(ctx context.Context, path string, size uint var err error // 检查文件大小 - if fs.User.Policy.MaxSize != 0 { - if size > fs.User.Policy.MaxSize { + if fs.Policy.MaxSize != 0 { + if size > fs.Policy.MaxSize { return nil, ErrFileSizeTooBig } } // 是否需要预先生成存储路径 var savePath string - if fs.User.Policy.IsPathGenerateNeeded() { + if fs.Policy.IsPathGenerateNeeded() { savePath = fs.GenerateSavePath(ctx, local.FileStream{Name: name, VirtualPath: path}) ctx = context.WithValue(ctx, fsctx.SavePathCtx, savePath) } @@ -182,7 +182,6 @@ func (fs *FileSystem) GetUploadToken(ctx context.Context, path string, size uint serializer.UploadSession{ Key: callbackKey, UID: fs.User.ID, - PolicyID: fs.User.GetPolicyID(0), VirtualPath: path, Name: name, Size: size, diff --git a/pkg/filesystem/validator.go b/pkg/filesystem/validator.go index 1639675..c7504f4 100644 --- a/pkg/filesystem/validator.go +++ b/pkg/filesystem/validator.go @@ -45,10 +45,10 @@ func (fs *FileSystem) ValidateLegalName(ctx context.Context, name string) bool { // ValidateFileSize 验证上传的文件大小是否超出限制 func (fs *FileSystem) ValidateFileSize(ctx context.Context, size uint64) bool { - if fs.User.Policy.MaxSize == 0 { + if fs.Policy.MaxSize == 0 { return true } - return size <= fs.User.Policy.MaxSize + return size <= fs.Policy.MaxSize } // ValidateCapacity 验证并扣除用户容量 @@ -59,11 +59,11 @@ func (fs *FileSystem) ValidateCapacity(ctx context.Context, size uint64) bool { // ValidateExtension 验证文件扩展名 func (fs *FileSystem) ValidateExtension(ctx context.Context, fileName string) bool { // 不需要验证 - if len(fs.User.Policy.OptionsSerialized.FileType) == 0 { + if len(fs.Policy.OptionsSerialized.FileType) == 0 { return true } - return IsInExtensionList(fs.User.Policy.OptionsSerialized.FileType, fileName) + return IsInExtensionList(fs.Policy.OptionsSerialized.FileType, fileName) } // IsInExtensionList 返回文件的扩展名是否在给定的列表范围内 diff --git a/pkg/serializer/explorer.go b/pkg/serializer/explorer.go index 6a76d6c..905f2d2 100644 --- a/pkg/serializer/explorer.go +++ b/pkg/serializer/explorer.go @@ -2,6 +2,8 @@ package serializer import ( "encoding/gob" + model "github.com/cloudreve/Cloudreve/v3/models" + "github.com/cloudreve/Cloudreve/v3/pkg/hashid" "time" ) @@ -21,3 +23,55 @@ type ObjectProps struct { QueryDate time.Time `json:"query_date"` } + +// ObjectList 文件、目录列表 +type ObjectList struct { + Parent string `json:"parent,omitempty"` + Objects []Object `json:"objects"` + Policy *PolicySummary `json:"policy,omitempty"` +} + +// Object 文件或者目录 +type Object struct { + ID string `json:"id"` + Name string `json:"name"` + Path string `json:"path"` + Pic string `json:"pic"` + Size uint64 `json:"size"` + Type string `json:"type"` + Date time.Time `json:"date"` + Key string `json:"key,omitempty"` + SourceEnabled bool `json:"source_enabled"` +} + +// PolicySummary 用于前端组件使用的存储策略概况 +type PolicySummary struct { + ID string `json:"id"` + Name string `json:"name"` + Type string `json:"type"` + MaxSize uint64 `json:"max_size"` + FileType []string `json:"file_type"` +} + +// BuildObjectList 构建列目录响应 +func BuildObjectList(parent uint, objects []Object, policy *model.Policy) ObjectList { + res := ObjectList{ + Objects: objects, + } + + if parent > 0 { + res.Parent = hashid.HashID(parent, hashid.FolderID) + } + + if policy != nil { + res.Policy = &PolicySummary{ + ID: hashid.HashID(policy.ID, hashid.PolicyID), + Name: policy.Name, + Type: policy.Type, + MaxSize: policy.MaxSize, + FileType: policy.OptionsSerialized.FileType, + } + } + + return res +} diff --git a/pkg/serializer/user.go b/pkg/serializer/user.go index 0ba8b5d..faf82a4 100644 --- a/pkg/serializer/user.go +++ b/pkg/serializer/user.go @@ -27,7 +27,6 @@ type User struct { CreatedAt time.Time `json:"created_at"` PreferredTheme string `json:"preferred_theme"` Anonymous bool `json:"anonymous"` - Policy policy `json:"policy"` Group group `json:"group"` Tags []tag `json:"tags"` } @@ -98,13 +97,6 @@ func BuildUser(user model.User) User { CreatedAt: user.CreatedAt, PreferredTheme: user.OptionsSerialized.PreferredTheme, Anonymous: user.IsAnonymous(), - Policy: policy{ - SaveType: user.Policy.Type, - MaxSize: fmt.Sprintf("%.2fmb", float64(user.Policy.MaxSize)/(1024*1024)), - AllowedType: user.Policy.OptionsSerialized.FileType, - UploadURL: user.Policy.GetUploadURL(), - AllowGetSource: user.Policy.IsOriginLinkEnable, - }, Group: group{ ID: user.GroupID, Name: user.Group.Name, diff --git a/routers/controllers/file.go b/routers/controllers/file.go index a3bf7cc..fdc323a 100644 --- a/routers/controllers/file.go +++ b/routers/controllers/file.go @@ -3,17 +3,16 @@ package controllers import ( "context" "fmt" + "github.com/cloudreve/Cloudreve/v3/pkg/request" "net/http" "net/url" "strconv" "sync" - model "github.com/cloudreve/Cloudreve/v3/models" "github.com/cloudreve/Cloudreve/v3/pkg/conf" "github.com/cloudreve/Cloudreve/v3/pkg/filesystem" "github.com/cloudreve/Cloudreve/v3/pkg/filesystem/driver/local" "github.com/cloudreve/Cloudreve/v3/pkg/filesystem/fsctx" - "github.com/cloudreve/Cloudreve/v3/pkg/request" "github.com/cloudreve/Cloudreve/v3/pkg/serializer" "github.com/cloudreve/Cloudreve/v3/service/explorer" "github.com/gin-gonic/gin" @@ -300,13 +299,6 @@ func FileUploadStream(c *gin.Context) { return } - // 非可用策略时拒绝上传 - if user, ok := c.Get("user"); ok && !user.(*model.User).Policy.IsTransitUpload(fileSize) { - request.BlackHole(c.Request.Body) - c.JSON(200, serializer.Err(serializer.CodePolicyNotAllowed, "当前存储策略无法使用", nil)) - return - } - // 解码文件名和路径 fileName, err := url.QueryUnescape(c.Request.Header.Get("X-Cr-FileName")) filePath, err := url.QueryUnescape(c.Request.Header.Get("X-Cr-Path")) @@ -330,6 +322,13 @@ func FileUploadStream(c *gin.Context) { return } + // 非可用策略时拒绝上传 + if !fs.Policy.IsTransitUpload(fileSize) { + request.BlackHole(c.Request.Body) + c.JSON(200, serializer.Err(serializer.CodePolicyNotAllowed, "当前存储策略无法使用", nil)) + return + } + // 给文件系统分配钩子 fs.Use("BeforeUpload", filesystem.HookValidateFile) fs.Use("BeforeUpload", filesystem.HookValidateCapacity) diff --git a/service/admin/file.go b/service/admin/file.go index bf9bd18..eeb4222 100644 --- a/service/admin/file.go +++ b/service/admin/file.go @@ -54,9 +54,7 @@ func (service *ListFolderService) List(c *gin.Context) serializer.Response { } return serializer.Response{ - Data: map[string]interface{}{ - "objects": res, - }, + Data: serializer.BuildObjectList(0, res, nil), } } @@ -82,9 +80,7 @@ func (service *ListFolderService) List(c *gin.Context) serializer.Response { } return serializer.Response{ - Data: map[string]interface{}{ - "objects": res, - }, + Data: serializer.BuildObjectList(0, res, nil), } } diff --git a/service/explorer/directory.go b/service/explorer/directory.go index 0291ba5..844f812 100644 --- a/service/explorer/directory.go +++ b/service/explorer/directory.go @@ -4,7 +4,6 @@ import ( "context" "github.com/cloudreve/Cloudreve/v3/pkg/filesystem" - "github.com/cloudreve/Cloudreve/v3/pkg/hashid" "github.com/cloudreve/Cloudreve/v3/pkg/serializer" "github.com/gin-gonic/gin" ) @@ -40,10 +39,7 @@ func (service *DirectoryService) ListDirectory(c *gin.Context) serializer.Respon return serializer.Response{ Code: 0, - Data: map[string]interface{}{ - "parent": hashid.HashID(parentID, hashid.FolderID), - "objects": objects, - }, + Data: serializer.BuildObjectList(parentID, objects, fs.Policy), } } diff --git a/service/explorer/upload.go b/service/explorer/upload.go index 4495461..4e16b8a 100644 --- a/service/explorer/upload.go +++ b/service/explorer/upload.go @@ -25,13 +25,6 @@ func (service *UploadCredentialService) Get(ctx context.Context, c *gin.Context) return serializer.Err(serializer.CodePolicyNotAllowed, err.Error(), err) } - // 存储策略是否一致 - if service.Type != "" { - if service.Type != fs.User.Policy.Type { - return serializer.Err(serializer.CodePolicyNotAllowed, "存储策略已变更,请刷新页面", nil) - } - } - ctx = context.WithValue(ctx, fsctx.GinCtx, c) credential, err := fs.GetUploadToken(ctx, service.Path, service.Size, service.Name) if err != nil { diff --git a/service/share/visit.go b/service/share/visit.go index 0eb0c8e..ce84d1b 100644 --- a/service/share/visit.go +++ b/service/share/visit.go @@ -263,10 +263,7 @@ func (service *Service) List(c *gin.Context) serializer.Response { return serializer.Response{ Code: 0, - Data: map[string]interface{}{ - "parent": "0000", - "objects": objects, - }, + Data: serializer.BuildObjectList(0, objects, nil), } }