test / bot /cogs /configuration.py
mtaaz's picture
Upload 94 files
91c7f83 verified
from __future__ import annotations
import datetime as dt
import re
import discord
from discord.ext import commands
from bot.theme import fancy_header, NEON_CYAN, NEON_PURPLE
from bot.i18n import get_cmd_desc
from bot.emojis import ui
from bot.emojis import ui
class ConfigPanelView(discord.ui.View):
def __init__(self, cog: "Configuration") -> None:
super().__init__(timeout=None)
self.cog = cog
@discord.ui.button(label="Refresh Panel", style=discord.ButtonStyle.blurple, emoji=ui("refresh"), row=3, custom_id="config_refresh")
async def refresh(self, interaction: discord.Interaction, _: discord.ui.Button) -> None:
if not interaction.guild:
await interaction.response.send_message("This button works only in servers.", ephemeral=True)
return
embed = await self.cog.build_config_embed(interaction.guild)
await interaction.response.edit_message(embed=embed, view=self)
@discord.ui.button(label="Toggle AutoMod", style=discord.ButtonStyle.danger, emoji="πŸ›‘οΈ", row=0, custom_id="config_automod")
async def toggle_automod(self, interaction: discord.Interaction, _: discord.ui.Button) -> None:
if not interaction.guild:
await interaction.response.send_message("Server only.", ephemeral=True)
return
if not interaction.user.guild_permissions.manage_guild:
await interaction.response.send_message("Manage Server permission required.", ephemeral=True)
return
row = await self.cog.bot.db.fetchone("SELECT automod_enabled FROM guild_config WHERE guild_id = ?", interaction.guild.id)
current = row[0] if row else 0
new_val = 0 if current else 1
await self.cog.bot.db.execute(
"INSERT INTO guild_config(guild_id, automod_enabled) VALUES (?, ?) ON CONFLICT(guild_id) DO UPDATE SET automod_enabled = excluded.automod_enabled",
interaction.guild.id, new_val,
)
state = "enabled" if new_val else "disabled"
await interaction.response.send_message(f"πŸ›‘οΈ AutoMod {state}.", ephemeral=True)
embed = await self.cog.build_config_embed(interaction.guild)
await interaction.message.edit(embed=embed, view=self)
@discord.ui.button(label="Toggle Daily", style=discord.ButtonStyle.success, emoji=ui("calendar"), row=0, custom_id="config_daily")
async def toggle_daily(self, interaction: discord.Interaction, _: discord.ui.Button) -> None:
if not interaction.guild:
await interaction.response.send_message("Server only.", ephemeral=True)
return
if not interaction.user.guild_permissions.manage_guild:
await interaction.response.send_message("Manage Server permission required.", ephemeral=True)
return
row = await self.cog.bot.db.fetchone("SELECT daily_enabled FROM guild_config WHERE guild_id = ?", interaction.guild.id)
current = row[0] if row else 0
new_val = 0 if current else 1
await self.cog.bot.db.execute(
"INSERT INTO guild_config(guild_id, daily_enabled) VALUES (?, ?) ON CONFLICT(guild_id) DO UPDATE SET daily_enabled = excluded.daily_enabled",
interaction.guild.id, new_val,
)
state = "enabled" if new_val else "disabled"
await interaction.response.send_message(f"πŸ“… Daily message {state}.", ephemeral=True)
embed = await self.cog.build_config_embed(interaction.guild)
await interaction.message.edit(embed=embed, view=self)
@discord.ui.button(label="Toggle Support AI", style=discord.ButtonStyle.primary, emoji=ui("support"), row=0, custom_id="config_support_ai")
async def toggle_support_ai(self, interaction: discord.Interaction, _: discord.ui.Button) -> None:
if not interaction.guild:
await interaction.response.send_message("Server only.", ephemeral=True)
return
if not interaction.user.guild_permissions.manage_guild:
await interaction.response.send_message("Manage Server permission required.", ephemeral=True)
return
row = await self.cog.bot.db.fetchone("SELECT support_ai_enabled FROM guild_config WHERE guild_id = ?", interaction.guild.id)
current = row[0] if row else 0
new_val = 0 if current else 1
await self.cog.bot.db.execute(
"INSERT INTO guild_config(guild_id, support_ai_enabled) VALUES (?, ?) ON CONFLICT(guild_id) DO UPDATE SET support_ai_enabled = excluded.support_ai_enabled",
interaction.guild.id, new_val,
)
state = "enabled" if new_val else "disabled"
await interaction.response.send_message(f"πŸ›Ÿ Support AI {state}.", ephemeral=True)
embed = await self.cog.build_config_embed(interaction.guild)
await interaction.message.edit(embed=embed, view=self)
@discord.ui.button(label="Toggle Wisdom", style=discord.ButtonStyle.secondary, emoji=ui("brain"), row=0, custom_id="config_wisdom")
async def toggle_wisdom(self, interaction: discord.Interaction, _: discord.ui.Button) -> None:
if not interaction.guild:
await interaction.response.send_message("Server only.", ephemeral=True)
return
if not interaction.user.guild_permissions.manage_guild:
await interaction.response.send_message("Manage Server permission required.", ephemeral=True)
return
row = await self.cog.bot.db.fetchone("SELECT wisdom_enabled FROM guild_config WHERE guild_id = ?", interaction.guild.id)
current = row[0] if row else 0
new_val = 0 if current else 1
await self.cog.bot.db.execute(
"INSERT INTO guild_config(guild_id, wisdom_enabled) VALUES (?, ?) ON CONFLICT(guild_id) DO UPDATE SET wisdom_enabled = excluded.wisdom_enabled",
interaction.guild.id, new_val,
)
state = "enabled" if new_val else "disabled"
await interaction.response.send_message(f"🧠 Daily wisdom {state}.", ephemeral=True)
embed = await self.cog.build_config_embed(interaction.guild)
await interaction.message.edit(embed=embed, view=self)
@discord.ui.button(label="Set Log Channel", style=discord.ButtonStyle.blurple, emoji="πŸ“", row=1, custom_id="config_log")
async def set_log(self, interaction: discord.Interaction, _: discord.ui.Button) -> None:
if not interaction.guild:
await interaction.response.send_message("Server only.", ephemeral=True)
return
if not interaction.user.guild_permissions.manage_guild:
await interaction.response.send_message("Manage Server permission required.", ephemeral=True)
return
await interaction.response.send_message(
"Select a text channel for logging:",
view=ChannelSelectModal(self.cog, interaction.guild.id, "log_channel_id", "πŸ“ Log channel set to"),
ephemeral=True,
)
@discord.ui.button(label="Set Welcome Channel", style=discord.ButtonStyle.blurple, emoji="πŸ‘‹", row=1, custom_id="config_welcome")
async def set_welcome(self, interaction: discord.Interaction, _: discord.ui.Button) -> None:
if not interaction.guild:
await interaction.response.send_message("Server only.", ephemeral=True)
return
if not interaction.user.guild_permissions.manage_guild:
await interaction.response.send_message("Manage Server permission required.", ephemeral=True)
return
await interaction.response.send_message(
"Select a text channel for welcomes:",
view=ChannelSelectModal(self.cog, interaction.guild.id, "welcome_channel_id", "πŸ‘‹ Welcome channel set to"),
ephemeral=True,
)
@discord.ui.button(label="Set Daily Channel", style=discord.ButtonStyle.blurple, emoji="πŸ“¨", row=1, custom_id="config_daily_ch")
async def set_daily_ch(self, interaction: discord.Interaction, _: discord.ui.Button) -> None:
if not interaction.guild:
await interaction.response.send_message("Server only.", ephemeral=True)
return
if not interaction.user.guild_permissions.manage_guild:
await interaction.response.send_message("Manage Server permission required.", ephemeral=True)
return
await interaction.response.send_message(
"Select a text channel for daily messages:",
view=ChannelSelectModal(self.cog, interaction.guild.id, "daily_channel_id", "πŸ“¨ Daily channel set to"),
ephemeral=True,
)
@discord.ui.button(label="Set Poll Channel", style=discord.ButtonStyle.blurple, emoji="πŸ“Š", row=1, custom_id="config_poll_ch")
async def set_poll_ch(self, interaction: discord.Interaction, _: discord.ui.Button) -> None:
if not interaction.guild:
await interaction.response.send_message("Server only.", ephemeral=True)
return
if not interaction.user.guild_permissions.manage_guild:
await interaction.response.send_message("Manage Server permission required.", ephemeral=True)
return
await interaction.response.send_message(
"Select a text channel for polls:",
view=ChannelSelectModal(self.cog, interaction.guild.id, "poll_channel_id", "πŸ“Š Poll channel set to"),
ephemeral=True,
)
@discord.ui.button(label="Set Daily Message", style=discord.ButtonStyle.gray, emoji="✏️", row=2, custom_id="config_daily_msg")
async def set_daily_msg(self, interaction: discord.Interaction, _: discord.ui.Button) -> None:
if not interaction.guild:
await interaction.response.send_message("Server only.", ephemeral=True)
return
if not interaction.user.guild_permissions.manage_guild:
await interaction.response.send_message("Manage Server permission required.", ephemeral=True)
return
await interaction.response.send_modal(DailyMessageModal(self.cog, interaction.guild.id))
@discord.ui.button(label="Test Daily", style=discord.ButtonStyle.gray, emoji="πŸ§ͺ", row=2, custom_id="config_test_daily")
async def test_daily(self, interaction: discord.Interaction, _: discord.ui.Button) -> None:
if not interaction.guild:
await interaction.response.send_message("Server only.", ephemeral=True)
return
row = await self.cog.bot.db.fetchone(
"SELECT daily_channel_id, daily_message, daily_title, daily_image_url, daily_button_label, daily_button_url FROM guild_config WHERE guild_id = ?",
interaction.guild.id,
)
if not row or not row[0]:
await interaction.response.send_message("Set a daily channel first.", ephemeral=True)
return
channel = interaction.guild.get_channel(row[0])
if not channel:
await interaction.response.send_message("Configured daily channel no longer exists.", ephemeral=True)
return
embed = self.cog._build_daily_embed(interaction.guild.name, row[2] or "", row[1] or "", row[3])
view = None
if row[4] and row[5]:
view = discord.ui.View()
view.add_item(discord.ui.Button(label=row[4], url=row[5]))
await channel.send(embed=embed, view=view)
await interaction.response.send_message(f"βœ… Sent test daily message to {channel.mention}", ephemeral=True)
class ChannelSelectModal(discord.ui.View):
def __init__(self, cog: "Configuration", guild_id: int, column: str, success_prefix: str) -> None:
super().__init__(timeout=300)
self.cog = cog
self.guild_id = guild_id
self.column = column
self.success_prefix = success_prefix
self.channel_select = discord.ui.ChannelSelect(
cls=discord.ui.ChannelSelect,
channel_types=[discord.ChannelType.text],
placeholder="Select a text channel...",
min_values=1,
max_values=1,
custom_id="channel_select_modal",
)
self.channel_select.callback = self._channel_select_callback
self.add_item(self.channel_select)
async def _channel_select_callback(self, interaction: discord.Interaction) -> None:
channel = self.channel_select.values[0]
await self.cog.bot.db.execute(
f"INSERT INTO guild_config(guild_id, {self.column}) VALUES (?, ?) ON CONFLICT(guild_id) DO UPDATE SET {self.column} = excluded.{self.column}",
self.guild_id, channel.id,
)
await interaction.response.send_message(f"{self.success_prefix} {channel.mention}", ephemeral=True)
class DailyMessageModal(discord.ui.Modal, title="✏️ Set Daily Message"):
message = discord.ui.TextInput(
label="Daily Message Text",
placeholder="Your daily message here...",
required=True,
style=discord.TextStyle.paragraph,
max_length=500,
)
def __init__(self, cog: "Configuration", guild_id: int) -> None:
super().__init__(timeout=None)
self.cog = cog
self.guild_id = guild_id
async def on_submit(self, interaction: discord.Interaction) -> None:
await self.cog.bot.db.execute(
"INSERT INTO guild_config(guild_id, daily_message) VALUES (?, ?) ON CONFLICT(guild_id) DO UPDATE SET daily_message = excluded.daily_message",
self.guild_id, str(self.message.value),
)
await interaction.response.send_message("πŸ—“οΈ Daily message text updated.", ephemeral=True)
class FreeGameSetupView(discord.ui.View):
def __init__(self, cog: "Configuration", guild_id: int, channel_id: int, role_id: int | None = None) -> None:
super().__init__(timeout=300)
self.cog = cog
self.guild_id = guild_id
self.channel_id = channel_id
self.role_id = role_id
self.mention_type = "role"
self.platforms = {"epic", "steam", "gog"}
async def _save(self, interaction: discord.Interaction) -> None:
await self.cog.bot.db.execute(
"INSERT INTO guild_config(guild_id, free_games_channel_id, free_games_role_id, free_games_platforms, free_games_mention_type) VALUES (?, ?, ?, ?, ?) "
"ON CONFLICT(guild_id) DO UPDATE SET free_games_channel_id=excluded.free_games_channel_id, free_games_role_id=excluded.free_games_role_id, free_games_platforms=excluded.free_games_platforms, free_games_mention_type=excluded.free_games_mention_type",
self.guild_id,
self.channel_id,
self.role_id,
",".join(sorted(self.platforms)),
self.mention_type,
)
@discord.ui.select(
placeholder="Choose stores for alerts",
min_values=1,
max_values=3,
options=[
discord.SelectOption(label="Epic Games", value="epic", emoji="<:animatedarrowgreen:1477261279428087979>"),
discord.SelectOption(label="Steam", value="steam", emoji="<:animatedarrowgreen:1477261279428087979>"),
discord.SelectOption(label="GOG", value="gog", emoji="<:animatedarrowgreen:1477261279428087979>"),
],
)
async def stores(self, interaction: discord.Interaction, select: discord.ui.Select) -> None:
self.platforms = set(select.values)
await self._save(interaction)
await interaction.response.send_message("<:animatedarrowgreen:1477261279428087979> Free games stores updated.", ephemeral=True)
@discord.ui.select(
placeholder="Choose ping role (optional)",
min_values=0,
max_values=1,
cls=discord.ui.RoleSelect,
)
async def role_select(self, interaction: discord.Interaction, select: discord.ui.RoleSelect) -> None:
role = select.values[0] if select.values else None
self.role_id = role.id if role else None
await self._save(interaction)
if role:
await interaction.response.send_message(f"βœ… Free games role set to {role.mention}", ephemeral=True)
else:
await interaction.response.send_message("βœ… Free games role cleared.", ephemeral=True)
@discord.ui.select(
placeholder="Mention style",
min_values=1,
max_values=1,
options=[
discord.SelectOption(label="Role mention", value="role", emoji="🏷️"),
discord.SelectOption(label="@everyone", value="everyone", emoji="πŸ“’"),
discord.SelectOption(label="@here", value="here", emoji="πŸ“£"),
discord.SelectOption(label="No mention", value="none", emoji="πŸ”•"),
],
)
async def mention_select(self, interaction: discord.Interaction, select: discord.ui.Select) -> None:
self.mention_type = (select.values[0] if select.values else "role").strip().lower()
await self._save(interaction)
await interaction.response.send_message(f"βœ… Mention type set to `{self.mention_type}`", ephemeral=True)
class Configuration(commands.Cog):
TIME_RE = re.compile(r"^(?:[01]\d|2[0-3]):[0-5]\d$")
def __init__(self, bot: commands.Bot) -> None:
self.bot = bot
async def cog_load(self) -> None:
self.bot.add_view(ConfigPanelView(self))
async def build_config_embed(self, guild: discord.Guild) -> discord.Embed:
row = await self.bot.db.fetchone(
"SELECT log_channel_id, welcome_channel_id, suggestion_channel_id, automod_enabled, daily_channel_id, "
"daily_enabled, daily_message, daily_time, daily_utc_offset, verify_channel_id, verify_role_id, "
"daily_title, daily_image_url, daily_button_label, daily_button_url, poll_channel_id, free_games_channel_id, free_games_role_id, "
"support_channel_id, support_ai_enabled, wisdom_channel_id, wisdom_enabled, game_news_channel_id, game_news_role_id "
"FROM guild_config WHERE guild_id = ?",
guild.id,
)
values = row if row else (None, None, None, 0, None, 0, "Not set", "09:00", 0, None, None, "πŸŒ… Daily Message", None, None, None, None, None, None, None, 0, None, 0, None, None)
(
log_id,
welcome_id,
suggestion_id,
automod_enabled,
daily_channel_id,
daily_enabled,
daily_message,
daily_time,
daily_utc_offset,
verify_channel_id,
verify_role_id,
daily_title,
daily_image_url,
daily_button_label,
daily_button_url,
poll_channel_id,
free_games_channel_id,
free_games_role_id,
support_channel_id,
support_ai_enabled,
wisdom_channel_id,
wisdom_enabled,
game_news_channel_id,
game_news_role_id,
) = values
def mention(channel_id: int | None) -> str:
return f"<#{channel_id}>" if channel_id else "Not set"
embed = discord.Embed(title=fancy_header(f"Settings β€’ {guild.name}"), color=NEON_CYAN)
embed.add_field(name="Log Channel", value=mention(log_id), inline=True)
embed.add_field(name="Welcome Channel", value=mention(welcome_id), inline=True)
embed.add_field(name="Suggestion Channel", value=mention(suggestion_id), inline=True)
embed.add_field(name="Verification Channel", value=mention(verify_channel_id), inline=True)
embed.add_field(name="Verification Role", value=f"<@&{verify_role_id}>" if verify_role_id else "Not set", inline=True)
embed.add_field(name="AutoMod", value="βœ… On" if automod_enabled else "❌ Off", inline=True)
embed.add_field(name="Daily Channel", value=mention(daily_channel_id), inline=True)
embed.add_field(name="Daily Enabled", value="βœ… On" if daily_enabled else "❌ Off", inline=True)
embed.add_field(name="Daily Time", value=f"`{daily_time or '09:00'}`", inline=True)
embed.add_field(name="Daily UTC Offset", value=f"`UTC{daily_utc_offset:+d}`", inline=True)
embed.add_field(name="Daily Title", value=(daily_title or "πŸŒ… Daily Message")[:128], inline=False)
embed.add_field(name="Daily Message Text", value=(daily_message or "Not set")[:1024], inline=False)
embed.add_field(name="Daily Image URL", value=daily_image_url or "Not set", inline=False)
embed.add_field(name="Daily Button", value=f"{daily_button_label or 'Not set'} | {daily_button_url or 'Not set'}", inline=False)
embed.add_field(name="Poll Channel", value=mention(poll_channel_id), inline=True)
embed.add_field(name="Free Games Channel", value=mention(free_games_channel_id), inline=True)
embed.add_field(name="Free Games Role", value=f"<@&{free_games_role_id}>" if free_games_role_id else "Not set", inline=True)
embed.add_field(name="Support AI Channel", value=mention(support_channel_id), inline=True)
embed.add_field(name="Support AI Enabled", value="βœ… On" if support_ai_enabled else "❌ Off", inline=True)
embed.add_field(name="Wisdom Channel", value=mention(wisdom_channel_id), inline=True)
embed.add_field(name="Wisdom Daily", value="βœ… On" if wisdom_enabled else "❌ Off", inline=True)
embed.add_field(name="Game News Channel", value=mention(game_news_channel_id), inline=True)
embed.add_field(name="Game News Role", value=f"<@&{game_news_role_id}>" if game_news_role_id else "Not set", inline=True)
embed.set_footer(text="Use /set commands to update β€’ Click Refresh to update panel")
return embed
def _build_daily_embed(self, guild_name: str, title: str, message_text: str, image_url: str | None) -> discord.Embed:
today = dt.datetime.utcnow().date().isoformat()
embed = discord.Embed(
title=title or "πŸŒ… Daily Message",
description=message_text or "Have a productive and positive day!",
color=discord.Color.gold(),
)
if image_url:
embed.set_image(url=image_url)
embed.set_footer(text=f"{guild_name} β€’ {today}")
return embed
@commands.hybrid_group(name="set", fallback="show")
@commands.has_permissions(manage_guild=True)
async def setgroup(self, ctx: commands.Context) -> None:
embed = await self.build_config_embed(ctx.guild)
await ctx.reply(embed=embed, view=ConfigPanelView(self))
@setgroup.command(name="log")
async def set_log(self, ctx: commands.Context, channel: discord.TextChannel) -> None:
await self.bot.db.execute(
"INSERT INTO guild_config(guild_id, log_channel_id) VALUES (?, ?) ON CONFLICT(guild_id) DO UPDATE SET log_channel_id = excluded.log_channel_id",
ctx.guild.id,
channel.id,
)
await ctx.reply(f"πŸ“ Log channel set to {channel.mention}")
@setgroup.command(name="welcome")
async def set_welcome(self, ctx: commands.Context, channel: discord.TextChannel) -> None:
await self.bot.db.execute(
"INSERT INTO guild_config(guild_id, welcome_channel_id) VALUES (?, ?) ON CONFLICT(guild_id) DO UPDATE SET welcome_channel_id = excluded.welcome_channel_id",
ctx.guild.id,
channel.id,
)
await ctx.reply(f"πŸ‘‹ Welcome channel set to {channel.mention}")
@setgroup.command(name="suggestions")
async def set_suggestion(self, ctx: commands.Context, channel: discord.TextChannel) -> None:
await self.bot.db.execute(
"INSERT INTO guild_config(guild_id, suggestion_channel_id) VALUES (?, ?) ON CONFLICT(guild_id) DO UPDATE SET suggestion_channel_id = excluded.suggestion_channel_id",
ctx.guild.id,
channel.id,
)
await ctx.reply(f"πŸ’‘ Suggestion channel set to {channel.mention}")
@setgroup.command(name="automod")
async def set_automod(self, ctx: commands.Context, enabled: bool) -> None:
await self.bot.db.execute(
"INSERT INTO guild_config(guild_id, automod_enabled) VALUES (?, ?) ON CONFLICT(guild_id) DO UPDATE SET automod_enabled = excluded.automod_enabled",
ctx.guild.id,
1 if enabled else 0,
)
await ctx.reply(f"πŸ›‘οΈ AutoMod {'enabled' if enabled else 'disabled'}")
@setgroup.command(name="dailychannel")
async def set_daily_channel(self, ctx: commands.Context, channel: discord.TextChannel) -> None:
await self.bot.db.execute(
"INSERT INTO guild_config(guild_id, daily_channel_id) VALUES (?, ?) ON CONFLICT(guild_id) DO UPDATE SET daily_channel_id = excluded.daily_channel_id",
ctx.guild.id,
channel.id,
)
await ctx.reply(f"πŸ“¨ Daily message channel set to {channel.mention}")
@setgroup.command(name="dailymessage")
async def set_daily_message(self, ctx: commands.Context, *, text: str) -> None:
await self.bot.db.execute(
"INSERT INTO guild_config(guild_id, daily_message) VALUES (?, ?) ON CONFLICT(guild_id) DO UPDATE SET daily_message = excluded.daily_message",
ctx.guild.id,
text,
)
await ctx.reply("πŸ—“οΈ Daily message text updated.")
@setgroup.command(name="dailytitle")
async def set_daily_title(self, ctx: commands.Context, *, title: str) -> None:
await self.bot.db.execute(
"INSERT INTO guild_config(guild_id, daily_title) VALUES (?, ?) ON CONFLICT(guild_id) DO UPDATE SET daily_title = excluded.daily_title",
ctx.guild.id,
title,
)
await ctx.reply("πŸ–‹οΈ Daily message title updated.")
@setgroup.command(name="dailyimage")
async def set_daily_image(self, ctx: commands.Context, image_url: str = "") -> None:
await self.bot.db.execute(
"INSERT INTO guild_config(guild_id, daily_image_url) VALUES (?, ?) ON CONFLICT(guild_id) DO UPDATE SET daily_image_url = excluded.daily_image_url",
ctx.guild.id,
image_url or None,
)
await ctx.reply("πŸ–ΌοΈ Daily image updated (empty value removes it).")
@setgroup.command(name="dailybutton")
async def set_daily_button(self, ctx: commands.Context, label: str = "", url: str = "") -> None:
await self.bot.db.execute(
"INSERT INTO guild_config(guild_id, daily_button_label, daily_button_url) VALUES (?, ?, ?) "
"ON CONFLICT(guild_id) DO UPDATE SET daily_button_label = excluded.daily_button_label, daily_button_url = excluded.daily_button_url",
ctx.guild.id,
label or None,
url or None,
)
await ctx.reply("πŸ”— Daily button settings updated.")
@setgroup.command(name="dailytime")
async def set_daily_time(self, ctx: commands.Context, hhmm: str) -> None:
hhmm = hhmm.strip()
if not self.TIME_RE.fullmatch(hhmm):
await ctx.reply("Use time in 24h format `HH:MM` (example: `18:30`).")
return
await self.bot.db.execute(
"INSERT INTO guild_config(guild_id, daily_time) VALUES (?, ?) ON CONFLICT(guild_id) DO UPDATE SET daily_time = excluded.daily_time",
ctx.guild.id,
hhmm,
)
await ctx.reply(f"⏰ Daily message time set to `{hhmm}`")
@setgroup.command(name="dailyutc")
async def set_daily_utc(self, ctx: commands.Context, offset: int) -> None:
if offset < -12 or offset > 14:
await ctx.reply("UTC offset must be between `-12` and `+14`.")
return
await self.bot.db.execute(
"INSERT INTO guild_config(guild_id, daily_utc_offset) VALUES (?, ?) ON CONFLICT(guild_id) DO UPDATE SET daily_utc_offset = excluded.daily_utc_offset",
ctx.guild.id,
offset,
)
await ctx.reply(f"🌍 Daily timezone set to `UTC{offset:+d}`")
@setgroup.command(name="dailytest")
async def set_daily_test(self, ctx: commands.Context) -> None:
row = await self.bot.db.fetchone(
"SELECT daily_channel_id, daily_message, daily_title, daily_image_url, daily_button_label, daily_button_url FROM guild_config WHERE guild_id = ?",
ctx.guild.id,
)
if not row or not row[0]:
await ctx.reply("Set a daily channel first with `/set dailychannel`.")
return
channel = ctx.guild.get_channel(row[0])
if not channel:
await ctx.reply("Configured daily channel no longer exists.")
return
embed = self._build_daily_embed(ctx.guild.name, row[2] or "", row[1] or "", row[3])
view = None
if row[4] and row[5]:
view = discord.ui.View()
view.add_item(discord.ui.Button(label=row[4], url=row[5]))
await channel.send(embed=embed, view=view)
await ctx.reply(f"βœ… Sent test daily message to {channel.mention}")
@setgroup.command(name="dailytoggle")
async def set_daily_toggle(self, ctx: commands.Context, enabled: bool) -> None:
await self.bot.db.execute(
"INSERT INTO guild_config(guild_id, daily_enabled) VALUES (?, ?) ON CONFLICT(guild_id) DO UPDATE SET daily_enabled = excluded.daily_enabled",
ctx.guild.id,
1 if enabled else 0,
)
await ctx.reply(f"πŸ“… Daily message {'enabled' if enabled else 'disabled'}.")
@setgroup.command(name="pollchannel")
async def set_poll_channel(self, ctx: commands.Context, channel: discord.TextChannel) -> None:
await self.bot.db.execute(
"INSERT INTO guild_config(guild_id, poll_channel_id) VALUES (?, ?) ON CONFLICT(guild_id) DO UPDATE SET poll_channel_id = excluded.poll_channel_id",
ctx.guild.id,
channel.id,
)
await ctx.reply(f"πŸ“Š Poll channel set to {channel.mention}")
@setgroup.command(name="freegames")
async def set_free_games_channel(self, ctx: commands.Context, channel: discord.TextChannel, role: discord.Role | None = None) -> None:
await self.bot.db.execute(
"INSERT INTO guild_config(guild_id, free_games_channel_id, free_games_role_id) VALUES (?, ?, ?) "
"ON CONFLICT(guild_id) DO UPDATE SET free_games_channel_id = excluded.free_games_channel_id, free_games_role_id = excluded.free_games_role_id",
ctx.guild.id,
channel.id,
role.id if role else None,
)
mention = f" with role {role.mention}" if role else ""
await ctx.reply(f"🎁 Free games alerts channel set to {channel.mention}{mention}")
@setgroup.command(name="gamenews")
async def set_game_news(self, ctx: commands.Context, channel: discord.TextChannel, role: discord.Role | None = None) -> None:
await self.bot.db.execute(
"INSERT INTO guild_config(guild_id, game_news_channel_id, game_news_role_id) VALUES (?, ?, ?) "
"ON CONFLICT(guild_id) DO UPDATE SET game_news_channel_id = excluded.game_news_channel_id, game_news_role_id = excluded.game_news_role_id",
ctx.guild.id,
channel.id,
role.id if role else None,
)
mention = f" with role {role.mention}" if role else ""
await ctx.reply(f"πŸ“° Game news alerts channel set to {channel.mention}{mention}")
@setgroup.command(name="supportai")
async def set_support_ai(self, ctx: commands.Context, channel: discord.TextChannel, enabled: bool = True) -> None:
await self.bot.db.execute(
"INSERT INTO guild_config(guild_id, support_channel_id, support_ai_enabled) VALUES (?, ?, ?) "
"ON CONFLICT(guild_id) DO UPDATE SET support_channel_id = excluded.support_channel_id, support_ai_enabled = excluded.support_ai_enabled",
ctx.guild.id,
channel.id,
1 if enabled else 0,
)
await ctx.reply(f"πŸ›Ÿ Support AI {'enabled' if enabled else 'disabled'} in {channel.mention}")
@setgroup.command(name="wisdom")
async def set_wisdom(self, ctx: commands.Context, channel: discord.TextChannel, enabled: bool = True) -> None:
await self.bot.db.execute(
"INSERT INTO guild_config(guild_id, wisdom_channel_id, wisdom_enabled) VALUES (?, ?, ?) "
"ON CONFLICT(guild_id) DO UPDATE SET wisdom_channel_id = excluded.wisdom_channel_id, wisdom_enabled = excluded.wisdom_enabled",
ctx.guild.id,
channel.id,
1 if enabled else 0,
)
await ctx.reply(f"🧠 Daily wisdom {'enabled' if enabled else 'disabled'} in {channel.mention}")
@setgroup.command(name="freegame")
async def set_free_game_alias(self, ctx: commands.Context, channel: discord.TextChannel, role: discord.Role | None = None) -> None:
await self.set_free_games_channel(ctx, channel, role)
@commands.hybrid_command(name="set_freegame", description=get_cmd_desc("commands.tools.set_freegame_desc"))
@commands.has_permissions(administrator=True)
async def set_freegame_panel(self, ctx: commands.Context, channel: discord.TextChannel, role: discord.Role | None = None) -> None:
await self.bot.db.execute(
"INSERT INTO guild_config(guild_id, free_games_channel_id, free_games_role_id) VALUES (?, ?, ?) "
"ON CONFLICT(guild_id) DO UPDATE SET free_games_channel_id=excluded.free_games_channel_id, free_games_role_id=excluded.free_games_role_id",
ctx.guild.id,
channel.id,
role.id if role else None,
)
view = FreeGameSetupView(self, ctx.guild.id, channel.id, role.id if role else None)
embed = discord.Embed(
title="<:animatedarrowgreen:1477261279428087979> Free Games Setup",
description=(
f"Channel: {channel.mention}\n"
f"Role ping: {role.mention if role else 'None'}\n"
"Use menu below to choose stores (Epic/Steam/GOG)."
),
color=discord.Color.green(),
)
await ctx.reply(embed=embed, view=view)
async def setup(bot: commands.Bot) -> None:
await bot.add_cog(Configuration(bot))