forked from sass/tipibot
Compare commits
5 Commits
3939c879c9
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0cdd8dac63 | ||
|
|
6101a278e7 | ||
|
|
1e9ec56761 | ||
|
|
a96488fe9e | ||
|
|
25cf60d2e1 |
5
bot.py
5
bot.py
@@ -594,12 +594,7 @@ class HelpSelect(discord.ui.Select):
|
|||||||
|
|
||||||
@tree.command(name="help", description=S.CMD["help"])
|
@tree.command(name="help", description=S.CMD["help"])
|
||||||
async def cmd_help(interaction: discord.Interaction):
|
async def cmd_help(interaction: discord.Interaction):
|
||||||
<<<<<<< HEAD
|
|
||||||
is_admin = is_bot_admin(interaction.user)
|
is_admin = is_bot_admin(interaction.user)
|
||||||
=======
|
|
||||||
member = interaction.user
|
|
||||||
is_admin = isinstance(member, discord.Member) and is_bot_admin(member)
|
|
||||||
>>>>>>> 42f7bae68124fa6a9824780ba17b46d00f3f2b36
|
|
||||||
await interaction.response.send_message(
|
await interaction.response.send_message(
|
||||||
embed=_help_embed("üldine"), view=HelpView(is_admin), ephemeral=True
|
embed=_help_embed("üldine"), view=HelpView(is_admin), ephemeral=True
|
||||||
)
|
)
|
||||||
|
|||||||
52
config.py
52
config.py
@@ -43,21 +43,28 @@ BIRTHDAY_WINDOW_DAYS = int(os.getenv("BIRTHDAY_WINDOW_DAYS", "7"))
|
|||||||
BASE_ROLE_IDS: list[int] = [1478304631930228779, 1478302278862766190]
|
BASE_ROLE_IDS: list[int] = [1478304631930228779, 1478302278862766190]
|
||||||
|
|
||||||
|
|
||||||
def _parse_admin_roles(raw: str) -> dict[int, int]:
|
def _parse_admin_roles(raw: str) -> dict[int, set[int]]:
|
||||||
"""Parse BOT_ADMIN_ROLES env var as "guild_id:role_id,guild_id:role_id"."""
|
"""Parse DISCORD_ADMIN_ROLES env var as "guild_id:role_id[:role_id...],guild_id:role_id...".
|
||||||
result: dict[int, int] = {}
|
|
||||||
for pair in raw.split(","):
|
Multiple admin roles per guild are colon-separated; guild entries are comma-separated.
|
||||||
pair = pair.strip()
|
Repeating a guild_id across entries merges its roles.
|
||||||
if not pair:
|
"""
|
||||||
|
result: dict[int, set[int]] = {}
|
||||||
|
for entry in raw.split(","):
|
||||||
|
entry = entry.strip()
|
||||||
|
if not entry:
|
||||||
continue
|
continue
|
||||||
guild_str, _, role_str = pair.partition(":")
|
parts = entry.split(":")
|
||||||
if not role_str:
|
if len(parts) < 2 or not all(p.strip() for p in parts):
|
||||||
raise SystemExit(f"BOT_ADMIN_ROLES: expected 'guild_id:role_id', got {pair!r}")
|
raise SystemExit(
|
||||||
result[int(guild_str)] = int(role_str)
|
f"DISCORD_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
|
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("DISCORD_ADMIN_ROLES", ""))
|
||||||
|
|
||||||
PB_URL = os.getenv("PB_URL", "http://127.0.0.1:8090")
|
PB_URL = os.getenv("PB_URL", "http://127.0.0.1:8090")
|
||||||
PB_ADMIN_EMAIL = os.getenv("PB_ADMIN_EMAIL", "")
|
PB_ADMIN_EMAIL = os.getenv("PB_ADMIN_EMAIL", "")
|
||||||
@@ -75,26 +82,3 @@ PB_ECONOMY_COLLECTION_ECONOMY = (
|
|||||||
PB_ECONOMY_COLLECTION = (
|
PB_ECONOMY_COLLECTION = (
|
||||||
PB_ECONOMY_COLLECTION_ECONOMY if BOT_PROFILE == "economy" else PB_ECONOMY_COLLECTION_DEV
|
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()
|
|
||||||
|
|||||||
@@ -6,38 +6,22 @@ from discord import app_commands
|
|||||||
import config
|
import config
|
||||||
|
|
||||||
|
|
||||||
<<<<<<< HEAD
|
|
||||||
def is_bot_admin(member: discord.abc.User | None) -> bool:
|
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:
|
if not isinstance(member, discord.Member) or member.guild is None:
|
||||||
return False
|
return False
|
||||||
=======
|
admin_role_ids = config.BOT_ADMIN_ROLES.get(member.guild.id)
|
||||||
def is_bot_admin(member: discord.Member) -> bool:
|
if not admin_role_ids:
|
||||||
"""Return True if the member has the configured bot-admin role for their guild."""
|
|
||||||
>>>>>>> 42f7bae68124fa6a9824780ba17b46d00f3f2b36
|
|
||||||
role_id = config.BOT_ADMIN_ROLES.get(member.guild.id)
|
|
||||||
if role_id is None:
|
|
||||||
return False
|
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():
|
def bot_admin_check():
|
||||||
<<<<<<< HEAD
|
|
||||||
"""Slash-command decorator that gates execution behind ``is_bot_admin``."""
|
"""Slash-command decorator that gates execution behind ``is_bot_admin``."""
|
||||||
|
|
||||||
async def predicate(interaction: discord.Interaction) -> bool:
|
async def predicate(interaction: discord.Interaction) -> bool:
|
||||||
if is_bot_admin(interaction.user):
|
if is_bot_admin(interaction.user):
|
||||||
return True
|
return True
|
||||||
raise app_commands.MissingPermissions(["bot_admin_role"])
|
raise app_commands.MissingPermissions(["bot_admin_role"])
|
||||||
=======
|
|
||||||
"""Slash-command check decorator: raises MissingPermissions if not a bot admin."""
|
|
||||||
def predicate(interaction: discord.Interaction) -> bool:
|
|
||||||
member = interaction.user
|
|
||||||
if not isinstance(member, discord.Member):
|
|
||||||
raise app_commands.MissingPermissions(["bot_admin"])
|
|
||||||
if not is_bot_admin(member):
|
|
||||||
raise app_commands.MissingPermissions(["bot_admin"])
|
|
||||||
return True
|
|
||||||
>>>>>>> 42f7bae68124fa6a9824780ba17b46d00f3f2b36
|
|
||||||
|
|
||||||
return app_commands.check(predicate)
|
return app_commands.check(predicate)
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ _DEV: dict[str, str] = {
|
|||||||
"TipiTROLL": "<:TipiTROLL:1483431380166774895>",
|
"TipiTROLL": "<:TipiTROLL:1483431380166774895>",
|
||||||
"TipICRY": "<:TipICRY:1483431288852709387>",
|
"TipICRY": "<:TipICRY:1483431288852709387>",
|
||||||
"TipiSKULL": "<:TipiSKULL:1483431378929451028>",
|
"TipiSKULL": "<:TipiSKULL:1483431378929451028>",
|
||||||
"TipiDICE": "<:TipiDICE:1485923107108556950>",
|
"TipiDICE": "<a:TipiDICE:1485923107108556950>",
|
||||||
"TipiYKS": "<:TipiYKS:1483103190491856916>",
|
"TipiYKS": "<:TipiYKS:1483103190491856916>",
|
||||||
"TipiKAKS": "<:TipiKAKS:1483103215841972404>",
|
"TipiKAKS": "<:TipiKAKS:1483103215841972404>",
|
||||||
"TipiKOLM": "<:TipiKOLM:1483103217846980781>",
|
"TipiKOLM": "<:TipiKOLM:1483103217846980781>",
|
||||||
@@ -47,11 +47,42 @@ _DEV: dict[str, str] = {
|
|||||||
"TipiSLOTS": "<a:TipiSLOTS:1483444233863037101>",
|
"TipiSLOTS": "<a:TipiSLOTS:1483444233863037101>",
|
||||||
}
|
}
|
||||||
|
|
||||||
# Production application emoji IDs. Replace each ID with the one from the
|
# Production application emoji IDs (from the TipiBOT application's dev-portal
|
||||||
# prod application in the dev portal. The dev IDs below are placeholders so
|
# Emojis tab). The display name in <:name:id> is cosmetic — Discord resolves
|
||||||
# this dict is structurally complete — they will NOT render in prod because
|
# by ID — so we keep the same logical names as _DEV even when the prod portal
|
||||||
# they belong to a different application.
|
# uses a different upload name (e.g. prod's "TipiFIVE" → key "TipiVIIS").
|
||||||
_ECONOMY: dict[str, str] = dict(_DEV)
|
_ECONOMY: dict[str, str] = {
|
||||||
|
"TipiCOIN": "<:TipiCOIN:1511754551747940485>",
|
||||||
|
"TipiFIRE": "<:TipiFIRE:1511754615761272862>",
|
||||||
|
"TipiHIIR": "<:TipiHIIR:1511754556105822218>",
|
||||||
|
"TipiMATT": "<:TipiMATT:1511754595448131665>",
|
||||||
|
"TipiKLAPID": "<:TipiKLAPID:1511754589798666433>",
|
||||||
|
"TipiPILET": "<:TipiPILET:1511754560593727652>",
|
||||||
|
"TipiBULL": "<:TipiBULL:1511754564179595264>",
|
||||||
|
"TipiLAP": "<:TipiLAP:1511754558970269907>",
|
||||||
|
"TipiVAC": "<:TipiVAC:1511754562413924442>",
|
||||||
|
"TipiLAUD": "<:TipiLAUD:1511754592759713985>",
|
||||||
|
"TipiSERVER": "<:TipiSERVER:1511754601186066534>",
|
||||||
|
"TipiMIC": "<:TipiMIC:1511754597016801310>",
|
||||||
|
"TipiKLAVA": "<:TipiKLAVA:1511754567648542780>",
|
||||||
|
"TipiMONITOR": "<:TipiMONITOR:1511754570722971868>",
|
||||||
|
"TipiCAT": "<:TipiCAT:1511754566092193853>",
|
||||||
|
"TipiMONITOR2": "<:TipiMONITOR2:1511754598732402689>",
|
||||||
|
"TipiKARIKAS": "<:TipiKARIKAS:1511754574405435502>",
|
||||||
|
"TipiTOOL": "<:TipiTOOL:1511754572522061874>",
|
||||||
|
"TipiHEART": "<:TipiHEART:1511754608299737139>",
|
||||||
|
"TipiTROLL": "<:TipiTROLL:1511754612775063832>",
|
||||||
|
"TipICRY": "<:TipICRY:1511754603308515368>",
|
||||||
|
"TipiSKULL": "<:TipiSKULL:1511754610195566622>",
|
||||||
|
"TipiDICE": "<a:TipiDICE:1511753607119376504>",
|
||||||
|
"TipiYKS": "<:TipiYKS:1511754576368373951>",
|
||||||
|
"TipiKAKS": "<:TipiKAKS:1511754577928523997>",
|
||||||
|
"TipiKOLM": "<:TipiKOLM:1511754581078442005>",
|
||||||
|
"TipiNELI": "<:TipiNELI:1511754582571880509>",
|
||||||
|
"TipiVIIS": "<:TipiVIIS:1511754584182227005>",
|
||||||
|
"TipiKUUS": "<:TipiKUUS:1511754586262736977>",
|
||||||
|
"TipiSLOTS": "<a:TipiSLOTS:1511754521188106431>",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
_EMOJI_SETS = {
|
_EMOJI_SETS = {
|
||||||
|
|||||||
Reference in New Issue
Block a user