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:
4
staffmsg/__init__.py
Normal file
4
staffmsg/__init__.py
Normal file
@@ -0,0 +1,4 @@
|
||||
from .staffmsg import StaffMsg
|
||||
|
||||
async def setup(bot):
|
||||
await bot.add_cog(StaffMsg(bot))
|
||||
17
staffmsg/info.json
Normal file
17
staffmsg/info.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"author": [
|
||||
"unstableCogs"
|
||||
],
|
||||
"install_msg": "Thank you for installing the Staff Messaging cog!",
|
||||
"name": "StaffMsg",
|
||||
"short": "A command for staff to send official DMs.",
|
||||
"description": "Provides a permission-controlled command for staff to send direct messages to server members, with logging for accountability.",
|
||||
"tags": [
|
||||
"dm",
|
||||
"messaging",
|
||||
"staff",
|
||||
"utility"
|
||||
],
|
||||
"requirements": [],
|
||||
"end_user_data_statement": "This cog may store message content and user IDs in a log file or channel for moderation purposes."
|
||||
}
|
||||
188
staffmsg/staffmsg.py
Normal file
188
staffmsg/staffmsg.py
Normal file
@@ -0,0 +1,188 @@
|
||||
import discord
|
||||
from redbot.core import commands, Config, app_commands
|
||||
from typing import Optional
|
||||
import datetime
|
||||
|
||||
# --- Modal for the Message Form ---
|
||||
|
||||
class MessageModal(discord.ui.Modal, title="Staff Message"):
|
||||
message_content = discord.ui.TextInput(
|
||||
label="Message to Send",
|
||||
style=discord.TextStyle.paragraph,
|
||||
placeholder="Type the official message you want to send to the user here.",
|
||||
max_length=1800
|
||||
)
|
||||
|
||||
def __init__(self, cog: "StaffMsg", target_user: discord.Member):
|
||||
super().__init__()
|
||||
self.cog = cog
|
||||
self.target_user = target_user
|
||||
|
||||
async def on_submit(self, interaction: discord.Interaction):
|
||||
guild = interaction.guild
|
||||
if not guild:
|
||||
return
|
||||
|
||||
# --- Send DM to User ---
|
||||
embed_to_user = discord.Embed(
|
||||
title=f"A Message from the Staff of {guild.name}",
|
||||
description=self.message_content.value,
|
||||
color=await self.cog.bot.get_embed_color(interaction.channel) if interaction.channel else discord.Color.blurple()
|
||||
)
|
||||
embed_to_user.set_footer(text="This is an official communication. Please do not reply to the bot.")
|
||||
|
||||
try:
|
||||
await self.target_user.send(embed=embed_to_user)
|
||||
except discord.Forbidden:
|
||||
await interaction.response.send_message(
|
||||
f"I could not send a DM to {self.target_user.mention}. They may have DMs disabled.",
|
||||
ephemeral=True
|
||||
)
|
||||
return
|
||||
except discord.HTTPException as e:
|
||||
await interaction.response.send_message(f"An error occurred while sending the DM: {e}", ephemeral=True)
|
||||
return
|
||||
|
||||
# --- Log the Message ---
|
||||
log_channel_id = await self.cog.config.guild(guild).log_channel()
|
||||
if log_channel_id:
|
||||
log_channel = guild.get_channel(log_channel_id)
|
||||
if isinstance(log_channel, discord.TextChannel):
|
||||
log_embed = discord.Embed(
|
||||
title="Staff DM Sent",
|
||||
description=self.message_content.value,
|
||||
color=discord.Color.blue()
|
||||
)
|
||||
log_embed.set_author(name=f"From: {interaction.user.name} ({interaction.user.id})", icon_url=interaction.user.display_avatar.url)
|
||||
log_embed.add_field(name="To", value=f"{self.target_user.mention} ({self.target_user.id})")
|
||||
|
||||
try:
|
||||
log_message = await log_channel.send(embed=log_embed)
|
||||
async with self.cog.config.guild(guild).sent_dms() as dms:
|
||||
dms[str(log_message.id)] = datetime.datetime.now(datetime.timezone.utc).isoformat()
|
||||
except discord.Forbidden:
|
||||
pass
|
||||
|
||||
await interaction.response.send_message(f"Your message has been successfully sent to {self.target_user.mention}.", ephemeral=True)
|
||||
|
||||
|
||||
# --- Main Cog Class ---
|
||||
|
||||
class StaffMsg(commands.Cog):
|
||||
"""A cog for staff to send official DMs to users."""
|
||||
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
self.config = Config.get_conf(self, identifier=1234567892, force_registration=True)
|
||||
default_guild = {
|
||||
"log_channel": None,
|
||||
"authorized_role": None,
|
||||
"sent_dms": {} # For DataManager
|
||||
}
|
||||
self.config.register_guild(**default_guild)
|
||||
|
||||
async def cog_check(self, ctx: commands.Context) -> bool:
|
||||
if not ctx.guild:
|
||||
await ctx.send("This command can only be used in a server.", ephemeral=True)
|
||||
return False
|
||||
|
||||
auth_role_id = await self.config.guild(ctx.guild).authorized_role()
|
||||
if not auth_role_id:
|
||||
await ctx.send("The authorized role for this command has not been set.", ephemeral=True)
|
||||
return False
|
||||
|
||||
author = ctx.author
|
||||
if not isinstance(author, discord.Member):
|
||||
return False
|
||||
|
||||
if author.guild_permissions.administrator:
|
||||
return True
|
||||
|
||||
auth_role = ctx.guild.get_role(auth_role_id)
|
||||
if not auth_role or auth_role not in author.roles:
|
||||
await ctx.send("You are not authorized to use this command.", ephemeral=True)
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
@commands.hybrid_command(name="smsg", aliases=["staff", "staffmsg"])
|
||||
@app_commands.describe(user="The user to send a DM to.", message="(Optional) The message to send. Opens a form if left blank.")
|
||||
@app_commands.guild_only()
|
||||
async def staff_message(self, ctx: commands.Context, user: discord.Member, *, message: Optional[str] = None):
|
||||
"""Send an official DM to a user. Opens a form if no message is provided."""
|
||||
|
||||
# This is a clever way to handle both slash and prefix commands.
|
||||
# If the 'message' is None, it means it was likely a slash command
|
||||
# or a prefix command with no text, so we open the modal.
|
||||
if message is None:
|
||||
if not ctx.interaction:
|
||||
await ctx.send("Please provide a message to send.", ephemeral=True)
|
||||
return
|
||||
modal = MessageModal(self, user)
|
||||
await ctx.interaction.response.send_modal(modal)
|
||||
return
|
||||
|
||||
guild = ctx.guild
|
||||
if not guild: # Should be caught by cog_check but for type safety
|
||||
return
|
||||
|
||||
embed_to_user = discord.Embed(
|
||||
title=f"A Message from the Staff of {guild.name}",
|
||||
description=message,
|
||||
color=await ctx.embed_color()
|
||||
)
|
||||
embed_to_user.set_footer(text="This is an official communication. Please do not reply to the bot.")
|
||||
|
||||
try:
|
||||
await user.send(embed=embed_to_user)
|
||||
except discord.Forbidden:
|
||||
await ctx.send(f"I could not send a DM to {user.mention}. They may have DMs disabled.", ephemeral=True)
|
||||
return
|
||||
|
||||
log_channel_id = await self.config.guild(guild).log_channel()
|
||||
if log_channel_id:
|
||||
log_channel = guild.get_channel(log_channel_id)
|
||||
if isinstance(log_channel, discord.TextChannel):
|
||||
log_embed = discord.Embed(
|
||||
title="Staff DM Sent",
|
||||
description=message,
|
||||
color=discord.Color.blue()
|
||||
)
|
||||
log_embed.set_author(name=f"From: {ctx.author.name} ({ctx.author.id})", icon_url=ctx.author.display_avatar.url)
|
||||
log_embed.add_field(name="To", value=f"{user.mention} ({user.id})")
|
||||
try:
|
||||
log_message = await log_channel.send(embed=log_embed)
|
||||
async with self.config.guild(guild).sent_dms() as dms:
|
||||
dms[str(log_message.id)] = datetime.datetime.now(datetime.timezone.utc).isoformat()
|
||||
except discord.Forbidden:
|
||||
pass
|
||||
|
||||
await ctx.send(f"Your message has been sent to {user.mention}.", ephemeral=True)
|
||||
|
||||
|
||||
@commands.group(aliases=["smset"]) # type: ignore
|
||||
@commands.guild_only()
|
||||
@commands.admin_or_permissions(manage_guild=True)
|
||||
async def staffmsgset(self, ctx: commands.Context):
|
||||
"""Configure StaffMsg settings."""
|
||||
pass
|
||||
|
||||
@staffmsgset.command(name="role")
|
||||
async def set_auth_role(self, ctx: commands.Context, role: discord.Role):
|
||||
"""Set the role authorized to use the staff message commands."""
|
||||
if not ctx.guild:
|
||||
return
|
||||
await self.config.guild(ctx.guild).authorized_role.set(role.id)
|
||||
await ctx.send(f"Authorized role has been set to {role.mention}")
|
||||
|
||||
@staffmsgset.command(name="logchannel")
|
||||
async def set_log_channel(self, ctx: commands.Context, channel: discord.TextChannel):
|
||||
"""Set the channel where sent DMs will be logged."""
|
||||
if not ctx.guild:
|
||||
return
|
||||
await self.config.guild(ctx.guild).log_channel.set(channel.id)
|
||||
await ctx.send(f"Log channel has been set to {channel.mention}")
|
||||
|
||||
async def setup(bot):
|
||||
await bot.add_cog(StaffMsg(bot))
|
||||
|
||||
Reference in New Issue
Block a user