mirror of
https://github.com/Lilac-Rose/Lacie.git
synced 2026-09-08 00:56:21 -05:00
- prestige color: block equipping the color copy of your highest role,
since the copy sits lower in the hierarchy and demotes your member list position; now shows a clear error message instead - emote credits: add /emote_credits_update command so users can submit corrections to existing credits (goes through the same approval flow, shows old → new credit in the approval embed and DMs) - emote credits: add is_update/old_artist columns to pending_credits with auto-migration for existing installs - bot: disable archipelago_monitor cog (unloads it if currently loaded)
This commit is contained in:
7
bot.py
7
bot.py
@@ -55,11 +55,18 @@ bot.tree.add_command(xp_admin_group)
|
||||
# --- Cog loading ---
|
||||
async def load_cogs(folder: str):
|
||||
non_cog_files = {"add_xp.py", "database.py", "utils.py", "__init__.py", "groups.py", "loader.py"}
|
||||
disabled_cogs = {"archipelago_monitor.py"}
|
||||
for file in glob.glob(f"{folder}/*.py"):
|
||||
filename = os.path.basename(file)
|
||||
if filename in non_cog_files:
|
||||
logger.debug(f"Skipping {filename} (utility file)")
|
||||
continue
|
||||
if filename in disabled_cogs:
|
||||
module_name = f"{folder}.{os.path.splitext(filename)[0]}"
|
||||
if module_name in bot.extensions:
|
||||
await bot.unload_extension(module_name)
|
||||
logger.info(f"Unloaded disabled cog {module_name}")
|
||||
continue
|
||||
module_name = f"{folder}.{os.path.splitext(filename)[0]}"
|
||||
try:
|
||||
if module_name in bot.extensions:
|
||||
|
||||
@@ -38,10 +38,19 @@ class EmoteCredits(ModerationBase, commands.Cog):
|
||||
artist TEXT NOT NULL,
|
||||
submitted_by INTEGER NOT NULL,
|
||||
submitted_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
message_id INTEGER
|
||||
message_id INTEGER,
|
||||
is_update BOOLEAN DEFAULT 0,
|
||||
old_artist TEXT
|
||||
)
|
||||
""")
|
||||
|
||||
# migrate existing tables that predate is_update / old_artist columns
|
||||
for col, definition in [("is_update", "BOOLEAN DEFAULT 0"), ("old_artist", "TEXT")]:
|
||||
try:
|
||||
await conn.execute(f"ALTER TABLE pending_credits ADD COLUMN {col} {definition}")
|
||||
except Exception:
|
||||
pass # column already exists
|
||||
|
||||
await conn.commit()
|
||||
|
||||
async def get_credit(self, emote_name: str):
|
||||
@@ -169,6 +178,75 @@ class EmoteCredits(ModerationBase, commands.Cog):
|
||||
)
|
||||
await interaction.followup.send(embed=embed, ephemeral=True)
|
||||
|
||||
@app_commands.command(name="emote_credits_update", description="Submit a correction to an existing emote or sticker credit")
|
||||
@app_commands.describe(
|
||||
emote="The emoji or sticker (you can type it directly!)",
|
||||
artist="The corrected artist name"
|
||||
)
|
||||
async def emote_credits_update(self, interaction: discord.Interaction, emote: str, artist: str):
|
||||
await interaction.response.defer(ephemeral=True)
|
||||
|
||||
emoji_name = self.parse_emoji_name(emote)
|
||||
|
||||
existing_credit = await self.get_credit(emoji_name)
|
||||
if not existing_credit:
|
||||
embed = discord.Embed(
|
||||
title="❌ No Existing Credit",
|
||||
description=f"**{emoji_name}** doesn't have a credit yet. Use `/emote_credits_add` to submit one.",
|
||||
color=discord.Color.red()
|
||||
)
|
||||
await interaction.followup.send(embed=embed, ephemeral=True)
|
||||
return
|
||||
|
||||
if existing_credit.lower() == artist.lower():
|
||||
embed = discord.Embed(
|
||||
title="⚠️ No Change",
|
||||
description=f"**{emoji_name}** is already credited to **{existing_credit}**.",
|
||||
color=discord.Color.orange()
|
||||
)
|
||||
await interaction.followup.send(embed=embed, ephemeral=True)
|
||||
return
|
||||
|
||||
async with aiosqlite.connect(self.db_path) as conn:
|
||||
cursor = await conn.execute(
|
||||
"INSERT INTO pending_credits (emote_name, artist, submitted_by, is_update, old_artist) VALUES (?, ?, ?, 1, ?)",
|
||||
(emoji_name, artist, interaction.user.id, existing_credit)
|
||||
)
|
||||
submission_id = cursor.lastrowid
|
||||
await conn.commit()
|
||||
|
||||
approval_channel = self.bot.get_channel(self.approval_channel_id)
|
||||
if not approval_channel:
|
||||
await interaction.followup.send("❌ Approval channel not found. Please contact an admin.", ephemeral=True)
|
||||
return
|
||||
|
||||
approval_embed = discord.Embed(
|
||||
title="✏️ Credit Update Submission",
|
||||
color=discord.Color.blue()
|
||||
)
|
||||
approval_embed.add_field(name="Emote Name", value=f"`{emoji_name}`", inline=False)
|
||||
approval_embed.add_field(name="Current Credit", value=existing_credit, inline=False)
|
||||
approval_embed.add_field(name="Proposed Credit", value=artist, inline=False)
|
||||
approval_embed.add_field(name="Submitted By", value=interaction.user.mention, inline=False)
|
||||
approval_embed.set_footer(text=f"Submission ID: {submission_id}")
|
||||
|
||||
view = CreditApprovalView(self, submission_id, emoji_name, artist, interaction.user.id, is_update=True, old_artist=existing_credit)
|
||||
approval_msg = await approval_channel.send(embed=approval_embed, view=view)
|
||||
|
||||
async with aiosqlite.connect(self.db_path) as conn:
|
||||
await conn.execute(
|
||||
"UPDATE pending_credits SET message_id = ? WHERE id = ?",
|
||||
(approval_msg.id, submission_id)
|
||||
)
|
||||
await conn.commit()
|
||||
|
||||
embed = discord.Embed(
|
||||
title="✅ Update Submitted",
|
||||
description=f"Your correction for **{emoji_name}** (changing credit from **{existing_credit}** to **{artist}**) has been sent for approval!",
|
||||
color=discord.Color.green()
|
||||
)
|
||||
await interaction.followup.send(embed=embed, ephemeral=True)
|
||||
|
||||
@app_commands.command(name="emote_artists", description="List all artists who have credited emotes or stickers")
|
||||
async def emote_artists(self, interaction: discord.Interaction):
|
||||
await interaction.response.defer()
|
||||
@@ -397,13 +475,15 @@ class EmoteCredits(ModerationBase, commands.Cog):
|
||||
|
||||
|
||||
class CreditApprovalView(discord.ui.View):
|
||||
def __init__(self, cog, submission_id, emote_name, artist, submitted_by):
|
||||
def __init__(self, cog, submission_id, emote_name, artist, submitted_by, is_update=False, old_artist=None):
|
||||
super().__init__(timeout=None)
|
||||
self.cog = cog
|
||||
self.submission_id = submission_id
|
||||
self.emote_name = emote_name
|
||||
self.artist = artist
|
||||
self.submitted_by = submitted_by
|
||||
self.is_update = is_update
|
||||
self.old_artist = old_artist
|
||||
|
||||
@discord.ui.button(label="Approve", style=discord.ButtonStyle.green, custom_id="approve_credit")
|
||||
async def approve_button(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||
@@ -417,11 +497,15 @@ class CreditApprovalView(discord.ui.View):
|
||||
|
||||
# Update message
|
||||
embed = discord.Embed(
|
||||
title="✅ Credit Approved",
|
||||
title="✅ Credit Update Approved" if self.is_update else "✅ Credit Approved",
|
||||
color=discord.Color.green()
|
||||
)
|
||||
embed.add_field(name="Emote Name", value=f"`{self.emote_name}`", inline=False)
|
||||
embed.add_field(name="Artist", value=self.artist, inline=False)
|
||||
if self.is_update and self.old_artist:
|
||||
embed.add_field(name="Old Credit", value=self.old_artist, inline=False)
|
||||
embed.add_field(name="New Credit", value=self.artist, inline=False)
|
||||
else:
|
||||
embed.add_field(name="Artist", value=self.artist, inline=False)
|
||||
embed.add_field(name="Approved By", value=interaction.user.mention, inline=False)
|
||||
|
||||
await interaction.response.edit_message(embed=embed, view=None)
|
||||
@@ -429,11 +513,18 @@ class CreditApprovalView(discord.ui.View):
|
||||
# Notify submitter
|
||||
try:
|
||||
submitter = await self.cog.bot.fetch_user(self.submitted_by)
|
||||
notify_embed = discord.Embed(
|
||||
title="✅ Your Credit Submission Was Approved!",
|
||||
description=f"**{self.emote_name}** by **{self.artist}** has been added to the credits database.",
|
||||
color=discord.Color.green()
|
||||
)
|
||||
if self.is_update and self.old_artist:
|
||||
notify_embed = discord.Embed(
|
||||
title="✅ Your Credit Update Was Approved!",
|
||||
description=f"The credit for **{self.emote_name}** has been updated from **{self.old_artist}** to **{self.artist}**.",
|
||||
color=discord.Color.green()
|
||||
)
|
||||
else:
|
||||
notify_embed = discord.Embed(
|
||||
title="✅ Your Credit Submission Was Approved!",
|
||||
description=f"**{self.emote_name}** by **{self.artist}** has been added to the credits database.",
|
||||
color=discord.Color.green()
|
||||
)
|
||||
await submitter.send(embed=notify_embed)
|
||||
except Exception:
|
||||
pass
|
||||
@@ -459,11 +550,18 @@ class CreditApprovalView(discord.ui.View):
|
||||
# Notify submitter
|
||||
try:
|
||||
submitter = await self.cog.bot.fetch_user(self.submitted_by)
|
||||
notify_embed = discord.Embed(
|
||||
title="❌ Your Credit Submission Was Denied",
|
||||
description=f"Your submission for **{self.emote_name}** by **{self.artist}** was not approved.",
|
||||
color=discord.Color.red()
|
||||
)
|
||||
if self.is_update and self.old_artist:
|
||||
notify_embed = discord.Embed(
|
||||
title="❌ Your Credit Update Was Denied",
|
||||
description=f"Your proposed change for **{self.emote_name}** (from **{self.old_artist}** to **{self.artist}**) was not approved.",
|
||||
color=discord.Color.red()
|
||||
)
|
||||
else:
|
||||
notify_embed = discord.Embed(
|
||||
title="❌ Your Credit Submission Was Denied",
|
||||
description=f"Your submission for **{self.emote_name}** by **{self.artist}** was not approved.",
|
||||
color=discord.Color.red()
|
||||
)
|
||||
await submitter.send(embed=notify_embed)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
@@ -18,7 +18,6 @@ PRESTIGE_ROLES: dict[str, int] = {
|
||||
"Elite Ritualist": 1296055376009101384,
|
||||
"Honorable Ritualist": 1213171315259736155,
|
||||
"Content Creator": 1038402681376612413,
|
||||
"Ritual Sponsor": 881560923494547477,
|
||||
}
|
||||
|
||||
# Color copies get placed just above this role in the hierarchy
|
||||
@@ -172,6 +171,24 @@ class PrestigeColor(commands.Cog):
|
||||
)
|
||||
return
|
||||
|
||||
# Block equipping the color copy of the user's highest prestige role.
|
||||
# The copy sits lower in the hierarchy than the original, so swapping it out
|
||||
# would actually demote the user's display position in the member list.
|
||||
member_prestige_roles = [
|
||||
guild.get_role(pid)
|
||||
for pid in PRESTIGE_ROLES.values()
|
||||
if guild.get_role(pid) and guild.get_role(pid) in member.roles
|
||||
]
|
||||
if member_prestige_roles:
|
||||
highest_prestige = max(member_prestige_roles, key=lambda r: r.position)
|
||||
if highest_prestige.id == original_id:
|
||||
await interaction.followup.send(
|
||||
f"**{prestige}** is already your highest role — its color is already showing correctly. "
|
||||
f"You can only equip a color for a role that isn't your highest.",
|
||||
ephemeral=True
|
||||
)
|
||||
return
|
||||
|
||||
all_copy_ids = set(color_ids.values())
|
||||
|
||||
# If they had a different color active, swap it out and give back the original.
|
||||
@@ -182,7 +199,7 @@ class PrestigeColor(commands.Cog):
|
||||
await member.remove_roles(*old_copies, reason="Switching prestige color")
|
||||
to_restore = [
|
||||
copy_to_original[r.id] for r in old_copies
|
||||
if copy_to_original.get(r.id) and copy_to_original[r.id] not in member.roles
|
||||
if copy_to_original.get(r.id)
|
||||
]
|
||||
if to_restore:
|
||||
await member.add_roles(*to_restore, reason="Restoring prestige role after color switch")
|
||||
@@ -223,7 +240,7 @@ class PrestigeColor(commands.Cog):
|
||||
copy_to_original = {v: guild.get_role(int(k)) for k, v in color_ids.items()}
|
||||
to_restore = [
|
||||
copy_to_original[r.id] for r in to_remove
|
||||
if copy_to_original.get(r.id) and copy_to_original[r.id] not in member.roles
|
||||
if copy_to_original.get(r.id)
|
||||
]
|
||||
if to_restore:
|
||||
await member.add_roles(*to_restore, reason="Restoring prestige role after color removal")
|
||||
|
||||
Reference in New Issue
Block a user