mirror of
https://github.com/System-End/nephthys.git
synced 2026-04-19 18:35:14 +00:00
Delete bot messages and database entries if a thread is deleted (#69)
* Differentiate between message creation and deletion * Add a comment to explain thread_broadcast * If top-level message gets deleted, then delete bot messages * Ensure top-level messages being deleted don't cause errors It would previously freak out when the tombstone message gets deleted :P * Remove deleted tickets from DB * Actually delete the correct ticket * Ensure unexpected SlackApiErrors are re-raised * refactor: Move deleted message handling into its own file
This commit is contained in:
parent
feb251de91
commit
8a83580fe8
3 changed files with 81 additions and 1 deletions
|
|
@ -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"],
|
||||
|
|
|
|||
70
nephthys/events/message_deletion.py
Normal file
70
nephthys/events/message_deletion.py
Normal file
|
|
@ -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)
|
||||
|
|
@ -16,6 +16,7 @@ from nephthys.events.app_home_opened import open_app_home
|
|||
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
|
||||
|
||||
|
|
@ -24,8 +25,16 @@ app = AsyncApp(token=env.slack_bot_token, signing_secret=env.slack_signing_secre
|
|||
|
||||
@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")
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue