mirror of
https://github.com/zulip/zulip.git
synced 2025-10-23 16:14:02 +00:00
markdown: Store ZulipMarkdown in members with the right type.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
(cherry picked from commit 8230324068
)
This commit is contained in:
committed by
Tim Abbott
parent
07e1e47db3
commit
d509cd0a0f
@@ -584,13 +584,17 @@ class InlineImageProcessor(markdown.treeprocessors.Treeprocessor):
|
|||||||
view.
|
view.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
def __init__(self, zmd: "ZulipMarkdown") -> None:
|
||||||
|
super().__init__(zmd)
|
||||||
|
self.zmd = zmd
|
||||||
|
|
||||||
def run(self, root: Element) -> None:
|
def run(self, root: Element) -> None:
|
||||||
# Get all URLs from the blob
|
# Get all URLs from the blob
|
||||||
found_imgs = walk_tree(root, lambda e: e if e.tag == "img" else None)
|
found_imgs = walk_tree(root, lambda e: e if e.tag == "img" else None)
|
||||||
for img in found_imgs:
|
for img in found_imgs:
|
||||||
url = img.get("src")
|
url = img.get("src")
|
||||||
assert url is not None
|
assert url is not None
|
||||||
if is_static_or_current_realm_url(url, self.md.zulip_realm):
|
if is_static_or_current_realm_url(url, self.zmd.zulip_realm):
|
||||||
# Don't rewrite images on our own site (e.g. emoji, user uploads).
|
# Don't rewrite images on our own site (e.g. emoji, user uploads).
|
||||||
continue
|
continue
|
||||||
img.set("src", get_camo_url(url))
|
img.set("src", get_camo_url(url))
|
||||||
@@ -622,6 +626,10 @@ class InlineInterestingLinkProcessor(markdown.treeprocessors.Treeprocessor):
|
|||||||
TWITTER_MAX_TO_PREVIEW = 3
|
TWITTER_MAX_TO_PREVIEW = 3
|
||||||
INLINE_PREVIEW_LIMIT_PER_MESSAGE = 10
|
INLINE_PREVIEW_LIMIT_PER_MESSAGE = 10
|
||||||
|
|
||||||
|
def __init__(self, zmd: "ZulipMarkdown") -> None:
|
||||||
|
super().__init__(zmd)
|
||||||
|
self.zmd = zmd
|
||||||
|
|
||||||
def add_a(
|
def add_a(
|
||||||
self,
|
self,
|
||||||
root: Element,
|
root: Element,
|
||||||
@@ -637,8 +645,8 @@ class InlineInterestingLinkProcessor(markdown.treeprocessors.Treeprocessor):
|
|||||||
desc = desc if desc is not None else ""
|
desc = desc if desc is not None else ""
|
||||||
|
|
||||||
# Update message.has_image attribute.
|
# Update message.has_image attribute.
|
||||||
if "message_inline_image" in class_attr and self.md.zulip_message:
|
if "message_inline_image" in class_attr and self.zmd.zulip_message:
|
||||||
self.md.zulip_message.has_image = True
|
self.zmd.zulip_message.has_image = True
|
||||||
|
|
||||||
if insertion_index is not None:
|
if insertion_index is not None:
|
||||||
div = Element("div")
|
div = Element("div")
|
||||||
@@ -753,7 +761,7 @@ class InlineInterestingLinkProcessor(markdown.treeprocessors.Treeprocessor):
|
|||||||
return url
|
return url
|
||||||
|
|
||||||
def is_image(self, url: str) -> bool:
|
def is_image(self, url: str) -> bool:
|
||||||
if not self.md.image_preview_enabled:
|
if not self.zmd.image_preview_enabled:
|
||||||
return False
|
return False
|
||||||
parsed_url = urllib.parse.urlparse(url)
|
parsed_url = urllib.parse.urlparse(url)
|
||||||
# remove HTML URLs which end with image extensions that can not be shorted
|
# remove HTML URLs which end with image extensions that can not be shorted
|
||||||
@@ -828,7 +836,7 @@ class InlineInterestingLinkProcessor(markdown.treeprocessors.Treeprocessor):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
def youtube_id(self, url: str) -> Optional[str]:
|
def youtube_id(self, url: str) -> Optional[str]:
|
||||||
if not self.md.image_preview_enabled:
|
if not self.zmd.image_preview_enabled:
|
||||||
return None
|
return None
|
||||||
# YouTube video id extraction regular expression from https://pastebin.com/KyKAFv1s
|
# YouTube video id extraction regular expression from https://pastebin.com/KyKAFv1s
|
||||||
# Slightly modified to support URLs of the forms
|
# Slightly modified to support URLs of the forms
|
||||||
@@ -866,7 +874,7 @@ class InlineInterestingLinkProcessor(markdown.treeprocessors.Treeprocessor):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
def vimeo_id(self, url: str) -> Optional[str]:
|
def vimeo_id(self, url: str) -> Optional[str]:
|
||||||
if not self.md.image_preview_enabled:
|
if not self.zmd.image_preview_enabled:
|
||||||
return None
|
return None
|
||||||
# (http|https)?:\/\/(www\.)?vimeo.com\/(?:channels\/(?:\w+\/)?|groups\/([^\/]*)\/videos\/|)(\d+)(?:|\/\?)
|
# (http|https)?:\/\/(www\.)?vimeo.com\/(?:channels\/(?:\w+\/)?|groups\/([^\/]*)\/videos\/|)(\d+)(?:|\/\?)
|
||||||
# If it matches, match.group('id') is the video id.
|
# If it matches, match.group('id') is the video id.
|
||||||
@@ -985,7 +993,7 @@ class InlineInterestingLinkProcessor(markdown.treeprocessors.Treeprocessor):
|
|||||||
else:
|
else:
|
||||||
current_node.tail = text
|
current_node.tail = text
|
||||||
|
|
||||||
db_data: Optional[DbData] = self.md.zulip_db_data
|
db_data: Optional[DbData] = self.zmd.zulip_db_data
|
||||||
current_index = 0
|
current_index = 0
|
||||||
for item in to_process:
|
for item in to_process:
|
||||||
# The text we want to link starts in already linked text skip it
|
# The text we want to link starts in already linked text skip it
|
||||||
@@ -1226,9 +1234,9 @@ class InlineInterestingLinkProcessor(markdown.treeprocessors.Treeprocessor):
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Set has_link and similar flags whenever a message is processed by Markdown
|
# Set has_link and similar flags whenever a message is processed by Markdown
|
||||||
if self.md.zulip_message:
|
if self.zmd.zulip_message:
|
||||||
self.md.zulip_message.has_link = len(found_urls) > 0
|
self.zmd.zulip_message.has_link = len(found_urls) > 0
|
||||||
self.md.zulip_message.has_image = False # This is updated in self.add_a
|
self.zmd.zulip_message.has_image = False # This is updated in self.add_a
|
||||||
|
|
||||||
for url in unique_urls:
|
for url in unique_urls:
|
||||||
# Due to rewrite_local_links_to_relative, we need to
|
# Due to rewrite_local_links_to_relative, we need to
|
||||||
@@ -1239,14 +1247,16 @@ class InlineInterestingLinkProcessor(markdown.treeprocessors.Treeprocessor):
|
|||||||
parsed_url = urllib.parse.urlsplit(urllib.parse.urljoin("/", url))
|
parsed_url = urllib.parse.urlsplit(urllib.parse.urljoin("/", url))
|
||||||
host = parsed_url.netloc
|
host = parsed_url.netloc
|
||||||
|
|
||||||
if host != "" and (self.md.zulip_realm is None or host != self.md.zulip_realm.host):
|
if host != "" and (
|
||||||
|
self.zmd.zulip_realm is None or host != self.zmd.zulip_realm.host
|
||||||
|
):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if not parsed_url.path.startswith("/user_uploads/"):
|
if not parsed_url.path.startswith("/user_uploads/"):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
path_id = parsed_url.path[len("/user_uploads/") :]
|
path_id = parsed_url.path[len("/user_uploads/") :]
|
||||||
self.md.zulip_rendering_result.potential_attachment_path_ids.append(path_id)
|
self.zmd.zulip_rendering_result.potential_attachment_path_ids.append(path_id)
|
||||||
|
|
||||||
if len(found_urls) == 0:
|
if len(found_urls) == 0:
|
||||||
return
|
return
|
||||||
@@ -1295,7 +1305,7 @@ class InlineInterestingLinkProcessor(markdown.treeprocessors.Treeprocessor):
|
|||||||
|
|
||||||
netloc = urlsplit(url).netloc
|
netloc = urlsplit(url).netloc
|
||||||
if netloc == "" or (
|
if netloc == "" or (
|
||||||
self.md.zulip_realm is not None and netloc == self.md.zulip_realm.host
|
self.zmd.zulip_realm is not None and netloc == self.zmd.zulip_realm.host
|
||||||
):
|
):
|
||||||
# We don't have a strong use case for doing URL preview for relative links.
|
# We don't have a strong use case for doing URL preview for relative links.
|
||||||
continue
|
continue
|
||||||
@@ -1320,20 +1330,20 @@ class InlineInterestingLinkProcessor(markdown.treeprocessors.Treeprocessor):
|
|||||||
# is enabled, but URL previews are a beta feature and YouTube
|
# is enabled, but URL previews are a beta feature and YouTube
|
||||||
# previews are pretty stable.
|
# previews are pretty stable.
|
||||||
|
|
||||||
db_data: Optional[DbData] = self.md.zulip_db_data
|
db_data: Optional[DbData] = self.zmd.zulip_db_data
|
||||||
if db_data and db_data.sent_by_bot:
|
if db_data and db_data.sent_by_bot:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if not self.md.url_embed_preview_enabled:
|
if not self.zmd.url_embed_preview_enabled:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if self.md.url_embed_data is None or url not in self.md.url_embed_data:
|
if self.zmd.url_embed_data is None or url not in self.zmd.url_embed_data:
|
||||||
self.md.zulip_rendering_result.links_for_preview.add(url)
|
self.zmd.zulip_rendering_result.links_for_preview.add(url)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Existing but being None means that we did process the
|
# Existing but being None means that we did process the
|
||||||
# URL, but it was not valid to preview.
|
# URL, but it was not valid to preview.
|
||||||
extracted_data = self.md.url_embed_data[url]
|
extracted_data = self.zmd.url_embed_data[url]
|
||||||
if extracted_data is None:
|
if extracted_data is None:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@@ -1356,12 +1366,13 @@ class InlineInterestingLinkProcessor(markdown.treeprocessors.Treeprocessor):
|
|||||||
|
|
||||||
|
|
||||||
class CompiledInlineProcessor(markdown.inlinepatterns.InlineProcessor):
|
class CompiledInlineProcessor(markdown.inlinepatterns.InlineProcessor):
|
||||||
def __init__(self, compiled_re: Pattern[str], md: markdown.Markdown) -> None:
|
def __init__(self, compiled_re: Pattern[str], zmd: "ZulipMarkdown") -> None:
|
||||||
# This is similar to the superclass's small __init__ function,
|
# This is similar to the superclass's small __init__ function,
|
||||||
# but we skip the compilation step and let the caller give us
|
# but we skip the compilation step and let the caller give us
|
||||||
# a compiled regex.
|
# a compiled regex.
|
||||||
self.compiled_re = compiled_re
|
self.compiled_re = compiled_re
|
||||||
self.md = md
|
self.md = zmd
|
||||||
|
self.zmd = zmd
|
||||||
|
|
||||||
|
|
||||||
class Timestamp(markdown.inlinepatterns.Pattern):
|
class Timestamp(markdown.inlinepatterns.Pattern):
|
||||||
@@ -1476,8 +1487,12 @@ def unicode_emoji_to_codepoint(unicode_emoji: str) -> str:
|
|||||||
class EmoticonTranslation(markdown.inlinepatterns.Pattern):
|
class EmoticonTranslation(markdown.inlinepatterns.Pattern):
|
||||||
"""Translates emoticons like `:)` into emoji like `:smile:`."""
|
"""Translates emoticons like `:)` into emoji like `:smile:`."""
|
||||||
|
|
||||||
|
def __init__(self, pattern: str, zmd: "ZulipMarkdown") -> None:
|
||||||
|
super().__init__(pattern, zmd)
|
||||||
|
self.zmd = zmd
|
||||||
|
|
||||||
def handleMatch(self, match: Match[str]) -> Optional[Element]:
|
def handleMatch(self, match: Match[str]) -> Optional[Element]:
|
||||||
db_data: Optional[DbData] = self.md.zulip_db_data
|
db_data: Optional[DbData] = self.zmd.zulip_db_data
|
||||||
if db_data is None or not db_data.translate_emoticons:
|
if db_data is None or not db_data.translate_emoticons:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -1499,12 +1514,16 @@ class UnicodeEmoji(markdown.inlinepatterns.Pattern):
|
|||||||
|
|
||||||
|
|
||||||
class Emoji(markdown.inlinepatterns.Pattern):
|
class Emoji(markdown.inlinepatterns.Pattern):
|
||||||
|
def __init__(self, pattern: str, zmd: "ZulipMarkdown") -> None:
|
||||||
|
super().__init__(pattern, zmd)
|
||||||
|
self.zmd = zmd
|
||||||
|
|
||||||
def handleMatch(self, match: Match[str]) -> Optional[Union[str, Element]]:
|
def handleMatch(self, match: Match[str]) -> Optional[Union[str, Element]]:
|
||||||
orig_syntax = match.group("syntax")
|
orig_syntax = match.group("syntax")
|
||||||
name = orig_syntax[1:-1]
|
name = orig_syntax[1:-1]
|
||||||
|
|
||||||
active_realm_emoji: Dict[str, EmojiInfo] = {}
|
active_realm_emoji: Dict[str, EmojiInfo] = {}
|
||||||
db_data: Optional[DbData] = self.md.zulip_db_data
|
db_data: Optional[DbData] = self.zmd.zulip_db_data
|
||||||
if db_data is not None:
|
if db_data is not None:
|
||||||
active_realm_emoji = db_data.active_realm_emoji
|
active_realm_emoji = db_data.active_realm_emoji
|
||||||
|
|
||||||
@@ -1525,7 +1544,7 @@ def content_has_emoji_syntax(content: str) -> bool:
|
|||||||
|
|
||||||
|
|
||||||
class Tex(markdown.inlinepatterns.Pattern):
|
class Tex(markdown.inlinepatterns.Pattern):
|
||||||
def handleMatch(self, match: Match[str]) -> Element:
|
def handleMatch(self, match: Match[str]) -> Union[str, Element]:
|
||||||
rendered = render_tex(match.group("body"), is_inline=True)
|
rendered = render_tex(match.group("body"), is_inline=True)
|
||||||
if rendered is not None:
|
if rendered is not None:
|
||||||
return self.md.htmlStash.store(rendered)
|
return self.md.htmlStash.store(rendered)
|
||||||
@@ -1605,18 +1624,19 @@ def url_to_a(
|
|||||||
|
|
||||||
|
|
||||||
class CompiledPattern(markdown.inlinepatterns.Pattern):
|
class CompiledPattern(markdown.inlinepatterns.Pattern):
|
||||||
def __init__(self, compiled_re: Pattern[str], md: markdown.Markdown) -> None:
|
def __init__(self, compiled_re: Pattern[str], zmd: "ZulipMarkdown") -> None:
|
||||||
# This is similar to the superclass's small __init__ function,
|
# This is similar to the superclass's small __init__ function,
|
||||||
# but we skip the compilation step and let the caller give us
|
# but we skip the compilation step and let the caller give us
|
||||||
# a compiled regex.
|
# a compiled regex.
|
||||||
self.compiled_re = compiled_re
|
self.compiled_re = compiled_re
|
||||||
self.md = md
|
self.md = zmd
|
||||||
|
self.zmd = zmd
|
||||||
|
|
||||||
|
|
||||||
class AutoLink(CompiledPattern):
|
class AutoLink(CompiledPattern):
|
||||||
def handleMatch(self, match: Match[str]) -> ElementStringNone:
|
def handleMatch(self, match: Match[str]) -> ElementStringNone:
|
||||||
url = match.group("url")
|
url = match.group("url")
|
||||||
db_data: Optional[DbData] = self.md.zulip_db_data
|
db_data: Optional[DbData] = self.zmd.zulip_db_data
|
||||||
return url_to_a(db_data, url)
|
return url_to_a(db_data, url)
|
||||||
|
|
||||||
|
|
||||||
@@ -1790,7 +1810,7 @@ class LinkifierPattern(CompiledInlineProcessor):
|
|||||||
self,
|
self,
|
||||||
source_pattern: str,
|
source_pattern: str,
|
||||||
format_string: str,
|
format_string: str,
|
||||||
md: markdown.Markdown,
|
zmd: "ZulipMarkdown",
|
||||||
) -> None:
|
) -> None:
|
||||||
# Do not write errors to stderr (this still raises exceptions)
|
# Do not write errors to stderr (this still raises exceptions)
|
||||||
options = re2.Options()
|
options = re2.Options()
|
||||||
@@ -1813,12 +1833,12 @@ class LinkifierPattern(CompiledInlineProcessor):
|
|||||||
r"(?<!%)(%%)*%([a-fA-F0-9][a-fA-F0-9])", r"\1%%\2", format_string
|
r"(?<!%)(%%)*%([a-fA-F0-9][a-fA-F0-9])", r"\1%%\2", format_string
|
||||||
)
|
)
|
||||||
|
|
||||||
super().__init__(compiled_re2, md)
|
super().__init__(compiled_re2, zmd)
|
||||||
|
|
||||||
def handleMatch( # type: ignore[override] # supertype incompatible with supersupertype
|
def handleMatch( # type: ignore[override] # supertype incompatible with supersupertype
|
||||||
self, m: Match[str], data: str
|
self, m: Match[str], data: str
|
||||||
) -> Union[Tuple[Element, int, int], Tuple[None, None, None]]:
|
) -> Union[Tuple[Element, int, int], Tuple[None, None, None]]:
|
||||||
db_data: Optional[DbData] = self.md.zulip_db_data
|
db_data: Optional[DbData] = self.zmd.zulip_db_data
|
||||||
url = url_to_a(
|
url = url_to_a(
|
||||||
db_data,
|
db_data,
|
||||||
self.format_string % m.groupdict(),
|
self.format_string % m.groupdict(),
|
||||||
@@ -1840,7 +1860,7 @@ class UserMentionPattern(CompiledInlineProcessor):
|
|||||||
) -> Union[Tuple[None, None, None], Tuple[Element, int, int]]:
|
) -> Union[Tuple[None, None, None], Tuple[Element, int, int]]:
|
||||||
name = m.group("match")
|
name = m.group("match")
|
||||||
silent = m.group("silent") == "_"
|
silent = m.group("silent") == "_"
|
||||||
db_data: Optional[DbData] = self.md.zulip_db_data
|
db_data: Optional[DbData] = self.zmd.zulip_db_data
|
||||||
if db_data is not None:
|
if db_data is not None:
|
||||||
wildcard = mention.user_mention_matches_wildcard(name)
|
wildcard = mention.user_mention_matches_wildcard(name)
|
||||||
|
|
||||||
@@ -1864,13 +1884,13 @@ class UserMentionPattern(CompiledInlineProcessor):
|
|||||||
|
|
||||||
if wildcard:
|
if wildcard:
|
||||||
if not silent:
|
if not silent:
|
||||||
self.md.zulip_rendering_result.mentions_wildcard = True
|
self.zmd.zulip_rendering_result.mentions_wildcard = True
|
||||||
user_id = "*"
|
user_id = "*"
|
||||||
elif user is not None:
|
elif user is not None:
|
||||||
assert isinstance(user, FullNameInfo)
|
assert isinstance(user, FullNameInfo)
|
||||||
|
|
||||||
if not silent:
|
if not silent:
|
||||||
self.md.zulip_rendering_result.mentions_user_ids.add(user.id)
|
self.zmd.zulip_rendering_result.mentions_user_ids.add(user.id)
|
||||||
name = user.full_name
|
name = user.full_name
|
||||||
user_id = str(user.id)
|
user_id = str(user.id)
|
||||||
else:
|
else:
|
||||||
@@ -1896,13 +1916,13 @@ class UserGroupMentionPattern(CompiledInlineProcessor):
|
|||||||
) -> Union[Tuple[None, None, None], Tuple[Element, int, int]]:
|
) -> Union[Tuple[None, None, None], Tuple[Element, int, int]]:
|
||||||
name = m.group("match")
|
name = m.group("match")
|
||||||
silent = m.group("silent") == "_"
|
silent = m.group("silent") == "_"
|
||||||
db_data: Optional[DbData] = self.md.zulip_db_data
|
db_data: Optional[DbData] = self.zmd.zulip_db_data
|
||||||
|
|
||||||
if db_data is not None:
|
if db_data is not None:
|
||||||
user_group = db_data.mention_data.get_user_group(name)
|
user_group = db_data.mention_data.get_user_group(name)
|
||||||
if user_group:
|
if user_group:
|
||||||
if not silent:
|
if not silent:
|
||||||
self.md.zulip_rendering_result.mentions_user_group_ids.add(user_group.id)
|
self.zmd.zulip_rendering_result.mentions_user_group_ids.add(user_group.id)
|
||||||
name = user_group.name
|
name = user_group.name
|
||||||
user_group_id = str(user_group.id)
|
user_group_id = str(user_group.id)
|
||||||
else:
|
else:
|
||||||
@@ -1925,7 +1945,7 @@ class UserGroupMentionPattern(CompiledInlineProcessor):
|
|||||||
|
|
||||||
class StreamPattern(CompiledInlineProcessor):
|
class StreamPattern(CompiledInlineProcessor):
|
||||||
def find_stream_id(self, name: str) -> Optional[int]:
|
def find_stream_id(self, name: str) -> Optional[int]:
|
||||||
db_data: Optional[DbData] = self.md.zulip_db_data
|
db_data: Optional[DbData] = self.zmd.zulip_db_data
|
||||||
if db_data is None:
|
if db_data is None:
|
||||||
return None
|
return None
|
||||||
stream_id = db_data.stream_names.get(name)
|
stream_id = db_data.stream_names.get(name)
|
||||||
@@ -1956,7 +1976,7 @@ class StreamPattern(CompiledInlineProcessor):
|
|||||||
|
|
||||||
class StreamTopicPattern(CompiledInlineProcessor):
|
class StreamTopicPattern(CompiledInlineProcessor):
|
||||||
def find_stream_id(self, name: str) -> Optional[int]:
|
def find_stream_id(self, name: str) -> Optional[int]:
|
||||||
db_data: Optional[DbData] = self.md.zulip_db_data
|
db_data: Optional[DbData] = self.zmd.zulip_db_data
|
||||||
if db_data is None:
|
if db_data is None:
|
||||||
return None
|
return None
|
||||||
stream_id = db_data.stream_names.get(name)
|
stream_id = db_data.stream_names.get(name)
|
||||||
@@ -2010,6 +2030,10 @@ class AlertWordNotificationProcessor(markdown.preprocessors.Preprocessor):
|
|||||||
"`",
|
"`",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def __init__(self, zmd: "ZulipMarkdown") -> None:
|
||||||
|
super().__init__(zmd)
|
||||||
|
self.zmd = zmd
|
||||||
|
|
||||||
def check_valid_start_position(self, content: str, index: int) -> bool:
|
def check_valid_start_position(self, content: str, index: int) -> bool:
|
||||||
if index <= 0 or content[index] in self.allowed_before_punctuation:
|
if index <= 0 or content[index] in self.allowed_before_punctuation:
|
||||||
return True
|
return True
|
||||||
@@ -2021,14 +2045,14 @@ class AlertWordNotificationProcessor(markdown.preprocessors.Preprocessor):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def run(self, lines: List[str]) -> List[str]:
|
def run(self, lines: List[str]) -> List[str]:
|
||||||
db_data: Optional[DbData] = self.md.zulip_db_data
|
db_data: Optional[DbData] = self.zmd.zulip_db_data
|
||||||
if db_data is not None:
|
if db_data is not None:
|
||||||
# We check for alert words here, the set of which are
|
# We check for alert words here, the set of which are
|
||||||
# dependent on which users may see this message.
|
# dependent on which users may see this message.
|
||||||
#
|
#
|
||||||
# Our caller passes in the list of possible_words. We
|
# Our caller passes in the list of possible_words. We
|
||||||
# don't do any special rendering; we just append the alert words
|
# don't do any special rendering; we just append the alert words
|
||||||
# we find to the set self.md.zulip_rendering_result.user_ids_with_alert_words.
|
# we find to the set self.zmd.zulip_rendering_result.user_ids_with_alert_words.
|
||||||
|
|
||||||
realm_alert_words_automaton = db_data.realm_alert_words_automaton
|
realm_alert_words_automaton = db_data.realm_alert_words_automaton
|
||||||
|
|
||||||
@@ -2040,11 +2064,15 @@ class AlertWordNotificationProcessor(markdown.preprocessors.Preprocessor):
|
|||||||
if self.check_valid_start_position(
|
if self.check_valid_start_position(
|
||||||
content, end_index - len(original_value)
|
content, end_index - len(original_value)
|
||||||
) and self.check_valid_end_position(content, end_index + 1):
|
) and self.check_valid_end_position(content, end_index + 1):
|
||||||
self.md.zulip_rendering_result.user_ids_with_alert_words.update(user_ids)
|
self.zmd.zulip_rendering_result.user_ids_with_alert_words.update(user_ids)
|
||||||
return lines
|
return lines
|
||||||
|
|
||||||
|
|
||||||
class LinkInlineProcessor(markdown.inlinepatterns.LinkInlineProcessor):
|
class LinkInlineProcessor(markdown.inlinepatterns.LinkInlineProcessor):
|
||||||
|
def __init__(self, pattern: str, zmd: "ZulipMarkdown") -> None:
|
||||||
|
super().__init__(pattern, zmd)
|
||||||
|
self.zmd = zmd
|
||||||
|
|
||||||
def zulip_specific_link_changes(self, el: Element) -> Union[None, Element]:
|
def zulip_specific_link_changes(self, el: Element) -> Union[None, Element]:
|
||||||
href = el.get("href")
|
href = el.get("href")
|
||||||
assert href is not None
|
assert href is not None
|
||||||
@@ -2055,7 +2083,7 @@ class LinkInlineProcessor(markdown.inlinepatterns.LinkInlineProcessor):
|
|||||||
return None # no-op; the link is not processed.
|
return None # no-op; the link is not processed.
|
||||||
|
|
||||||
# Rewrite local links to be relative
|
# Rewrite local links to be relative
|
||||||
db_data: Optional[DbData] = self.md.zulip_db_data
|
db_data: Optional[DbData] = self.zmd.zulip_db_data
|
||||||
href = rewrite_local_links_to_relative(db_data, href)
|
href = rewrite_local_links_to_relative(db_data, href)
|
||||||
|
|
||||||
# Make changes to <a> tag attributes
|
# Make changes to <a> tag attributes
|
||||||
|
Reference in New Issue
Block a user