diff --git a/nephthys/events/message.py b/nephthys/events/message.py index 3aed67f..5b4640f 100644 --- a/nephthys/events/message.py +++ b/nephthys/events/message.py @@ -4,6 +4,7 @@ from typing import Dict from slack_sdk.web.async_client import AsyncWebClient from nephthys.data.transcript import Transcript +from nephthys.macros import run_macro from nephthys.utils.env import env from nephthys.utils.logging import send_heartbeat @@ -17,15 +18,30 @@ async def on_message(event: Dict[str, Any], client: AsyncWebClient): if "subtype" in event and event["subtype"] not in ALLOWED_SUBTYPES: return - if event.get("thread_ts"): - return - user = event.get("user", "unknown") text = event.get("text", "") + db_user = await env.db.user.find_first(where={"slackId": user}) + + if event.get("thread_ts") and db_user and db_user.helper: + ticket = await env.db.ticket.find_first( + where={"msgTs": event["thread_ts"]}, + include={"openedBy": True, "tagsOnTickets": True}, + ) + first_word = text.split()[0].lower() + + if first_word[0] == "?" and ticket: + await run_macro( + name=first_word.lstrip("?"), + ticket=ticket, + helper=db_user, + text=text, + macro_ts=event["ts"], + ) + return + thread_url = f"https://hackclub.slack.com/archives/{env.slack_help_channel}/p{event['ts'].replace('.', '')}" - db_user = await env.db.user.find_first(where={"slackId": user}) if db_user: past_tickets = await env.db.ticket.count(where={"openedById": db_user.id}) else: diff --git a/nephthys/macros/__init__.py b/nephthys/macros/__init__.py new file mode 100644 index 0000000..7a03be4 --- /dev/null +++ b/nephthys/macros/__init__.py @@ -0,0 +1,33 @@ +from typing import Any + +from nephthys.macros.hello_world import HelloWorld +from nephthys.macros.resolve import Resolve +from nephthys.utils.env import env +from nephthys.utils.logging import send_heartbeat +from prisma.models import Ticket +from prisma.models import User + + +macros = [Resolve, HelloWorld] + + +async def run_macro( + name: str, ticket: Ticket, helper: User, macro_ts: str, text: str, **kwargs: Any +) -> None | bool: + """ + Run the macro with the given name and arguments. + """ + for macro in macros: + if macro.name == name: + new_kwargs = kwargs.copy() + new_kwargs["text"] = text + await macro().run(ticket, helper, **new_kwargs) + await env.slack_client.chat_delete( + channel=env.slack_help_channel, ts=macro_ts, token=env.slack_user_token + ) + + await send_heartbeat( + f"Macro {name} not found from <@{helper.slackId}.", + messages=[f"Ticket ID: {ticket.id}", f"Helper ID: {helper.id}"], + ) + return False diff --git a/nephthys/macros/hello_world.py b/nephthys/macros/hello_world.py new file mode 100644 index 0000000..ab82880 --- /dev/null +++ b/nephthys/macros/hello_world.py @@ -0,0 +1,22 @@ +from nephthys.macros.types import Macro +from nephthys.utils.env import env + + +class HelloWorld(Macro): + name = "hii" + + async def run(self, ticket, helper, **kwargs): + """ + A simple hello world macro that does nothing. + """ + user_info = await env.slack_client.users_info(user=helper.slackId) + name = ( + user_info["user"]["profile"].get("display_name") + or user_info["user"]["profile"].get("real_name") + or user_info["user"]["name"] + ) + await env.slack_client.chat_postMessage( + text=f"hey, {name}! i'm heidi :rac_shy: say hi to orpheus for me would you? :rac_cute:", + channel=env.slack_help_channel, + thread_ts=ticket.msgTs, + ) diff --git a/nephthys/macros/resolve.py b/nephthys/macros/resolve.py new file mode 100644 index 0000000..721925f --- /dev/null +++ b/nephthys/macros/resolve.py @@ -0,0 +1,28 @@ +from nephthys.actions.resolve import resolve +from nephthys.macros.types import Macro +from nephthys.utils.env import env +from nephthys.utils.logging import send_heartbeat +from prisma.enums import TicketStatus +from prisma.models import Ticket +from prisma.models import User + + +class Resolve(Macro): + name = "resolve" + + async def run(self, ticket: Ticket, helper: User, **kwargs) -> None: + """ + Resolve the ticket with the given arguments. + """ + await send_heartbeat( + f"Resolving ticket with ts {ticket.msgTs} by <@{helper.slackId}>.", + messages=[f"Ticket ID: {ticket.id}", f"Helper ID: {helper.id}"], + ) + if not ticket.status == TicketStatus.CLOSED: + await resolve( + ts=ticket.msgTs, + resolver=helper.slackId, + client=env.slack_client, + ) + else: + raise ValueError("Ticket is already resolved.") diff --git a/nephthys/macros/types.py b/nephthys/macros/types.py new file mode 100644 index 0000000..ca296ec --- /dev/null +++ b/nephthys/macros/types.py @@ -0,0 +1,12 @@ +from prisma.models import Ticket +from prisma.models import User + + +class Macro: + name: str + + async def run(self, ticket: Ticket, helper: User, **kwargs) -> None: + """ + Run the macro with the given arguments. + """ + raise NotImplementedError("Subclasses must implement this method.")