kra/internal/data/system/user.go

382 lines
10 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package system
import (
"context"
"encoding/json"
"errors"
"kra/internal/biz/system"
"kra/internal/data/model"
"kra/internal/data/query"
"github.com/google/uuid"
"gorm.io/gorm"
)
type userRepo struct {
db *gorm.DB
}
// NewUserRepo 创建用户仓储
func NewUserRepo(db *gorm.DB) system.UserRepo {
query.SetDefault(db)
return &userRepo{db: db}
}
func (r *userRepo) Create(ctx context.Context, user *system.User) error {
m := toBizUser(user)
return query.SysUser.WithContext(ctx).Create(m)
}
func (r *userRepo) Update(ctx context.Context, user *system.User) error {
_, err := query.SysUser.WithContext(ctx).Where(query.SysUser.ID.Eq(int64(user.ID))).Updates(map[string]any{
"nick_name": user.NickName,
"header_img": user.HeaderImg,
"phone": user.Phone,
"email": user.Email,
"enable": user.Enable,
})
return err
}
func (r *userRepo) UpdateSelf(ctx context.Context, user *system.User) error {
updates := map[string]any{}
if user.NickName != "" {
updates["nick_name"] = user.NickName
}
if user.HeaderImg != "" {
updates["header_img"] = user.HeaderImg
}
if user.Phone != "" {
updates["phone"] = user.Phone
}
if user.Email != "" {
updates["email"] = user.Email
}
if user.SideMode != "" {
updates["side_mode"] = user.SideMode
}
if user.BaseColor != "" {
updates["base_color"] = user.BaseColor
}
if len(updates) == 0 {
return nil
}
_, err := query.SysUser.WithContext(ctx).Where(query.SysUser.ID.Eq(int64(user.ID))).Updates(updates)
return err
}
func (r *userRepo) UpdateSelfSetting(ctx context.Context, id uint, setting json.RawMessage) error {
_, err := query.SysUser.WithContext(ctx).Where(query.SysUser.ID.Eq(int64(id))).Update(query.SysUser.OriginSetting, string(setting))
return err
}
func (r *userRepo) Delete(ctx context.Context, id uint) error {
return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
if err := tx.Where("id = ?", id).Delete(&model.SysUser{}).Error; err != nil {
return err
}
if err := tx.Where("sys_user_id = ?", id).Delete(&model.SysUserAuthority{}).Error; err != nil {
return err
}
return nil
})
}
func (r *userRepo) FindByID(ctx context.Context, id uint) (*system.User, error) {
m, err := query.SysUser.WithContext(ctx).Where(query.SysUser.ID.Eq(int64(id))).First()
if err != nil {
return nil, err
}
return toModelUser(m), nil
}
func (r *userRepo) FindByIDWithAuthorities(ctx context.Context, id uint) (*system.User, error) {
m, err := query.SysUser.WithContext(ctx).
Preload(query.SysUser.Authority).
Preload(query.SysUser.Authorities).
Where(query.SysUser.ID.Eq(int64(id))).
First()
if err != nil {
return nil, err
}
return toModelUserWithAuthorities(m), nil
}
func (r *userRepo) FindByUUID(ctx context.Context, uuidStr string) (*system.User, error) {
m, err := query.SysUser.WithContext(ctx).Where(query.SysUser.UUID.Eq(uuidStr)).First()
if err != nil {
return nil, err
}
return toModelUser(m), nil
}
func (r *userRepo) FindByUUIDWithAuthorities(ctx context.Context, uuidStr string) (*system.User, error) {
m, err := query.SysUser.WithContext(ctx).
Preload(query.SysUser.Authority).
Preload(query.SysUser.Authorities).
Where(query.SysUser.UUID.Eq(uuidStr)).
First()
if err != nil {
return nil, err
}
return toModelUserWithAuthorities(m), nil
}
func (r *userRepo) FindByUsername(ctx context.Context, username string) (*system.User, error) {
m, err := query.SysUser.WithContext(ctx).Where(query.SysUser.Username.Eq(username)).First()
if err != nil {
return nil, err
}
return toModelUser(m), nil
}
func (r *userRepo) FindByUsernameWithAuthorities(ctx context.Context, username string) (*system.User, error) {
m, err := query.SysUser.WithContext(ctx).
Preload(query.SysUser.Authority).
Preload(query.SysUser.Authorities).
Where(query.SysUser.Username.Eq(username)).
First()
if err != nil {
return nil, err
}
return toModelUserWithAuthorities(m), nil
}
func (r *userRepo) List(ctx context.Context, page, pageSize int, filters map[string]string) ([]*system.User, int64, error) {
u := query.SysUser
q := u.WithContext(ctx)
if v, ok := filters["username"]; ok && v != "" {
q = q.Where(u.Username.Like("%" + v + "%"))
}
if v, ok := filters["nick_name"]; ok && v != "" {
q = q.Where(u.NickName.Like("%" + v + "%"))
}
if v, ok := filters["phone"]; ok && v != "" {
q = q.Where(u.Phone.Like("%" + v + "%"))
}
if v, ok := filters["email"]; ok && v != "" {
q = q.Where(u.Email.Like("%" + v + "%"))
}
total, err := q.Count()
if err != nil {
return nil, 0, err
}
offset := (page - 1) * pageSize
list, err := q.Preload(u.Authority).Preload(u.Authorities).Offset(offset).Limit(pageSize).Find()
if err != nil {
return nil, 0, err
}
users := make([]*system.User, len(list))
for i := range list {
users[i] = toModelUserWithAuthorities(list[i])
}
return users, total, nil
}
func (r *userRepo) UpdatePassword(ctx context.Context, id uint, password string) error {
return r.db.WithContext(ctx).Model(&model.SysUser{}).Where("id = ?", id).Update("password", password).Error
}
func (r *userRepo) UpdateAuthorityID(ctx context.Context, id uint, authorityId uint) error {
return r.db.WithContext(ctx).Model(&model.SysUser{}).Where("id = ?", id).Update("authority_id", authorityId).Error
}
func (r *userRepo) SetUserAuthorities(ctx context.Context, adminAuthorityID, userId uint, authorityIds []uint) error {
return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
var user model.SysUser
if err := tx.Where("id = ?", userId).First(&user).Error; err != nil {
return errors.New("查询用户数据失败")
}
if err := tx.Where("sys_user_id = ?", userId).Delete(&model.SysUserAuthority{}).Error; err != nil {
return err
}
for _, aid := range authorityIds {
if err := checkAuthorityIDAuth(tx, adminAuthorityID, aid); err != nil {
return err
}
ua := &model.SysUserAuthority{
SysUserID: int64(userId),
SysAuthorityAuthorityID: int64(aid),
}
if err := tx.Create(ua).Error; err != nil {
return err
}
}
if len(authorityIds) > 0 {
if err := tx.Model(&model.SysUser{}).Where("id = ?", userId).Update("authority_id", authorityIds[0]).Error; err != nil {
return err
}
}
return nil
})
}
func checkAuthorityIDAuth(tx *gorm.DB, adminAuthorityID, targetAuthorityID uint) error {
// 超级管理员(888)直接通过
if adminAuthorityID == 888 {
return nil
}
// 获取管理员角色的所有子角色ID递归
authIDs, err := getStructAuthorityList(tx, adminAuthorityID)
if err != nil {
return err
}
// 检查目标角色是否在权限列表中
for _, id := range authIDs {
if id == targetAuthorityID {
return nil
}
}
return errors.New("您没有权限分配该角色")
}
// getStructAuthorityList 递归获取角色ID列表包含子角色
func getStructAuthorityList(tx *gorm.DB, authorityID uint) ([]uint, error) {
var auth model.SysAuthority
if err := tx.First(&auth, "authority_id = ?", authorityID).Error; err != nil {
return nil, err
}
var list []uint
var children []model.SysAuthority
if err := tx.Where("parent_id = ?", authorityID).Find(&children).Error; err != nil {
return nil, err
}
for _, child := range children {
list = append(list, uint(child.AuthorityID))
childList, err := getStructAuthorityList(tx, uint(child.AuthorityID))
if err == nil {
list = append(list, childList...)
}
}
// 如果是顶级角色,包含自己
if auth.ParentID == 0 {
list = append(list, authorityID)
}
return list, nil
}
func (r *userRepo) CheckUserHasAuthority(ctx context.Context, userId, authorityId uint) (bool, error) {
var count int64
err := r.db.WithContext(ctx).Model(&model.SysUserAuthority{}).
Where("sys_user_id = ? AND sys_authority_authority_id = ?", userId, authorityId).
Count(&count).Error
return count > 0, err
}
func (r *userRepo) GetAuthorityMenuRouters(ctx context.Context, authorityId uint) ([]string, error) {
var authorityMenus []model.SysAuthorityMenu
if err := r.db.WithContext(ctx).Where("sys_authority_authority_id = ?", authorityId).Find(&authorityMenus).Error; err != nil {
return nil, err
}
if len(authorityMenus) == 0 {
return []string{}, nil
}
menuIDs := make([]int64, len(authorityMenus))
for i, am := range authorityMenus {
menuIDs[i] = am.SysBaseMenuID
}
var menus []model.SysBaseMenu
if err := r.db.WithContext(ctx).Where("id IN ?", menuIDs).Find(&menus).Error; err != nil {
return nil, err
}
routers := make([]string, len(menus))
for i, m := range menus {
routers[i] = m.Name
}
return routers, nil
}
func (r *userRepo) GetAuthorityDefaultRouter(ctx context.Context, authorityId uint) (string, error) {
var authority model.SysAuthority
if err := r.db.WithContext(ctx).Where("authority_id = ?", authorityId).First(&authority).Error; err != nil {
return "", err
}
return authority.DefaultRouter, nil
}
// 转换函数
func toBizUser(u *system.User) *model.SysUser {
return &model.SysUser{
ID: int64(u.ID),
UUID: u.UUID.String(),
Username: u.Username,
Password: u.Password,
NickName: u.NickName,
HeaderImg: u.HeaderImg,
AuthorityID: int64(u.AuthorityId),
Phone: u.Phone,
Email: u.Email,
Enable: int64(u.Enable),
}
}
func toModelUser(m *model.SysUser) *system.User {
u := &system.User{
ID: uint(m.ID),
Username: m.Username,
Password: m.Password,
NickName: m.NickName,
HeaderImg: m.HeaderImg,
AuthorityId: uint(m.AuthorityID),
Phone: m.Phone,
Email: m.Email,
Enable: int(m.Enable),
OriginSetting: json.RawMessage(m.OriginSetting),
CreatedAt: m.CreatedAt,
UpdatedAt: m.UpdatedAt,
}
u.UUID, _ = uuid.Parse(m.UUID)
return u
}
func toModelUserWithAuthorities(m *model.SysUser) *system.User {
u := toModelUser(m)
// 转换Authority
u.Authority = &system.Authority{
AuthorityId: uint(m.Authority.AuthorityID),
AuthorityName: m.Authority.AuthorityName,
DefaultRouter: m.Authority.DefaultRouter,
}
if m.Authority.ParentID != 0 {
pid := uint(m.Authority.ParentID)
u.Authority.ParentId = &pid
}
// 转换Authorities
if len(m.Authorities) > 0 {
u.Authorities = make([]*system.Authority, len(m.Authorities))
for i, a := range m.Authorities {
u.Authorities[i] = &system.Authority{
AuthorityId: uint(a.AuthorityID),
AuthorityName: a.AuthorityName,
DefaultRouter: a.DefaultRouter,
}
if a.ParentID != 0 {
pid := uint(a.ParentID)
u.Authorities[i].ParentId = &pid
}
}
}
return u
}