feat: add multiple discord bot cogs
Adds new cogs including DataManager, Hiring, KofiShop, Logging, ModMail, MORS, ServiceReview, StaffMsg, and Translator to enhance bot functionality for data management, hiring processes, logging events, and more.
This commit is contained in:
263
hiring/hiring.py
Normal file
263
hiring/hiring.py
Normal file
@@ -0,0 +1,263 @@
|
||||
import discord
|
||||
from redbot.core import commands, Config, app_commands
|
||||
from typing import Literal, Optional, TYPE_CHECKING, Type
|
||||
import datetime
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from redbot.core.bot import Red
|
||||
|
||||
# --- 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 Invite Link")
|
||||
|
||||
def __init__(self, ticket_channel: discord.TextChannel):
|
||||
super().__init__()
|
||||
self.ticket_channel = ticket_channel
|
||||
|
||||
async def on_submit(self, interaction: discord.Interaction):
|
||||
cog: Optional["Hiring"] = interaction.client.get_cog("Hiring") # type: ignore
|
||||
if not cog:
|
||||
await interaction.response.send_message("Hiring cog not loaded.", ephemeral=True)
|
||||
return
|
||||
|
||||
embed = discord.Embed(title="New Staff Application", color=discord.Color.blue())
|
||||
embed.set_author(name=interaction.user.name, icon_url=interaction.user.display_avatar.url)
|
||||
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 self.ticket_channel.send(embed=embed)
|
||||
await interaction.response.send_message("Your staff application has been submitted.", ephemeral=True)
|
||||
|
||||
class PMApplicationModal(discord.ui.Modal, title="PM Application"):
|
||||
ad = discord.ui.TextInput(label="Your Ad", style=discord.TextStyle.paragraph)
|
||||
reqs = discord.ui.TextInput(label="Your Requirements", style=discord.TextStyle.paragraph)
|
||||
tox_level = discord.ui.TextInput(label="What is your toxicity level tolerance?")
|
||||
chosen_plan = discord.ui.TextInput(label="What plan are you interested in?")
|
||||
|
||||
def __init__(self, ticket_channel: discord.TextChannel):
|
||||
super().__init__()
|
||||
self.ticket_channel = ticket_channel
|
||||
|
||||
async def on_submit(self, interaction: discord.Interaction):
|
||||
cog: Optional["Hiring"] = interaction.client.get_cog("Hiring") # type: ignore
|
||||
if not cog:
|
||||
await interaction.response.send_message("Hiring cog not loaded.", ephemeral=True)
|
||||
return
|
||||
|
||||
embed = discord.Embed(title="New PM Application", color=discord.Color.green())
|
||||
embed.set_author(name=interaction.user.name, icon_url=interaction.user.display_avatar.url)
|
||||
embed.add_field(name="Ad", value=f"```\n{self.ad.value}\n```", inline=False)
|
||||
embed.add_field(name="Requirements", value=f"```\n{self.reqs.value}\n```", 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 self.ticket_channel.send(embed=embed)
|
||||
await interaction.response.send_message("Your PM application has been submitted.", ephemeral=True)
|
||||
|
||||
class HPMApplicationModal(discord.ui.Modal, title="HPM Application"):
|
||||
ad = discord.ui.TextInput(label="Your Ad", style=discord.TextStyle.paragraph)
|
||||
reqs = discord.ui.TextInput(label="Your Requirements", style=discord.TextStyle.paragraph)
|
||||
|
||||
def __init__(self, ticket_channel: discord.TextChannel):
|
||||
super().__init__()
|
||||
self.ticket_channel = ticket_channel
|
||||
|
||||
async def on_submit(self, interaction: discord.Interaction):
|
||||
cog: Optional["Hiring"] = interaction.client.get_cog("Hiring") # type: ignore
|
||||
if not cog:
|
||||
await interaction.response.send_message("Hiring cog not loaded.", ephemeral=True)
|
||||
return
|
||||
|
||||
embed = discord.Embed(title="New HPM Application", color=discord.Color.purple())
|
||||
embed.set_author(name=interaction.user.name, icon_url=interaction.user.display_avatar.url)
|
||||
embed.add_field(name="Ad", value=f"```\n{self.ad.value}\n```", inline=False)
|
||||
embed.add_field(name="Requirements", value=f"```\n{self.reqs.value}\n```", inline=False)
|
||||
await self.ticket_channel.send(embed=embed)
|
||||
await interaction.response.send_message("Your HPM application has been submitted.", ephemeral=True)
|
||||
|
||||
# --- Views with Buttons ---
|
||||
|
||||
async def create_ticket(interaction: discord.Interaction, ticket_type: str, modal_class: Type[discord.ui.Modal]):
|
||||
"""Helper function to create a ticket, used by multiple views."""
|
||||
cog: Optional["Hiring"] = interaction.client.get_cog("Hiring") # type: ignore
|
||||
if not cog:
|
||||
await interaction.response.send_message("The Hiring cog is not loaded.", ephemeral=True)
|
||||
return
|
||||
|
||||
guild = interaction.guild
|
||||
if not guild:
|
||||
await interaction.response.send_message("This action can only be performed in a server.", ephemeral=True)
|
||||
return
|
||||
|
||||
category_id_raw = await cog.config.guild(guild).get_raw(f"{ticket_type}_category")
|
||||
if not isinstance(category_id_raw, int):
|
||||
await interaction.response.send_message(f"The category for '{ticket_type}' applications has not been set correctly.", ephemeral=True)
|
||||
return
|
||||
|
||||
category = guild.get_channel(category_id_raw)
|
||||
if not isinstance(category, discord.CategoryChannel):
|
||||
await interaction.response.send_message(f"The configured category for '{ticket_type}' is invalid.", ephemeral=True)
|
||||
return
|
||||
|
||||
assert isinstance(interaction.user, discord.Member)
|
||||
|
||||
try:
|
||||
thread_name = f"{ticket_type}-application-{interaction.user.name}"
|
||||
overwrites = {
|
||||
guild.default_role: discord.PermissionOverwrite(read_messages=False),
|
||||
interaction.user: discord.PermissionOverwrite(read_messages=True, send_messages=True)
|
||||
}
|
||||
ticket_channel = await category.create_text_channel(name=thread_name, overwrites=overwrites)
|
||||
|
||||
modal_instance = modal_class(ticket_channel) # type: ignore
|
||||
await interaction.response.send_modal(modal_instance)
|
||||
|
||||
async with cog.config.guild(guild).closed_applications() as closed_apps:
|
||||
closed_apps[str(ticket_channel.id)] = datetime.datetime.now(datetime.timezone.utc).isoformat()
|
||||
|
||||
except discord.Forbidden:
|
||||
if not interaction.response.is_done():
|
||||
await interaction.response.send_message("I don't have permission to create channels in that category.", ephemeral=True)
|
||||
except Exception as e:
|
||||
if not interaction.response.is_done():
|
||||
await interaction.response.send_message(f"An unexpected error occurred: {e}", ephemeral=True)
|
||||
|
||||
class HireView(discord.ui.View):
|
||||
def __init__(self):
|
||||
super().__init__(timeout=None)
|
||||
|
||||
@discord.ui.button(label="Staff", style=discord.ButtonStyle.primary, custom_id="staff_apply_button_persistent")
|
||||
async def staff_button(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||
await create_ticket(interaction, "staff", StaffApplicationModal)
|
||||
|
||||
@discord.ui.button(label="PM", style=discord.ButtonStyle.secondary, custom_id="pm_apply_button_persistent")
|
||||
async def pm_button(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||
await create_ticket(interaction, "pm", PMApplicationModal)
|
||||
|
||||
@discord.ui.button(label="HPM", style=discord.ButtonStyle.success, custom_id="hpm_apply_button_persistent")
|
||||
async def hpm_button(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||
await create_ticket(interaction, "hpm", HPMApplicationModal)
|
||||
|
||||
|
||||
class WorkView(discord.ui.View):
|
||||
def __init__(self):
|
||||
super().__init__(timeout=None)
|
||||
|
||||
@discord.ui.button(label="Apply for PM Position", style=discord.ButtonStyle.green, custom_id="work_apply_pm_persistent")
|
||||
async def work_apply_button(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||
await create_ticket(interaction, "pm", PMApplicationModal)
|
||||
|
||||
|
||||
# --- Main Cog Class ---
|
||||
|
||||
class Hiring(commands.Cog):
|
||||
"""
|
||||
A cog for handling staff hiring applications.
|
||||
"""
|
||||
def __init__(self, bot: "Red"):
|
||||
self.bot = bot
|
||||
self.config = Config.get_conf(self, identifier=1234567891, force_registration=True)
|
||||
default_guild = {
|
||||
"staff_category": None,
|
||||
"pm_category": None,
|
||||
"hpm_category": None,
|
||||
"work_channel": None,
|
||||
"closed_applications": {}
|
||||
}
|
||||
self.config.register_guild(**default_guild)
|
||||
|
||||
async def cog_load(self):
|
||||
self.bot.add_view(HireView())
|
||||
self.bot.add_view(WorkView())
|
||||
|
||||
@commands.hybrid_command() # type: ignore
|
||||
@app_commands.guild_only()
|
||||
@commands.admin_or_permissions(manage_guild=True)
|
||||
async def hire(self, ctx: commands.Context):
|
||||
"""Sends the hiring application view."""
|
||||
view = HireView()
|
||||
embed = discord.Embed(
|
||||
title="Hiring Applications",
|
||||
description="Please select the position you are applying for below.",
|
||||
color=await ctx.embed_color()
|
||||
)
|
||||
await ctx.send(embed=embed, view=view)
|
||||
|
||||
@commands.hybrid_command() # type: ignore
|
||||
@app_commands.guild_only()
|
||||
@commands.admin_or_permissions(manage_guild=True)
|
||||
async def work(self, ctx: commands.Context):
|
||||
"""Posts the persistent PM application button."""
|
||||
guild = ctx.guild
|
||||
if not guild:
|
||||
return
|
||||
|
||||
work_channel_id = await self.config.guild(guild).work_channel()
|
||||
if not work_channel_id:
|
||||
await ctx.send("The work channel has not been set. Please use `/hiringset workchannel`.")
|
||||
return
|
||||
|
||||
channel = guild.get_channel(work_channel_id)
|
||||
if not isinstance(channel, discord.TextChannel):
|
||||
await ctx.send("The configured work channel is invalid.")
|
||||
return
|
||||
|
||||
view = WorkView()
|
||||
embed = discord.Embed(
|
||||
title="Partnership Manager Applications",
|
||||
description="Click the button below to apply for a Partnership Manager (PM) position.",
|
||||
color=discord.Color.green()
|
||||
)
|
||||
try:
|
||||
await channel.send(embed=embed, view=view)
|
||||
await ctx.send(f"Application message posted in {channel.mention}.", ephemeral=True)
|
||||
except discord.Forbidden:
|
||||
await ctx.send("I don't have permission to send messages in that channel.", ephemeral=True)
|
||||
|
||||
|
||||
@commands.group(aliases=["hset"]) # type: ignore
|
||||
@commands.guild_only()
|
||||
@commands.admin_or_permissions(manage_guild=True)
|
||||
async def hiringset(self, ctx: commands.Context):
|
||||
"""Configure Hiring 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 for the /work command announcements."""
|
||||
if not ctx.guild:
|
||||
return
|
||||
await self.config.guild(ctx.guild).work_channel.set(channel.id)
|
||||
await ctx.send(f"Work announcement channel set to {channel.mention}.")
|
||||
|
||||
async def setup(bot):
|
||||
await bot.add_cog(Hiring(bot))
|
||||
|
||||
Reference in New Issue
Block a user