diff --git a/config.py b/config.py index 1ecd1f2..1470b49 100644 --- a/config.py +++ b/config.py @@ -43,21 +43,28 @@ BIRTHDAY_WINDOW_DAYS = int(os.getenv("BIRTHDAY_WINDOW_DAYS", "7")) BASE_ROLE_IDS: list[int] = [1478304631930228779, 1478302278862766190] -def _parse_admin_roles(raw: str) -> dict[int, int]: - """Parse BOT_ADMIN_ROLES env var as "guild_id:role_id,guild_id:role_id".""" - result: dict[int, int] = {} - for pair in raw.split(","): - pair = pair.strip() - if not pair: +def _parse_admin_roles(raw: str) -> dict[int, set[int]]: + """Parse BOT_ADMIN_ROLES env var as "guild_id:role_id[:role_id...],guild_id:role_id...". + + Multiple admin roles per guild are colon-separated; guild entries are comma-separated. + Repeating a guild_id across entries merges its roles. + """ + result: dict[int, set[int]] = {} + for entry in raw.split(","): + entry = entry.strip() + if not entry: continue - guild_str, _, role_str = pair.partition(":") - if not role_str: - raise SystemExit(f"BOT_ADMIN_ROLES: expected 'guild_id:role_id', got {pair!r}") - result[int(guild_str)] = int(role_str) + parts = entry.split(":") + if len(parts) < 2 or not all(p.strip() for p in parts): + raise SystemExit( + f"BOT_ADMIN_ROLES: expected 'guild_id:role_id[:role_id...]', got {entry!r}" + ) + guild_id = int(parts[0].strip()) + result.setdefault(guild_id, set()).update(int(p.strip()) for p in parts[1:]) return result -BOT_ADMIN_ROLES: dict[int, int] = _parse_admin_roles(os.getenv("BOT_ADMIN_ROLES", "")) +BOT_ADMIN_ROLES: dict[int, set[int]] = _parse_admin_roles(os.getenv("BOT_ADMIN_ROLES", "")) PB_URL = os.getenv("PB_URL", "http://127.0.0.1:8090") PB_ADMIN_EMAIL = os.getenv("PB_ADMIN_EMAIL", "") @@ -75,26 +82,3 @@ PB_ECONOMY_COLLECTION_ECONOMY = ( PB_ECONOMY_COLLECTION = ( PB_ECONOMY_COLLECTION_ECONOMY if BOT_PROFILE == "economy" else PB_ECONOMY_COLLECTION_DEV ) - - -def _parse_admin_roles() -> dict[int, int]: - """Parse BOT_ADMIN_ROLES env var (format: guild_id:role_id,guild_id:role_id).""" - raw = os.getenv("BOT_ADMIN_ROLES", "").strip() - if not raw: - return {} - result: dict[int, int] = {} - for pair in raw.split(","): - pair = pair.strip() - if not pair: - continue - parts = pair.split(":") - if len(parts) != 2: - continue - try: - result[int(parts[0].strip())] = int(parts[1].strip()) - except ValueError: - continue - return result - - -BOT_ADMIN_ROLES: dict[int, int] = _parse_admin_roles() diff --git a/core/admin.py b/core/admin.py index 74d127f..3e1b206 100644 --- a/core/admin.py +++ b/core/admin.py @@ -7,13 +7,13 @@ import config def is_bot_admin(member: discord.abc.User | None) -> bool: - """True when the member has the configured admin role for their guild.""" + """True when the member has any of the configured admin roles for their guild.""" if not isinstance(member, discord.Member) or member.guild is None: return False - role_id = config.BOT_ADMIN_ROLES.get(member.guild.id) - if role_id is None: + admin_role_ids = config.BOT_ADMIN_ROLES.get(member.guild.id) + if not admin_role_ids: return False - return any(r.id == role_id for r in member.roles) + return any(r.id in admin_role_ids for r in member.roles) def bot_admin_check():