package user import ( "context" "fmt" "time" "perms-system-server/internal/consts" authHelper "perms-system-server/internal/logic/auth" "perms-system-server/internal/middleware" "perms-system-server/internal/model/userrole" "perms-system-server/internal/response" "perms-system-server/internal/svc" "perms-system-server/internal/types" "github.com/zeromicro/go-zero/core/logx" "github.com/zeromicro/go-zero/core/stores/sqlx" ) type BindRolesLogic struct { logx.Logger ctx context.Context svcCtx *svc.ServiceContext } func NewBindRolesLogic(ctx context.Context, svcCtx *svc.ServiceContext) *BindRolesLogic { return &BindRolesLogic{ Logger: logx.WithContext(ctx), ctx: ctx, svcCtx: svcCtx, } } func (l *BindRolesLogic) BindRoles(req *types.BindRolesReq) error { if _, err := l.svcCtx.SysUserModel.FindOne(l.ctx, req.UserId); err != nil { return response.ErrNotFound("用户不存在") } productCode := middleware.GetProductCode(l.ctx) if err := authHelper.CheckManageAccess(l.ctx, l.svcCtx, req.UserId, productCode); err != nil { return err } if _, err := l.svcCtx.SysProductMemberModel.FindOneByProductCodeUserId(l.ctx, productCode, req.UserId); err != nil { return response.ErrBadRequest("目标用户不是当前产品的成员") } if len(req.RoleIds) > 0 { seen := make(map[int64]bool, len(req.RoleIds)) uniqueIds := make([]int64, 0, len(req.RoleIds)) for _, id := range req.RoleIds { if !seen[id] { seen[id] = true uniqueIds = append(uniqueIds, id) } } req.RoleIds = uniqueIds } caller := middleware.GetUserDetails(l.ctx) if len(req.RoleIds) > 0 { roles, err := l.svcCtx.SysRoleModel.FindByIds(l.ctx, req.RoleIds) if err != nil { return err } if int64(len(roles)) != int64(len(req.RoleIds)) { return response.ErrBadRequest("包含无效的角色ID") } for _, r := range roles { if r.ProductCode != productCode { return response.ErrBadRequest("不能绑定其他产品的角色") } if r.Status != consts.StatusEnabled { return response.ErrBadRequest("不能绑定已禁用的角色") } if caller != nil && !caller.IsSuperAdmin { if caller.MinPermsLevel == 0 || r.PermsLevel < caller.MinPermsLevel { return response.ErrForbidden("不能分配权限级别高于自身的角色") } } } } existingRoleIds, err := l.svcCtx.SysUserRoleModel.FindRoleIdsByUserIdForProduct(l.ctx, req.UserId, productCode) if err != nil { return err } existingSet := make(map[int64]bool, len(existingRoleIds)) for _, id := range existingRoleIds { existingSet[id] = true } newSet := make(map[int64]bool, len(req.RoleIds)) for _, id := range req.RoleIds { newSet[id] = true } var toAdd []int64 for _, id := range req.RoleIds { if !existingSet[id] { toAdd = append(toAdd, id) } } var toRemove []int64 for _, id := range existingRoleIds { if !newSet[id] { toRemove = append(toRemove, id) } } if len(toAdd) == 0 && len(toRemove) == 0 { return nil } if err := l.svcCtx.SysUserRoleModel.TransactCtx(l.ctx, func(ctx context.Context, session sqlx.Session) error { for _, roleId := range toRemove { query := fmt.Sprintf("DELETE FROM %s WHERE `userId` = ? AND `roleId` = ?", l.svcCtx.SysUserRoleModel.TableName()) if _, err := session.ExecCtx(ctx, query, req.UserId, roleId); err != nil { return err } } if len(toAdd) > 0 { now := time.Now().Unix() data := make([]*userrole.SysUserRole, 0, len(toAdd)) for _, roleId := range toAdd { data = append(data, &userrole.SysUserRole{ UserId: req.UserId, RoleId: roleId, CreateTime: now, UpdateTime: now, }) } return l.svcCtx.SysUserRoleModel.BatchInsertWithTx(ctx, session, data) } return nil }); err != nil { return err } l.svcCtx.UserDetailsLoader.Clean(l.ctx, req.UserId) return nil }