refactor: separate backend domains and storage adapters
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user