feat(api): test doc upload

This commit is contained in:
neo-f 2023-03-23 22:28:17 +08:00
parent 6851fe95a0
commit 2d3cf0857a
7 changed files with 45 additions and 47 deletions

View File

@ -3,7 +3,7 @@ http_port: 8080
prometheus_port: 18090
host: http://localhost:8080
databases:
storage: minio://admin:uh8Cz62LKFDe9tBHg2PVyDVX7XKqE584xP@10.16.129.140:31141/pangu2-demo
storage: minio://admin:uh8Cz62LKFDe9tBHg2PVyDVX7XKqE584xP@10.16.129.140:31141?bucket=pangu2-demo
postgresql: postgres://postgres:TvpHKxDhXzMsVkXWdzwiwUw9KmaLuGdRJo@10.16.129.140:31258/octopus
qdrant: 10.16.129.104:32352
casdoor:

View File

@ -34,10 +34,11 @@ func (f *DocFolder) ParentID() string {
return parts[len(parts)-1]
}
func (df *DocFolder) ToSchema() *schema.DocFolder {
func (df DocFolder) ToSchema() *schema.DocFolder {
return &schema.DocFolder{
ID: df.ID,
Name: df.Name,
IsDefault: df.IsDefault,
CreatedAt: df.CreatedAt,
UpdatedAt: df.UpdatedAt,
}
@ -89,7 +90,7 @@ func (d *Doc) ToSchema(ctx context.Context) *schema.Doc {
return &schema.Doc{
ID: d.ID,
Folder: d.Folder.ToSchema(),
PresignedURL: url,
PresignedURL: url.String(),
UploadedAt: d.UploadedAt,
CreatedAt: d.CreatedAt,
UpdatedAt: d.UpdatedAt,

View File

@ -34,13 +34,13 @@ func RegisterDocRouter(app *soda.Soda) {
AddJWTSecurity(JWTRequired).
SetParameters(schema.DocID{}).
AddJSONResponse(200, nil).OK()
app.Post("/docs/batch/delete", DeleteDoc).
app.Post("/docs/batch/delete", DeleteDocBatch).
AddTags("文档管理").
SetSummary("批量-文件删除").
AddJWTSecurity(JWTRequired).
SetJSONRequestBody(schema.DocsBatchDelete{}).
AddJSONResponse(200, schema.DocBatchResults{}).OK()
app.Post("/docs/batch/update", UpdateDoc).
app.Post("/docs/batch/update", UpdateDocBatch).
AddTags("文档管理").
SetSummary("批量-文件更新").
AddJWTSecurity(JWTRequired).
@ -132,7 +132,7 @@ func CreateUploadURL(c *fiber.Ctx) error {
}
return c.JSON(schema.UploadURL{
URL: *u,
URL: u.String(),
ObjectName: objectName,
})
}

View File

@ -1,13 +1,13 @@
package schema
import (
"net/url"
"time"
)
type DocFolder struct {
ID string `json:"id" oai:"description=文件夹ID"`
Name string `json:"name" oai:"description=文件夹名称"`
IsDefault bool `json:"is_default,omitempty" oai:"description=是否默认分组"`
CreatedAt time.Time `json:"created_at" oai:"description=创建时间"`
UpdatedAt time.Time `json:"updated_at" oai:"description=更新时间"`
}
@ -38,7 +38,7 @@ type DocFolderWithChildren struct {
type Doc struct {
ID string `json:"id" oai:"description=文档ID"`
Folder *DocFolder `json:"folder" oai:"description=归属文件夹信息"`
PresignedURL *url.URL `json:"presigned_url" oai:"description=文档预签名下载URL(临时下载URL)"`
PresignedURL string `json:"presigned_url" oai:"description=文档预签名下载URL(临时下载URL)"`
UploadedAt time.Time `json:"uploaded_at" oai:"description=上传时间"`
CreatedAt time.Time `json:"created_at" oai:"description=创建时间"`
UpdatedAt time.Time `json:"updated_at" oai:"description=更新时间"`
@ -76,7 +76,7 @@ type DocsBatchDelete struct {
type DocsBatchUpdate struct {
IDs []string `json:"ids" validate:"required" oai:"description=批量选择文件ID列表"`
FolderID string `json:"folder_id" validate:"required" oai:"description=更新归属文件夹ID"`
FolderID *string `json:"folder_id" oai:"description=更新归属文件夹ID"`
}
type DocBatchResult struct {
@ -92,6 +92,6 @@ type CreateUploadURL struct {
}
type UploadURL struct {
URL url.URL `json:"url" oai:"description=生成的预签名上传URL"`
URL string `json:"url" oai:"description=生成的预签名上传URL"`
ObjectName string `json:"object_name" oai:"description=上传文件名"`
}

View File

@ -9,7 +9,6 @@ import (
"octopus/internal/dal/model"
"octopus/internal/dal/query"
"octopus/internal/schema"
"strings"
"time"
"github.com/casdoor/casdoor-go-sdk/casdoorsdk"
@ -19,7 +18,9 @@ import (
)
func ListDocs(ctx context.Context, auth *casdoorsdk.User, param *schema.ListDocQuery) ([]*model.Doc, int64, error) {
base := query.Doc.Where(query.Doc.OrgID.Eq(auth.Owner))
base := query.Doc.
Where(query.Doc.OrgID.Eq(auth.Owner)).
Preload(query.Doc.Folder)
if param.FolderIDs != nil {
base = base.Where(query.Doc.FolderID.In(*param.FolderIDs...))
}
@ -47,8 +48,8 @@ func CreateDoc(ctx context.Context, auth *casdoorsdk.User, param *schema.CreateD
}
// 将对象从临时地址移动到新地址
newPath := fmt.Sprintf("%s/%s/%s", auth.Owner, folder.ParentPath, param.Name)
if err := storage.MoveObject(ctx, param.ObjectName, newPath); err != nil {
newObjectName := fmt.Sprintf("%s/%s/%s", auth.Owner, time.Now().UTC().Format(time.DateOnly), param.Name)
if err := storage.MoveObject(ctx, param.ObjectName, newObjectName); err != nil {
return nil, fmt.Errorf("failed to move object: %w", err)
}
@ -58,9 +59,10 @@ func CreateDoc(ctx context.Context, auth *casdoorsdk.User, param *schema.CreateD
IsDeletable: true,
IsEditable: true,
FolderID: param.FolderID,
ObjectName: newPath,
ObjectName: newObjectName,
UploadedAt: stat.LastModified,
CreatedBy: auth.Id,
Folder: folder,
}
if err := query.Doc.Create(&doc); err != nil {
return nil, fmt.Errorf("failed to create doc: %w", err)
@ -69,7 +71,13 @@ func CreateDoc(ctx context.Context, auth *casdoorsdk.User, param *schema.CreateD
}
func GetDoc(ctx context.Context, auth *casdoorsdk.User, id string) (*model.Doc, error) {
doc, err := query.Doc.Where(query.Doc.OrgID.Eq(auth.Owner), query.Doc.ID.Eq(id)).Take()
doc, err := query.Doc.
Where(
query.Doc.OrgID.Eq(auth.Owner),
query.Doc.ID.Eq(id),
).
Preload(query.Doc.Folder).
Take()
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, fmt.Errorf("specified doc not exists")
}
@ -80,8 +88,7 @@ func GetDoc(ctx context.Context, auth *casdoorsdk.User, id string) (*model.Doc,
}
func UpdateDoc(ctx context.Context, auth *casdoorsdk.User, id string, body *schema.UpdateDoc) (*model.Doc, error) {
doc, err := GetDoc(ctx, auth, id)
if err != nil {
if _, err := GetDoc(ctx, auth, id); err != nil {
return nil, fmt.Errorf("failed to get doc: %w", err)
}
@ -94,15 +101,6 @@ func UpdateDoc(ctx context.Context, auth *casdoorsdk.User, id string, body *sche
if _, err := GetDocFolder(ctx, auth, *body.FolderID); err != nil {
return nil, fmt.Errorf("failed to get doc folder: %w", err)
}
// 将对象从临时地址移动到新地址
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))
}
@ -145,7 +143,7 @@ func UpdateDocBatch(ctx context.Context, auth *casdoorsdk.User, param *schema.Do
results := make(schema.DocBatchResults, 0, len(param.IDs))
// NOTE: 后面应该需要优化一下
for _, docID := range param.IDs {
_, err := UpdateDoc(ctx, auth, docID, &schema.UpdateDoc{FolderID: &param.FolderID})
_, err := UpdateDoc(ctx, auth, docID, &schema.UpdateDoc{FolderID: param.FolderID})
if err != nil {
results = append(results, schema.DocBatchResult{ID: docID, Success: false, Error: err.Error()})
} else {
@ -156,7 +154,7 @@ func UpdateDocBatch(ctx context.Context, auth *casdoorsdk.User, param *schema.Do
}
func CreateUploadURL(ctx context.Context, auth *casdoorsdk.User, param *schema.CreateUploadURL) (u *url.URL, objectName string, err error) {
tmpObjectName := fmt.Sprintf("/tmp/%s/%s-%s", auth.Owner, param.FileName, xid.New())
tmpObjectName := fmt.Sprintf("/tmp/%s/%s-%s", auth.Owner, xid.New(), param.FileName)
u, err = dal.GetStorage().PresignedPutObject(ctx, tmpObjectName, time.Hour)
if err != nil {
return nil, "", fmt.Errorf("failed to create presigned url: %w", err)

View File

@ -8,6 +8,7 @@ import (
"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"
@ -38,7 +39,7 @@ func GetDocFolderTree(ctx context.Context, auth *casdoorsdk.User, param *schema.
}
// 如果没有的话,就创建一个默认的分组
if len(folders) == 0 {
if utils.Unptr(param.ParentID) == "" && len(folders) == 0 {
folder := model.DocFolder{
Base: model.Base{OrgID: auth.Owner},
Name: "默认分组",
@ -132,9 +133,9 @@ func DeleteDocFolder(ctx context.Context, auth *casdoorsdk.User, id string) erro
if err != nil {
return fmt.Errorf("failed to get doc folder: %w", err)
}
if folder.IsDefault {
return fmt.Errorf("cannot delete the default folder")
}
// 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)

View File

@ -86,16 +86,14 @@ func (m *StorageMinio) DeleteObject(ctx context.Context, objectName string) (err
// MoveObject implements ObjectStorage
func (m *StorageMinio) DeleteObjects(ctx context.Context, objectNames []string) []minio.RemoveObjectError {
objs := make(chan minio.ObjectInfo, len(objectNames))
for _, objectName := range objectNames {
objs <- minio.ObjectInfo{Key: objectName}
}
errCh := m.client.RemoveObjects(ctx, m.bucket, objs, minio.RemoveObjectsOptions{})
// FIXME: why does DeleteObjects not working??
var errors []minio.RemoveObjectError
for err := range errCh {
if err.Err != nil {
errors = append(errors, err)
for _, objectName := range objectNames {
if err := m.DeleteObject(ctx, objectName); err != nil {
errors = append(errors, minio.RemoveObjectError{
ObjectName: objectName,
Err: err,
})
}
}
return errors