优化结构

This commit is contained in:
Yvan
2026-08-20 23:02:06 +08:00
parent 63dbb4cfbc
commit e65cf0b1d0
338 changed files with 622 additions and 481 deletions
-3
View File
@@ -1,3 +0,0 @@
# Service
本目录负责管理端 DTO 与领域对象之间的转换和输入校验,不直接访问数据库。固定 JSON 契约放在 `dto/`,只有用户设置、导出行等真正动态的数据使用 `map[string]any`。
-29
View File
@@ -1,29 +0,0 @@
package service
import (
"context"
"kra/internal/biz"
)
type AccessControlService struct{ uc *biz.AccessControlUsecase }
func NewAccessControlService(uc *biz.AccessControlUsecase) *AccessControlService {
return &AccessControlService{uc: uc}
}
func (s *AccessControlService) Authorize(ctx context.Context, authorityID uint, path, method string) (bool, error) {
return s.uc.Authorize(ctx, authorityID, path, method)
}
func (s *AccessControlService) ResolveDataScope(ctx context.Context, authorityID, userID uint) (biz.DataScope, error) {
return s.uc.ResolveDataScope(ctx, authorityID, userID)
}
func (s *AccessControlService) ContextWithDataScope(ctx context.Context, authorityID, userID uint) (context.Context, error) {
scope, err := s.ResolveDataScope(ctx, authorityID, userID)
if err != nil {
return ctx, err
}
return biz.NewDataScopeContext(ctx, scope), nil
}
-80
View File
@@ -1,80 +0,0 @@
package service
import (
"context"
"encoding/json"
"time"
"kra/internal/biz"
"kra/internal/service/dto"
)
type AnnouncementInput struct {
ID uint
Title string
Content string
UserID *int
Attachments json.RawMessage
}
type AnnouncementService struct{ uc *biz.AnnouncementUsecase }
func NewAnnouncementService(uc *biz.AnnouncementUsecase) *AnnouncementService {
return &AnnouncementService{uc: uc}
}
func announcementDTO(item *biz.Announcement) *dto.AnnouncementResponse {
return &dto.AnnouncementResponse{ID: item.ID, CreatedAt: item.CreatedAt, UpdatedAt: item.UpdatedAt, DeletedAt: nil, Title: item.Title, Content: item.Content, UserID: item.UserID, Attachments: json.RawMessage(item.Attachments)}
}
func announcementDO(in AnnouncementInput) *biz.Announcement {
return &biz.Announcement{ID: in.ID, Title: in.Title, Content: in.Content, UserID: in.UserID, Attachments: in.Attachments}
}
func (s *AnnouncementService) Create(ctx context.Context, in AnnouncementInput) error {
return s.uc.Create(ctx, announcementDO(in))
}
func (s *AnnouncementService) Update(ctx context.Context, in AnnouncementInput) error {
return s.uc.Update(ctx, announcementDO(in))
}
func (s *AnnouncementService) Delete(ctx context.Context, id string) error {
return s.uc.Delete(ctx, id)
}
func (s *AnnouncementService) DeleteByIDs(ctx context.Context, ids []string) error {
return s.uc.DeleteByIDs(ctx, ids)
}
func (s *AnnouncementService) Find(ctx context.Context, id string) (*dto.AnnouncementResponse, error) {
item, err := s.uc.Find(ctx, id)
if err != nil {
return nil, err
}
return announcementDTO(item), nil
}
func (s *AnnouncementService) List(ctx context.Context, page, pageSize int, start, end *time.Time) ([]*dto.AnnouncementResponse, int64, error) {
items, total, err := s.uc.List(ctx, biz.AnnouncementFilter{Page: page, PageSize: pageSize, StartCreatedAt: start, EndCreatedAt: end})
if err != nil {
return nil, 0, err
}
result := make([]*dto.AnnouncementResponse, 0, len(items))
for _, item := range items {
result = append(result, announcementDTO(item))
}
return result, total, nil
}
func (s *AnnouncementService) UserOptions(ctx context.Context) ([]*dto.SelectOptionResponse, error) {
items, err := s.uc.UserOptions(ctx)
if err != nil {
return nil, err
}
result := make([]*dto.SelectOptionResponse, 0, len(items))
for _, item := range items {
result = append(result, &dto.SelectOptionResponse{Label: item.Label, Value: item.Value})
}
return result, nil
}
-168
View File
@@ -1,168 +0,0 @@
package service
import (
"context"
"strings"
"kra/internal/biz"
"kra/internal/service/dto"
)
type APIService struct {
uc *biz.APIUsecase
settings biz.RuntimeSettings
}
func NewAPIService(uc *biz.APIUsecase, settings biz.RuntimeSettings) *APIService {
return &APIService{uc: uc, settings: settings}
}
func (s *APIService) NormalizeRoutePath(path string) string {
if s.settings == nil {
return path
}
return NormalizeRoutePath(path, s.settings.RouterPrefix())
}
func (s *APIService) apiDomain(value *dto.APIRequest) *biz.API {
return &biz.API{ID: value.ID, Path: s.NormalizeRoutePath(value.Path), Description: value.Description, APIGroup: value.APIGroup, Method: value.Method}
}
func apiResponse(value *biz.API) *dto.APIResponse {
return &dto.APIResponse{ID: value.ID, CreatedAt: value.CreatedAt, UpdatedAt: value.UpdatedAt, DeletedAt: nil, Path: value.Path, Description: value.Description, APIGroup: value.APIGroup, Method: value.Method}
}
func apiResponses(items []*biz.API) []*dto.APIResponse {
out := make([]*dto.APIResponse, 0, len(items))
for _, item := range items {
out = append(out, apiResponse(item))
}
return out
}
func (s *APIService) ListAPI(ctx context.Context, req *dto.APIListRequest) ([]*dto.APIResponse, int64, error) {
items, total, err := s.uc.ListAPIs(ctx, req.Page, req.PageSize, &biz.API{Path: req.Path, Description: req.Description, APIGroup: req.APIGroup, Method: req.Method, OrderKey: req.OrderKey, Desc: req.Desc})
if err != nil {
return nil, 0, err
}
return apiResponses(items), total, nil
}
func (s *APIService) AllAPI(ctx context.Context, strict bool) ([]*dto.APIResponse, error) {
items, _, err := s.uc.ListAPIs(ctx, 0, 0, &biz.API{StrictAll: strict})
if err != nil {
return nil, err
}
return apiResponses(items), nil
}
func (s *APIService) Groups(ctx context.Context) ([]string, map[string]string, error) {
// The compatible group endpoint uses an unqualified Find, whose natural order is
// the primary-key ascending order. GetAllApis intentionally uses id DESC,
// so do not reuse it here or the group/dropdown order changes.
items, _, err := s.uc.ListAPIs(ctx, 0, 0, &biz.API{OrderKey: "id"})
if err != nil {
return nil, nil, err
}
seen := make(map[string]bool)
groups := make([]string, 0)
groupAPIMap := make(map[string]string)
for _, item := range items {
if !seen[item.APIGroup] {
seen[item.APIGroup] = true
groups = append(groups, item.APIGroup)
}
parts := strings.Split(item.Path, "/")
if len(parts) > 1 {
groupAPIMap[parts[1]] = item.APIGroup
}
}
return groups, groupAPIMap, nil
}
func (s *APIService) CreateAPIRequest(ctx context.Context, req *dto.APIRequest) (*dto.APIResponse, error) {
value := s.apiDomain(req)
if err := s.uc.CreateAPI(ctx, value); err != nil {
return nil, err
}
return apiResponse(value), nil
}
func (s *APIService) UpdateAPIRequest(ctx context.Context, req *dto.APIRequest) error {
return s.uc.UpdateAPI(ctx, s.apiDomain(req))
}
func (s *APIService) FindAPIResponse(ctx context.Context, id uint) (*dto.APIResponse, error) {
value, err := s.uc.FindAPI(ctx, id)
if err != nil {
return nil, err
}
return apiResponse(value), nil
}
func (s *APIService) ApplyAPISyncRequest(ctx context.Context, req *dto.ApplyAPISyncRequest) error {
added := make([]*biz.API, 0, len(req.NewAPIs))
deleted := make([]*biz.API, 0, len(req.DeleteAPIs))
for i := range req.NewAPIs {
added = append(added, s.apiDomain(&req.NewAPIs[i]))
}
for i := range req.DeleteAPIs {
deleted = append(deleted, s.apiDomain(&req.DeleteAPIs[i]))
}
return s.uc.ApplyAPISync(ctx, added, deleted)
}
func (s *APIService) SetPolicyPathsRequest(ctx context.Context, req *dto.SetPolicyPathsRequest) error {
paths := make([]*biz.API, 0, len(req.Infos))
for _, value := range req.Infos {
paths = append(paths, &biz.API{Path: value.Path, Method: value.Method})
}
return s.uc.SetPolicyPaths(ctx, req.AuthorityID, paths)
}
func (s *APIService) PolicyPathResponses(ctx context.Context, authorityID uint) ([]dto.PolicyPathRequest, error) {
items, err := s.uc.PolicyPaths(ctx, authorityID)
if err != nil {
return nil, err
}
var out []dto.PolicyPathRequest
if len(items) > 0 {
out = make([]dto.PolicyPathRequest, 0, len(items))
}
for _, item := range items {
out = append(out, dto.PolicyPathRequest{Path: item.Path, Method: item.Method})
}
return out, nil
}
func (s *APIService) SyncAPIResponses(ctx context.Context, routes []dto.APIRequest) (*dto.APISyncResponse, error) {
items := make([]*biz.API, 0, len(routes))
for i := range routes {
routes[i].Path = s.NormalizeRoutePath(routes[i].Path)
// The compatible sync endpoint compares Gin's route table directly, so newly
// discovered routes carry only path and method. Group/description are
// intentionally left empty for the operator to fill in the sync dialog.
items = append(items, s.apiDomain(&routes[i]))
}
return s.SyncAPIs(ctx, items)
}
func (s *APIService) DeleteAPIs(ctx context.Context, ids []uint) error {
return s.uc.DeleteAPIs(ctx, ids)
}
func (s *APIService) DeleteAPI(ctx context.Context, id uint) error {
return s.uc.DeleteAPI(ctx, id)
}
func (s *APIService) APIRoleIDs(ctx context.Context, path, method string) ([]uint, error) {
return s.uc.APIRoleIDs(ctx, s.NormalizeRoutePath(path), method)
}
func (s *APIService) SetAPIRoles(ctx context.Context, path, method string, ids []uint) error {
return s.uc.SetAPIRoles(ctx, s.NormalizeRoutePath(path), method, ids)
}
func (s *APIService) FreshCasbin(ctx context.Context) error {
return s.uc.FreshCasbin(ctx)
}
func (s *APIService) SyncAPIs(ctx context.Context, routes []*biz.API) (*dto.APISyncResponse, error) {
diff, err := s.uc.SyncAPIs(ctx, routes)
if err != nil {
return nil, err
}
return &dto.APISyncResponse{NewAPIs: apiResponses(diff.Added), DeleteAPIs: apiResponses(diff.Deleted), IgnoreAPIs: apiResponses(diff.Ignored)}, nil
}
func (s *APIService) SetAPIIgnored(ctx context.Context, path, method string, ignored bool) error {
return s.uc.SetAPIIgnored(ctx, s.NormalizeRoutePath(path), method, ignored)
}
-62
View File
@@ -1,62 +0,0 @@
package service
import (
"context"
"time"
"kra/internal/biz"
"kra/internal/service/dto"
)
type TokenService struct {
uc *biz.TokenUsecase
issuer biz.TokenIssuer
}
func NewTokenService(uc *biz.TokenUsecase, issuer biz.TokenIssuer) *TokenService {
return &TokenService{uc: uc, issuer: issuer}
}
func tokenDTO(v *biz.APIToken) *dto.APITokenResponse {
var user *dto.UserResponse
if v.User != nil {
user = convertUser(v.User)
}
return &dto.APITokenResponse{ID: v.ID, CreatedAt: v.CreatedAt, UpdatedAt: v.UpdatedAt, DeletedAt: nil, UserID: v.UserID, AuthorityID: v.AuthorityID, Token: v.Token, Status: v.Status, ExpiresAt: v.ExpiresAt, Remark: v.Remark, User: user}
}
func (s *TokenService) CreateAPIToken(ctx context.Context, userID, authorityID uint, days int, remark string) (string, error) {
user, duration, err := s.uc.PrepareAPIToken(ctx, userID, authorityID, days)
if err != nil {
return "", err
}
issued, err := s.issuer.IssueToken(user, authorityID, false, duration)
if err != nil {
return "", err
}
record := &biz.APIToken{UserID: userID, AuthorityID: authorityID, Token: issued.Value, Status: true, ExpiresAt: time.Now().Add(duration), Remark: remark}
if err = s.uc.CreateAPIToken(ctx, record); err != nil {
return "", err
}
return issued.Value, nil
}
func (s *TokenService) APITokens(ctx context.Context, page, size int, userID uint, status *bool) ([]*dto.APITokenResponse, int64, error) {
items, total, err := s.uc.ListAPITokens(ctx, page, size, userID, status)
if err != nil {
return nil, 0, err
}
out := make([]*dto.APITokenResponse, 0, len(items))
for _, v := range items {
out = append(out, tokenDTO(v))
}
return out, total, nil
}
func (s *TokenService) DisableAPIToken(ctx context.Context, id uint) error {
return s.uc.DisableToken(ctx, id)
}
func (s *TokenService) BlacklistToken(ctx context.Context, token string) error {
return s.uc.BlacklistToken(ctx, token)
}
func (s *TokenService) IsTokenDisabled(ctx context.Context, token string) (bool, error) {
return s.uc.IsTokenDisabled(ctx, token)
}
-119
View File
@@ -1,119 +0,0 @@
package service
import (
"context"
"kra/internal/biz"
"kra/internal/service/dto"
)
type AuditService struct{ uc *biz.AuditUsecase }
func NewAuditService(uc *biz.AuditUsecase) *AuditService { return &AuditService{uc: uc} }
type AuditRecorder struct{ uc *biz.AuditRecorderUsecase }
func NewAuditRecorder(uc *biz.AuditRecorderUsecase) *AuditRecorder { return &AuditRecorder{uc: uc} }
func (s *AuditRecorder) RecordOperation(ctx context.Context, v *biz.OperationRecord) error {
return s.uc.RecordOperation(ctx, v)
}
func (s *AuditRecorder) RecordOperationRequest(ctx context.Context, value *dto.OperationRecordRequest) error {
return s.RecordOperation(ctx, &biz.OperationRecord{IP: value.IP, Method: value.Method, Path: value.Path, Status: value.Status, LatencyMS: value.LatencyMS, Agent: value.Agent, ErrorMessage: value.ErrorMessage, Body: value.Body, Response: value.Response, UserID: value.UserID, RequestID: value.RequestID, TraceID: value.TraceID, DeviceID: value.DeviceID})
}
func (s *AuditService) OperationsFilter(ctx context.Context, page, size int, path, method string, status int) ([]*dto.OperationRecordResponse, int64, error) {
return s.Operations(ctx, page, size, &biz.OperationRecord{Path: path, Method: method, Status: status})
}
func opDTO(v *biz.OperationRecord) *dto.OperationRecordResponse {
var user any = map[string]any{}
if v.User != nil {
user = convertUser(v.User)
}
return &dto.OperationRecordResponse{ID: v.ID, CreatedAt: v.CreatedAt, UpdatedAt: v.UpdatedAt, DeletedAt: nil, IP: v.IP, Method: v.Method, Path: v.Path, Status: v.Status, LatencyMS: v.LatencyMS, Agent: v.Agent, ErrorMessage: v.ErrorMessage, Body: v.Body, Response: v.Response, UserID: v.UserID, RequestID: v.RequestID, TraceID: v.TraceID, DeviceID: v.DeviceID, User: user}
}
func (s *AuditService) Operations(ctx context.Context, page, size int, q *biz.OperationRecord) ([]*dto.OperationRecordResponse, int64, error) {
items, total, err := s.uc.ListOperations(ctx, page, size, q)
if err != nil {
return nil, 0, err
}
out := make([]*dto.OperationRecordResponse, 0, len(items))
for _, v := range items {
out = append(out, opDTO(v))
}
return out, total, nil
}
func (s *AuditService) Operation(ctx context.Context, id uint) (*dto.OperationRecordResponse, error) {
v, err := s.uc.FindOperation(ctx, id)
if err != nil {
return nil, err
}
return opDTO(v), nil
}
func (s *AuditService) DeleteOperations(ctx context.Context, ids []int) error {
return s.uc.DeleteOperations(ctx, ids)
}
func (s *AuditRecorder) RecordLogin(ctx context.Context, v *biz.LoginLog) error {
return s.uc.RecordLogin(ctx, v)
}
func (s *AuditRecorder) RecordLoginRequest(ctx context.Context, value *dto.LoginLogRequest) error {
return s.RecordLogin(ctx, &biz.LoginLog{Username: value.Username, IP: value.IP, Status: value.Status, ErrorMessage: value.ErrorMessage, Agent: value.Agent, UserID: value.UserID})
}
func (s *AuditService) LoginsFilter(ctx context.Context, page, size int, username string, status bool) ([]*dto.LoginLogResponse, int64, error) {
return s.Logins(ctx, page, size, &biz.LoginLog{Username: username, Status: status, FilterByStatus: status})
}
func loginDTO(v *biz.LoginLog) *dto.LoginLogResponse {
var user any = map[string]any{}
if v.User != nil {
user = convertUser(v.User)
}
return &dto.LoginLogResponse{ID: v.ID, CreatedAt: v.CreatedAt, UpdatedAt: v.UpdatedAt, DeletedAt: nil, Username: v.Username, IP: v.IP, Status: v.Status, ErrorMessage: v.ErrorMessage, Agent: v.Agent, UserID: v.UserID, User: user}
}
func (s *AuditService) Logins(ctx context.Context, page, size int, q *biz.LoginLog) ([]*dto.LoginLogResponse, int64, error) {
items, total, err := s.uc.ListLogins(ctx, page, size, q)
if err != nil {
return nil, 0, err
}
out := make([]*dto.LoginLogResponse, 0, len(items))
for _, v := range items {
out = append(out, loginDTO(v))
}
return out, total, nil
}
func (s *AuditService) Login(ctx context.Context, id uint) (*dto.LoginLogResponse, error) {
v, err := s.uc.FindLogin(ctx, id)
if err != nil {
return nil, err
}
return loginDTO(v), nil
}
func (s *AuditService) DeleteLogins(ctx context.Context, ids []int) error {
return s.uc.DeleteLogins(ctx, ids)
}
func (s *AuditRecorder) RecordDataAccess(ctx context.Context, v *biz.DataAccessLog) error {
return s.uc.RecordDataAccess(ctx, v)
}
func (s *AuditRecorder) RecordDataAccessRequest(ctx context.Context, value *dto.DataAccessRecordRequest) error {
return s.RecordDataAccess(ctx, &biz.DataAccessLog{EventType: value.EventType, Operation: value.Operation, UserID: value.UserID, AuthorityID: value.AuthorityID, RequestID: value.RequestID, Method: value.Method, Path: value.Path, Detail: value.Detail})
}
func (s *AuditService) DataAccessRequest(ctx context.Context, req *dto.DataAccessListRequest) ([]*dto.DataAccessLogResponse, int64, error) {
return s.DataAccess(ctx, req.Page, req.PageSize, &biz.DataAccessLog{EventType: req.EventType, TargetTable: req.TargetTable})
}
func dataAccessDTO(v *biz.DataAccessLog) *dto.DataAccessLogResponse {
return &dto.DataAccessLogResponse{ID: v.ID, CreatedAt: v.CreatedAt, UpdatedAt: v.UpdatedAt, DeletedAt: nil, EventType: v.EventType, TargetTable: v.TargetTable, Operation: v.Operation, UserID: v.UserID, AuthorityID: v.AuthorityID, Scope: v.Scope, RequestID: v.RequestID, Method: v.Method, Path: v.Path, Detail: v.Detail}
}
func (s *AuditService) DataAccess(ctx context.Context, page, size int, q *biz.DataAccessLog) ([]*dto.DataAccessLogResponse, int64, error) {
items, total, err := s.uc.ListDataAccess(ctx, page, size, q)
if err != nil {
return nil, 0, err
}
out := make([]*dto.DataAccessLogResponse, 0, len(items))
for _, v := range items {
out = append(out, dataAccessDTO(v))
}
return out, total, nil
}
func (s *AuditService) DeleteDataAccess(ctx context.Context, ids []uint) error {
return s.uc.DeleteDataAccess(ctx, ids)
}
-71
View File
@@ -1,71 +0,0 @@
package service
import (
"context"
"time"
"kra/internal/biz"
"kra/internal/service/dto"
)
func errorDTO(v *biz.ErrorRecord) *dto.ErrorRecordResponse {
return &dto.ErrorRecordResponse{ID: v.ID, CreatedAt: v.CreatedAt, UpdatedAt: v.UpdatedAt, DeletedAt: nil, Form: v.Form, Info: v.Info, Level: v.Level, RequestID: v.RequestID, TraceID: v.TraceID, Solution: v.Solution, Status: v.Status}
}
func (s *AuditRecorder) CreateError(ctx context.Context, v *biz.ErrorRecord) error {
return s.uc.CreateError(ctx, v)
}
func recordedErrorDomain(value *dto.ErrorRecordRequest) *biz.ErrorRecord {
form, info := value.Form, value.Info
result := &biz.ErrorRecord{Form: &form, Info: &info, Level: value.Level, RequestID: value.RequestID, TraceID: value.TraceID, Status: value.Status}
if value.Solution != "" {
solution := value.Solution
result.Solution = &solution
}
return result
}
func mutatedErrorDomain(value *dto.ErrorRecordMutationRequest) *biz.ErrorRecord {
return &biz.ErrorRecord{ID: value.ID, CreatedAt: value.CreatedAt, UpdatedAt: value.UpdatedAt, Form: value.Form, Info: value.Info, Level: value.Level, RequestID: value.RequestID, TraceID: value.TraceID, Solution: value.Solution, Status: value.Status}
}
func (s *AuditRecorder) CreateErrorRequest(ctx context.Context, req *dto.ErrorRecordRequest) error {
return s.CreateError(ctx, recordedErrorDomain(req))
}
func (s *AuditRecorder) CreateErrorMutationRequest(ctx context.Context, req *dto.ErrorRecordMutationRequest) error {
return s.CreateError(ctx, mutatedErrorDomain(req))
}
func (s *AuditService) UpdateErrorRequest(ctx context.Context, req *dto.ErrorRecordMutationRequest) error {
return s.UpdateError(ctx, mutatedErrorDomain(req))
}
func (s *AuditService) ErrorsFilter(ctx context.Context, page, size int, form, info string, createdAtRange []time.Time) ([]*dto.ErrorRecordResponse, int64, error) {
query := &biz.ErrorRecord{CreatedAtRange: createdAtRange}
if form != "" {
query.Form = &form
}
if info != "" {
query.Info = &info
}
return s.Errors(ctx, page, size, query)
}
func (s *AuditService) UpdateError(ctx context.Context, v *biz.ErrorRecord) error {
return s.uc.UpdateError(ctx, v)
}
func (s *AuditService) DeleteErrors(ctx context.Context, ids []uint) error {
return s.uc.DeleteErrors(ctx, ids)
}
func (s *AuditService) Error(ctx context.Context, id uint) (*dto.ErrorRecordResponse, error) {
v, err := s.uc.FindError(ctx, id)
if err != nil {
return nil, err
}
return errorDTO(v), nil
}
func (s *AuditService) Errors(ctx context.Context, page, size int, q *biz.ErrorRecord) ([]*dto.ErrorRecordResponse, int64, error) {
items, total, err := s.uc.ListErrors(ctx, page, size, q)
if err != nil {
return nil, 0, err
}
out := make([]*dto.ErrorRecordResponse, 0, len(items))
for _, v := range items {
out = append(out, errorDTO(v))
}
return out, total, nil
}
-44
View File
@@ -1,44 +0,0 @@
package service
import (
"context"
"kra/internal/biz"
"kra/internal/service/dto"
)
type LogViewerService struct{ uc *biz.LogViewerUsecase }
func NewLogViewerService(uc *biz.LogViewerUsecase) *LogViewerService {
return &LogViewerService{uc: uc}
}
func (s *LogViewerService) LogDates(ctx context.Context, month string) (*dto.LogDatesResponse, error) {
items, err := s.uc.LogDates(ctx, month)
if err != nil {
return nil, err
}
out := make([]*dto.LogDateResponse, 0, len(items))
for _, v := range items {
out = append(out, &dto.LogDateResponse{Date: v.Date, FileCount: v.FileCount})
}
return &dto.LogDatesResponse{Month: month, Dates: out}, nil
}
func (s *LogViewerService) LogFiles(ctx context.Context, date string) (*dto.LogFilesResponse, error) {
items, err := s.uc.LogFiles(ctx, date)
if err != nil {
return nil, err
}
out := make([]*dto.LogFileResponse, 0, len(items))
for _, v := range items {
out = append(out, &dto.LogFileResponse{Path: v.Path, Name: v.Name, Size: v.Size, ModifiedAt: v.ModifiedAt})
}
return &dto.LogFilesResponse{Date: date, Files: out}, nil
}
func (s *LogViewerService) LogContent(ctx context.Context, date, path string, cursor *int64) (*dto.LogContentResponse, error) {
v, err := s.uc.LogContent(ctx, date, path, cursor)
if err != nil {
return nil, err
}
return &dto.LogContentResponse{Date: v.Date, Path: v.Path, Content: v.Content, LineCount: v.LineCount, NextCursor: v.NextCursor, HasMore: v.HasMore, LimitedByBytes: v.LimitedByBytes, Size: v.Size, ModifiedAt: v.ModifiedAt}, nil
}
-40
View File
@@ -1,40 +0,0 @@
package service
import (
"context"
"kra/internal/biz"
"kra/internal/service/dto"
)
type AuthService struct {
uc *biz.AuthenticationUsecase
}
func NewAuthService(uc *biz.AuthenticationUsecase) *AuthService {
return &AuthService{uc: uc}
}
func loginResult(value *biz.AuthenticationResult) *dto.LoginResponse {
return &dto.LoginResponse{User: convertUser(value.User), Token: value.Token, ExpiresAt: value.ExpiresAt.UnixMilli(), NeedChangePassword: value.NeedChangePassword}
}
func (s *AuthService) Login(ctx context.Context, req *dto.LoginRequest, ip, agent string) (*dto.LoginResponse, error) {
value, err := s.uc.Login(ctx, &biz.LoginAttempt{Username: req.Username, Password: req.Password, CaptchaID: req.CaptchaID, Captcha: req.Captcha, IP: ip, Agent: agent})
if err != nil {
return nil, err
}
return loginResult(value), nil
}
func (s *AuthService) SwitchAuthority(ctx context.Context, claims *biz.AuthClaims, authorityID uint) (*dto.LoginResponse, error) {
value, err := s.uc.SwitchAuthority(ctx, claims, authorityID)
if err != nil {
return nil, err
}
return loginResult(value), nil
}
func (s *AuthService) AuthenticateToken(ctx context.Context, token string) (*biz.TokenAuthentication, error) {
return s.uc.AuthenticateToken(ctx, token)
}
-94
View File
@@ -1,94 +0,0 @@
package service
import (
"context"
"kra/internal/biz"
"kra/internal/service/dto"
)
type AuthorityService struct{ uc *biz.AuthorityUsecase }
func NewAuthorityService(uc *biz.AuthorityUsecase) *AuthorityService {
return &AuthorityService{uc: uc}
}
func authorityDTO(value *biz.Authority) *dto.AuthorityResponse {
out := convertAuthority(*value)
children := make([]*dto.AuthorityResponse, 0, len(value.Children))
for _, child := range value.Children {
children = append(children, authorityDTO(child))
}
out.Children = children
return out
}
func authorityDomain(req *dto.AuthorityRequest) *biz.Authority {
return &biz.Authority{AuthorityID: req.AuthorityID, AuthorityName: req.AuthorityName, ParentID: req.ParentID, DataScope: req.DataScope, DefaultRouter: req.DefaultRouter}
}
func authorityResponse(value *biz.Authority) *dto.AuthorityResponse {
var menus []*dto.MenuResponse
if value.Menus != nil {
menus = menuResponses(value.Menus)
}
return &dto.AuthorityResponse{CreatedAt: value.CreatedAt, UpdatedAt: value.UpdatedAt, DeletedAt: value.DeletedAt, AuthorityID: value.AuthorityID, AuthorityName: value.AuthorityName, ParentID: value.ParentID, Children: nil, Menus: menus, DataScope: value.DataScope, DefaultRouter: value.DefaultRouter}
}
func (s *AuthorityService) Authorities(ctx context.Context) ([]*dto.AuthorityResponse, error) {
items, err := s.uc.AuthorityTree(ctx)
if err != nil {
return nil, err
}
roots := make([]*dto.AuthorityResponse, 0, len(items))
for _, value := range items {
roots = append(roots, authorityDTO(value))
}
return roots, nil
}
func (s *AuthorityService) CreateAuthorityRequest(ctx context.Context, req *dto.AuthorityRequest) (*dto.AuthorityResponse, error) {
value := authorityDomain(req)
if err := s.uc.CreateAuthority(ctx, value); err != nil {
return nil, err
}
return authorityResponse(value), nil
}
func (s *AuthorityService) CopyAuthorityRequest(ctx context.Context, req *dto.CopyAuthorityRequest) (*dto.AuthorityResponse, error) {
value := authorityDomain(&req.Authority)
if err := s.uc.CopyAuthority(ctx, req.OldAuthorityID, value); err != nil {
return nil, err
}
result := authorityResponse(value)
result.Children = []*dto.AuthorityResponse{}
return result, nil
}
func (s *AuthorityService) UpdateAuthorityRequest(ctx context.Context, req *dto.AuthorityRequest) (*dto.AuthorityResponse, error) {
value := authorityDomain(req)
if err := s.uc.UpdateAuthority(ctx, value); err != nil {
return nil, err
}
return authorityResponse(value), nil
}
func (s *AuthorityService) DeleteAuthority(ctx context.Context, id uint) error {
return s.uc.DeleteAuthority(ctx, id)
}
func (s *AuthorityService) SetAuthorityUsers(ctx context.Context, id uint, ids []uint) error {
return s.uc.SetAuthorityUsers(ctx, id, ids)
}
func (s *AuthorityService) AuthorityUserIDs(ctx context.Context, id uint) ([]uint, error) {
return s.uc.AuthorityUserIDs(ctx, id)
}
func (s *AuthorityService) SetDataScope(ctx context.Context, id uint, scope int, ids []uint) error {
return s.uc.SetDataScope(ctx, id, scope, ids)
}
func (s *AuthorityService) DataScopeDepartmentIDs(ctx context.Context, id uint) ([]uint, error) {
return s.uc.DataScopeDepartmentIDs(ctx, id)
}
-77
View File
@@ -1,77 +0,0 @@
package service
import (
"context"
"kra/internal/biz"
"kra/internal/service/dto"
)
type DepartmentService struct{ uc *biz.DepartmentUsecase }
func NewDepartmentService(uc *biz.DepartmentUsecase) *DepartmentService {
return &DepartmentService{uc: uc}
}
func departmentResponse(value *biz.Department) *dto.DepartmentResponse {
var children []*dto.DepartmentResponse
if value.Children != nil {
children = make([]*dto.DepartmentResponse, 0, len(value.Children))
for _, child := range value.Children {
children = append(children, departmentResponse(child))
}
}
var leader any
if value.Leader != nil {
leader = convertUser(value.Leader)
}
return &dto.DepartmentResponse{ID: value.ID, CreatedAt: value.CreatedAt, UpdatedAt: value.UpdatedAt, DeletedAt: nil, Name: value.Name, ParentID: value.ParentID, Ancestors: value.Ancestors, Sort: value.Sort, LeaderID: value.LeaderID, Leader: leader, Status: value.Status, Children: children, NamePath: value.NamePath}
}
func departmentDomain(value *dto.DepartmentRequest) *biz.Department {
return &biz.Department{ID: value.ID, Name: value.Name, ParentID: value.ParentID, Sort: value.Sort, LeaderID: value.LeaderID, Status: value.Status}
}
func (s *DepartmentService) Departments(ctx context.Context, name string) ([]*dto.DepartmentResponse, error) {
items, err := s.uc.Departments(ctx, name)
if err != nil {
return nil, err
}
out := make([]*dto.DepartmentResponse, 0, len(items))
for _, item := range items {
out = append(out, departmentResponse(item))
}
return out, nil
}
func (s *DepartmentService) Create(ctx context.Context, req *dto.DepartmentRequest) error {
return s.uc.CreateDepartment(ctx, departmentDomain(req))
}
func (s *DepartmentService) Update(ctx context.Context, req *dto.DepartmentRequest) error {
return s.uc.UpdateDepartment(ctx, departmentDomain(req))
}
func (s *DepartmentService) Delete(ctx context.Context, id uint) error {
return s.uc.DeleteDepartment(ctx, id)
}
func (s *DepartmentService) Department(ctx context.Context, id uint) (*dto.DepartmentResponse, error) {
value, err := s.uc.Department(ctx, id)
if err != nil {
return nil, err
}
return departmentResponse(value), nil
}
func (s *DepartmentService) UserIDs(ctx context.Context, id uint) ([]uint, error) {
return s.uc.DepartmentUserIDs(ctx, id)
}
func (s *DepartmentService) SetUsers(ctx context.Context, req *dto.SetDepartmentUsersRequest) error {
return s.uc.SetDepartmentUsers(ctx, req.DepartmentID, req.UserIDs)
}
func (s *DepartmentService) SetUserDepartments(ctx context.Context, req *dto.SetUserDepartmentsRequest) error {
return s.uc.SetUserDepartments(ctx, req.ID, req.DepartmentIDs, req.Primary)
}
-16
View File
@@ -1,16 +0,0 @@
package service
import (
"testing"
"kra/internal/biz"
)
func TestDepartmentResponsePreservesNilAndEmptyChildren(t *testing.T) {
if got := departmentResponse(&biz.Department{}).Children; got != nil {
t.Fatalf("single/search department children = %#v, want nil", got)
}
if got := departmentResponse(&biz.Department{Children: []*biz.Department{}}).Children; got == nil || len(got) != 0 {
t.Fatalf("tree leaf children = %#v, want empty slice", got)
}
}
-173
View File
@@ -1,173 +0,0 @@
package service
import (
"context"
"kra/internal/biz"
"kra/internal/service/dto"
)
type DictionaryService struct{ uc *biz.DictionaryUsecase }
func NewDictionaryService(uc *biz.DictionaryUsecase) *DictionaryService {
return &DictionaryService{uc: uc}
}
func dictionaryDomain(value *dto.DictionaryRequest) *biz.Dictionary {
return &biz.Dictionary{ID: value.ID, Name: value.Name, Type: value.Type, Status: value.Status, Desc: value.Description, ParentID: value.ParentID}
}
func (s *DictionaryService) CreateDictionaryRequest(ctx context.Context, req *dto.DictionaryRequest) (*dto.DictionaryResponse, error) {
value := dictionaryDomain(req)
if err := s.CreateDictionary(ctx, value); err != nil {
return nil, err
}
return dictionaryDTO(value), nil
}
func (s *DictionaryService) UpdateDictionaryRequest(ctx context.Context, req *dto.DictionaryRequest) error {
return s.UpdateDictionary(ctx, dictionaryDomain(req))
}
func dictionaryDTO(v *biz.Dictionary) *dto.DictionaryResponse {
var children []*dto.DictionaryResponse
if v.Children != nil {
children = make([]*dto.DictionaryResponse, 0, len(v.Children))
for _, x := range v.Children {
children = append(children, dictionaryDTO(x))
}
}
var details []*dto.DictionaryDetailResponse
if v.Details != nil {
details = make([]*dto.DictionaryDetailResponse, 0, len(v.Details))
for _, x := range v.Details {
details = append(details, detailDTO(x))
}
}
return &dto.DictionaryResponse{ID: v.ID, CreatedAt: v.CreatedAt, UpdatedAt: v.UpdatedAt, DeletedAt: nil, Name: v.Name, Type: v.Type, Status: v.Status, Desc: v.Desc, ParentID: v.ParentID, Children: children, SysDictionaryDetails: details}
}
func (s *DictionaryService) Dictionaries(ctx context.Context, page, size int, name, typ string, details bool) ([]*dto.DictionaryResponse, int64, error) {
items, total, err := s.uc.ListDictionaries(ctx, page, size, name, typ, details)
if err != nil {
return nil, 0, err
}
out := make([]*dto.DictionaryResponse, 0, len(items))
for _, v := range items {
out = append(out, dictionaryDTO(v))
}
return out, total, nil
}
func (s *DictionaryService) Dictionary(ctx context.Context, id uint, typ string, status *bool, details bool) (*dto.DictionaryResponse, error) {
v, err := s.uc.FindDictionary(ctx, id, typ, status, details)
if err != nil {
return nil, err
}
return dictionaryDTO(v), nil
}
func (s *DictionaryService) ExportDictionary(ctx context.Context, id uint) (*dto.DictionaryExportResponse, error) {
v, err := s.uc.ExportDictionary(ctx, id)
if err != nil {
return nil, err
}
var details []*dto.DictionaryDetailExportResponse
for _, detail := range v.Details {
details = append(details, &dto.DictionaryDetailExportResponse{
Label: detail.Label, Value: detail.Value, Extend: detail.Extend,
Status: detail.Status, Sort: detail.Sort, Level: detail.Level, Path: detail.Path,
})
}
return &dto.DictionaryExportResponse{
Name: v.Name, Type: v.Type, Status: v.Status, Desc: v.Desc,
SysDictionaryDetails: details,
}, nil
}
func (s *DictionaryService) CreateDictionary(ctx context.Context, v *biz.Dictionary) error {
return s.uc.CreateDictionary(ctx, v)
}
func (s *DictionaryService) UpdateDictionary(ctx context.Context, v *biz.Dictionary) error {
return s.uc.UpdateDictionary(ctx, v)
}
func (s *DictionaryService) DeleteDictionary(ctx context.Context, id uint) error {
return s.uc.DeleteDictionary(ctx, id)
}
func detailDomain(value *dto.DictionaryDetailRequest) *biz.DictionaryDetail {
return &biz.DictionaryDetail{ID: value.ID, Label: value.Label, Value: value.Value, Extend: value.Extend, Status: value.Status, Sort: value.Sort, DictionaryID: value.DictionaryID, ParentID: value.ParentID, Level: value.Level, Path: value.Path}
}
func (s *DictionaryService) CreateDictionaryDetailRequest(ctx context.Context, req *dto.DictionaryDetailRequest) error {
return s.CreateDictionaryDetail(ctx, detailDomain(req))
}
func (s *DictionaryService) UpdateDictionaryDetailRequest(ctx context.Context, req *dto.DictionaryDetailRequest) error {
return s.UpdateDictionaryDetail(ctx, detailDomain(req))
}
func detailDTO(v *biz.DictionaryDetail) *dto.DictionaryDetailResponse {
var children []*dto.DictionaryDetailResponse
if v.Children != nil {
children = make([]*dto.DictionaryDetailResponse, 0, len(v.Children))
for _, x := range v.Children {
children = append(children, detailDTO(x))
}
}
disabled := v.Status != nil && !*v.Status
return &dto.DictionaryDetailResponse{ID: v.ID, CreatedAt: v.CreatedAt, UpdatedAt: v.UpdatedAt, DeletedAt: nil, Label: v.Label, Value: v.Value, Extend: v.Extend, Status: v.Status, Sort: v.Sort, DictionaryID: v.DictionaryID, ParentID: v.ParentID, Level: v.Level, Path: v.Path, Disabled: disabled, Children: children}
}
func (s *DictionaryService) DictionaryDetails(ctx context.Context, page, size int, filter biz.DictionaryDetailFilter) ([]*dto.DictionaryDetailResponse, int64, error) {
items, total, err := s.uc.ListDictionaryDetails(ctx, page, size, filter)
if err != nil {
return nil, 0, err
}
out := make([]*dto.DictionaryDetailResponse, 0, len(items))
for _, v := range items {
out = append(out, detailDTO(v))
}
return out, total, nil
}
func (s *DictionaryService) DictionaryDetailsRequest(ctx context.Context, page, size int, request dto.DictionaryDetailListRequest) ([]*dto.DictionaryDetailResponse, int64, error) {
return s.DictionaryDetails(ctx, page, size, biz.DictionaryDetailFilter{
DictionaryID: request.DictionaryID,
Label: request.Label,
Value: request.Value,
Status: request.Status,
ParentID: request.ParentID,
Level: request.Level,
})
}
func (s *DictionaryService) DictionaryDetail(ctx context.Context, id uint) (*dto.DictionaryDetailResponse, error) {
v, err := s.uc.FindDictionaryDetail(ctx, id)
if err != nil {
return nil, err
}
return detailDTO(v), nil
}
func (s *DictionaryService) DictionaryPath(ctx context.Context, id uint) ([]*dto.DictionaryDetailResponse, error) {
path := make([]*dto.DictionaryDetailResponse, 0)
for id != 0 {
value, err := s.uc.FindDictionaryDetail(ctx, id)
if err != nil {
return nil, err
}
path = append([]*dto.DictionaryDetailResponse{detailDTO(value)}, path...)
if value.ParentID == nil {
break
}
id = *value.ParentID
}
return path, nil
}
func (s *DictionaryService) DictionaryTree(ctx context.Context, id uint, typ string) ([]*dto.DictionaryDetailResponse, error) {
items, err := s.uc.DictionaryDetailTree(ctx, id, typ)
if err != nil {
return nil, err
}
out := make([]*dto.DictionaryDetailResponse, 0, len(items))
for _, v := range items {
out = append(out, detailDTO(v))
}
return out, nil
}
func (s *DictionaryService) CreateDictionaryDetail(ctx context.Context, v *biz.DictionaryDetail) error {
return s.uc.CreateDictionaryDetail(ctx, v)
}
func (s *DictionaryService) UpdateDictionaryDetail(ctx context.Context, v *biz.DictionaryDetail) error {
return s.uc.UpdateDictionaryDetail(ctx, v)
}
func (s *DictionaryService) DeleteDictionaryDetail(ctx context.Context, id uint) error {
return s.uc.DeleteDictionaryDetail(ctx, id)
}
-46
View File
@@ -1,46 +0,0 @@
package service
import (
"context"
"encoding/json"
"errors"
"kra/internal/biz"
"kra/internal/service/dto"
)
func (s *DictionaryService) ImportDictionaryJSON(ctx context.Context, raw string) error {
var payload struct {
Name string `json:"name"`
Type string `json:"type"`
Status *bool `json:"status"`
Description string `json:"desc"`
Details []dto.DictionaryDetailRequest `json:"sysDictionaryDetails"`
}
if err := json.Unmarshal([]byte(raw), &payload); err != nil {
return errors.New("JSON 格式错误: " + err.Error())
}
if payload.Name == "" {
return errors.New("字典名称不能为空")
}
if payload.Type == "" {
return errors.New("字典类型不能为空")
}
dictionary := dictionaryDomain(&dto.DictionaryRequest{Name: payload.Name, Type: payload.Type, Status: payload.Status, Description: payload.Description})
details := make([]*biz.DictionaryDetail, 0, len(payload.Details))
for i := range payload.Details {
details = append(details, detailDomain(&payload.Details[i]))
}
return s.uc.ImportDictionary(ctx, dictionary, details)
}
func (s *DictionaryService) DictionaryDetailsByParent(ctx context.Context, dictionaryID uint, parentID *uint, includeChildren bool) ([]*dto.DictionaryDetailResponse, error) {
items, err := s.uc.DictionaryDetailsByParent(ctx, dictionaryID, parentID, includeChildren)
if err != nil {
return nil, err
}
out := make([]*dto.DictionaryDetailResponse, 0, len(items))
for _, item := range items {
out = append(out, detailDTO(item))
}
return out, nil
}
-28
View File
@@ -1,28 +0,0 @@
package service
import (
"context"
"testing"
"kra/internal/biz"
)
type dictionaryExportRepo struct {
biz.DictionaryRepo
value *biz.Dictionary
}
func (r dictionaryExportRepo) ExportDictionary(context.Context, uint) (*biz.Dictionary, error) {
return r.value, nil
}
func TestExportDictionaryPreservesNilDetails(t *testing.T) {
service := NewDictionaryService(biz.NewDictionaryUsecase(dictionaryExportRepo{value: &biz.Dictionary{Name: "empty", Type: "empty"}}))
result, err := service.ExportDictionary(context.Background(), 1)
if err != nil {
t.Fatal(err)
}
if result.SysDictionaryDetails != nil {
t.Fatalf("export details = %#v, want nil", result.SysDictionaryDetails)
}
}
-39
View File
@@ -1,39 +0,0 @@
package dto
import (
"encoding/json"
"time"
)
type AnnouncementRequest struct {
ID uint `json:"ID"`
Title string `json:"title"`
Content string `json:"content"`
UserID *int `json:"userID"`
Attachments json.RawMessage `json:"attachments"`
}
type AnnouncementSearchRequest struct {
Page int `form:"page"`
PageSize int `form:"pageSize"`
StartCreatedAt *time.Time `form:"startCreatedAt"`
EndCreatedAt *time.Time `form:"endCreatedAt"`
}
type AnnouncementResponse struct {
ID uint `json:"ID"`
CreatedAt time.Time `json:"CreatedAt"`
UpdatedAt time.Time `json:"UpdatedAt"`
// Keep the soft-delete slot in the transport shape while omitting it from
// JSON responses.
DeletedAt any `json:"-"`
Title string `json:"title"`
Content string `json:"content"`
UserID *int `json:"userID"`
Attachments any `json:"attachments"`
}
type SelectOptionResponse struct {
Label string `json:"label"`
Value uint `json:"value"`
}
-74
View File
@@ -1,74 +0,0 @@
package dto
import "time"
type APIRequest struct {
ID uint `json:"ID"`
Path string `json:"path"`
Description string `json:"description"`
APIGroup string `json:"apiGroup"`
Method string `json:"method"`
}
type APIListRequest struct {
Page int `json:"page"`
PageSize int `json:"pageSize"`
Path string `json:"path"`
Description string `json:"description"`
APIGroup string `json:"apiGroup"`
Method string `json:"method"`
OrderKey string `json:"orderKey"`
Desc bool `json:"desc"`
}
type APIResponse struct {
ID uint `json:"ID"`
CreatedAt time.Time `json:"CreatedAt"`
UpdatedAt time.Time `json:"UpdatedAt"`
DeletedAt any `json:"-"`
Path string `json:"path"`
Description string `json:"description"`
APIGroup string `json:"apiGroup"`
Method string `json:"method"`
}
type DeleteAPIRequest struct {
ID uint `json:"ID"`
}
type DeleteAPIsRequest struct {
IDs []uint `json:"ids"`
}
type GetAPIRequest struct {
ID uint `json:"id"`
}
type SetAPIRolesRequest struct {
Path string `json:"path"`
Method string `json:"method"`
AuthorityIDs []uint `json:"authorityIds"`
}
type IgnoreAPIRequest struct {
Path string `json:"path"`
Method string `json:"method"`
Flag bool `json:"flag"`
}
type ApplyAPISyncRequest struct {
NewAPIs []APIRequest `json:"newApis"`
DeleteAPIs []APIRequest `json:"deleteApis"`
}
type PolicyPathRequest struct {
Path string `json:"path"`
Method string `json:"method"`
}
type SetPolicyPathsRequest struct {
AuthorityID uint `json:"authorityId"`
Infos []PolicyPathRequest `json:"casbinInfos"`
}
type GetPolicyPathsRequest struct {
AuthorityID uint `json:"authorityId"`
}
type APISyncResponse struct {
NewAPIs []*APIResponse `json:"newApis"`
DeleteAPIs []*APIResponse `json:"deleteApis"`
IgnoreAPIs []*APIResponse `json:"ignoreApis"`
}
-186
View File
@@ -1,186 +0,0 @@
package dto
import "time"
type OperationRecordRequest struct {
IP string
Method string
Path string
Status int
LatencyMS int64
Agent string
ErrorMessage string
Body string
Response string
UserID uint
RequestID string
TraceID string
DeviceID string
}
type DataAccessRecordRequest struct {
EventType string
Operation string
UserID uint
AuthorityID uint
RequestID string
Method string
Path string
Detail string
}
type DataAccessListRequest struct {
Page int `json:"page"`
PageSize int `json:"pageSize"`
EventType string `json:"eventType"`
TargetTable string `json:"targetTable"`
}
type OperationRecordSearchRequest struct {
Page int `form:"page"`
PageSize int `form:"pageSize"`
Path string `form:"path"`
Method string `form:"method"`
Status int `form:"status"`
}
type LoginLogSearchRequest struct {
Page int `form:"page"`
PageSize int `form:"pageSize"`
Username string `form:"username"`
Status bool `form:"status"`
}
type AuditIDQuery struct {
ID uint `form:"ID"`
}
type AuditIDsRequest struct {
IDs []int `json:"ids"`
}
type ErrorRecordRequest struct {
Form string `json:"form"`
Info string `json:"info"`
Level string `json:"level"`
RequestID string `json:"request_id"`
TraceID string `json:"trace_id"`
Solution string `json:"solution"`
Status string `json:"status"`
}
// ErrorRecordMutationRequest mirrors the public error-record model. Pointer
// fields preserve the distinction between an omitted value and an explicitly
// supplied empty string, which is required by the update contract.
type ErrorRecordMutationRequest struct {
ID uint `json:"ID"`
CreatedAt time.Time `json:"CreatedAt"`
UpdatedAt time.Time `json:"UpdatedAt"`
Form *string `json:"form" binding:"required"`
Info *string `json:"info"`
Level string `json:"level"`
RequestID string `json:"request_id"`
TraceID string `json:"trace_id"`
Solution *string `json:"solution"`
Status string `json:"status"`
}
type OperationRecordResponse struct {
ID uint `json:"ID"`
CreatedAt time.Time `json:"CreatedAt"`
UpdatedAt time.Time `json:"UpdatedAt"`
DeletedAt any `json:"-"`
IP string `json:"ip"`
Method string `json:"method"`
Path string `json:"path"`
Status int `json:"status"`
LatencyMS int64 `json:"latency_ms"`
Agent string `json:"agent"`
ErrorMessage string `json:"error_message"`
Body string `json:"body"`
Response string `json:"resp"`
UserID uint `json:"user_id"`
RequestID string `json:"request_id"`
TraceID string `json:"trace_id"`
DeviceID string `json:"device_id"`
User any `json:"user"`
}
type LoginLogResponse struct {
ID uint `json:"ID"`
CreatedAt time.Time `json:"CreatedAt"`
UpdatedAt time.Time `json:"UpdatedAt"`
DeletedAt any `json:"-"`
Username string `json:"username"`
IP string `json:"ip"`
Status bool `json:"status"`
ErrorMessage string `json:"errorMessage"`
Agent string `json:"agent"`
UserID uint `json:"userId"`
User any `json:"user"`
}
type DataAccessLogResponse struct {
ID uint `json:"ID"`
CreatedAt time.Time `json:"CreatedAt"`
UpdatedAt time.Time `json:"UpdatedAt"`
DeletedAt any `json:"-"`
EventType string `json:"eventType"`
TargetTable string `json:"targetTable"`
Operation string `json:"operation"`
UserID uint `json:"userId"`
AuthorityID uint `json:"authorityId"`
Scope int `json:"scope"`
RequestID string `json:"requestId"`
Method string `json:"method"`
Path string `json:"path"`
Detail string `json:"detail"`
}
type ErrorRecordResponse struct {
ID uint `json:"ID"`
CreatedAt time.Time `json:"CreatedAt"`
UpdatedAt time.Time `json:"UpdatedAt"`
DeletedAt any `json:"-"`
Form *string `json:"form"`
Info *string `json:"info"`
Level string `json:"level"`
RequestID string `json:"request_id"`
TraceID string `json:"trace_id"`
Solution *string `json:"solution"`
Status string `json:"status"`
}
type LogDateResponse struct {
Date string `json:"date"`
FileCount int `json:"fileCount"`
}
type LogDatesResponse struct {
Month string `json:"month"`
Dates []*LogDateResponse `json:"dates"`
}
type LogFileResponse struct {
Path string `json:"path"`
Name string `json:"name"`
Size int64 `json:"size"`
ModifiedAt time.Time `json:"modifiedAt"`
}
type LogFilesResponse struct {
Date string `json:"date"`
Files []*LogFileResponse `json:"files"`
}
type LogContentResponse struct {
Date string `json:"date"`
Path string `json:"path"`
Content string `json:"content"`
LineCount int `json:"lineCount"`
NextCursor int64 `json:"nextCursor"`
HasMore bool `json:"hasMore"`
LimitedByBytes bool `json:"limitedByBytes"`
Size int64 `json:"size"`
ModifiedAt time.Time `json:"modifiedAt"`
}
-38
View File
@@ -1,38 +0,0 @@
package dto
import (
"net/http/httptest"
"strings"
"testing"
"github.com/gin-gonic/gin"
)
func bindErrorMutation(t *testing.T, body string) (ErrorRecordMutationRequest, error) {
t.Helper()
context, _ := gin.CreateTestContext(httptest.NewRecorder())
context.Request = httptest.NewRequest("PUT", "/sysError/updateSysError", strings.NewReader(body))
context.Request.Header.Set("Content-Type", "application/json")
var request ErrorRecordMutationRequest
return request, context.ShouldBindJSON(&request)
}
func TestErrorRecordMutationAcceptsExplicitEmptyPointerFields(t *testing.T) {
request, err := bindErrorMutation(t, `{"ID":1,"form":"","info":"","solution":""}`)
if err != nil {
t.Fatal(err)
}
if request.Form == nil || *request.Form != "" || request.Info == nil || *request.Info != "" || request.Solution == nil || *request.Solution != "" {
t.Fatalf("explicit empty values lost: form=%#v info=%#v solution=%#v", request.Form, request.Info, request.Solution)
}
}
func TestErrorRecordMutationRequiresFormButKeepsOtherFieldsOmittable(t *testing.T) {
request, err := bindErrorMutation(t, `{"ID":1}`)
if err == nil {
t.Fatal("missing form unexpectedly accepted")
}
if request.Info != nil || request.Solution != nil {
t.Fatalf("omitted fields = (%#v, %#v), want nil", request.Info, request.Solution)
}
}
-8
View File
@@ -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"`
}
-42
View File
@@ -1,42 +0,0 @@
package dto
import "time"
type AuthorityRequest struct {
AuthorityID uint `json:"authorityId"`
AuthorityName string `json:"authorityName"`
ParentID *uint `json:"parentId"`
DataScope int `json:"dataScope"`
DefaultRouter string `json:"defaultRouter"`
}
type CopyAuthorityRequest struct {
Authority AuthorityRequest `json:"authority"`
OldAuthorityID uint `json:"oldAuthorityId"`
}
type DeleteAuthorityRequest struct {
AuthorityID uint `json:"authorityId"`
}
type SetRoleUsersRequest struct {
AuthorityID uint `json:"authorityId" form:"authorityId"`
UserIDs []uint `json:"userIds" form:"userIds"`
}
type SetDataScopeRequest struct {
AuthorityID uint `json:"authorityId" form:"authorityId"`
DataScope int `json:"dataScope" form:"dataScope"`
DepartmentIDs []uint `json:"deptIds" form:"deptIds"`
}
type AuthorityResponse struct {
CreatedAt time.Time `json:"CreatedAt"`
UpdatedAt time.Time `json:"UpdatedAt"`
DeletedAt *time.Time `json:"DeletedAt"`
AuthorityID uint `json:"authorityId"`
AuthorityName string `json:"authorityName"`
ParentID *uint `json:"parentId"`
Children []*AuthorityResponse `json:"children"`
Menus []*MenuResponse `json:"menus"`
DataScope int `json:"dataScope"`
DefaultRouter string `json:"defaultRouter"`
}
-7
View File
@@ -1,7 +0,0 @@
package dto
type SendEmailRequest struct {
To string `json:"to"`
Subject string `json:"subject"`
Body string `json:"body"`
}
-75
View File
@@ -1,75 +0,0 @@
package dto
import "time"
type ExportConditionRequest struct {
ID uint `json:"ID"`
CreatedAt time.Time `json:"CreatedAt"`
UpdatedAt time.Time `json:"UpdatedAt"`
TemplateID string `json:"templateID"`
From string `json:"from"`
Column string `json:"column"`
Operator string `json:"operator"`
}
type ExportJoinRequest struct {
ID uint `json:"ID"`
CreatedAt time.Time `json:"CreatedAt"`
UpdatedAt time.Time `json:"UpdatedAt"`
TemplateID string `json:"templateID"`
Join string `json:"joins"`
Table string `json:"table"`
On string `json:"on"`
}
type ExportTemplateRequest struct {
ID uint `json:"ID"`
DBName string `json:"dbName"`
Name string `json:"name"`
TableName string `json:"tableName"`
TemplateID string `json:"templateID"`
TemplateInfo string `json:"templateInfo"`
SQL string `json:"sql"`
ImportSQL string `json:"importSql"`
Limit *int `json:"limit"`
Order string `json:"order"`
Conditions []ExportConditionRequest `json:"conditions"`
Joins []ExportJoinRequest `json:"joinTemplate"`
}
type ExportConditionResponse struct {
ID uint `json:"ID"`
CreatedAt time.Time `json:"CreatedAt"`
UpdatedAt time.Time `json:"UpdatedAt"`
TemplateID string `json:"templateID"`
From string `json:"from"`
Column string `json:"column"`
Operator string `json:"operator"`
}
type ExportJoinResponse struct {
ID uint `json:"ID"`
CreatedAt time.Time `json:"CreatedAt"`
UpdatedAt time.Time `json:"UpdatedAt"`
TemplateID string `json:"templateID"`
Join string `json:"joins"`
Table string `json:"table"`
On string `json:"on"`
}
type ExportTemplateResponse struct {
ID uint `json:"ID"`
CreatedAt time.Time `json:"CreatedAt"`
UpdatedAt time.Time `json:"UpdatedAt"`
// The compatible embedded gorm.DeletedAt field is json:"-".
DeletedAt any `json:"-"`
DBName string `json:"dbName"`
Name string `json:"name"`
TableName string `json:"tableName"`
TemplateID string `json:"templateID"`
TemplateInfo string `json:"templateInfo"`
SQL string `json:"sql"`
ImportSQL string `json:"importSql"`
Limit *int `json:"limit"`
Order string `json:"order"`
Conditions []ExportConditionResponse `json:"conditions"`
Joins []ExportJoinResponse `json:"joinTemplate"`
}
-102
View File
@@ -1,102 +0,0 @@
package dto
import "time"
type MediaResponse struct {
ID uint `json:"ID"`
CreatedAt time.Time `json:"CreatedAt"`
UpdatedAt time.Time `json:"UpdatedAt"`
// The compatible model embeds gorm.DeletedAt with json:"-", so this field is omitted.
DeletedAt any `json:"-"`
Name string `json:"name"`
ClassID int `json:"classId"`
URL string `json:"url"`
Tag string `json:"tag"`
Key string `json:"key"`
Size int64 `json:"size"`
Mime string `json:"mime"`
MD5 string `json:"md5"`
UserID uint `json:"userId"`
}
type MediaCategoryResponse struct {
ID uint `json:"ID"`
CreatedAt time.Time `json:"CreatedAt"`
UpdatedAt time.Time `json:"UpdatedAt"`
DeletedAt any `json:"-"`
Name string `json:"name"`
PID uint `json:"pid"`
Children []*MediaCategoryResponse `json:"children"`
}
type StorageObjectResponse struct {
Key string `json:"Key"`
Size int64 `json:"Size"`
LastModified time.Time `json:"LastModified"`
ContentType string `json:"ContentType"`
}
type InitUploadResponse struct {
Instant bool `json:"instant"`
UploadID uint `json:"uploadId"`
UploadedChunks []int `json:"uploadedChunks"`
Media *MediaResponse `json:"media,omitempty"`
}
type MediaListRequest struct {
Page int `json:"page"`
PageSize int `json:"pageSize"`
Keyword string `json:"keyword"`
ClassID int `json:"classId"`
Tag string `json:"tag"`
UserID uint `json:"userId"`
StartCreatedAt time.Time `json:"startCreatedAt"`
EndCreatedAt time.Time `json:"endCreatedAt"`
OrderKey string `json:"orderKey"`
Desc bool `json:"desc"`
}
type IDRequest struct {
ID uint `json:"ID" form:"id"`
}
type IDsRequest struct {
IDs []uint `json:"ids"`
}
type MediaBatchDeleteRequest struct {
IDs []uint `json:"ids" binding:"required"`
}
type RenameMediaRequest struct {
ID uint `json:"ID"`
Name string `json:"name"`
}
type ImportMediaRequest struct {
Name string `json:"name"`
ClassID int `json:"classId"`
URL string `json:"url"`
Tag string `json:"tag"`
Key string `json:"key"`
Size int64 `json:"size"`
Mime string `json:"mime"`
MD5 string `json:"md5"`
UserID uint `json:"userId"`
}
type StorageListRequest struct {
Prefix string `json:"prefix"`
Cursor string `json:"cursor"`
Limit int `json:"limit"`
}
type CategoryRequest struct {
ID uint `json:"ID"`
Name string `json:"name"`
PID uint `json:"pid"`
}
type InitUploadRequest struct {
FileName string `json:"fileName" binding:"required"`
FileHash string `json:"fileHash" binding:"required"`
FileSize int64 `json:"fileSize" binding:"required"`
ChunkSize int64 `json:"chunkSize" binding:"required"`
ChunkTotal int `json:"chunkTotal" binding:"required"`
Mime string `json:"mime"`
}
type CompleteUploadRequest struct {
UploadID uint `json:"uploadId" binding:"required"`
}
-143
View File
@@ -1,143 +0,0 @@
package dto
import "time"
type MenuMetaRequest struct {
ActiveName string `json:"activeName"`
KeepAlive bool `json:"keepAlive"`
DefaultMenu bool `json:"defaultMenu"`
Title string `json:"title"`
Icon string `json:"icon"`
CloseTab bool `json:"closeTab"`
TransitionType string `json:"transitionType"`
}
type MenuButtonRequest struct {
CreatedAt time.Time `json:"CreatedAt"`
UpdatedAt time.Time `json:"UpdatedAt"`
ID uint `json:"ID"`
Name string `json:"name"`
Description string `json:"desc"`
SysBaseMenuID uint `json:"sysBaseMenuID"`
}
type MenuParameterRequest struct {
CreatedAt time.Time `json:"CreatedAt"`
UpdatedAt time.Time `json:"UpdatedAt"`
ID uint `json:"ID"`
SysBaseMenuID uint `json:"SysBaseMenuID"`
Type string `json:"type"`
Key string `json:"key"`
Value string `json:"value"`
}
type MenuRequest struct {
CreatedAt time.Time `json:"CreatedAt"`
UpdatedAt time.Time `json:"UpdatedAt"`
ID uint `json:"ID"`
ParentID uint `json:"parentId"`
Path string `json:"path"`
Name string `json:"name"`
Hidden bool `json:"hidden"`
Component string `json:"component"`
Sort int `json:"sort"`
Meta MenuMetaRequest `json:"meta"`
MenuButtons []MenuButtonRequest `json:"menuBtn"`
Parameters []MenuParameterRequest `json:"parameters"`
}
type DeleteMenuRequest struct {
ID int `json:"id"`
}
type GetMenuRequest struct {
ID int `json:"id"`
}
type SetAuthorityMenusRequest struct {
AuthorityID uint `json:"authorityId"`
Menus []MenuRequest `json:"menus"`
}
type GetAuthorityMenusRequest struct {
AuthorityID uint `json:"authorityId"`
}
type SetMenuRolesRequest struct {
MenuID uint `json:"menuId" form:"menuId"`
AuthorityIDs []uint `json:"authorityIds"`
}
type MenuMetaResponse struct {
ActiveName string `json:"activeName"`
KeepAlive bool `json:"keepAlive"`
DefaultMenu bool `json:"defaultMenu"`
Title string `json:"title"`
Icon string `json:"icon"`
CloseTab bool `json:"closeTab"`
TransitionType string `json:"transitionType"`
}
type MenuButtonResponse struct {
CreatedAt time.Time `json:"CreatedAt"`
UpdatedAt time.Time `json:"UpdatedAt"`
ID uint `json:"ID"`
Name string `json:"name"`
Description string `json:"desc"`
SysBaseMenuID uint `json:"sysBaseMenuID"`
}
type MenuParameterResponse struct {
CreatedAt time.Time `json:"CreatedAt"`
UpdatedAt time.Time `json:"UpdatedAt"`
ID uint `json:"ID"`
SysBaseMenuID uint `json:"SysBaseMenuID"`
Type string `json:"type"`
Key string `json:"key"`
Value string `json:"value"`
}
type MenuResponse struct {
CreatedAt time.Time `json:"CreatedAt"`
UpdatedAt time.Time `json:"UpdatedAt"`
ID uint `json:"ID"`
MenuID uint `json:"menuId,omitempty"`
ParentID uint `json:"parentId"`
Path string `json:"path"`
Name string `json:"name"`
Hidden bool `json:"hidden"`
Component string `json:"component"`
Sort int `json:"sort"`
Meta MenuMetaResponse `json:"meta"`
Children []*MenuResponse `json:"children"`
Parameters []MenuParameterResponse `json:"parameters"`
MenuButtons []MenuButtonResponse `json:"menuBtn"`
Authorities []*AuthorityResponse `json:"authoritys"`
}
type DynamicMenuResponse struct {
CreatedAt time.Time `json:"CreatedAt"`
UpdatedAt time.Time `json:"UpdatedAt"`
ID uint `json:"ID"`
MenuID uint `json:"menuId"`
ParentID uint `json:"parentId"`
Path string `json:"path"`
Name string `json:"name"`
Hidden bool `json:"hidden"`
Component string `json:"component"`
Sort int `json:"sort"`
Meta MenuMetaResponse `json:"meta"`
Children []*DynamicMenuResponse `json:"children"`
Parameters []MenuParameterResponse `json:"parameters"`
MenuButtons []MenuButtonResponse `json:"menuBtn"`
Buttons map[string]uint `json:"btns"`
Authorities []*AuthorityResponse `json:"authoritys"`
}
type AuthorityMenuResponse struct {
// The administration response embeds the base-menu fields, so menu fields are
// flat in the response (there is no sysBaseMenu envelope). Keep the
// authority ID internal, matching the compatible json:"-" field.
*DynamicMenuResponse
AuthorityID uint `json:"-"`
}
-84
View File
@@ -1,84 +0,0 @@
package dto
import "time"
type DepartmentRequest struct {
ID uint `json:"ID"`
Name string `json:"name"`
ParentID uint `json:"parentId"`
Sort int `json:"sort"`
LeaderID uint `json:"leaderId"`
Status *bool `json:"status"`
}
type DepartmentListRequest struct {
Name string `json:"name"`
}
type DeleteDepartmentRequest struct {
ID uint `json:"ID" form:"id"`
}
type SetDepartmentUsersRequest struct {
DepartmentID uint `json:"deptId" form:"deptId"`
UserIDs []uint `json:"userIds"`
}
type SetUserDepartmentsRequest struct {
ID uint `json:"ID"`
DepartmentIDs []uint `json:"deptIds"`
Primary uint `json:"primaryDeptId"`
}
type DepartmentResponse struct {
ID uint `json:"ID"`
CreatedAt time.Time `json:"CreatedAt"`
UpdatedAt time.Time `json:"UpdatedAt"`
DeletedAt any `json:"-"`
Name string `json:"name"`
ParentID uint `json:"parentId"`
Ancestors string `json:"ancestors"`
Sort int `json:"sort"`
LeaderID uint `json:"leaderId"`
Leader any `json:"leader"`
Status *bool `json:"status"`
Children []*DepartmentResponse `json:"children"`
NamePath string `json:"namePath"`
}
type PositionRequest struct {
ID uint `json:"ID"`
Name string `json:"name"`
Code string `json:"code"`
Sort int `json:"sort"`
Status *bool `json:"status"`
Remark string `json:"remark"`
}
type PositionListRequest struct {
Page int `json:"page"`
PageSize int `json:"pageSize"`
Name string `json:"name"`
Code string `json:"code"`
Status *bool `json:"status"`
}
type DeletePositionRequest struct {
ID uint `json:"ID" form:"id"`
}
type SetPositionUsersRequest struct {
PositionID uint `json:"positionId" form:"positionId"`
UserIDs []uint `json:"userIds"`
}
type SetUserPositionsRequest struct {
ID uint `json:"ID"`
PositionIDs []uint `json:"positionIds"`
}
type PositionResponse struct {
ID uint `json:"ID"`
CreatedAt time.Time `json:"CreatedAt"`
UpdatedAt time.Time `json:"UpdatedAt"`
DeletedAt any `json:"-"`
Name string `json:"name"`
Code string `json:"code"`
Sort int `json:"sort"`
Status *bool `json:"status"`
Remark string `json:"remark"`
}
-132
View File
@@ -1,132 +0,0 @@
package dto
import (
"encoding/json"
"time"
)
type PaymentConfigRequest struct {
Provider string `json:"provider"`
Enabled bool `json:"enabled"`
Config json.RawMessage `json:"config"`
}
// PaymentConfigResponse is the transport representation returned by the
// payment configuration endpoint. Values are already masked by the usecase's
// repository boundary.
type PaymentConfigResponse struct {
Provider string `json:"provider"`
Enabled bool `json:"enabled"`
Config json.RawMessage `json:"config"`
}
type PaymentOrderListRequest struct {
Page int `form:"page"`
PageSize int `form:"pageSize"`
Provider string `form:"provider"`
TradeNo string `form:"tradeNo"`
BusinessType string `form:"businessType"`
BusinessID string `form:"businessId"`
PaymentStatus string `form:"paymentStatus"`
RefundStatus string `form:"refundStatus"`
}
type PaymentRequest struct {
Provider string `json:"provider"`
TradeNo string `json:"tradeNo"`
Subject string `json:"subject"`
Amount int64 `json:"amount"`
OriginalAmount int64 `json:"originalAmount"`
Currency string `json:"currency"`
NotifyURL string `json:"notifyUrl"`
ReturnURL string `json:"returnUrl"`
Extra map[string]any `json:"extra"`
ClientIP string `json:"-"`
BusinessType string `json:"businessType"`
BusinessID string `json:"businessId"`
PaymentMode string `json:"paymentMode"`
}
type PaymentQueryRequest struct {
Provider string `json:"provider"`
TradeNo string `json:"tradeNo"`
}
type PaymentRefundRequest struct {
Provider string `json:"provider"`
TradeNo string `json:"tradeNo"`
Amount int64 `json:"amount"`
}
// PaymentCallbackRequest is populated by the HTTP transport and converted to
// the biz callback object inside service.
type PaymentCallbackRequest struct {
Provider string
Headers map[string]string
Body []byte
Query map[string]string
}
type PaymentCallbackAck struct {
StatusCode int
ContentType string
Body []byte
}
type PaymentResultResponse struct {
Provider string `json:"provider"`
Status string `json:"status"`
TradeNo string `json:"tradeNo"`
ProviderTradeNo string `json:"providerTradeNo"`
Amount int64 `json:"amount"`
PayerPaidAmount int64 `json:"payerPaidAmount,omitempty"`
CashPaidAmount int64 `json:"cashPaidAmount,omitempty"`
PointPaidAmount int64 `json:"pointPaidAmount,omitempty"`
DiscountAmount int64 `json:"discountAmount,omitempty"`
ProviderDiscountAmount int64 `json:"providerDiscountAmount,omitempty"`
MerchantDiscountAmount int64 `json:"merchantDiscountAmount,omitempty"`
SettlementAmount int64 `json:"settlementAmount,omitempty"`
Currency string `json:"currency"`
PayerCurrency string `json:"payerCurrency,omitempty"`
AmountBreakdownKnown bool `json:"amountBreakdownKnown"`
Duplicate bool `json:"duplicate"`
Payload json.RawMessage `json:"payload"`
OrderStatus string `json:"orderStatus,omitempty"`
FulfillmentStatus string `json:"fulfillmentStatus,omitempty"`
RefundStatus string `json:"refundStatus,omitempty"`
}
type PaymentOrderResponse struct {
ID uint64 `json:"ID"`
Provider string `json:"provider"`
TradeNo string `json:"tradeNo"`
ProviderTradeNo string `json:"providerTradeNo"`
BusinessType string `json:"businessType"`
BusinessID string `json:"businessId"`
Subject string `json:"subject"`
PaymentMode string `json:"paymentMode"`
OriginalAmount int64 `json:"originalAmount"`
Amount int64 `json:"amount"`
PaidAmount int64 `json:"paidAmount"`
PayerPaidAmount int64 `json:"payerPaidAmount"`
CashPaidAmount int64 `json:"cashPaidAmount"`
PointPaidAmount int64 `json:"pointPaidAmount"`
DiscountAmount int64 `json:"discountAmount"`
ProviderDiscountAmount int64 `json:"providerDiscountAmount"`
MerchantDiscountAmount int64 `json:"merchantDiscountAmount"`
SettlementAmount int64 `json:"settlementAmount"`
Currency string `json:"currency"`
PayerCurrency string `json:"payerCurrency,omitempty"`
AmountBreakdownKnown bool `json:"amountBreakdownKnown"`
PaymentStatus string `json:"paymentStatus"`
ProviderStatus string `json:"providerStatus"`
FulfillmentStatus string `json:"fulfillmentStatus"`
RefundStatus string `json:"refundStatus"`
RefundedAmount int64 `json:"refundedAmount"`
RefundRequestedAmount int64 `json:"refundRequestedAmount"`
RefundNo string `json:"refundNo,omitempty"`
LastError string `json:"lastError,omitempty"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
PaidAt *time.Time `json:"paidAt,omitempty"`
FulfilledAt *time.Time `json:"fulfilledAt,omitempty"`
RefundedAt *time.Time `json:"refundedAt,omitempty"`
}
-13
View File
@@ -1,13 +0,0 @@
package dto
type GetAuthorityButtonsRequest struct {
MenuID uint `json:"menuID"`
AuthorityID uint `json:"authorityId"`
Selected []uint `json:"selected"`
}
type SetAuthorityButtonsRequest struct {
MenuID uint `json:"menuID"`
AuthorityID uint `json:"authorityId"`
Selected []uint `json:"selected"`
}
-172
View File
@@ -1,172 +0,0 @@
package dto
import "time"
type DictionaryRequest struct {
ID uint `json:"ID" form:"ID"`
Name string `json:"name" form:"name"`
Type string `json:"type" form:"type"`
Status *bool `json:"status" form:"status"`
Description string `json:"desc" form:"desc"`
ParentID *uint `json:"parentID" form:"parentID"`
}
type DictionaryDetailRequest struct {
ID uint `json:"ID" form:"ID"`
Label string `json:"label" form:"label"`
Value string `json:"value" form:"value"`
Extend string `json:"extend" form:"extend"`
Status *bool `json:"status" form:"status"`
Sort int `json:"sort" form:"sort"`
DictionaryID uint `json:"sysDictionaryID" form:"sysDictionaryID"`
ParentID *uint `json:"parentID" form:"parentID"`
Level int `json:"level"`
Path string `json:"path"`
}
type ImportDictionaryRequest struct {
JSON string `json:"json"`
}
type DictionaryDetailsByParentRequest struct {
DictionaryID uint `json:"sysDictionaryID" form:"sysDictionaryID" binding:"required"`
ParentID *uint `json:"parentID" form:"parentID"`
IncludeChildren bool `json:"includeChildren" form:"includeChildren"`
}
type DictionaryDetailListRequest struct {
DictionaryID uint
Label string
Value string
Status *bool
ParentID *uint
Level *int
}
type SystemParameterRequest struct {
ID uint `json:"ID" form:"ID"`
CreatedAt time.Time `json:"CreatedAt" form:"CreatedAt"`
UpdatedAt time.Time `json:"UpdatedAt" form:"UpdatedAt"`
Name string `json:"name" form:"name" binding:"required"`
Key string `json:"key" form:"key" binding:"required"`
Value string `json:"value" form:"value" binding:"required"`
Description string `json:"desc" form:"desc"`
}
type SystemParameterSearchRequest struct {
Page int `json:"page" form:"page"`
PageSize int `json:"pageSize" form:"pageSize"`
StartCreatedAt *time.Time `json:"startCreatedAt" form:"startCreatedAt"`
EndCreatedAt *time.Time `json:"endCreatedAt" form:"endCreatedAt"`
Name string `json:"name" form:"name"`
Key string `json:"key" form:"key"`
}
type CreateAPITokenRequest struct {
UserID uint `json:"userId"`
AuthorityID uint `json:"authorityId"`
Days int `json:"days"`
Remark string `json:"remark"`
}
type APITokenListRequest struct {
Page int `json:"page"`
PageSize int `json:"pageSize"`
UserID uint `json:"userId"`
Status *bool `json:"status"`
}
type APITokenResponse struct {
ID uint `json:"ID"`
CreatedAt time.Time `json:"CreatedAt"`
UpdatedAt time.Time `json:"UpdatedAt"`
DeletedAt any `json:"-"`
UserID uint `json:"userId"`
AuthorityID uint `json:"authorityId"`
Token string `json:"token"`
Status bool `json:"status"`
ExpiresAt time.Time `json:"expiresAt"`
Remark string `json:"remark"`
User *UserResponse `json:"user"`
}
type SecurityConfigResponse struct {
ID uint `json:"ID"`
CreatedAt time.Time `json:"CreatedAt"`
UpdatedAt time.Time `json:"UpdatedAt"`
DeletedAt any `json:"-"`
CaptchaOpen int `json:"captchaOpen"`
CaptchaTimeout int `json:"captchaTimeout"`
KeyLong int `json:"keyLong"`
ImgWidth int `json:"imgWidth"`
ImgHeight int `json:"imgHeight"`
PwdMinLength int `json:"pwdMinLength"`
PwdRequireUpper bool `json:"pwdRequireUpper"`
PwdRequireLower bool `json:"pwdRequireLower"`
PwdRequireDigit bool `json:"pwdRequireDigit"`
PwdRequireSpecial bool `json:"pwdRequireSpecial"`
LimitEnable bool `json:"limitEnable"`
LimitWindow int `json:"limitWindow"`
LimitCount int `json:"limitCount"`
LockEnable bool `json:"lockEnable"`
LockThreshold int `json:"lockThreshold"`
LockDuration int `json:"lockDuration"`
PwdExpireEnable bool `json:"pwdExpireEnable"`
PwdExpireDays int `json:"pwdExpireDays"`
ForceNewUserChangePassword bool `json:"forceNewUserChangePassword"`
}
type SystemParameterResponse struct {
ID uint `json:"ID"`
CreatedAt time.Time `json:"CreatedAt"`
UpdatedAt time.Time `json:"UpdatedAt"`
DeletedAt any `json:"-"`
Name string `json:"name"`
Key string `json:"key"`
Value string `json:"value"`
Desc string `json:"desc"`
}
type DictionaryResponse struct {
ID uint `json:"ID"`
CreatedAt time.Time `json:"CreatedAt"`
UpdatedAt time.Time `json:"UpdatedAt"`
DeletedAt any `json:"-"`
Name string `json:"name"`
Type string `json:"type"`
Status *bool `json:"status"`
Desc string `json:"desc"`
ParentID *uint `json:"parentID"`
Children []*DictionaryResponse `json:"children"`
SysDictionaryDetails []*DictionaryDetailResponse `json:"sysDictionaryDetails"`
}
type DictionaryDetailResponse struct {
ID uint `json:"ID"`
CreatedAt time.Time `json:"CreatedAt"`
UpdatedAt time.Time `json:"UpdatedAt"`
DeletedAt any `json:"-"`
Label string `json:"label"`
Value string `json:"value"`
Extend string `json:"extend"`
Status *bool `json:"status"`
Sort int `json:"sort"`
DictionaryID uint `json:"sysDictionaryID"`
ParentID *uint `json:"parentID"`
Level int `json:"level"`
Path string `json:"path"`
Disabled bool `json:"disabled"`
Children []*DictionaryDetailResponse `json:"children"`
}
type DictionaryExportResponse struct {
Name string `json:"name"`
Type string `json:"type"`
Status *bool `json:"status"`
Desc string `json:"desc"`
SysDictionaryDetails []*DictionaryDetailExportResponse `json:"sysDictionaryDetails"`
}
type DictionaryDetailExportResponse struct {
Label string `json:"label"`
Value string `json:"value"`
Extend string `json:"extend"`
Status *bool `json:"status"`
Sort int `json:"sort"`
Level int `json:"level"`
Path string `json:"path"`
}
-133
View File
@@ -1,133 +0,0 @@
package dto
import "time"
type LoginRequest struct {
Username string `json:"username"`
Password string `json:"password"`
Captcha string `json:"captcha"`
CaptchaID string `json:"captchaId"`
}
type Route struct {
Path string
Method string
}
type UserListRequest struct {
Page int `json:"page"`
PageSize int `json:"pageSize"`
Username string `json:"username"`
NickName string `json:"nickName"`
Phone string `json:"phone"`
Email string `json:"email"`
OrderKey string `json:"orderKey"`
Desc bool `json:"desc"`
}
type UserRequest struct {
ID uint `json:"ID" form:"id"`
Username string `json:"userName"`
Password string `json:"passWord"`
NickName string `json:"nickName"`
HeaderImg string `json:"headerImg"`
AuthorityID uint `json:"authorityId"`
AuthorityIDs []uint `json:"authorityIds"`
Enable int `json:"enable"`
Phone string `json:"phone"`
Email string `json:"email"`
}
type SelfUserRequest struct {
NickName string `json:"nickName"`
HeaderImg string `json:"headerImg"`
Phone string `json:"phone"`
Email string `json:"email"`
Enable int `json:"enable"`
}
type ResetPasswordRequest struct {
ID uint `json:"ID"`
Password string `json:"password"`
}
type ChangePasswordRequest struct {
Password string `json:"password"`
NewPassword string `json:"newPassword"`
}
type UserAuthoritiesRequest struct {
ID uint `json:"ID"`
AuthorityIDs []uint `json:"authorityIds"`
}
type SwitchAuthorityRequest struct {
AuthorityID uint `json:"authorityId"`
}
type LoginLogRequest struct {
Username string
IP string
Status bool
ErrorMessage string
Agent string
UserID uint
}
type UserResponse struct {
ID uint `json:"ID"`
CreatedAt time.Time `json:"CreatedAt"`
UpdatedAt time.Time `json:"UpdatedAt"`
DeletedAt any `json:"-"`
UUID string `json:"uuid"`
Username string `json:"userName"`
NickName string `json:"nickName"`
HeaderImg string `json:"headerImg"`
AuthorityID uint `json:"authorityId"`
Authority *AuthorityResponse `json:"authority"`
Authorities []*AuthorityResponse `json:"authorities"`
DeptID uint `json:"deptId"`
Department any `json:"dept"`
Departments []*DepartmentResponse `json:"departments"`
Positions []*PositionResponse `json:"positions"`
Phone string `json:"phone"`
Email string `json:"email"`
Enable int `json:"enable"`
OriginSetting map[string]any `json:"originSetting"`
PasswordUpdatedAt *time.Time `json:"passwordUpdatedAt"`
}
type ServerInfoResponse struct {
OS ServerOSResponse `json:"os"`
CPU ServerCPUResponse `json:"cpu"`
RAM ServerRAMResponse `json:"ram"`
Disk []ServerDiskResponse `json:"disk"`
}
type ServerOSResponse struct {
GOOS string `json:"goos"`
NumCPU int `json:"numCpu"`
Compiler string `json:"compiler"`
GoVersion string `json:"goVersion"`
NumGoroutine int `json:"numGoroutine"`
}
type ServerCPUResponse struct {
CPUs []float64 `json:"cpus"`
Cores int `json:"cores"`
}
type ServerRAMResponse struct {
UsedMB uint64 `json:"usedMb"`
TotalMB uint64 `json:"totalMb"`
UsedPercent int `json:"usedPercent"`
}
type ServerDiskResponse struct {
MountPoint string `json:"mountPoint"`
UsedMB uint64 `json:"usedMb"`
UsedGB uint64 `json:"usedGb"`
TotalMB uint64 `json:"totalMb"`
TotalGB uint64 `json:"totalGb"`
UsedPercent int `json:"usedPercent"`
}
-30
View File
@@ -1,30 +0,0 @@
package dto
import "encoding/json"
type SecurityConfigRequest struct {
ID uint `json:"ID"`
CaptchaOpen int `json:"captchaOpen"`
CaptchaTimeout int `json:"captchaTimeout"`
KeyLong int `json:"keyLong"`
ImgWidth int `json:"imgWidth"`
ImgHeight int `json:"imgHeight"`
PwdMinLength int `json:"pwdMinLength"`
PwdRequireUpper bool `json:"pwdRequireUpper"`
PwdRequireLower bool `json:"pwdRequireLower"`
PwdRequireDigit bool `json:"pwdRequireDigit"`
PwdRequireSpecial bool `json:"pwdRequireSpecial"`
LimitEnable bool `json:"limitEnable"`
LimitWindow int `json:"limitWindow"`
LimitCount int `json:"limitCount"`
LockEnable bool `json:"lockEnable"`
LockThreshold int `json:"lockThreshold"`
LockDuration int `json:"lockDuration"`
PwdExpireEnable bool `json:"pwdExpireEnable"`
PwdExpireDays int `json:"pwdExpireDays"`
ForceNewUserChangePassword bool `json:"forceNewUserChangePassword"`
}
type SetSystemConfigRequest struct {
Config json.RawMessage `json:"config"`
}
-13
View File
@@ -1,13 +0,0 @@
package dto
type DatabaseInitRequest struct {
DBType string `json:"dbType"`
Host string `json:"host"`
Port string `json:"port"`
UserName string `json:"userName"`
Password string `json:"password"`
DBName string `json:"dbName" binding:"required"`
DBPath string `json:"dbPath"`
Template string `json:"template"`
AdminPassword string `json:"adminPassword" binding:"required"`
}
-88
View File
@@ -1,88 +0,0 @@
package dto
import (
"encoding/json"
"time"
)
type TaskRequest struct {
ID uint `json:"ID"`
Name string `json:"name"`
Description string `json:"description"`
Spec string `json:"spec"`
WithSeconds bool `json:"withSeconds"`
ExecutorType string `json:"executorType"`
MethodName string `json:"methodName"`
Params json.RawMessage `json:"params"`
HTTPURL string `json:"httpUrl"`
HTTPMethod string `json:"httpMethod"`
HTTPHeader json.RawMessage `json:"httpHeader"`
HTTPBody string `json:"httpBody"`
HTTPAllowPrivate bool `json:"httpAllowPrivate"`
Enabled bool `json:"enabled"`
}
type DeleteTaskRequest struct {
ID uint `json:"ID" binding:"required"`
}
type ToggleTaskRequest struct {
ID uint `json:"ID" binding:"required"`
Enabled bool `json:"enabled"`
}
type TaskListRequest struct {
Page int `form:"page"`
PageSize int `form:"pageSize"`
Name string `form:"name"`
ExecutorType string `form:"executorType"`
Enabled *bool `form:"enabled"`
}
type TaskLogListRequest struct {
Page int `form:"page"`
PageSize int `form:"pageSize"`
TaskID uint `form:"taskId"`
Status string `form:"status"`
}
type TaskResponse struct {
ID uint `json:"ID"`
CreatedAt time.Time `json:"CreatedAt"`
UpdatedAt time.Time `json:"UpdatedAt"`
DeletedAt any `json:"-"`
Name string `json:"name"`
Description string `json:"description"`
Spec string `json:"spec"`
WithSeconds bool `json:"withSeconds"`
ExecutorType string `json:"executorType"`
MethodName string `json:"methodName"`
Params json.RawMessage `json:"params"`
HTTPURL string `json:"httpUrl"`
HTTPMethod string `json:"httpMethod"`
HTTPHeader json.RawMessage `json:"httpHeader"`
HTTPBody string `json:"httpBody"`
HTTPAllowPrivate bool `json:"httpAllowPrivate"`
Enabled bool `json:"enabled"`
NextRunAt *time.Time `json:"nextRunAt"`
}
type TaskLogResponse struct {
ID uint `json:"ID"`
CreatedAt time.Time `json:"CreatedAt"`
UpdatedAt time.Time `json:"UpdatedAt"`
DeletedAt any `json:"-"`
TaskID uint `json:"taskId"`
TaskName string `json:"taskName"`
TriggerType string `json:"triggerType"`
StartedAt time.Time `json:"startedAt"`
FinishedAt time.Time `json:"finishedAt"`
DurationMS int64 `json:"durationMs"`
Status string `json:"status"`
ErrorMsg string `json:"errorMsg"`
Output string `json:"output"`
}
type TaskMethodResponse struct {
Name string `json:"name"`
Description string `json:"description"`
}
-94
View File
@@ -1,94 +0,0 @@
package dto
import "time"
type VersionResponse struct {
ID uint `json:"ID"`
CreatedAt time.Time `json:"CreatedAt"`
UpdatedAt time.Time `json:"UpdatedAt"`
DeletedAt any `json:"-"`
VersionName *string `json:"versionName"`
VersionCode *string `json:"versionCode"`
Description *string `json:"description"`
VersionData *string `json:"versionData"`
}
type VersionSearchRequest struct {
CreatedAtRange []time.Time `json:"createdAtRange" form:"createdAtRange[]"`
VersionName *string `json:"versionName" form:"versionName"`
VersionCode *string `json:"versionCode" form:"versionCode"`
Page int `json:"page" form:"page"`
PageSize int `json:"pageSize" form:"pageSize"`
}
type VersionMenuMetaRequest struct {
ActiveName string `json:"activeName"`
KeepAlive bool `json:"keepAlive"`
DefaultMenu bool `json:"defaultMenu"`
Title string `json:"title"`
Icon string `json:"icon"`
CloseTab bool `json:"closeTab"`
TransitionType string `json:"transitionType"`
}
type VersionMenuButtonRequest struct {
Name string `json:"name"`
Description string `json:"desc"`
}
type VersionMenuParameterRequest struct {
Type string `json:"type"`
Key string `json:"key"`
Value string `json:"value"`
}
type VersionMenuRequest struct {
Path string `json:"path"`
Name string `json:"name"`
Hidden bool `json:"hidden"`
Component string `json:"component"`
Sort int `json:"sort"`
Meta VersionMenuMetaRequest `json:"meta"`
MenuButtons []VersionMenuButtonRequest `json:"menuBtn"`
Parameters []VersionMenuParameterRequest `json:"parameters"`
Children []VersionMenuRequest `json:"children"`
}
type VersionAPIRequest struct {
Path string `json:"path"`
Description string `json:"description"`
APIGroup string `json:"apiGroup"`
Method string `json:"method"`
}
type VersionDictionaryDetailRequest struct {
Label string `json:"label"`
Value string `json:"value"`
Extend string `json:"extend"`
Status *bool `json:"status"`
Sort int `json:"sort"`
ParentID *uint `json:"parentID"`
Level int `json:"level"`
Path string `json:"path"`
}
type VersionDictionaryRequest struct {
Name string `json:"name"`
Type string `json:"type"`
Status *bool `json:"status"`
Description string `json:"desc"`
Details []VersionDictionaryDetailRequest `json:"sysDictionaryDetails"`
}
type ImportVersionRequest struct {
Version struct {
Name string `json:"name" binding:"required"`
Code string `json:"code" binding:"required"`
Description string `json:"description"`
ExportTime string `json:"exportTime"`
} `json:"version" binding:"required"`
Menus []VersionMenuRequest `json:"menus"`
APIs []VersionAPIRequest `json:"apis"`
Dictionaries []VersionDictionaryRequest `json:"dictionaries"`
}
type ExportVersionRequest struct {
VersionName string `json:"versionName" binding:"required"`
VersionCode string `json:"versionCode" binding:"required"`
Description string `json:"description"`
MenuIDs []uint `json:"menuIds"`
APIIDs []uint `json:"apiIds"`
DictIDs []uint `json:"dictIds"`
}
-20
View File
@@ -1,20 +0,0 @@
package service
import (
"context"
"kra/internal/biz"
)
type EmailService struct{ uc *biz.EmailUsecase }
func NewEmailService(uc *biz.EmailUsecase) *EmailService { return &EmailService{uc: uc} }
func (s *EmailService) Test(ctx context.Context) error { return s.uc.Test(ctx) }
func (s *EmailService) Send(ctx context.Context, to, subject, body string) error {
return s.uc.Send(ctx, to, subject, body)
}
func (s *EmailService) Alert(ctx context.Context, subject, body string) error {
return s.uc.Alert(ctx, subject, body)
}
-132
View File
@@ -1,132 +0,0 @@
package service
import (
"context"
"encoding/json"
"errors"
"strings"
"time"
"kra/internal/biz"
"kra/internal/service/dto"
"github.com/google/uuid"
)
var (
ErrExportTokenInvalid = errors.New("export token invalid")
ErrExportTokenMalformed = errors.New("export token malformed")
ErrExportTokenType = errors.New("export token type mismatch")
)
type ExportService struct {
uc *biz.ExportUsecase
cache biz.Cache
}
type ExportToken struct {
TemplateID string
Params map[string]string
Blank bool
}
type exportTokenCache struct {
TemplateID string `json:"templateID"`
Params map[string]string `json:"params"`
Blank bool `json:"blank"`
}
func NewExportService(uc *biz.ExportUsecase, cache biz.Cache) *ExportService {
return &ExportService{uc: uc, cache: cache}
}
func (s *ExportService) IssueToken(ctx context.Context, templateID string, params map[string]string, blank bool) (string, error) {
token := strings.ReplaceAll(uuid.NewString(), "-", "")
raw, err := json.Marshal(exportTokenCache{TemplateID: templateID, Params: params, Blank: blank})
if err != nil {
return "", err
}
if err = s.cache.Set(ctx, "export:"+token, string(raw), 30*time.Minute); err != nil {
return "", err
}
return token, nil
}
func (s *ExportService) ConsumeToken(ctx context.Context, token string, expectBlank bool) (*ExportToken, error) {
raw, ok, err := s.cache.Get(ctx, "export:"+token)
if err != nil || !ok {
return nil, ErrExportTokenInvalid
}
var value exportTokenCache
if json.Unmarshal([]byte(raw), &value) != nil {
return nil, ErrExportTokenMalformed
}
if value.Blank != expectBlank {
return nil, ErrExportTokenType
}
_ = s.cache.Delete(ctx, "export:"+token)
return &ExportToken{TemplateID: value.TemplateID, Params: value.Params, Blank: value.Blank}, nil
}
func exportTemplateDomain(value *dto.ExportTemplateRequest) *biz.ExportTemplate {
out := &biz.ExportTemplate{ID: value.ID, DBName: value.DBName, Name: value.Name, TableName: value.TableName, TemplateID: value.TemplateID, TemplateInfo: value.TemplateInfo, SQL: value.SQL, ImportSQL: value.ImportSQL, Limit: value.Limit, Order: value.Order}
for _, item := range value.Conditions {
out.Conditions = append(out.Conditions, biz.ExportCondition{ID: item.ID, CreatedAt: item.CreatedAt, UpdatedAt: item.UpdatedAt, TemplateID: item.TemplateID, From: item.From, Column: item.Column, Operator: item.Operator})
}
for _, item := range value.Joins {
out.Joins = append(out.Joins, biz.ExportJoin{ID: item.ID, CreatedAt: item.CreatedAt, UpdatedAt: item.UpdatedAt, TemplateID: item.TemplateID, Join: item.Join, Table: item.Table, On: item.On})
}
return out
}
func (s *ExportService) CreateRequest(ctx context.Context, req *dto.ExportTemplateRequest) error {
return s.Create(ctx, exportTemplateDomain(req))
}
func (s *ExportService) UpdateRequest(ctx context.Context, req *dto.ExportTemplateRequest) error {
return s.Update(ctx, exportTemplateDomain(req))
}
func (s *ExportService) TemplatesFilter(ctx context.Context, page, size int, name, tableName, templateID string, start, end *time.Time) ([]*dto.ExportTemplateResponse, int64, error) {
return s.Templates(ctx, page, size, &biz.ExportTemplate{Name: name, TableName: tableName, TemplateID: templateID, StartCreatedAt: start, EndCreatedAt: end})
}
func exportDTO(v *biz.ExportTemplate) *dto.ExportTemplateResponse {
var conditions []dto.ExportConditionResponse
if v.Conditions != nil {
conditions = make([]dto.ExportConditionResponse, 0, len(v.Conditions))
for _, x := range v.Conditions {
conditions = append(conditions, dto.ExportConditionResponse{ID: x.ID, CreatedAt: x.CreatedAt, UpdatedAt: x.UpdatedAt, TemplateID: x.TemplateID, From: x.From, Column: x.Column, Operator: x.Operator})
}
}
var joins []dto.ExportJoinResponse
if v.Joins != nil {
joins = make([]dto.ExportJoinResponse, 0, len(v.Joins))
for _, x := range v.Joins {
joins = append(joins, dto.ExportJoinResponse{ID: x.ID, CreatedAt: x.CreatedAt, UpdatedAt: x.UpdatedAt, TemplateID: x.TemplateID, Join: x.Join, Table: x.Table, On: x.On})
}
}
return &dto.ExportTemplateResponse{ID: v.ID, CreatedAt: v.CreatedAt, UpdatedAt: v.UpdatedAt, DeletedAt: nil, DBName: v.DBName, Name: v.Name, TableName: v.TableName, TemplateID: v.TemplateID, TemplateInfo: v.TemplateInfo, SQL: v.SQL, ImportSQL: v.ImportSQL, Limit: v.Limit, Order: v.Order, Conditions: conditions, Joins: joins}
}
func (s *ExportService) Create(ctx context.Context, v *biz.ExportTemplate) error {
return s.uc.CreateExportTemplate(ctx, v)
}
func (s *ExportService) Update(ctx context.Context, v *biz.ExportTemplate) error {
return s.uc.UpdateExportTemplate(ctx, v)
}
func (s *ExportService) Delete(ctx context.Context, ids []uint) error {
return s.uc.DeleteExportTemplates(ctx, ids)
}
func (s *ExportService) Template(ctx context.Context, id uint, tid string) (*dto.ExportTemplateResponse, error) {
v, err := s.uc.FindExportTemplate(ctx, id, tid)
if err != nil {
return nil, err
}
return exportDTO(v), nil
}
func (s *ExportService) Templates(ctx context.Context, page, size int, q *biz.ExportTemplate) ([]*dto.ExportTemplateResponse, int64, error) {
items, total, err := s.uc.ListExportTemplates(ctx, page, size, q)
if err != nil {
return nil, 0, err
}
out := make([]*dto.ExportTemplateResponse, 0, len(items))
for _, v := range items {
out = append(out, exportDTO(v))
}
return out, total, nil
}
-163
View File
@@ -1,163 +0,0 @@
package service
import (
"context"
"encoding/json"
"errors"
"fmt"
"io"
"strconv"
"strings"
"time"
"github.com/xuri/excelize/v2"
)
func templateColumns(raw string) ([]string, map[string]string, error) {
labels := map[string]string{}
decoder := json.NewDecoder(strings.NewReader(raw))
token, err := decoder.Token()
if err != nil || token != json.Delim('{') {
return nil, nil, err
}
keys := make([]string, 0)
for decoder.More() {
keyToken, tokenErr := decoder.Token()
if tokenErr != nil {
return nil, nil, tokenErr
}
key := keyToken.(string)
var label string
if tokenErr = decoder.Decode(&label); tokenErr != nil {
return nil, nil, tokenErr
}
keys = append(keys, key)
labels[key] = label
}
if _, err = decoder.Token(); err != nil {
return nil, nil, err
}
return keys, labels, nil
}
func (s *ExportService) Export(ctx context.Context, tid string, params map[string]string) ([]byte, string, error) {
template, err := s.uc.FindExportTemplate(ctx, 0, tid)
if err != nil {
return nil, "", err
}
rows, _, err := s.uc.QueryExport(ctx, template, params)
if err != nil {
return nil, "", err
}
keys, labels, err := templateColumns(template.TemplateInfo)
if err != nil {
return nil, "", err
}
file := excelize.NewFile()
sheet := file.GetSheetName(0)
for column, key := range keys {
cell, _ := excelize.CoordinatesToCellName(column+1, 1)
_ = file.SetCellValue(sheet, cell, labels[key])
}
for rowIndex, row := range rows {
for column, key := range keys {
cell, _ := excelize.CoordinatesToCellName(column+1, rowIndex+2)
lookup := strings.ReplaceAll(strings.ReplaceAll(key, `"`, ""), "`", "")
if len(template.Joins) > 0 {
if parts := strings.Split(lookup, " as "); len(parts) > 1 {
lookup = strings.TrimSpace(parts[1])
} else if parts = strings.Split(lookup, "."); len(parts) > 1 {
lookup = parts[1]
}
}
value := fmt.Sprintf("%v", row[lookup])
if timestamp, ok := row[lookup].(time.Time); ok {
value = timestamp.Format("2006-01-02 15:04:05")
}
if number, parseErr := strconv.ParseFloat(value, 64); parseErr == nil {
_ = file.SetCellValue(sheet, cell, number)
} else {
_ = file.SetCellValue(sheet, cell, value)
}
}
}
buffer, err := file.WriteToBuffer()
_ = file.Close()
if err != nil {
return nil, "", err
}
return buffer.Bytes(), template.Name + ".xlsx", nil
}
func (s *ExportService) ExportBlankTemplate(ctx context.Context, tid string) ([]byte, string, error) {
template, err := s.uc.FindExportTemplate(ctx, 0, tid)
if err != nil {
return nil, "", err
}
keys, labels, err := templateColumns(template.TemplateInfo)
if err != nil {
return nil, "", err
}
file := excelize.NewFile()
sheet := file.GetSheetName(0)
for column, key := range keys {
cell, _ := excelize.CoordinatesToCellName(column+1, 1)
_ = file.SetCellValue(sheet, cell, labels[key])
}
buffer, err := file.WriteToBuffer()
_ = file.Close()
if err != nil {
return nil, "", err
}
return buffer.Bytes(), template.Name + "_template.xlsx", nil
}
func (s *ExportService) Preview(ctx context.Context, tid string, params map[string]string) (string, error) {
template, err := s.uc.FindExportTemplate(ctx, 0, tid)
if err != nil {
return "", err
}
return s.uc.PreviewExport(ctx, template, params)
}
func (s *ExportService) Import(ctx context.Context, tid string, reader io.Reader) error {
template, err := s.uc.FindExportTemplate(ctx, 0, tid)
if err != nil {
return err
}
file, err := excelize.OpenReader(reader)
if err != nil {
return err
}
defer file.Close()
rows, err := file.GetRows("Sheet1")
if err != nil {
return err
}
if len(rows) < 2 {
return errors.New("Excel data is not enough.\nIt should contain title row and data")
}
keys, labels, err := templateColumns(template.TemplateInfo)
if err != nil {
return err
}
reverse := map[string]string{}
for _, key := range keys {
reverse[labels[key]] = key
}
headers := rows[0]
for index := range headers {
headers[index] = strings.TrimSpace(headers[index])
}
items := make([]map[string]any, 0, len(rows)-1)
for _, row := range rows[1:] {
item := map[string]any{}
for column, value := range row {
if column >= len(headers) {
continue
}
key := reverse[headers[column]]
if key != "" {
item[key] = value
}
}
items = append(items, item)
}
return s.uc.ImportExportRows(ctx, template, items)
}
-112
View File
@@ -1,112 +0,0 @@
package service
import (
"context"
"io"
"kra/internal/biz"
"kra/internal/service/dto"
)
type MediaService struct {
uc *biz.MediaUsecase
settings biz.RuntimeSettings
}
func NewMediaService(uc *biz.MediaUsecase, settings biz.RuntimeSettings) *MediaService {
return &MediaService{uc: uc, settings: settings}
}
func (s *MediaService) MediaConfig() biz.MediaSettings {
return s.settings.MediaSettings()
}
func mediaDTO(v *biz.MediaFile) *dto.MediaResponse {
return &dto.MediaResponse{ID: v.ID, CreatedAt: v.CreatedAt, UpdatedAt: v.UpdatedAt, DeletedAt: nil, Name: v.Name, ClassID: v.CategoryID, URL: v.URL, Tag: v.Tag, Key: v.Key, Size: v.Size, Mime: v.Mime, MD5: v.MD5, UserID: v.UserID}
}
func categoryDTO(v *biz.AttachmentCategory) *dto.MediaCategoryResponse {
var children []*dto.MediaCategoryResponse
if v.Children != nil {
children = make([]*dto.MediaCategoryResponse, 0, len(v.Children))
for _, x := range v.Children {
children = append(children, categoryDTO(x))
}
}
return &dto.MediaCategoryResponse{ID: v.ID, CreatedAt: v.CreatedAt, UpdatedAt: v.UpdatedAt, DeletedAt: nil, Name: v.Name, PID: v.ParentID, Children: children}
}
func (s *MediaService) Upload(ctx context.Context, userID uint, name, mime string, categoryID int, reader io.Reader, save bool) (*dto.MediaResponse, error) {
v, err := s.uc.Upload(ctx, userID, name, mime, categoryID, reader, save)
if err != nil {
return nil, err
}
return mediaDTO(v), nil
}
func (s *MediaService) Media(ctx context.Context, id uint) (*dto.MediaResponse, error) {
v, err := s.uc.FindMedia(ctx, id)
if err != nil {
return nil, err
}
return mediaDTO(v), nil
}
func (s *MediaService) MediaList(ctx context.Context, filter biz.MediaFilter) ([]*dto.MediaResponse, int64, error) {
items, total, err := s.uc.ListMedia(ctx, filter)
if err != nil {
return nil, 0, err
}
out := make([]*dto.MediaResponse, 0, len(items))
for _, v := range items {
out = append(out, mediaDTO(v))
}
return out, total, nil
}
func (s *MediaService) MediaListRequest(ctx context.Context, request *dto.MediaListRequest) ([]*dto.MediaResponse, int64, error) {
return s.MediaList(ctx, biz.MediaFilter{
Page: request.Page, PageSize: request.PageSize, Keyword: request.Keyword,
CategoryID: request.ClassID, Tag: request.Tag, UserID: request.UserID,
StartCreatedAt: request.StartCreatedAt, EndCreatedAt: request.EndCreatedAt,
OrderKey: request.OrderKey, Desc: request.Desc,
})
}
func (s *MediaService) Delete(ctx context.Context, id uint) error { return s.uc.Delete(ctx, id) }
func (s *MediaService) Rename(ctx context.Context, id uint, name string) error {
return s.uc.UpdateMediaName(ctx, id, name)
}
func (s *MediaService) ImportURLs(ctx context.Context, items []*biz.MediaFile) error {
return s.uc.CreateMediaBatch(ctx, items)
}
func (s *MediaService) ImportURLRequests(ctx context.Context, values []dto.ImportMediaRequest) error {
items := make([]*biz.MediaFile, 0, len(values))
for _, value := range values {
items = append(items, &biz.MediaFile{Name: value.Name, CategoryID: value.ClassID, URL: value.URL, Tag: value.Tag, Key: value.Key, Size: value.Size, Mime: value.Mime, MD5: value.MD5, UserID: value.UserID})
}
return s.ImportURLs(ctx, items)
}
func (s *MediaService) Storage(ctx context.Context, prefix, cursor string, limit int) ([]*dto.StorageObjectResponse, string, bool, error) {
items, next, more, err := s.uc.ListStorage(ctx, prefix, cursor, limit)
if err != nil {
return nil, "", false, err
}
out := make([]*dto.StorageObjectResponse, 0, len(items))
for _, v := range items {
out = append(out, &dto.StorageObjectResponse{Key: v.Path, Size: v.Size, LastModified: v.LastModified, ContentType: v.ContentType})
}
return out, next, more, nil
}
func (s *MediaService) Categories(ctx context.Context) ([]*dto.MediaCategoryResponse, error) {
items, err := s.uc.ListCategories(ctx)
if err != nil {
return nil, err
}
out := make([]*dto.MediaCategoryResponse, 0, len(items))
for _, v := range items {
out = append(out, categoryDTO(v))
}
return out, nil
}
func (s *MediaService) SaveCategory(ctx context.Context, v *biz.AttachmentCategory) error {
return s.uc.SaveCategory(ctx, v)
}
func (s *MediaService) SaveCategoryRequest(ctx context.Context, value *dto.CategoryRequest) error {
return s.SaveCategory(ctx, &biz.AttachmentCategory{ID: value.ID, Name: value.Name, ParentID: value.PID})
}
func (s *MediaService) DeleteCategory(ctx context.Context, id uint) error {
return s.uc.DeleteCategory(ctx, id)
}
-34
View File
@@ -1,34 +0,0 @@
package service
import (
"context"
"io"
"kra/internal/service/dto"
)
func (s *MediaService) InitUpload(ctx context.Context, userID uint, name, hash string, size, chunkSize int64, total int) (*dto.InitUploadResponse, error) {
session, media, chunks, err := s.uc.InitUpload(ctx, userID, name, hash, size, chunkSize, total)
if err != nil {
return nil, err
}
if media != nil {
// The compatible response leaves UploadedChunks nil on an instant-upload hit, producing
// JSON null while still returning uploadId: 0.
return &dto.InitUploadResponse{Instant: true, Media: mediaDTO(media)}, nil
}
return &dto.InitUploadResponse{Instant: false, UploadID: session.ID, UploadedChunks: chunks, Media: nil}, nil
}
func (s *MediaService) SaveChunk(ctx context.Context, userID, uploadID uint, index int, hash string, reader io.Reader) error {
return s.uc.SaveChunk(ctx, userID, uploadID, index, hash, reader)
}
func (s *MediaService) CompleteUpload(ctx context.Context, userID, uploadID uint) (*dto.MediaResponse, error) {
v, err := s.uc.CompleteUpload(ctx, userID, uploadID, "")
if err != nil {
return nil, err
}
return mediaDTO(v), nil
}
func (s *MediaService) CancelUpload(ctx context.Context, userID, uploadID uint) error {
return s.uc.CancelUpload(ctx, userID, uploadID)
}
-160
View File
@@ -1,160 +0,0 @@
package service
import (
"context"
"kra/internal/biz"
"kra/internal/service/dto"
)
type MenuService struct{ uc *biz.MenuUsecase }
func NewMenuService(uc *biz.MenuUsecase) *MenuService { return &MenuService{uc: uc} }
func (s *MenuService) List(ctx context.Context) ([]*dto.MenuResponse, error) {
items, err := s.uc.List(ctx)
if err != nil {
return nil, err
}
return menuResponses(items), nil
}
func (s *MenuService) Tree(ctx context.Context) ([]*dto.MenuResponse, error) {
items, err := s.uc.Tree(ctx)
if err != nil {
return nil, err
}
return menuResponses(items), nil
}
func (s *MenuService) Create(ctx context.Context, req *dto.MenuRequest) error {
return s.uc.Create(ctx, menuDomain(req))
}
func (s *MenuService) Update(ctx context.Context, req *dto.MenuRequest) error {
return s.uc.Update(ctx, menuDomain(req))
}
func (s *MenuService) Delete(ctx context.Context, id uint) error { return s.uc.Delete(ctx, id) }
func (s *MenuService) Find(ctx context.Context, id uint) (*dto.MenuResponse, error) {
item, err := s.uc.Find(ctx, id)
if err != nil {
return nil, err
}
return menuResponse(item), nil
}
func (s *MenuService) SetAuthorityMenus(ctx context.Context, req *dto.SetAuthorityMenusRequest) error {
ids := make([]uint, 0, len(req.Menus))
for _, menu := range req.Menus {
ids = append(ids, menu.ID)
}
return s.uc.SetAuthorityMenus(ctx, req.AuthorityID, ids)
}
func (s *MenuService) AuthorityMenus(ctx context.Context, authorityID uint) ([]*dto.AuthorityMenuResponse, error) {
items, err := s.uc.AuthorityMenus(ctx, authorityID)
if err != nil {
return nil, err
}
var out []*dto.AuthorityMenuResponse
for _, item := range items {
item.MenuID = item.ID
out = append(out, &dto.AuthorityMenuResponse{DynamicMenuResponse: dynamicMenuResponse(item), AuthorityID: authorityID})
}
return out, nil
}
func (s *MenuService) RoleIDs(ctx context.Context, menuID uint) ([]uint, error) {
return s.uc.RoleIDs(ctx, menuID)
}
func (s *MenuService) DefaultRouterRoleIDs(ctx context.Context, menuID uint) ([]uint, error) {
return s.uc.DefaultRouterRoleIDs(ctx, menuID)
}
func (s *MenuService) SetRoles(ctx context.Context, req *dto.SetMenuRolesRequest) error {
return s.uc.SetRoles(ctx, req.MenuID, req.AuthorityIDs)
}
func menuDomain(v *dto.MenuRequest) *biz.Menu {
menu := &biz.Menu{CreatedAt: v.CreatedAt, UpdatedAt: v.UpdatedAt, ID: v.ID, ParentID: v.ParentID, Path: v.Path, Name: v.Name, Hidden: v.Hidden, Component: v.Component, Sort: v.Sort, ActiveName: v.Meta.ActiveName, KeepAlive: v.Meta.KeepAlive, DefaultMenu: v.Meta.DefaultMenu, Title: v.Meta.Title, Icon: v.Meta.Icon, CloseTab: v.Meta.CloseTab, TransitionType: v.Meta.TransitionType}
menu.Buttons = make([]*biz.MenuButton, 0, len(v.MenuButtons))
for _, button := range v.MenuButtons {
menu.Buttons = append(menu.Buttons, &biz.MenuButton{CreatedAt: button.CreatedAt, UpdatedAt: button.UpdatedAt, ID: button.ID, Name: button.Name, Description: button.Description, MenuID: v.ID})
}
menu.Parameters = make([]*biz.MenuParameter, 0, len(v.Parameters))
for _, parameter := range v.Parameters {
menu.Parameters = append(menu.Parameters, &biz.MenuParameter{CreatedAt: parameter.CreatedAt, UpdatedAt: parameter.UpdatedAt, ID: parameter.ID, MenuID: v.ID, Type: parameter.Type, Key: parameter.Key, Value: parameter.Value})
}
return menu
}
func menuResponse(menu *biz.Menu) *dto.MenuResponse {
var children []*dto.MenuResponse
if menu.Children != nil {
children = make([]*dto.MenuResponse, 0, len(menu.Children))
for _, child := range menu.Children {
children = append(children, menuResponse(child))
}
}
var buttons []dto.MenuButtonResponse
if menu.Buttons != nil {
buttons = make([]dto.MenuButtonResponse, 0, len(menu.Buttons))
for _, button := range menu.Buttons {
buttons = append(buttons, dto.MenuButtonResponse{CreatedAt: button.CreatedAt, UpdatedAt: button.UpdatedAt, ID: button.ID, Name: button.Name, Description: button.Description, SysBaseMenuID: button.MenuID})
}
}
var parameters []dto.MenuParameterResponse
if menu.Parameters != nil {
parameters = make([]dto.MenuParameterResponse, 0, len(menu.Parameters))
for _, parameter := range menu.Parameters {
parameters = append(parameters, dto.MenuParameterResponse{CreatedAt: parameter.CreatedAt, UpdatedAt: parameter.UpdatedAt, ID: parameter.ID, SysBaseMenuID: parameter.MenuID, Type: parameter.Type, Key: parameter.Key, Value: parameter.Value})
}
}
return &dto.MenuResponse{CreatedAt: menu.CreatedAt, UpdatedAt: menu.UpdatedAt, ID: menu.ID, MenuID: menu.MenuID, ParentID: menu.ParentID, Path: menu.Path, Name: menu.Name, Hidden: menu.Hidden, Component: menu.Component, Sort: menu.Sort, Meta: dto.MenuMetaResponse{ActiveName: menu.ActiveName, KeepAlive: menu.KeepAlive, DefaultMenu: menu.DefaultMenu, Title: menu.Title, Icon: menu.Icon, CloseTab: menu.CloseTab, TransitionType: menu.TransitionType}, Children: children, Parameters: parameters, MenuButtons: buttons}
}
func dynamicMenuResponse(menu *biz.Menu) *dto.DynamicMenuResponse {
var children []*dto.DynamicMenuResponse
if menu.Children != nil {
children = make([]*dto.DynamicMenuResponse, 0, len(menu.Children))
for _, child := range menu.Children {
children = append(children, dynamicMenuResponse(child))
}
}
var parameters []dto.MenuParameterResponse
if menu.Parameters != nil {
parameters = make([]dto.MenuParameterResponse, 0, len(menu.Parameters))
for _, parameter := range menu.Parameters {
parameters = append(parameters, dto.MenuParameterResponse{CreatedAt: parameter.CreatedAt, UpdatedAt: parameter.UpdatedAt, ID: parameter.ID, SysBaseMenuID: parameter.MenuID, Type: parameter.Type, Key: parameter.Key, Value: parameter.Value})
}
}
var buttonAuthorities map[string]uint
for _, button := range menu.Buttons {
if button.AuthorityID == 0 {
continue
}
if buttonAuthorities == nil {
buttonAuthorities = make(map[string]uint)
}
buttonAuthorities[button.Name] = button.AuthorityID
}
return &dto.DynamicMenuResponse{CreatedAt: menu.CreatedAt, UpdatedAt: menu.UpdatedAt, ID: menu.ID, MenuID: menu.MenuID, ParentID: menu.ParentID, Path: menu.Path, Name: menu.Name, Hidden: menu.Hidden, Component: menu.Component, Sort: menu.Sort, Meta: dto.MenuMetaResponse{ActiveName: menu.ActiveName, KeepAlive: menu.KeepAlive, DefaultMenu: menu.DefaultMenu, Title: menu.Title, Icon: menu.Icon, CloseTab: menu.CloseTab, TransitionType: menu.TransitionType}, Children: children, Parameters: parameters, MenuButtons: nil, Buttons: buttonAuthorities}
}
func menuResponses(items []*biz.Menu) []*dto.MenuResponse {
if items == nil {
return nil
}
out := make([]*dto.MenuResponse, 0, len(items))
for _, item := range items {
out = append(out, menuResponse(item))
}
return out
}
func dynamicMenuResponses(items []*biz.Menu) []*dto.DynamicMenuResponse {
out := make([]*dto.DynamicMenuResponse, 0, len(items))
for _, item := range items {
out = append(out, dynamicMenuResponse(item))
}
return out
}
-63
View File
@@ -1,63 +0,0 @@
package service
import (
"encoding/json"
"testing"
"time"
"kra/internal/biz"
"kra/internal/service/dto"
)
func TestMenuDomainPreservesRelationIdentity(t *testing.T) {
createdAt := time.Date(2025, time.March, 4, 5, 6, 7, 0, time.UTC)
updatedAt := time.Date(2025, time.April, 5, 6, 7, 8, 0, time.UTC)
menu := menuDomain(&dto.MenuRequest{
CreatedAt: createdAt,
UpdatedAt: updatedAt,
ID: 10,
MenuButtons: []dto.MenuButtonRequest{{
CreatedAt: createdAt, UpdatedAt: updatedAt, ID: 31, Name: "edit", Description: "编辑",
}},
Parameters: []dto.MenuParameterRequest{{
CreatedAt: createdAt, UpdatedAt: updatedAt, ID: 21, Type: "query", Key: "id", Value: "1",
}},
})
if !menu.CreatedAt.Equal(createdAt) || !menu.UpdatedAt.Equal(updatedAt) {
t.Fatalf("menu timestamps = (%v, %v), want (%v, %v)", menu.CreatedAt, menu.UpdatedAt, createdAt, updatedAt)
}
if len(menu.Buttons) != 1 || menu.Buttons[0].ID != 31 || menu.Buttons[0].MenuID != 10 || !menu.Buttons[0].CreatedAt.Equal(createdAt) || !menu.Buttons[0].UpdatedAt.Equal(updatedAt) {
t.Fatalf("button conversion = %+v", menu.Buttons)
}
if len(menu.Parameters) != 1 || menu.Parameters[0].ID != 21 || menu.Parameters[0].MenuID != 10 || !menu.Parameters[0].CreatedAt.Equal(createdAt) || !menu.Parameters[0].UpdatedAt.Equal(updatedAt) {
t.Fatalf("parameter conversion = %+v", menu.Parameters)
}
}
func TestMenuResponseEmptyCollectionContracts(t *testing.T) {
if got := menuResponses(nil); got != nil {
t.Fatalf("base menu top-level nil = %#v, want nil", got)
}
if got := dynamicMenuResponses(nil); got == nil || len(got) != 0 {
t.Fatalf("dynamic menu top-level empty = %#v, want non-nil empty slice", got)
}
base := menuResponse(&biz.Menu{Children: nil, Buttons: []*biz.MenuButton{}, Parameters: []*biz.MenuParameter{}})
if base.Children != nil {
t.Fatalf("leaf children = %#v, want nil", base.Children)
}
if base.MenuButtons == nil || base.Parameters == nil {
t.Fatalf("preloaded empty relations = (%#v, %#v), want empty slices", base.MenuButtons, base.Parameters)
}
encoded, err := json.Marshal(base)
if err != nil {
t.Fatal(err)
}
var payload map[string]any
if err := json.Unmarshal(encoded, &payload); err != nil {
t.Fatal(err)
}
if value, ok := payload["authoritys"]; !ok || value != nil {
t.Fatalf("authoritys JSON = %#v (present=%v), want explicit null", value, ok)
}
}
-65
View File
@@ -1,65 +0,0 @@
package service
import (
"context"
"time"
"kra/internal/biz"
"kra/internal/service/dto"
)
type ParameterService struct{ uc *biz.ParameterUsecase }
func NewParameterService(uc *biz.ParameterUsecase) *ParameterService {
return &ParameterService{uc: uc}
}
func parameterDomain(value *dto.SystemParameterRequest) *biz.SystemParameter {
return &biz.SystemParameter{ID: value.ID, CreatedAt: value.CreatedAt, UpdatedAt: value.UpdatedAt, Name: value.Name, Key: value.Key, Value: value.Value, Desc: value.Description}
}
func (s *ParameterService) CreateParameterRequest(ctx context.Context, req *dto.SystemParameterRequest) error {
return s.CreateParameter(ctx, parameterDomain(req))
}
func (s *ParameterService) UpdateParameterRequest(ctx context.Context, req *dto.SystemParameterRequest) error {
return s.UpdateParameter(ctx, parameterDomain(req))
}
func (s *ParameterService) ParametersFilter(ctx context.Context, page, size int, name, key string, start, end *time.Time) ([]*dto.SystemParameterResponse, int64, error) {
return s.Parameters(ctx, page, size, &biz.SystemParameter{Name: name, Key: key, StartCreatedAt: start, EndCreatedAt: end})
}
func parameterDTO(v *biz.SystemParameter) *dto.SystemParameterResponse {
return &dto.SystemParameterResponse{ID: v.ID, CreatedAt: v.CreatedAt, UpdatedAt: v.UpdatedAt, DeletedAt: nil, Name: v.Name, Key: v.Key, Value: v.Value, Desc: v.Desc}
}
func (s *ParameterService) Parameters(ctx context.Context, page, size int, q *biz.SystemParameter) ([]*dto.SystemParameterResponse, int64, error) {
items, total, err := s.uc.ListParameters(ctx, page, size, q)
if err != nil {
return nil, 0, err
}
out := make([]*dto.SystemParameterResponse, 0, len(items))
for _, v := range items {
out = append(out, parameterDTO(v))
}
return out, total, nil
}
func (s *ParameterService) ParameterByID(ctx context.Context, id string) (*dto.SystemParameterResponse, error) {
v, err := s.uc.FindParameterByID(ctx, id)
if err != nil {
return nil, err
}
return parameterDTO(v), nil
}
func (s *ParameterService) ParameterByKey(ctx context.Context, key string) (*dto.SystemParameterResponse, error) {
v, err := s.uc.FindParameterByKey(ctx, key)
if err != nil {
return nil, err
}
return parameterDTO(v), nil
}
func (s *ParameterService) CreateParameter(ctx context.Context, v *biz.SystemParameter) error {
return s.uc.CreateParameter(ctx, v)
}
func (s *ParameterService) UpdateParameter(ctx context.Context, v *biz.SystemParameter) error {
return s.uc.UpdateParameter(ctx, v)
}
func (s *ParameterService) DeleteParameters(ctx context.Context, ids []string) error {
return s.uc.DeleteParameters(ctx, ids)
}
-169
View File
@@ -1,169 +0,0 @@
package service
import (
"context"
"errors"
"kra/internal/biz"
"kra/internal/service/dto"
)
type PaymentService struct{ uc *biz.PaymentUsecase }
func NewPaymentService(uc *biz.PaymentUsecase) *PaymentService { return &PaymentService{uc: uc} }
func (s *PaymentService) Configs(ctx context.Context) ([]*dto.PaymentConfigResponse, error) {
configs, err := s.uc.Configs(ctx)
if err != nil {
return nil, err
}
result := make([]*dto.PaymentConfigResponse, 0, len(configs))
for _, config := range configs {
if config == nil {
continue
}
result = append(result, &dto.PaymentConfigResponse{Provider: config.Provider, Enabled: config.Enabled, Config: config.Values})
}
return result, nil
}
func (s *PaymentService) SaveConfig(ctx context.Context, req *dto.PaymentConfigRequest) error {
if req == nil {
return errors.New("支付配置请求为空")
}
return s.uc.SaveConfig(ctx, &biz.PaymentConfig{Provider: req.Provider, Enabled: req.Enabled, Values: req.Config})
}
func (s *PaymentService) Order(ctx context.Context, provider, tradeNo string) (*dto.PaymentOrderResponse, error) {
order, err := s.uc.Order(ctx, provider, tradeNo)
if err != nil {
return nil, err
}
return &dto.PaymentOrderResponse{
ID: order.ID,
Provider: order.Provider, TradeNo: order.TradeNo, ProviderTradeNo: order.ProviderTradeNo,
BusinessType: order.BusinessType, BusinessID: order.BusinessID, Subject: order.Subject,
PaymentMode: order.PaymentMode, OriginalAmount: order.OriginalAmount,
Amount: order.Amount, PaidAmount: order.PaidAmount, PayerPaidAmount: order.PayerPaidAmount,
CashPaidAmount: order.CashPaidAmount, PointPaidAmount: order.PointPaidAmount,
DiscountAmount: order.DiscountAmount, ProviderDiscountAmount: order.ProviderDiscountAmount,
MerchantDiscountAmount: order.MerchantDiscountAmount, SettlementAmount: order.SettlementAmount,
Currency: order.Currency, PayerCurrency: order.PayerCurrency, AmountBreakdownKnown: order.AmountBreakdownKnown,
PaymentStatus: order.PaymentStatus, ProviderStatus: order.ProviderStatus, FulfillmentStatus: order.FulfillmentStatus,
RefundStatus: order.RefundStatus, RefundedAmount: order.RefundedAmount, RefundRequestedAmount: order.RefundRequestedAmount, RefundNo: order.RefundNo, LastError: order.LastError,
CreatedAt: order.CreatedAt, UpdatedAt: order.UpdatedAt, PaidAt: order.PaidAt,
FulfilledAt: order.FulfilledAt, RefundedAt: order.RefundedAt,
}, nil
}
func (s *PaymentService) Orders(ctx context.Context, req *dto.PaymentOrderListRequest) ([]*dto.PaymentOrderResponse, int64, int, int, error) {
if req == nil {
return nil, 0, 1, 10, errors.New("支付订单列表请求为空")
}
page, pageSize := req.Page, req.PageSize
if page <= 0 {
page = 1
}
if pageSize <= 0 {
pageSize = 10
}
items, total, err := s.uc.Orders(ctx, page, pageSize, biz.PaymentOrderFilter{
Provider: req.Provider, TradeNo: req.TradeNo, BusinessType: req.BusinessType,
BusinessID: req.BusinessID, PaymentStatus: req.PaymentStatus, RefundStatus: req.RefundStatus,
})
if err != nil {
return nil, 0, page, pageSize, err
}
result := make([]*dto.PaymentOrderResponse, 0, len(items))
for _, item := range items {
converted, convertErr := paymentOrderResponse(item)
if convertErr != nil {
return nil, 0, page, pageSize, convertErr
}
result = append(result, converted)
}
return result, total, page, pageSize, nil
}
func paymentOrderResponse(order *biz.PaymentOrder) (*dto.PaymentOrderResponse, error) {
if order == nil {
return nil, errors.New("支付订单为空")
}
return &dto.PaymentOrderResponse{
ID: order.ID, Provider: order.Provider, TradeNo: order.TradeNo, ProviderTradeNo: order.ProviderTradeNo,
BusinessType: order.BusinessType, BusinessID: order.BusinessID, Subject: order.Subject,
PaymentMode: order.PaymentMode, OriginalAmount: order.OriginalAmount, Amount: order.Amount, PaidAmount: order.PaidAmount,
PayerPaidAmount: order.PayerPaidAmount, CashPaidAmount: order.CashPaidAmount, PointPaidAmount: order.PointPaidAmount,
DiscountAmount: order.DiscountAmount, ProviderDiscountAmount: order.ProviderDiscountAmount,
MerchantDiscountAmount: order.MerchantDiscountAmount, SettlementAmount: order.SettlementAmount,
Currency: order.Currency, PayerCurrency: order.PayerCurrency, AmountBreakdownKnown: order.AmountBreakdownKnown,
PaymentStatus: order.PaymentStatus, ProviderStatus: order.ProviderStatus, FulfillmentStatus: order.FulfillmentStatus,
RefundStatus: order.RefundStatus, RefundedAmount: order.RefundedAmount, RefundRequestedAmount: order.RefundRequestedAmount,
RefundNo: order.RefundNo, LastError: order.LastError, CreatedAt: order.CreatedAt, UpdatedAt: order.UpdatedAt,
PaidAt: order.PaidAt, FulfilledAt: order.FulfilledAt, RefundedAt: order.RefundedAt,
}, nil
}
func (s *PaymentService) Create(ctx context.Context, req *dto.PaymentRequest) (*dto.PaymentResultResponse, error) {
if req == nil {
return nil, errors.New("支付请求为空")
}
result, err := s.uc.Create(ctx, &biz.PaymentRequest{
Provider: req.Provider, TradeNo: req.TradeNo, Subject: req.Subject,
Amount: req.Amount, OriginalAmount: req.OriginalAmount, Currency: req.Currency,
NotifyURL: req.NotifyURL, ReturnURL: req.ReturnURL, ClientIP: req.ClientIP,
Extra: req.Extra, BusinessType: req.BusinessType, BusinessID: req.BusinessID,
PaymentMode: req.PaymentMode,
})
return paymentResultResponse(result), err
}
func (s *PaymentService) Query(ctx context.Context, req *dto.PaymentQueryRequest) (*dto.PaymentResultResponse, error) {
if req == nil {
return nil, errors.New("支付查询请求为空")
}
result, err := s.uc.Query(ctx, req.Provider, req.TradeNo)
return paymentResultResponse(result), err
}
func (s *PaymentService) Refund(ctx context.Context, req *dto.PaymentRefundRequest) (*dto.PaymentResultResponse, error) {
if req == nil {
return nil, errors.New("支付退款请求为空")
}
result, err := s.uc.Refund(ctx, req.Provider, req.TradeNo, req.Amount)
return paymentResultResponse(result), err
}
func (s *PaymentService) Callback(ctx context.Context, req *dto.PaymentCallbackRequest) (dto.PaymentCallbackAck, error) {
if req == nil {
return paymentCallbackAckResponse(biz.DefaultPaymentCallbackAck("", false)), errors.New("支付回调请求为空")
}
result, err := s.uc.Callback(ctx, &biz.PaymentCallback{Provider: req.Provider, Headers: req.Headers, Body: req.Body, Query: req.Query})
if err != nil {
return paymentCallbackAckResponse(biz.CallbackFailure(err, biz.DefaultPaymentCallbackAck(req.Provider, false))), err
}
ack := biz.DefaultPaymentCallbackAck(req.Provider, true)
if result != nil && result.SuccessAck.StatusCode != 0 {
ack = result.SuccessAck
}
return paymentCallbackAckResponse(ack), nil
}
func DefaultPaymentCallbackAck(provider string, success bool) dto.PaymentCallbackAck {
return paymentCallbackAckResponse(biz.DefaultPaymentCallbackAck(provider, success))
}
func paymentResultResponse(result *biz.PaymentResult) *dto.PaymentResultResponse {
if result == nil {
return nil
}
return &dto.PaymentResultResponse{
Provider: result.Provider, Status: result.Status, TradeNo: result.TradeNo,
ProviderTradeNo: result.ProviderTradeNo, Amount: result.Amount,
PayerPaidAmount: result.PayerPaidAmount, CashPaidAmount: result.CashPaidAmount,
PointPaidAmount: result.PointPaidAmount, DiscountAmount: result.DiscountAmount,
ProviderDiscountAmount: result.ProviderDiscountAmount,
MerchantDiscountAmount: result.MerchantDiscountAmount, SettlementAmount: result.SettlementAmount,
Currency: result.Currency, PayerCurrency: result.PayerCurrency,
AmountBreakdownKnown: result.AmountBreakdownKnown, Duplicate: result.Duplicate,
Payload: result.Payload, OrderStatus: result.OrderStatus,
FulfillmentStatus: result.FulfillmentStatus, RefundStatus: result.RefundStatus,
}
}
func paymentCallbackAckResponse(ack biz.PaymentCallbackAck) dto.PaymentCallbackAck {
return dto.PaymentCallbackAck{StatusCode: ack.StatusCode, ContentType: ack.ContentType, Body: ack.Body}
}
-25
View File
@@ -1,25 +0,0 @@
package service
import (
"context"
"kra/internal/biz"
)
type PermissionService struct{ uc *biz.PermissionUsecase }
func NewPermissionService(uc *biz.PermissionUsecase) *PermissionService {
return &PermissionService{uc: uc}
}
func (s *PermissionService) SelectedButtons(ctx context.Context, authorityID, menuID uint) ([]uint, error) {
return s.uc.SelectedButtons(ctx, authorityID, menuID)
}
func (s *PermissionService) SetSelectedButtons(ctx context.Context, authorityID, menuID uint, ids []uint) error {
return s.uc.SetSelectedButtons(ctx, authorityID, menuID, ids)
}
func (s *PermissionService) CanRemoveButton(ctx context.Context, id string) (bool, error) {
return s.uc.CanRemoveButton(ctx, id)
}
-66
View File
@@ -1,66 +0,0 @@
package service
import (
"context"
"kra/internal/biz"
"kra/internal/service/dto"
)
type PositionService struct{ uc *biz.PositionUsecase }
func NewPositionService(uc *biz.PositionUsecase) *PositionService {
return &PositionService{uc: uc}
}
func positionDomain(value *dto.PositionRequest) *biz.Position {
return &biz.Position{ID: value.ID, Name: value.Name, Code: value.Code, Sort: value.Sort, Status: value.Status, Remark: value.Remark}
}
func positionResponse(value *biz.Position) *dto.PositionResponse {
return &dto.PositionResponse{ID: value.ID, CreatedAt: value.CreatedAt, UpdatedAt: value.UpdatedAt, DeletedAt: nil, Name: value.Name, Code: value.Code, Sort: value.Sort, Status: value.Status, Remark: value.Remark}
}
func (s *PositionService) Positions(ctx context.Context, req *dto.PositionListRequest) ([]*dto.PositionResponse, int64, error) {
items, total, err := s.uc.Positions(ctx, req.Page, req.PageSize, &biz.PositionListFilter{Name: req.Name, Code: req.Code, Status: req.Status})
if err != nil {
return nil, 0, err
}
out := make([]*dto.PositionResponse, 0, len(items))
for _, item := range items {
out = append(out, positionResponse(item))
}
return out, total, nil
}
func (s *PositionService) Create(ctx context.Context, req *dto.PositionRequest) error {
return s.uc.CreatePosition(ctx, positionDomain(req))
}
func (s *PositionService) Update(ctx context.Context, req *dto.PositionRequest) error {
return s.uc.UpdatePosition(ctx, positionDomain(req))
}
func (s *PositionService) Delete(ctx context.Context, id uint) error {
return s.uc.DeletePosition(ctx, id)
}
func (s *PositionService) Position(ctx context.Context, id uint) (*dto.PositionResponse, error) {
value, err := s.uc.Position(ctx, id)
if err != nil {
return nil, err
}
return positionResponse(value), nil
}
func (s *PositionService) UserIDs(ctx context.Context, id uint) ([]uint, error) {
return s.uc.PositionUserIDs(ctx, id)
}
func (s *PositionService) SetUsers(ctx context.Context, req *dto.SetPositionUsersRequest) error {
return s.uc.SetPositionUsers(ctx, req.PositionID, req.UserIDs)
}
func (s *PositionService) SetUserPositions(ctx context.Context, req *dto.SetUserPositionsRequest) error {
return s.uc.SetUserPositions(ctx, req.ID, req.PositionIDs)
}
-19
View File
@@ -1,19 +0,0 @@
package service
import "strings"
// NormalizeRoutePath removes only a complete configured router prefix. Paths
// such as /administrator must not be shortened when the prefix is /admin.
func NormalizeRoutePath(path, routerPrefix string) string {
prefix := strings.TrimSuffix(strings.TrimSpace(routerPrefix), "/")
if prefix == "" || prefix == "/" {
return path
}
if path == prefix {
return "/"
}
if strings.HasPrefix(path, prefix+"/") {
return strings.TrimPrefix(path, prefix)
}
return path
}
-26
View File
@@ -1,26 +0,0 @@
package service
import "testing"
func TestNormalizeRoutePath(t *testing.T) {
tests := []struct {
name string
path string
prefix string
want string
}{
{name: "empty prefix", path: "/api/login", prefix: "", want: "/api/login"},
{name: "configured prefix", path: "/admin/api/login", prefix: "/admin", want: "/api/login"},
{name: "trailing slash prefix", path: "/admin/api/login", prefix: "/admin/", want: "/api/login"},
{name: "prefix root", path: "/admin", prefix: "/admin", want: "/"},
{name: "prefix boundary", path: "/administrator/api/login", prefix: "/admin", want: "/administrator/api/login"},
{name: "already normalized", path: "/api/login", prefix: "/admin", want: "/api/login"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := NormalizeRoutePath(tt.path, tt.prefix); got != tt.want {
t.Fatalf("NormalizeRoutePath(%q, %q) = %q, want %q", tt.path, tt.prefix, got, tt.want)
}
})
}
}
-62
View File
@@ -1,62 +0,0 @@
package service
import (
"context"
"errors"
"kra/internal/biz"
"kra/internal/service/dto"
)
type PasswordPolicyError struct{ Err error }
func (e *PasswordPolicyError) Error() string { return e.Err.Error() }
func (e *PasswordPolicyError) Unwrap() error { return e.Err }
func IsPasswordPolicyError(err error) bool {
var policyErr *PasswordPolicyError
return errors.As(err, &policyErr)
}
func securityDTO(v *biz.SecurityConfig) *dto.SecurityConfigResponse {
return &dto.SecurityConfigResponse{ID: v.ID, CreatedAt: v.CreatedAt, UpdatedAt: v.UpdatedAt, DeletedAt: nil, CaptchaOpen: v.CaptchaOpen, CaptchaTimeout: v.CaptchaTimeout, KeyLong: v.KeyLong, ImgWidth: v.ImgWidth, ImgHeight: v.ImgHeight, PwdMinLength: v.PwdMinLength, PwdRequireUpper: v.PwdRequireUpper, PwdRequireLower: v.PwdRequireLower, PwdRequireDigit: v.PwdRequireDigit, PwdRequireSpecial: v.PwdRequireSpecial, LimitEnable: v.LimitEnable, LimitWindow: v.LimitWindow, LimitCount: v.LimitCount, LockEnable: v.LockEnable, LockThreshold: v.LockThreshold, LockDuration: v.LockDuration, PwdExpireEnable: v.PwdExpireEnable, PwdExpireDays: v.PwdExpireDays, ForceNewUserChangePassword: v.ForceNewUserChangePassword}
}
func (s *SecurityService) CurrentSecurity(ctx context.Context) (*biz.SecurityConfig, error) {
return s.uc.Current(ctx)
}
func (s *SecurityService) Security(ctx context.Context) (*dto.SecurityConfigResponse, error) {
value, err := s.uc.Security(ctx)
if err != nil {
return nil, err
}
return securityDTO(value), nil
}
func (s *SecurityService) SaveSecurity(ctx context.Context, value *biz.SecurityConfig) (*dto.SecurityConfigResponse, error) {
if err := s.uc.UpdateSecurity(ctx, value); err != nil {
return nil, err
}
return securityDTO(value), nil
}
func (s *SecurityService) SaveSecurityRequest(ctx context.Context, value *dto.SecurityConfigRequest) (*dto.SecurityConfigResponse, error) {
return s.SaveSecurity(ctx, &biz.SecurityConfig{
ID: value.ID, CaptchaOpen: value.CaptchaOpen, CaptchaTimeout: value.CaptchaTimeout,
KeyLong: value.KeyLong, ImgWidth: value.ImgWidth, ImgHeight: value.ImgHeight,
PwdMinLength: value.PwdMinLength, PwdRequireUpper: value.PwdRequireUpper,
PwdRequireLower: value.PwdRequireLower, PwdRequireDigit: value.PwdRequireDigit,
PwdRequireSpecial: value.PwdRequireSpecial, LimitEnable: value.LimitEnable,
LimitWindow: value.LimitWindow, LimitCount: value.LimitCount, LockEnable: value.LockEnable,
LockThreshold: value.LockThreshold, LockDuration: value.LockDuration,
PwdExpireEnable: value.PwdExpireEnable, PwdExpireDays: value.PwdExpireDays,
ForceNewUserChangePassword: value.ForceNewUserChangePassword,
})
}
func (s *SecurityService) ValidatePassword(ctx context.Context, password string) error {
cfg, err := s.CurrentSecurity(ctx)
if err != nil {
return err
}
if err := s.uc.ValidatePassword(cfg, password); err != nil {
return &PasswordPolicyError{Err: err}
}
return nil
}
-74
View File
@@ -1,74 +0,0 @@
package service
import (
"context"
"time"
"kra/internal/biz"
)
type SecurityService struct {
uc *biz.SecurityUsecase
}
func NewSecurityService(uc *biz.SecurityUsecase) *SecurityService {
return &SecurityService{uc: uc}
}
func (s *SecurityService) ActiveToken(ctx context.Context, username string) (string, error) {
return s.uc.ActiveToken(ctx, username)
}
func (s *SecurityService) LoginLocked(ctx context.Context, username string) (bool, error) {
return s.uc.LoginLocked(ctx, username)
}
func (s *SecurityService) IncrementLoginFailure(ctx context.Context, username string, expiration time.Duration) (int64, error) {
return s.uc.IncrementLoginFailure(ctx, username, expiration)
}
func (s *SecurityService) LockLogin(ctx context.Context, username string, expiration time.Duration) error {
return s.uc.LockLogin(ctx, username, expiration)
}
func (s *SecurityService) ClearLoginState(ctx context.Context, username string) {
s.uc.ClearLoginState(ctx, username)
}
func (s *SecurityService) EnsureLoginIPCounter(ctx context.Context, ip string, expiration time.Duration) (int, error) {
return s.uc.EnsureLoginIPCounter(ctx, ip, expiration)
}
func (s *SecurityService) IncrementLoginIP(ctx context.Context, ip string, expiration time.Duration) (int64, error) {
return s.uc.IncrementLoginIP(ctx, ip, expiration)
}
func (s *SecurityService) IncrementRateLimit(ctx context.Context, key string, expiration time.Duration) (int64, error) {
return s.uc.IncrementRateLimit(ctx, key, expiration)
}
func (s *SecurityService) SetCaptcha(ctx context.Context, id, value string, expiration time.Duration) error {
return s.uc.SetCaptcha(ctx, id, value, expiration)
}
func (s *SecurityService) GetCaptcha(ctx context.Context, id string) (string, bool, error) {
return s.uc.GetCaptcha(ctx, id)
}
func (s *SecurityService) DeleteCaptcha(ctx context.Context, id string) error {
return s.uc.DeleteCaptcha(ctx, id)
}
func (s *SecurityService) UseMultipoint() bool { return s.uc.UseMultipoint() }
func (s *SecurityService) CaptchaSettings() biz.CaptchaSettings {
return s.uc.CaptchaRuntimeSettings()
}
func (s *SecurityService) ActiveTokenMatches(ctx context.Context, username, token string) (bool, error) {
return s.uc.ActiveTokenMatches(ctx, username, token)
}
func (s *SecurityService) RotateActiveToken(ctx context.Context, username, oldToken, newToken string, expiration time.Duration) error {
return s.uc.RotateActiveToken(ctx, username, oldToken, newToken, expiration)
}
-6
View File
@@ -1,6 +0,0 @@
package service
import "github.com/google/wire"
// ProviderSet is service providers.
var ProviderSet = wire.NewSet(NewAuthService, NewUserService, NewSystemConfigService, NewAuthorityService, NewPermissionService, NewAccessControlService, NewAPIService, NewMenuService, NewDepartmentService, NewPositionService, NewDictionaryService, NewParameterService, NewTokenService, NewSecurityService, NewVersionService, NewExportService, NewAuditService, NewAuditRecorder, NewLogViewerService, NewTaskService, NewMediaService, NewAnnouncementService, NewEmailService, NewPaymentService)
-20
View File
@@ -1,20 +0,0 @@
package service
import (
"context"
"kra/internal/biz"
)
type SystemConfigService struct {
uc *biz.SystemConfigUsecase
settings biz.RuntimeSettings
}
func NewSystemConfigService(uc *biz.SystemConfigUsecase, settings biz.RuntimeSettings) *SystemConfigService {
return &SystemConfigService{uc: uc, settings: settings}
}
func (s *SystemConfigService) IsInitialized(ctx context.Context) (bool, error) {
return s.uc.IsInitialized(ctx)
}
-26
View File
@@ -1,26 +0,0 @@
package service
import (
"context"
"encoding/json"
"kra/internal/service/dto"
)
func (s *SystemConfigService) PersistConfig(ctx context.Context) error {
return s.uc.PersistConfig(ctx)
}
func (s *SystemConfigService) ReloadConfig(ctx context.Context) error {
return s.uc.ReloadConfig(ctx)
}
func (s *SystemConfigService) DiskMountPoints() []string { return s.uc.DiskMountPoints() }
func (s *SystemConfigService) SystemConfig() (json.RawMessage, error) {
return s.uc.ConfigurationJSON()
}
func (s *SystemConfigService) SaveSystemConfig(ctx context.Context, req *dto.SetSystemConfigRequest) error {
return s.uc.SaveConfigurationJSON(ctx, req.Config)
}
-42
View File
@@ -1,42 +0,0 @@
package service
import (
"runtime"
"time"
"kra/internal/service/dto"
"github.com/shirou/gopsutil/v4/cpu"
"github.com/shirou/gopsutil/v4/disk"
"github.com/shirou/gopsutil/v4/mem"
)
func (s *SystemConfigService) ServerInfo() (*dto.ServerInfoResponse, error) {
physicalCores, err := cpu.Counts(false)
if err != nil {
return nil, err
}
cpuPercent, err := cpu.Percent(200*time.Millisecond, true)
if err != nil {
return nil, err
}
memory, err := mem.VirtualMemory()
if err != nil {
return nil, err
}
diskInfo := make([]dto.ServerDiskResponse, 0)
for _, mountPoint := range s.DiskMountPoints() {
usage, usageErr := disk.Usage(mountPoint)
if usageErr != nil {
return nil, usageErr
}
diskInfo = append(diskInfo, dto.ServerDiskResponse{MountPoint: mountPoint, UsedMB: usage.Used / 1024 / 1024, UsedGB: usage.Used / 1024 / 1024 / 1024, TotalMB: usage.Total / 1024 / 1024, TotalGB: usage.Total / 1024 / 1024 / 1024, UsedPercent: int(usage.UsedPercent)})
}
usedMB, totalMB := memory.Used/1024/1024, memory.Total/1024/1024
return &dto.ServerInfoResponse{
OS: dto.ServerOSResponse{GOOS: runtime.GOOS, NumCPU: runtime.NumCPU(), Compiler: runtime.Compiler, GoVersion: runtime.Version(), NumGoroutine: runtime.NumGoroutine()},
CPU: dto.ServerCPUResponse{CPUs: cpuPercent, Cores: physicalCores},
RAM: dto.ServerRAMResponse{UsedMB: usedMB, TotalMB: totalMB, UsedPercent: int(memory.UsedPercent)},
Disk: diskInfo,
}, nil
}
-36
View File
@@ -1,36 +0,0 @@
package service
import (
"context"
"kra/internal/biz"
"kra/internal/routeinfo"
"kra/internal/service/dto"
)
func (s *SystemConfigService) Initialize(ctx context.Context, input *dto.DatabaseInitRequest, apis []*biz.API) error {
driver, config := input.DBType, ""
switch driver {
case "mysql":
config = "charset=utf8mb4&parseTime=True&loc=Local"
case "pgsql":
config = "sslmode=disable TimeZone=Asia/Shanghai"
case "sqlite", "mssql":
default:
// The compatible initialization flow treats an omitted or unknown dbType as MySQL during
// initialization rather than rejecting it as an unsupported driver.
driver = "mysql"
config = "charset=utf8mb4&parseTime=True&loc=Local"
}
return s.uc.Initialize(ctx, &biz.DatabaseConfig{Driver: driver, Host: input.Host, Port: input.Port, User: input.UserName, Password: input.Password, Name: input.DBName, Path: input.DBPath, Config: config, Template: input.Template, AdminPassword: input.AdminPassword, APIs: apis})
}
func (s *SystemConfigService) InitializeRoutes(ctx context.Context, input *dto.DatabaseInitRequest, routes []dto.Route) error {
apis := make([]*biz.API, 0, len(routes))
for _, route := range routes {
path := NormalizeRoutePath(route.Path, s.settings.RouterPrefix())
group, description := routeinfo.Metadata(route.Method, path)
apis = append(apis, &biz.API{Path: path, Method: route.Method, APIGroup: group, Description: description})
}
return s.Initialize(ctx, input, apis)
}
-91
View File
@@ -1,91 +0,0 @@
package service
import (
"context"
"encoding/json"
"time"
"kra/internal/biz"
"kra/internal/service/dto"
)
type TaskService struct {
uc *biz.TaskApplicationUsecase
}
func NewTaskService(uc *biz.TaskApplicationUsecase) *TaskService {
return &TaskService{uc: uc}
}
func taskDomain(v *dto.TaskRequest) *biz.TimedTask {
return &biz.TimedTask{ID: v.ID, Name: v.Name, Description: v.Description, Spec: v.Spec, WithSeconds: v.WithSeconds, ExecutorType: v.ExecutorType, MethodName: v.MethodName, Params: v.Params, HTTPURL: v.HTTPURL, HTTPMethod: v.HTTPMethod, HTTPHeader: v.HTTPHeader, HTTPBody: v.HTTPBody, HTTPAllowPrivate: v.HTTPAllowPrivate, Enabled: v.Enabled}
}
func (s *TaskService) CreateRequest(ctx context.Context, req *dto.TaskRequest) (uint, error) {
value := taskDomain(req)
if err := s.Create(ctx, value); err != nil {
return 0, err
}
return value.ID, nil
}
func (s *TaskService) UpdateRequest(ctx context.Context, req *dto.TaskRequest) error {
return s.Update(ctx, taskDomain(req))
}
func (s *TaskService) ListRequest(ctx context.Context, page, size int, name, executorType string, enabled *bool) ([]*dto.TaskResponse, int64, error) {
return s.Tasks(ctx, page, size, &biz.TimedTask{Name: name, ExecutorType: executorType, EnabledFilter: enabled})
}
func (s *TaskService) Create(ctx context.Context, v *biz.TimedTask) error {
return s.uc.Create(ctx, v)
}
func (s *TaskService) Update(ctx context.Context, v *biz.TimedTask) error {
return s.uc.Update(ctx, v)
}
func (s *TaskService) Delete(ctx context.Context, id uint) error {
return s.uc.Delete(ctx, id)
}
func (s *TaskService) Toggle(ctx context.Context, id uint, enabled bool) error {
return s.uc.Toggle(ctx, id, enabled)
}
func taskDTO(v *biz.TimedTask, next *time.Time) *dto.TaskResponse {
return &dto.TaskResponse{ID: v.ID, CreatedAt: v.CreatedAt, UpdatedAt: v.UpdatedAt, DeletedAt: nil, Name: v.Name, Description: v.Description, Spec: v.Spec, WithSeconds: v.WithSeconds, ExecutorType: v.ExecutorType, MethodName: v.MethodName, Params: json.RawMessage(v.Params), HTTPURL: v.HTTPURL, HTTPMethod: v.HTTPMethod, HTTPHeader: json.RawMessage(v.HTTPHeader), HTTPBody: v.HTTPBody, HTTPAllowPrivate: v.HTTPAllowPrivate, Enabled: v.Enabled, NextRunAt: next}
}
func (s *TaskService) Tasks(ctx context.Context, page, size int, q *biz.TimedTask) ([]*dto.TaskResponse, int64, error) {
items, total, next, err := s.uc.List(ctx, page, size, q)
if err != nil {
return nil, 0, err
}
out := make([]*dto.TaskResponse, 0, len(items))
for _, v := range items {
var ptr *time.Time
if value, ok := next[v.ID]; ok {
copy := value
ptr = &copy
}
out = append(out, taskDTO(v, ptr))
}
return out, total, nil
}
func (s *TaskService) Logs(ctx context.Context, page, size int, taskID uint, status string) ([]*dto.TaskLogResponse, int64, error) {
items, total, err := s.uc.Logs(ctx, page, size, taskID, status)
if err != nil {
return nil, 0, err
}
out := make([]*dto.TaskLogResponse, 0, len(items))
for _, v := range items {
out = append(out, &dto.TaskLogResponse{ID: v.ID, CreatedAt: v.CreatedAt, UpdatedAt: v.UpdatedAt, DeletedAt: nil, TaskID: v.TaskID, TaskName: v.TaskName, TriggerType: v.TriggerType, StartedAt: v.StartedAt, FinishedAt: v.FinishedAt, DurationMS: v.DurationMS, Status: v.Status, ErrorMsg: v.ErrorMsg, Output: v.Output})
}
return out, total, nil
}
func (s *TaskService) Trigger(ctx context.Context, id uint) error { return s.uc.Trigger(ctx, id) }
func (s *TaskService) Reload(ctx context.Context) error { return s.uc.Reload(ctx) }
func (s *TaskService) Subscribe(userID uint) chan []byte { return s.uc.Subscribe(userID) }
func (s *TaskService) Unsubscribe(userID uint, events chan []byte) { s.uc.Unsubscribe(userID, events) }
func (s *TaskService) RegisteredMethods() []*dto.TaskMethodResponse {
methods := biz.RegisteredTaskMethods()
out := make([]*dto.TaskMethodResponse, 0, len(methods))
for _, method := range methods {
out = append(out, &dto.TaskMethodResponse{Name: method.Name, Description: method.Description})
}
return out
}
-132
View File
@@ -1,132 +0,0 @@
package service
import (
"context"
"kra/internal/biz"
"kra/internal/service/dto"
)
type userInput struct {
ID uint
Username, Password, NickName, HeaderImg, Phone, Email string
AuthorityID uint
Enable int
AuthorityIDs []uint
}
type UserService struct {
uc *biz.UserUsecase
settings *SecurityService
}
func NewUserService(uc *biz.UserUsecase, settings *SecurityService) *UserService {
return &UserService{uc: uc, settings: settings}
}
func userRequestInput(value *dto.UserRequest) userInput {
return userInput{ID: value.ID, Username: value.Username, Password: value.Password, NickName: value.NickName, HeaderImg: value.HeaderImg, AuthorityID: value.AuthorityID, AuthorityIDs: value.AuthorityIDs, Enable: value.Enable, Phone: value.Phone, Email: value.Email}
}
func (s *UserService) ListUsersRequest(ctx context.Context, value *dto.UserListRequest) ([]*dto.UserResponse, int64, error) {
return s.ListUsers(ctx, value.Page, value.PageSize, &biz.UserListFilter{Username: value.Username, NickName: value.NickName, Phone: value.Phone, Email: value.Email, OrderKey: value.OrderKey, Desc: value.Desc})
}
func (s *UserService) CreateUserRequest(ctx context.Context, value *dto.UserRequest) (*dto.UserResponse, error) {
return s.createUser(ctx, userRequestInput(value))
}
func (s *UserService) UpdateUserRequest(ctx context.Context, value *dto.UserRequest) error {
return s.updateUser(ctx, userRequestInput(value))
}
func (s *UserService) UpdateSelfUserRequest(ctx context.Context, id uint, value *dto.SelfUserRequest) error {
return s.updateSelfUser(ctx, userInput{ID: id, NickName: value.NickName, HeaderImg: value.HeaderImg, Phone: value.Phone, Email: value.Email, Enable: value.Enable})
}
func (s *UserService) User(ctx context.Context, id uint) (*dto.UserResponse, error) {
value, err := s.uc.User(ctx, id)
if err != nil {
return nil, err
}
return convertUser(value), nil
}
func (s *UserService) UserByUUID(ctx context.Context, uuid string) (*dto.UserResponse, error) {
value, err := s.uc.UserByUUID(ctx, uuid)
if err != nil {
return nil, err
}
return convertUser(value), nil
}
func (s *UserService) Menus(ctx context.Context, authorityID uint) ([]*dto.DynamicMenuResponse, error) {
menus, err := s.uc.Menus(ctx, authorityID)
if err != nil {
return nil, err
}
return dynamicMenuResponses(menus), nil
}
func (s *UserService) ListUsers(ctx context.Context, page, pageSize int, filter *biz.UserListFilter) ([]*dto.UserResponse, int64, error) {
users, total, err := s.uc.ListUsers(ctx, page, pageSize, filter)
if err != nil {
return nil, 0, err
}
result := make([]*dto.UserResponse, 0, len(users))
for _, user := range users {
result = append(result, convertUser(user))
}
return result, total, nil
}
func (s *UserService) Authorities(ctx context.Context) ([]*dto.AuthorityResponse, error) {
values, err := s.uc.Authorities(ctx)
if err != nil {
return nil, err
}
result := make([]*dto.AuthorityResponse, 0, len(values))
for _, value := range values {
result = append(result, convertAuthority(*value))
}
return result, nil
}
func (s *UserService) createUser(ctx context.Context, input userInput) (*dto.UserResponse, error) {
if err := s.settings.ValidatePassword(ctx, input.Password); err != nil {
return nil, err
}
security, _ := s.settings.CurrentSecurity(ctx)
mustChange := security != nil && security.ForceNewUserChangePassword
user, err := s.uc.CreateUser(ctx, &biz.User{Username: input.Username, Password: input.Password, NickName: input.NickName, HeaderImg: input.HeaderImg, AuthorityID: input.AuthorityID, Phone: input.Phone, Email: input.Email, Enable: input.Enable, MustChangePassword: mustChange}, input.AuthorityIDs)
if err != nil {
return nil, err
}
return convertUser(user), nil
}
func (s *UserService) updateUser(ctx context.Context, input userInput) error {
// The compatible ChangeUserInfo payload uses authorityIds for role assignment; the
// standalone authorityId field is not applied by setUserInfo.
return s.uc.UpdateUser(ctx, &biz.User{ID: input.ID, NickName: input.NickName, HeaderImg: input.HeaderImg, Phone: input.Phone, Email: input.Email, Enable: input.Enable}, input.AuthorityIDs)
}
func (s *UserService) updateSelfUser(ctx context.Context, input userInput) error {
return s.uc.UpdateSelfUser(ctx, &biz.User{ID: input.ID, NickName: input.NickName, HeaderImg: input.HeaderImg, Phone: input.Phone, Email: input.Email, Enable: input.Enable})
}
func (s *UserService) DeleteUser(ctx context.Context, id uint) error {
return s.uc.DeleteUser(ctx, id)
}
func (s *UserService) ResetPassword(ctx context.Context, id uint, password string) error {
if err := s.settings.ValidatePassword(ctx, password); err != nil {
return err
}
return s.uc.ResetPassword(ctx, id, password)
}
func (s *UserService) ChangePassword(ctx context.Context, id uint, oldPassword, newPassword string) error {
if err := s.settings.ValidatePassword(ctx, newPassword); err != nil {
return err
}
return s.uc.ChangePassword(ctx, id, oldPassword, newPassword)
}
func (s *UserService) SetUserAuthorities(ctx context.Context, id uint, authorityIDs []uint) error {
return s.uc.SetUserAuthorities(ctx, id, authorityIDs)
}
func (s *UserService) SetUserSetting(ctx context.Context, id uint, setting map[string]any) error {
return s.uc.SetUserSetting(ctx, id, setting)
}
-44
View File
@@ -1,44 +0,0 @@
package service
import (
"kra/internal/biz"
"kra/internal/service/dto"
)
func convertAuthority(value biz.Authority) *dto.AuthorityResponse {
var menus []*dto.MenuResponse
if value.Menus != nil {
menus = menuResponses(value.Menus)
}
return &dto.AuthorityResponse{CreatedAt: value.CreatedAt, UpdatedAt: value.UpdatedAt, DeletedAt: value.DeletedAt, AuthorityID: value.AuthorityID, AuthorityName: value.AuthorityName, ParentID: value.ParentID, Children: nil, Menus: menus, DataScope: value.DataScope, DefaultRouter: value.DefaultRouter}
}
func convertUser(user *biz.User) *dto.UserResponse {
var authorities []*dto.AuthorityResponse
if user.Authorities != nil {
authorities = make([]*dto.AuthorityResponse, 0, len(user.Authorities))
for _, value := range user.Authorities {
authorities = append(authorities, convertAuthority(value))
}
}
var departments []*dto.DepartmentResponse
if user.Departments != nil {
departments = make([]*dto.DepartmentResponse, 0, len(user.Departments))
for i := range user.Departments {
departments = append(departments, departmentResponse(&user.Departments[i]))
}
}
var positions []*dto.PositionResponse
if user.Positions != nil {
positions = make([]*dto.PositionResponse, 0, len(user.Positions))
for i := range user.Positions {
positions = append(positions, positionResponse(&user.Positions[i]))
}
}
// The primary department is represented by a zero-value object when it is
// absent, preserving the response shape expected by the administration UI.
var department any = dto.DepartmentResponse{}
if user.Department != nil {
department = departmentResponse(user.Department)
}
return &dto.UserResponse{ID: user.ID, CreatedAt: user.CreatedAt, UpdatedAt: user.UpdatedAt, DeletedAt: nil, UUID: user.UUID, Username: user.Username, NickName: user.NickName, HeaderImg: user.HeaderImg, AuthorityID: user.AuthorityID, Authority: convertAuthority(user.Authority), Authorities: authorities, DeptID: user.DeptID, Department: department, Departments: departments, Positions: positions, Phone: user.Phone, Email: user.Email, Enable: user.Enable, OriginSetting: user.OriginSetting, PasswordUpdatedAt: user.PasswordUpdatedAt}
}
-268
View File
@@ -1,268 +0,0 @@
package service
import (
"context"
"encoding/json"
"time"
"kra/internal/biz"
"kra/internal/service/dto"
)
type VersionService struct{ uc *biz.VersionUsecase }
func NewVersionService(uc *biz.VersionUsecase) *VersionService { return &VersionService{uc: uc} }
type versionExportInfo struct {
Name string `json:"name"`
Code string `json:"code"`
Description string `json:"description"`
ExportTime string `json:"exportTime"`
}
type versionExportMenuParameter struct {
ID uint `json:"ID"`
CreatedAt time.Time `json:"CreatedAt"`
UpdatedAt time.Time `json:"UpdatedAt"`
SysBaseMenuID uint `json:"SysBaseMenuID"`
Type string `json:"type"`
Key string `json:"key"`
Value string `json:"value"`
}
type versionExportMenuButton struct {
ID uint `json:"ID"`
CreatedAt time.Time `json:"CreatedAt"`
UpdatedAt time.Time `json:"UpdatedAt"`
Name string `json:"name"`
Description string `json:"desc"`
SysBaseMenuID uint `json:"sysBaseMenuID"`
}
type versionExportMenu struct {
ID uint `json:"ID"`
CreatedAt time.Time `json:"CreatedAt"`
UpdatedAt time.Time `json:"UpdatedAt"`
ParentID uint `json:"parentId"`
Path string `json:"path"`
Name string `json:"name"`
Hidden bool `json:"hidden"`
Component string `json:"component"`
Sort int `json:"sort"`
Meta dto.VersionMenuMetaRequest `json:"meta"`
Authorities []any `json:"authoritys"`
Children []*versionExportMenu `json:"children"`
Parameters []versionExportMenuParameter `json:"parameters"`
MenuButtons []versionExportMenuButton `json:"menuBtn"`
}
type versionExportAPI struct {
ID uint `json:"ID"`
CreatedAt time.Time `json:"CreatedAt"`
UpdatedAt time.Time `json:"UpdatedAt"`
Path string `json:"path"`
Description string `json:"description"`
APIGroup string `json:"apiGroup"`
Method string `json:"method"`
}
type versionExportDictionaryDetail struct {
ID uint `json:"ID"`
CreatedAt time.Time `json:"CreatedAt"`
UpdatedAt time.Time `json:"UpdatedAt"`
Label string `json:"label"`
Value string `json:"value"`
Extend string `json:"extend"`
Status *bool `json:"status"`
Sort int `json:"sort"`
DictionaryID int `json:"sysDictionaryID"`
ParentID *uint `json:"parentID"`
Children []versionExportDictionaryDetail `json:"children"`
Level int `json:"level"`
Path string `json:"path"`
Disabled bool `json:"disabled"`
}
type versionExportDictionary struct {
ID uint `json:"ID"`
CreatedAt time.Time `json:"CreatedAt"`
UpdatedAt time.Time `json:"UpdatedAt"`
Name string `json:"name"`
Type string `json:"type"`
Status *bool `json:"status"`
Desc string `json:"desc"`
ParentID *uint `json:"parentID"`
Children []versionExportDictionary `json:"children"`
Details []versionExportDictionaryDetail `json:"sysDictionaryDetails"`
}
type versionExportDocument struct {
Version versionExportInfo `json:"version"`
Menus []*versionExportMenu `json:"menus"`
APIs []versionExportAPI `json:"apis"`
Dictionaries []versionExportDictionary `json:"dictionaries"`
}
func exportMenu(value *biz.Menu) *versionExportMenu {
menu := &versionExportMenu{
Path: value.Path, Name: value.Name, Hidden: value.Hidden, Component: value.Component, Sort: value.Sort,
Meta: dto.VersionMenuMetaRequest{ActiveName: value.ActiveName, KeepAlive: value.KeepAlive, DefaultMenu: value.DefaultMenu, Title: value.Title, Icon: value.Icon, CloseTab: value.CloseTab, TransitionType: value.TransitionType},
}
if len(value.Parameters) > 0 {
menu.Parameters = make([]versionExportMenuParameter, 0, len(value.Parameters))
for _, parameter := range value.Parameters {
menu.Parameters = append(menu.Parameters, versionExportMenuParameter{Type: parameter.Type, Key: parameter.Key, Value: parameter.Value})
}
}
if len(value.Buttons) > 0 {
menu.MenuButtons = make([]versionExportMenuButton, 0, len(value.Buttons))
for _, button := range value.Buttons {
menu.MenuButtons = append(menu.MenuButtons, versionExportMenuButton{Name: button.Name, Description: button.Description})
}
}
if len(value.Children) > 0 {
menu.Children = make([]*versionExportMenu, 0, len(value.Children))
for _, child := range value.Children {
menu.Children = append(menu.Children, exportMenu(child))
}
}
return menu
}
func versionDTO(v *biz.Version) *dto.VersionResponse {
return &dto.VersionResponse{ID: v.ID, CreatedAt: v.CreatedAt, UpdatedAt: v.UpdatedAt, DeletedAt: nil, VersionName: v.Name, VersionCode: v.Code, Description: v.Description, VersionData: v.Data}
}
func versionValue(value *string) string {
if value == nil {
return ""
}
return *value
}
func versionPointer(value string) *string { return &value }
func (s *VersionService) Versions(ctx context.Context, page, size int, name, code string, createdAtRange []*time.Time) ([]*dto.VersionResponse, int64, error) {
items, total, err := s.uc.ListVersions(ctx, page, size, name, code, createdAtRange)
if err != nil {
return nil, 0, err
}
out := make([]*dto.VersionResponse, 0, len(items))
for _, v := range items {
out = append(out, versionDTO(v))
}
return out, total, nil
}
func (s *VersionService) Version(ctx context.Context, id uint) (*dto.VersionResponse, error) {
v, err := s.uc.FindVersion(ctx, id)
if err != nil {
return nil, err
}
return versionDTO(v), nil
}
func (s *VersionService) VersionData(ctx context.Context, id uint) (string, string, error) {
v, err := s.uc.FindVersion(ctx, id)
if err != nil {
return "", "", err
}
if v.Data != nil && *v.Data != "" {
return *v.Data, versionValue(v.Code), nil
}
payload := versionExportDocument{
Version: versionExportInfo{Name: versionValue(v.Name), Code: versionValue(v.Code), Description: versionValue(v.Description), ExportTime: v.CreatedAt.Format("2006-01-02 15:04:05")},
Menus: []*versionExportMenu{},
APIs: []versionExportAPI{},
}
raw, marshalErr := json.MarshalIndent(payload, "", " ")
if marshalErr != nil {
return "", "", marshalErr
}
return string(raw), versionValue(v.Code), nil
}
func (s *VersionService) DeleteVersions(ctx context.Context, ids []uint) error {
return s.uc.DeleteVersions(ctx, ids)
}
func (s *VersionService) Export(ctx context.Context, name, code, description string, menuIDs, apiIDs, dictIDs []uint) error {
bundle, err := s.uc.BuildVersionBundle(ctx, menuIDs, apiIDs, dictIDs)
if err != nil {
return err
}
bundle.Name = name
bundle.Code = code
bundle.Description = description
bundle.ExportTime = time.Now().Format("2006-01-02 15:04:05")
var menus []*versionExportMenu
if bundle.Menus != nil {
menus = make([]*versionExportMenu, 0, len(bundle.Menus))
for _, value := range bundle.Menus {
menus = append(menus, exportMenu(value))
}
}
apis := make([]versionExportAPI, 0, len(bundle.APIs))
for _, value := range bundle.APIs {
apis = append(apis, versionExportAPI{Path: value.Path, Description: value.Description, APIGroup: value.APIGroup, Method: value.Method})
}
dictionaries := make([]versionExportDictionary, 0, len(bundle.Dictionaries))
for _, value := range bundle.Dictionaries {
details := make([]versionExportDictionaryDetail, 0, len(value.Details))
for _, detail := range value.Details {
details = append(details, versionExportDictionaryDetail{Label: detail.Label, Value: detail.Value, Extend: detail.Extend, Status: detail.Status, Sort: detail.Sort})
}
dictionaries = append(dictionaries, versionExportDictionary{Name: value.Name, Type: value.Type, Status: value.Status, Desc: value.Desc, Details: details})
}
payload := versionExportDocument{Version: versionExportInfo{Name: name, Code: code, Description: description, ExportTime: bundle.ExportTime}, Menus: menus, APIs: apis, Dictionaries: dictionaries}
raw, err := json.MarshalIndent(payload, "", " ")
if err != nil {
return &biz.VersionStageError{Stage: biz.VersionStageJSON, Err: err}
}
if err = s.uc.CreateVersion(ctx, &biz.Version{Name: versionPointer(name), Code: versionPointer(code), Description: versionPointer(description), Data: versionPointer(string(raw))}); err != nil {
return &biz.VersionStageError{Stage: biz.VersionStageSave, Err: err}
}
return nil
}
func (s *VersionService) Import(ctx context.Context, bundle *biz.VersionBundle) error {
return s.uc.ImportVersionBundle(ctx, bundle)
}
func versionMenuDomain(value dto.VersionMenuRequest) *biz.Menu {
menu := &biz.Menu{Path: value.Path, Name: value.Name, Hidden: value.Hidden, Component: value.Component, Sort: value.Sort, ActiveName: value.Meta.ActiveName, KeepAlive: value.Meta.KeepAlive, DefaultMenu: value.Meta.DefaultMenu, Title: value.Meta.Title, Icon: value.Meta.Icon, CloseTab: value.Meta.CloseTab, TransitionType: value.Meta.TransitionType}
for _, button := range value.MenuButtons {
menu.Buttons = append(menu.Buttons, &biz.MenuButton{Name: button.Name, Description: button.Description})
}
for _, parameter := range value.Parameters {
menu.Parameters = append(menu.Parameters, &biz.MenuParameter{Type: parameter.Type, Key: parameter.Key, Value: parameter.Value})
}
for _, child := range value.Children {
menu.Children = append(menu.Children, versionMenuDomain(child))
}
return menu
}
func (s *VersionService) ImportRequest(ctx context.Context, req *dto.ImportVersionRequest) error {
if req.Version.Name == "" || req.Version.Code == "" {
return biz.ErrInvalidVersion
}
bundle := &biz.VersionBundle{Name: req.Version.Name, Code: req.Version.Code, Description: req.Version.Description, ExportTime: req.Version.ExportTime}
for _, menu := range req.Menus {
bundle.Menus = append(bundle.Menus, versionMenuDomain(menu))
}
for _, api := range req.APIs {
bundle.APIs = append(bundle.APIs, &biz.API{Path: api.Path, Description: api.Description, APIGroup: api.APIGroup, Method: api.Method})
}
for _, dictionary := range req.Dictionaries {
item := &biz.Dictionary{Name: dictionary.Name, Type: dictionary.Type, Status: dictionary.Status, Desc: dictionary.Description}
for _, detail := range dictionary.Details {
item.Details = append(item.Details, &biz.DictionaryDetail{Label: detail.Label, Value: detail.Value, Extend: detail.Extend, Status: detail.Status, Sort: detail.Sort, ParentID: detail.ParentID, Level: detail.Level, Path: detail.Path})
}
bundle.Dictionaries = append(bundle.Dictionaries, item)
}
if err := s.Import(ctx, bundle); err != nil {
return err
}
raw, _ := json.Marshal(req)
_ = s.uc.CreateVersion(ctx, &biz.Version{
Name: versionPointer(req.Version.Name),
Code: versionPointer(req.Version.Code + "_imported_" + time.Now().Format("20060102150405")),
Description: versionPointer("导入版本: " + req.Version.Description),
Data: versionPointer(string(raw)),
})
return nil
}