package service import ( "context" "errors" "fmt" "octopus/internal/dal" "octopus/internal/dal/model" "octopus/internal/dal/query" "octopus/internal/schema" "octopus/pkg/utils" "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 utils.Unptr(param.ParentID) == "" && 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 }