Skip to content
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
1 change: 1 addition & 0 deletions nephthys/events/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ async def on_message(event: Dict[str, Any], client: AsyncWebClient):

db_user = await env.db.user.find_first(where={"slackId": user})

# Messages sent in a thread with the "send to channel" checkbox checked
if event.get("subtype") == "thread_broadcast" and not (db_user and db_user.helper):
await client.chat_delete(
channel=event["channel"],
Expand Down
70 changes: 70 additions & 0 deletions nephthys/events/message_deletion.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import logging
from typing import Any
from typing import Dict

import slack_sdk.errors
from slack_sdk.web.async_client import AsyncWebClient

from nephthys.utils.env import env
from nephthys.utils.logging import send_heartbeat


async def handle_question_deletion(
client: AsyncWebClient, channel: str, deleted_msg: Dict[str, Any]
) -> None:
"""Handle deletion of a top-level question message in the help channel.

- If the thread has non-bot messages, do nothing.
- Otherwise, deletes the bot messages in the thread and removes the ticket from the DB.
- This behaviour is similar to `?thread`, except it removes the ticket from the DB instead of marking it as resolved.
"""
try:
thread_history = await client.conversations_replies(
channel=channel, ts=deleted_msg["ts"]
)
except slack_sdk.errors.SlackApiError as e:
if e.response.get("error") == "thread_not_found":
# Nothing to clean up; we good
return
else:
raise e
bot_info = await env.slack_client.auth_test()
bot_user_id = bot_info.get("user_id")
messages_to_delete = []
for msg in thread_history["messages"]:
if msg["user"] == bot_user_id:
messages_to_delete.append(msg)
elif msg["ts"] != deleted_msg["ts"]:
# Don't clear the thread if there are non-bot messages in there
return

# Delete ticket from DB
await env.db.ticket.delete(where={"msgTs": deleted_msg["ts"]})

# Delete messages
await send_heartbeat(
f"Removing my {len(messages_to_delete)} message(s) in a thread because the question was deleted."
)
for msg in messages_to_delete:
await client.chat_delete(
channel=channel,
ts=msg["ts"],
)


async def on_message_deletion(event: Dict[str, Any], client: AsyncWebClient) -> None:
"""Handles the two types of message deletion events
(i.e. a message being turned into a tombstone, and a message being fully deleted)."""
if event.get("subtype") == "message_deleted":
# This means the message has been completely deleted with out leaving a "tombstone", so no cleanup to do
return
deleted_msg = event.get("previous_message")
if not deleted_msg:
logging.warning("No previous_message found in message deletion event")
return
is_top_level_message = (
"thread_ts" not in deleted_msg or deleted_msg["ts"] == deleted_msg["thread_ts"]
)
if is_top_level_message:
# A question (i.e. top-level message in help channel) has been deleted
await handle_question_deletion(client, event["channel"], deleted_msg)
11 changes: 10 additions & 1 deletion nephthys/utils/slack.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from nephthys.events.channel_join import channel_join
from nephthys.events.channel_left import channel_left
from nephthys.events.message import on_message
from nephthys.events.message_deletion import on_message_deletion
from nephthys.options.tags import get_tags
from nephthys.utils.env import env

Expand All @@ -24,8 +25,16 @@

@app.event("message")
async def handle_message(event: Dict[str, Any], client: AsyncWebClient):
print(event)
is_message_deletion = (
event.get("subtype") == "message_changed"
and event["message"]["subtype"] == "tombstone"
) or event.get("subtype") == "message_deleted"
if event["channel"] == env.slack_help_channel:
await on_message(event, client)
if is_message_deletion:
await on_message_deletion(event, client)
else:
await on_message(event, client)


@app.action("mark_resolved")
Expand Down