Feat: API for getting object property

pull/796/head
HFO4 3 years ago
parent a93b964d8b
commit 1f1bc056e3

@ -1 +1 @@
Subproject commit e2d4f13a54dfd424cfbc129664772e104ccf97fc
Subproject commit 4f114cf386770dfdc568b60465a29feb4db65371

@ -44,6 +44,26 @@ func (folder *Folder) GetChild(name string) (*Folder, error) {
return &resFolder, err
}
// TraceRoot 向上递归查找父目录
func (folder *Folder) TraceRoot() error {
if folder.ParentID == nil {
return nil
}
var parentFolder Folder
err := DB.
Where("id = ? AND owner_id = ?", folder.ParentID, folder.OwnerID).
First(&parentFolder).Error
if err == nil {
err := parentFolder.TraceRoot()
folder.Position = path.Join(parentFolder.Position, parentFolder.Name)
return err
}
return err
}
// GetChildFolder 查找子目录
func (folder *Folder) GetChildFolder() ([]Folder, error) {
var folders []Folder

@ -530,3 +530,37 @@ func TestFolder_FileInfoInterface(t *testing.T) {
asserts.True(folder.IsDir())
asserts.Equal("/test", folder.GetPosition())
}
func TestTraceRoot(t *testing.T) {
asserts := assert.New(t)
var parentId uint
parentId = 5
folder := Folder{
ParentID: &parentId,
OwnerID: 1,
Name: "test_name",
}
// 成功
{
mock.ExpectQuery("SELECT(.+)").WithArgs(5, 1).
WillReturnRows(sqlmock.NewRows([]string{"id", "name", "parent_id"}).AddRow(5, "parent", 1))
mock.ExpectQuery("SELECT(.+)").WithArgs(1, 0).
WillReturnRows(sqlmock.NewRows([]string{"id", "name"}).AddRow(5, "/"))
asserts.NoError(folder.TraceRoot())
asserts.Equal("/parent", folder.Position)
asserts.NoError(mock.ExpectationsWereMet())
}
// 出现错误
// 成功
{
mock.ExpectQuery("SELECT(.+)").WithArgs(5, 1).
WillReturnRows(sqlmock.NewRows([]string{"id", "name", "parent_id"}).AddRow(5, "parent", 1))
mock.ExpectQuery("SELECT(.+)").WithArgs(1, 0).
WillReturnError(errors.New("error"))
asserts.Error(folder.TraceRoot())
asserts.Equal("parent", folder.Position)
asserts.NoError(mock.ExpectationsWereMet())
}
}

@ -104,6 +104,7 @@ func addDefaultSettings() {
{Name: "share_download_session_timeout", Value: `2073600`, Type: "timeout"},
{Name: "onedrive_callback_check", Value: `20`, Type: "timeout"},
{Name: "aria2_call_timeout", Value: `5`, Type: "timeout"},
{Name: "folder_props_timeout", Value: `300`, Type: "timeout"},
{Name: "onedrive_chunk_retries", Value: `1`, Type: "retry"},
{Name: "onedrive_source_timeout", Value: `1800`, Type: "timeout"},
{Name: "reset_after_upload_failed", Value: `0`, Type: "upload"},

@ -0,0 +1,23 @@
package serializer
import (
"encoding/gob"
"time"
)
func init() {
gob.Register(ObjectProps{})
}
// ObjectProps 文件、目录对象的详细属性信息
type ObjectProps struct {
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
Policy string `json:"policy"`
Size uint64 `json:"size"`
ChildFolderNum int `json:"child_folder_num"`
ChildFileNum int `json:"child_file_num"`
Path string `json:"path"`
QueryDate time.Time
}

@ -66,3 +66,19 @@ func Rename(c *gin.Context) {
c.JSON(200, ErrorResponse(err))
}
}
// Rename 重命名文件或目录
func GetProperty(c *gin.Context) {
// 创建上下文
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
var service explorer.ItemPropertyService
service.ID = c.Param("id")
if err := c.ShouldBindQuery(&service); err == nil {
res := service.GetProperty(ctx, c)
c.JSON(200, res)
} else {
c.JSON(200, ErrorResponse(err))
}
}

@ -510,6 +510,8 @@ func InitMasterRouter() *gin.Engine {
object.POST("copy", controllers.Copy)
// 重命名对象
object.POST("rename", controllers.Rename)
// 获取对象属性
object.GET("property/:id", controllers.GetProperty)
}
// 分享

@ -60,6 +60,13 @@ type ItemDecompressService struct {
Dst string `json:"dst" binding:"required,min=1,max=65535"`
}
// ItemPropertyService 获取对象属性服务
type ItemPropertyService struct {
ID string `binding:"required"`
TraceRoot bool `form:"trace_root"`
IsFolder bool `form:"is_folder"`
}
// Raw 批量解码HashID获取原始ID
func (service *ItemIDService) Raw() *ItemService {
if service.Source != nil {
@ -353,3 +360,100 @@ func (service *ItemRenameService) Rename(ctx context.Context, c *gin.Context) se
Code: 0,
}
}
// GetProperty 获取对象的属性
func (service *ItemPropertyService) GetProperty(ctx context.Context, c *gin.Context) serializer.Response {
userCtx, _ := c.Get("user")
user := userCtx.(*model.User)
var props serializer.ObjectProps
props.QueryDate = time.Now()
// 如果是文件对象
if !service.IsFolder {
res, err := hashid.DecodeHashID(service.ID, hashid.FileID)
if err != nil {
return serializer.Err(serializer.CodeNotFound, "对象不存在", err)
}
file, err := model.GetFilesByIDs([]uint{res}, user.ID)
if err != nil {
return serializer.DBErr("找不到文件", err)
}
props.CreatedAt = file[0].CreatedAt
props.UpdatedAt = file[0].UpdatedAt
props.Policy = file[0].GetPolicy().Name
props.Size = file[0].Size
// 查找父目录
if service.TraceRoot {
parent, err := model.GetFoldersByIDs([]uint{file[0].FolderID}, user.ID)
if err != nil {
return serializer.DBErr("找不到父目录", err)
}
if err := parent[0].TraceRoot(); err != nil {
return serializer.DBErr("无法溯源父目录", err)
}
props.Path = path.Join(parent[0].Position, parent[0].Name)
}
} else {
res, err := hashid.DecodeHashID(service.ID, hashid.FolderID)
if err != nil {
return serializer.Err(serializer.CodeNotFound, "对象不存在", err)
}
// 如果对象是目录, 先尝试返回缓存结果
if cacheRes, ok := cache.Get(fmt.Sprintf("folder_props_%d", res)); ok {
return serializer.Response{Data: cacheRes.(serializer.ObjectProps)}
}
folder, err := model.GetFoldersByIDs([]uint{res}, user.ID)
if err != nil {
return serializer.DBErr("找不到目录", err)
}
props.CreatedAt = folder[0].CreatedAt
props.UpdatedAt = folder[0].UpdatedAt
// 统计子目录
childFolders, err := model.GetRecursiveChildFolder([]uint{folder[0].ID},
user.ID, true)
if err != nil {
return serializer.DBErr("无法列取子目录", err)
}
props.ChildFolderNum = len(childFolders) - 1
// 统计子文件
files, err := model.GetChildFilesOfFolders(&childFolders)
if err != nil {
return serializer.DBErr("无法列取子文件", err)
}
// 统计子文件个数和大小
props.ChildFileNum = len(files)
for i := 0; i < len(files); i++ {
props.Size += files[i].Size
}
// 查找父目录
if service.TraceRoot {
if err := folder[0].TraceRoot(); err != nil {
return serializer.DBErr("无法溯源父目录", err)
}
props.Path = folder[0].Position
}
// 如果列取对象是目录,则缓存结果
cache.Set(fmt.Sprintf("folder_props_%d", res), props,
model.GetIntSetting("folder_props_timeout", 300))
}
return serializer.Response{
Code: 0,
Data: props,
}
}

Loading…
Cancel
Save