Compare commits
22 Commits
roleplayga
...
b27a734e3c
| Author | SHA1 | Date | |
|---|---|---|---|
| b27a734e3c | |||
| 9ad286b671 | |||
| b186a9c119 | |||
| d3ee48112a | |||
| 48c3793768 | |||
| 141efc4253 | |||
| 61b81068ba | |||
| a0df694243 | |||
| ca7dba5af6 | |||
| d65197e552 | |||
| 0909717fb6 | |||
| 84a2b41a79 | |||
| 82e48c2383 | |||
| 2d199d9247 | |||
| f546eaa633 | |||
| e552ba7552 | |||
| e0330148c2 | |||
| 3955e61a62 | |||
| a3e210a7ce | |||
| 5fd4e08d90 | |||
| 8a7621836f | |||
| eec57c7e23 |
4
hiring/__init__.py
Normal file
4
hiring/__init__.py
Normal file
@@ -0,0 +1,4 @@
|
||||
from .hiring import setup
|
||||
|
||||
# This function is required for the cog to be loaded by Red.
|
||||
# It simply imports the setup function from the main cog file.
|
||||
253
hiring/hiring.py
Normal file
253
hiring/hiring.py
Normal file
@@ -0,0 +1,253 @@
|
||||
import discord
|
||||
from redbot.core import commands, Config
|
||||
from redbot.core.bot import Red
|
||||
from typing import Optional, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from hiring.hiring import Hiring
|
||||
|
||||
# --- Modals for the Application Forms ---
|
||||
|
||||
class StaffApplicationModal(discord.ui.Modal, title="Staff Application"):
|
||||
chosen_plan = discord.ui.TextInput(label="What plan are you interested in?")
|
||||
tox_level = discord.ui.TextInput(label="What is your toxicity level tolerance?")
|
||||
describe_server = discord.ui.TextInput(label="Please describe your server.", style=discord.TextStyle.paragraph)
|
||||
server_link = discord.ui.TextInput(label="Server Link")
|
||||
|
||||
async def on_submit(self, interaction: discord.Interaction):
|
||||
embed = discord.Embed(
|
||||
title="New Staff Application",
|
||||
description=f"Submitted by {interaction.user.mention}",
|
||||
color=0xadd8e6
|
||||
)
|
||||
embed.add_field(name="Chosen Plan", value=self.chosen_plan.value, inline=False)
|
||||
embed.add_field(name="Toxicity Level", value=self.tox_level.value, inline=False)
|
||||
embed.add_field(name="Server Description", value=self.describe_server.value, inline=False)
|
||||
embed.add_field(name="Server Link", value=self.server_link.value, inline=False)
|
||||
|
||||
await interaction.response.send_message("Your application has been submitted!", ephemeral=True)
|
||||
if isinstance(interaction.channel, discord.TextChannel):
|
||||
await interaction.channel.send(embed=embed)
|
||||
|
||||
|
||||
class PMApplicationModal(discord.ui.Modal, title="PM Application"):
|
||||
ad = discord.ui.TextInput(label="Please provide your server ad.", style=discord.TextStyle.paragraph)
|
||||
reqs = discord.ui.TextInput(label="What are your requirements?")
|
||||
tox_level = discord.ui.TextInput(label="What is your toxicity level tolerance?")
|
||||
chosen_plan = discord.ui.TextInput(label="What plan are you interested in?")
|
||||
|
||||
async def on_submit(self, interaction: discord.Interaction):
|
||||
embed = discord.Embed(
|
||||
title="New PM Application",
|
||||
description=f"Submitted by {interaction.user.mention}",
|
||||
color=0xadd8e6
|
||||
)
|
||||
embed.add_field(name="Server Ad", value=f"```\n{self.ad.value}\n```", inline=False)
|
||||
embed.add_field(name="Requirements", value=self.reqs.value, inline=False)
|
||||
embed.add_field(name="Toxicity Level", value=self.tox_level.value, inline=False)
|
||||
embed.add_field(name="Chosen Plan", value=self.chosen_plan.value, inline=False)
|
||||
await interaction.response.send_message("Your application has been submitted!", ephemeral=True)
|
||||
if isinstance(interaction.channel, discord.TextChannel):
|
||||
await interaction.channel.send(embed=embed)
|
||||
|
||||
class HPMApplicationModal(discord.ui.Modal, title="HPM Application"):
|
||||
ad = discord.ui.TextInput(label="Please provide your server ad.", style=discord.TextStyle.paragraph)
|
||||
reqs = discord.ui.TextInput(label="What are your requirements?")
|
||||
|
||||
async def on_submit(self, interaction: discord.Interaction):
|
||||
embed = discord.Embed(
|
||||
title="New HPM Application",
|
||||
description=f"Submitted by {interaction.user.mention}",
|
||||
color=0xadd8e6
|
||||
)
|
||||
embed.add_field(name="Server Ad", value=f"```\n{self.ad.value}\n```", inline=False)
|
||||
embed.add_field(name="Requirements", value=self.reqs.value, inline=False)
|
||||
await interaction.response.send_message("Your application has been submitted!", ephemeral=True)
|
||||
if isinstance(interaction.channel, discord.TextChannel):
|
||||
await interaction.channel.send(embed=embed)
|
||||
|
||||
|
||||
# --- Reusable Ticket Creation Logic ---
|
||||
async def create_ticket(interaction: discord.Interaction, role_type: str, category_id: Optional[int], modal: discord.ui.Modal):
|
||||
if not interaction.guild:
|
||||
await interaction.response.send_message("This interaction must be used in a server.", ephemeral=True)
|
||||
return
|
||||
|
||||
if not category_id:
|
||||
await interaction.response.send_message(f"The category for '{role_type}' applications has not been set by an admin.", ephemeral=True)
|
||||
return
|
||||
|
||||
category = interaction.guild.get_channel(category_id)
|
||||
if not isinstance(category, discord.CategoryChannel):
|
||||
await interaction.response.send_message(f"The category for '{role_type}' applications is invalid or has been deleted.", ephemeral=True)
|
||||
return
|
||||
|
||||
ticket_name = f"{role_type}-app-{interaction.user.name}"
|
||||
|
||||
try:
|
||||
overwrites = {
|
||||
interaction.guild.default_role: discord.PermissionOverwrite(read_messages=False),
|
||||
interaction.user: discord.PermissionOverwrite(read_messages=True, send_messages=True),
|
||||
interaction.guild.me: discord.PermissionOverwrite(read_messages=True, send_messages=True)
|
||||
}
|
||||
ticket_channel = await interaction.guild.create_text_channel(
|
||||
name=ticket_name,
|
||||
category=category,
|
||||
overwrites=overwrites
|
||||
)
|
||||
await ticket_channel.send(f"Welcome {interaction.user.mention}! Please fill out the form to complete your application.")
|
||||
await interaction.response.send_modal(modal)
|
||||
|
||||
except discord.Forbidden:
|
||||
if interaction.response.is_done():
|
||||
await interaction.followup.send("I don't have permission to create channels in that category.", ephemeral=True)
|
||||
else:
|
||||
await interaction.response.send_message("I don't have permission to create channels in that category.", ephemeral=True)
|
||||
except Exception as e:
|
||||
if interaction.response.is_done():
|
||||
await interaction.followup.send(f"An unexpected error occurred: {e}", ephemeral=True)
|
||||
else:
|
||||
await interaction.response.send_message(f"An unexpected error occurred: {e}", ephemeral=True)
|
||||
|
||||
|
||||
# --- Button Views for Commands ---
|
||||
|
||||
class HireView(discord.ui.View):
|
||||
def __init__(self, cog: "Hiring"):
|
||||
super().__init__(timeout=None)
|
||||
self.cog = cog
|
||||
|
||||
@discord.ui.button(label="Staff", style=discord.ButtonStyle.primary, custom_id="staff_apply_button")
|
||||
async def staff_button(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||
if not interaction.guild: return
|
||||
category_id = await self.cog.config.guild(interaction.guild).staff_category()
|
||||
await create_ticket(interaction, "staff", category_id, StaffApplicationModal())
|
||||
|
||||
@discord.ui.button(label="PM", style=discord.ButtonStyle.secondary, custom_id="pm_apply_button")
|
||||
async def pm_button(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||
if not interaction.guild: return
|
||||
category_id = await self.cog.config.guild(interaction.guild).pm_category()
|
||||
await create_ticket(interaction, "pm", category_id, PMApplicationModal())
|
||||
|
||||
@discord.ui.button(label="HPM", style=discord.ButtonStyle.success, custom_id="hpm_apply_button")
|
||||
async def hpm_button(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||
if not interaction.guild: return
|
||||
category_id = await self.cog.config.guild(interaction.guild).hpm_category()
|
||||
await create_ticket(interaction, "hpm", category_id, HPMApplicationModal())
|
||||
|
||||
|
||||
class WorkView(discord.ui.View):
|
||||
def __init__(self, cog: "Hiring"):
|
||||
super().__init__(timeout=None)
|
||||
self.cog = cog
|
||||
|
||||
@discord.ui.button(label="Apply for PM Position", style=discord.ButtonStyle.blurple, custom_id="work_apply_button")
|
||||
async def work_button(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||
if not interaction.guild: return
|
||||
category_id = await self.cog.config.guild(interaction.guild).pm_category()
|
||||
await create_ticket(interaction, "pm", category_id, PMApplicationModal())
|
||||
|
||||
|
||||
class Hiring(commands.Cog):
|
||||
"""
|
||||
A cog for managing staff and PM applications.
|
||||
"""
|
||||
|
||||
def __init__(self, bot: Red):
|
||||
self.bot = bot
|
||||
self.config = Config.get_conf(self, identifier=1122334455, force_registration=True)
|
||||
|
||||
default_guild = {
|
||||
"hpm_category": None,
|
||||
"pm_category": None,
|
||||
"staff_category": None,
|
||||
"work_channel": None # New setting for the /work command channel
|
||||
}
|
||||
self.config.register_guild(**default_guild)
|
||||
# We need to make sure the views are persistent so buttons work after a restart
|
||||
self.bot.add_view(HireView(self))
|
||||
self.bot.add_view(WorkView(self))
|
||||
|
||||
|
||||
# --- Commands ---
|
||||
@commands.hybrid_command() # type: ignore
|
||||
@commands.guild_only()
|
||||
@commands.admin_or_permissions(manage_guild=True)
|
||||
async def hire(self, ctx: commands.Context):
|
||||
"""Post the application message with buttons in the current channel."""
|
||||
embed = discord.Embed(
|
||||
title="Start an Application",
|
||||
description="Click a button below to open a ticket for the role you are interested in.",
|
||||
color=0xadd8e6
|
||||
)
|
||||
await ctx.send(embed=embed, view=HireView(self))
|
||||
|
||||
@commands.hybrid_command() # type: ignore
|
||||
@commands.guild_only()
|
||||
@commands.admin_or_permissions(manage_guild=True)
|
||||
async def work(self, ctx: commands.Context):
|
||||
"""Post the PM hiring message in the configured work channel."""
|
||||
if not ctx.guild:
|
||||
return
|
||||
work_channel_id = await self.config.guild(ctx.guild).work_channel()
|
||||
if not work_channel_id:
|
||||
await ctx.send("The work channel has not been set. Please use `[p]hiringset workchannel` to set it.", ephemeral=True)
|
||||
return
|
||||
|
||||
work_channel = ctx.guild.get_channel(work_channel_id)
|
||||
if not isinstance(work_channel, discord.TextChannel):
|
||||
await ctx.send("The configured work channel is invalid or has been deleted.", ephemeral=True)
|
||||
return
|
||||
|
||||
embed = discord.Embed(
|
||||
title="Now Hiring: Partnership Managers",
|
||||
description="We are for talented Partnership Managers (PMs) to join our team. If you are interested in applying, please click the button below to begin the application process.",
|
||||
color=0xadd8e6
|
||||
)
|
||||
try:
|
||||
await work_channel.send(embed=embed, view=WorkView(self))
|
||||
await ctx.send(f"Hiring message posted in {work_channel.mention}.", ephemeral=True)
|
||||
except discord.Forbidden:
|
||||
await ctx.send(f"I don't have permission to send messages in {work_channel.mention}.", ephemeral=True)
|
||||
|
||||
|
||||
# --- Settings Commands ---
|
||||
@commands.group(aliases=["hset"]) # type: ignore
|
||||
@commands.guild_only()
|
||||
@commands.admin_or_permissions(manage_guild=True)
|
||||
async def hiringset(self, ctx: commands.Context):
|
||||
"""Configure the Hiring cog settings."""
|
||||
pass
|
||||
|
||||
@hiringset.command(name="staffcategory")
|
||||
async def set_staff_category(self, ctx: commands.Context, category: discord.CategoryChannel):
|
||||
"""Set the category for Staff applications."""
|
||||
if not ctx.guild: return
|
||||
await self.config.guild(ctx.guild).staff_category.set(category.id)
|
||||
await ctx.send(f"Staff application category set to **{category.name}**.")
|
||||
|
||||
@hiringset.command(name="pmcategory")
|
||||
async def set_pm_category(self, ctx: commands.Context, category: discord.CategoryChannel):
|
||||
"""Set the category for PM applications."""
|
||||
if not ctx.guild: return
|
||||
await self.config.guild(ctx.guild).pm_category.set(category.id)
|
||||
await ctx.send(f"PM application category set to **{category.name}**.")
|
||||
|
||||
@hiringset.command(name="hpmcategory")
|
||||
async def set_hpm_category(self, ctx: commands.Context, category: discord.CategoryChannel):
|
||||
"""Set the category for HPM applications."""
|
||||
if not ctx.guild: return
|
||||
await self.config.guild(ctx.guild).hpm_category.set(category.id)
|
||||
await ctx.send(f"HPM application category set to **{category.name}**.")
|
||||
|
||||
@hiringset.command(name="workchannel")
|
||||
async def set_work_channel(self, ctx: commands.Context, channel: discord.TextChannel):
|
||||
"""Set the channel where the /work hiring message will be posted."""
|
||||
if not ctx.guild: return
|
||||
await self.config.guild(ctx.guild).work_channel.set(channel.id)
|
||||
await ctx.send(f"The work channel has been set to {channel.mention}.")
|
||||
|
||||
|
||||
async def setup(bot: Red):
|
||||
await bot.add_cog(Hiring(bot))
|
||||
|
||||
15
hiring/info.json
Normal file
15
hiring/info.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"author": [ "unstableCogs" ],
|
||||
"install_msg": "Thank you for installing the Hiring cog! Use `[p]help Hiring` for a list of commands.",
|
||||
"name": "Hiring",
|
||||
"short": "A ticket-based system for staff and PM applications.",
|
||||
"description": "Provides /hire and /work commands to manage the staff and PM hiring process through a ticket system with forms and buttons.",
|
||||
"tags": [
|
||||
"hiring",
|
||||
"tickets",
|
||||
"utility",
|
||||
"modmail"
|
||||
],
|
||||
"requirements": [],
|
||||
"end_user_data_statement": "This cog stores user IDs and the content of their applications for the duration of the hiring process."
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"author" : ["KWUK"],
|
||||
"install_msg" : "Thank you for installing my repo! If you need support, create an issue on Gitea or ping me in KWDS.",
|
||||
"install_msg" : "Thank you for installing my repo! If you need support, create an issue on Gitea or ping me in KWDS. Cogs: hiring, kbump, kofishop, modmail, mors, pp, rpg, iservice, welcomer. ",
|
||||
"name" : "unstable-cogs",
|
||||
"short" : "Cogs for Red-DiscordBot!",
|
||||
"description" : "Cogs for Red-DiscordBot!",
|
||||
|
||||
1
kofishop/__init__.py
Normal file
1
kofishop/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from .kofishop import setup
|
||||
175
kofishop/kofishop.py
Normal file
175
kofishop/kofishop.py
Normal file
@@ -0,0 +1,175 @@
|
||||
import discord
|
||||
from redbot.core import commands, Config
|
||||
from redbot.core.bot import Red
|
||||
from typing import Optional
|
||||
|
||||
# --- Modals for the Commands ---
|
||||
|
||||
class OrderModal(discord.ui.Modal, title="Commission/Shop Order"):
|
||||
def __init__(self, cog: "KofiShop"):
|
||||
super().__init__()
|
||||
self.cog = cog
|
||||
|
||||
comm_type = discord.ui.TextInput(label="What type of commission/item is this?")
|
||||
payment_status = discord.ui.TextInput(label="Is this free or paid?")
|
||||
description = discord.ui.TextInput(label="Please describe your request.", style=discord.TextStyle.paragraph)
|
||||
questions = discord.ui.TextInput(label="Any questions for the artist?", style=discord.TextStyle.paragraph, required=False)
|
||||
|
||||
async def on_submit(self, interaction: discord.Interaction):
|
||||
if not interaction.guild:
|
||||
return await interaction.response.send_message("This must be used in a server.", ephemeral=True)
|
||||
|
||||
order_channel_id = await self.cog.config.guild(interaction.guild).order_channel()
|
||||
if not order_channel_id:
|
||||
return await interaction.response.send_message("The order channel has not been set by an admin.", ephemeral=True)
|
||||
|
||||
order_channel = interaction.guild.get_channel(order_channel_id)
|
||||
if not isinstance(order_channel, discord.TextChannel):
|
||||
return await interaction.response.send_message("The configured order channel is invalid.", ephemeral=True)
|
||||
|
||||
embed = discord.Embed(
|
||||
title="New Order Placed",
|
||||
description=f"Submitted by {interaction.user.mention}",
|
||||
color=0x00ff00 # Green for new orders
|
||||
)
|
||||
embed.add_field(name="Item/Commission Type", value=self.comm_type.value, inline=False)
|
||||
embed.add_field(name="Payment Status", value=self.payment_status.value, inline=False)
|
||||
embed.add_field(name="Description", value=self.description.value, inline=False)
|
||||
if self.questions.value:
|
||||
embed.add_field(name="Questions", value=self.questions.value, inline=False)
|
||||
|
||||
try:
|
||||
await order_channel.send(embed=embed)
|
||||
await interaction.response.send_message("Your order has been successfully submitted!", ephemeral=True)
|
||||
except discord.Forbidden:
|
||||
await interaction.response.send_message("I don't have permission to send messages in the order channel.", ephemeral=True)
|
||||
|
||||
class ReviewModal(discord.ui.Modal, title="Leave a Review"):
|
||||
def __init__(self, cog: "KofiShop"):
|
||||
super().__init__()
|
||||
self.cog = cog
|
||||
|
||||
item_name = discord.ui.TextInput(label="What item/commission are you reviewing?")
|
||||
rating = discord.ui.TextInput(label="Rating (e.g., 10/10)")
|
||||
review_text = discord.ui.TextInput(label="Your Review", style=discord.TextStyle.paragraph)
|
||||
|
||||
async def on_submit(self, interaction: discord.Interaction):
|
||||
if not interaction.guild:
|
||||
return await interaction.response.send_message("This must be used in a server.", ephemeral=True)
|
||||
|
||||
review_channel_id = await self.cog.config.guild(interaction.guild).review_channel()
|
||||
if not review_channel_id:
|
||||
return await interaction.response.send_message("The review channel has not been set by an admin.", ephemeral=True)
|
||||
|
||||
review_channel = interaction.guild.get_channel(review_channel_id)
|
||||
if not isinstance(review_channel, discord.TextChannel):
|
||||
return await interaction.response.send_message("The configured review channel is invalid.", ephemeral=True)
|
||||
|
||||
embed = discord.Embed(
|
||||
title=f"New Review for: {self.item_name.value}",
|
||||
description=f"Submitted by {interaction.user.mention}",
|
||||
color=0xadd8e6 # Pastel Blue
|
||||
)
|
||||
embed.add_field(name="Rating", value=self.rating.value, inline=False)
|
||||
embed.add_field(name="Review", value=self.review_text.value, inline=False)
|
||||
|
||||
try:
|
||||
await review_channel.send(embed=embed)
|
||||
await interaction.response.send_message("Thank you! Your review has been submitted.", ephemeral=True)
|
||||
except discord.Forbidden:
|
||||
await interaction.response.send_message("I don't have permission to send messages in the review channel.", ephemeral=True)
|
||||
|
||||
|
||||
class KofiShop(commands.Cog):
|
||||
"""
|
||||
A cog to manage Ko-fi shop orders and reviews.
|
||||
"""
|
||||
|
||||
def __init__(self, bot: Red):
|
||||
self.bot = bot
|
||||
self.config = Config.get_conf(self, identifier=5566778899, force_registration=True)
|
||||
|
||||
default_guild = {
|
||||
"order_channel": None,
|
||||
"review_channel": None,
|
||||
"waitlist_channel": None
|
||||
}
|
||||
self.config.register_guild(**default_guild)
|
||||
|
||||
# --- Commands ---
|
||||
@commands.hybrid_command()
|
||||
@commands.guild_only()
|
||||
async def order(self, ctx: commands.Context):
|
||||
"""Place an order for a shop or commission item."""
|
||||
if not ctx.interaction:
|
||||
return
|
||||
# We pass `self` (the cog instance) to the modal
|
||||
await ctx.interaction.response.send_modal(OrderModal(self))
|
||||
|
||||
@commands.hybrid_command()
|
||||
@commands.guild_only()
|
||||
async def review(self, ctx: commands.Context):
|
||||
"""Leave a review for a completed shop or commission item."""
|
||||
if not ctx.interaction:
|
||||
return
|
||||
await ctx.interaction.response.send_modal(ReviewModal(self))
|
||||
|
||||
@commands.hybrid_command() # type: ignore
|
||||
@commands.guild_only()
|
||||
@commands.admin_or_permissions(manage_guild=True)
|
||||
async def waitlist(self, ctx: commands.Context, user: discord.Member, *, item: str):
|
||||
"""Add a user and their requested item to the waitlist."""
|
||||
if not ctx.guild or not isinstance(ctx.channel, discord.TextChannel):
|
||||
return await ctx.send("This command must be used in a server's text channel.", ephemeral=True)
|
||||
|
||||
waitlist_channel_id = await self.config.guild(ctx.guild).waitlist_channel()
|
||||
if not waitlist_channel_id:
|
||||
return await ctx.send("The waitlist channel has not been set by an admin.", ephemeral=True)
|
||||
|
||||
waitlist_channel = ctx.guild.get_channel(waitlist_channel_id)
|
||||
if not isinstance(waitlist_channel, discord.TextChannel):
|
||||
return await ctx.send("The configured waitlist channel is invalid.", ephemeral=True)
|
||||
|
||||
message = f"**{item}** ིྀ {user.mention} ✧ in {ctx.channel.mention}"
|
||||
|
||||
try:
|
||||
await waitlist_channel.send(message)
|
||||
await ctx.send(f"{user.mention} has been added to the waitlist for '{item}'.", ephemeral=True)
|
||||
except discord.Forbidden:
|
||||
await ctx.send(f"I don't have permission to send messages in the waitlist channel.", ephemeral=True)
|
||||
|
||||
# --- Settings Commands ---
|
||||
@commands.group(aliases=["kset"]) # type: ignore
|
||||
@commands.guild_only()
|
||||
@commands.admin_or_permissions(manage_guild=True)
|
||||
async def kofiset(self, ctx: commands.Context):
|
||||
"""
|
||||
Configure the KofiShop settings.
|
||||
"""
|
||||
pass
|
||||
|
||||
@kofiset.command(name="orderchannel")
|
||||
async def kofiset_order(self, ctx: commands.Context, channel: discord.TextChannel):
|
||||
"""Set the channel where new orders will be sent."""
|
||||
if not ctx.guild: return
|
||||
await self.config.guild(ctx.guild).order_channel.set(channel.id)
|
||||
await ctx.send(f"Order channel has been set to {channel.mention}.")
|
||||
|
||||
@kofiset.command(name="reviewchannel")
|
||||
async def kofiset_review(self, ctx: commands.Context, channel: discord.TextChannel):
|
||||
"""Set the channel where new reviews will be sent."""
|
||||
if not ctx.guild: return
|
||||
await self.config.guild(ctx.guild).review_channel.set(channel.id)
|
||||
await ctx.send(f"Review channel has been set to {channel.mention}.")
|
||||
|
||||
@kofiset.command(name="waitlistchannel")
|
||||
async def kofiset_waitlist(self, ctx: commands.Context, channel: discord.TextChannel):
|
||||
"""Set the channel where waitlist notifications will be sent."""
|
||||
if not ctx.guild: return
|
||||
await self.config.guild(ctx.guild).waitlist_channel.set(channel.id)
|
||||
await ctx.send(f"Waitlist channel has been set to {channel.mention}.")
|
||||
|
||||
|
||||
async def setup(bot: Red):
|
||||
await bot.add_cog(KofiShop(bot))
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
from .modmail import setup
|
||||
@@ -0,0 +1,218 @@
|
||||
import discord
|
||||
from redbot.core import commands, Config
|
||||
from redbot.core.bot import Red
|
||||
from typing import Optional
|
||||
|
||||
class ModMail(commands.Cog):
|
||||
"""
|
||||
A configurable, forum-based ModMail system.
|
||||
"""
|
||||
|
||||
def __init__(self, bot: Red):
|
||||
self.bot = bot
|
||||
# Initialize Red's Config system for storing settings per-server.
|
||||
self.config = Config.get_conf(self, identifier=9876543210, force_registration=True)
|
||||
|
||||
# Define the default settings for each server.
|
||||
default_guild = {
|
||||
"modmail_forum": None, # The ID of the forum channel for tickets
|
||||
"enabled": False, # Whether the system is on or off
|
||||
"active_threads": {} # A dictionary to track {user_id: thread_id}
|
||||
}
|
||||
|
||||
# Register the default settings.
|
||||
self.config.register_guild(**default_guild)
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_message(self, message: discord.Message):
|
||||
"""
|
||||
This is the core event listener. It handles both incoming DMs from users
|
||||
and outgoing replies from staff.
|
||||
"""
|
||||
# Ignore messages from bots to prevent loops.
|
||||
if message.author.bot:
|
||||
return
|
||||
|
||||
# --- Part 1: Handling DMs from Users ---
|
||||
if isinstance(message.channel, discord.DMChannel):
|
||||
await self.handle_dm(message)
|
||||
|
||||
# --- Part 2: Handling Replies from Staff ---
|
||||
elif isinstance(message.channel, discord.Thread):
|
||||
await self.handle_staff_reply(message)
|
||||
|
||||
async def handle_dm(self, message: discord.Message):
|
||||
"""Handles messages sent directly to the bot."""
|
||||
# Find a mutual server with the user.
|
||||
guild = next((g for g in self.bot.guilds if g.get_member(message.author.id)), None)
|
||||
if not guild:
|
||||
return
|
||||
|
||||
settings = await self.config.guild(guild).all()
|
||||
if not settings["enabled"] or not settings["modmail_forum"]:
|
||||
return
|
||||
|
||||
forum_channel = guild.get_channel(settings["modmail_forum"])
|
||||
if not isinstance(forum_channel, discord.ForumChannel):
|
||||
return
|
||||
|
||||
active_threads = settings["active_threads"]
|
||||
user_id_str = str(message.author.id)
|
||||
|
||||
# Check if the user already has an active thread.
|
||||
if user_id_str in active_threads:
|
||||
thread_id = active_threads[user_id_str]
|
||||
thread = guild.get_thread(thread_id)
|
||||
if thread:
|
||||
# Relay the message to the existing thread.
|
||||
await thread.send(f"**{message.author.display_name}:** {message.content}")
|
||||
await message.add_reaction("✅")
|
||||
return
|
||||
else:
|
||||
# The thread was deleted, so we clean up our records.
|
||||
async with self.config.guild(guild).active_threads() as threads:
|
||||
del threads[user_id_str]
|
||||
|
||||
# Create a new thread for the user.
|
||||
try:
|
||||
thread_name = f"ModMail | {message.author.name}"
|
||||
embed = discord.Embed(
|
||||
title=f"New ModMail Thread",
|
||||
description=f"**User:** {message.author.mention} (`{message.author.id}`)",
|
||||
color=0xadd8e6 # Light grey pastel blue
|
||||
)
|
||||
embed.add_field(name="Initial Message", value=message.content, inline=False)
|
||||
embed.set_footer(text="Staff can reply in this thread to send a message.")
|
||||
|
||||
thread_with_message = await forum_channel.create_thread(name=thread_name, embed=embed)
|
||||
thread = thread_with_message.thread
|
||||
|
||||
async with self.config.guild(guild).active_threads() as threads:
|
||||
threads[user_id_str] = thread.id
|
||||
|
||||
await message.channel.send("Your message has been received, and a ModMail ticket has been opened. Staff will be with you shortly.")
|
||||
await message.add_reaction("✅")
|
||||
except discord.Forbidden:
|
||||
print(f"ModMail: I don't have permission to create threads in {forum_channel.name}.")
|
||||
except Exception as e:
|
||||
print(f"ModMail: An unexpected error occurred: {e}")
|
||||
|
||||
async def handle_staff_reply(self, message: discord.Message):
|
||||
"""Handles messages sent by staff inside a ModMail thread."""
|
||||
guild = message.guild
|
||||
if not guild:
|
||||
return
|
||||
|
||||
active_threads = await self.config.guild(guild).active_threads()
|
||||
|
||||
# Find which user this thread belongs to by checking our records.
|
||||
thread_id_str = str(message.channel.id)
|
||||
user_id = None
|
||||
for uid, tid in active_threads.items():
|
||||
if str(tid) == thread_id_str:
|
||||
user_id = int(uid)
|
||||
break
|
||||
|
||||
if not user_id:
|
||||
# This is a regular thread, not a ModMail thread we're tracking.
|
||||
return
|
||||
|
||||
user = guild.get_member(user_id)
|
||||
if not user:
|
||||
# User might have left the server.
|
||||
await message.channel.send("⚠️ **Error:** Could not find the user. They may have left the server.")
|
||||
return
|
||||
|
||||
# Send the staff's message to the user's DMs.
|
||||
try:
|
||||
embed = discord.Embed(
|
||||
description=message.content,
|
||||
color=0xadd8e6 # Light grey pastel blue
|
||||
)
|
||||
embed.set_author(name="Staff Response") # Anonymize the staff member
|
||||
|
||||
await user.send(embed=embed)
|
||||
await message.add_reaction("📨") # Add a mail icon to show it was sent
|
||||
except discord.Forbidden:
|
||||
await message.channel.send("⚠️ **Error:** I could not send a DM to this user. They may have DMs disabled.")
|
||||
except Exception as e:
|
||||
await message.channel.send(f"⚠️ **Error:** An unexpected error occurred: {e}")
|
||||
|
||||
|
||||
# --- Settings and Management Commands ---
|
||||
@commands.group(aliases=["mmset"]) # type: ignore
|
||||
@commands.guild_only()
|
||||
@commands.admin_or_permissions(manage_guild=True)
|
||||
async def modmailset(self, ctx: commands.Context):
|
||||
"""
|
||||
Configure the ModMail settings for this server.
|
||||
"""
|
||||
pass
|
||||
|
||||
@modmailset.command(name="forum")
|
||||
async def modmailset_forum(self, ctx: commands.Context, channel: discord.ForumChannel):
|
||||
"""Set the forum channel where ModMail tickets will be created."""
|
||||
if not ctx.guild:
|
||||
return
|
||||
await self.config.guild(ctx.guild).modmail_forum.set(channel.id)
|
||||
await ctx.send(f"The ModMail forum has been set to {channel.mention}.")
|
||||
|
||||
@modmailset.command(name="toggle")
|
||||
async def modmailset_toggle(self, ctx: commands.Context):
|
||||
"""Enable or disable the ModMail system on this server."""
|
||||
if not ctx.guild:
|
||||
return
|
||||
current_status = await self.config.guild(ctx.guild).enabled()
|
||||
new_status = not current_status
|
||||
await self.config.guild(ctx.guild).enabled.set(new_status)
|
||||
status_text = "enabled" if new_status else "disabled"
|
||||
await ctx.send(f"The ModMail system has been {status_text}.")
|
||||
|
||||
@modmailset.command(name="close")
|
||||
async def modmailset_close(self, ctx: commands.Context, *, reason: Optional[str] = "No reason provided."):
|
||||
"""
|
||||
Close the current ModMail thread.
|
||||
|
||||
You must run this command inside the thread you wish to close.
|
||||
"""
|
||||
if not ctx.guild or not isinstance(ctx.channel, discord.Thread):
|
||||
await ctx.send("This command can only be run inside a ModMail thread.")
|
||||
return
|
||||
|
||||
active_threads = await self.config.guild(ctx.guild).active_threads()
|
||||
thread_id_str = str(ctx.channel.id)
|
||||
user_id = None
|
||||
for uid, tid in active_threads.items():
|
||||
if str(tid) == thread_id_str:
|
||||
user_id = int(uid)
|
||||
break
|
||||
|
||||
if not user_id:
|
||||
await ctx.send("This does not appear to be an active ModMail thread.")
|
||||
return
|
||||
|
||||
# Clean up our records.
|
||||
async with self.config.guild(ctx.guild).active_threads() as threads:
|
||||
del threads[str(user_id)]
|
||||
|
||||
# Notify the user.
|
||||
user = self.bot.get_user(user_id)
|
||||
if user:
|
||||
try:
|
||||
embed = discord.Embed(
|
||||
title="ModMail Ticket Closed",
|
||||
description=f"Your ticket has been closed by staff.\n\n**Reason:** {reason}",
|
||||
color=0xadd8e6
|
||||
)
|
||||
await user.send(embed=embed)
|
||||
except discord.Forbidden:
|
||||
pass # Can't notify user if DMs are closed
|
||||
|
||||
# Archive the thread.
|
||||
await ctx.send(f"Ticket closed by {ctx.author.mention}. Archiving thread...")
|
||||
await ctx.channel.edit(archived=True, locked=True)
|
||||
|
||||
# This required function allows Red to load the cog.
|
||||
async def setup(bot: Red):
|
||||
await bot.add_cog(ModMail(bot))
|
||||
|
||||
|
||||
15
servicereview/info.json
Normal file
15
servicereview/info.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"author": [ "unstableCogs" ],
|
||||
"install_msg": "Thank you for installing the Service Review cog!",
|
||||
"name": "ServiceReview",
|
||||
"short": "A command for users to leave a service review.",
|
||||
"description": "Allows users to submit a service review at any time, independently of any ticket system. Submissions are sent to a designated channel for staff.",
|
||||
"tags": [
|
||||
"review",
|
||||
"service",
|
||||
"feedback",
|
||||
"utility"
|
||||
],
|
||||
"requirements": [ "rich" ],
|
||||
"end_user_data_statement": "This cog persistently stores the user's ID and the content of their submitted review for record-keeping purposes."
|
||||
}
|
||||
0
servicereview/iservice.py
Normal file
0
servicereview/iservice.py
Normal file
4
translator/__init__.py
Normal file
4
translator/__init__.py
Normal file
@@ -0,0 +1,4 @@
|
||||
from .translator import Translator
|
||||
|
||||
async def setup(bot):
|
||||
await bot.add_cog(Translator(bot))
|
||||
17
translator/info.json
Normal file
17
translator/info.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"author": [
|
||||
"unstableCogs"
|
||||
],
|
||||
"install_msg": "Thank you for installing the Translator cog. Use the `/translate` command to get started.",
|
||||
"name": "Translator",
|
||||
"short": "Translates text into various fantasy and fun languages.",
|
||||
"description": "A feature-rich translator cog ported from a web application. Supports numerous languages from Common to Valspiren, Sinary, and more. Includes a command to list all available languages.",
|
||||
"tags": [
|
||||
"translate",
|
||||
"fun",
|
||||
"roleplay",
|
||||
"language"
|
||||
],
|
||||
"requirements": [],
|
||||
"end_user_data_statement": "This cog does not store any end user data."
|
||||
}
|
||||
162
translator/translator.py
Normal file
162
translator/translator.py
Normal file
@@ -0,0 +1,162 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import discord
|
||||
import re
|
||||
from redbot.core import commands, app_commands
|
||||
|
||||
# --- Translation Maps (Ported from JavaScript) ---
|
||||
VALSPIREN_MAP = {'a':'ak','b':'ba','c':'ce','d':'di','e':'ek','f':'fo','g':'gu','h':'ha','i':'ik','j':'je','k':'ki','l':'lo','m':'mu','n':'na','o':'ok','p':'pe','q':'qi','r':'ro','s':'su','t':'ta','u':'uk','v':'ve','w':'wi','x':'xo','y':'yk','z':'zu'}
|
||||
KITSUNE_MAP = {'a':'ka','b':'be','c':'chi','d':'de','e':'e','f':'fu','g':'ga','h':'hi','i':'i','j':'ji','k':'ki','l':'ru','m':'ma','n':'na','o':'o','p':'pe','q':'kyu','r':'re','s':'sa','t':'to','u':'u','v':'ve','w':'wa','x':'za','y':'ya','z':'ze'}
|
||||
ELVISH_MAP = {'a':'ael','b':'\'eth','c':'cal','d':'dor','e':'elen','f':'fae','g':'\'gan','h':'hîr','i':'ia','j':'yel','k':'\'ken','l':'lael','m':'mel','n':'nîn','o':'oia','p':'\'pes','q':'qen','r':'rae','s':'sil','t':'tâ','u':'ui','v':'vae','w':'win','x':'\'xal','y':'yl','z':'zîr'}
|
||||
DWARVISH_MAP = {'a':'az','b':'bar','c':'krag','d':'dur','e':'ek','f':'fol','g':'grum','h':'hur','i':'in','j':'jor','k':'kaz','l':'lur','m':'mor','n':'nur','o':'ok','p':'por','q':'qur','r':'ruk','s':'son','t':'thor','u':'um','v':'val','w':'wor','x':'xor','z':'zul'}
|
||||
ORCISH_MAP = {'a':'agh','b':'bug','c':'karg','d':'dur','e':'egh','f':'fug','g':'grol','h':'hosh','i':'izg','j':'jug','k':'krunk','l':'lug','m':'mog','n':'nog','o':'ogg','p':'pug','q':'qug','r':'ruk','s':'snaga','t':'tusk','u':'uruk','v':'vug','w':'warg','x':'xug','y':'yag','z':'zug'}
|
||||
GOBLIN_MAP = {'a':'az','b':'bik','c':'clik','d':'dik','e':'ek','f':'fiz','g':'gib','h':'hik','i':'ik','j':'jik','k':'krik','l':'lik','m':'mik','n':'nik','o':'ok','p':'pik','q':'qik','r':'rik','s':'snik','t':'tik','u':'uk','v':'vik','w':'wik','x':'xik','y':'yik','z':'zik'}
|
||||
DRACONIC_MAP = {'a':'ax','b':'baxis','c':'caex','d':'drak','e':'ess','f':'faex','g':'gix','h':'heth','i':'ir','j':'jyss','k':'kex','l':'lix','m':'maex','n':'nex','o':'oth','p':'pex','q':'qexis','r':'rax','s':'syth','t':'thrax','u':'ur','v':'vyx','w':'wess','x':'xis','y':'yth','z':'zix'}
|
||||
FELINE_MAP = {'a':'meow','b':'brrt','c':'chrr','d':'drrt','e':'eek','f':'frrt','g':'grrowl','h':'hiss','i':'mii','j':'jrr','k':'krr','l':'lrr','m':'mrow','n':'nyah','o':'oww','p':'purr','q':'qrr','r':'rrr','s':'sss','t':'trill','u':'urr','v':'vrr','w':'wrr','x':'xrr','y':'yowl','z':'zzz'}
|
||||
AQUAN_MAP = {'a':'aqua','b':'blub','c':'\'cress','d':'drop','e':'eelee','f':'flow','g':'glur','h':'hydro','i':'ishi','j':'\'jyr','k':'\'kyr','l':'luu','m':'\'myr','n':'\'nyr','o':'oro','p':'ploop','q':'\'qyr','r':'\'ryp','s':'sh\'l','t':'tide','u':'\'urn','v':'\'vyr','w':'wash','x':'\'xyr','y':'\'yyr','z':'\'zyr'}
|
||||
CELESTIAL_MAP = {'a':'\'ana','b':'\'bara','c':'\'cera','d':'\'dona','e':'\'elara','f':'\'fana','g':'\'gala','h':'\'hylia','i':'\'iana','j':'\'jana','k':'\'kana','l':'\'lora','m':'\'mara','n':'\'nara','o':'\'ora','p':'\'pera','q':'\'qana','r':'\'ria','s':'\'sera','t':'\'tara','u':'\'ura','v':'\'vara','w':'\'wana','x':'\'xara','y':'\'yana','z':'\'zara'}
|
||||
INFERNAL_MAP = {'a':'az\'','b':'\'baal','c':'\'krez','d':'\'drak','e':'ez\'','f':'\'fel','g':'\'gor','h':'\'hath','i':'iz\'','j':'\'jaz','k':'\'kraz','l':'\'laz','m':'\'mor','n':'\'naz','o':'oz\'','p':'\'paz','q':'\'qaz','r':'\'raz','s':'\'saz','t':'\'taz','u':'uz\'','v':'\'vaz','w':'\'waz','x':'\'xaz','y':'\'yaz','z':'\'zaz'}
|
||||
SYLVAN_MAP = {'a':'ani','b':'bri','c':'cae','d':'dae','e':'eni','f':'fae','g':'gra','h':'hae','i':'ia','j':'jae','k':'kae','l':'lor','m':'mae','n':'nem','o':'olo','p':'pae','q':'qae','r':'rae','s':'sae','t':'tae','u':'uni','v':'vae','w':'wae','x':'xae','y':'yae','z':'zae'}
|
||||
GNOMISH_MAP = {'a':'akk','b':'bink','c':'clank','d':'dink','e':'enk','f':'fizz','g':'giz','h':'hink','i':'ink','j':'jink','k':'kink','l':'link','m':'mink','n':'nink','o':'onk','p':'sprok','q':'qink','r':'rink','s':'sprock','t':'tink','u':'unk','v':'vink','w':'whirr','x':'xink','y':'yink','z':'zink'}
|
||||
SINARY_MAP = {'a':'a!','b':'7b','c':'c#','d':'d4','e':'3e','f':'f^','g':'g&','h':'h8','i':'(i','j':'j0','k':'_k','l':'l2','m':'=m','n':'n+','o':'5o','p':'-p','q':'q{','r':'}r','s':'[s','t':'t]','u':'|u','v':':v','w':'"w','x':'x<','y':'>y','z':'?z'}
|
||||
SUCCUBUS_MAP = {'a':'ah\'','b':'\'bel','c':'\'chae','d':'\'des','e':'\'esh','f':'\'fey','g':'\'gis','h':'hah\'','i':'\'ish','j':'\'jo','k':'\'ka','l':'\'lis','m':'\'mah','n':'\'nah','o':'oh\'','p':'\'pah','q':'\'qia','r':'\'rah','s':'\'sha','t':'\'thae','u':'uh\'','v':'\'vi','w':'\'wah','x':'\'xi','y':'\'yah','z':'\'zah'}
|
||||
SCORPION_MAP = {'a':'sk\'','b':'t\'k','c':'k\'ss','d':'d\'th','e':'e\'sk','f':'f\'t','g':'g\'th','h':'h\'k','i':'i\'s','j':'j\'t','k':'k\'t','l':'l\'k','m':'m\'k','n':'n\'t','o':'o\'s','p':'p\'k','q':'q\'t','r':'r\'k','s':'s\'k','t':'t\'s','u':'u\'s','v':'v\'t','w':'w\'k','x':'x\'s','y':'y\'k','z':'z\'t'}
|
||||
ABYSSAL_MAP = {'a':'azg','b':'braz','c':'kraz','d':'dorg','e':'ezg','f':'fraz','g':'gor','h':'hath','i':'ix','j':'jraz','k':'kral','l':'laz','m':'maz','n':'naz','o':'oz','p':'praz','q':'qor','r':'raz','s':'saz','t':'taz','u':'uzg','v':'vraz','w':'waz','x':'xul','y':'yaz','z':'zaz'}
|
||||
SPIRITUAL_MAP = {'a':'\'aura','b':'\'breth','c':'\'ciel','d':'\'dion','e':'\'ethys','f':'\'fey','g':'\'glyn','h':'\'hymn','i':'\'ia','j':'\'jora','k':'\'kye','l':'\'lume','m':'\'mana','n':'\'nima','o':'\'omni','p':'\'pria','q':'\'qia','r':'\'reth','s':'\'seren','t':'\'thyme','u':'\'umbra','v':'\'vym','w':'\'wisp','x':'\'xia','y':'\'yara','z':'\'zion'}
|
||||
OGRISH_MAP = {'a':'ug','b':'blud','c':'crag','d':'dug','e':'eeg','f':'fug','g':'gron','h':'hug','i':'ig','j':'jug','k':'krug','l':'lug','m':'mush','n':'nug','o':'og','p':'pug','q':'qug','r':'rug','s':'slog','t':'thok','u':'urk','v':'vog','w':'wug','x':'xug','y':'yug','z':'zug'}
|
||||
AVIAN_MAP = {'a':'\'aara','b':'\'bree','c':'chir\'','d':'\'dree','e':'eek','f':'\'flutter','g':'gree\'','h':'hrooa','i':'ii\'','j':'\'jakk','k':'kree\'','l':'\'liri','m':'\'meeka','n':'\'neer','o':'\'oroo','p':'pip\'','q':'\'qree','r':'\'reea','s':'\'skraw','t':'tweet\'','u':'\'urr','v':'\'vree','w':'\'warble','x':'\'xee','y':'\'yari','z':'\'zeer'}
|
||||
DEVILISH_MAP = {'a':'\'ayl','b':'\'baal','c':'\'cress','d':'\'drev','e':'\'eyl','f':'\'fane','g':'\'gyl','h':'hysh\'','i':'\'iyl','j':'\'jex','k':'\'krys','l':'\'lyl','m':'\'mal','n':'\'nyl','o':'\'oyl','p':'\'prax','q':'\'qyl','r':'\'ryl','s':'\'shayd','t':'\'trys','u':'\'uyl','v':'\'vyl','w':'\'wryl','x':'\'xyl','y':'\'yyl','z':'\'zyll'}
|
||||
HERBILORE_MAP = {'a':'aloe','b':'bark','c':'clover','d':'dand','e':'elder','f':'fern','g':'groot','h':'herb','i':'ivy','j':'juni','k':'kelp','l':'leaf','m':'moss','n':'nettle','o':'oak','p':'petal','q':'quin','r':'root','s':'sprout','t':'thyme','u':'ursi','v':'vine','w':'willow','x':'xylem','y':'yarrow','z':'zinni'}
|
||||
FIENDISH_MAP = {'a':'az\'ael','b':'ba\'al','c':'cre\'z','d':'dre\'th','e':'esh\'','f':'fiir\'','g':'gre\'th','h':'ha\'el','i':'i\'z','j':'je\'th','k':'krez\'','l':'le\'th','m':'morn\'','n':'ne\'th','o':'o\'z','p':'pre\'th','q':'qe\'th','r':'re\'th','s':'se\'th','t':'te\'th','u':'u\'z','v':'ve\'th','w':'we\'th','x':'xith\'','y':'ye\'th','z':'zael\''}
|
||||
ELEMENTAL_MAP = {'a':'aer','b':'breeze','c':'cinder','d':'dust','e':'ember','f':'flow','g':'gust','h':'hail','i':'ignis','j':'jet','k':'kinetic','l':'lava','m':'mist','n':'nova','o':'ozone','p':'pyre','q':'quake','r':'rain','s':'stone','t':'terra','u':'umbra','v':'vapor','w':'wave','x':'xenon','y':'yon','z':'zephyr'}
|
||||
AQUATIC_MAP = {'a':'abyss','b':'brine','c':'coral','d':'depth','e':'eel','f':'fin','g':'gurgle','h':'hydro','i':'ink','j':'jelly','k':'krill','l':'lagoon','m':'murk','n':'naut','o':'ocean','p':'pearl','q':'quatic','r':'reef','s':'salt','t':'tide','u':'urchin','v':'void','w':'wave','x':'xiph','y':'yacht','z':'zone'}
|
||||
CONSTRUCT_MAP = {'a':'auto','b':'bolt','c':'clank','d':'diode','e':'engine','f':'forge','g':'gear','h':'hydro','i':'iron','j':'joint','k':'kinetic','l':'link','m':'motor','n':'node','o':'optic','p':'piston','q':'quantum','r':'rivet','s':'servo','t':'titan','u':'unit','v':'volt','w':'whirr','x':'xenon','y':'yoke','z':'zinc'}
|
||||
MYCONID_MAP = {'a':'agaric','b':'bolete','c':'cap','d':'decay','e':'enoki','f':'fungi','g':'gill','h':'hyphae','i':'indigo','j':'jelly','k':'kombu','l':'lichen','m':'myco\'','n':'nidur','o':'oyster','p':'puff','q':'quorn','r':'rhizo','s':'spore\'','t':'thallus','u':'umbra','v':'velvet','w':'wart','x':'xero','y':'yeast','z':'zoospore'}
|
||||
VOIDTOUCHED_MAP = {'a':'a\'th','b':'b\'zoth','c':'c\'thun','d':'d\'gol','e':'e\'th','f':'f\'thagn','g':'g\'noth','h':'h\'zoth','i':'i\'th','j':'j\'th','k':'k\'th','l':'l\'th','m':'m\'th','n':'n\'th','o':'o\'th','p':'p\'th','q':'qor\'','r':'r\'lyeh','s':'s\'th','t':'t\'th','u':'u\'th','v':'v\'lath','w':'w\'th','x':'x\'thul','y':'y\'th','z':'zy\'th'}
|
||||
LIZARDFOLK_MAP = {'a':'\'ax','b':'\'bax','c':'\'caz','d':'\'daz','e':'\'ex','f':'\'fax','g':'\'gaz','h':'h\'ss','i':'\'ix','j':'\'jax','k':'sk\'ex','l':'\'lax','m':'\'max','n':'\'nax','o':'\'ox','p':'\'pax','q':'\'qax','r':'\'rax','s':'s\'lith','t':'t\'char','u':'\'ux','v':'\'vax','w':'\'wax','x':'\'xax','y':'\'yax','z':'\'zax'}
|
||||
ARACHNID_MAP = {'a':'\'arr','b':'\'brach','c':'ch\'t','d':'\'drach','e':'\'err','f':'\'fune','g':'\'goss','h':'\'harr','i':'\'itt','j':'\'jarr','k':'klik\'','l':'\'lar','m':'\'marr','n':'\'narr','o':'\'orr','p':'\'parr','q':'\'qarr','r':'\'rarr','s':'skitter\'','t':'th\'k','u':'\'urr','v':'\'varr','w':'web\'','x':'\'xarr','y':'\'yarr','z':'\'zarr'}
|
||||
ANGELIC_MAP = {'a':'adriel','b':'baraqiel','c':'camael','d':'divinus','e':'elohim','f':'fanuel','g':'gloria','h':'hesed','i':'israfel','j':'jophiel','k':'kyrie','l':'lux','m':'michael','n':'netzach','o':'ophaniel','p':'peniel','q':'qadish','r':'raphael','s':'seraph','t':'tiferet','u':'uriel','v':'virtues','w':'wele\'el','x':'xathanael','y':'yesod','z':'zadkiel'}
|
||||
RATFOLK_MAP = {'a':'skree','b':'bite','c':'claw','d':'dark-thing','e':'eek','f':'filth','g':'gnaw','h':'hiss','i':'itch','j':'junk','k':'kill','l':'long-tail','m':'muck','n':'nest-thing','o':'rot-stink','p':'plague','q':'quick-quick','r':'rust','s':'skitter','t':'twitch','u':'under-thing','v':'vermin','w':'waste','x':'pox','y':'yes-yes','z':'zap-tail'}
|
||||
HALFTONGUE_MAP = {'a':'apple','b':'bramble','c':'crumpet','d':'dale','e':'elderberry','f':'fiddle','g':'garden','h':'hearth','i':'iris','j':'jam','k':'kettle','l':'lazy','m':'meadow','n':'nimble','o':'oats','p':'pudding','q':'quaint','r':'river','s':'sunny','t':'tater','u':'underhill','v':'vine','w':'willow','x':'extra','y':'yarn','z':'zesty'}
|
||||
UNDERCOMMON_MAP = {'a':'velk','b':'xund','c':'k\'yorl','d':'d\'ruth','e':'e\'trorn','f':'faer','g':'gol','h':'h\'chak','i':'i\'lith','j':'j\'lar','k':'k\'lar','l':'lil','m':'m\'lar','n':'nind','o':'olath','p':'p\'lar','q':'qu\'ellar','r':'ril','s':'sorn','t':'t\'lar','u':'uss','v':'v\'lar','w':'wyl','x':'x\'lar','y':'y\'lar','z':'z\'ress'}
|
||||
MORSE_MAP = {'a':'.-','b':'-...','c':'-.-.','d':'-..','e':'.','f':'..-.','g':'--.','h':'....','i':'..','j':'.---','k':'-.-','l':'.-..','m':'--','n':'-.','o':'---','p':'.--.','q':'--.-','r':'.-.','s':'...','t':'-','u':'..-','v':'...-','w':'.--','x':'-..-','y':'-.--','z':'--..','1':'.----','2':'..---','3':'...--','4':'....-','5':'.....','6':'-....','7':'--...','8':'---..','9':'----.','0':'-----',' ':'/'}
|
||||
LEET_MAP = {'a':'4','b':'8','c':'(','d':')','e':'3','f':'|=','g':'6','h':'#','i':'1','j':']','k':'|<','l':'1','m':'/\\/\\','n':'/\\/','o':'0','p':'|D','q':'(,)','r':'|2','s':'5','t':'7','u':'|_|','v':'\\/','w':'\\/\\/','x':'><','y':'`/','z':'2'}
|
||||
|
||||
# --- Translation Logic Functions ---
|
||||
|
||||
def generic_translator(text, translation_map, separator):
|
||||
"""Translate text by mapping characters and joining them."""
|
||||
translated_words = []
|
||||
for word in text.split(' '):
|
||||
translated_chars = [translation_map.get(char.lower(), char) for char in word]
|
||||
translated_words.append(separator.join(translated_chars))
|
||||
return (' ' if separator else ' ').join(translated_words)
|
||||
|
||||
# --- Main Cog Class ---
|
||||
|
||||
class Translator(commands.Cog):
|
||||
"""A cog for translating text into various languages."""
|
||||
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
self.languages = self._setup_languages()
|
||||
|
||||
def _setup_languages(self):
|
||||
"""Initializes the language definitions."""
|
||||
# Using lambdas to keep it concise, matching the JS structure
|
||||
return {
|
||||
'common': {'name': 'Common', 'translate': lambda text: text},
|
||||
'abyssal': {'name': 'Abyssal', 'translate': lambda text: generic_translator(text, ABYSSAL_MAP, ' ')},
|
||||
'angelic': {'name': 'Angelic', 'translate': lambda text: generic_translator(text, ANGELIC_MAP, ' ')},
|
||||
'aquan': {'name': 'Aquan', 'translate': lambda text: generic_translator(text, AQUAN_MAP, ' ')},
|
||||
'aquatic': {'name': 'Aquatic', 'translate': lambda text: generic_translator(text, AQUATIC_MAP, ' ')},
|
||||
'arachnid': {'name': 'Arachnid', 'translate': lambda text: generic_translator(text, ARACHNID_MAP, ' ')},
|
||||
'avian': {'name': 'Avian', 'translate': lambda text: generic_translator(text, AVIAN_MAP, ' ')},
|
||||
'celestial': {'name': 'Celestial', 'translate': lambda text: generic_translator(text, CELESTIAL_MAP, ' ')},
|
||||
'construct': {'name': 'Construct', 'translate': lambda text: generic_translator(text, CONSTRUCT_MAP, ' ')},
|
||||
'devilish': {'name': 'Devilish', 'translate': lambda text: generic_translator(text, DEVILISH_MAP, ' ')},
|
||||
'draconic': {'name': 'Draconic', 'translate': lambda text: generic_translator(text, DRACONIC_MAP, ' ')},
|
||||
'dwarvish': {'name': 'Dwarvish', 'translate': lambda text: generic_translator(text, DWARVISH_MAP, ' ')},
|
||||
'elemental': {'name': 'Elemental', 'translate': lambda text: generic_translator(text, ELEMENTAL_MAP, ' ')},
|
||||
'elvish': {'name': 'Elvish', 'translate': lambda text: generic_translator(text, ELVISH_MAP, ' ')},
|
||||
'feline': {'name': 'Feline', 'translate': lambda text: generic_translator(text, FELINE_MAP, ' ')},
|
||||
'fiendish': {'name': 'Fiendish', 'translate': lambda text: generic_translator(text, FIENDISH_MAP, ' ')},
|
||||
'gnomish': {'name': 'Gnomish', 'translate': lambda text: generic_translator(text, GNOMISH_MAP, ' ')},
|
||||
'goblin': {'name': 'Goblin', 'translate': lambda text: generic_translator(text, GOBLIN_MAP, ' ')},
|
||||
'halftongue': {'name': 'Half-Tongue', 'translate': lambda text: generic_translator(text, HALFTONGUE_MAP, ' ')},
|
||||
'herbilore': {'name': 'Herbilore', 'translate': lambda text: generic_translator(text, HERBILORE_MAP, ' ')},
|
||||
'infernal': {'name': 'Infernal', 'translate': lambda text: generic_translator(text, INFERNAL_MAP, ' ')},
|
||||
'kitsune': {'name': 'Kitsune', 'translate': lambda text: generic_translator(text, KITSUNE_MAP, '')},
|
||||
'leet': {'name': 'Leet Speak', 'translate': lambda text: generic_translator(text, LEET_MAP, '')},
|
||||
'lizardfolk': {'name': 'Lizardfolk', 'translate': lambda text: generic_translator(text, LIZARDFOLK_MAP, ' ')},
|
||||
'morse': {'name': 'Morse Code', 'translate': lambda text: generic_translator(text, MORSE_MAP, ' ')},
|
||||
'myconid': {'name': 'Myconid', 'translate': lambda text: generic_translator(text, MYCONID_MAP, ' ')},
|
||||
'ogrish': {'name': 'Ogrish', 'translate': lambda text: generic_translator(text, OGRISH_MAP, ' ')},
|
||||
'orcish': {'name': 'Orcish', 'translate': lambda text: generic_translator(text, ORCISH_MAP, ' ')},
|
||||
'ratfolk': {'name': 'Ratfolk', 'translate': lambda text: generic_translator(text, RATFOLK_MAP, ' ')},
|
||||
'scorpion': {'name': 'Scorpion', 'translate': lambda text: generic_translator(text, SCORPION_MAP, ' ')},
|
||||
'sinary': {'name': 'Sinary', 'translate': lambda text: generic_translator(text, SINARY_MAP, '')},
|
||||
'spiritual': {'name': 'Spiritual', 'translate': lambda text: generic_translator(text, SPIRITUAL_MAP, ' ')},
|
||||
'succubus': {'name': 'Succubus', 'translate': lambda text: generic_translator(text, SUCCUBUS_MAP, ' ')},
|
||||
'sylvan': {'name': 'Sylvan', 'translate': lambda text: generic_translator(text, SYLVAN_MAP, ' ')},
|
||||
'undercommon': {'name': 'Undercommon', 'translate': lambda text: generic_translator(text, UNDERCOMMON_MAP, ' ')},
|
||||
'valspiren': {'name': 'Valspiren', 'translate': lambda text: generic_translator(text, VALSPIREN_MAP, '')},
|
||||
'voidtouched': {'name': 'Voidtouched', 'translate': lambda text: generic_translator(text, VOIDTOUCHED_MAP, ' ')},
|
||||
}
|
||||
|
||||
async def language_autocomplete(self, interaction: discord.Interaction, current: str) -> list[app_commands.Choice[str]]:
|
||||
"""Autocomplete for language choices."""
|
||||
choices = [
|
||||
app_commands.Choice(name=lang_data['name'], value=lang_key)
|
||||
for lang_key, lang_data in self.languages.items()
|
||||
if current.lower() in lang_data['name'].lower()
|
||||
]
|
||||
return choices[:25]
|
||||
|
||||
@commands.hybrid_command(name="translate", description="Translate text to a selected language.")
|
||||
@app_commands.describe(
|
||||
language="The language to translate the text into.",
|
||||
text="The text to translate."
|
||||
)
|
||||
@app_commands.autocomplete(language=language_autocomplete)
|
||||
async def translate(self, ctx: commands.Context, language: str, *, text: str):
|
||||
"""
|
||||
Translates the given text into the specified language.
|
||||
|
||||
To see a list of available languages, use the command without specifying a language.
|
||||
"""
|
||||
language_key = language.lower()
|
||||
|
||||
if language_key not in self.languages:
|
||||
await ctx.send(f"Sorry, '{language}' is not a valid language. Please choose from the list.", ephemeral=True)
|
||||
return
|
||||
|
||||
translator_func = self.languages[language_key]['translate']
|
||||
translated_text = translator_func(text)
|
||||
|
||||
embed = discord.Embed(
|
||||
title=f"Translation to {self.languages[language_key]['name']}",
|
||||
color=discord.Color.blue()
|
||||
)
|
||||
embed.add_field(name="Original Text", value=f"```\n{text}\n```", inline=False)
|
||||
embed.add_field(name="Translated Text", value=f"```\n{translated_text}\n```", inline=False)
|
||||
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
@commands.hybrid_command(name="languages", description="List all available languages for translation.")
|
||||
async def list_languages(self, ctx: commands.Context):
|
||||
"""Provides a list of all available languages."""
|
||||
|
||||
sorted_languages = sorted(self.languages.values(), key=lambda x: x['name'])
|
||||
|
||||
description = "\n".join([lang['name'] for lang in sorted_languages])
|
||||
|
||||
embed = discord.Embed(
|
||||
title="Available Languages",
|
||||
description=description,
|
||||
color=discord.Color.green()
|
||||
)
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
async def setup(bot):
|
||||
await bot.add_cog(Translator(bot))
|
||||
|
||||
82
welcomer/README.md
Normal file
82
welcomer/README.md
Normal file
@@ -0,0 +1,82 @@
|
||||
# Welcomer Cog - ver-1.0.0
|
||||
A configurable cog to automatically welcome new users when they join your server.
|
||||
|
||||
# Features
|
||||
- Fully Configurable: Set a custom welcome message and channel for each server.
|
||||
- Enable/Disable: Easily toggle the welcomer on or off without losing your settings.
|
||||
- Placeholder Support: Personalize your welcome message with user and server details.
|
||||
- Easy Setup: A simple command group for admins to manage all settings.
|
||||
- Permissions: All settings commands require `Manage Server` permissions to use.
|
||||
|
||||
# Commands
|
||||
All configuration is handled through the `[p]welcomeset` command group.
|
||||
|
||||
[p]welcomeset channel <#channel>
|
||||
Sets the channel where welcome messages will be sent.
|
||||
|
||||
Alias: chnl
|
||||
|
||||
Example: [p]welcomeset channel #welcome
|
||||
|
||||
[p]welcomeset message <message>
|
||||
Sets the custom welcome message. See the "Placeholders" section below for available variables.
|
||||
|
||||
Alias: msg
|
||||
|
||||
Example: [p]welcomeset message Welcome {user.mention} to {server_name}! We're glad you're here.
|
||||
|
||||
[p]welcomeset toggle
|
||||
Toggles the welcomer system on or off for the server.
|
||||
|
||||
Aliases: on, off
|
||||
|
||||
Example: [p]welcomeset toggle
|
||||
|
||||
[p]welcomeset settings
|
||||
Displays the current settings for the welcomer in an embed.
|
||||
|
||||
Aliases: show, status
|
||||
|
||||
Example: [p]welcomeset settings
|
||||
|
||||
[p]welcomeset test
|
||||
Sends a preview of the current welcome message to the channel where the command is run.
|
||||
|
||||
Example: [p]welcomeset test
|
||||
|
||||
[p]welcomeset reset
|
||||
Resets all welcomer settings for the server to their default values.
|
||||
|
||||
Example: [p]welcomeset reset
|
||||
|
||||
Quick Setup Guide
|
||||
Load the Cog:
|
||||
|
||||
[p]load welcomer
|
||||
|
||||
Set the Welcome Channel:
|
||||
|
||||
[p]welcomeset channel #your-welcome-channel
|
||||
|
||||
Set Your Custom Message:
|
||||
|
||||
[p]welcomeset message Welcome, {user.mention}! Enjoy your stay in {server_name}!
|
||||
|
||||
Enable the System:
|
||||
|
||||
[p]welcomeset toggle
|
||||
|
||||
The bot will now welcome new members in the channel you specified. You can use [p]welcomeset settings at any time to check your configuration.
|
||||
|
||||
Placeholders for the Welcome Message
|
||||
You can use the following placeholders in your custom welcome message. They will be automatically replaced with the correct information when a new user joins.
|
||||
|
||||
{user}: The user object itself.
|
||||
|
||||
{user.mention}: Pings the new user (e.g., @UnstableKitsune).
|
||||
|
||||
{user_name}: The new user's name (e.g., UnstableKitsune).
|
||||
|
||||
{server_name}: The name of the server they joined.
|
||||
|
||||
For full documentation, please visit the [repository wiki](https://git.kitsunic.org/kitsunicWorks/unstable-cogs/wiki).
|
||||
1
welcomer/__init__.py
Normal file
1
welcomer/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from .welcomer import setup
|
||||
14
welcomer/info.json
Normal file
14
welcomer/info.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"author": [ "unstableCogs" ],
|
||||
"install_msg": "Thank you for installing the Welcomer cog!",
|
||||
"name": "Welcomer",
|
||||
"short": "A simple cog to welcome new users.",
|
||||
"description": "Greets new members in a designated channel with a customizable message. This cog is part of the Unified Bot Suite.",
|
||||
"tags": [
|
||||
"welcome",
|
||||
"utility",
|
||||
"greeting"
|
||||
],
|
||||
"requirements": [],
|
||||
"end_user_data_statement": "This cog does not persistently store any end user data."
|
||||
}
|
||||
195
welcomer/welcomer.py
Normal file
195
welcomer/welcomer.py
Normal file
@@ -0,0 +1,195 @@
|
||||
# welcomer.py
|
||||
|
||||
import discord
|
||||
from redbot.core import commands, Config
|
||||
from redbot.core.bot import Red
|
||||
|
||||
class Welcomer(commands.Cog):
|
||||
"""
|
||||
A configurable cog to welcome new users to a server.
|
||||
"""
|
||||
|
||||
def __init__(self, bot: Red):
|
||||
self.bot = bot
|
||||
# Initialize Red's Config system. This will store our settings.
|
||||
# The "GUILD" identifier means settings will be saved on a per-server basis.
|
||||
self.config = Config.get_conf(self, identifier=1234567890, force_registration=True)
|
||||
|
||||
# Define the default settings for each server.
|
||||
default_guild = {
|
||||
"welcome_channel": None, # The ID of the channel to send welcomes to
|
||||
"welcome_message": "Welcome to the server, {user.mention}!", # Default message
|
||||
"enabled": False # Whether the system is on or off
|
||||
}
|
||||
|
||||
# Register the default settings.
|
||||
self.config.register_guild(**default_guild)
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_member_join(self, member: discord.Member):
|
||||
"""
|
||||
The event listener that runs when a new member joins.
|
||||
"""
|
||||
guild = member.guild
|
||||
|
||||
# Check if the welcomer is enabled for this server.
|
||||
if not await self.config.guild(guild).enabled():
|
||||
return
|
||||
|
||||
# Get the welcome channel ID from our saved settings.
|
||||
channel_id = await self.config.guild(guild).welcome_channel()
|
||||
if not channel_id:
|
||||
return # If no channel is set, do nothing.
|
||||
|
||||
# Try to find the channel object in the server.
|
||||
channel = guild.get_channel(channel_id)
|
||||
if not channel:
|
||||
# The channel might have been deleted.
|
||||
return
|
||||
|
||||
# Explicitly check if the channel is a TextChannel before trying to send a message.
|
||||
if not isinstance(channel, discord.TextChannel):
|
||||
print(f"Welcomer: Configured channel '{channel.name}' in {guild.name} is not a text channel.")
|
||||
return
|
||||
|
||||
# Get the custom welcome message from our settings.
|
||||
message_template = await self.config.guild(guild).welcome_message()
|
||||
|
||||
# Format the message with the new member's info.
|
||||
# .format() is a safe way to replace placeholders.
|
||||
formatted_message = message_template.format(
|
||||
user=member,
|
||||
user_mention=member.mention,
|
||||
user_name=member.name,
|
||||
server_name=guild.name
|
||||
)
|
||||
|
||||
# Check if we have permission to send messages in the channel.
|
||||
if not channel.permissions_for(guild.me).send_messages:
|
||||
# We can't send a message, so we'll just log this internally.
|
||||
print(f"Welcomer: No permission to send messages in {channel.name} in {guild.name}.")
|
||||
return
|
||||
|
||||
try:
|
||||
await channel.send(formatted_message)
|
||||
except discord.Forbidden:
|
||||
# This is a final safety check in case permissions change suddenly.
|
||||
pass
|
||||
except discord.HTTPException as e:
|
||||
# This can happen if the message is too long or there's a Discord API error.
|
||||
print(f"Welcomer: Failed to send welcome message in {guild.name}: {e}")
|
||||
|
||||
# Create a command group for all our settings commands.
|
||||
@commands.group(aliases=["wset"]) # type: ignore
|
||||
@commands.guild_only() # Ensures this command and its subcommands can only be run in a server
|
||||
@commands.admin_or_permissions(manage_guild=True)
|
||||
async def welcomeset(self, ctx: commands.Context):
|
||||
"""
|
||||
Configure the welcomer settings for this server.
|
||||
"""
|
||||
pass
|
||||
|
||||
@welcomeset.command(name="channel", aliases=["chnl"])
|
||||
async def welcomeset_channel(self, ctx: commands.Context, channel: discord.TextChannel):
|
||||
"""
|
||||
Set the channel where welcome messages will be sent.
|
||||
|
||||
Example:
|
||||
[p]welcomeset channel #welcome
|
||||
"""
|
||||
if not ctx.guild:
|
||||
return # This check satisfies the type checker
|
||||
await self.config.guild(ctx.guild).welcome_channel.set(channel.id)
|
||||
await ctx.send(f"The welcome channel has been set to {channel.mention}.")
|
||||
|
||||
@welcomeset.command(name="message", aliases=["msg"])
|
||||
async def welcomeset_message(self, ctx: commands.Context, *, message: str):
|
||||
"""
|
||||
Set the custom welcome message.
|
||||
|
||||
You can use these placeholders:
|
||||
{user} - The user object.
|
||||
{user_mention} - Pings the user.
|
||||
{user_name} - The user's name.
|
||||
{server_name} - The name of this server.
|
||||
|
||||
Example:
|
||||
[p]welcomeset message Hello {user_mention}, welcome to {server_name}!
|
||||
"""
|
||||
if not ctx.guild:
|
||||
return
|
||||
await self.config.guild(ctx.guild).welcome_message.set(message)
|
||||
await ctx.send(f"The welcome message has been updated.")
|
||||
# Send a preview of the new message.
|
||||
preview = message.format(
|
||||
user=ctx.author,
|
||||
user_mention=ctx.author.mention,
|
||||
user_name=ctx.author.name,
|
||||
server_name=ctx.guild.name
|
||||
)
|
||||
await ctx.send(f"**Preview:**\n{preview}")
|
||||
|
||||
@welcomeset.command(name="toggle", aliases=["on", "off"])
|
||||
async def welcomeset_toggle(self, ctx: commands.Context):
|
||||
"""
|
||||
Enable or disable the welcomer system on this server.
|
||||
"""
|
||||
if not ctx.guild:
|
||||
return
|
||||
current_status = await self.config.guild(ctx.guild).enabled()
|
||||
new_status = not current_status
|
||||
await self.config.guild(ctx.guild).enabled.set(new_status)
|
||||
status_text = "enabled" if new_status else "disabled"
|
||||
await ctx.send(f"The welcomer system has been {status_text}.")
|
||||
|
||||
@welcomeset.command(name="settings", aliases=["show", "status"])
|
||||
async def welcomeset_settings(self, ctx: commands.Context):
|
||||
"""
|
||||
Show the current welcomer settings for this server.
|
||||
"""
|
||||
if not ctx.guild:
|
||||
return
|
||||
settings = await self.config.guild(ctx.guild).all()
|
||||
channel_id = settings['welcome_channel']
|
||||
channel = ctx.guild.get_channel(channel_id) if channel_id else None
|
||||
message = settings['welcome_message']
|
||||
enabled = "Enabled" if settings['enabled'] else "Disabled"
|
||||
|
||||
embed = discord.Embed(title="Welcomer Settings", color=await ctx.embed_color())
|
||||
embed.add_field(name="Status", value=enabled, inline=False)
|
||||
embed.add_field(name="Channel", value=channel.mention if isinstance(channel, discord.TextChannel) else "Not Set", inline=False)
|
||||
embed.add_field(name="Message", value=f"```{message}```", inline=False)
|
||||
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
@welcomeset.command(name="test")
|
||||
async def welcomeset_test(self, ctx: commands.Context):
|
||||
"""
|
||||
Test the welcome message by sending a preview to this channel.
|
||||
"""
|
||||
if not ctx.guild:
|
||||
return
|
||||
message_template = await self.config.guild(ctx.guild).welcome_message()
|
||||
preview = message_template.format(
|
||||
user=ctx.author,
|
||||
user_mention=ctx.author.mention,
|
||||
user_name=ctx.author.name,
|
||||
server_name=ctx.guild.name
|
||||
)
|
||||
await ctx.send(f"**Welcome Message Preview**:\n{preview}")
|
||||
|
||||
@welcomeset.command(name="reset")
|
||||
async def welcomeset_reset(self, ctx: commands.Context):
|
||||
"""
|
||||
Reset all welcomer settings to their defaults.
|
||||
"""
|
||||
if not ctx.guild:
|
||||
return
|
||||
await self.config.guild(ctx.guild).clear()
|
||||
await ctx.send("The welcomer settings have been reset to their defaults.")
|
||||
|
||||
|
||||
# This function allows Red to load the cog.
|
||||
# It is required in every cog file.
|
||||
async def setup(bot: Red):
|
||||
await bot.add_cog(Welcomer(bot))
|
||||
Reference in New Issue
Block a user