Skip to content

Commit

Permalink
Catch error if edited tech-support message has already been reacted to
Browse files Browse the repository at this point in the history
  • Loading branch information
rebkwok committed Jan 12, 2024
1 parent a054c43 commit d8fdb02
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 3 deletions.
22 changes: 20 additions & 2 deletions ebmbot/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from slack_bolt.adapter.socket_mode import SocketModeHandler
from slack_bolt.error import BoltUnhandledRequestError
from slack_bolt.util.utils import get_boot_message
from slack_sdk.errors import SlackApiError

from workspace.techsupport.jobs import get_dates_from_config as get_tech_support_dates

Expand Down Expand Up @@ -204,6 +205,10 @@ def _repost_to_tech_support(message, say, ack):
# Don't repost messages in DMs with the bot
if message["channel_type"] in ["channel", "group"]:
# Respond with SOS reaction
# If we've already responded, the attempt to react here will raise
# an exception; if this happens, then the user is editing something
# other than the tech-support keyword in the message, and we don't need to
# repost it again. We let the default error handler will deal with it.
app.client.reactions_add(
channel=message["channel"], timestamp=message["ts"], name="sos"
)
Expand Down Expand Up @@ -239,15 +244,28 @@ def join_channel(event, ack):

@app.error
def handle_errors(error, body):
message_text = body["event"].get("message", {}).get("text", "")
if isinstance(error, BoltUnhandledRequestError):
# Unhandled messages are common (anything that doesn't get matched
# by one of the listeners). We don't want to log those.
return BoltResponse(status=200, body="Unhandled message")
elif (
isinstance(error, SlackApiError)
and error.response.data["error"] == "already_reacted"
and "tech-support" in message_text
):
# If we're already reacted to a tech-support message and the
# user edits the message, we get a slack error, but that's OK
logger.info(
"Already reacted to tech-support message",
message=message_text,
)
return BoltResponse(
status=200, body="Already reacted to tech-support message"
)
else:
# other error patterns
channel = body["event"]["channel"]
message_text = body["event"].get("message", {}).get("text", "")

ts = body["event"]["ts"]
logger.error("Unexpected error", error=error, body=body)
app.client.reactions_add(channel=channel, timestamp=ts, name="x")
Expand Down
52 changes: 51 additions & 1 deletion tests/test_bot.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import json
import time
from datetime import datetime, timedelta
from unittest.mock import patch
from unittest.mock import Mock, patch

import pytest
from slack_bolt.request import BoltRequest
from slack_sdk.errors import SlackApiError
from slack_sdk.signature import SignatureVerifier

from ebmbot import bot, scheduler
Expand Down Expand Up @@ -522,6 +523,55 @@ def test_unexpected_error(mock_app):
)


def test_already_reacted_to_tech_support_error(mock_app):
# mock an error from a method that's called during the tech-support
# handling to return an "already reacted" SlackApiError
with patch(
"ebmbot.bot.tech_support_out_of_office",
side_effect=SlackApiError(
message="Error", response=Mock(data={"error": "already_reacted"})
),
):
handle_message(
mock_app,
"tech-support help",
channel="channel",
reaction_count=1,
event_type="message",
expected_status=200,
)

assert_slack_client_sends_messages(
mock_app.recorder,
messages_kwargs=[],
)


def test_already_reacted_to_non_tech_support_error(mock_app):
# Only already-reacted to tech support messages are ignored;
# another sort of message that raises this error gets
# reported back to slack
with patch(
"ebmbot.bot.handle_namespace_help",
side_effect=SlackApiError(
message="Error", response=Mock(data={"error": "already_reacted"})
),
):
handle_message(
mock_app, "<@U1234> test help", reaction_count=1, expected_status=500
)

assert_slack_client_sends_messages(
mock_app.recorder,
messages_kwargs=[
{
"channel": "channel",
"text": "Unexpected error: SlackApiError",
}
],
)


def test_new_channel_created(mock_app):
# When a channel_created event is received, the bot user joins that channel
handle_event(
Expand Down

0 comments on commit d8fdb02

Please sign in to comment.