Skip to content

Feat: Convert modmail to forum channel, other changes #68

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Aug 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 70 additions & 53 deletions cogs/modmail.py
Original file line number Diff line number Diff line change
@@ -1,55 +1,85 @@
import typing
import aiohttp
from ext.consts import MODMAIL_CHANNEL_ID, MODMAIL_WEBHOOK_URL
from ext.consts import MODMAIL_CHANNEL_ID, MODMAIL_ROLE_ID, MODMAIL_CLOSED, MODMAIL_OPEN
from discord.ext import commands
import discord
from ext.ui.view import YesNoView
import os

def none_if_error(func):
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except Exception:
return None

return wrapper

class ModMail(commands.Cog):
def __init__(self, bot: commands.Bot):
self.bot = bot
self.current_modmail = {}
self.opposite_current_modmail = {}
self.channel: typing.Optional[discord.TextChannel] = None
self.sessions = [] # [{user: discord.Member, thread: discord.Thread}]
self.channel: typing.Optional[discord.ForumChannel] = None

@none_if_error
def get_thread(self, user) -> discord.Thread | None:
return [i['thread'] for i in self.sessions if i['user'] == user][0]

@none_if_error
def get_user(self, thread) -> discord.Member | discord.User | None:
return [i['user'] for i in self.sessions if i['thread'] == thread][0]

async def send_webhook_message(
self,
message: discord.Message,
thread: discord.Thread
):
webhook = thread.parent.webhooks()[0]
await webhook.send(
username=message.author.name,
content=message.content,
avatar_url=message.author.display_avatar.url,
files=message.attachments,
allowed_mentions=discord.AllowedMentions(
users=False, everyone=False, roles=False
),
thread=thread,
)
await message.add_reaction("✅")

async def close_thread(self, thread: discord.Thread):
await thread.add_tags(thread.parent.get_tag(MODMAIL_CLOSED))
await thread.remove_tags(thread.parent.get_tag(MODMAIL_OPEN))
await thread.edit(locked=True, archived=True)
self.sessions.remove({'user': self.get_user(thread), 'thread': thread})

@commands.hybrid_command()
async def close(self, ctx):
if not ctx.guild:
if ctx.author in self.current_modmail:
thread = self.current_modmail[ctx.author]
await thread.edit(locked=True)
self.current_modmail.pop(ctx.author)
self.opposite_current_modmail.pop(thread)
await ctx.send("Your modmail ticket has successfully closed!")
elif ctx.channel in self.opposite_current_modmail:
member = self.opposite_current_modmail[ctx.channel]
async def close(self, ctx: commands.Context):
if not ctx.guild and (thread := self.get_thread(ctx.author)):
await thread.send("This ticket has been closed by the user.")
await self.close_thread(thread)
await ctx.send("Your modmail ticket has successfully closed!")

elif member := self.get_user(ctx.channel):
view = YesNoView(
yes_message="Your modmail ticket has successfully closed!",
no_message="Aborted.",
)
await member.send(content="Do you want to close the ticket?", view=view)
await view.wait()
if view.yes:
await ctx.channel.edit(locked=True)
self.current_modmail.pop(member)
self.opposite_current_modmail.pop(ctx.channel)
await self.close_thread(ctx.channel)
else:
await ctx.channel.send("Member refused to close the ticket.")

@commands.Cog.listener()
async def on_message(self, message: discord.Message):
if (
not self.channel
): # I was unsure if getting the channel in the __init__ is wise
self.channel = self.bot.get_channel(MODMAIL_CHANNEL_ID)
if not self.channel:
self.channel: discord.ForumChannel = self.bot.get_channel(MODMAIL_CHANNEL_ID)

if message.author.bot or message.content.startswith(self.bot.command_prefix):
if message.author.bot or message.content.startswith(self.bot.command_prefix[0]):
return

if not message.guild:
if message.author not in self.current_modmail:
if not (thread := self.get_thread(message.author)):
view = YesNoView(
yes_message="Your modmail ticket has been successfully created!",
no_message="Aborted.",
Expand All @@ -59,37 +89,24 @@ async def on_message(self, message: discord.Message):
)
await view.wait()
if view.yes:
msg_sent = await self.channel.send(
message.content,
thread, _ = await self.channel.create_thread(
name=f"Modmail @{message.author.name}",
content="New ModMail ticket created by "\
f"{message.author.mention}, <@&{MODMAIL_ROLE_ID}>",
files=message.attachments,
allowed_mentions=discord.AllowedMentions(
users=False, everyone=False, roles=False
),
)
thread = await self.channel.create_thread(
name=f"{message.author.name} vs mods", message=msg_sent
applied_tags=[self.channel.get_tag(MODMAIL_OPEN)],
)
self.current_modmail[message.author] = thread
self.opposite_current_modmail[thread] = message.author
await self.send_webhook_message(message, thread)

self.sessions.append({'user': message.author, 'thread': thread})
else:
thread = self.current_modmail[message.author]
async with aiohttp.ClientSession() as session:
webhook = discord.Webhook.from_url(
MODMAIL_WEBHOOK_URL, session=session
)
await webhook.send(
content=message.content,
avatar_url=message.author.display_avatar.url,
files=message.attachments,
allowed_mentions=discord.AllowedMentions(
users=False, everyone=False, roles=False
),
thread=thread,
)
await message.add_reaction("✅")
elif message.channel in self.opposite_current_modmail:
member = self.opposite_current_modmail[message.channel]
await member.send("⚒️ staff: " + message.content, files=message.attachments)
await self.send_webhook_message(message, thread)

elif member := self.get_user(message.channel):
await member.send(
f"⚒️ @{message.author.name}: " + message.content,
files=message.attachments
)


async def setup(bot):
Expand Down
5 changes: 4 additions & 1 deletion ext/consts.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,10 @@ def release_format(self):
READ_HELP_RULES_ROLE_ID = 903133599715459153
TCR_STAFF_ROLE_ID = 795145820210462771
TCR_MEMBER_ROLE_ID = 744403871262179430
MODMAIL_CHANNEL_ID = 1144329989072900106
MODMAIL_CHANNEL_ID = 1144791467391455242 # conch: 1144827896171610185
MODMAIL_ROLE_ID = 788799215417032705
MODMAIL_OPEN = 1144842655671517305 # conch internal: 1144839090609602611
MODMAIL_CLOSED = 1144842686579359837 # conch: 1144839107353256017

# mods pls fill this up
TICKET_CATEGORY_ID = 0
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ bs4==0.0.1
button_paginator @ git+https://github.com/andrewthederp/Button_paginator
charset-normalizer==2.0.12
colorthief==0.2.1
discord.py @ git+https://github.com/Rapptz/discord.py@db5a22d7912557c55fc047f30f42ef10b6a63289
discord.py
DiscordUtils==1.3.4
frozenlist==1.3.0
humanize==4.1.0
Expand Down