完善角色与消息权限:收紧板管内容处置,彻底删除仅站长,并统一管理删帖/评弹窗。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-20 14:30:08 +08:00
parent 1f2e4b2a33
commit c0462a3500
37 changed files with 1340 additions and 472 deletions

View File

@@ -44,15 +44,23 @@ export function isOwner(role?: string | null): boolean {
return role === ROLES.OWNER;
}
/** 站长/超管:群聊监管旁路(可见全部群、撤回任意消息) */
/** 站长/超管:群聊监管旁路(可见全部群含私聊、撤回任意消息) */
export function canOverseeChat(role?: string | null): boolean {
return role === ROLES.OWNER || role === ROLES.SUPER_ADMIN;
}
/** 携带板块授权的最小用户形状(/me、帖子详情作者等均满足) */
/** 彻底删除帖/评:仅站长 */
export function canPurgeContent(role?: string | null): boolean {
return role === ROLES.OWNER;
}
/** 携带板块授权与消息权限的最小用户形状 */
export interface RoleUserLike {
role?: string | null;
board_ids?: number[] | null;
can_manage_messages?: boolean | null;
/** 是否至少管理一个群(/me 可带;后台入口用) */
chat_admin_room_count?: number | null;
}
/**
@@ -69,6 +77,29 @@ export function canModerateBoard(
return (user.board_ids ?? []).includes(boardId);
}
/**
* 板管不可软删管理员及以上作者的内容;作者本人不受此限(由调用方先判断自删)
*/
export function canModerateAuthor(
actor: RoleUserLike | null | undefined,
authorRole?: string | null
): boolean {
if (!actor) return false;
if (actor.role === ROLES.BOARD_ADMIN) {
return roleLevel(authorRole) < ROLE_LEVEL[ROLES.ADMIN];
}
return true;
}
/** 是否可软删他人内容(板块范围 + 作者角色保护) */
export function canStaffSoftDelete(
actor: RoleUserLike | null | undefined,
boardId: number | null | undefined,
authorRole?: string | null
): boolean {
return canModerateBoard(actor, boardId) && canModerateAuthor(actor, authorRole);
}
/** 是否拥有任意板块的内容审核权(后台「内容管理」入口) */
export function canModerateAny(user: RoleUserLike | null | undefined): boolean {
if (!user) return false;
@@ -76,6 +107,20 @@ export function canModerateAny(user: RoleUserLike | null | undefined): boolean {
return user.role === ROLES.BOARD_ADMIN && (user.board_ids?.length ?? 0) > 0;
}
/** 站点级消息管理(站长/超管固有,或 can_manage_messages) */
export function hasSiteMessagePerm(user: RoleUserLike | null | undefined): boolean {
if (!user) return false;
if (canOverseeChat(user.role)) return true;
return !!user.can_manage_messages;
}
/** 后台「消息管理」入口:站点消息权或至少是一个群的管理员 */
export function canAccessAdminMessages(user: RoleUserLike | null | undefined): boolean {
if (!user) return false;
if (hasSiteMessagePerm(user)) return true;
return (user.chat_admin_room_count ?? 0) > 0;
}
/** 角色图标 key(RoleBadge 负责映射到具体图标,集中配置便于替换) */
export type RoleIconKey = "crown" | "shield-star" | "shield" | "shield-board" | "user";
@@ -102,7 +147,7 @@ export const ROLE_META: Record<RoleKey, RoleMeta> = {
colorToken: "--gold",
softToken: "--gold-soft",
grantDesc:
"站点所有者:全部后台能力、群聊监管、用户内容档案;身份不可授予或降级。",
"站点所有者:全部后台能力、群聊监管、用户内容档案、彻底删除内容;身份不可授予或降级。",
},
[ROLES.SUPER_ADMIN]: {
key: ROLES.SUPER_ADMIN,
@@ -111,7 +156,7 @@ export const ROLE_META: Record<RoleKey, RoleMeta> = {
colorToken: "--accent",
softToken: "--accent-soft",
grantDesc:
"用户与角色管理、封禁、外观主题、公告;全站内容审核与置顶/加精;群聊监管(可见全部会话、可撤回任意消息)。不可动站长账号,亦无站长专属的用户内容档案。",
"用户与角色管理、封禁、外观主题、公告;全站内容软删与置顶/加精;群聊监管(可见全部会话、可撤回任意消息)。不可彻底删除内容,不可动站长账号,亦无站长专属的用户内容档案。",
},
[ROLES.ADMIN]: {
key: ROLES.ADMIN,
@@ -120,7 +165,7 @@ export const ROLE_META: Record<RoleKey, RoleMeta> = {
colorToken: "--accent",
softToken: "--accent-soft",
grantDesc:
"公告管理;全站帖子/评论审核;前台置顶与加精。不含用户权限、外观设置与群聊监管旁路。",
"公告管理;全站帖子/评论审核与软删;前台置顶与加精。不含用户权限、外观设置、彻底删除与默认的群聊监管(可由站长另授消息管理或任命群管理员)。",
},
[ROLES.BOARD_ADMIN]: {
key: ROLES.BOARD_ADMIN,
@@ -129,7 +174,7 @@ export const ROLE_META: Record<RoleKey, RoleMeta> = {
colorToken: "--accent",
softToken: "--accent-soft",
grantDesc:
"仅审核并管理被授权板块内的帖子与评论(含删除违规内容)。无公告、置顶/加精、用户管理与外观设置;须至少勾选一个板块。",
"仅审核并软删被授权板块内普通用户的帖子与评论;不可处置管理员/站长发布的内容,无消息管理、公告、置顶/加精、用户管理与外观设置;须至少勾选一个板块。",
},
[ROLES.USER]: {
key: ROLES.USER,