feat(slop): tag system needs to be fixed

This commit is contained in:
neoarz
2025-09-17 23:05:08 -04:00
parent de49b17001
commit e5a90a5ee0
11 changed files with 908 additions and 0 deletions

14
bot.py
View File

@@ -163,6 +163,20 @@ class DiscordBot(commands.Bot):
self.logger.error(
f"Failed to load extension {folder}.{extension}\n{exception}"
)
elif os.path.isdir(os.path.join(folder_path, file)) and not file.startswith('__'):
if os.path.exists(os.path.join(folder_path, file, "__init__.py")):
full_name = f"{folder}.{file}".lower()
if file.lower() in disabled_cogs or full_name in disabled_cogs:
self.logger.info(f"Skipped disabled extension '{full_name}'")
continue
try:
await self.load_extension(f"cogs.{folder}.{file}")
self.logger.info(f"Loaded extension '{folder}.{file}'")
except Exception as e:
exception = f"{type(e).__name__}: {e}"
self.logger.error(
f"Failed to load extension {folder}.{file}\n{exception}"
)
for file in os.listdir(cogs_path):
if file.endswith(".py") and not file.startswith('__'):

View File

@@ -0,0 +1,145 @@
from discord import Interaction, Embed, Color
from discord.ui import View
from discord.app_commands import Choice, Group, autocomplete, describe
from .views.base import BaseCog
from .views.models import AsyncTagManager, Tag
from .views.tags import (
AddTagButtonModal,
TagSelectButton,
)
from .tagsend import TagSend
from .tagcreate import TagCreate
from .tagedit import TagEdit
from .tagdelete import TagDelete
class Tags(BaseCog):
def __init__(self, bot):
super().__init__(bot)
self.description = "A cog for retrieving and setting tags."
self._conn: AsyncTagManager | None = None
# Initialize command classes
self.tag_send = TagSend(self)
self.tag_create = TagCreate(self)
self.tag_edit = TagEdit(self)
self.tag_delete = TagDelete(self)
@property
def conn(self) -> AsyncTagManager:
if self._conn is None: raise ValueError("Initialized improperly!")
return self._conn
@classmethod
async def setup(cls, bot):
import os
c = await super().setup(bot)
db_path = f"{os.path.realpath(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__)))))}/database/database.db"
c._conn = await AsyncTagManager.from_file(db_path)
return c
async def cog_unload(self):
if self._conn:
await self._conn.close()
await super().cog_unload()
async def tag_completer(self, inter: Interaction, current: str):
_ = inter
if self._conn is None or inter.guild is None:
return []
return [
Choice(name=f"[G] {t.name}" if t.guild is None else t.name, value=str(t.tid))
for t in await self._conn.tags
if current.lower() in t.name.lower() and (inter.guild.id == t.guild or t.guild is None)
][:25]
async def tag_button_completer(self, inter: Interaction, current: str):
_ = inter
if self._conn is None or inter.guild is None:
return []
return [
Choice(name=f"[G] {t.name}" if t.guild is None else t.name, value=str(t.tid))
for t in await self._conn.tags
if current.lower() in t.name.lower()
and (inter.guild.id == t.guild or t.guild is None)
and len(t.buttons) > 0
][:25]
tags = Group(name="tags", description="The parent for tag operations.", guild_only=True)
urls = Group(name="urls", description="Manage url buttons for tags.", parent=tags, guild_only=True)
async def check_conn_tag(self, name: str) -> str | Tag:
if self._conn is None:
return "Error: couldn't connect to the db file to get tags!"
if not name.isnumeric():
return f"Error: Tag {name!r} was not found!"
if (tag := await self._conn.tag(tid=int(name))) is None:
return f"Error: Tag with id {name!r} was not found!"
return tag
@tags.command(description="Send contents of a tag.")
@describe(name="The name of the tag you want to send.")
@autocomplete(name=tag_completer)
async def send(self, inter: Interaction, name: str):
await self.tag_send.send(inter, name)
@tags.command(description="Create a new tag.")
async def create(self, inter: Interaction):
await self.tag_create.create(inter)
@tags.command(description="Edit a tag.")
@describe(name="The name of the tag you want to edit.")
@autocomplete(name=tag_completer)
async def edit(self, inter: Interaction, name: str):
await self.tag_edit.edit(inter, name)
@tags.command(description="Delete a tag.")
@describe(name="The name of the tag you want to delete.")
@autocomplete(name=tag_completer)
async def delete(self, inter: Interaction, name: str):
await self.tag_delete.delete(inter, name)
@urls.command(name="add", description="Add a url button to tag.")
@describe(name="The name of the tag you want to add a url button to.")
@autocomplete(name=tag_completer)
async def button_add(self, inter: Interaction, name: str):
tag = await self.check_conn_tag(name)
if isinstance(tag, str) or self._conn is None:
return await inter.response.send_message(tag, ephemeral=True)
await inter.response.send_modal(AddTagButtonModal(self, tag))
@urls.command(name="edit", description="Edit a button for a tag.")
@describe(name="The name of the tag you want to edit button from.")
@autocomplete(name=tag_button_completer)
async def button_edit(self, inter: Interaction, name: str):
tag = await self.check_conn_tag(name)
if isinstance(tag, str) or self._conn is None:
return await inter.response.send_message(tag, ephemeral=True)
try:
button_sel = TagSelectButton(self, tag)
button_view = View()
button_view.add_item(button_sel)
await inter.response.send_message(view=button_view, ephemeral=True)
except:
button_sel = TagSelectButton(self, tag, safe=True)
button_view = View()
button_view.add_item(button_sel)
await inter.response.send_message(view=button_view, ephemeral=True)
@urls.command(name="delete", description="Delete button(s) for a tag.")
@describe(name="The name of the tag you want to delete button(s) from.")
@autocomplete(name=tag_button_completer)
async def button_delete(self, inter: Interaction, name: str):
tag = await self.check_conn_tag(name)
if isinstance(tag, str) or self._conn is None:
return await inter.response.send_message(tag, ephemeral=True)
button_sel = TagSelectButton(self, tag, True)
button_view = View()
button_view.add_item(button_sel)
await inter.response.send_message(view=button_view, ephemeral=True)
async def setup(bot):
await bot.add_cog(await Tags.setup(bot))

View File

@@ -0,0 +1,16 @@
from discord import Interaction
from .views.base import BaseCog
from .views.tags import CreateTagModal
class TagCreate:
def __init__(self, cog: BaseCog):
self.cog = cog
async def create(self, inter: Interaction):
"""Create a new tag."""
if self.cog._conn is None:
await inter.response.send_message(f"Error: DB connection was None!", ephemeral=True)
return
await inter.response.send_modal(CreateTagModal(self.cog))

View File

@@ -0,0 +1,38 @@
import discord
from discord import Interaction
from .views.base import BaseCog
from .views.models import AsyncTagManager, Tag
from .views.tags import ConfirmDeleteTag
class TagDelete:
def __init__(self, cog: BaseCog):
self.cog = cog
async def check_conn_tag(self, name: str) -> str | Tag:
if self.cog._conn is None:
return "Error: couldn't connect to the db file to get tags!"
if not name.isnumeric():
return f"Error: Tag {name!r} was not found!"
if (tag := await self.cog._conn.tag(tid=int(name))) is None:
return f"Error: Tag with id {name!r} was not found!"
return tag
async def delete(self, inter: Interaction, name: str):
"""Delete a tag."""
tag = await self.check_conn_tag(name)
if isinstance(tag, str) or self.cog._conn is None:
return await inter.response.send_message(tag, ephemeral=True)
delete_tag = ConfirmDeleteTag(self.cog, tag)
embed = discord.Embed(
title="Confirm Deletion",
description=f"Are you sure you want to delete `{tag.name}`?",
color=0xFF0000
)
embed.set_author(name="Tags", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp")
await inter.response.send_message(
embed=embed,
view=delete_tag,
ephemeral=True,
)

View File

@@ -0,0 +1,36 @@
from discord import Interaction, Embed
from .views.base import BaseCog
from .views.models import AsyncTagManager, Tag
from .views.tags import EditTagPreview
class TagEdit:
def __init__(self, cog: BaseCog):
self.cog = cog
async def check_conn_tag(self, name: str) -> str | Tag:
if self.cog._conn is None:
return "Error: couldn't connect to the db file to get tags!"
if not name.isnumeric():
return f"Error: Tag {name!r} was not found!"
if (tag := await self.cog._conn.tag(tid=int(name))) is None:
return f"Error: Tag with id {name!r} was not found!"
return tag
async def edit(self, inter: Interaction, name: str):
"""Edit a tag."""
tag = await self.check_conn_tag(name)
if isinstance(tag, str) or self.cog._conn is None:
return await inter.response.send_message(tag, ephemeral=True)
embed = Embed(
title=f"Edit Tag: {tag.name}",
description=f"```\n{tag.content}\n```",
color=0x7289DA
)
embed.set_author(name="Tags", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp")
embed.set_footer(text="Click Edit to modify this tag or Close to cancel")
view = EditTagPreview(self.cog, tag)
await inter.response.send_message(embed=embed, view=view, ephemeral=True)

View File

@@ -0,0 +1,40 @@
from discord import Interaction
from .views.base import BaseCog
from .views.models import AsyncTagManager, Tag
from .views.tags import TagEmbed, TagButtonView
class TagSend:
def __init__(self, cog: BaseCog):
self.cog = cog
@property
def conn(self) -> AsyncTagManager:
return self.cog.conn
async def check_conn_tag(self, name: str) -> str | Tag:
if self.cog._conn is None:
return "Error: couldn't connect to the db file to get tags!"
if not name.isnumeric():
return f"Error: Tag {name!r} was not found!"
if (tag := await self.cog._conn.tag(tid=int(name))) is None:
return f"Error: Tag with id {name!r} was not found!"
return tag
async def send(self, inter: Interaction, name: str):
"""Send contents of a tag."""
tag = await self.check_conn_tag(name)
if isinstance(tag, str) or self.cog._conn is None:
return await inter.response.send_message(tag, ephemeral=True)
ephemeral = inter.guild is None
author = self.cog.bot.get_user(tag.author)
authname = author.name if author else str(tag.author)
await inter.response.send_message(
embeds=[TagEmbed(tag, authname)],
view=TagButtonView(tag.buttons),
ephemeral=ephemeral
)
tag.used += 1
await self.cog._conn.update(tag)
self.cog.logger.info(f"{inter.user.name!r} sent {tag.name!r}")

View File

View File

@@ -0,0 +1,15 @@
import logging
from discord.ext import commands
class BaseCog(commands.Cog):
def __init__(self, bot):
self.bot = bot
self.logger = logging.getLogger(f"discord_bot.{self.__class__.__name__}")
@classmethod
async def setup(cls, bot):
return cls(bot)
async def cog_unload(self):
pass

View File

@@ -0,0 +1,187 @@
import aiosqlite
import asyncio
from dataclasses import dataclass
from typing import List, Optional
@dataclass
class TagButton:
id: int
tag_id: int
label: str
url: str
emoji: Optional[str] = None
@dataclass
class Tag:
tid: int
name: str
content: str
author: int
guild: Optional[int]
used: int = 0
buttons: List[TagButton] = None
def __post_init__(self):
if self.buttons is None:
self.buttons = []
class AsyncTagManager:
def __init__(self, db_path: str):
self.db_path = db_path
self._connection = None
self._tags_cache = None
@classmethod
async def from_file(cls, db_path: str):
manager = cls(db_path)
await manager._connect()
return manager
async def _connect(self):
self._connection = await aiosqlite.connect(self.db_path)
await self._load_tags()
async def close(self):
if self._connection:
await self._connection.close()
self._connection = None
async def _load_tags(self):
if not self._connection:
return
cursor = await self._connection.execute("""
SELECT t.tid, t.name, t.content, t.author, t.guild, t.used,
b.id, b.label, b.url, b.emoji
FROM tags t
LEFT JOIN tag_buttons b ON t.tid = b.tag_id
ORDER BY t.tid
""")
rows = await cursor.fetchall()
await cursor.close()
tags_dict = {}
for row in rows:
tid = row[0]
if tid not in tags_dict:
tags_dict[tid] = Tag(
tid=row[0],
name=row[1],
content=row[2],
author=row[3],
guild=row[4],
used=row[5],
buttons=[]
)
if row[6] is not None:
button = TagButton(
id=row[6],
tag_id=tid,
label=row[7],
url=row[8],
emoji=row[9]
)
tags_dict[tid].buttons.append(button)
self._tags_cache = list(tags_dict.values())
@property
async def tags(self) -> List[Tag]:
if self._tags_cache is None:
await self._load_tags()
return self._tags_cache
async def tag(self, tid: int = None, name: str = None) -> Optional[Tag]:
tags = await self.tags
if tid is not None:
return next((tag for tag in tags if tag.tid == tid), None)
if name is not None:
return next((tag for tag in tags if tag.name.lower() == name.lower()), None)
return None
async def create_tag(self, name: str, content: str, author: int, guild: Optional[int] = None) -> Tag:
if not self._connection:
raise ValueError("Database not connected")
cursor = await self._connection.execute(
"INSERT INTO tags (name, content, author, guild) VALUES (?, ?, ?, ?)",
(name, content, author, guild)
)
await self._connection.commit()
tid = cursor.lastrowid
await cursor.close()
tag = Tag(tid=tid, name=name, content=content, author=author, guild=guild, used=0, buttons=[])
self._tags_cache.append(tag)
return tag
async def update(self, tag: Tag):
if not self._connection:
raise ValueError("Database not connected")
await self._connection.execute(
"UPDATE tags SET name=?, content=?, used=? WHERE tid=?",
(tag.name, tag.content, tag.used, tag.tid)
)
await self._connection.commit()
if self._tags_cache:
for i, cached_tag in enumerate(self._tags_cache):
if cached_tag.tid == tag.tid:
self._tags_cache[i] = tag
break
async def delete_tag(self, tag: Tag):
if not self._connection:
raise ValueError("Database not connected")
await self._connection.execute("DELETE FROM tags WHERE tid=?", (tag.tid,))
await self._connection.commit()
if self._tags_cache:
self._tags_cache = [t for t in self._tags_cache if t.tid != tag.tid]
async def add_button(self, tag: Tag, label: str, url: str, emoji: Optional[str] = None) -> TagButton:
if not self._connection:
raise ValueError("Database not connected")
cursor = await self._connection.execute(
"INSERT INTO tag_buttons (tag_id, label, url, emoji) VALUES (?, ?, ?, ?)",
(tag.tid, label, url, emoji)
)
await self._connection.commit()
button_id = cursor.lastrowid
await cursor.close()
button = TagButton(id=button_id, tag_id=tag.tid, label=label, url=url, emoji=emoji)
tag.buttons.append(button)
return button
async def update_button(self, button: TagButton):
if not self._connection:
raise ValueError("Database not connected")
await self._connection.execute(
"UPDATE tag_buttons SET label=?, url=?, emoji=? WHERE id=?",
(button.label, button.url, button.emoji, button.id)
)
await self._connection.commit()
async def delete_button(self, button: TagButton):
if not self._connection:
raise ValueError("Database not connected")
await self._connection.execute("DELETE FROM tag_buttons WHERE id=?", (button.id,))
await self._connection.commit()
for tag in await self.tags:
if tag.tid == button.tag_id:
tag.buttons = [b for b in tag.buttons if b.id != button.id]
break

View File

@@ -0,0 +1,398 @@
import discord
from discord import Interaction, ButtonStyle, SelectOption
from discord.ui import Modal, TextInput, View, Button, Select
from typing import TYPE_CHECKING, List
if TYPE_CHECKING:
from .models import Tag, TagButton
class TagEmbed(discord.Embed):
def __init__(self, tag: "Tag", author_name: str):
super().__init__(
description=tag.content,
color=0x7289DA,
timestamp=discord.utils.utcnow()
)
self.set_author(name="Tags", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp")
self.set_footer(text=f"Created by {author_name} | Used {tag.used} times")
class TagButtonView(View):
def __init__(self, buttons: List["TagButton"]):
super().__init__(timeout=None)
for button in buttons[:5]:
self.add_item(TagUrlButton(button))
class TagUrlButton(Button):
def __init__(self, tag_button: "TagButton"):
super().__init__(
label=tag_button.label,
url=tag_button.url,
emoji=tag_button.emoji,
style=ButtonStyle.link
)
class CreateTagModal(Modal):
def __init__(self, cog):
super().__init__(title="Create New Tag")
self.cog = cog
self.name_input = TextInput(
label="Tag Name",
placeholder="Enter the name for your tag...",
max_length=100,
required=True
)
self.content_input = TextInput(
label="Tag Content",
placeholder="Enter the content for your tag...",
style=discord.TextStyle.paragraph,
max_length=2000,
required=True
)
self.add_item(self.name_input)
self.add_item(self.content_input)
async def on_submit(self, interaction: Interaction):
name = self.name_input.value
content = self.content_input.value
author = interaction.user.id
guild = interaction.guild.id if interaction.guild else None
existing_tag = await self.cog.conn.tag(name=name)
if existing_tag and (existing_tag.guild == guild or existing_tag.guild is None):
await interaction.response.send_message(
f"A tag with the name '{name}' already exists!",
ephemeral=True
)
return
try:
tag = await self.cog.conn.create_tag(name, content, author, guild)
embed = discord.Embed(
title="Tag Created!",
description=f"Successfully created tag `{name}`!",
color=0x7289DA
)
embed.set_author(name="Tags", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp")
await interaction.response.send_message(embed=embed, ephemeral=True)
self.cog.logger.info(f"Tag '{name}' created by {interaction.user.name}")
except Exception as e:
await interaction.response.send_message(
f"An error occurred while creating the tag: {str(e)}",
ephemeral=True
)
class EditTagPreview(View):
def __init__(self, cog, tag: "Tag"):
super().__init__(timeout=300)
self.cog = cog
self.tag = tag
@discord.ui.button(label="Edit", style=ButtonStyle.primary)
async def edit_button(self, interaction: Interaction, button: Button):
if interaction.user.id != self.tag.author and not interaction.user.guild_permissions.manage_messages:
await interaction.response.send_message(
"You don't have permission to edit this tag!",
ephemeral=True
)
return
await interaction.response.send_modal(EditTagModal(self.cog, self.tag))
@discord.ui.button(label="Close", style=ButtonStyle.danger)
async def close_button(self, interaction: Interaction, button: Button):
await interaction.response.edit_message(content="Tag edit cancelled.", embed=None, view=None)
class EditTagModal(Modal):
def __init__(self, cog, tag: "Tag"):
super().__init__(title=f"Edit Tag: {tag.name}")
self.cog = cog
self.tag = tag
self.name_input = TextInput(
label="Tag Name",
default=tag.name,
max_length=100,
required=True
)
self.content_input = TextInput(
label="Tag Content",
default=tag.content,
style=discord.TextStyle.paragraph,
max_length=2000,
required=True
)
self.add_item(self.name_input)
self.add_item(self.content_input)
async def on_submit(self, interaction: Interaction):
if interaction.user.id != self.tag.author and not interaction.user.guild_permissions.manage_messages:
await interaction.response.send_message(
"You don't have permission to edit this tag!",
ephemeral=True
)
return
name = self.name_input.value
content = self.content_input.value
guild = interaction.guild.id if interaction.guild else None
existing_tag = await self.cog.conn.tag(name=name)
if existing_tag and existing_tag.tid != self.tag.tid and (existing_tag.guild == guild or existing_tag.guild is None):
await interaction.response.send_message(
f"A tag with the name '{name}' already exists!",
ephemeral=True
)
return
try:
self.tag.name = name
self.tag.content = content
await self.cog.conn.update(self.tag)
embed = discord.Embed(
title="Success!",
description=f"Successfully updated tag `{name}`!",
color=0x00FF00
)
embed.set_author(name="Tags", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp")
await interaction.response.send_message(embed=embed, ephemeral=True)
self.cog.logger.info(f"Tag '{name}' updated by {interaction.user.name}")
except Exception as e:
await interaction.response.send_message(
f"An error occurred while updating the tag: {str(e)}",
ephemeral=True
)
class ConfirmDeleteTag(View):
def __init__(self, cog, tag: "Tag"):
super().__init__(timeout=60)
self.cog = cog
self.tag = tag
@discord.ui.button(label="Yes", style=ButtonStyle.danger)
async def confirm_delete(self, interaction: Interaction, button: Button):
if interaction.user.id != self.tag.author and not interaction.user.guild_permissions.manage_messages:
await interaction.response.send_message(
"You don't have permission to delete this tag!",
ephemeral=True
)
return
try:
await self.cog.conn.delete_tag(self.tag)
await interaction.response.edit_message(
embed=discord.Embed(
title="Success!",
description=f"Tag `{self.tag.name}` has been deleted.",
color=0x00FF00
),
view=None
)
self.cog.logger.info(f"Tag '{self.tag.name}' deleted by {interaction.user.name}")
except Exception as e:
await interaction.response.send_message(
f"An error occurred while deleting the tag: {str(e)}",
ephemeral=True
)
@discord.ui.button(label="No", style=ButtonStyle.secondary)
async def cancel_delete(self, interaction: Interaction, button: Button):
await interaction.response.edit_message(
content="Tag deletion cancelled.",
view=None
)
class AddTagButtonModal(Modal):
def __init__(self, cog, tag: "Tag"):
super().__init__(title=f"Add Button to: {tag.name}")
self.cog = cog
self.tag = tag
self.label_input = TextInput(
label="Button Label",
placeholder="Enter the button label...",
max_length=80,
required=True
)
self.url_input = TextInput(
label="Button URL",
placeholder="https://example.com",
max_length=512,
required=True
)
self.emoji_input = TextInput(
label="Button Emoji (Optional)",
placeholder="Enter emoji...",
max_length=100,
required=False
)
self.add_item(self.label_input)
self.add_item(self.url_input)
self.add_item(self.emoji_input)
async def on_submit(self, interaction: Interaction):
if interaction.user.id != self.tag.author and not interaction.user.guild_permissions.manage_messages:
await interaction.response.send_message(
"You don't have permission to modify this tag!",
ephemeral=True
)
return
if len(self.tag.buttons) >= 5:
await interaction.response.send_message(
"Tags can only have up to 5 buttons!",
ephemeral=True
)
return
label = self.label_input.value
url = self.url_input.value
emoji = self.emoji_input.value if self.emoji_input.value else None
try:
await self.cog.conn.add_button(self.tag, label, url, emoji)
await interaction.response.send_message(
f"Successfully added button '{label}' to tag '{self.tag.name}'!",
ephemeral=True
)
self.cog.logger.info(f"Button '{label}' added to tag '{self.tag.name}' by {interaction.user.name}")
except Exception as e:
await interaction.response.send_message(
f"An error occurred while adding the button: {str(e)}",
ephemeral=True
)
class TagSelectButton(Select):
def __init__(self, cog, tag: "Tag", delete_mode: bool = False, safe: bool = False):
self.cog = cog
self.tag = tag
self.delete_mode = delete_mode
options = []
for i, button in enumerate(tag.buttons[:25]):
option_label = button.label
if len(option_label) > 100:
option_label = option_label[:97] + "..."
options.append(SelectOption(
label=option_label,
value=str(button.id),
description=button.url[:100] if len(button.url) <= 100 else button.url[:97] + "...",
emoji=button.emoji if not safe else None
))
if not options:
options.append(SelectOption(
label="No buttons available",
value="none",
description="This tag has no buttons"
))
super().__init__(
placeholder="Select a button to edit..." if not delete_mode else "Select a button to delete...",
options=options,
disabled=len(tag.buttons) == 0
)
async def callback(self, interaction: Interaction):
if interaction.user.id != self.tag.author and not interaction.user.guild_permissions.manage_messages:
await interaction.response.send_message(
"You don't have permission to modify this tag!",
ephemeral=True
)
return
if self.values[0] == "none":
await interaction.response.send_message(
"No buttons available to modify.",
ephemeral=True
)
return
button_id = int(self.values[0])
button = next((b for b in self.tag.buttons if b.id == button_id), None)
if not button:
await interaction.response.send_message(
"Button not found!",
ephemeral=True
)
return
if self.delete_mode:
try:
await self.cog.conn.delete_button(button)
await interaction.response.send_message(
f"Successfully deleted button '{button.label}' from tag '{self.tag.name}'!",
ephemeral=True
)
self.cog.logger.info(f"Button '{button.label}' deleted from tag '{self.tag.name}' by {interaction.user.name}")
except Exception as e:
await interaction.response.send_message(
f"An error occurred while deleting the button: {str(e)}",
ephemeral=True
)
else:
await interaction.response.send_modal(EditTagButtonModal(self.cog, self.tag, button))
class EditTagButtonModal(Modal):
def __init__(self, cog, tag: "Tag", button: "TagButton"):
super().__init__(title=f"Edit Button: {button.label}")
self.cog = cog
self.tag = tag
self.button = button
self.label_input = TextInput(
label="Button Label",
default=button.label,
max_length=80,
required=True
)
self.url_input = TextInput(
label="Button URL",
default=button.url,
max_length=512,
required=True
)
self.emoji_input = TextInput(
label="Button Emoji (Optional)",
default=button.emoji or "",
max_length=100,
required=False
)
self.add_item(self.label_input)
self.add_item(self.url_input)
self.add_item(self.emoji_input)
async def on_submit(self, interaction: Interaction):
label = self.label_input.value
url = self.url_input.value
emoji = self.emoji_input.value if self.emoji_input.value else None
try:
self.button.label = label
self.button.url = url
self.button.emoji = emoji
await self.cog.conn.update_button(self.button)
await interaction.response.send_message(
f"Successfully updated button '{label}' on tag '{self.tag.name}'!",
ephemeral=True
)
self.cog.logger.info(f"Button '{label}' updated on tag '{self.tag.name}' by {interaction.user.name}")
except Exception as e:
await interaction.response.send_message(
f"An error occurred while updating the button: {str(e)}",
ephemeral=True
)

View File

@@ -7,4 +7,23 @@ CREATE TABLE IF NOT EXISTS `warns` (
`moderator_id` varchar(20) NOT NULL,
`reason` varchar(255) NOT NULL,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS `tags` (
`tid` INTEGER PRIMARY KEY AUTOINCREMENT,
`name` varchar(255) NOT NULL,
`content` TEXT NOT NULL,
`author` varchar(20) NOT NULL,
`guild` varchar(20),
`used` INTEGER DEFAULT 0,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS `tag_buttons` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
`tag_id` INTEGER NOT NULL,
`label` varchar(80) NOT NULL,
`url` TEXT NOT NULL,
`emoji` varchar(100),
FOREIGN KEY (tag_id) REFERENCES tags(tid) ON DELETE CASCADE
);