fix
This commit is contained in:
@@ -3,7 +3,6 @@ package biz
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -43,51 +42,23 @@ func NewAnnouncementUsecase(repo AnnouncementRepo) *AnnouncementUsecase {
|
||||
return &AnnouncementUsecase{repo: repo}
|
||||
}
|
||||
|
||||
func validateAnnouncement(item *Announcement) error {
|
||||
if item == nil || item.Title == "" {
|
||||
return errors.New("公告标题不能为空")
|
||||
}
|
||||
if len(item.Attachments) == 0 || !json.Valid(item.Attachments) {
|
||||
item.Attachments = json.RawMessage("[]")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (uc *AnnouncementUsecase) Create(ctx context.Context, item *Announcement) error {
|
||||
if err := validateAnnouncement(item); err != nil {
|
||||
return err
|
||||
}
|
||||
return uc.repo.Create(ctx, item)
|
||||
}
|
||||
|
||||
func (uc *AnnouncementUsecase) Update(ctx context.Context, item *Announcement) error {
|
||||
if item == nil || item.ID == 0 {
|
||||
return errors.New("公告ID不能为空")
|
||||
}
|
||||
if err := validateAnnouncement(item); err != nil {
|
||||
return err
|
||||
}
|
||||
return uc.repo.Update(ctx, item)
|
||||
}
|
||||
|
||||
func (uc *AnnouncementUsecase) Delete(ctx context.Context, id uint) error {
|
||||
if id == 0 {
|
||||
return errors.New("公告ID不能为空")
|
||||
}
|
||||
return uc.repo.Delete(ctx, id)
|
||||
}
|
||||
|
||||
func (uc *AnnouncementUsecase) DeleteByIDs(ctx context.Context, ids []uint) error {
|
||||
if len(ids) == 0 {
|
||||
return errors.New("公告ID不能为空")
|
||||
}
|
||||
return uc.repo.DeleteByIDs(ctx, ids)
|
||||
}
|
||||
|
||||
func (uc *AnnouncementUsecase) Find(ctx context.Context, id uint) (*Announcement, error) {
|
||||
if id == 0 {
|
||||
return nil, errors.New("公告ID不能为空")
|
||||
}
|
||||
return uc.repo.Find(ctx, id)
|
||||
}
|
||||
|
||||
|
||||
@@ -2,9 +2,19 @@ package biz
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrInvalidLogMonth = errors.New("日志月份格式不正确")
|
||||
ErrInvalidLogDate = errors.New("日志日期格式不正确")
|
||||
ErrInvalidLogPath = errors.New("日志文件路径不合法")
|
||||
ErrLogFileNotFound = errors.New("日志文件不存在")
|
||||
ErrLogFileUnreadable = errors.New("日志文件不可读取")
|
||||
ErrLogRootUnavailable = errors.New("日志目录不可读取")
|
||||
)
|
||||
|
||||
type OperationRecord struct {
|
||||
ID uint
|
||||
CreatedAt time.Time
|
||||
|
||||
@@ -71,16 +71,39 @@ func (uc *SettingsUsecase) ImportDictionary(ctx context.Context, dictionary *Dic
|
||||
return uc.SettingsRepo.ImportDictionary(ctx, dictionary, details)
|
||||
}
|
||||
|
||||
func (uc *SettingsUsecase) DictionaryDetailsByParent(ctx context.Context, dictionaryID, parentID uint) ([]*DictionaryDetail, error) {
|
||||
func (uc *SettingsUsecase) DictionaryDetailsByParent(ctx context.Context, dictionaryID uint, parentID *uint, includeChildren bool) ([]*DictionaryDetail, error) {
|
||||
items, _, err := uc.ListDictionaryDetails(ctx, 0, 0, DictionaryDetailFilter{DictionaryID: dictionaryID})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out := make([]*DictionaryDetail, 0)
|
||||
direct := make([]*DictionaryDetail, 0)
|
||||
for _, item := range items {
|
||||
if (parentID == 0 && item.ParentID == nil) || (item.ParentID != nil && *item.ParentID == parentID) {
|
||||
out = append(out, item)
|
||||
if (parentID == nil && item.ParentID == nil) || (parentID != nil && item.ParentID != nil && *item.ParentID == *parentID) {
|
||||
direct = append(direct, item)
|
||||
}
|
||||
}
|
||||
return out, nil
|
||||
if !includeChildren {
|
||||
return direct, nil
|
||||
}
|
||||
children := make(map[uint][]*DictionaryDetail)
|
||||
for _, item := range items {
|
||||
item.Children = []*DictionaryDetail{}
|
||||
if item.ParentID != nil {
|
||||
children[*item.ParentID] = append(children[*item.ParentID], item)
|
||||
}
|
||||
}
|
||||
var attach func(*DictionaryDetail)
|
||||
attach = func(item *DictionaryDetail) {
|
||||
item.Children = children[item.ID]
|
||||
if item.Children == nil {
|
||||
item.Children = []*DictionaryDetail{}
|
||||
}
|
||||
for _, child := range item.Children {
|
||||
attach(child)
|
||||
}
|
||||
}
|
||||
for _, item := range direct {
|
||||
attach(item)
|
||||
}
|
||||
return direct, nil
|
||||
}
|
||||
|
||||
@@ -22,12 +22,12 @@ func (uc *MediaUsecase) InitUpload(ctx context.Context, userID uint, name, hash
|
||||
if size <= 0 || chunkSize <= 0 || total <= 0 {
|
||||
return nil, nil, nil, errors.New("上传参数不合法")
|
||||
}
|
||||
if media, err := uc.FindMediaByHash(ctx, userID, hash); err == nil {
|
||||
copy := *media
|
||||
copy.ID = 0
|
||||
copy.Name = name
|
||||
if err = uc.CreateMedia(ctx, ©); err == nil {
|
||||
return nil, ©, nil, nil
|
||||
if completed, err := uc.FindCompletedSession(ctx, userID, hash); err == nil && completed.MediaID != 0 {
|
||||
if media, findErr := uc.FindMedia(ctx, completed.MediaID); findErr == nil {
|
||||
copy := &MediaFile{Name: name, URL: media.URL, Tag: media.Tag, Key: media.Key}
|
||||
if createErr := uc.CreateMedia(ctx, copy); createErr == nil {
|
||||
return nil, copy, nil, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
session, err := uc.FindUploadingSession(ctx, userID, hash)
|
||||
@@ -53,8 +53,8 @@ func (uc *MediaUsecase) SaveChunk(ctx context.Context, userID, uploadID uint, in
|
||||
if err != nil || session.UserID != userID {
|
||||
return errors.New("上传会话不存在或无权操作")
|
||||
}
|
||||
if session.Status != "uploading" || index < 0 || index >= session.ChunkTotal {
|
||||
return errors.New("上传会话状态或分片序号不合法")
|
||||
if session.Status != "uploading" {
|
||||
return errors.New("上传会话状态不允许收片")
|
||||
}
|
||||
hash := md5.New()
|
||||
key := fmt.Sprintf(".chunks/%d/%08d", uploadID, index)
|
||||
@@ -63,9 +63,9 @@ func (uc *MediaUsecase) SaveChunk(ctx context.Context, userID, uploadID uint, in
|
||||
return err
|
||||
}
|
||||
actual := hex.EncodeToString(hash.Sum(nil))
|
||||
if !strings.EqualFold(actual, expected) {
|
||||
if actual != expected {
|
||||
_ = uc.files.Delete(ctx, key)
|
||||
return errors.New("分片校验失败")
|
||||
return fmt.Errorf("分片 %d 校验失败", index)
|
||||
}
|
||||
return uc.UpsertChunk(ctx, uploadID, &UploadChunk{Index: index, Hash: actual, Size: stored.Size})
|
||||
}
|
||||
@@ -74,15 +74,26 @@ func (uc *MediaUsecase) CompleteUpload(ctx context.Context, userID, uploadID uin
|
||||
if err != nil || session.UserID != userID {
|
||||
return nil, errors.New("上传会话不存在或无权操作")
|
||||
}
|
||||
claimed, err := uc.ClaimUploadSession(ctx, uploadID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !claimed {
|
||||
return nil, errors.New("上传不在可合并状态(可能已在合并或已完成)")
|
||||
}
|
||||
fail := func(value error) (*MediaFile, error) {
|
||||
_ = uc.FailUploadSession(ctx, uploadID)
|
||||
return nil, value
|
||||
}
|
||||
chunks, err := uc.ListChunks(ctx, uploadID)
|
||||
if err != nil || len(chunks) != session.ChunkTotal {
|
||||
return nil, errors.New("分片不完整")
|
||||
return fail(fmt.Errorf("分片不全: %d/%d", len(chunks), session.ChunkTotal))
|
||||
}
|
||||
sort.Slice(chunks, func(i, j int) bool { return chunks[i].Index < chunks[j].Index })
|
||||
names := make([]string, 0, len(chunks))
|
||||
for index, chunk := range chunks {
|
||||
if chunk.Index != index {
|
||||
return nil, errors.New("分片序号不连续")
|
||||
return fail(errors.New("分片序号不连续"))
|
||||
}
|
||||
names = append(names, fmt.Sprintf(".chunks/%d/%08d", uploadID, index))
|
||||
}
|
||||
@@ -90,16 +101,16 @@ func (uc *MediaUsecase) CompleteUpload(ctx context.Context, userID, uploadID uin
|
||||
key := time.Now().Format("20060102") + "/" + uuid.NewString() + ext
|
||||
stored, hash, err := uc.files.Compose(ctx, names, key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return fail(err)
|
||||
}
|
||||
if !strings.EqualFold(hash, session.FileHash) {
|
||||
if hash != session.FileHash {
|
||||
_ = uc.files.Delete(ctx, key)
|
||||
return nil, errors.New("整文件校验失败")
|
||||
return fail(errors.New("整文件校验失败"))
|
||||
}
|
||||
media := &MediaFile{Name: session.FileName, URL: stored.URL, Tag: strings.TrimPrefix(ext, "."), Key: key, Size: stored.Size, Mime: mime, MD5: hash, UserID: userID}
|
||||
if err = uc.CreateMedia(ctx, media); err != nil {
|
||||
_ = uc.files.Delete(ctx, key)
|
||||
return nil, err
|
||||
return fail(err)
|
||||
}
|
||||
_ = uc.CompleteUploadSession(ctx, uploadID, key, media.ID)
|
||||
_ = uc.DeleteChunks(ctx, uploadID)
|
||||
|
||||
@@ -22,9 +22,12 @@ type UploadChunk struct {
|
||||
}
|
||||
|
||||
type UploadRepo interface {
|
||||
FindCompletedSession(context.Context, uint, string) (*UploadSession, error)
|
||||
FindUploadingSession(context.Context, uint, string) (*UploadSession, error)
|
||||
CreateUploadSession(context.Context, *UploadSession) error
|
||||
FindUploadSession(context.Context, uint) (*UploadSession, error)
|
||||
ClaimUploadSession(context.Context, uint) (bool, error)
|
||||
FailUploadSession(context.Context, uint) error
|
||||
CompleteUploadSession(context.Context, uint, string, uint) error
|
||||
DeleteUploadSession(context.Context, uint) error
|
||||
UpsertChunk(context.Context, uint, *UploadChunk) error
|
||||
|
||||
Reference in New Issue
Block a user