migrate from github
This commit is contained in:
@@ -0,0 +1,198 @@
|
||||
package document_service
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"mime"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/XingfenD/yoresee_doc/internal/config"
|
||||
"github.com/XingfenD/yoresee_doc/internal/dto"
|
||||
"github.com/XingfenD/yoresee_doc/internal/model"
|
||||
"github.com/XingfenD/yoresee_doc/internal/status"
|
||||
"github.com/XingfenD/yoresee_doc/internal/utils"
|
||||
"github.com/XingfenD/yoresee_doc/pkg/storage"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const maxAttachmentSize = 5 * 1024 * 1024
|
||||
|
||||
func (s *DocumentService) UploadAttachment(
|
||||
ctx context.Context,
|
||||
userExternalID string,
|
||||
documentExternalID string,
|
||||
file []byte,
|
||||
fileName string,
|
||||
contentType string,
|
||||
) (*dto.AttachmentResponse, error) {
|
||||
if s == nil || strings.TrimSpace(userExternalID) == "" || strings.TrimSpace(documentExternalID) == "" {
|
||||
return nil, status.GenErrWithCustomMsg(status.StatusParamError, "invalid upload attachment request")
|
||||
}
|
||||
if len(file) == 0 || len(file) > maxAttachmentSize {
|
||||
return nil, status.GenErrWithCustomMsg(status.StatusParamError, "invalid attachment file")
|
||||
}
|
||||
if config.GlobalConfig == nil || strings.TrimSpace(config.GlobalConfig.Minio.Bucket) == "" {
|
||||
return nil, status.GenErrWithCustomMsg(status.StatusServiceInternalError, "attachment storage is not configured")
|
||||
}
|
||||
|
||||
documentID, err := s.documentRepo.GetIDByExternalID(documentExternalID).Exec(ctx)
|
||||
if err != nil {
|
||||
logrus.Errorf("[Service layer: DocumentService] query document id failed, document_external_id=%s, err=%+v", documentExternalID, err)
|
||||
return nil, status.GenErrWithCustomMsg(status.StatusReadDBError, "query document failed")
|
||||
}
|
||||
if documentID <= 0 {
|
||||
return nil, status.GenErrWithCustomMsg(status.StatusDocumentNotFound, "document not found")
|
||||
}
|
||||
|
||||
userID, err := s.userRepo.GetIDByExternalID(userExternalID).Exec()
|
||||
if err != nil || userID <= 0 {
|
||||
logrus.Errorf("[Service layer: DocumentService] query user id failed, user_external_id=%s, err=%+v", userExternalID, err)
|
||||
return nil, status.GenErrWithCustomMsg(status.StatusUserNotFound, "user not found")
|
||||
}
|
||||
|
||||
safeName := strings.TrimSpace(fileName)
|
||||
if safeName == "" {
|
||||
safeName = "attachment.bin"
|
||||
}
|
||||
contentType = strings.TrimSpace(contentType)
|
||||
if contentType == "" {
|
||||
contentType = http.DetectContentType(file)
|
||||
}
|
||||
|
||||
attachmentExternalID := utils.GenerateExternalID(utils.ExternalIDContextAttachment)
|
||||
objectName := fmt.Sprintf(
|
||||
"attachments/%s/%s-%d%s",
|
||||
documentExternalID,
|
||||
attachmentExternalID,
|
||||
time.Now().UnixNano(),
|
||||
resolveAttachmentExt(safeName, contentType),
|
||||
)
|
||||
|
||||
err = storage.PutFile(
|
||||
config.GlobalConfig.Minio.Bucket,
|
||||
objectName,
|
||||
bytes.NewReader(file),
|
||||
int64(len(file)),
|
||||
contentType,
|
||||
)
|
||||
if err != nil {
|
||||
logrus.Errorf("[Service layer: DocumentService] upload attachment to minio failed, document_external_id=%s, object_name=%s, err=%+v", documentExternalID, objectName, err)
|
||||
return nil, status.GenErrWithCustomMsg(status.StatusServiceInternalError, "upload attachment failed")
|
||||
}
|
||||
|
||||
attachment := &model.Attachment{
|
||||
ExternalID: attachmentExternalID,
|
||||
DocumentID: documentID,
|
||||
Name: safeName,
|
||||
Path: objectName,
|
||||
Size: int64(len(file)),
|
||||
MimeType: contentType,
|
||||
UserID: userID,
|
||||
}
|
||||
if err = s.attachmentRepo.Create(attachment); err != nil {
|
||||
logrus.Errorf("[Service layer: DocumentService] save attachment meta failed, document_external_id=%s, attachment_external_id=%s, err=%+v", documentExternalID, attachmentExternalID, err)
|
||||
return nil, status.GenErrWithCustomMsg(status.StatusWriteDBError, "save attachment failed")
|
||||
}
|
||||
|
||||
return &dto.AttachmentResponse{
|
||||
ExternalID: attachment.ExternalID,
|
||||
DocumentExternalID: documentExternalID,
|
||||
Name: attachment.Name,
|
||||
Size: attachment.Size,
|
||||
MimeType: attachment.MimeType,
|
||||
Path: attachment.Path,
|
||||
URL: storage.BuildPublicObjectPath(attachment.Path),
|
||||
CreatedAt: attachment.CreatedAt,
|
||||
UpdatedAt: attachment.UpdatedAt,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *DocumentService) ListAttachments(ctx context.Context, documentExternalID string) ([]*dto.AttachmentResponse, error) {
|
||||
if s == nil || strings.TrimSpace(documentExternalID) == "" {
|
||||
return nil, status.GenErrWithCustomMsg(status.StatusParamError, "invalid list attachments request")
|
||||
}
|
||||
if config.GlobalConfig == nil || strings.TrimSpace(config.GlobalConfig.Minio.Bucket) == "" {
|
||||
return nil, status.GenErrWithCustomMsg(status.StatusServiceInternalError, "attachment storage is not configured")
|
||||
}
|
||||
|
||||
documentID, err := s.documentRepo.GetIDByExternalID(documentExternalID).Exec(ctx)
|
||||
if err != nil {
|
||||
logrus.Errorf("[Service layer: DocumentService] query document id failed, document_external_id=%s, err=%+v", documentExternalID, err)
|
||||
return nil, status.GenErrWithCustomMsg(status.StatusReadDBError, "query document failed")
|
||||
}
|
||||
if documentID <= 0 {
|
||||
return nil, status.GenErrWithCustomMsg(status.StatusDocumentNotFound, "document not found")
|
||||
}
|
||||
|
||||
attachments, err := s.attachmentRepo.ListByDocumentID(documentID)
|
||||
if err != nil {
|
||||
logrus.Errorf("[Service layer: DocumentService] list attachments failed, document_external_id=%s, document_id=%d, err=%+v", documentExternalID, documentID, err)
|
||||
return nil, status.GenErrWithCustomMsg(status.StatusReadDBError, "list attachments failed")
|
||||
}
|
||||
|
||||
resp := make([]*dto.AttachmentResponse, 0, len(attachments))
|
||||
for _, attachment := range attachments {
|
||||
resp = append(resp, &dto.AttachmentResponse{
|
||||
ExternalID: attachment.ExternalID,
|
||||
DocumentExternalID: documentExternalID,
|
||||
Name: attachment.Name,
|
||||
Size: attachment.Size,
|
||||
MimeType: attachment.MimeType,
|
||||
Path: attachment.Path,
|
||||
URL: storage.BuildPublicObjectPath(attachment.Path),
|
||||
CreatedAt: attachment.CreatedAt,
|
||||
UpdatedAt: attachment.UpdatedAt,
|
||||
})
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (s *DocumentService) DeleteAttachment(ctx context.Context, documentExternalID, attachmentExternalID string) error {
|
||||
if s == nil || strings.TrimSpace(documentExternalID) == "" || strings.TrimSpace(attachmentExternalID) == "" {
|
||||
return status.GenErrWithCustomMsg(status.StatusParamError, "invalid delete attachment request")
|
||||
}
|
||||
if config.GlobalConfig == nil || strings.TrimSpace(config.GlobalConfig.Minio.Bucket) == "" {
|
||||
return status.GenErrWithCustomMsg(status.StatusServiceInternalError, "attachment storage is not configured")
|
||||
}
|
||||
|
||||
documentID, err := s.documentRepo.GetIDByExternalID(documentExternalID).Exec(ctx)
|
||||
if err != nil {
|
||||
logrus.Errorf("[Service layer: DocumentService] query document id failed, document_external_id=%s, err=%+v", documentExternalID, err)
|
||||
return status.GenErrWithCustomMsg(status.StatusReadDBError, "query document failed")
|
||||
}
|
||||
if documentID <= 0 {
|
||||
return status.GenErrWithCustomMsg(status.StatusDocumentNotFound, "document not found")
|
||||
}
|
||||
|
||||
attachment, err := s.attachmentRepo.GetByExternalIDAndDocumentID(attachmentExternalID, documentID)
|
||||
if err != nil {
|
||||
logrus.Errorf("[Service layer: DocumentService] query attachment failed, document_external_id=%s, attachment_external_id=%s, err=%+v", documentExternalID, attachmentExternalID, err)
|
||||
return status.GenErrWithCustomMsg(status.StatusDocumentNotFound, "attachment not found")
|
||||
}
|
||||
|
||||
if err = storage.DeleteFile(config.GlobalConfig.Minio.Bucket, attachment.Path); err != nil {
|
||||
logrus.Errorf("[Service layer: DocumentService] delete attachment object failed, attachment_external_id=%s, path=%s, err=%+v", attachmentExternalID, attachment.Path, err)
|
||||
return status.GenErrWithCustomMsg(status.StatusServiceInternalError, "delete attachment failed")
|
||||
}
|
||||
if err = s.attachmentRepo.DeleteByID(attachment.ID); err != nil {
|
||||
logrus.Errorf("[Service layer: DocumentService] delete attachment meta failed, attachment_external_id=%s, err=%+v", attachmentExternalID, err)
|
||||
return status.GenErrWithCustomMsg(status.StatusWriteDBError, "delete attachment failed")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func resolveAttachmentExt(filename, contentType string) string {
|
||||
ext := strings.TrimSpace(strings.ToLower(filepath.Ext(filename)))
|
||||
if ext != "" {
|
||||
return ext
|
||||
}
|
||||
exts, err := mime.ExtensionsByType(contentType)
|
||||
if err == nil && len(exts) > 0 {
|
||||
return exts[0]
|
||||
}
|
||||
return ".bin"
|
||||
}
|
||||
Reference in New Issue
Block a user