diff --git a/zerver/lib/bugdown/__init__.py b/zerver/lib/bugdown/__init__.py index df2374af06..386870862b 100644 --- a/zerver/lib/bugdown/__init__.py +++ b/zerver/lib/bugdown/__init__.py @@ -2114,7 +2114,7 @@ def get_possible_mentions_info(realm_id: int, mention_texts: Set[str]) -> List[F class MentionData: def __init__(self, realm_id: int, content: str) -> None: - mention_texts = possible_mentions(content) + mention_texts, has_wildcards = possible_mentions(content) possible_mentions_info = get_possible_mentions_info(realm_id, mention_texts) self.full_name_info = { row['full_name'].lower(): row @@ -2125,6 +2125,10 @@ class MentionData: for row in possible_mentions_info } self.init_user_group_data(realm_id=realm_id, content=content) + self.has_wildcards = has_wildcards + + def message_has_wildcards(self) -> bool: + return self.has_wildcards def init_user_group_data(self, realm_id: int, diff --git a/zerver/lib/mention.py b/zerver/lib/mention.py index 979aca5829..b1fc0e8e9c 100644 --- a/zerver/lib/mention.py +++ b/zerver/lib/mention.py @@ -12,25 +12,29 @@ wildcards = ['all', 'everyone', 'stream'] def user_mention_matches_wildcard(mention: str) -> bool: return mention in wildcards -def extract_mention_text(m: Tuple[str, str]) -> Optional[str]: +def extract_mention_text(m: Tuple[str, str]) -> Tuple[Optional[str], bool]: # re.findall provides tuples of match elements; we want the second # to get the main mention content. s = m[1] if s.startswith("**") and s.endswith("**"): text = s[2:-2] if text in wildcards: - return None - return text + return None, True + return text, False + return None, False - # We don't care about @all, @everyone or @stream - return None - -def possible_mentions(content: str) -> Set[str]: +def possible_mentions(content: str) -> Tuple[Set[str], bool]: matches = re.findall(find_mentions, content) # mention texts can either be names, or an extended name|id syntax. - texts_with_none = (extract_mention_text(match) for match in matches) - texts = {text for text in texts_with_none if text} - return texts + texts = set() + message_has_wildcards = False + for match in matches: + text, is_wildcard = extract_mention_text(match) + if text: + texts.add(text) + if is_wildcard: + message_has_wildcards = True + return texts, message_has_wildcards def extract_user_group(matched_text: str) -> str: return matched_text[1:-1] diff --git a/zerver/tests/test_bugdown.py b/zerver/tests/test_bugdown.py index 2924de5613..ca28214fdc 100644 --- a/zerver/tests/test_bugdown.py +++ b/zerver/tests/test_bugdown.py @@ -242,6 +242,11 @@ class BugdownMiscTest(ZulipTestCase): assert(user is not None) self.assertEqual(user['email'], hamlet.email) + self.assertFalse(mention_data.message_has_wildcards()) + content = '@**King Hamlet** @**Cordelia lear** @**all**' + mention_data = bugdown.MentionData(realm.id, content) + self.assertTrue(mention_data.message_has_wildcards()) + def test_invalid_katex_path(self) -> None: with self.settings(DEPLOY_ROOT="/nonexistent"): with mock.patch('logging.error') as mock_logger: @@ -1344,17 +1349,17 @@ class BugdownTest(ZulipTestCase): self.assertEqual(msg.mentions_user_ids, set()) def test_possible_mentions(self) -> None: - def assert_mentions(content: str, names: Set[str]) -> None: - self.assertEqual(possible_mentions(content), names) + def assert_mentions(content: str, names: Set[str], has_wildcards: Optional[bool]=False) -> None: + self.assertEqual(possible_mentions(content), (names, has_wildcards)) assert_mentions('', set()) assert_mentions('boring', set()) - assert_mentions('@**all**', set()) + assert_mentions('@**all**', set(), True) assert_mentions('smush@**steve**smush', set()) assert_mentions( 'Hello @**King Hamlet** and @**Cordelia Lear**\n@**Foo van Barson|1234** @**all**', - {'King Hamlet', 'Cordelia Lear', 'Foo van Barson|1234'} + {'King Hamlet', 'Cordelia Lear', 'Foo van Barson|1234'}, True ) def test_mention_multiple(self) -> None: