feat(api): doc folders curd implemention
This commit is contained in:
@@ -9,6 +9,7 @@ import (
|
||||
"octopus/internal/dal/model"
|
||||
"octopus/internal/dal/query"
|
||||
"octopus/internal/schema"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/casdoor/casdoor-go-sdk/casdoorsdk"
|
||||
@@ -46,7 +47,7 @@ func CreateDoc(ctx context.Context, auth *casdoorsdk.User, param *schema.CreateD
|
||||
}
|
||||
|
||||
// 将对象从临时地址移动到新地址
|
||||
newPath := fmt.Sprintf("%s/%s/%s", auth.Owner, folder.Path, param.Name)
|
||||
newPath := fmt.Sprintf("%s/%s/%s", auth.Owner, folder.ParentPath, param.Name)
|
||||
if err := storage.MoveObject(ctx, param.ObjectName, newPath); err != nil {
|
||||
return nil, fmt.Errorf("failed to move object: %w", err)
|
||||
}
|
||||
@@ -90,17 +91,17 @@ func UpdateDoc(ctx context.Context, auth *casdoorsdk.User, id string, body *sche
|
||||
}
|
||||
|
||||
if body.FolderID != nil {
|
||||
folder, err := GetDocFolder(ctx, auth, *body.FolderID)
|
||||
if err != nil {
|
||||
if _, err := GetDocFolder(ctx, auth, *body.FolderID); err != nil {
|
||||
return nil, fmt.Errorf("failed to get doc folder: %w", err)
|
||||
}
|
||||
|
||||
// 将对象从临时地址移动到新地址
|
||||
newObjectName := fmt.Sprintf("%s/%s/%s", auth.Owner, folder.Path, doc.Name)
|
||||
parts := strings.Split(doc.ObjectName, "/")
|
||||
objname := parts[len(parts)-1]
|
||||
newObjectName := fmt.Sprintf("%s/%s/%s", auth.Owner, time.Now().UTC().Format(time.DateOnly), objname)
|
||||
if err := dal.GetStorage().MoveObject(ctx, doc.ObjectName, newObjectName); err != nil {
|
||||
return nil, fmt.Errorf("failed to move object: %w", err)
|
||||
}
|
||||
|
||||
updates = append(updates, query.Doc.ObjectName.Value(newObjectName))
|
||||
updates = append(updates, query.Doc.FolderID.Value(*body.FolderID))
|
||||
}
|
||||
@@ -162,14 +163,3 @@ func CreateUploadURL(ctx context.Context, auth *casdoorsdk.User, param *schema.C
|
||||
}
|
||||
return u, tmpObjectName, nil
|
||||
}
|
||||
|
||||
func GetDocFolder(ctx context.Context, auth *casdoorsdk.User, id string) (*model.DocFolder, error) {
|
||||
folder, err := query.DocFolder.Where(query.DocFolder.OrgID.Eq(auth.Owner), query.DocFolder.ID.Eq(id)).Take()
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, fmt.Errorf("specified doc folder not exists")
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return folder, nil
|
||||
}
|
||||
|
||||
203
internal/service/doc_folder.go
Normal file
203
internal/service/doc_folder.go
Normal file
@@ -0,0 +1,203 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"octopus/internal/dal"
|
||||
"octopus/internal/dal/model"
|
||||
"octopus/internal/dal/query"
|
||||
"octopus/internal/schema"
|
||||
|
||||
"github.com/casdoor/casdoor-go-sdk/casdoorsdk"
|
||||
"gorm.io/gen/field"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func GetDocFolderTree(ctx context.Context, auth *casdoorsdk.User, param *schema.GetDocFolderTree) ([]*model.DocFolderWithChildren, error) {
|
||||
parentPath := ""
|
||||
parentID := ""
|
||||
if param.ParentID != nil {
|
||||
parent, err := GetDocFolder(ctx, auth, *param.ParentID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get parent folder: %w", err)
|
||||
}
|
||||
parentPath = parent.ParentPath
|
||||
parentID = parent.ID
|
||||
}
|
||||
|
||||
folders, err := query.DocFolder.
|
||||
Where(
|
||||
query.DocFolder.OrgID.Eq(auth.Owner),
|
||||
query.DocFolder.ParentPath.Like(parentPath+"%"),
|
||||
).
|
||||
Order(query.DocFolder.ParentPath).
|
||||
Find()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get doc folders: %w", err)
|
||||
}
|
||||
|
||||
// 如果没有的话,就创建一个默认的分组
|
||||
if len(folders) == 0 {
|
||||
folder := model.DocFolder{
|
||||
Base: model.Base{OrgID: auth.Owner},
|
||||
Name: "默认分组",
|
||||
IsDefault: true,
|
||||
ParentPath: parentPath,
|
||||
CreatedBy: auth.Id,
|
||||
}
|
||||
if err := query.DocFolder.Create(&folder); err != nil {
|
||||
return nil, fmt.Errorf("failed to create doc folder: %w", err)
|
||||
}
|
||||
|
||||
folders = append(folders, &folder)
|
||||
}
|
||||
|
||||
return composeFolders(parentID, folders), nil
|
||||
}
|
||||
|
||||
func GetDocFolder(ctx context.Context, auth *casdoorsdk.User, id string) (*model.DocFolder, error) {
|
||||
folder, err := query.DocFolder.Where(query.DocFolder.OrgID.Eq(auth.Owner), query.DocFolder.ID.Eq(id)).Take()
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, fmt.Errorf("specified doc folder not exists")
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return folder, nil
|
||||
}
|
||||
|
||||
func GetDocFolderChildren(ctx context.Context, auth *casdoorsdk.User, id string) ([]*model.DocFolder, error) {
|
||||
folder, err := GetDocFolder(ctx, auth, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return query.DocFolder.Where(query.DocFolder.OrgID.Eq(auth.Owner), query.DocFolder.ParentPath.Like(folder.ParentPath+"%")).Find()
|
||||
}
|
||||
|
||||
func CreateDocFolder(ctx context.Context, auth *casdoorsdk.User, param *schema.CreateDocFolder) (*model.DocFolder, error) {
|
||||
path := ""
|
||||
if param.ParentID != "" {
|
||||
parent, err := GetDocFolder(ctx, auth, param.ParentID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get parent folder: %w", err)
|
||||
}
|
||||
path = fmt.Sprintf("%s/%s", parent.ParentPath, parent.ID)
|
||||
}
|
||||
|
||||
folder := model.DocFolder{
|
||||
Base: model.Base{OrgID: auth.Owner},
|
||||
Name: param.Name,
|
||||
ParentPath: path,
|
||||
CreatedBy: auth.Id,
|
||||
}
|
||||
if err := query.DocFolder.Create(&folder); err != nil {
|
||||
return nil, fmt.Errorf("failed to create doc folder: %w", err)
|
||||
}
|
||||
return &folder, nil
|
||||
}
|
||||
|
||||
func UpdateDocFolder(ctx context.Context, auth *casdoorsdk.User, id string, param *schema.UpdateDocFolder) (*model.DocFolder, error) {
|
||||
folder, err := GetDocFolder(ctx, auth, id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get doc folder: %w", err)
|
||||
}
|
||||
|
||||
var updates []field.AssignExpr
|
||||
|
||||
if param.ParentID != nil {
|
||||
if folder.IsDefault {
|
||||
return nil, fmt.Errorf("cannot move the default folder")
|
||||
}
|
||||
|
||||
parent, err := GetDocFolder(ctx, auth, *param.ParentID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get parent folder: %w", err)
|
||||
}
|
||||
newParentPath := fmt.Sprintf("%s/%s", parent.ParentPath, parent.ID)
|
||||
updates = append(updates, query.DocFolder.ParentPath.Value(newParentPath))
|
||||
}
|
||||
|
||||
if param.Name != nil {
|
||||
updates = append(updates, query.DocFolder.Name.Value(*param.Name))
|
||||
}
|
||||
if _, err := query.DocFolder.Where(query.DocFolder.ID.Eq(id)).UpdateSimple(updates...); err != nil {
|
||||
return nil, fmt.Errorf("failed to update doc folder: %w", err)
|
||||
}
|
||||
return GetDocFolder(ctx, auth, id)
|
||||
}
|
||||
|
||||
func DeleteDocFolder(ctx context.Context, auth *casdoorsdk.User, id string) error {
|
||||
folder, err := GetDocFolder(ctx, auth, id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get doc folder: %w", err)
|
||||
}
|
||||
if folder.IsDefault {
|
||||
return fmt.Errorf("cannot delete the default folder")
|
||||
}
|
||||
subFolders, err := GetDocFolderChildren(ctx, auth, id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get doc folder children: %w", err)
|
||||
}
|
||||
|
||||
allFolderIDs := make([]string, 0, len(subFolders)+1)
|
||||
allFolderIDs = append(allFolderIDs, folder.ID)
|
||||
for _, subFolder := range subFolders {
|
||||
allFolderIDs = append(allFolderIDs, subFolder.ID)
|
||||
}
|
||||
|
||||
// 需要把文件和对应的对象存储中的文件一并删除
|
||||
docs, err := query.Doc.Where(query.Doc.OrgID.Eq(auth.Owner), query.Doc.FolderID.In(allFolderIDs...)).Find()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get docs: %w", err)
|
||||
}
|
||||
|
||||
objectNames := make([]string, 0, len(docs))
|
||||
docIDs := make([]string, 0, len(docs))
|
||||
for _, doc := range docs {
|
||||
objectNames = append(objectNames, doc.ObjectName)
|
||||
docIDs = append(docIDs, doc.ID)
|
||||
}
|
||||
|
||||
if len(objectNames) > 0 {
|
||||
if errs := dal.GetStorage().DeleteObjects(ctx, objectNames); len(errs) != 0 {
|
||||
err := errors.New("failed to delete objects")
|
||||
for _, e := range errs {
|
||||
err = fmt.Errorf("failed to delete object %s: %w", e.ObjectName, e.Err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(docIDs) > 0 {
|
||||
if _, err := query.Doc.Where(query.Doc.ID.In(docIDs...)).Delete(); err != nil {
|
||||
return fmt.Errorf("failed to delete docs: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := query.DocFolder.Where(query.DocFolder.ID.In(allFolderIDs...)).Delete(); err != nil {
|
||||
return fmt.Errorf("failed to delete doc folder: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// composeFolders() 用于把文件夹列表转换成树形结构
|
||||
func composeFolders(topID string, folders []*model.DocFolder) []*model.DocFolderWithChildren {
|
||||
m := make(map[string]*model.DocFolderWithChildren)
|
||||
for _, folder := range folders {
|
||||
m[folder.ID] = &model.DocFolderWithChildren{DocFolder: folder}
|
||||
}
|
||||
|
||||
results := make([]*model.DocFolderWithChildren, 0)
|
||||
for _, folder := range folders {
|
||||
parentID := folder.ParentID()
|
||||
if parentID == topID {
|
||||
results = append(results, m[folder.ID])
|
||||
continue
|
||||
}
|
||||
if parent, ok := m[parentID]; ok {
|
||||
parent.Children = append(parent.Children, m[folder.ID])
|
||||
}
|
||||
}
|
||||
return results
|
||||
}
|
||||
Reference in New Issue
Block a user