package service import ( "context" "errors" "server/internal/db" "server/internal/db/sqlc" "server/internal/middleware" "server/internal/model/request" "server/internal/model/response" "server/internal/pkg/cache" "server/internal/pkg/cache/cachekey" "server/internal/pkg/dberr" "server/internal/pkg/errs" "server/internal/pkg/httputil" "golang.org/x/sync/errgroup" ) type SysUserService struct { store *db.Store jwt *middleware.JWTMiddleware cache *cache.Caches } func NewSysUserService(store *db.Store, jwt *middleware.JWTMiddleware, cache *cache.Caches) *SysUserService { return &SysUserService{ store: store, jwt: jwt, cache: cache, } } // clearUserCache func (s *SysUserService) clearUserCache(ctx context.Context, id int32) error { if err := s.cache.Del(ctx, cachekey.UserApiPermissions(id)); err != nil { return err } if err := s.cache.Del(ctx, cachekey.UserInfo(id)); err != nil { return err } return nil } // clearRefreshToken func (s *SysUserService) clearRefreshToken(ctx context.Context, id int32) error { keys, err := s.cache.SMembers(ctx, cachekey.AuthRefreshUser(id)) if err != nil { return err } // 循环删除所有的token for _, key := range keys { if err = s.cache.Del(ctx, cachekey.AuthRefresh(key)); err != nil { return err } } // 删除反向索引 err = s.cache.DelSetMembers(ctx, cachekey.AuthRefreshUser(id)) return err } func (s *SysUserService) GetUserInfo(ctx context.Context, id int32, isAdmin bool) (*response.SysUserInfo, error) { return cache.GetOrSetJSON[*response.SysUserInfo](ctx, s.cache, cachekey.UserInfo(id), 0, func() (*response.SysUserInfo, error) { g, ctx := errgroup.WithContext(ctx) var ( user sqlc.GetSysUserByIDRow roles []sqlc.SysRole menus []sqlc.SysMenu permissions []*string ) g.Go(func() error { u, err := s.store.GetSysUserByID(ctx, id) if err != nil { return dberr.MapNoRows(err, errs.ErrUserNotFound) } user = u return nil }) g.Go(func() error { r, err := s.store.GetSysUserRoles(ctx, id) if err != nil { return err } roles = r return nil }) g.Go(func() error { var ( p []*string err error ) if isAdmin { p, err = s.store.GetSysAdminPermissions(ctx) } else { p, err = s.store.GetSysUserPermissions(ctx, id) } if err != nil { return err } permissions = p return nil }) g.Go(func() error { var ( m []sqlc.SysMenu err error ) if isAdmin { m, err = s.store.GetSysAdminMenus(ctx) } else { m, err = s.store.GetSysUserMenus(ctx, id) } if err != nil { return err } menus = m return nil }) if err := g.Wait(); err != nil { return nil, err } // 如果用户被禁用 返回错误 超管不用管状态 if user.ID != 1 && user.Status != 1 { return nil, errs.ErrUserDisabled } // 处理角色 userInfo := response.NewSysUserInfo(user, roles, menus, permissions) return userInfo, nil }) } func (s *SysUserService) ListPage(ctx context.Context, p request.SearchSysUserParams) ([]sqlc.ListSysUsersRow, int64, error) { params := sqlc.ListSysUsersParams{ Limit: p.PageSize, Offset: (p.Page - 1) * p.PageSize, Username: p.Username, } total, err := s.store.CountSysUsers(ctx, p.Username) if err != nil { return nil, 0, err } users, err := s.store.ListSysUsers(ctx, params) if err != nil { return nil, 0, err } // 处理每个用户的头像URL for i := range users { url := httputil.BuildFileUrl(users[i].AvatarUrl) users[i].AvatarUrl = &url } return users, total, nil } func (s *SysUserService) GetRoles(ctx context.Context, id int32) ([]sqlc.SysRole, error) { // 先查询用户是否存在 _, err := s.store.GetSysUserByID(ctx, id) if err != nil { return nil, dberr.MapNoRows(err, errs.ErrUserNotFound) } return s.store.GetSysUserRoles(ctx, id) } func (s *SysUserService) Create(ctx context.Context, req request.CreateSysUserRequest) error { passwordHash, err := generatePasswordHash(req.Password) if err != nil { return err } user := sqlc.CreateSysUserParams{ Account: req.Account, Username: req.Username, PasswordHash: passwordHash, AvatarID: req.AvatarID, Status: *req.Status, } if err = s.store.CreateSysUser(ctx, user); err != nil { return dberr.MapUniqueViolation(err, dberr.SysUserAccountKey, errs.ErrAccountAlreadyExists) } return nil } func (s *SysUserService) Update(ctx context.Context, id int32, req request.UpdateSysUserRequest) error { user := sqlc.UpdateSysUserParams{ Username: req.Username, ID: id, Status: req.Status, } if req.AvatarID.Set { user.UpdateAvatarID = true if req.AvatarID.Valid { user.AvatarID = &req.AvatarID.Value } } rows, err := s.store.UpdateSysUser(ctx, user) if err = dberr.MapRowsAffected(rows, err, errs.ErrUserNotFound); err != nil { return err } // 清理缓存 _ = s.clearUserCache(ctx, id) // 如果将用户的状态修改为0,则清除用户刷新令牌 if req.Status != nil && *req.Status == 0 { _ = s.clearRefreshToken(ctx, id) } return nil } func (s *SysUserService) SetRoles(ctx context.Context, userID int32, req request.SetSysUserRolesRequest) error { // 先查询用户是否存在 _, err := s.store.GetSysUserByID(ctx, userID) if err != nil { return dberr.MapNoRows(err, errs.ErrUserNotFound) } err = s.store.WithTx(ctx, func(q *sqlc.Queries) error { // 1. 先删除关联数据 if err = q.ClearSysUserRoles(ctx, userID); err != nil { return err } var params []sqlc.CreateSysUserRoleParams for _, roleID := range req.RoleIDs { params = append(params, sqlc.CreateSysUserRoleParams{ UserID: userID, RoleID: roleID, }) } // 2. 关联用户角色数据 _, err = q.CreateSysUserRole(ctx, params) if err != nil { return err } return nil }) if err != nil { return err } // 3. 清理缓存 _ = s.clearUserCache(ctx, userID) return nil } func (s *SysUserService) UpdatePassword(ctx context.Context, id int32, req request.UpdateSysUserPassword) error { passwordHash, err := generatePasswordHash(req.Password) if err != nil { return err } params := sqlc.UpdateSysUserPasswordParams{ ID: id, PasswordHash: passwordHash, } rows, err := s.store.UpdateSysUserPassword(ctx, params) err = dberr.MapRowsAffected(rows, err, errs.ErrUserNotFound) if err != nil { return err } // 下线当前用户 _ = s.clearRefreshToken(ctx, id) return nil } func (s *SysUserService) Delete(ctx context.Context, id int32) error { if id == 1 { return errs.ErrCannotDeleteSuperAdmin } err := s.store.WithTx(ctx, func(q *sqlc.Queries) error { // 清理用户角色关联数据 err := q.ClearSysUserRoles(ctx, id) if err != nil { return err } // 删除用户 rows, err := q.DeleteSysUser(ctx, id) return dberr.MapRowsAffected(rows, err, errs.ErrUserNotFound) }) if err != nil { if errors.Is(err, errs.ErrUserNotFound) { // 用户不存在也执行清理缓存操作 _ = s.clearUserCache(ctx, id) } return err } // 事务执行成功后清理缓存 _ = s.clearUserCache(ctx, id) _ = s.clearRefreshToken(ctx, id) return nil }