Skip to content

Commit

Permalink
Implement ?reply command
Browse files Browse the repository at this point in the history
  • Loading branch information
No767 committed Jan 3, 2024
1 parent 8869635 commit 90629bb
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 4 deletions.
86 changes: 83 additions & 3 deletions bot/cogs/tickets.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
from __future__ import annotations

from functools import lru_cache
from typing import TYPE_CHECKING, NamedTuple, Optional, Union
from typing import TYPE_CHECKING, Annotated, NamedTuple, Optional, Union

import asyncpg
import discord
from async_lru import alru_cache
from discord.ext import commands
from discord.utils import format_dt, utcnow
from libs.tickets.structs import ReservedTags, StatusChecklist, TicketThread
from libs.tickets.utils import get_cached_thread, get_partial_ticket
from libs.tickets.utils import (
get_cached_thread,
get_partial_ticket,
safe_content,
)
from libs.utils.embeds import Embed, LoggingEmbed

from .config import GuildWebhookDispatcher

if TYPE_CHECKING:
from libs.utils import RoboContext
from libs.utils import GuildContext, RoboContext

from rodhaj import Rodhaj


Expand All @@ -34,6 +40,19 @@ def pred(ctx: RoboContext) -> bool:
return commands.check(pred)


def is_ticket_thread():
def pred(ctx: RoboContext) -> bool:
partial_config = ctx.partial_config
return (
isinstance(ctx.channel, discord.Thread)
and ctx.guild is not None
and partial_config is not None
and ctx.channel.parent_id == partial_config.ticket_channel_id
)

return commands.check(pred)


class TicketOutput(NamedTuple):
status: bool
ticket: discord.channel.ThreadWithMessage
Expand All @@ -49,6 +68,15 @@ def __init__(self, **kwargs):
self.set_footer(text="Ticket closed at")


class ReplyEmbed(discord.Embed):
def __init__(self, author: Union[discord.User, discord.Member], **kwargs):
kwargs.setdefault("color", discord.Color.from_rgb(246, 194, 255))
kwargs.setdefault("timestamp", discord.utils.utcnow())
super().__init__(**kwargs)
self.set_footer(text="Sent at")
self.set_author(name=author.global_name, icon_url=author.display_avatar.url)


class Tickets(commands.Cog):
"""The main central ticket management hub"""

Expand Down Expand Up @@ -249,6 +277,21 @@ async def create_ticket(self, ticket: TicketThread) -> Optional[TicketOutput]:
msg="Ticket successfully created. In order to use this ticket, please continue sending messages to Rodhaj. The messages will be directed towards the appropriate ticket.",
)

### Obtaining owner of tickets
@alru_cache()
async def get_ticket_owner_id(self, thread_id: int) -> Optional[discord.User]:
query = """
SELECT owner_id
FROM tickets
WHERE thread_id = $1;
"""
owner_id = await self.pool.fetchval(query, thread_id)
if owner_id is None:
self.get_ticket_owner_id.cache_invalidate(thread_id)
return None
user = self.bot.get_user(owner_id) or (await self.bot.fetch_user(owner_id))
return user

### Misc Utils

async def obtain_webhook(self, guild_id: int) -> Optional[discord.Webhook]:
Expand All @@ -271,6 +314,8 @@ def get_solved_tag(
return None
return solved_tag

### Feature commands

@is_ticket_or_dm()
@commands.hybrid_command(name="close", aliases=["solved", "closed", "resolved"])
async def close(self, ctx: RoboContext) -> None:
Expand Down Expand Up @@ -305,8 +350,43 @@ async def close(self, ctx: RoboContext) -> None:
await conn.execute(query, closed_ticket.id, owner_id)
get_cached_thread.cache_invalidate(self.bot, owner_id, self.pool)
get_partial_ticket.cache_invalidate(self.bot, owner_id, self.pool)
self.get_ticket_owner_id.cache_invalidate(closed_ticket.id)
await self.notify_finished_ticket(ctx, owner_id)

@is_ticket_thread()
@commands.command(name="reply", aliases=["r"])
async def reply(
self, ctx: GuildContext, *, message: Annotated[str, commands.clean_content]
) -> None:
"""Replies back to the owner of the active ticket with a message"""
ticket_owner = await self.get_ticket_owner_id(ctx.channel.id)

if ticket_owner is None:
await ctx.send("No owner could be found for the current ticket")
return

dispatcher = GuildWebhookDispatcher(self.bot, ctx.guild.id)
tw = await dispatcher.get_ticket_webhook()
if tw is None:
await ctx.send("Could not find webhook")
return

# We might want to have these as a chain of embeds but eh
embed = ReplyEmbed(author=ctx.author)
embed.description = safe_content(message)
await self.tick_post(ctx)

if isinstance(ctx.channel, discord.Thread):
await tw.send(
content=message,
username=f"[REPLY] {ctx.author.display_name}",
avatar_url=ctx.author.display_avatar.url,
thread=ctx.channel,
)
await ticket_owner.send(embed=embed)

### Ticket information

@is_ticket_or_dm()
@commands.hybrid_command(name="is-active", aliases=["is_active"])
async def is_active(self, ctx: RoboContext) -> None:
Expand Down
2 changes: 1 addition & 1 deletion bot/rodhaj.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ async def on_message(self, message: discord.Message) -> None:
if webhook is not None:
await webhook.send(
message.content,
username=author.display_name,
username=f"[RESPONSE] {author.display_name}",
avatar_url=author.display_avatar.url,
thread=cached_thread.thread,
)
Expand Down

0 comments on commit 90629bb

Please sign in to comment.