Files
Mace-AIO-Discord-Bot---With…/bot/cogs/commands/welcome.py
2026-07-16 11:14:48 +05:30

951 lines
46 KiB
Python

# ╔══════════════════════════════════════════════════════════════════╗
# ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
# ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║
# ║ ║
# ║ discord ── https://discord.gg/codexdev ║
# ║ youtube ── https://youtube.com/@CodeXDevs ║
# ║ github ── https://github.com/RayExo ║
# ║ ║
# ╚══════════════════════════════════════════════════════════════════╝
import discord
from utils.emoji import ICONS_CHANNEL, ICONS_PLUS, TICK, ZTICK
from discord.ext import commands
from discord.ui import View, Select, Button
import aiosqlite
import asyncio
import re
import json
from utils.Tools import *
class VariableButton(Button):
def __init__(self, author):
super().__init__(label="Variables", style=discord.ButtonStyle.secondary)
self.author = author
async def callback(self, interaction: discord.Interaction):
if interaction.user != self.author:
await interaction.response.send_message("Only the command author can use this button.", ephemeral=True)
return
variables = {
"{user}": "Mentions the user (e.g., @UserName).",
"{user_avatar}": "The user's avatar URL.",
"{user_name}": "The user's username.",
"{user_id}": "The user's ID number.",
"{user_nick}": "The user's nickname in the server.",
"{user_joindate}": "The user's join date in the server (formatted as Day, Month Day, Year).",
"{user_createdate}": "The user's account creation date (formatted as Day, Month Day, Year).",
"{server_name}": "The server's name.",
"{server_id}": "The server's ID number.",
"{server_membercount}": "The server's total member count.",
"{server_icon}": "The server's icon URL."
}
embed = discord.Embed(
title="Available Placeholders",
description="Use these placeholders in your welcome message:",
color=discord.Color(0xFF0000)
)
for var, desc in variables.items():
embed.add_field(name=var, value=desc, inline=False)
embed.set_footer(text="Add placeholders directly in the welcome message or embed fields.")
await interaction.response.send_message(embed=embed, ephemeral=True)
class Welcomer(commands.Cog):
def __init__(self, bot):
self.bot = bot
self.bot.loop.create_task(self._create_table())
async def _create_table(self):
async with aiosqlite.connect("db/welcome.db") as db:
await db.execute("""
CREATE TABLE IF NOT EXISTS welcome (
guild_id INTEGER PRIMARY KEY,
welcome_type TEXT,
welcome_message TEXT,
channel_id INTEGER,
embed_data TEXT,
auto_delete_duration INTEGER
)
""")
await db.commit()
@commands.hybrid_group(invoke_without_command=True, name="greet", help="Shows all the greet commands.")
@blacklist_check()
@ignore_check()
async def greet(self, ctx: commands.Context):
if ctx.subcommand_passed is None:
await ctx.send_help(ctx.command)
ctx.command.reset_cooldown(ctx)
@greet.command(name="setup", help="Configures a welcome message for new members joining the server. ")
@blacklist_check()
@ignore_check()
@commands.has_permissions(administrator=True)
@commands.cooldown(1, 6, commands.BucketType.user)
@commands.max_concurrency(1, per=commands.BucketType.default, wait=False)
async def greet_setup(self, ctx):
async with aiosqlite.connect("db/welcome.db") as db:
async with db.execute("SELECT * FROM welcome WHERE guild_id = ?", (ctx.guild.id,)) as cursor:
row = await cursor.fetchone()
if row:
error = discord.Embed(description=f"A welcome message has already been set in {ctx.guild.name}. Use `{ctx.prefix}greet reset` to reconfigure.", color=0xFF0000)
error.set_author(name="Error", icon_url="https://cdn.discordapp.com/emojis/1294218790082711553.png")
return await ctx.send(embed=error)
options_view = View(timeout=600)
async def option_callback(interaction: discord.Interaction, button: Button):
if interaction.user != ctx.author:
await interaction.response.send_message("You cannot interact with this setup.", ephemeral=True)
return
await interaction.response.defer()
if button.custom_id == "simple":
await interaction.message.delete()
await self.simple_setup(ctx)
elif button.custom_id == "embed":
await interaction.message.delete()
await self.embed_setup(ctx)
elif button.custom_id == "cancel":
await interaction.message.delete()
button_simple = Button(label="Simple", style=discord.ButtonStyle.success, custom_id="simple")
button_simple.callback = lambda interaction: option_callback(interaction, button_simple)
options_view.add_item(button_simple)
button_embed = Button(label="Embed", style=discord.ButtonStyle.success, custom_id="embed")
button_embed.callback = lambda interaction: option_callback(interaction, button_embed)
options_view.add_item(button_embed)
button_cancel = Button(label="Cancel", style=discord.ButtonStyle.danger, custom_id="cancel")
button_cancel.callback = lambda interaction: option_callback(interaction, button_cancel)
options_view.add_item(button_cancel)
embed = discord.Embed(
title="Welcome Message Setup",
description="Choose the type of welcome message you want to create:",
color=0xFF0000
)
embed.add_field(
name=" Simple",
value="Send a plain text welcome message. You can use placeholders to personalize it.\n\n",
inline=False
)
embed.add_field(
name=" Embed",
value="Send a welcome message in an embed format. You can customize the embed with a title, description, image, etc.",
inline=False
)
embed.set_footer(text="Click the buttons below to choose the welcome message type.", icon_url=self.bot.user.display_avatar.url)
await ctx.send(embed=embed, view=options_view)
async def simple_setup(self, ctx):
setup_view = View(timeout=600)
first = View(timeout=600)
message_content = []
placeholders = {
"user": ctx.author.mention,
"user_avatar": ctx.author.avatar.url if ctx.author.avatar else ctx.author.default_avatar.url,
"user_name": ctx.author.name,
"user_id": ctx.author.id,
"user_nick": ctx.author.display_name,
"user_joindate": ctx.author.joined_at.strftime("%a, %b %d, %Y"),
"user_createdate": ctx.author.created_at.strftime("%a, %b %d, %Y"),
"server_name": ctx.guild.name,
"server_id": ctx.guild.id,
"server_membercount": ctx.guild.member_count,
"server_icon": ctx.guild.icon.url if ctx.guild.icon else "https://cdn.discordapp.com/embed/avatars/0.png",
"timestamp": discord.utils.format_dt(ctx.message.created_at)
}
def safe_format(text):
placeholders_lower = {k.lower(): v for k, v in placeholders.items()}
def replace_var(match):
var_name = match.group(1).lower()
return str(placeholders_lower.get(var_name, f"{{{var_name}}}"))
return re.sub(r"\{(\w+)\}", replace_var, text or "")
async def update_preview(content):
preview = safe_format(content)
await preview_message.edit(content=f"**Preview:** {preview}", view=setup_view)
first.add_item(VariableButton(ctx.author))
preview_message = await ctx.send("__**Simple Message Setup**__ \nEnter your welcome message here:", view=first)
async def submit_callback(interaction):
if interaction.user != ctx.author:
await interaction.response.send_message("You cannot interact with this setup.", ephemeral=True)
return
if message_content:
await self._save_welcome_data(ctx.guild.id, "simple", message_content[0])
await interaction.response.send_message(f"{TICK}> Welcome message setup completed!")
for item in setup_view.children:
item.disabled = True
await preview_message.edit(view=setup_view)
else:
await interaction.response.send_message("No message entered to submit.", ephemeral=True)
async def edit_callback(interaction):
if interaction.user != ctx.author:
await interaction.response.send_message("You cannot interact with this setup.", ephemeral=True)
return
await interaction.response.defer()
await ctx.send("Enter the updated welcome message:")
try:
msg = await self.bot.wait_for("message", timeout=600, check=lambda m: m.author == ctx.author and m.channel == ctx.channel)
message_content.clear()
message_content.append(msg.content)
await update_preview(msg.content)
except asyncio.TimeoutError:
await ctx.send("Editing timed out.")
async def cancel_callback(interaction):
if interaction.user != ctx.author:
await interaction.response.send_message("You cannot interact with this setup.", ephemeral=True)
return
await preview_message.delete()
submit_button = Button(label="Submit", style=discord.ButtonStyle.success)
submit_button.callback = submit_callback
setup_view.add_item(submit_button)
edit_button = Button(label="Edit", style=discord.ButtonStyle.primary)
edit_button.callback = edit_callback
setup_view.add_item(edit_button)
setup_view.add_item(VariableButton(ctx.author))
cancel_button = Button(emoji=ICONS_PLUS, style=discord.ButtonStyle.secondary)
cancel_button.callback = cancel_callback
setup_view.add_item(cancel_button)
try:
msg = await self.bot.wait_for("message", timeout=600, check=lambda m: m.author == ctx.author and m.channel == ctx.channel)
message_content.append(msg.content)
await update_preview(msg.content)
except asyncio.TimeoutError:
await ctx.send("Setup timed out.")
async def _save_welcome_data(self, guild_id, welcome_type, message, embed_data=None):
async with aiosqlite.connect("db/welcome.db") as db:
await db.execute("""
INSERT OR REPLACE INTO welcome (guild_id, welcome_type, welcome_message, embed_data)
VALUES (?, ?, ?, ?)
""", (guild_id, welcome_type, message, json.dumps(embed_data) if embed_data else None))
await db.commit()
async def embed_setup(self, ctx):
setup_view = View(timeout=600)
embed_data = {
"message": None,
"title": None,
"description": None,
"color": None,
"footer_text": None,
"footer_icon": None,
"author_name": None,
"author_icon": None,
"thumbnail": None,
"image": None,
}
placeholders = {
"user": ctx.author.mention,
"user_avatar": ctx.author.avatar.url if ctx.author.avatar else ctx.author.default_avatar.url,
"user_name": ctx.author.name,
"user_id": ctx.author.id,
"user_nick": ctx.author.display_name,
"user_joindate": ctx.author.joined_at.strftime("%a, %b %d, %Y"),
"user_createdate": ctx.author.created_at.strftime("%a, %b %d, %Y"),
"server_name": ctx.guild.name,
"server_id": ctx.guild.id,
"server_membercount": ctx.guild.member_count,
"server_icon": ctx.guild.icon.url if ctx.guild.icon else "https://cdn.discordapp.com/embed/avatars/0.png",
"timestamp": discord.utils.format_dt(ctx.message.created_at)
}
def safe_format(text):
placeholders_lower = {k.lower(): v for k, v in placeholders.items()}
def replace_var(match):
var_name = match.group(1).lower()
return str(placeholders_lower.get(var_name, f"{{{var_name}}}"))
return re.sub(r"\{(\w+)\}", replace_var, text or "")
async def update_preview():
content = safe_format(embed_data["message"]) or "Message Content."
embed = discord.Embed(
title=safe_format(embed_data["title"]) or "",
description=safe_format(embed_data["description"]) or "```Customize your welcome embed, take help of variables.```",
color=discord.Color(embed_data["color"]) if embed_data["color"] else discord.Color(0x2f3136)
)
if embed_data["footer_text"]:
embed.set_footer(text=safe_format(embed_data["footer_text"]), icon_url=safe_format(embed_data["footer_icon"]) or None)
if embed_data["author_name"]:
embed.set_author(name=safe_format(embed_data["author_name"]), icon_url=safe_format(embed_data["author_icon"]) or None)
if embed_data["thumbnail"]:
embed.set_thumbnail(url=safe_format(embed_data["thumbnail"]))
if embed_data["image"]:
embed.set_image(url=safe_format(embed_data["image"]))
await preview_message.edit(content="**Embed Preview:** " + content, embed=embed, view=setup_view)
preview_message = await ctx.send("Configuring embed welcome message...")
async def handle_selection(interaction: discord.Interaction):
if interaction.user != ctx.author:
await interaction.response.send_message("You cannot interact with this setup.", ephemeral=True)
return
selected_option = select_menu.values[0]
await interaction.response.defer()
try:
if selected_option == "message":
await ctx.send("Enter the welcome message content:")
msg = await self.bot.wait_for("message", check=lambda m: m.author == ctx.author and m.channel == ctx.channel)
embed_data["message"] = msg.content
elif selected_option == "title":
await ctx.send("Enter the embed title:")
msg = await self.bot.wait_for("message", check=lambda m: m.author == ctx.author and m.channel == ctx.channel)
embed_data["title"] = msg.content
elif selected_option == "description":
await ctx.send("Enter the embed description:")
msg = await self.bot.wait_for("message", check=lambda m: m.author == ctx.author and m.channel == ctx.channel)
embed_data["description"] = msg.content
elif selected_option == "color":
await ctx.send("Enter a hex color (e.g., #3498db or 3498db):")
msg = await self.bot.wait_for("message", check=lambda m: m.author == ctx.author and m.channel == ctx.channel)
color_code = msg.content.lstrip("#")
if all(c in "0123456789abcdefABCDEF" for c in color_code) and len(color_code) in {3, 6}:
embed_data["color"] = int(color_code.lstrip("#"), 16)
else:
await ctx.send("Invalid color code. Please enter a valid hex color.")
elif selected_option in ["footer_text", "footer_icon", "author_name", "author_icon", "thumbnail", "image"]:
await ctx.send(f"Enter the URL or text for {selected_option.replace('_', ' ')}:")
msg = await self.bot.wait_for("message", check=lambda m: m.author == ctx.author and m.channel == ctx.channel)
url_or_text = msg.content
if selected_option in ["footer_icon", "author_icon", "thumbnail", "image"]:
if url_or_text.startswith("http") or url_or_text in ["{user_avatar}", "{server_icon}"]:
embed_data[selected_option] = url_or_text
else:
await ctx.send("Invalid URL. Please enter a valid image URL or a supported placeholder ({user_avatar} or {server_icon}).")
else:
embed_data[selected_option] = url_or_text
await update_preview()
await interaction.followup.send(f"{selected_option.capitalize()} updated.", ephemeral=True)
except asyncio.TimeoutError:
await ctx.send("You took too long to respond. Please try again.")
except Exception as e:
await ctx.send(f"An error occurred: {e}")
select_menu = Select(
placeholder="Choose an option to edit the Embed",
options=[
discord.SelectOption(label="Message Content", value="message"),
discord.SelectOption(label="Title", value="title"),
discord.SelectOption(label="Description", value="description"),
discord.SelectOption(label="Color", value="color"),
discord.SelectOption(label="Footer Text", value="footer_text"),
discord.SelectOption(label="Footer Icon", value="footer_icon"),
discord.SelectOption(label="Author Name", value="author_name"),
discord.SelectOption(label="Author Icon", value="author_icon"),
discord.SelectOption(label="Thumbnail", value="thumbnail"),
discord.SelectOption(label="Image", value="image")
]
)
select_menu.callback = handle_selection
setup_view.add_item(select_menu)
async def submit_callback(interaction):
if interaction.user != ctx.author:
await interaction.response.send_message("You cannot interact with this setup.", ephemeral=True)
return
if not any(embed_data[key] for key in ["title", "description"]):
await interaction.response.send_message("Please provide at least a title or an description before submitting.", ephemeral=True)
return
await self._save_welcome_data(ctx.guild.id, "embed", embed_data["message"] or "", embed_data)
await interaction.response.send_message(f"{TICK}> Embed welcome message setup completed!")
for item in setup_view.children:
item.disabled = True
await preview_message.edit(view=setup_view)
submit_button = Button(label="Submit", style=discord.ButtonStyle.success)
submit_button.callback = submit_callback
setup_view.add_item(submit_button)
setup_view.add_item(VariableButton(ctx.author))
async def cancel_callback(interaction):
if interaction.user != ctx.author:
await interaction.response.send_message("You cannot interact with this setup.", ephemeral=True)
return
await preview_message.delete()
await interaction.response.send_message("Embed setup cancelled.", ephemeral=True)
cancel_button = Button(label="Cancel", style=discord.ButtonStyle.danger)
cancel_button.callback = cancel_callback
setup_view.add_item(cancel_button)
await update_preview()
@greet.command(name="reset", aliases=["disable"], help="Resets and deletes the current welcome configuration for the server.")
@blacklist_check()
@ignore_check()
@commands.has_permissions(administrator=True)
@commands.cooldown(1, 6, commands.BucketType.user)
@commands.max_concurrency(1, per=commands.BucketType.default, wait=False)
async def greet_reset(self, ctx):
async with aiosqlite.connect("db/welcome.db") as db:
cursor = await db.execute("SELECT 1 FROM welcome WHERE guild_id = ?", (ctx.guild.id,))
is_set_up = await cursor.fetchone()
if not is_set_up:
error = discord.Embed(description=f"No welcome message has been set for {ctx.guild.name}! Please set a welcome message first using `{ctx.prefix}greet setup`", color=0xFF0000)
error.set_author(name="Greet is not configured!", icon_url="https://cdn.discordapp.com/emojis/1294218790082711553.png")
return await ctx.send(embed=error)
embed = discord.Embed(
title="Are you sure?",
description="This will remove all welcome configurations & data related to welcome messages for this server!",
color=0xFF0000
)
yes_button = Button(label="Confirm", style=discord.ButtonStyle.danger)
no_button = Button(label="Cancel", style=discord.ButtonStyle.secondary)
async def yes_button_callback(interaction):
if interaction.user != ctx.author:
await interaction.response.send_message("Only the command author can confirm this action.", ephemeral=True)
return
async with aiosqlite.connect("db/welcome.db") as db:
await db.execute("DELETE FROM welcome WHERE guild_id = ?", (ctx.guild.id,))
await db.commit()
embed.color = discord.Color(0xFF0000)
embed.title = f"{TICK}> Success"
embed.description = "Welcome message configuration has been successfully reset."
await interaction.message.edit(embed=embed, view=None)
async def no_button_callback(interaction):
if interaction.user != ctx.author:
await interaction.response.send_message("Only the command author can cancel this action.", ephemeral=True)
return
embed.color = discord.Color(0xFF0000)
embed.title = "Cancelled"
embed.description = "Greet Reset operation has been cancelled."
await interaction.message.edit(embed=embed, view=None)
yes_button.callback = yes_button_callback
no_button.callback = no_button_callback
view = View()
view.add_item(yes_button)
view.add_item(no_button)
await ctx.send(embed=embed, view=view)
@greet.command(name="channel", help="Sets the channel where welcome messages will be sent.")
@blacklist_check()
@ignore_check()
@commands.has_permissions(administrator=True)
@commands.cooldown(1, 6, commands.BucketType.user)
@commands.max_concurrency(1, per=commands.BucketType.default, wait=False)
async def greet_channel(self, ctx):
async with aiosqlite.connect("db/welcome.db") as db:
async with db.execute("SELECT welcome_type, channel_id FROM welcome WHERE guild_id = ?", (ctx.guild.id,)) as cursor:
result = await cursor.fetchone()
welcome_message = result[0] if result else None
welcome_channel = ctx.guild.get_channel(result[1]) if result and result[1] else None
if not welcome_message:
error = discord.Embed(description=f"No welcome message has been set for {ctx.guild.name}! Please set a welcome message first using `{ctx.prefix}greet setup`", color=0xFF0000)
error.set_author(name="Greet is not configured!", icon_url="https://cdn.discordapp.com/emojis/1294218790082711553.png")
await ctx.send(embed=error)
return
channels = ctx.guild.text_channels
chunk_size = 25
chunks = [channels[i:i + chunk_size] for i in range(0, len(channels), chunk_size)]
current_page = 0
def generate_view(page):
select_menu = Select(
placeholder="Select a channel for welcome messages",
options=[
discord.SelectOption(label=channel.name, emoji=ICONS_CHANNEL, value=str(channel.id))
for channel in chunks[page]
]
)
async def select_callback(interaction: discord.Interaction):
if interaction.user != ctx.author:
await interaction.response.send_message("You are not authorized to set the welcome channel.", ephemeral=True)
return
selected_channel_id = int(select_menu.values[0])
selected_channel = ctx.guild.get_channel(selected_channel_id)
async with aiosqlite.connect("db/welcome.db") as db:
await db.execute("UPDATE welcome SET channel_id = ? WHERE guild_id = ?", (selected_channel_id, ctx.guild.id))
await db.commit()
embed.description = f"Current Welcome Channel: {selected_channel.mention}"
await interaction.response.edit_message(embed=embed, view=None)
await ctx.send(f"{TICK}> Welcome channel has been set to {selected_channel.mention}")
select_menu.callback = select_callback
next_button = Button(label="Next List of Channels", style=discord.ButtonStyle.secondary, disabled=page >= len(chunks) - 1)
previous_button = Button(label="Previous", style=discord.ButtonStyle.secondary, disabled=page <= 0)
async def next_callback(interaction: discord.Interaction):
if interaction.user != ctx.author:
await interaction.response.send_message("You are not authorized to navigate these menus.", ephemeral=True)
return
nonlocal current_page
current_page += 1
await interaction.response.edit_message(embed=embed, view=generate_view(current_page))
async def previous_callback(interaction: discord.Interaction):
if interaction.user != ctx.author:
await interaction.response.send_message("You are not authorized to navigate these menus.", ephemeral=True)
return
nonlocal current_page
current_page -= 1
await interaction.response.edit_message(embed=embed, view=generate_view(current_page))
next_button.callback = next_callback
previous_button.callback = previous_callback
view = View()
view.add_item(select_menu)
view.add_item(previous_button)
view.add_item(next_button)
return view
embed = discord.Embed(
title=f"Welcome Channel for {ctx.guild.name}",
description=f"Current Welcome Channel: {welcome_channel.mention if welcome_channel else 'None'}",
color=0xFF0000
)
embed.set_footer(text="Use the dropdown menu to select a channel. Navigate pages if needed.")
await ctx.send(embed=embed, view=generate_view(current_page))
@greet.command(name="test", help="Sends a test welcome message to preview the setup.")
@blacklist_check()
@ignore_check()
@commands.has_permissions(administrator=True)
@commands.cooldown(1, 6, commands.BucketType.user)
@commands.max_concurrency(1, per=commands.BucketType.default, wait=False)
async def greet_test(self, ctx):
async with aiosqlite.connect("db/welcome.db") as db:
async with db.execute("SELECT welcome_type, welcome_message, channel_id, embed_data FROM welcome WHERE guild_id = ?", (ctx.guild.id,)) as cursor:
row = await cursor.fetchone()
if row is None:
error = discord.Embed(description=f"No welcome message has been set for {ctx.guild.name}! Please set a welcome message first using `{ctx.prefix}greet setup`", color=0xFF0000)
error.set_author(name="Greet is not configured!", icon_url="https://cdn.discordapp.com/emojis/1294218790082711553.png")
await ctx.send(embed=error)
return
welcome_type, welcome_message, channel_id, embed_data = row
welcome_channel = self.bot.get_channel(channel_id)
if not welcome_channel:
error2 = discord.Embed(description=f"Welcome channel not set or invalid. Use `{ctx.prefix}greet channel` to set one.", color=0xFF0000)
error2.set_author(name="Channel not set", icon_url="https://cdn.discordapp.com/emojis/1294218790082711553.png")
await ctx.send(embed=error2)
return
placeholders = {
"user": ctx.author.mention,
"user_avatar": ctx.author.avatar.url if ctx.author.avatar else ctx.author.default_avatar.url,
"user_name": ctx.author.name,
"user_id": ctx.author.id,
"user_nick": ctx.author.display_name,
"user_joindate": ctx.author.joined_at.strftime("%a, %b %d, %Y"),
"user_createdate": ctx.author.created_at.strftime("%a, %b %d, %Y"),
"server_name": ctx.guild.name,
"server_id": ctx.guild.id,
"server_membercount": ctx.guild.member_count,
"server_icon": ctx.guild.icon.url if ctx.guild.icon else "https://cdn.discordapp.com/embed/avatars/0.png",
"timestamp": discord.utils.format_dt(ctx.message.created_at)
}
def safe_format(text):
placeholders_lower = {k.lower(): v for k, v in placeholders.items()}
def replace_var(match):
var_name = match.group(1).lower()
return str(placeholders_lower.get(var_name, f"{{{var_name}}}"))
return re.sub(r"\{(\w+)\}", replace_var, text or "")
if welcome_type == "simple" and welcome_message:
await welcome_channel.send(safe_format(welcome_message))
elif welcome_type == "embed" and embed_data:
try:
embed_info = json.loads(embed_data)
color_value = embed_info.get("color", None)
embed_color = 0x2f3136
if color_value and isinstance(color_value, str) and color_value.startswith("#"):
embed_color = discord.Color(int(color_value.lstrip("#"), 16))
elif isinstance(color_value, int):
embed_color = discord.Color(color_value)
except (ValueError, SyntaxError, json.JSONDecodeError):
await ctx.send("Invalid embed data format. Please reconfigure.")
return
content = safe_format(embed_info.get("message", "")) or None
embed = discord.Embed(
title=safe_format(embed_info.get("title", "")),
description=safe_format(embed_info.get("description", "")),
color=embed_color
)
embed.timestamp = discord.utils.utcnow()
if embed_info.get("footer_text"):
embed.set_footer(
text=safe_format(embed_info["footer_text"]),
icon_url=safe_format(embed_info.get("footer_icon", ""))
)
if embed_info.get("author_name"):
embed.set_author(
name=safe_format(embed_info["author_name"]),
icon_url=safe_format(embed_info.get("author_icon", ""))
)
if embed_info.get("thumbnail"):
embed.set_thumbnail(url=safe_format(embed_info["thumbnail"]))
if embed_info.get("image"):
embed.set_image(url=safe_format(embed_info["image"]))
await welcome_channel.send(content=content, embed=embed)
@greet.command(name="config", help="Shows the current welcome configuration.")
@blacklist_check()
@ignore_check()
@commands.has_permissions(administrator=True)
@commands.cooldown(1, 6, commands.BucketType.user)
@commands.max_concurrency(1, per=commands.BucketType.default, wait=False)
async def greet_config(self, ctx):
async with aiosqlite.connect("db/welcome.db") as db:
async with db.execute("SELECT * FROM welcome WHERE guild_id = ?", (ctx.guild.id,)) as cursor:
row = await cursor.fetchone()
if row:
_, welcome_type, welcome_message, channel_id, embed_data, auto_delete_duration = row
response_type = "Simple" if welcome_type == "simple" else "Embed"
embed = discord.Embed(
title=f"Greet Configuration for {ctx.guild.name}",
color=0xFF0000
)
embed.add_field(name="Response Type", value=response_type, inline=False)
if welcome_type == "simple":
details = f"Message Content: {welcome_message or 'None'}"
embed.add_field(name="Details", value=details[:1024], inline=False)
else:
embed_details = json.loads(embed_data) if embed_data else {}
formatted_embed_data = "\n".join(
f"{key.replace('_', ' ').title()}: {value or 'None'}" for key, value in embed_details.items()
) or "None"
for i, chunk in enumerate([formatted_embed_data[i:i+1024] for i in range(0, len(formatted_embed_data), 1024)]):
embed.add_field(name=f"Embed Data Part {i+1}", value=chunk, inline=False)
greet_channel = self.bot.get_channel(channel_id)
channel_display = greet_channel.mention if greet_channel else "None"
auto_delete_duration = f"{auto_delete_duration} seconds" if auto_delete_duration else "None"
embed.add_field(name="Greet Channel", value=channel_display, inline=False)
embed.add_field(name="Auto Delete Duration", value=auto_delete_duration, inline=False)
await ctx.send(embed=embed)
else:
error = discord.Embed(
description=f"No welcome message has been set for {ctx.guild.name}! Please set a welcome message first using `{ctx.prefix}greet setup`",
color=0xFF0000
)
error.set_author(name="Greet is not configured!", icon_url="https://cdn.discordapp.com/emojis/1294218790082711553.png")
await ctx.send(embed=error)
@greet.command(name="autodelete", aliases=["autodel"], help="Sets the auto-delete duration for the welcome message.")
@blacklist_check()
@ignore_check()
@commands.has_permissions(administrator=True)
@commands.cooldown(1, 6, commands.BucketType.user)
@commands.max_concurrency(1, per=commands.BucketType.default, wait=False)
async def greet_autodelete(self, ctx, time: str):
if time.endswith("s"):
seconds = int(time[:-1])
if 3 <= seconds <= 300:
auto_delete_duration = seconds
else:
await ctx.send("Auto delete time should be between 3 seconds and 300 seconds.")
return
elif time.endswith("m"):
minutes = int(time[:-1])
if 1 <= minutes <= 5:
auto_delete_duration = minutes * 60
else:
await ctx.send("Auto delete time should be between 1 minute and 5 minutes.")
return
else:
await ctx.send("Invalid time format. Please use 's' for seconds and 'm' for minutes.")
return
async with aiosqlite.connect("db/welcome.db") as db:
await db.execute("""
UPDATE welcome
SET auto_delete_duration = ?
WHERE guild_id = ?
""", (auto_delete_duration, ctx.guild.id))
await db.commit()
await ctx.send(f"{ZTICK} Auto delete duration has been set to **{auto_delete_duration}** seconds.")
@greet.command(name="edit", help="Edits the current welcome message settings for the server.")
@blacklist_check()
@ignore_check()
@commands.has_permissions(administrator=True)
@commands.cooldown(1, 6, commands.BucketType.user)
@commands.max_concurrency(1, per=commands.BucketType.default, wait=False)
async def greet_edit(self, ctx):
async with aiosqlite.connect("db/welcome.db") as db:
async with db.execute("SELECT welcome_type, welcome_message, embed_data FROM welcome WHERE guild_id = ?", (ctx.guild.id,)) as cursor:
row = await cursor.fetchone()
if row is None:
error = discord.Embed(description=f"No welcome message has been set for {ctx.guild.name}! Please set a welcome message first using `{ctx.prefix}greet setup`", color=0xFF0000)
error.set_author(name="Greet is not configured!", icon_url="https://cdn.discordapp.com/emojis/1294218790082711553.png")
await ctx.send(embed=error)
return
welcome_type, welcome_message, embed_data = row
cancel_flag = False
if welcome_type == "simple":
embed = discord.Embed(
title="Edit Welcome Message",
description=f"**Response Type:** Simple\n**Message Content:** {welcome_message or 'None'}",
color=0xFF0000
)
edit_button = Button(label="Edit", style=discord.ButtonStyle.primary)
cancel_button = Button(label="Cancel", style=discord.ButtonStyle.danger)
async def cancel_button_callback(interaction):
nonlocal cancel_flag
if interaction.user != ctx.author:
await interaction.response.send_message("You are not authorized to cancel the setup.", ephemeral=True)
return
await interaction.response.send_message("Setup has been canceled.", ephemeral=True)
cancel_flag = True
view.clear_items()
await interaction.message.edit(embed=embed, view=view)
cancel_button.callback = cancel_button_callback
async def edit_button_callback(interaction):
if interaction.user != ctx.author:
await interaction.response.send_message("You are not authorized to edit the welcome message.", ephemeral=True)
return
await interaction.response.send_message("Please provide the new welcome message:", ephemeral=True)
try:
new_message = await self.bot.wait_for(
"message",
check=lambda m: m.author == ctx.author and m.channel == ctx.channel,
timeout=600
)
if cancel_flag:
await ctx.send("Setup was canceled. No changes were made.")
return
await new_message.delete()
async with aiosqlite.connect("db/welcome.db") as db:
await db.execute("UPDATE welcome SET welcome_message = ? WHERE guild_id = ?", (new_message.content, ctx.guild.id))
await db.commit()
embed.description = f"**Response Type:** Simple\n**Message Content:** {new_message.content}"
edit_button.disabled = True
cancel_button.disabled = True
await interaction.message.edit(embed=embed, view=view)
await ctx.send("Welcome message has been successfully updated.")
except asyncio.TimeoutError:
await ctx.send("You took too long to respond.")
except Exception as e:
await ctx.send(f"An error occurred: {e}")
edit_button.callback = edit_button_callback
view = View()
view.add_item(edit_button)
view.add_item(VariableButton(ctx.author))
view.add_item(cancel_button)
await ctx.send(embed=embed, view=view)
elif welcome_type == "embed":
embed_data_json = json.loads(embed_data) if embed_data else {}
formatted_embed_data = "\n".join(
f"{key.replace('_', ' ').title()}: {value or 'None'}" for key, value in embed_data_json.items()
) or "None"
embed = discord.Embed(
title="Edit Welcome Message",
description=f"**Response Type:** Embed\n**Embed Data:**\n```{formatted_embed_data}```",
color=0xFF0000
)
select_menu = Select(
placeholder="Select an embed field to edit",
options=[
discord.SelectOption(label=field.replace('_', ' ').title(), value=field)
for field in embed_data_json.keys()
]
)
cancel_button = Button(label="Cancel", style=discord.ButtonStyle.danger)
async def cancel_button_callback(interaction):
nonlocal cancel_flag
if interaction.user != ctx.author:
await interaction.response.send_message("You are not authorized to cancel the setup.", ephemeral=True)
return
await interaction.response.send_message("Setup has been canceled.", ephemeral=True)
cancel_flag = True
view.clear_items()
await interaction.message.edit(embed=embed, view=view)
cancel_button.callback = cancel_button_callback
async def select_callback(interaction):
nonlocal cancel_flag
if interaction.user != ctx.author:
await interaction.response.send_message("You are not authorized to edit this embed.", ephemeral=True)
return
selected_option = select_menu.values[0]
await interaction.response.defer()
while not cancel_flag:
try:
if selected_option == "message":
await ctx.send("Enter the welcome message content:")
msg = await self.bot.wait_for("message", check=lambda m: m.author == ctx.author and m.channel == ctx.channel)
embed_data_json["message"] = msg.content
elif selected_option == "title":
await ctx.send("Enter the embed title:")
msg = await self.bot.wait_for("message", check=lambda m: m.author == ctx.author and m.channel == ctx.channel)
embed_data_json["title"] = msg.content
elif selected_option == "description":
await ctx.send("Enter the embed description:")
msg = await self.bot.wait_for("message", check=lambda m: m.author == ctx.author and m.channel == ctx.channel)
embed_data_json["description"] = msg.content
elif selected_option == "color":
await ctx.send("Enter a hex color (e.g., #3498db or 3498db):")
msg = await self.bot.wait_for("message", check=lambda m: m.author == ctx.author and m.channel == ctx.channel)
color_code = msg.content.lstrip("#")
if all(c in "0123456789abcdefABCDEF" for c in color_code) and len(color_code) in {3, 6}:
embed_data_json["color"] = int(color_code.lstrip("#"), 16)
else:
await ctx.send("Invalid color code. Please enter a valid hex color.")
continue
elif selected_option in ["footer_text", "footer_icon", "author_name", "author_icon", "thumbnail", "image"]:
await ctx.send(f"Enter the URL or text for {selected_option.replace('_', ' ')}:")
msg = await self.bot.wait_for("message", check=lambda m: m.author == ctx.author and m.channel == ctx.channel)
url_or_text = msg.content
if selected_option in ["footer_icon", "author_icon", "thumbnail", "image"]:
if url_or_text.startswith("http") or url_or_text in ["{user_avatar}", "{server_icon}"]:
embed_data_json[selected_option] = url_or_text
else:
await ctx.send("Invalid URL. Please enter a valid image URL or a supported placeholder ({user_avatar} or {server_icon}).")
continue
else:
embed_data_json[selected_option] = url_or_text
async with aiosqlite.connect("db/welcome.db") as db:
await db.execute("UPDATE welcome SET embed_data = ? WHERE guild_id = ?", (json.dumps(embed_data_json), ctx.guild.id))
await db.commit()
embed.description = f"**Response Type:** Embed\n**Embed Data:**\n```{json.dumps(embed_data_json, indent=4)}```"
await interaction.message.edit(embed=embed, view=None)
await ctx.send("Embed data has been successfully updated.")
break
except asyncio.TimeoutError:
await ctx.send("You took too long to respond.")
break
except Exception as e:
await ctx.send(f"An error occurred: {e}")
break
select_menu.callback = select_callback
view = View()
view.add_item(select_menu)
view.add_item(VariableButton(ctx.author))
view.add_item(cancel_button)
await ctx.send(embed=embed, view=view)