markdown: Fix invalid mention bug for user mention.

Modifies `UserMentionPattern` to inherit from InlineProcessor
instead of Pattern. This change is done because Pattern
stopped checking for matching patterns as soon as it found
a match which was not a valid user. Due to this all the
subsequent user mention failed. This bug was only present in
backend renderring due to markdown.inlinepatterns.Pattern.

This was reported as issue #17535.

These changes were tested locally in dev server and by adding
some new markdown tests to test these.
This commit is contained in:
m-e-l-u-h-a-n
2021-03-16 22:49:51 +05:30
committed by Tim Abbott
parent 42aea49784
commit c8979a5100
2 changed files with 38 additions and 6 deletions

View File

@@ -1796,8 +1796,10 @@ class RealmFilterPattern(markdown.inlinepatterns.Pattern):
)
class UserMentionPattern(markdown.inlinepatterns.Pattern):
def handleMatch(self, m: Match[str]) -> Optional[Element]:
class UserMentionPattern(markdown.inlinepatterns.InlineProcessor):
def handleMatch( # type: ignore[override] # supertype incompatible with supersupertype
self, m: Match[str], data: str
) -> Union[Tuple[None, None, None], Tuple[Element, int, int]]:
match = m.group("match")
silent = m.group("silent") == "_"
@@ -1806,7 +1808,7 @@ class UserMentionPattern(markdown.inlinepatterns.Pattern):
if match.startswith("**") and match.endswith("**"):
name = match[2:-2]
else:
return None
return None, None, None
wildcard = mention.user_mention_matches_wildcard(name)
@@ -1827,7 +1829,7 @@ class UserMentionPattern(markdown.inlinepatterns.Pattern):
user_id = str(user["id"])
else:
# Don't highlight @mentions that don't refer to a valid user
return None
return None, None, None
el = Element("span")
el.set("data-user-id", user_id)
@@ -1838,8 +1840,8 @@ class UserMentionPattern(markdown.inlinepatterns.Pattern):
el.set("class", "user-mention")
text = f"@{text}"
el.text = markdown.util.AtomicString(text)
return el
return None
return el, m.start(), m.end()
return None, None, None
class UserGroupMentionPattern(markdown.inlinepatterns.Pattern):

View File

@@ -1845,6 +1845,36 @@ class MarkdownTest(ZulipTestCase):
)
self.assertEqual(msg.mentions_user_ids, set())
def test_mention_invalid_followed_by_valid(self) -> None:
sender_user_profile = self.example_user("othello")
user_profile = self.example_user("hamlet")
msg = Message(sender=sender_user_profile, sending_client=get_client("test"))
user_id = user_profile.id
content = "@**Invalid user** and @**King Hamlet**"
self.assertEqual(
render_markdown(msg, content),
'<p>@<strong>Invalid user</strong> and <span class="user-mention" '
f'data-user-id="{user_id}">'
"@King Hamlet</span></p>",
)
self.assertEqual(msg.mentions_user_ids, {user_profile.id})
def test_silent_mention_invalid_followed_by_valid(self) -> None:
sender_user_profile = self.example_user("othello")
user_profile = self.example_user("hamlet")
msg = Message(sender=sender_user_profile, sending_client=get_client("test"))
user_id = user_profile.id
content = "@_**Invalid user** and @_**King Hamlet**"
self.assertEqual(
render_markdown(msg, content),
'<p>@_<strong>Invalid user</strong> and <span class="user-mention silent" '
f'data-user-id="{user_id}">'
"King Hamlet</span></p>",
)
self.assertEqual(msg.mentions_user_ids, set())
def test_possible_mentions(self) -> None:
def assert_mentions(content: str, names: Set[str], has_wildcards: bool = False) -> None:
self.assertEqual(possible_mentions(content), (names, has_wildcards))