refactor: separate backend domains and storage adapters
This commit is contained in:
@@ -106,6 +106,13 @@ func (s *AccessService) DataScopeDepartmentIDs(ctx context.Context, id uint) ([]
|
||||
func (s *AccessService) ResolveDataScope(ctx context.Context, authorityID, userID uint) (biz.DataScope, error) {
|
||||
return s.uc.Repo().ResolveDataScope(ctx, authorityID, userID)
|
||||
}
|
||||
func (s *AccessService) 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
|
||||
}
|
||||
|
||||
func (s *AccessService) DeleteAPIs(ctx context.Context, ids []uint) error {
|
||||
return s.uc.Repo().DeleteAPIs(ctx, ids)
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"kra/internal/biz"
|
||||
"kra/pkg/adminauth"
|
||||
)
|
||||
|
||||
func tokenDTO(v *biz.APIToken) map[string]any {
|
||||
var user any = nil
|
||||
if v.User != nil {
|
||||
user = convertUser(v.User)
|
||||
}
|
||||
return map[string]any{"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 *SettingsService) CreateAPIToken(ctx context.Context, userID, authorityID uint, days int, remark string) (string, error) {
|
||||
user, allowed, err := s.Repo().UserHasAuthority(ctx, userID, authorityID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if !allowed {
|
||||
return "", errors.New("用户不具备该角色权限")
|
||||
}
|
||||
duration := time.Duration(days) * 24 * time.Hour
|
||||
if days == -1 {
|
||||
duration = 100 * 365 * 24 * time.Hour
|
||||
}
|
||||
if duration <= 0 {
|
||||
return "", errors.New("有效天数必须大于0或为-1")
|
||||
}
|
||||
secret, issuer := "", "kra"
|
||||
buffer := 24 * time.Hour
|
||||
if s.config != nil && s.config.Jwt != nil {
|
||||
secret = s.config.Jwt.SigningKey
|
||||
if s.config.Jwt.Issuer != "" {
|
||||
issuer = s.config.Jwt.Issuer
|
||||
}
|
||||
if s.config.Jwt.BufferTime != nil {
|
||||
buffer = s.config.Jwt.BufferTime.AsDuration()
|
||||
}
|
||||
}
|
||||
token, _, err := adminauth.Generate(secret, issuer, duration, buffer, user.ID, authorityID, user.UUID, user.Username, user.NickName, false)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
record := &biz.APIToken{UserID: userID, AuthorityID: authorityID, Token: token, Status: true, ExpiresAt: time.Now().Add(duration), Remark: remark}
|
||||
if err = s.Repo().CreateAPIToken(ctx, record); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return token, nil
|
||||
}
|
||||
func (s *SettingsService) APITokens(ctx context.Context, page, size int, userID uint, status *bool) ([]map[string]any, int64, error) {
|
||||
items, total, err := s.Repo().ListAPITokens(ctx, page, size, userID, status)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
out := make([]map[string]any, 0, len(items))
|
||||
for _, v := range items {
|
||||
out = append(out, tokenDTO(v))
|
||||
}
|
||||
return out, total, nil
|
||||
}
|
||||
func (s *SettingsService) DisableAPIToken(ctx context.Context, id uint) error {
|
||||
token, err := s.Repo().DisableAPIToken(ctx, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return s.Repo().BlacklistToken(ctx, token)
|
||||
}
|
||||
func (s *SettingsService) BlacklistToken(ctx context.Context, token string) error {
|
||||
return s.Repo().BlacklistToken(ctx, token)
|
||||
}
|
||||
func (s *SettingsService) IsTokenDisabled(ctx context.Context, token string) (bool, error) {
|
||||
return s.Repo().IsTokenDisabled(ctx, token)
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package service
|
||||
import (
|
||||
"context"
|
||||
"kra/internal/biz"
|
||||
"kra/internal/service/dto"
|
||||
)
|
||||
|
||||
type AuditService struct{ uc *biz.AuditUsecase }
|
||||
@@ -11,12 +12,30 @@ func NewAuditService(uc *biz.AuditUsecase) *AuditService { return &AuditService{
|
||||
func (s *AuditService) RecordOperation(ctx context.Context, v *biz.OperationRecord) error {
|
||||
return s.uc.Repo().RecordOperation(ctx, v)
|
||||
}
|
||||
func (s *AuditService) 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, ip string, userID uint) ([]map[string]any, int64, error) {
|
||||
return s.Operations(ctx, page, size, &biz.OperationRecord{Path: path, Method: method, Status: status, IP: ip, UserID: userID})
|
||||
}
|
||||
func (s *AuditService) RecordLogin(ctx context.Context, v *biz.LoginLog) error {
|
||||
return s.uc.Repo().RecordLogin(ctx, v)
|
||||
}
|
||||
func (s *AuditService) 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, ip string) ([]map[string]any, int64, error) {
|
||||
return s.Logins(ctx, page, size, &biz.LoginLog{Username: username, IP: ip})
|
||||
}
|
||||
func (s *AuditService) RecordDataAccess(ctx context.Context, v *biz.DataAccessLog) error {
|
||||
return s.uc.Repo().RecordDataAccess(ctx, v)
|
||||
}
|
||||
func (s *AuditService) 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) ([]map[string]any, int64, error) {
|
||||
return s.DataAccess(ctx, req.Page, req.PageSize, &biz.DataAccessLog{EventType: req.EventType, TargetTable: req.TargetTable, UserID: req.UserID})
|
||||
}
|
||||
func opDTO(v *biz.OperationRecord) map[string]any {
|
||||
return map[string]any{"ID": v.ID, "CreatedAt": v.CreatedAt, "DeletedAt": nil, "ip": v.IP, "method": v.Method, "path": v.Path, "status": v.Status, "latency_ms": v.LatencyMS, "agent": v.Agent, "error_message": v.ErrorMessage, "body": v.Body, "resp": v.Response, "user_id": v.UserID, "request_id": v.RequestID, "trace_id": v.TraceID, "device_id": v.DeviceID, "user": nil}
|
||||
}
|
||||
@@ -117,6 +136,18 @@ func errorDTO(v *biz.ErrorRecord) map[string]any {
|
||||
func (s *AuditService) CreateError(ctx context.Context, v *biz.ErrorRecord) error {
|
||||
return s.uc.Repo().CreateError(ctx, v)
|
||||
}
|
||||
func errorDomain(value *dto.ErrorRecordRequest) *biz.ErrorRecord {
|
||||
return &biz.ErrorRecord{ID: value.ID, Form: value.Form, Info: value.Info, Level: value.Level, RequestID: value.RequestID, TraceID: value.TraceID, Solution: value.Solution, Status: value.Status}
|
||||
}
|
||||
func (s *AuditService) CreateErrorRequest(ctx context.Context, req *dto.ErrorRecordRequest) error {
|
||||
return s.CreateError(ctx, errorDomain(req))
|
||||
}
|
||||
func (s *AuditService) UpdateErrorRequest(ctx context.Context, req *dto.ErrorRecordRequest) error {
|
||||
return s.UpdateError(ctx, errorDomain(req))
|
||||
}
|
||||
func (s *AuditService) ErrorsFilter(ctx context.Context, page, size int, form, level, status string) ([]map[string]any, int64, error) {
|
||||
return s.Errors(ctx, page, size, &biz.ErrorRecord{Form: form, Level: level, Status: status})
|
||||
}
|
||||
func (s *AuditService) UpdateError(ctx context.Context, v *biz.ErrorRecord) error {
|
||||
return s.uc.Repo().UpdateError(ctx, v)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"kra/internal/biz"
|
||||
"kra/pkg/adminauth"
|
||||
)
|
||||
|
||||
type LoginResult struct {
|
||||
User map[string]any `json:"user"`
|
||||
Token string `json:"token"`
|
||||
ExpiresAt int64 `json:"expiresAt"`
|
||||
NeedChangePassword bool `json:"needChangePassword"`
|
||||
}
|
||||
|
||||
func (s *SystemService) CacheGet(ctx context.Context, key string) (string, bool, error) {
|
||||
return s.uc.CacheGet(ctx, key)
|
||||
}
|
||||
func (s *SystemService) CacheSet(ctx context.Context, key, value string, expiration time.Duration) error {
|
||||
return s.uc.CacheSet(ctx, key, value, expiration)
|
||||
}
|
||||
func (s *SystemService) CacheDelete(ctx context.Context, key string) error {
|
||||
return s.uc.CacheDelete(ctx, key)
|
||||
}
|
||||
func (s *SystemService) CacheIncrement(ctx context.Context, key string, expiration time.Duration) (int64, error) {
|
||||
return s.uc.CacheIncrement(ctx, key, expiration)
|
||||
}
|
||||
|
||||
func (s *SystemService) Login(ctx context.Context, username, password string) (*LoginResult, error) {
|
||||
u, err := s.uc.Login(ctx, username, password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if u.Enable != 1 {
|
||||
return nil, biz.ErrInvalidCredentials
|
||||
}
|
||||
if security, securityErr := s.settings.CurrentSecurity(ctx); securityErr == nil && security.PwdExpireEnable && u.PasswordUpdatedAt != nil && time.Since(*u.PasswordUpdatedAt) > time.Duration(security.PwdExpireDays)*24*time.Hour {
|
||||
u.MustChangePassword = true
|
||||
}
|
||||
return s.issueLogin(u, u.AuthorityID)
|
||||
}
|
||||
|
||||
func (s *SystemService) issueLogin(user *biz.User, authorityID uint) (*LoginResult, error) {
|
||||
expires, buffer := 7*24*time.Hour, 24*time.Hour
|
||||
secret, issuer := "", "kra"
|
||||
if s.config != nil && s.config.Jwt != nil {
|
||||
secret, issuer = s.config.Jwt.SigningKey, s.config.Jwt.Issuer
|
||||
if s.config.Jwt.ExpiresTime != nil {
|
||||
expires = s.config.Jwt.ExpiresTime.AsDuration()
|
||||
}
|
||||
if s.config.Jwt.BufferTime != nil {
|
||||
buffer = s.config.Jwt.BufferTime.AsDuration()
|
||||
}
|
||||
}
|
||||
token, claims, err := adminauth.Generate(secret, issuer, expires, buffer, user.ID, authorityID, user.UUID, user.Username, user.NickName, user.MustChangePassword)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &LoginResult{User: convertUser(user), Token: token, ExpiresAt: claims.ExpiresAt.UnixMilli(), NeedChangePassword: user.MustChangePassword}, nil
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
||||
"kra/internal/biz"
|
||||
"kra/internal/service/dto"
|
||||
)
|
||||
|
||||
func dictionaryDomain(value *dto.DictionaryRequest) *biz.Dictionary {
|
||||
status := true
|
||||
if value.Status != nil {
|
||||
status = *value.Status
|
||||
}
|
||||
return &biz.Dictionary{ID: value.ID, Name: value.Name, Type: value.Type, Status: status, Desc: value.Description, ParentID: value.ParentID}
|
||||
}
|
||||
func detailDomain(value *dto.DictionaryDetailRequest) *biz.DictionaryDetail {
|
||||
status := true
|
||||
if value.Status != nil {
|
||||
status = *value.Status
|
||||
}
|
||||
return &biz.DictionaryDetail{ID: value.ID, Label: value.Label, Value: value.Value, Extend: value.Extend, Status: status, Sort: value.Sort, DictionaryID: value.DictionaryID, ParentID: value.ParentID, Level: value.Level, Path: value.Path}
|
||||
}
|
||||
func (s *SettingsService) CreateDictionaryRequest(ctx context.Context, req *dto.DictionaryRequest) error {
|
||||
return s.CreateDictionary(ctx, dictionaryDomain(req))
|
||||
}
|
||||
func (s *SettingsService) UpdateDictionaryRequest(ctx context.Context, req *dto.DictionaryRequest) error {
|
||||
return s.UpdateDictionary(ctx, dictionaryDomain(req))
|
||||
}
|
||||
func (s *SettingsService) CreateDictionaryDetailRequest(ctx context.Context, req *dto.DictionaryDetailRequest) error {
|
||||
return s.CreateDictionaryDetail(ctx, detailDomain(req))
|
||||
}
|
||||
func (s *SettingsService) UpdateDictionaryDetailRequest(ctx context.Context, req *dto.DictionaryDetailRequest) error {
|
||||
return s.UpdateDictionaryDetail(ctx, detailDomain(req))
|
||||
}
|
||||
func dictionaryDTO(v *biz.Dictionary) map[string]any {
|
||||
children := make([]map[string]any, 0, len(v.Children))
|
||||
for _, x := range v.Children {
|
||||
children = append(children, dictionaryDTO(x))
|
||||
}
|
||||
details := make([]map[string]any, 0, len(v.Details))
|
||||
for _, x := range v.Details {
|
||||
details = append(details, detailDTO(x))
|
||||
}
|
||||
return map[string]any{"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 detailDTO(v *biz.DictionaryDetail) map[string]any {
|
||||
children := make([]map[string]any, 0, len(v.Children))
|
||||
for _, x := range v.Children {
|
||||
children = append(children, detailDTO(x))
|
||||
}
|
||||
return map[string]any{"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, "sysDictionaryID": v.DictionaryID, "parentID": v.ParentID, "level": v.Level, "path": v.Path, "disabled": !v.Status, "children": children}
|
||||
}
|
||||
func (s *SettingsService) Dictionaries(ctx context.Context, page, size int, name, typ string, details bool) ([]map[string]any, int64, error) {
|
||||
items, total, err := s.Repo().ListDictionaries(ctx, page, size, name, typ, details)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
out := make([]map[string]any, 0, len(items))
|
||||
for _, v := range items {
|
||||
out = append(out, dictionaryDTO(v))
|
||||
}
|
||||
return out, total, nil
|
||||
}
|
||||
func (s *SettingsService) Dictionary(ctx context.Context, id uint, typ string, details bool) (map[string]any, error) {
|
||||
v, err := s.Repo().FindDictionary(ctx, id, typ, details)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dictionaryDTO(v), nil
|
||||
}
|
||||
func (s *SettingsService) CreateDictionary(ctx context.Context, v *biz.Dictionary) error {
|
||||
return s.Repo().CreateDictionary(ctx, v)
|
||||
}
|
||||
func (s *SettingsService) UpdateDictionary(ctx context.Context, v *biz.Dictionary) error {
|
||||
return s.Repo().UpdateDictionary(ctx, v)
|
||||
}
|
||||
func (s *SettingsService) DeleteDictionary(ctx context.Context, id uint) error {
|
||||
return s.Repo().DeleteDictionary(ctx, id)
|
||||
}
|
||||
func (s *SettingsService) DictionaryDetails(ctx context.Context, page, size int, dictionaryID uint, label, value string) ([]map[string]any, int64, error) {
|
||||
items, total, err := s.Repo().ListDictionaryDetails(ctx, page, size, dictionaryID, label, value)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
out := make([]map[string]any, 0, len(items))
|
||||
for _, v := range items {
|
||||
out = append(out, detailDTO(v))
|
||||
}
|
||||
return out, total, nil
|
||||
}
|
||||
func (s *SettingsService) DictionaryDetail(ctx context.Context, id uint) (map[string]any, error) {
|
||||
v, err := s.Repo().FindDictionaryDetail(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return detailDTO(v), nil
|
||||
}
|
||||
func (s *SettingsService) DictionaryTree(ctx context.Context, id uint, typ string) ([]map[string]any, error) {
|
||||
items, err := s.Repo().DictionaryDetailTree(ctx, id, typ)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out := make([]map[string]any, 0, len(items))
|
||||
for _, v := range items {
|
||||
out = append(out, detailDTO(v))
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
func (s *SettingsService) CreateDictionaryDetail(ctx context.Context, v *biz.DictionaryDetail) error {
|
||||
return s.Repo().CreateDictionaryDetail(ctx, v)
|
||||
}
|
||||
func (s *SettingsService) UpdateDictionaryDetail(ctx context.Context, v *biz.DictionaryDetail) error {
|
||||
return s.Repo().UpdateDictionaryDetail(ctx, v)
|
||||
}
|
||||
func (s *SettingsService) DeleteDictionaryDetail(ctx context.Context, id uint) error {
|
||||
return s.Repo().DeleteDictionaryDetail(ctx, id)
|
||||
}
|
||||
func (s *SettingsService) 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 json.Unmarshal([]byte(raw), &payload) != nil || payload.Name == "" || payload.Type == "" {
|
||||
return errors.New("JSON 格式错误")
|
||||
}
|
||||
dictionary := dictionaryDomain(&dto.DictionaryRequest{Name: payload.Name, Type: payload.Type, Status: payload.Status, Description: payload.Description})
|
||||
if err := s.CreateDictionary(ctx, dictionary); err != nil {
|
||||
return err
|
||||
}
|
||||
mapping := map[uint]uint{}
|
||||
pending := append([]dto.DictionaryDetailRequest(nil), payload.Details...)
|
||||
for len(pending) > 0 {
|
||||
progress := false
|
||||
next := pending[:0]
|
||||
for _, item := range pending {
|
||||
oldID := item.ID
|
||||
if item.ParentID != nil && *item.ParentID != 0 {
|
||||
parent, exists := mapping[*item.ParentID]
|
||||
if !exists {
|
||||
next = append(next, item)
|
||||
continue
|
||||
}
|
||||
item.ParentID = &parent
|
||||
}
|
||||
value := detailDomain(&item)
|
||||
value.ID = 0
|
||||
value.DictionaryID = dictionary.ID
|
||||
if err := s.CreateDictionaryDetail(ctx, value); err != nil {
|
||||
return errors.New("导入详情失败")
|
||||
}
|
||||
if oldID != 0 {
|
||||
mapping[oldID] = value.ID
|
||||
}
|
||||
progress = true
|
||||
}
|
||||
if !progress {
|
||||
return errors.New("字典层级关系无效")
|
||||
}
|
||||
pending = next
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (s *SettingsService) DictionaryDetailsByParent(ctx context.Context, dictionaryID, parentID uint) ([]map[string]any, error) {
|
||||
items, _, err := s.DictionaryDetails(ctx, 1, 10000, dictionaryID, "", "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out := []map[string]any{}
|
||||
for _, item := range items {
|
||||
parent, _ := item["parentID"].(*uint)
|
||||
if (parentID == 0 && parent == nil) || (parent != nil && *parent == parentID) {
|
||||
out = append(out, item)
|
||||
}
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package dto
|
||||
|
||||
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"`
|
||||
UserID uint `json:"userId"`
|
||||
}
|
||||
type ErrorRecordRequest struct {
|
||||
ID uint `json:"ID"`
|
||||
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"`
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package dto
|
||||
|
||||
type ExportConditionRequest struct {
|
||||
From string `json:"from"`
|
||||
Column string `json:"column"`
|
||||
Operator string `json:"operator"`
|
||||
}
|
||||
type ExportJoinRequest struct {
|
||||
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"`
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package dto
|
||||
|
||||
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"`
|
||||
}
|
||||
type IDRequest struct {
|
||||
ID uint `json:"ID" form:"id"`
|
||||
}
|
||||
type IDsRequest struct {
|
||||
IDs []uint `json:"ids"`
|
||||
}
|
||||
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"`
|
||||
}
|
||||
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"`
|
||||
FileHash string `json:"fileHash"`
|
||||
FileSize int64 `json:"fileSize"`
|
||||
ChunkSize int64 `json:"chunkSize"`
|
||||
ChunkTotal int `json:"chunkTotal"`
|
||||
}
|
||||
type CompleteUploadRequest struct {
|
||||
UploadID uint `json:"uploadId"`
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package dto
|
||||
|
||||
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 SystemParameterRequest struct {
|
||||
ID uint `json:"ID" form:"ID"`
|
||||
Name string `json:"name" form:"name"`
|
||||
Key string `json:"key" form:"key"`
|
||||
Value string `json:"value" form:"value"`
|
||||
Description string `json:"desc" form:"desc"`
|
||||
}
|
||||
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"`
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package dto
|
||||
|
||||
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"`
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package dto
|
||||
|
||||
import "kra/internal/conf"
|
||||
|
||||
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 struct {
|
||||
Admin struct {
|
||||
RouterPrefix string `json:"routerPrefix"`
|
||||
JWT struct {
|
||||
SigningKey string `json:"signingKey"`
|
||||
Issuer string `json:"issuer"`
|
||||
} `json:"jwt"`
|
||||
Local struct {
|
||||
StorePath string `json:"storePath"`
|
||||
PathPrefix string `json:"pathPrefix"`
|
||||
} `json:"local"`
|
||||
Media struct {
|
||||
SessionTTL int32 `json:"sessionTtl"`
|
||||
} `json:"media"`
|
||||
Storage *conf.AdminBackend_Storage `json:"storage"`
|
||||
} `json:"admin"`
|
||||
Email *struct {
|
||||
To string `json:"to"`
|
||||
From string `json:"from"`
|
||||
Host string `json:"host"`
|
||||
Secret string `json:"secret"`
|
||||
Nickname string `json:"nickname"`
|
||||
Port int32 `json:"port"`
|
||||
IsSSL bool `json:"is-ssl"`
|
||||
IsLoginAuth bool `json:"is-loginauth"`
|
||||
} `json:"email"`
|
||||
} `json:"config"`
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package dto
|
||||
|
||||
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 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"`
|
||||
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"`
|
||||
Code string `json:"code"`
|
||||
Description string `json:"description"`
|
||||
ExportTime string `json:"exportTime"`
|
||||
} `json:"version"`
|
||||
Menus []VersionMenuRequest `json:"menus"`
|
||||
APIs []VersionAPIRequest `json:"apis"`
|
||||
Dictionaries []VersionDictionaryRequest `json:"dictionaries"`
|
||||
}
|
||||
type ExportVersionRequest struct {
|
||||
VersionName string `json:"versionName"`
|
||||
VersionCode string `json:"versionCode"`
|
||||
Description string `json:"description"`
|
||||
MenuIDs []uint `json:"menuIds"`
|
||||
APIIDs []uint `json:"apiIds"`
|
||||
DictIDs []uint `json:"dictIds"`
|
||||
}
|
||||
@@ -8,12 +8,32 @@ import (
|
||||
"github.com/xuri/excelize/v2"
|
||||
"io"
|
||||
"kra/internal/biz"
|
||||
"kra/internal/service/dto"
|
||||
"sort"
|
||||
)
|
||||
|
||||
type ExportService struct{ uc *biz.ExportUsecase }
|
||||
|
||||
func NewExportService(uc *biz.ExportUsecase) *ExportService { return &ExportService{uc: uc} }
|
||||
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{From: item.From, Column: item.Column, Operator: item.Operator})
|
||||
}
|
||||
for _, item := range value.Joins {
|
||||
out.Joins = append(out.Joins, biz.ExportJoin{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) ([]map[string]any, int64, error) {
|
||||
return s.Templates(ctx, page, size, &biz.ExportTemplate{Name: name, TableName: tableName, TemplateID: templateID})
|
||||
}
|
||||
func exportDTO(v *biz.ExportTemplate) map[string]any {
|
||||
conditions := make([]map[string]any, 0, len(v.Conditions))
|
||||
for _, x := range v.Conditions {
|
||||
|
||||
+12
-23
@@ -3,7 +3,9 @@ package service
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"kra/internal/biz"
|
||||
"kra/internal/service/dto"
|
||||
)
|
||||
|
||||
type MediaService struct{ uc *biz.MediaUsecase }
|
||||
@@ -51,6 +53,13 @@ func (s *MediaService) Rename(ctx context.Context, id uint, name string) error {
|
||||
func (s *MediaService) ImportURLs(ctx context.Context, items []*biz.MediaFile) error {
|
||||
return s.uc.Repo().CreateMediaBatch(ctx, items)
|
||||
}
|
||||
func (s *MediaService) ImportURLRequests(ctx context.Context, userID uint, 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: userID})
|
||||
}
|
||||
return s.ImportURLs(ctx, items)
|
||||
}
|
||||
func (s *MediaService) Storage(ctx context.Context, prefix, cursor string, limit int) ([]map[string]any, string, bool, error) {
|
||||
items, next, more, err := s.uc.ListStorage(ctx, prefix, cursor, limit)
|
||||
if err != nil {
|
||||
@@ -76,29 +85,9 @@ func (s *MediaService) Categories(ctx context.Context) ([]map[string]any, error)
|
||||
func (s *MediaService) SaveCategory(ctx context.Context, v *biz.AttachmentCategory) error {
|
||||
return s.uc.Repo().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.Repo().DeleteCategory(ctx, id)
|
||||
}
|
||||
func (s *MediaService) InitUpload(ctx context.Context, userID uint, name, hash string, size, chunkSize int64, total int) (map[string]any, error) {
|
||||
session, media, chunks, err := s.uc.InitUpload(ctx, userID, name, hash, size, chunkSize, total)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if media != nil {
|
||||
return map[string]any{"instant": true, "media": mediaDTO(media), "uploadedChunks": []int{}}, nil
|
||||
}
|
||||
return map[string]any{"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) (map[string]any, 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)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
)
|
||||
|
||||
func (s *MediaService) InitUpload(ctx context.Context, userID uint, name, hash string, size, chunkSize int64, total int) (map[string]any, error) {
|
||||
session, media, chunks, err := s.uc.InitUpload(ctx, userID, name, hash, size, chunkSize, total)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if media != nil {
|
||||
return map[string]any{"instant": true, "media": mediaDTO(media), "uploadedChunks": []int{}}, nil
|
||||
}
|
||||
return map[string]any{"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) (map[string]any, 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)
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"kra/internal/biz"
|
||||
"kra/internal/service/dto"
|
||||
)
|
||||
|
||||
func parameterDomain(value *dto.SystemParameterRequest) *biz.SystemParameter {
|
||||
return &biz.SystemParameter{ID: value.ID, Name: value.Name, Key: value.Key, Value: value.Value, Desc: value.Description}
|
||||
}
|
||||
func (s *SettingsService) CreateParameterRequest(ctx context.Context, req *dto.SystemParameterRequest) error {
|
||||
return s.CreateParameter(ctx, parameterDomain(req))
|
||||
}
|
||||
func (s *SettingsService) UpdateParameterRequest(ctx context.Context, req *dto.SystemParameterRequest) error {
|
||||
return s.UpdateParameter(ctx, parameterDomain(req))
|
||||
}
|
||||
func (s *SettingsService) ParametersFilter(ctx context.Context, page, size int, name, key string) ([]map[string]any, int64, error) {
|
||||
return s.Parameters(ctx, page, size, &biz.SystemParameter{Name: name, Key: key})
|
||||
}
|
||||
func parameterDTO(v *biz.SystemParameter) map[string]any {
|
||||
return map[string]any{"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 *SettingsService) Parameters(ctx context.Context, page, size int, q *biz.SystemParameter) ([]map[string]any, int64, error) {
|
||||
items, total, err := s.Repo().ListParameters(ctx, page, size, q)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
out := make([]map[string]any, 0, len(items))
|
||||
for _, v := range items {
|
||||
out = append(out, parameterDTO(v))
|
||||
}
|
||||
return out, total, nil
|
||||
}
|
||||
func (s *SettingsService) Parameter(ctx context.Context, id uint, key string) (map[string]any, error) {
|
||||
v, err := s.Repo().FindParameter(ctx, id, key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return parameterDTO(v), nil
|
||||
}
|
||||
func (s *SettingsService) CreateParameter(ctx context.Context, v *biz.SystemParameter) error {
|
||||
return s.Repo().CreateParameter(ctx, v)
|
||||
}
|
||||
func (s *SettingsService) UpdateParameter(ctx context.Context, v *biz.SystemParameter) error {
|
||||
return s.Repo().UpdateParameter(ctx, v)
|
||||
}
|
||||
func (s *SettingsService) DeleteParameters(ctx context.Context, ids []uint) error {
|
||||
return s.Repo().DeleteParameters(ctx, ids)
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"kra/internal/biz"
|
||||
"kra/internal/service/dto"
|
||||
)
|
||||
|
||||
func securityDTO(v *biz.SecurityConfig) map[string]any {
|
||||
return map[string]any{"ID": v.ID, "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 *SettingsService) CurrentSecurity(ctx context.Context) (*biz.SecurityConfig, error) {
|
||||
s.securityMu.RLock()
|
||||
if s.securityCache != nil {
|
||||
copy := *s.securityCache
|
||||
s.securityMu.RUnlock()
|
||||
return ©, nil
|
||||
}
|
||||
s.securityMu.RUnlock()
|
||||
value, err := s.Repo().SecurityConfig(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.securityMu.Lock()
|
||||
s.securityCache = value
|
||||
copy := *value
|
||||
s.securityMu.Unlock()
|
||||
return ©, nil
|
||||
}
|
||||
func (s *SettingsService) Security(ctx context.Context) (map[string]any, error) {
|
||||
value, err := s.CurrentSecurity(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return securityDTO(value), nil
|
||||
}
|
||||
func (s *SettingsService) SaveSecurity(ctx context.Context, value *biz.SecurityConfig) (map[string]any, error) {
|
||||
if value.KeyLong < 1 || value.ImgWidth < 1 || value.ImgHeight < 1 || value.PwdMinLength < 1 || value.LimitWindow < 1 || value.LimitCount < 1 || value.LockThreshold < 1 || value.LockDuration < 1 || value.PwdExpireDays < 1 {
|
||||
return nil, errors.New("安全配置数值必须大于0")
|
||||
}
|
||||
if err := s.Repo().SaveSecurityConfig(ctx, value); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.securityMu.Lock()
|
||||
s.securityCache = value
|
||||
s.securityMu.Unlock()
|
||||
return securityDTO(value), nil
|
||||
}
|
||||
func (s *SettingsService) SaveSecurityRequest(ctx context.Context, value *dto.SecurityConfigRequest) (map[string]any, 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 *SettingsService) ValidatePassword(ctx context.Context, password string) error {
|
||||
cfg, err := s.CurrentSecurity(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len([]rune(password)) < cfg.PwdMinLength {
|
||||
return errors.New("密码长度不足")
|
||||
}
|
||||
hasUpper, hasLower, hasDigit, hasSpecial := false, false, false, false
|
||||
for _, ch := range password {
|
||||
switch {
|
||||
case ch >= 'A' && ch <= 'Z':
|
||||
hasUpper = true
|
||||
case ch >= 'a' && ch <= 'z':
|
||||
hasLower = true
|
||||
case ch >= '0' && ch <= '9':
|
||||
hasDigit = true
|
||||
default:
|
||||
hasSpecial = true
|
||||
}
|
||||
}
|
||||
if cfg.PwdRequireUpper && !hasUpper {
|
||||
return errors.New("密码必须包含大写字母")
|
||||
}
|
||||
if cfg.PwdRequireLower && !hasLower {
|
||||
return errors.New("密码必须包含小写字母")
|
||||
}
|
||||
if cfg.PwdRequireDigit && !hasDigit {
|
||||
return errors.New("密码必须包含数字")
|
||||
}
|
||||
if cfg.PwdRequireSpecial && !hasSpecial {
|
||||
return errors.New("密码必须包含特殊字符")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,14 +1,10 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"kra/internal/biz"
|
||||
"kra/internal/conf"
|
||||
"kra/pkg/adminauth"
|
||||
)
|
||||
|
||||
type SettingsService struct {
|
||||
@@ -22,263 +18,3 @@ func NewSettingsService(uc *biz.SettingsUsecase, config *conf.AdminBackend) *Set
|
||||
return &SettingsService{uc: uc, config: config}
|
||||
}
|
||||
func (s *SettingsService) Repo() biz.SettingsRepo { return s.uc.Repo() }
|
||||
|
||||
func dictionaryDTO(v *biz.Dictionary) map[string]any {
|
||||
children := make([]map[string]any, 0, len(v.Children))
|
||||
for _, x := range v.Children {
|
||||
children = append(children, dictionaryDTO(x))
|
||||
}
|
||||
details := make([]map[string]any, 0, len(v.Details))
|
||||
for _, x := range v.Details {
|
||||
details = append(details, detailDTO(x))
|
||||
}
|
||||
return map[string]any{"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 detailDTO(v *biz.DictionaryDetail) map[string]any {
|
||||
children := make([]map[string]any, 0, len(v.Children))
|
||||
for _, x := range v.Children {
|
||||
children = append(children, detailDTO(x))
|
||||
}
|
||||
return map[string]any{"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, "sysDictionaryID": v.DictionaryID, "parentID": v.ParentID, "level": v.Level, "path": v.Path, "disabled": !v.Status, "children": children}
|
||||
}
|
||||
func parameterDTO(v *biz.SystemParameter) map[string]any {
|
||||
return map[string]any{"ID": v.ID, "CreatedAt": v.CreatedAt, "UpdatedAt": v.UpdatedAt, "DeletedAt": nil, "name": v.Name, "key": v.Key, "value": v.Value, "desc": v.Desc}
|
||||
}
|
||||
func tokenDTO(v *biz.APIToken) map[string]any {
|
||||
var user any = nil
|
||||
if v.User != nil {
|
||||
user = convertUser(v.User)
|
||||
}
|
||||
return map[string]any{"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 *SettingsService) Dictionaries(ctx context.Context, page, size int, name, typ string, details bool) ([]map[string]any, int64, error) {
|
||||
items, total, err := s.Repo().ListDictionaries(ctx, page, size, name, typ, details)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
out := make([]map[string]any, 0, len(items))
|
||||
for _, v := range items {
|
||||
out = append(out, dictionaryDTO(v))
|
||||
}
|
||||
return out, total, nil
|
||||
}
|
||||
func (s *SettingsService) Dictionary(ctx context.Context, id uint, typ string, details bool) (map[string]any, error) {
|
||||
v, err := s.Repo().FindDictionary(ctx, id, typ, details)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dictionaryDTO(v), nil
|
||||
}
|
||||
func (s *SettingsService) CreateDictionary(ctx context.Context, v *biz.Dictionary) error {
|
||||
return s.Repo().CreateDictionary(ctx, v)
|
||||
}
|
||||
func (s *SettingsService) UpdateDictionary(ctx context.Context, v *biz.Dictionary) error {
|
||||
return s.Repo().UpdateDictionary(ctx, v)
|
||||
}
|
||||
func (s *SettingsService) DeleteDictionary(ctx context.Context, id uint) error {
|
||||
return s.Repo().DeleteDictionary(ctx, id)
|
||||
}
|
||||
func (s *SettingsService) DictionaryDetails(ctx context.Context, page, size int, dictionaryID uint, label, value string) ([]map[string]any, int64, error) {
|
||||
items, total, err := s.Repo().ListDictionaryDetails(ctx, page, size, dictionaryID, label, value)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
out := make([]map[string]any, 0, len(items))
|
||||
for _, v := range items {
|
||||
out = append(out, detailDTO(v))
|
||||
}
|
||||
return out, total, nil
|
||||
}
|
||||
func (s *SettingsService) DictionaryDetail(ctx context.Context, id uint) (map[string]any, error) {
|
||||
v, err := s.Repo().FindDictionaryDetail(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return detailDTO(v), nil
|
||||
}
|
||||
func (s *SettingsService) DictionaryTree(ctx context.Context, id uint, typ string) ([]map[string]any, error) {
|
||||
items, err := s.Repo().DictionaryDetailTree(ctx, id, typ)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out := make([]map[string]any, 0, len(items))
|
||||
for _, v := range items {
|
||||
out = append(out, detailDTO(v))
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
func (s *SettingsService) CreateDictionaryDetail(ctx context.Context, v *biz.DictionaryDetail) error {
|
||||
return s.Repo().CreateDictionaryDetail(ctx, v)
|
||||
}
|
||||
func (s *SettingsService) UpdateDictionaryDetail(ctx context.Context, v *biz.DictionaryDetail) error {
|
||||
return s.Repo().UpdateDictionaryDetail(ctx, v)
|
||||
}
|
||||
func (s *SettingsService) DeleteDictionaryDetail(ctx context.Context, id uint) error {
|
||||
return s.Repo().DeleteDictionaryDetail(ctx, id)
|
||||
}
|
||||
|
||||
func (s *SettingsService) Parameters(ctx context.Context, page, size int, q *biz.SystemParameter) ([]map[string]any, int64, error) {
|
||||
items, total, err := s.Repo().ListParameters(ctx, page, size, q)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
out := make([]map[string]any, 0, len(items))
|
||||
for _, v := range items {
|
||||
out = append(out, parameterDTO(v))
|
||||
}
|
||||
return out, total, nil
|
||||
}
|
||||
func (s *SettingsService) Parameter(ctx context.Context, id uint, key string) (map[string]any, error) {
|
||||
v, err := s.Repo().FindParameter(ctx, id, key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return parameterDTO(v), nil
|
||||
}
|
||||
func (s *SettingsService) CreateParameter(ctx context.Context, v *biz.SystemParameter) error {
|
||||
return s.Repo().CreateParameter(ctx, v)
|
||||
}
|
||||
func (s *SettingsService) UpdateParameter(ctx context.Context, v *biz.SystemParameter) error {
|
||||
return s.Repo().UpdateParameter(ctx, v)
|
||||
}
|
||||
func (s *SettingsService) DeleteParameters(ctx context.Context, ids []uint) error {
|
||||
return s.Repo().DeleteParameters(ctx, ids)
|
||||
}
|
||||
|
||||
func (s *SettingsService) CreateAPIToken(ctx context.Context, userID, authorityID uint, days int, remark string) (string, error) {
|
||||
user, allowed, err := s.Repo().UserHasAuthority(ctx, userID, authorityID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if !allowed {
|
||||
return "", errors.New("用户不具备该角色权限")
|
||||
}
|
||||
duration := time.Duration(days) * 24 * time.Hour
|
||||
if days == -1 {
|
||||
duration = 100 * 365 * 24 * time.Hour
|
||||
}
|
||||
if duration <= 0 {
|
||||
return "", errors.New("有效天数必须大于0或为-1")
|
||||
}
|
||||
secret, issuer := "", "kra"
|
||||
buffer := 24 * time.Hour
|
||||
if s.config != nil && s.config.Jwt != nil {
|
||||
secret = s.config.Jwt.SigningKey
|
||||
if s.config.Jwt.Issuer != "" {
|
||||
issuer = s.config.Jwt.Issuer
|
||||
}
|
||||
if s.config.Jwt.BufferTime != nil {
|
||||
buffer = s.config.Jwt.BufferTime.AsDuration()
|
||||
}
|
||||
}
|
||||
token, _, err := adminauth.Generate(secret, issuer, duration, buffer, user.ID, authorityID, user.UUID, user.Username, user.NickName, false)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
record := &biz.APIToken{UserID: userID, AuthorityID: authorityID, Token: token, Status: true, ExpiresAt: time.Now().Add(duration), Remark: remark}
|
||||
if err = s.Repo().CreateAPIToken(ctx, record); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return token, nil
|
||||
}
|
||||
func (s *SettingsService) APITokens(ctx context.Context, page, size int, userID uint, status *bool) ([]map[string]any, int64, error) {
|
||||
items, total, err := s.Repo().ListAPITokens(ctx, page, size, userID, status)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
out := make([]map[string]any, 0, len(items))
|
||||
for _, v := range items {
|
||||
out = append(out, tokenDTO(v))
|
||||
}
|
||||
return out, total, nil
|
||||
}
|
||||
func (s *SettingsService) DisableAPIToken(ctx context.Context, id uint) error {
|
||||
token, err := s.Repo().DisableAPIToken(ctx, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return s.Repo().BlacklistToken(ctx, token)
|
||||
}
|
||||
func (s *SettingsService) BlacklistToken(ctx context.Context, token string) error {
|
||||
return s.Repo().BlacklistToken(ctx, token)
|
||||
}
|
||||
func (s *SettingsService) IsTokenDisabled(ctx context.Context, token string) (bool, error) {
|
||||
return s.Repo().IsTokenDisabled(ctx, token)
|
||||
}
|
||||
|
||||
func securityDTO(v *biz.SecurityConfig) map[string]any {
|
||||
return map[string]any{"ID": v.ID, "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 *SettingsService) CurrentSecurity(ctx context.Context) (*biz.SecurityConfig, error) {
|
||||
s.securityMu.RLock()
|
||||
if s.securityCache != nil {
|
||||
copy := *s.securityCache
|
||||
s.securityMu.RUnlock()
|
||||
return ©, nil
|
||||
}
|
||||
s.securityMu.RUnlock()
|
||||
value, err := s.Repo().SecurityConfig(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.securityMu.Lock()
|
||||
s.securityCache = value
|
||||
copy := *value
|
||||
s.securityMu.Unlock()
|
||||
return ©, nil
|
||||
}
|
||||
func (s *SettingsService) Security(ctx context.Context) (map[string]any, error) {
|
||||
value, err := s.CurrentSecurity(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return securityDTO(value), nil
|
||||
}
|
||||
func (s *SettingsService) SaveSecurity(ctx context.Context, value *biz.SecurityConfig) (map[string]any, error) {
|
||||
if value.KeyLong < 1 || value.ImgWidth < 1 || value.ImgHeight < 1 || value.PwdMinLength < 1 || value.LimitWindow < 1 || value.LimitCount < 1 || value.LockThreshold < 1 || value.LockDuration < 1 || value.PwdExpireDays < 1 {
|
||||
return nil, errors.New("安全配置数值必须大于0")
|
||||
}
|
||||
if err := s.Repo().SaveSecurityConfig(ctx, value); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.securityMu.Lock()
|
||||
s.securityCache = value
|
||||
s.securityMu.Unlock()
|
||||
return securityDTO(value), nil
|
||||
}
|
||||
func (s *SettingsService) ValidatePassword(ctx context.Context, password string) error {
|
||||
cfg, err := s.CurrentSecurity(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len([]rune(password)) < cfg.PwdMinLength {
|
||||
return errors.New("密码长度不足")
|
||||
}
|
||||
hasUpper, hasLower, hasDigit, hasSpecial := false, false, false, false
|
||||
for _, ch := range password {
|
||||
switch {
|
||||
case ch >= 'A' && ch <= 'Z':
|
||||
hasUpper = true
|
||||
case ch >= 'a' && ch <= 'z':
|
||||
hasLower = true
|
||||
case ch >= '0' && ch <= '9':
|
||||
hasDigit = true
|
||||
default:
|
||||
hasSpecial = true
|
||||
}
|
||||
}
|
||||
if cfg.PwdRequireUpper && !hasUpper {
|
||||
return errors.New("密码必须包含大写字母")
|
||||
}
|
||||
if cfg.PwdRequireLower && !hasLower {
|
||||
return errors.New("密码必须包含小写字母")
|
||||
}
|
||||
if cfg.PwdRequireDigit && !hasDigit {
|
||||
return errors.New("密码必须包含数字")
|
||||
}
|
||||
if cfg.PwdRequireSpecial && !hasSpecial {
|
||||
return errors.New("密码必须包含特殊字符")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -2,12 +2,9 @@ package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"google.golang.org/protobuf/encoding/protojson"
|
||||
"kra/internal/biz"
|
||||
"kra/internal/conf"
|
||||
"kra/pkg/adminauth"
|
||||
)
|
||||
|
||||
type SystemService struct {
|
||||
@@ -16,13 +13,6 @@ type SystemService struct {
|
||||
settings *SettingsService
|
||||
}
|
||||
|
||||
type LoginResult struct {
|
||||
User map[string]any `json:"user"`
|
||||
Token string `json:"token"`
|
||||
ExpiresAt int64 `json:"expiresAt"`
|
||||
NeedChangePassword bool `json:"needChangePassword"`
|
||||
}
|
||||
|
||||
func NewSystemService(uc *biz.SystemUsecase, config *conf.AdminBackend, settings *SettingsService) *SystemService {
|
||||
return &SystemService{uc: uc, config: config, settings: settings}
|
||||
}
|
||||
@@ -30,264 +20,3 @@ func NewSystemService(uc *biz.SystemUsecase, config *conf.AdminBackend, settings
|
||||
func (s *SystemService) IsInitialized(ctx context.Context) (bool, error) {
|
||||
return s.uc.IsInitialized(ctx)
|
||||
}
|
||||
func (s *SystemService) PersistConfig(ctx context.Context) error { return s.uc.PersistConfig(ctx) }
|
||||
func (s *SystemService) PersistAdminConfig(ctx context.Context, value *conf.AdminBackend) error {
|
||||
raw, err := protojson.MarshalOptions{UseProtoNames: true}.Marshal(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return s.uc.PersistAdminConfig(ctx, raw)
|
||||
}
|
||||
func (s *SystemService) ReloadConfig(ctx context.Context) error { return s.uc.ReloadConfig(ctx) }
|
||||
|
||||
type DatabaseInit 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"`
|
||||
DBPath string `json:"dbPath"`
|
||||
Template string `json:"template"`
|
||||
AdminPassword string `json:"adminPassword"`
|
||||
}
|
||||
|
||||
func (s *SystemService) Initialize(ctx context.Context, input *DatabaseInit, apis []*biz.API) error {
|
||||
config := ""
|
||||
switch input.DBType {
|
||||
case "mysql":
|
||||
config = "timeout=5s&parseTime=True&loc=Local&charset=utf8mb4"
|
||||
case "pgsql":
|
||||
config = "sslmode=disable TimeZone=Local"
|
||||
}
|
||||
return s.uc.Initialize(ctx, &biz.DatabaseConfig{Driver: input.DBType, 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 *SystemService) CacheGet(ctx context.Context, key string) (string, bool, error) {
|
||||
return s.uc.CacheGet(ctx, key)
|
||||
}
|
||||
func (s *SystemService) CacheSet(ctx context.Context, key, value string, expiration time.Duration) error {
|
||||
return s.uc.CacheSet(ctx, key, value, expiration)
|
||||
}
|
||||
func (s *SystemService) CacheDelete(ctx context.Context, key string) error {
|
||||
return s.uc.CacheDelete(ctx, key)
|
||||
}
|
||||
func (s *SystemService) CacheIncrement(ctx context.Context, key string, expiration time.Duration) (int64, error) {
|
||||
return s.uc.CacheIncrement(ctx, key, expiration)
|
||||
}
|
||||
|
||||
func (s *SystemService) Login(ctx context.Context, username, password string) (*LoginResult, error) {
|
||||
u, err := s.uc.Login(ctx, username, password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if u.Enable != 1 {
|
||||
return nil, biz.ErrInvalidCredentials
|
||||
}
|
||||
if security, securityErr := s.settings.CurrentSecurity(ctx); securityErr == nil && security.PwdExpireEnable && u.PasswordUpdatedAt != nil && time.Since(*u.PasswordUpdatedAt) > time.Duration(security.PwdExpireDays)*24*time.Hour {
|
||||
u.MustChangePassword = true
|
||||
}
|
||||
expires, buffer := 7*24*time.Hour, 24*time.Hour
|
||||
secret, issuer := "", "kra"
|
||||
if s.config != nil && s.config.Jwt != nil {
|
||||
secret, issuer = s.config.Jwt.SigningKey, s.config.Jwt.Issuer
|
||||
if s.config.Jwt.ExpiresTime != nil {
|
||||
expires = s.config.Jwt.ExpiresTime.AsDuration()
|
||||
}
|
||||
if s.config.Jwt.BufferTime != nil {
|
||||
buffer = s.config.Jwt.BufferTime.AsDuration()
|
||||
}
|
||||
}
|
||||
token, claims, err := adminauth.Generate(secret, issuer, expires, buffer, u.ID, u.AuthorityID, u.UUID, u.Username, u.NickName, u.MustChangePassword)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &LoginResult{User: convertUser(u), Token: token, ExpiresAt: claims.ExpiresAt.UnixMilli(), NeedChangePassword: u.MustChangePassword}, nil
|
||||
}
|
||||
|
||||
func (s *SystemService) User(ctx context.Context, id uint) (map[string]any, error) {
|
||||
u, err := s.uc.User(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return convertUser(u), nil
|
||||
}
|
||||
|
||||
func (s *SystemService) Menus(ctx context.Context, authorityID uint) ([]map[string]any, error) {
|
||||
menus, err := s.uc.Menus(ctx, authorityID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := make([]map[string]any, 0, len(menus))
|
||||
for _, menu := range menus {
|
||||
result = append(result, convertMenu(menu))
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type UserInput struct {
|
||||
ID uint
|
||||
Username, Password, NickName, HeaderImg, Phone, Email string
|
||||
AuthorityID uint
|
||||
Enable int
|
||||
AuthorityIDs []uint
|
||||
}
|
||||
|
||||
func (s *SystemService) ListUsers(ctx context.Context, page, pageSize int, filter *biz.UserListFilter) ([]map[string]any, int64, error) {
|
||||
users, total, err := s.uc.ListUsers(ctx, page, pageSize, filter)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
result := make([]map[string]any, 0, len(users))
|
||||
for _, u := range users {
|
||||
result = append(result, convertUser(u))
|
||||
}
|
||||
return result, total, nil
|
||||
}
|
||||
func (s *SystemService) CreateUser(ctx context.Context, in UserInput) (map[string]any, error) {
|
||||
if err := s.settings.ValidatePassword(ctx, in.Password); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
security, _ := s.settings.CurrentSecurity(ctx)
|
||||
mustChange := security != nil && security.ForceNewUserChangePassword
|
||||
if in.AuthorityID == 0 && len(in.AuthorityIDs) > 0 {
|
||||
in.AuthorityID = in.AuthorityIDs[0]
|
||||
}
|
||||
in.AuthorityIDs = includeAuthority(in.AuthorityIDs, in.AuthorityID)
|
||||
u, err := s.uc.CreateUser(ctx, &biz.User{Username: in.Username, Password: in.Password, NickName: in.NickName, HeaderImg: in.HeaderImg, AuthorityID: in.AuthorityID, Phone: in.Phone, Email: in.Email, Enable: in.Enable, MustChangePassword: mustChange})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(in.AuthorityIDs) > 0 {
|
||||
if err = s.uc.SetUserAuthorities(ctx, u.ID, in.AuthorityIDs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
u, err = s.uc.User(ctx, u.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return convertUser(u), nil
|
||||
}
|
||||
func (s *SystemService) UpdateUser(ctx context.Context, in UserInput) error {
|
||||
in.AuthorityIDs = includeAuthority(in.AuthorityIDs, in.AuthorityID)
|
||||
if err := s.uc.UpdateUser(ctx, &biz.User{ID: in.ID, NickName: in.NickName, HeaderImg: in.HeaderImg, AuthorityID: in.AuthorityID, Phone: in.Phone, Email: in.Email, Enable: in.Enable}); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(in.AuthorityIDs) > 0 {
|
||||
return s.uc.SetUserAuthorities(ctx, in.ID, in.AuthorityIDs)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func includeAuthority(ids []uint, primary uint) []uint {
|
||||
if primary == 0 {
|
||||
return ids
|
||||
}
|
||||
for _, id := range ids {
|
||||
if id == primary {
|
||||
return ids
|
||||
}
|
||||
}
|
||||
return append(ids, primary)
|
||||
}
|
||||
func (s *SystemService) DeleteUser(ctx context.Context, id uint) error {
|
||||
return s.uc.DeleteUser(ctx, id)
|
||||
}
|
||||
func (s *SystemService) 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 *SystemService) 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 *SystemService) Authorities(ctx context.Context) ([]map[string]any, error) {
|
||||
authorities, err := s.uc.Authorities(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := make([]map[string]any, 0, len(authorities))
|
||||
for _, a := range authorities {
|
||||
result = append(result, convertAuthority(*a))
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
func (s *SystemService) SetUserAuthorities(ctx context.Context, id uint, authorityIDs []uint) error {
|
||||
return s.uc.SetUserAuthorities(ctx, id, authorityIDs)
|
||||
}
|
||||
func (s *SystemService) SwitchAuthority(ctx context.Context, id, authorityID uint) (*LoginResult, error) {
|
||||
if err := s.uc.SetUserAuthority(ctx, id, authorityID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
u, err := s.uc.User(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
expires, buffer := 7*24*time.Hour, 24*time.Hour
|
||||
secret, issuer := "", "kra"
|
||||
if s.config != nil && s.config.Jwt != nil {
|
||||
secret, issuer = s.config.Jwt.SigningKey, s.config.Jwt.Issuer
|
||||
if s.config.Jwt.ExpiresTime != nil {
|
||||
expires = s.config.Jwt.ExpiresTime.AsDuration()
|
||||
}
|
||||
if s.config.Jwt.BufferTime != nil {
|
||||
buffer = s.config.Jwt.BufferTime.AsDuration()
|
||||
}
|
||||
}
|
||||
token, claims, err := adminauth.Generate(secret, issuer, expires, buffer, u.ID, authorityID, u.UUID, u.Username, u.NickName, u.MustChangePassword)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &LoginResult{User: convertUser(u), Token: token, ExpiresAt: claims.ExpiresAt.UnixMilli(), NeedChangePassword: u.MustChangePassword}, nil
|
||||
}
|
||||
func (s *SystemService) SetUserSetting(ctx context.Context, id uint, setting map[string]any) error {
|
||||
return s.uc.SetUserSetting(ctx, id, setting)
|
||||
}
|
||||
|
||||
func convertAuthority(a biz.Authority) map[string]any {
|
||||
return map[string]any{"authorityId": a.AuthorityID, "authorityName": a.AuthorityName, "parentId": a.ParentID, "children": []map[string]any{}, "menus": []any{}, "dataScope": a.DataScope, "defaultRouter": a.DefaultRouter}
|
||||
}
|
||||
|
||||
func convertUser(u *biz.User) map[string]any {
|
||||
authorities := make([]map[string]any, 0, len(u.Authorities))
|
||||
for _, a := range u.Authorities {
|
||||
authorities = append(authorities, convertAuthority(a))
|
||||
}
|
||||
departments := make([]map[string]any, 0, len(u.Departments))
|
||||
for i := range u.Departments {
|
||||
departments = append(departments, departmentDTO(&u.Departments[i]))
|
||||
}
|
||||
positions := make([]map[string]any, 0, len(u.Positions))
|
||||
for i := range u.Positions {
|
||||
positions = append(positions, positionDTO(&u.Positions[i]))
|
||||
}
|
||||
dept := map[string]any{}
|
||||
if u.Department != nil {
|
||||
dept = departmentDTO(u.Department)
|
||||
}
|
||||
return map[string]any{"ID": u.ID, "CreatedAt": u.CreatedAt, "UpdatedAt": u.UpdatedAt, "DeletedAt": nil, "uuid": u.UUID, "userName": u.Username, "nickName": u.NickName, "headerImg": u.HeaderImg, "authorityId": u.AuthorityID, "authority": convertAuthority(u.Authority), "authorities": authorities, "deptId": u.DeptID, "dept": dept, "departments": departments, "positions": positions, "phone": u.Phone, "email": u.Email, "enable": u.Enable, "originSetting": u.OriginSetting}
|
||||
}
|
||||
|
||||
func convertMenu(menu *biz.Menu) map[string]any {
|
||||
children := make([]map[string]any, 0, len(menu.Children))
|
||||
for _, child := range menu.Children {
|
||||
children = append(children, convertMenu(child))
|
||||
}
|
||||
buttons := make([]map[string]any, 0, len(menu.Buttons))
|
||||
buttonAuthorities := make(map[string]uint, len(menu.Buttons))
|
||||
for _, button := range menu.Buttons {
|
||||
buttons = append(buttons, map[string]any{"ID": button.ID, "name": button.Name, "desc": button.Description, "sysBaseMenuID": button.MenuID})
|
||||
if button.AuthorityID != 0 {
|
||||
buttonAuthorities[button.Name] = button.AuthorityID
|
||||
}
|
||||
}
|
||||
parameters := make([]map[string]any, 0, len(menu.Parameters))
|
||||
for _, parameter := range menu.Parameters {
|
||||
parameters = append(parameters, map[string]any{"ID": parameter.ID, "SysBaseMenuID": parameter.MenuID, "type": parameter.Type, "key": parameter.Key, "value": parameter.Value})
|
||||
}
|
||||
return map[string]any{"ID": menu.ID, "parentId": menu.ParentID, "path": menu.Path, "name": menu.Name, "hidden": menu.Hidden, "component": menu.Component, "sort": menu.Sort, "meta": map[string]any{"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, "menuBtn": buttons, "btns": buttonAuthorities}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"kra/internal/conf"
|
||||
"kra/internal/service/dto"
|
||||
|
||||
"google.golang.org/protobuf/encoding/protojson"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
func (s *SystemService) PersistConfig(ctx context.Context) error { return s.uc.PersistConfig(ctx) }
|
||||
|
||||
func (s *SystemService) PersistAdminConfig(ctx context.Context, value *conf.AdminBackend) error {
|
||||
raw, err := protojson.MarshalOptions{UseProtoNames: true}.Marshal(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return s.uc.PersistAdminConfig(ctx, raw)
|
||||
}
|
||||
|
||||
func (s *SystemService) ReloadConfig(ctx context.Context) error { return s.uc.ReloadConfig(ctx) }
|
||||
|
||||
func (s *SystemService) SystemConfig() map[string]any {
|
||||
admin := map[string]any{"routerPrefix": ""}
|
||||
email := map[string]any{}
|
||||
if s.config == nil {
|
||||
return map[string]any{"config": map[string]any{"admin": admin, "email": email}}
|
||||
}
|
||||
admin["routerPrefix"] = s.config.RouterPrefix
|
||||
if s.config.Jwt != nil {
|
||||
admin["jwt"] = map[string]any{"signingKey": "******", "expiresTime": s.config.Jwt.ExpiresTime.AsDuration().String(), "bufferTime": s.config.Jwt.BufferTime.AsDuration().String(), "issuer": s.config.Jwt.Issuer}
|
||||
}
|
||||
if s.config.Captcha != nil {
|
||||
admin["captcha"] = map[string]any{"keyLong": s.config.Captcha.KeyLong, "imgWidth": s.config.Captcha.ImgWidth, "imgHeight": s.config.Captcha.ImgHeight, "storeExpiration": s.config.Captcha.StoreExpiration.AsDuration().String()}
|
||||
}
|
||||
if s.config.Local != nil {
|
||||
admin["local"] = map[string]any{"storePath": s.config.Local.StorePath, "pathPrefix": s.config.Local.PathPrefix}
|
||||
}
|
||||
if s.config.Media != nil {
|
||||
admin["media"] = map[string]any{"sessionTtl": s.config.Media.SessionTtl}
|
||||
}
|
||||
if s.config.Email != nil {
|
||||
email = map[string]any{"to": s.config.Email.To, "from": s.config.Email.From, "host": s.config.Email.Host, "secret": "******", "nickname": s.config.Email.Nickname, "port": s.config.Email.Port, "is-ssl": s.config.Email.IsSsl, "is-loginauth": s.config.Email.IsLoginAuth}
|
||||
}
|
||||
if s.config.Storage != nil {
|
||||
storage := proto.Clone(s.config.Storage).(*conf.AdminBackend_Storage)
|
||||
maskStorageSecrets(storage)
|
||||
admin["storage"] = storage
|
||||
}
|
||||
return map[string]any{"config": map[string]any{"admin": admin, "email": email}}
|
||||
}
|
||||
|
||||
func (s *SystemService) SaveSystemConfig(ctx context.Context, req *dto.SetSystemConfigRequest) error {
|
||||
if s.config == nil {
|
||||
return nil
|
||||
}
|
||||
next := proto.Clone(s.config).(*conf.AdminBackend)
|
||||
next.RouterPrefix = req.Config.Admin.RouterPrefix
|
||||
if next.Jwt != nil {
|
||||
if req.Config.Admin.JWT.SigningKey != "" && req.Config.Admin.JWT.SigningKey != "******" {
|
||||
next.Jwt.SigningKey = req.Config.Admin.JWT.SigningKey
|
||||
}
|
||||
if req.Config.Admin.JWT.Issuer != "" {
|
||||
next.Jwt.Issuer = req.Config.Admin.JWT.Issuer
|
||||
}
|
||||
}
|
||||
if next.Local != nil {
|
||||
if req.Config.Admin.Local.StorePath != "" {
|
||||
next.Local.StorePath = req.Config.Admin.Local.StorePath
|
||||
}
|
||||
if req.Config.Admin.Local.PathPrefix != "" {
|
||||
next.Local.PathPrefix = req.Config.Admin.Local.PathPrefix
|
||||
}
|
||||
}
|
||||
if next.Media != nil && req.Config.Admin.Media.SessionTTL > 0 {
|
||||
next.Media.SessionTtl = req.Config.Admin.Media.SessionTTL
|
||||
}
|
||||
if req.Config.Admin.Storage != nil {
|
||||
preserveStorageSecrets(req.Config.Admin.Storage, next.Storage)
|
||||
next.Storage = req.Config.Admin.Storage
|
||||
}
|
||||
if next.Email != nil && req.Config.Email != nil {
|
||||
next.Email.To, next.Email.From, next.Email.Host = req.Config.Email.To, req.Config.Email.From, req.Config.Email.Host
|
||||
next.Email.Nickname, next.Email.Port = req.Config.Email.Nickname, req.Config.Email.Port
|
||||
next.Email.IsSsl, next.Email.IsLoginAuth = req.Config.Email.IsSSL, req.Config.Email.IsLoginAuth
|
||||
if req.Config.Email.Secret != "" && req.Config.Email.Secret != "******" {
|
||||
next.Email.Secret = req.Config.Email.Secret
|
||||
}
|
||||
}
|
||||
return s.PersistAdminConfig(ctx, next)
|
||||
}
|
||||
|
||||
func objectStores(storage *conf.AdminBackend_Storage) []*conf.AdminBackend_ObjectStore {
|
||||
if storage == nil {
|
||||
return nil
|
||||
}
|
||||
return []*conf.AdminBackend_ObjectStore{storage.AliyunOss, storage.HuaweiObs, storage.TencentCos, storage.AwsS3, storage.CloudflareR2, storage.Minio}
|
||||
}
|
||||
|
||||
func maskStorageSecrets(storage *conf.AdminBackend_Storage) {
|
||||
if storage.Qiniu != nil {
|
||||
storage.Qiniu.SecretKey = "******"
|
||||
}
|
||||
for _, item := range objectStores(storage) {
|
||||
if item != nil {
|
||||
item.SecretKey = "******"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func preserveStorageSecrets(next, current *conf.AdminBackend_Storage) {
|
||||
if next == nil || current == nil {
|
||||
return
|
||||
}
|
||||
if next.Qiniu != nil && current.Qiniu != nil && (next.Qiniu.SecretKey == "" || next.Qiniu.SecretKey == "******") {
|
||||
next.Qiniu.SecretKey = current.Qiniu.SecretKey
|
||||
}
|
||||
nextItems, currentItems := objectStores(next), objectStores(current)
|
||||
for i := range nextItems {
|
||||
if nextItems[i] != nil && currentItems[i] != nil && (nextItems[i].SecretKey == "" || nextItems[i].SecretKey == "******") {
|
||||
nextItems[i].SecretKey = currentItems[i].SecretKey
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"kra/internal/biz"
|
||||
"kra/internal/service/dto"
|
||||
)
|
||||
|
||||
type DatabaseInit 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"`
|
||||
DBPath string `json:"dbPath"`
|
||||
Template string `json:"template"`
|
||||
AdminPassword string `json:"adminPassword"`
|
||||
}
|
||||
|
||||
func (s *SystemService) Initialize(ctx context.Context, input *DatabaseInit, apis []*biz.API) error {
|
||||
config := ""
|
||||
switch input.DBType {
|
||||
case "mysql":
|
||||
config = "timeout=5s&parseTime=True&loc=Local&charset=utf8mb4"
|
||||
case "pgsql":
|
||||
config = "sslmode=disable TimeZone=Local"
|
||||
}
|
||||
return s.uc.Initialize(ctx, &biz.DatabaseConfig{Driver: input.DBType, 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 *SystemService) InitializeRoutes(ctx context.Context, input *DatabaseInit, routes []dto.Route) error {
|
||||
apis := make([]*biz.API, 0, len(routes))
|
||||
for _, route := range routes {
|
||||
apis = append(apis, &biz.API{Path: route.Path, Method: route.Method, APIGroup: routeGroup(route.Path)})
|
||||
}
|
||||
return s.Initialize(ctx, input, apis)
|
||||
}
|
||||
|
||||
func routeGroup(path string) string {
|
||||
parts := strings.Split(strings.Trim(path, "/"), "/")
|
||||
if len(parts) > 0 && parts[0] != "" {
|
||||
return parts[0]
|
||||
}
|
||||
return "base"
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"kra/internal/biz"
|
||||
"kra/internal/service/dto"
|
||||
)
|
||||
|
||||
func (s *SystemService) User(ctx context.Context, id uint) (map[string]any, error) {
|
||||
value, err := s.uc.User(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return convertUser(value), nil
|
||||
}
|
||||
|
||||
func (s *SystemService) Menus(ctx context.Context, authorityID uint) ([]map[string]any, error) {
|
||||
menus, err := s.uc.Menus(ctx, authorityID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := make([]map[string]any, 0, len(menus))
|
||||
for _, menu := range menus {
|
||||
result = append(result, convertMenu(menu))
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type UserInput struct {
|
||||
ID uint
|
||||
Username, Password, NickName, HeaderImg, Phone, Email string
|
||||
AuthorityID uint
|
||||
Enable int
|
||||
AuthorityIDs []uint
|
||||
}
|
||||
|
||||
func userInput(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 *SystemService) ListUsersRequest(ctx context.Context, value *dto.UserListRequest) ([]map[string]any, 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 *SystemService) CreateUserRequest(ctx context.Context, value *dto.UserRequest) (map[string]any, error) {
|
||||
return s.CreateUser(ctx, userInput(value))
|
||||
}
|
||||
func (s *SystemService) UpdateUserRequest(ctx context.Context, value *dto.UserRequest) error {
|
||||
return s.UpdateUser(ctx, userInput(value))
|
||||
}
|
||||
|
||||
func (s *SystemService) ListUsers(ctx context.Context, page, pageSize int, filter *biz.UserListFilter) ([]map[string]any, int64, error) {
|
||||
users, total, err := s.uc.ListUsers(ctx, page, pageSize, filter)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
result := make([]map[string]any, 0, len(users))
|
||||
for _, user := range users {
|
||||
result = append(result, convertUser(user))
|
||||
}
|
||||
return result, total, nil
|
||||
}
|
||||
func (s *SystemService) CreateUser(ctx context.Context, input UserInput) (map[string]any, error) {
|
||||
if err := s.settings.ValidatePassword(ctx, input.Password); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
security, _ := s.settings.CurrentSecurity(ctx)
|
||||
mustChange := security != nil && security.ForceNewUserChangePassword
|
||||
if input.AuthorityID == 0 && len(input.AuthorityIDs) > 0 {
|
||||
input.AuthorityID = input.AuthorityIDs[0]
|
||||
}
|
||||
input.AuthorityIDs = includeAuthority(input.AuthorityIDs, input.AuthorityID)
|
||||
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})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(input.AuthorityIDs) > 0 {
|
||||
if err = s.uc.SetUserAuthorities(ctx, user.ID, input.AuthorityIDs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
user, err = s.uc.User(ctx, user.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return convertUser(user), nil
|
||||
}
|
||||
func (s *SystemService) UpdateUser(ctx context.Context, input UserInput) error {
|
||||
input.AuthorityIDs = includeAuthority(input.AuthorityIDs, input.AuthorityID)
|
||||
if err := s.uc.UpdateUser(ctx, &biz.User{ID: input.ID, NickName: input.NickName, HeaderImg: input.HeaderImg, AuthorityID: input.AuthorityID, Phone: input.Phone, Email: input.Email, Enable: input.Enable}); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(input.AuthorityIDs) > 0 {
|
||||
return s.uc.SetUserAuthorities(ctx, input.ID, input.AuthorityIDs)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func includeAuthority(ids []uint, primary uint) []uint {
|
||||
if primary == 0 {
|
||||
return ids
|
||||
}
|
||||
for _, id := range ids {
|
||||
if id == primary {
|
||||
return ids
|
||||
}
|
||||
}
|
||||
return append(ids, primary)
|
||||
}
|
||||
func (s *SystemService) DeleteUser(ctx context.Context, id uint) error {
|
||||
return s.uc.DeleteUser(ctx, id)
|
||||
}
|
||||
func (s *SystemService) 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 *SystemService) 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 *SystemService) Authorities(ctx context.Context) ([]map[string]any, error) {
|
||||
values, err := s.uc.Authorities(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := make([]map[string]any, 0, len(values))
|
||||
for _, value := range values {
|
||||
result = append(result, convertAuthority(*value))
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
func (s *SystemService) SetUserAuthorities(ctx context.Context, id uint, authorityIDs []uint) error {
|
||||
return s.uc.SetUserAuthorities(ctx, id, authorityIDs)
|
||||
}
|
||||
func (s *SystemService) SwitchAuthority(ctx context.Context, id, authorityID uint) (*LoginResult, error) {
|
||||
if err := s.uc.SetUserAuthority(ctx, id, authorityID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
user, err := s.uc.User(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s.issueLogin(user, authorityID)
|
||||
}
|
||||
func (s *SystemService) SetUserSetting(ctx context.Context, id uint, setting map[string]any) error {
|
||||
return s.uc.SetUserSetting(ctx, id, setting)
|
||||
}
|
||||
|
||||
func convertAuthority(value biz.Authority) map[string]any {
|
||||
return map[string]any{"authorityId": value.AuthorityID, "authorityName": value.AuthorityName, "parentId": value.ParentID, "children": []map[string]any{}, "menus": []any{}, "dataScope": value.DataScope, "defaultRouter": value.DefaultRouter}
|
||||
}
|
||||
func convertUser(user *biz.User) map[string]any {
|
||||
authorities := make([]map[string]any, 0, len(user.Authorities))
|
||||
for _, value := range user.Authorities {
|
||||
authorities = append(authorities, convertAuthority(value))
|
||||
}
|
||||
departments := make([]map[string]any, 0, len(user.Departments))
|
||||
for i := range user.Departments {
|
||||
departments = append(departments, departmentDTO(&user.Departments[i]))
|
||||
}
|
||||
positions := make([]map[string]any, 0, len(user.Positions))
|
||||
for i := range user.Positions {
|
||||
positions = append(positions, positionDTO(&user.Positions[i]))
|
||||
}
|
||||
department := map[string]any{}
|
||||
if user.Department != nil {
|
||||
department = departmentDTO(user.Department)
|
||||
}
|
||||
return map[string]any{"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, "dept": department, "departments": departments, "positions": positions, "phone": user.Phone, "email": user.Email, "enable": user.Enable, "originSetting": user.OriginSetting}
|
||||
}
|
||||
func convertMenu(menu *biz.Menu) map[string]any {
|
||||
children := make([]map[string]any, 0, len(menu.Children))
|
||||
for _, child := range menu.Children {
|
||||
children = append(children, convertMenu(child))
|
||||
}
|
||||
buttons := make([]map[string]any, 0, len(menu.Buttons))
|
||||
buttonAuthorities := make(map[string]uint, len(menu.Buttons))
|
||||
for _, button := range menu.Buttons {
|
||||
buttons = append(buttons, map[string]any{"ID": button.ID, "name": button.Name, "desc": button.Description, "sysBaseMenuID": button.MenuID})
|
||||
if button.AuthorityID != 0 {
|
||||
buttonAuthorities[button.Name] = button.AuthorityID
|
||||
}
|
||||
}
|
||||
parameters := make([]map[string]any, 0, len(menu.Parameters))
|
||||
for _, parameter := range menu.Parameters {
|
||||
parameters = append(parameters, map[string]any{"ID": parameter.ID, "SysBaseMenuID": parameter.MenuID, "type": parameter.Type, "key": parameter.Key, "value": parameter.Value})
|
||||
}
|
||||
return map[string]any{"ID": menu.ID, "parentId": menu.ParentID, "path": menu.Path, "name": menu.Name, "hidden": menu.Hidden, "component": menu.Component, "sort": menu.Sort, "meta": map[string]any{"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, "menuBtn": buttons, "btns": buttonAuthorities}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"time"
|
||||
|
||||
"kra/internal/biz"
|
||||
"kra/internal/service/dto"
|
||||
)
|
||||
|
||||
type VersionService struct{ uc *biz.VersionUsecase }
|
||||
@@ -73,3 +74,34 @@ func (s *VersionService) Export(ctx context.Context, name, code, description str
|
||||
func (s *VersionService) Import(ctx context.Context, bundle *biz.VersionBundle) error {
|
||||
return s.uc.Repo().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 _, child := range value.Children {
|
||||
menu.Children = append(menu.Children, versionMenuDomain(child))
|
||||
}
|
||||
return menu
|
||||
}
|
||||
func (s *VersionService) ImportRequest(ctx context.Context, req *dto.ImportVersionRequest) error {
|
||||
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 {
|
||||
status := true
|
||||
if detail.Status != nil {
|
||||
status = *detail.Status
|
||||
}
|
||||
item.Details = append(item.Details, &biz.DictionaryDetail{Label: detail.Label, Value: detail.Value, Extend: detail.Extend, Status: status, Sort: detail.Sort, ParentID: detail.ParentID, Level: detail.Level, Path: detail.Path})
|
||||
}
|
||||
bundle.Dictionaries = append(bundle.Dictionaries, item)
|
||||
}
|
||||
return s.Import(ctx, bundle)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user