kra-oa/internal/service/system.go

245 lines
9.4 KiB
Go

package service
import (
"context"
"time"
"kra/internal/biz"
"kra/internal/conf"
"kra/pkg/adminauth"
)
type SystemService struct {
uc *biz.SystemUsecase
config *conf.AdminBackend
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}
}
func (s *SystemService) IsInitialized(ctx context.Context) (bool, error) {
return s.uc.IsInitialized(ctx)
}
func (s *SystemService) Initialize(ctx context.Context) error { return s.uc.Initialize(ctx) }
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) 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 := 7 * 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()
}
}
token, claims, err := adminauth.Generate(secret, issuer, expires, 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 := 7 * 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()
}
}
token, claims, err := adminauth.Generate(secret, issuer, expires, 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))
for _, button := range menu.Buttons {
buttons = append(buttons, map[string]any{"ID": button.ID, "name": button.Name, "desc": button.Description, "sysBaseMenuID": button.MenuID})
}
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": []any{}, "menuBtn": buttons}
}