package service import ( "strings" "github.com/freefire/jiang13-bbs/model" ) // 权限码:后台功能点。路由通过 RequirePerm 声明, // 板块管理员的板块范围由 Actor.BoardIDs 在业务层二次校验。 const ( PermUsers = "users" // 用户与权限管理(超管/站长) PermAnnouncements = "announcements" // 公告管理(管理员及以上) PermSettings = "settings" // 站点外观设置(超管/站长) PermModeration = "moderation" // 内容审核(任意管理角色,板块范围受限) PermMessages = "messages" // 后台消息管理(站长/超管/站点消息 flag;群管另有业务层放行) PermBoards = "boards" // 板块管理(仅站长) ) // Actor 当前请求操作者的实时权限快照(每次后台请求从 DB 现取, // 不依赖 JWT 内的 role claim,角色/授权变更立即生效) type Actor struct { ID uint Username string Role model.Role BoardIDs []uint // 板块管理员被授权的板块;其他角色为空 CanManageMessages bool // 站点级消息管理 flag(站长授予);站长/超管不必依赖此字段 } // IsStaff 是否管理团队成员 func (a *Actor) IsStaff() bool { return a != nil && model.IsStaff(a.Role) } // HasPerm 是否拥有某后台功能点 func (a *Actor) HasPerm(p string) bool { if a == nil { return false } switch p { case PermBoards: return a.Role == model.RoleOwner case PermUsers, PermSettings: return a.Role == model.RoleSuperAdmin || a.Role == model.RoleOwner case PermAnnouncements: return model.RoleLevel(a.Role) >= model.RoleLevel(model.RoleAdmin) case PermModeration: return a.IsStaff() case PermMessages: return a.HasSiteMessagePerm() } return false } // HasSiteMessagePerm 站点级消息管理:站长/超管固有,或被授予 CanManageMessages func (a *Actor) HasSiteMessagePerm() bool { if a == nil { return false } if a.Role == model.RoleOwner || a.Role == model.RoleSuperAdmin { return true } return a.CanManageMessages } // CanPurgeContent 彻底删除帖/评:仅站长 func (a *Actor) CanPurgeContent() bool { return a != nil && a.Role == model.RoleOwner } // CanModerateBoard 是否可管理指定板块的内容: // 管理员及以上不限板块;板块管理员仅限被授权板块 func (a *Actor) CanModerateBoard(boardID uint) bool { if a == nil { return false } if model.RoleLevel(a.Role) >= model.RoleLevel(model.RoleAdmin) { return true } if a.Role != model.RoleBoardAdmin { return false } for _, id := range a.BoardIDs { if id == boardID { return true } } return false } // CanModerateAuthor 板管不可软删/恢复管理员及以上作者的内容;其他角色不受此限 func (a *Actor) CanModerateAuthor(authorRole model.Role) bool { if a == nil { return false } if a.Role == model.RoleBoardAdmin { return model.RoleLevel(authorRole) < model.RoleLevel(model.RoleAdmin) } return true } // CanAssignRole 操作者能否把他人设置为目标角色(站长不可被授予,仅站长可授予超管) func (a *Actor) CanAssignRole(target model.Role) bool { if a == nil { return false } if target == model.RoleOwner { return false // 站长身份不通过授权产生 } if target == model.RoleSuperAdmin { return a.Role == model.RoleOwner } return a.HasPerm(PermUsers) } // LoadActor 读取用户实时角色与板块授权 func (s *AuthService) LoadActor(id uint) (*Actor, error) { var u model.User if err := s.db.Select("id", "username", "role", "can_manage_messages").First(&u, id).Error; err != nil { return nil, err } actor := &Actor{ ID: u.ID, Username: u.Username, Role: u.Role, BoardIDs: []uint{}, CanManageMessages: u.CanManageMessages, } if u.Role == model.RoleBoardAdmin { var ids []uint if err := s.db.Model(&model.UserBoard{}). Where("user_id = ?", id). Order("board_id ASC"). Pluck("board_id", &ids).Error; err != nil { return nil, err } actor.BoardIDs = ids } return actor, nil } // GetUserRole 读取用户角色(内容作者保护用);用户不存在返回 user func (s *AuthService) GetUserRole(id uint) (model.Role, error) { var u model.User if err := s.db.Select("role").First(&u, id).Error; err != nil { return model.RoleUser, err } return u.Role, nil } // GetUserBoardIDs 读取用户被授权的板块 ID(供 /me 等场景) func (s *AuthService) GetUserBoardIDs(id uint) ([]uint, error) { var ids []uint err := s.db.Model(&model.UserBoard{}). Where("user_id = ?", id).Order("board_id ASC").Pluck("board_id", &ids).Error return ids, err } // GetUserIDByUsername 按用户名查 ID(登录失败审计用),用户不存在返回 0 func (s *AuthService) GetUserIDByUsername(username string) uint { username = strings.TrimSpace(username) if username == "" { return 0 } var u model.User if err := s.db.Select("id").Where("username = ?", username).First(&u).Error; err != nil { return 0 } return u.ID } // ListBoardModeratorIDs 可审核指定板块的用户 ID: // 站长/超管/全站管理员 + 被授权该板的板块管理员(未封禁、未删除) func (s *AuthService) ListBoardModeratorIDs(boardID uint) ([]uint, error) { var ids []uint // 全站可审:admin / super_admin / owner if err := s.db.Model(&model.User{}). Where("deleted_at IS NULL AND banned = ? AND role IN ?", false, []string{string(model.RoleAdmin), string(model.RoleSuperAdmin), string(model.RoleOwner)}). Pluck("id", &ids).Error; err != nil { return nil, err } // 板块管理员(授权该板) var boardAdminIDs []uint if err := s.db.Model(&model.UserBoard{}). Select("user_boards.user_id"). Joins("JOIN users ON users.id = user_boards.user_id"). Where("user_boards.board_id = ? AND users.deleted_at IS NULL AND users.banned = ? AND users.role = ?", boardID, false, string(model.RoleBoardAdmin)). Pluck("user_boards.user_id", &boardAdminIDs).Error; err != nil { return nil, err } seen := make(map[uint]struct{}, len(ids)+len(boardAdminIDs)) out := make([]uint, 0, len(ids)+len(boardAdminIDs)) for _, id := range ids { if _, ok := seen[id]; ok { continue } seen[id] = struct{}{} out = append(out, id) } for _, id := range boardAdminIDs { if _, ok := seen[id]; ok { continue } seen[id] = struct{}{} out = append(out, id) } return out, nil }