| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246 |
- from __future__ import annotations
- from collections.abc import Iterable
- from dataclasses import asdict, dataclass
- @dataclass(frozen=True)
- class BotPermission:
- key: str
- name: str
- group: str
- description: str
- @dataclass(frozen=True)
- class BuiltinBotRole:
- role_id: str
- name: str
- description: str
- permissions: tuple[str, ...]
- PERMISSIONS = (
- BotPermission("chat.profile", "群资料", "群组管理", "修改群标题和描述。"),
- BotPermission("chat.members", "成员与管理员", "群组管理", "查询、处罚及调整管理员。"),
- BotPermission("chat.permissions", "群权限", "群组管理", "修改普通成员默认权限。"),
- BotPermission("chat.announcements", "公告", "群组管理", "发送并置顶群公告。"),
- BotPermission("chat.invites", "邀请链接", "群组管理", "创建和撤销邀请链接。"),
- BotPermission("chat.rules", "群规", "群组管理", "查看和维护群规。"),
- BotPermission("chat.notes", "群笔记", "群组管理", "维护群内笔记功能。"),
- BotPermission(
- "automation.manage",
- "自动化与风控",
- "自动化",
- "管理欢迎语、自动回复、验证码、聊天机器人、内容风控和资料监控。",
- ),
- BotPermission("points.manage", "积分", "社区运营", "运行积分规则、排行和人工调整。"),
- BotPermission("giveaways.manage", "抽奖", "社区运营", "创建、开奖、退款和管理参与者。"),
- BotPermission("karma.manage", "声望", "社区运营", "处理点赞、点踩和声望排行。"),
- BotPermission(
- "teacher_directory.manage",
- "技师与附近",
- "社区运营",
- "提供技师申请、上下榜、在线状态、位置和附近技师目录。",
- ),
- BotPermission("media.upload", "媒体中转", "系统能力", "向媒体中转群上传文件。"),
- )
- ALL_BOT_PERMISSIONS = frozenset(item.key for item in PERMISSIONS)
- GROUP_MANAGEMENT_PERMISSIONS = frozenset(
- {
- "chat.announcements",
- "chat.members",
- "chat.permissions",
- "automation.manage",
- "points.manage",
- "giveaways.manage",
- }
- )
- PRIVATE_MANAGEMENT_PERMISSIONS = GROUP_MANAGEMENT_PERMISSIONS | {
- "teacher_directory.manage"
- }
- BUILTIN_ROLES = (
- BuiltinBotRole(
- "full_access",
- "全部职责",
- "拥有当前系统的全部机器人职责。",
- tuple(item.key for item in PERMISSIONS),
- ),
- BuiltinBotRole(
- "group_manager",
- "群组管理员",
- "负责群资料、成员、权限、公告、邀请链接、群规和群笔记。",
- (
- "chat.profile",
- "chat.members",
- "chat.permissions",
- "chat.announcements",
- "chat.invites",
- "chat.rules",
- "chat.notes",
- ),
- ),
- BuiltinBotRole(
- "automation_manager",
- "自动化与风控专员",
- "负责自动回复、欢迎语、验证码、聊天机器人、风控和资料监控。",
- ("automation.manage", "media.upload"),
- ),
- BuiltinBotRole(
- "points_manager",
- "积分专员",
- "负责积分规则、签到、排行榜和积分调整。",
- ("points.manage",),
- ),
- BuiltinBotRole(
- "giveaway_manager",
- "抽奖专员",
- "负责抽奖全流程,并可处理抽奖关联积分。",
- ("giveaways.manage", "points.manage"),
- ),
- BuiltinBotRole(
- "karma_manager",
- "声望专员",
- "负责点赞、点踩和声望排行。",
- ("karma.manage",),
- ),
- BuiltinBotRole(
- "teacher_directory_manager",
- "技师目录专员",
- "负责技师申请、位置、上下榜、在线状态和附近技师目录。",
- ("teacher_directory.manage",),
- ),
- )
- MODULE_PERMISSIONS: dict[str, frozenset[str]] = {
- "admin": frozenset({"chat.members", "chat.announcements", "chat.invites"}),
- "admin_misc": frozenset({"chat.profile", "chat.members"}),
- "admin_panel": GROUP_MANAGEMENT_PERMISSIONS,
- "antiservice": frozenset({"automation.manage"}),
- "blacklist": frozenset({"automation.manage"}),
- "blacklist_chat": frozenset({"automation.manage"}),
- "chatbot": frozenset({"automation.manage"}),
- "filters": frozenset({"automation.manage"}),
- "flood": frozenset({"automation.manage"}),
- "greetings": frozenset({"automation.manage"}),
- "giveaway": frozenset({"giveaways.manage"}),
- "karma": frozenset({"karma.manage"}),
- "locks": frozenset({"chat.permissions"}),
- "notes": frozenset({"chat.notes"}),
- "points": frozenset({"points.manage"}),
- "rules": frozenset({"chat.rules"}),
- "teacher_directory": frozenset({"teacher_directory.manage"}),
- "technician_services": frozenset({"teacher_directory.manage"}),
- }
- TELEGRAM_COMMAND_PERMISSIONS = {
- "purge": "chat.members",
- "kick": "chat.members",
- "dkick": "chat.members",
- "ban": "chat.members",
- "dban": "chat.members",
- "tban": "chat.members",
- "unban": "chat.members",
- "listban": "chat.members",
- "listunban": "chat.members",
- "del": "chat.members",
- "promote": "chat.members",
- "fullpromote": "chat.members",
- "demote": "chat.members",
- "mute": "chat.members",
- "tmute": "chat.members",
- "unmute": "chat.members",
- "ban_ghosts": "chat.members",
- "warn": "chat.members",
- "dwarn": "chat.members",
- "rmwarns": "chat.members",
- "warns": "chat.members",
- "report": "chat.members",
- "admins": "chat.members",
- "admin": "chat.members",
- "set_user_title": "chat.members",
- "pin": "chat.announcements",
- "unpin": "chat.announcements",
- "invite": "chat.invites",
- "set_chat_title": "chat.profile",
- "set_chat_photo": "chat.profile",
- }
- def permission_catalog() -> list[dict[str, str]]:
- return [asdict(item) for item in PERMISSIONS]
- def builtin_roles() -> list[dict[str, object]]:
- return [
- {
- "role_id": item.role_id,
- "name": item.name,
- "description": item.description,
- "permissions": list(item.permissions),
- "builtin": True,
- }
- for item in BUILTIN_ROLES
- ]
- def normalize_permissions(values: object) -> list[str]:
- if not isinstance(values, (list, tuple, set, frozenset)):
- values = str(values or "").replace(",", " ").split()
- normalized = list(dict.fromkeys(str(item).strip() for item in values if str(item).strip()))
- unknown = sorted(set(normalized) - ALL_BOT_PERMISSIONS)
- if unknown:
- raise ValueError(f"未知机器人权限:{', '.join(unknown)}")
- return normalized
- def has_permission(permission: str, permissions: Iterable[str] | None) -> bool:
- current = set(permissions or ())
- return "*" in current or permission in current
- def has_any_permission(
- required: Iterable[str],
- permissions: Iterable[str] | None,
- ) -> bool:
- current = set(permissions or ())
- return "*" in current or bool(set(required) & current)
- def module_allowed(module: str, permissions: Iterable[str] | None) -> bool:
- required = MODULE_PERMISSIONS.get(module)
- return not required or has_any_permission(required, permissions)
- def api_permission(method: str, path: str) -> str | None:
- if path.startswith("/api/admin/v1/directory"):
- return "teacher_directory.manage"
- if path.startswith("/api/admin/v1/media"):
- return "media.upload"
- if path.startswith("/api/admin/v1/points"):
- return "points.manage"
- if path.startswith("/api/admin/v1/giveaways"):
- return "giveaways.manage"
- if "/giveaway-bans" in path:
- return "giveaways.manage"
- if not path.startswith("/api/admin/v1/chats/"):
- return None
- if path.endswith("/profile"):
- return "chat.profile"
- if path.endswith("/permissions"):
- return "chat.permissions"
- if path.endswith("/announcements"):
- return "chat.announcements"
- if "/members" in path or path.endswith("/admins"):
- return "chat.members"
- if path.endswith("/invites"):
- return "chat.invites"
- if path.endswith("/rules"):
- return "chat.rules"
- if path.endswith("/automation"):
- return "automation.manage"
- if "/points/" in path:
- return "points.manage"
- return None
|