Ver Fonte

Cover messages that name several people

Multiple mentions worked but nothing pinned the behaviour down, and one
case contradicted the rule we settled on: "@here @bob" fell silent even
though @here keeps the bot in the audience — naming a colleague as well
does not take it out. Treat a broadcast handle as addressing us whatever
else the message names.

Also locks in that the scan does not stop at the first token it cannot
resolve, so "@nonexistent @bob" is still recognised as bob's.
Paul Klumpp há 1 semana atrás
pai
commit
9c4cc5a136
2 ficheiros alterados com 41 adições e 2 exclusões
  1. 10 2
      adapter.py
  2. 31 0
      test_adapter.py

+ 10 - 2
adapter.py

@@ -496,13 +496,21 @@ class ChattoAdapter(BasePlatformAdapter):
     # ------------------------------------------------------------------ #
 
     def _mentions_me(self, body: str) -> bool:
-        """Whether the message @-mentions this bot, by login or display name."""
+        """Whether the message addresses this bot.
+
+        By login, by display name, or by a broadcast handle — ``@here`` speaks
+        to everyone present and the bot is one of them, so naming a colleague
+        alongside it does not take the bot out of the audience.
+        """
         if not self.me:
             return False
         for handle in (self.me.login, self.me.display_name):
             if handle and f"@{handle}" in body:
                 return True
-        return False
+        return any(
+            handle.lower() in ChattoConstants.BROADCAST_MENTIONS
+            for handle in ChattoConstants.MENTION_RE.findall(body)
+        )
 
     async def _handle_belongs_to_a_user(self, handle: str) -> bool:
         """Whether ``handle`` is the login of a real Chatto user.

+ 31 - 0
test_adapter.py

@@ -899,6 +899,37 @@ class TestForeignMention:
         adapter.handle_message.assert_called_once()
         adapter.add_reaction.assert_not_awaited()
 
+    async def test_several_people_addressed_and_none_of_them_us(self):
+        adapter = self._adapter()
+        adapter._chatto_client.get_user = AsyncMock(side_effect=lambda **kw: (
+            DirectoryMember(user=_make_user("u", kw["login"]))
+            if kw.get("login") in {"bob", "carol"} else None
+        ))
+        await self._dispatch(adapter, "@bob @carol schaut mal drüber")
+        adapter.handle_message.assert_not_called()
+        adapter.add_reaction.assert_awaited_once()
+
+    async def test_a_real_handle_after_an_unknown_one_still_counts(self):
+        """The scan must not stop at the first token it cannot resolve."""
+        adapter = self._adapter()
+        await self._dispatch(adapter, "@nonexistent @bob schaut mal drüber")
+        adapter.handle_message.assert_not_called()
+        adapter.add_reaction.assert_awaited_once()
+
+    async def test_being_named_among_several_others_still_answers(self):
+        adapter = self._adapter()
+        await self._dispatch(adapter, "@bob @hermes_bot @carol — was meint ihr?")
+        adapter.handle_message.assert_called_once()
+        adapter.add_reaction.assert_not_awaited()
+
+    async def test_broadcast_alongside_a_named_colleague_still_answers(self):
+        """@here keeps the bot in the audience; naming bob as well does not
+        remove it."""
+        adapter = self._adapter()
+        await self._dispatch(adapter, "@here @bob schaut mal drüber")
+        adapter.handle_message.assert_called_once()
+        adapter.add_reaction.assert_not_awaited()
+
     async def test_broadcast_mentions_address_the_bot_too(self):
         adapter = self._adapter()
         for body in ("@here standup in 5", "@channel heads up", "@everyone hi"):