diff --git a/models/file.go b/models/file.go index f40bf13..d29960f 100644 --- a/models/file.go +++ b/models/file.go @@ -31,6 +31,13 @@ func (file *File) Create() (uint, error) { // GetFileByPathAndName 给定路径、文件名、用户ID,查找文件 func GetFileByPathAndName(path string, name string, uid uint) (File, error) { var file File - result := DB.Where("user_id = ? AND dir = ? AND name=?", uid, path, name).Find(&file) + result := DB.Where("user_id = ? AND dir = ? AND name=?", uid, path, name).First(&file) return file, result.Error } + +// GetChildFile 查找目录下子文件 TODO:test +func (folder *Folder) GetChildFile() ([]File, error) { + var files []File + result := DB.Where("folder_id = ?", folder.ID).Find(&files) + return files, result.Error +} diff --git a/models/folder.go b/models/folder.go index 7f40352..d539edb 100644 --- a/models/folder.go +++ b/models/folder.go @@ -16,7 +16,7 @@ type Folder struct { PositionAbsolute string `gorm:"size:65536"` } -// Create 创建目录 +// Create 创建目录 TODO:test func (folder *Folder) Create() (uint, error) { if err := DB.Create(folder).Error; err != nil { util.Log().Warning("无法插入目录记录, %s", err) @@ -28,6 +28,13 @@ func (folder *Folder) Create() (uint, error) { // GetFolderByPath 根据绝对路径和UID查找目录 func GetFolderByPath(path string, uid uint) (Folder, error) { var folder Folder - result := DB.Where("owner_id = ? AND position_absolute = ?", uid, path).Find(&folder) + result := DB.Where("owner_id = ? AND position_absolute = ?", uid, path).First(&folder) return folder, result.Error } + +// GetChildFolder 查找子目录 TODO:test +func (folder *Folder) GetChildFolder() ([]Folder, error) { + var folders []Folder + result := DB.Where("parent_id = ?", folder.ID).Find(&folders) + return folders, result.Error +} diff --git a/pkg/filesystem/filesystem.go b/pkg/filesystem/filesystem.go index dc36834..b9b1604 100644 --- a/pkg/filesystem/filesystem.go +++ b/pkg/filesystem/filesystem.go @@ -4,6 +4,7 @@ import ( "context" "github.com/HFO4/cloudreve/models" "github.com/HFO4/cloudreve/pkg/filesystem/local" + "github.com/gin-gonic/gin" testMock "github.com/stretchr/testify/mock" "io" ) @@ -73,3 +74,11 @@ func NewFileSystem(user *model.User) (*FileSystem, error) { Handler: handler, }, nil } + +// NewFileSystemFromContext 从gin.Context创建文件系统 +// TODO:test +func NewFileSystemFromContext(c *gin.Context) (*FileSystem, error) { + user, _ := c.Get("user") + fs, err := NewFileSystem(user.(*model.User)) + return fs, err +} diff --git a/pkg/filesystem/path.go b/pkg/filesystem/path.go index 1a80dfe..cd73f73 100644 --- a/pkg/filesystem/path.go +++ b/pkg/filesystem/path.go @@ -11,7 +11,79 @@ import ( ================= */ -// CreateDirectory 在`base`路径下创建名为`dir`的目录 +// Object 文件或者目录 +type Object struct { + ID uint `json:"id"` + Name string `json:"name"` + Path string `json:"path"` + Pic string `json:"pic"` + Size uint64 `json:"size"` + Type string `json:"type"` +} + +// List 列出路径下的内容 +func (fs *FileSystem) List(ctx context.Context, path string, pathProcessor func(string) string) ([]Object, error) { + // 获取父目录 + isExist, folder := fs.IsPathExist(path) + // 不存在时返回空的结果 + if !isExist { + return nil, nil + } + + // 获取子目录 + childFolders, _ := folder.GetChildFolder() + // 获取子文件 + childFiles, _ := folder.GetChildFile() + + // 汇总处理结果 + objects := make([]Object, 0, len(childFiles)+len(childFolders)) + // 所有对象的父目录 + var processedPath string + + for _, folder := range childFolders { + // 路径处理钩子, + // 所有对象父目录都是一样的,所以只处理一次 + if processedPath == "" { + if pathProcessor != nil { + processedPath = pathProcessor(folder.Position) + } else { + processedPath = folder.Position + } + } + + objects = append(objects, Object{ + ID: folder.ID, + Name: folder.Name, + Path: processedPath, + Pic: "", + Size: 0, + Type: "dir", + }) + } + + for _, file := range childFiles { + if processedPath == "" { + if pathProcessor != nil { + processedPath = pathProcessor(file.Dir) + } else { + processedPath = file.Dir + } + } + + objects = append(objects, Object{ + ID: file.ID, + Name: file.Name, + Path: processedPath, + Pic: file.PicInfo, + Size: file.Size, + Type: "file", + }) + } + + return objects, nil +} + +// CreateDirectory 在`base`路径下创建名为`dir`的目录 TODO: test func (fs *FileSystem) CreateDirectory(ctx context.Context, fullPath string) error { // 获取要创建目录的父路径和目录名 fullPath = path.Clean(fullPath) diff --git a/routers/controllers/directory.go b/routers/controllers/directory.go index 523c5a6..efd8702 100644 --- a/routers/controllers/directory.go +++ b/routers/controllers/directory.go @@ -7,7 +7,7 @@ import ( // CreateDirectory 创建目录 func CreateDirectory(c *gin.Context) { - var service explorer.DirectoryCreateService + var service explorer.DirectoryService if err := c.ShouldBindJSON(&service); err == nil { res := service.CreateDirectory(c) c.JSON(200, res) @@ -15,3 +15,14 @@ func CreateDirectory(c *gin.Context) { c.JSON(200, ErrorResponse(err)) } } + +// ListDirectory 列出目录下内容 +func ListDirectory(c *gin.Context) { + var service explorer.DirectoryService + if err := c.ShouldBindJSON(&service); err == nil { + res := service.ListDirectory(c) + c.JSON(200, res) + } else { + c.JSON(200, ErrorResponse(err)) + } +} diff --git a/routers/controllers/file.go b/routers/controllers/file.go index 132ca0e..b9f87a1 100644 --- a/routers/controllers/file.go +++ b/routers/controllers/file.go @@ -37,10 +37,9 @@ func FileUploadStream(c *gin.Context) { Name: c.Request.Header.Get("X-FileName"), VirtualPath: util.DotPathToStandardPath(c.Request.Header.Get("X-Path")), } - user, _ := c.Get("user") // 创建文件系统 - fs, err := filesystem.NewFileSystem(user.(*model.User)) + fs, err := filesystem.NewFileSystemFromContext(c) if err != nil { c.JSON(200, serializer.Err(serializer.CodePolicyNotAllowed, err.Error(), err)) return diff --git a/routers/router.go b/routers/router.go index 207908b..50237db 100644 --- a/routers/router.go +++ b/routers/router.go @@ -69,6 +69,8 @@ func InitRouter() *gin.Engine { { // 创建目录 directory.PUT("", controllers.CreateDirectory) + // 列出目录下内容 + directory.GET("", controllers.ListDirectory) } } diff --git a/service/explorer/directory.go b/service/explorer/directory.go index 4363c26..7c8e340 100644 --- a/service/explorer/directory.go +++ b/service/explorer/directory.go @@ -2,22 +2,44 @@ package explorer import ( "context" - model "github.com/HFO4/cloudreve/models" "github.com/HFO4/cloudreve/pkg/filesystem" "github.com/HFO4/cloudreve/pkg/serializer" "github.com/gin-gonic/gin" ) -// DirectoryCreateService 创建新目录服务 -type DirectoryCreateService struct { - Path string `form:"newPath" json:"newPath" binding:"required,min=1,max=65535"` +// DirectoryService 创建新目录服务 +type DirectoryService struct { + Path string `form:"path" json:"path" binding:"required,min=1,max=65535"` } -// CreateDirectory 创建目录 -func (service *DirectoryCreateService) CreateDirectory(c *gin.Context) serializer.Response { +// ListDirectory 列出目录内容 TODO:test +func (service *DirectoryService) ListDirectory(c *gin.Context) serializer.Response { // 创建文件系统 - user, _ := c.Get("user") - fs, err := filesystem.NewFileSystem(user.(*model.User)) + fs, err := filesystem.NewFileSystemFromContext(c) + if err != nil { + return serializer.Err(serializer.CodePolicyNotAllowed, err.Error(), err) + } + + // 上下文 + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + // 获取子项目 + objects, err := fs.List(ctx, service.Path, nil) + if err != nil { + return serializer.Err(serializer.CodeCreateFolderFailed, err.Error(), err) + } + + return serializer.Response{ + Code: 0, + Data: objects, + } +} + +// CreateDirectory 创建目录 TODO:test +func (service *DirectoryService) CreateDirectory(c *gin.Context) serializer.Response { + // 创建文件系统 + fs, err := filesystem.NewFileSystemFromContext(c) if err != nil { return serializer.Err(serializer.CodePolicyNotAllowed, err.Error(), err) }