fix
This commit is contained in:
@@ -29,19 +29,11 @@ type announcementRepo struct{ data *Data }
|
||||
func NewAnnouncementRepo(data *Data) biz.AnnouncementRepo { return &announcementRepo{data: data} }
|
||||
|
||||
func newAnnouncement(item *biz.Announcement) announcementPO {
|
||||
attachments := []byte(item.Attachments)
|
||||
if len(attachments) == 0 || !json.Valid(attachments) {
|
||||
attachments = []byte("[]")
|
||||
}
|
||||
return announcementPO{ID: item.ID, Title: item.Title, Content: item.Content, UserID: item.UserID, Attachments: jsonPO(attachments)}
|
||||
return announcementPO{ID: item.ID, Title: item.Title, Content: item.Content, UserID: item.UserID, Attachments: jsonPO(item.Attachments)}
|
||||
}
|
||||
|
||||
func announcementToBiz(item announcementPO) *biz.Announcement {
|
||||
attachments := json.RawMessage(item.Attachments)
|
||||
if len(attachments) == 0 || !json.Valid(attachments) {
|
||||
attachments = json.RawMessage("[]")
|
||||
}
|
||||
return &biz.Announcement{ID: item.ID, CreatedAt: item.CreatedAt, UpdatedAt: item.UpdatedAt, Title: item.Title, Content: item.Content, UserID: item.UserID, Attachments: attachments}
|
||||
return &biz.Announcement{ID: item.ID, CreatedAt: item.CreatedAt, UpdatedAt: item.UpdatedAt, Title: item.Title, Content: item.Content, UserID: item.UserID, Attachments: json.RawMessage(item.Attachments)}
|
||||
}
|
||||
|
||||
func (r *announcementRepo) Create(ctx context.Context, item *biz.Announcement) error {
|
||||
@@ -63,16 +55,7 @@ func (r *announcementRepo) DeleteByIDs(ctx context.Context, ids []uint) error {
|
||||
|
||||
func (r *announcementRepo) Update(ctx context.Context, item *biz.Announcement) error {
|
||||
po := newAnnouncement(item)
|
||||
result := r.data.gormDB.WithContext(ctx).Model(&announcementPO{}).Where("id = ?", item.ID).Updates(map[string]any{
|
||||
"title": po.Title, "content": po.Content, "user_id": po.UserID, "attachments": po.Attachments,
|
||||
})
|
||||
if result.Error != nil {
|
||||
return result.Error
|
||||
}
|
||||
if result.RowsAffected == 0 {
|
||||
return gorm.ErrRecordNotFound
|
||||
}
|
||||
return nil
|
||||
return r.data.gormDB.WithContext(ctx).Model(&announcementPO{}).Where("id = ?", item.ID).Updates(&po).Error
|
||||
}
|
||||
|
||||
func (r *announcementRepo) Find(ctx context.Context, id uint) (*biz.Announcement, error) {
|
||||
|
||||
+23
-1
@@ -46,6 +46,13 @@ func apiFromPO(po apiPO) *biz.API {
|
||||
}
|
||||
func (r *accessRepo) CreateAPI(ctx context.Context, v *biz.API) error {
|
||||
po := apiPO{Path: v.Path, Description: v.Description, APIGroup: v.APIGroup, Method: strings.ToUpper(v.Method)}
|
||||
var count int64
|
||||
if err := r.data.gormDB.WithContext(ctx).Model(&apiPO{}).Where("path = ? AND method = ?", po.Path, po.Method).Count(&count).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if count > 0 {
|
||||
return errors.New("存在相同api")
|
||||
}
|
||||
if err := r.data.gormDB.WithContext(ctx).Create(&po).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -53,7 +60,22 @@ func (r *accessRepo) CreateAPI(ctx context.Context, v *biz.API) error {
|
||||
return nil
|
||||
}
|
||||
func (r *accessRepo) UpdateAPI(ctx context.Context, v *biz.API) error {
|
||||
return r.data.gormDB.WithContext(ctx).Model(&apiPO{}).Where("id = ?", v.ID).Updates(map[string]any{"path": v.Path, "description": v.Description, "api_group": v.APIGroup, "method": strings.ToUpper(v.Method)}).Error
|
||||
db := r.data.gormDB.WithContext(ctx)
|
||||
var old apiPO
|
||||
if err := db.First(&old, v.ID).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
method := strings.ToUpper(v.Method)
|
||||
if old.Path != v.Path || old.Method != method {
|
||||
var count int64
|
||||
if err := db.Model(&apiPO{}).Where("id <> ? AND path = ? AND method = ?", v.ID, v.Path, method).Count(&count).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if count > 0 {
|
||||
return errors.New("存在相同api路径")
|
||||
}
|
||||
}
|
||||
return db.Model(&old).Updates(map[string]any{"path": v.Path, "description": v.Description, "api_group": v.APIGroup, "method": method}).Error
|
||||
}
|
||||
func (r *accessRepo) DeleteAPIs(ctx context.Context, ids []uint) error {
|
||||
return r.data.gormDB.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||
|
||||
+29
-18
@@ -14,28 +14,32 @@ import (
|
||||
"kra/internal/biz"
|
||||
)
|
||||
|
||||
func logRoot() (string, error) {
|
||||
root, err := filepath.Abs("logs")
|
||||
func (r *auditRepo) logRoot() (string, error) {
|
||||
admin := r.data.runtime.Admin()
|
||||
if admin == nil || admin.Zap == nil || strings.TrimSpace(admin.Zap.Director) == "" {
|
||||
return "", biz.ErrLogRootUnavailable
|
||||
}
|
||||
root, err := filepath.Abs(admin.Zap.Director)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", errors.Join(biz.ErrLogRootUnavailable, err)
|
||||
}
|
||||
info, err := os.Stat(root)
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
return root, nil
|
||||
}
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", errors.Join(biz.ErrLogRootUnavailable, err)
|
||||
}
|
||||
if !info.IsDir() {
|
||||
return "", errors.New("日志路径不是目录")
|
||||
return "", biz.ErrLogRootUnavailable
|
||||
}
|
||||
return root, nil
|
||||
}
|
||||
func (r *auditRepo) LogDates(ctx context.Context, month string) ([]biz.LogDate, error) {
|
||||
if parsed, err := time.Parse("2006-01", month); err != nil || parsed.Format("2006-01") != month {
|
||||
return nil, errors.New("日志月份格式不正确")
|
||||
return nil, biz.ErrInvalidLogMonth
|
||||
}
|
||||
root, err := logRoot()
|
||||
root, err := r.logRoot()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -73,9 +77,9 @@ func (r *auditRepo) LogDates(ctx context.Context, month string) ([]biz.LogDate,
|
||||
}
|
||||
func (r *auditRepo) LogFiles(ctx context.Context, date string) ([]biz.LogFile, error) {
|
||||
if parsed, err := time.Parse("2006-01-02", date); err != nil || parsed.Format("2006-01-02") != date {
|
||||
return nil, errors.New("日志日期格式不正确")
|
||||
return nil, biz.ErrInvalidLogDate
|
||||
}
|
||||
root, err := logRoot()
|
||||
root, err := r.logRoot()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -112,24 +116,27 @@ func (r *auditRepo) LogFiles(ctx context.Context, date string) ([]biz.LogFile, e
|
||||
return out, err
|
||||
}
|
||||
func (r *auditRepo) LogContent(ctx context.Context, date, path string, cursor *int64) (*biz.LogContent, error) {
|
||||
if _, err := time.Parse("2006-01-02", date); err != nil {
|
||||
return nil, errors.New("日志日期格式不正确")
|
||||
if parsed, err := time.Parse("2006-01-02", date); err != nil || parsed.Format("2006-01-02") != date {
|
||||
return nil, biz.ErrInvalidLogDate
|
||||
}
|
||||
root, err := logRoot()
|
||||
root, err := r.logRoot()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dateRoot := filepath.Join(root, date)
|
||||
target := filepath.Clean(filepath.Join(dateRoot, filepath.FromSlash(path)))
|
||||
if target == dateRoot || !strings.HasPrefix(target, dateRoot+string(os.PathSeparator)) || !strings.EqualFold(filepath.Ext(target), ".log") {
|
||||
return nil, errors.New("日志文件路径不合法")
|
||||
return nil, biz.ErrInvalidLogPath
|
||||
}
|
||||
info, err := os.Lstat(target)
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
return nil, biz.ErrLogFileNotFound
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Join(biz.ErrLogFileUnreadable, err)
|
||||
}
|
||||
if info.Mode()&os.ModeSymlink != 0 || !info.Mode().IsRegular() {
|
||||
return nil, errors.New("日志文件路径不合法")
|
||||
return nil, biz.ErrInvalidLogPath
|
||||
}
|
||||
end := info.Size()
|
||||
if cursor != nil && *cursor >= 0 && *cursor < end {
|
||||
@@ -142,13 +149,13 @@ func (r *auditRepo) LogContent(ctx context.Context, date, path string, cursor *i
|
||||
}
|
||||
file, err := os.Open(target)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Join(biz.ErrLogFileUnreadable, err)
|
||||
}
|
||||
defer file.Close()
|
||||
data := make([]byte, end-start)
|
||||
n, err := file.ReadAt(data, start)
|
||||
if err != nil && n == 0 {
|
||||
return nil, err
|
||||
return nil, errors.Join(biz.ErrLogFileUnreadable, err)
|
||||
}
|
||||
data = data[:n]
|
||||
lines := bytes.Split(data, []byte("\n"))
|
||||
@@ -162,5 +169,9 @@ func (r *auditRepo) LogContent(ctx context.Context, date, path string, cursor *i
|
||||
data = data[offset:]
|
||||
limited = true
|
||||
}
|
||||
return &biz.LogContent{Date: date, Path: path, Content: string(data), LineCount: bytes.Count(data, []byte("\n")), NextCursor: start, HasMore: start > 0, LimitedByBytes: limited, Size: info.Size(), ModifiedAt: info.ModTime()}, nil
|
||||
lineCount := bytes.Count(data, []byte("\n"))
|
||||
if len(data) > 0 && data[len(data)-1] != '\n' {
|
||||
lineCount++
|
||||
}
|
||||
return &biz.LogContent{Date: date, Path: path, Content: string(data), LineCount: lineCount, NextCursor: start, HasMore: start > 0, LimitedByBytes: limited, Size: info.Size(), ModifiedAt: info.ModTime()}, nil
|
||||
}
|
||||
|
||||
@@ -44,6 +44,13 @@ func (uploadChunkPO) TableName() string { return "media_upload_chunks" }
|
||||
func uploadFromPO(v uploadSessionPO) *biz.UploadSession {
|
||||
return &biz.UploadSession{ID: v.ID, UserID: v.UserID, FileName: v.FileName, FileHash: v.FileHash, FileSize: v.FileSize, ChunkSize: v.ChunkSize, ChunkTotal: v.ChunkTotal, Status: v.Status, StorageKey: v.StorageKey, MediaID: v.MediaID}
|
||||
}
|
||||
func (r *mediaRepo) FindCompletedSession(ctx context.Context, userID uint, hash string) (*biz.UploadSession, error) {
|
||||
var po uploadSessionPO
|
||||
if err := r.data.gormDB.WithContext(ctx).Where("user_id = ? AND file_hash = ? AND status = ?", userID, hash, "completed").First(&po).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return uploadFromPO(po), nil
|
||||
}
|
||||
func (r *mediaRepo) FindUploadingSession(ctx context.Context, userID uint, hash string) (*biz.UploadSession, error) {
|
||||
var po uploadSessionPO
|
||||
if err := r.data.gormDB.WithContext(ctx).Where("user_id = ? AND file_hash = ? AND status = ?", userID, hash, "uploading").First(&po).Error; err != nil {
|
||||
@@ -66,6 +73,13 @@ func (r *mediaRepo) FindUploadSession(ctx context.Context, id uint) (*biz.Upload
|
||||
}
|
||||
return uploadFromPO(po), nil
|
||||
}
|
||||
func (r *mediaRepo) ClaimUploadSession(ctx context.Context, id uint) (bool, error) {
|
||||
result := r.data.gormDB.WithContext(ctx).Model(&uploadSessionPO{}).Where("id = ? AND status = ?", id, "uploading").Update("status", "merging")
|
||||
return result.RowsAffected == 1, result.Error
|
||||
}
|
||||
func (r *mediaRepo) FailUploadSession(ctx context.Context, id uint) error {
|
||||
return r.data.gormDB.WithContext(ctx).Model(&uploadSessionPO{}).Where("id = ?", id).Update("status", "failed").Error
|
||||
}
|
||||
func (r *mediaRepo) CompleteUploadSession(ctx context.Context, id uint, key string, mediaID uint) error {
|
||||
return r.data.gormDB.WithContext(ctx).Model(&uploadSessionPO{}).Where("id = ?", id).Updates(map[string]any{"status": "completed", "storage_key": key, "media_id": mediaID}).Error
|
||||
}
|
||||
@@ -74,7 +88,7 @@ func (r *mediaRepo) DeleteUploadSession(ctx context.Context, id uint) error {
|
||||
}
|
||||
func (r *mediaRepo) UpsertChunk(ctx context.Context, uploadID uint, v *biz.UploadChunk) error {
|
||||
po := uploadChunkPO{UploadID: uploadID, ChunkIndex: v.Index, ChunkHash: v.Hash, Size: v.Size}
|
||||
return r.data.gormDB.WithContext(ctx).Clauses(clause.OnConflict{Columns: []clause.Column{{Name: "upload_id"}, {Name: "chunk_index"}}, DoUpdates: clause.AssignmentColumns([]string{"chunk_hash", "size", "updated_at"})}).Create(&po).Error
|
||||
return r.data.gormDB.WithContext(ctx).Clauses(clause.OnConflict{Columns: []clause.Column{{Name: "upload_id"}, {Name: "chunk_index"}}, DoNothing: true}).Create(&po).Error
|
||||
}
|
||||
func (r *mediaRepo) ListChunks(ctx context.Context, uploadID uint) ([]*biz.UploadChunk, error) {
|
||||
var pos []uploadChunkPO
|
||||
|
||||
Reference in New Issue
Block a user