优化结构
This commit is contained in:
@@ -97,7 +97,7 @@ func (uc *MediaUsecase) InitUpload(ctx context.Context, userID uint, name, hash
|
||||
completed, err := uc.FindCompletedSession(ctx, userID, strings.ToLower(hash))
|
||||
if err == nil && completed.MediaID != 0 {
|
||||
if media, findErr := uc.FindMedia(ctx, completed.MediaID); findErr == nil {
|
||||
copy := &MediaFile{Name: name, URL: media.URL, Tag: strings.TrimPrefix(filepath.Ext(name), "."), Key: media.Key, Size: media.Size, MD5: media.MD5, Mime: media.Mime, UserID: userID}
|
||||
copy := &MediaFile{Name: name, CategoryID: media.CategoryID, URL: media.URL, Tag: strings.TrimPrefix(filepath.Ext(name), "."), Key: media.Key, Size: media.Size, MD5: media.MD5, Mime: media.Mime, UserID: userID}
|
||||
if strings.TrimSpace(copy.Mime) == "" {
|
||||
copy.Mime = stdmime.TypeByExtension(strings.ToLower(filepath.Ext(name)))
|
||||
if copy.Mime == "" {
|
||||
@@ -294,8 +294,10 @@ func (uc *MediaUsecase) CleanupStale(ctx context.Context, ttlHours int) error {
|
||||
// scheduler. Keep the endpoint-independent background behavior compatible.
|
||||
ids, _ := uc.StaleUploadSessionIDs(ctx, time.Now().Add(-time.Duration(ttlHours)*time.Hour))
|
||||
for _, id := range ids {
|
||||
if err := uc.files.DeletePrefix(ctx, uc.chunkPrefix(id)); err != nil {
|
||||
continue
|
||||
}
|
||||
_ = uc.DeleteUploadData(ctx, id)
|
||||
_ = uc.files.DeletePrefix(ctx, uc.chunkPrefix(id))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ func NewTaskUsecaseWithRegistry(repo TaskRepo, methods TaskMethodRegistry) *Task
|
||||
return &TaskUsecase{TaskRepo: repo, methods: methods}
|
||||
}
|
||||
|
||||
func (uc *TaskUsecase) RegisteredMethods() []TaskMethod { return uc.methods.List() }
|
||||
func (uc *TaskUsecase) RegisteredMethods() []platformtask.Method { return uc.methods.List() }
|
||||
|
||||
func (uc *TaskUsecase) Validate(value *TimedTask) error {
|
||||
if value.Name == "" {
|
||||
@@ -165,7 +165,7 @@ func NewTaskApplicationUsecase(tasks *TaskUsecase, runtime TaskRuntime) *TaskApp
|
||||
return &TaskApplicationUsecase{tasks: tasks, runtime: runtime}
|
||||
}
|
||||
|
||||
func (uc *TaskApplicationUsecase) RegisteredMethods() []TaskMethod {
|
||||
func (uc *TaskApplicationUsecase) RegisteredMethods() []platformtask.Method {
|
||||
return uc.tasks.RegisteredMethods()
|
||||
}
|
||||
|
||||
|
||||
@@ -2,10 +2,7 @@ package task
|
||||
|
||||
import platformtask "kra/pkg/task"
|
||||
|
||||
type TaskMethodFunc = platformtask.MethodFunc
|
||||
type TaskMethod = platformtask.Method
|
||||
|
||||
type TaskMethodRegistry interface {
|
||||
Lookup(string) (TaskMethodFunc, bool)
|
||||
List() []TaskMethod
|
||||
Lookup(string) (platformtask.MethodFunc, bool)
|
||||
List() []platformtask.Method
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package config
|
||||
|
||||
import "strings"
|
||||
|
||||
// MaskedSecret is the placeholder written in place of a stored secret whenever a
|
||||
// configuration payload leaves the process. Every layer that masks or preserves
|
||||
// configuration secrets shares this sentinel so a masked read round-trips into a
|
||||
@@ -8,7 +10,9 @@ const MaskedSecret = "******"
|
||||
|
||||
// IsMaskedSecret reports whether an inbound value carries no new secret, either
|
||||
// because it was omitted or because it is the mask handed out on read.
|
||||
func IsMaskedSecret(value string) bool { return value == "" || value == MaskedSecret }
|
||||
func IsMaskedSecret(value string) bool {
|
||||
return strings.TrimSpace(value) == "" || strings.TrimSpace(value) == MaskedSecret
|
||||
}
|
||||
|
||||
// ObjectStores lists every object-store block of a storage configuration so
|
||||
// callers iterate the providers instead of repeating the list.
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"kra/internal/biz/system"
|
||||
datasystem "kra/internal/data/system"
|
||||
"log/slog"
|
||||
"reflect"
|
||||
"strings"
|
||||
@@ -13,6 +14,10 @@ import (
|
||||
"gorm.io/gorm/schema"
|
||||
)
|
||||
|
||||
// dataAccessLogPO is the infrastructure-side write model used by GORM
|
||||
// callbacks. The system module owns the query repository for the same table.
|
||||
type dataAccessLogPO = datasystem.DataAccessLogPO
|
||||
|
||||
// registerDataScopeCallbacks installs the global GORM data-scope engine.
|
||||
// System tables are deliberately excluded: their access is controlled by
|
||||
// Casbin, while ownership columns on business tables are row-level scope.
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
datasystem "kra/internal/data/system"
|
||||
)
|
||||
|
||||
// dataAccessLogPO is the infrastructure-side write model used by GORM
|
||||
// callbacks. The system module owns the query repository for the same table.
|
||||
type dataAccessLogPO = datasystem.DataAccessLogPO
|
||||
@@ -90,11 +90,17 @@ func (r *mediaRepo) FailUploadSession(ctx context.Context, id uint) error {
|
||||
return r.data.DB().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.DB().WithContext(ctx).Model(&uploadSessionPO{}).Where("id = ?", id).Updates(map[string]any{"status": "completed", "storage_key": key, "media_id": mediaID}).Error
|
||||
result := r.data.DB().WithContext(ctx).Model(&uploadSessionPO{}).Where("id = ? AND status = ?", id, "merging").Updates(map[string]any{"status": "completed", "storage_key": key, "media_id": mediaID})
|
||||
if result.Error != nil {
|
||||
return result.Error
|
||||
}
|
||||
if result.RowsAffected != 1 {
|
||||
return system.ErrUploadSessionNotFound
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (r *mediaRepo) DeleteUploadSession(ctx context.Context, id uint) error {
|
||||
// The compatible flow uses GORM's normal Delete here, retaining the soft-deleted session
|
||||
// for audit/recovery rather than physically removing it.
|
||||
// Upload sessions are staging records; cleanup physically removes them and their chunks.
|
||||
return r.data.DB().WithContext(ctx).Unscoped().Delete(&uploadSessionPO{}, id).Error
|
||||
}
|
||||
func (r *mediaRepo) UpsertChunk(ctx context.Context, uploadID uint, v *system.UploadChunk) error {
|
||||
|
||||
@@ -1,13 +1,5 @@
|
||||
package task
|
||||
|
||||
import (
|
||||
dataprovider "kra/internal/data/provider"
|
||||
|
||||
"github.com/google/wire"
|
||||
)
|
||||
|
||||
// Provider is the minimal database seam required by the task tables.
|
||||
// Task persistence must not depend on the full data runtime or system repos.
|
||||
type Provider = dataprovider.Database
|
||||
import "github.com/google/wire"
|
||||
|
||||
var ProviderSet = wire.NewSet(NewTaskRepo)
|
||||
|
||||
@@ -3,6 +3,7 @@ package task
|
||||
import (
|
||||
"context"
|
||||
taskbiz "kra/internal/biz/task"
|
||||
dataprovider "kra/internal/data/provider"
|
||||
"kra/pkg/database/gormkit"
|
||||
"kra/pkg/database/pagination"
|
||||
"time"
|
||||
@@ -44,9 +45,9 @@ type taskLogPO struct {
|
||||
|
||||
func (taskLogPO) TableName() string { return "sys_timed_task_logs" }
|
||||
|
||||
type taskRepo struct{ data Provider }
|
||||
type taskRepo struct{ data dataprovider.Database }
|
||||
|
||||
func NewTaskRepo(data Provider) taskbiz.TaskRepo { return &taskRepo{data: data} }
|
||||
func NewTaskRepo(data dataprovider.Database) taskbiz.TaskRepo { return &taskRepo{data: data} }
|
||||
func taskToPO(v *taskbiz.TimedTask) taskPO {
|
||||
return taskPO{ID: v.ID, Name: v.Name, Description: v.Description, Spec: v.Spec, WithSeconds: v.WithSeconds, ExecutorType: v.ExecutorType, MethodName: v.MethodName, Params: gormkit.JSON(v.Params), HTTPURL: v.HTTPURL, HTTPMethod: v.HTTPMethod, HTTPHeader: gormkit.JSON(v.HTTPHeader), HTTPBody: v.HTTPBody, HTTPAllowPrivate: v.HTTPAllowPrivate, Enabled: v.Enabled}
|
||||
}
|
||||
|
||||
@@ -56,8 +56,8 @@ var routes = map[string]routeValue{
|
||||
"DELETE /sysExportTemplate/deleteSysExportTemplateByIds": {group: "导出模板", description: "批量删除导出模板", audit: true},
|
||||
"DELETE /sysLoginLog/deleteLoginLog": {group: "登录日志", description: "删除登录日志", audit: true},
|
||||
"DELETE /sysLoginLog/deleteLoginLogByIds": {group: "登录日志", description: "批量删除登录日志", audit: true},
|
||||
"DELETE /sysOperationRecord/deleteSysOperationRecord": {group: "操作记录", description: "删除操作记录"},
|
||||
"DELETE /sysOperationRecord/deleteSysOperationRecordByIds": {group: "操作记录", description: "批量删除操作历史"},
|
||||
"DELETE /sysOperationRecord/deleteSysOperationRecord": {group: "操作记录", description: "删除操作记录", audit: true},
|
||||
"DELETE /sysOperationRecord/deleteSysOperationRecordByIds": {group: "操作记录", description: "批量删除操作历史", audit: true},
|
||||
"DELETE /sysParams/deleteSysParams": {group: "参数管理", description: "删除参数", audit: true},
|
||||
"DELETE /sysParams/deleteSysParamsByIds": {group: "参数管理", description: "批量删除参数", audit: true},
|
||||
"DELETE /sysVersion/deleteSysVersion": {group: "版本控制", description: "删除版本", audit: true},
|
||||
@@ -135,7 +135,7 @@ var routes = map[string]routeValue{
|
||||
"POST /api/setApiRoles": {group: "api", description: "全量覆盖API关联角色列表", audit: true},
|
||||
"POST /api/updateApi": {group: "api", description: "更新Api", audit: true},
|
||||
"POST /attachmentCategory/addCategory": {group: "媒体库分类", description: "添加/编辑分类"},
|
||||
"POST /attachmentCategory/deleteCategory": {group: "媒体库分类", description: "删除分类"},
|
||||
"POST /attachmentCategory/deleteCategory": {group: "媒体库分类", description: "删除分类", audit: true},
|
||||
"POST /authority/copyAuthority": {group: "角色", description: "拷贝角色", audit: true},
|
||||
"POST /authority/createAuthority": {group: "角色", description: "创建角色", audit: true},
|
||||
"POST /authority/deleteAuthority": {group: "角色", description: "删除角色", audit: true},
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
package dto
|
||||
|
||||
type LoginResponse struct {
|
||||
User *UserResponse `json:"user"`
|
||||
Token string `json:"token"`
|
||||
ExpiresAt int64 `json:"expiresAt"`
|
||||
NeedChangePassword bool `json:"needChangePassword"`
|
||||
}
|
||||
@@ -9,6 +9,13 @@ type LoginRequest struct {
|
||||
CaptchaID string `json:"captchaId"`
|
||||
}
|
||||
|
||||
type LoginResponse struct {
|
||||
User *UserResponse `json:"user"`
|
||||
Token string `json:"token"`
|
||||
ExpiresAt int64 `json:"expiresAt"`
|
||||
NeedChangePassword bool `json:"needChangePassword"`
|
||||
}
|
||||
|
||||
type Route struct {
|
||||
Path string
|
||||
Method string
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"unicode/utf8"
|
||||
|
||||
taskbiz "kra/internal/biz/task"
|
||||
platformtask "kra/pkg/task"
|
||||
)
|
||||
|
||||
type TaskExecutor struct {
|
||||
@@ -199,7 +200,7 @@ func (e *TaskExecutor) runMethod(ctx context.Context, task *taskbiz.TimedTask) e
|
||||
if ctx == nil {
|
||||
ctx = context.Background()
|
||||
}
|
||||
var method taskbiz.TaskMethodFunc
|
||||
var method platformtask.MethodFunc
|
||||
var ok bool
|
||||
if e.methods != nil {
|
||||
method, ok = e.methods.Lookup(task.MethodName)
|
||||
|
||||
Reference in New Issue
Block a user