mirror of https://github.com/zulip/zulip.git
refactor: Rename most of "filter" to "linkifier".
After this only the database table, events, and API endpoints remain.
This commit is contained in:
parent
f896a7667f
commit
68fe912c63
|
@ -232,8 +232,8 @@ from zerver.models import (
|
|||
get_user_by_id_in_realm_including_cross_realm,
|
||||
get_user_profile_by_id,
|
||||
is_cross_realm_bot_email,
|
||||
linkifiers_for_realm,
|
||||
query_for_ids,
|
||||
realm_filters_for_realm,
|
||||
validate_attachment_request,
|
||||
)
|
||||
from zerver.tornado.django_api import send_event
|
||||
|
@ -6492,8 +6492,8 @@ def do_mark_hotspot_as_read(user: UserProfile, hotspot: str) -> None:
|
|||
send_event(user.realm, event, [user.id])
|
||||
|
||||
|
||||
def notify_realm_filters(realm: Realm) -> None:
|
||||
realm_filters = realm_filters_for_realm(realm.id)
|
||||
def notify_linkifiers(realm: Realm) -> None:
|
||||
realm_filters = linkifiers_for_realm(realm.id)
|
||||
event = dict(type="realm_filters", realm_filters=realm_filters)
|
||||
send_event(realm, event, active_user_ids(realm.id))
|
||||
|
||||
|
@ -6502,25 +6502,25 @@ def notify_realm_filters(realm: Realm) -> None:
|
|||
# RegExp syntax. In addition to JS-compatible syntax, the following features are available:
|
||||
# * Named groups will be converted to numbered groups automatically
|
||||
# * Inline-regex flags will be stripped, and where possible translated to RegExp-wide flags
|
||||
def do_add_realm_filter(realm: Realm, pattern: str, url_format_string: str) -> int:
|
||||
def do_add_linkifier(realm: Realm, pattern: str, url_format_string: str) -> int:
|
||||
pattern = pattern.strip()
|
||||
url_format_string = url_format_string.strip()
|
||||
linkifier = RealmFilter(realm=realm, pattern=pattern, url_format_string=url_format_string)
|
||||
linkifier.full_clean()
|
||||
linkifier.save()
|
||||
notify_realm_filters(realm)
|
||||
notify_linkifiers(realm)
|
||||
|
||||
return linkifier.id
|
||||
|
||||
|
||||
def do_remove_realm_filter(
|
||||
def do_remove_linkifier(
|
||||
realm: Realm, pattern: Optional[str] = None, id: Optional[int] = None
|
||||
) -> None:
|
||||
if pattern is not None:
|
||||
RealmFilter.objects.get(realm=realm, pattern=pattern).delete()
|
||||
else:
|
||||
RealmFilter.objects.get(realm=realm, pk=id).delete()
|
||||
notify_realm_filters(realm)
|
||||
notify_linkifiers(realm)
|
||||
|
||||
|
||||
def get_emails_from_user_ids(user_ids: Sequence[int]) -> Dict[int, str]:
|
||||
|
|
|
@ -58,7 +58,7 @@ from zerver.models import (
|
|||
custom_profile_fields_for_realm,
|
||||
get_default_stream_groups,
|
||||
get_realm_domains,
|
||||
realm_filters_for_realm,
|
||||
linkifiers_for_realm,
|
||||
)
|
||||
from zerver.tornado.django_api import get_user_events, request_event_queue
|
||||
from zproject.backends import email_auth_enabled, password_auth_enabled
|
||||
|
@ -252,7 +252,7 @@ def fetch_initial_state_data(
|
|||
state["realm_emoji"] = realm.get_emoji()
|
||||
|
||||
if want("realm_filters"):
|
||||
state["realm_filters"] = realm_filters_for_realm(realm.id)
|
||||
state["realm_filters"] = linkifiers_for_realm(realm.id)
|
||||
|
||||
if want("realm_user_groups"):
|
||||
state["realm_user_groups"] = user_groups_in_realm_serialized(realm)
|
||||
|
|
|
@ -72,9 +72,9 @@ from zerver.models import (
|
|||
UserGroup,
|
||||
UserGroupMembership,
|
||||
UserProfile,
|
||||
all_realm_filters,
|
||||
all_linkifiers_for_installation,
|
||||
get_active_streams,
|
||||
realm_filters_for_realm,
|
||||
linkifiers_for_realm,
|
||||
)
|
||||
|
||||
ReturnT = TypeVar("ReturnT")
|
||||
|
@ -1780,7 +1780,7 @@ class MarkdownListPreprocessor(markdown.preprocessors.Preprocessor):
|
|||
OUTER_CAPTURE_GROUP = "linkifier_actual_match"
|
||||
|
||||
|
||||
def prepare_realm_pattern(source: str) -> str:
|
||||
def prepare_linkifier_pattern(source: str) -> str:
|
||||
"""Augment a linkifier so it only matches after start-of-string,
|
||||
whitespace, or opening delimiters, won't match if there are word
|
||||
characters directly after, and saves what was matched as
|
||||
|
@ -1790,8 +1790,8 @@ def prepare_realm_pattern(source: str) -> str:
|
|||
|
||||
# Given a regular expression pattern, linkifies groups that match it
|
||||
# using the provided format string to construct the URL.
|
||||
class RealmFilterPattern(markdown.inlinepatterns.Pattern):
|
||||
""" Applied a given realm filter to the input """
|
||||
class LinkifierPattern(markdown.inlinepatterns.Pattern):
|
||||
""" Applied a given linkifier to the input """
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
|
@ -1799,7 +1799,7 @@ class RealmFilterPattern(markdown.inlinepatterns.Pattern):
|
|||
format_string: str,
|
||||
markdown_instance: Optional[markdown.Markdown] = None,
|
||||
) -> None:
|
||||
self.pattern = prepare_realm_pattern(source_pattern)
|
||||
self.pattern = prepare_linkifier_pattern(source_pattern)
|
||||
self.format_string = format_string
|
||||
markdown.inlinepatterns.Pattern.__init__(self, self.pattern, markdown_instance)
|
||||
|
||||
|
@ -2088,8 +2088,8 @@ def get_sub_registry(r: markdown.util.Registry, keys: List[str]) -> markdown.uti
|
|||
return new_r
|
||||
|
||||
|
||||
# These are used as keys ("realm_filters_keys") to md_engines and the respective
|
||||
# realm filter caches
|
||||
# These are used as keys ("linkifiers_keys") to md_engines and the respective
|
||||
# linkifier caches
|
||||
DEFAULT_MARKDOWN_KEY = -1
|
||||
ZEPHYR_MIRROR_MARKDOWN_KEY = -2
|
||||
|
||||
|
@ -2103,12 +2103,12 @@ class Markdown(markdown.Markdown):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
realm_filters: List[Tuple[str, str, int]],
|
||||
realm_filters_key: int,
|
||||
linkifiers: List[Tuple[str, str, int]],
|
||||
linkifiers_key: int,
|
||||
email_gateway: bool,
|
||||
) -> None:
|
||||
self.realm_filters = realm_filters
|
||||
self.realm_filters_key = realm_filters_key
|
||||
self.linkifiers = linkifiers
|
||||
self.linkifiers_key = linkifiers_key
|
||||
self.email_gateway = email_gateway
|
||||
|
||||
super().__init__(
|
||||
|
@ -2231,8 +2231,8 @@ class Markdown(markdown.Markdown):
|
|||
)
|
||||
reg.register(LinkInlineProcessor(markdown.inlinepatterns.LINK_RE, self), "link", 60)
|
||||
reg.register(AutoLink(get_web_link_regex(), self), "autolink", 55)
|
||||
# Reserve priority 45-54 for realm filters
|
||||
reg = self.register_realm_filters(reg)
|
||||
# Reserve priority 45-54 for linkifiers
|
||||
reg = self.register_linkifiers(reg)
|
||||
reg.register(markdown.inlinepatterns.HtmlInlineProcessor(ENTITY_RE, self), "entity", 40)
|
||||
reg.register(
|
||||
markdown.inlinepatterns.SimpleTagPattern(r"(\*\*)([^\n]+?)\2", "strong"), "strong", 35
|
||||
|
@ -2248,12 +2248,12 @@ class Markdown(markdown.Markdown):
|
|||
reg.register(UnicodeEmoji(unicode_emoji_regex), "unicodeemoji", 0)
|
||||
return reg
|
||||
|
||||
def register_realm_filters(
|
||||
self, inlinePatterns: markdown.util.Registry
|
||||
) -> markdown.util.Registry:
|
||||
for (pattern, format_string, id) in self.realm_filters:
|
||||
def register_linkifiers(self, inlinePatterns: markdown.util.Registry) -> markdown.util.Registry:
|
||||
for (pattern, format_string, id) in self.linkifiers:
|
||||
inlinePatterns.register(
|
||||
RealmFilterPattern(pattern, format_string, self), f"realm_filters/{pattern}", 45
|
||||
LinkifierPattern(pattern, format_string, self),
|
||||
f"linkifiers/{pattern}",
|
||||
45,
|
||||
)
|
||||
return inlinePatterns
|
||||
|
||||
|
@ -2281,7 +2281,7 @@ class Markdown(markdown.Markdown):
|
|||
return postprocessors
|
||||
|
||||
def handle_zephyr_mirror(self) -> None:
|
||||
if self.realm_filters_key == ZEPHYR_MIRROR_MARKDOWN_KEY:
|
||||
if self.linkifiers_key == ZEPHYR_MIRROR_MARKDOWN_KEY:
|
||||
# Disable almost all inline patterns for zephyr mirror
|
||||
# users' traffic that is mirrored. Note that
|
||||
# inline_interesting_links is a treeprocessor and thus is
|
||||
|
@ -2302,18 +2302,18 @@ class Markdown(markdown.Markdown):
|
|||
|
||||
|
||||
md_engines: Dict[Tuple[int, bool], Markdown] = {}
|
||||
realm_filter_data: Dict[int, List[Tuple[str, str, int]]] = {}
|
||||
linkifier_data: Dict[int, List[Tuple[str, str, int]]] = {}
|
||||
|
||||
|
||||
def make_md_engine(realm_filters_key: int, email_gateway: bool) -> None:
|
||||
md_engine_key = (realm_filters_key, email_gateway)
|
||||
def make_md_engine(linkifiers_key: int, email_gateway: bool) -> None:
|
||||
md_engine_key = (linkifiers_key, email_gateway)
|
||||
if md_engine_key in md_engines:
|
||||
del md_engines[md_engine_key]
|
||||
|
||||
realm_filters = realm_filter_data[realm_filters_key]
|
||||
linkifiers = linkifier_data[linkifiers_key]
|
||||
md_engines[md_engine_key] = Markdown(
|
||||
realm_filters=realm_filters,
|
||||
realm_filters_key=realm_filters_key,
|
||||
linkifiers=linkifiers,
|
||||
linkifiers_key=linkifiers_key,
|
||||
email_gateway=email_gateway,
|
||||
)
|
||||
|
||||
|
@ -2326,18 +2326,18 @@ basic_link_splitter = re.compile(r"[ !;\?\),\'\"]")
|
|||
# function on the URLs; they are expected to be HTML-escaped when
|
||||
# rendered by clients (just as links rendered into message bodies
|
||||
# are validated and escaped inside `url_to_a`).
|
||||
def topic_links(realm_filters_key: int, topic_name: str) -> List[Dict[str, str]]:
|
||||
def topic_links(linkifiers_key: int, topic_name: str) -> List[Dict[str, str]]:
|
||||
matches: List[Dict[str, Union[str, int]]] = []
|
||||
realm_filters = realm_filters_for_realm(realm_filters_key)
|
||||
linkifiers = linkifiers_for_realm(linkifiers_key)
|
||||
|
||||
for realm_filter in realm_filters:
|
||||
raw_pattern = realm_filter[0]
|
||||
url_format_string = realm_filter[1]
|
||||
pattern = prepare_realm_pattern(raw_pattern)
|
||||
for linkifier in linkifiers:
|
||||
raw_pattern = linkifier[0]
|
||||
url_format_string = linkifier[1]
|
||||
pattern = prepare_linkifier_pattern(raw_pattern)
|
||||
for m in re.finditer(pattern, topic_name):
|
||||
match_details = m.groupdict()
|
||||
match_text = match_details["linkifier_actual_match"]
|
||||
# We format the realm_filter's url string using the matched text.
|
||||
# We format the linkifier's url string using the matched text.
|
||||
# Also, we include the matched text in the response, so that our clients
|
||||
# don't have to implement any logic of their own to get back the text.
|
||||
matches += [
|
||||
|
@ -2371,35 +2371,32 @@ def topic_links(realm_filters_key: int, topic_name: str) -> List[Dict[str, str]]
|
|||
return [{k: str(v) for k, v in match.items() if k != "index"} for match in matches]
|
||||
|
||||
|
||||
def maybe_update_markdown_engines(realm_filters_key: Optional[int], email_gateway: bool) -> None:
|
||||
# If realm_filters_key is None, load all filters
|
||||
global realm_filter_data
|
||||
if realm_filters_key is None:
|
||||
all_filters = all_realm_filters()
|
||||
all_filters[DEFAULT_MARKDOWN_KEY] = []
|
||||
for realm_filters_key, filters in all_filters.items():
|
||||
realm_filter_data[realm_filters_key] = filters
|
||||
make_md_engine(realm_filters_key, email_gateway)
|
||||
# Hack to ensure that realm_filters_key is right for mirrored Zephyrs
|
||||
realm_filter_data[ZEPHYR_MIRROR_MARKDOWN_KEY] = []
|
||||
def maybe_update_markdown_engines(linkifiers_key: Optional[int], email_gateway: bool) -> None:
|
||||
# If linkifiers_key is None, load all linkifiers
|
||||
global linkifier_data
|
||||
if linkifiers_key is None:
|
||||
all_linkifiers = all_linkifiers_for_installation()
|
||||
all_linkifiers[DEFAULT_MARKDOWN_KEY] = []
|
||||
for linkifiers_key, linkifiers in all_linkifiers.items():
|
||||
linkifier_data[linkifiers_key] = linkifiers
|
||||
make_md_engine(linkifiers_key, email_gateway)
|
||||
# Hack to ensure that linkifiers_key is right for mirrored Zephyrs
|
||||
linkifier_data[ZEPHYR_MIRROR_MARKDOWN_KEY] = []
|
||||
make_md_engine(ZEPHYR_MIRROR_MARKDOWN_KEY, False)
|
||||
else:
|
||||
realm_filters = realm_filters_for_realm(realm_filters_key)
|
||||
if (
|
||||
realm_filters_key not in realm_filter_data
|
||||
or realm_filter_data[realm_filters_key] != realm_filters
|
||||
):
|
||||
# Realm filters data has changed, update `realm_filter_data` and any
|
||||
# of the existing Markdown engines using this set of realm filters.
|
||||
realm_filter_data[realm_filters_key] = realm_filters
|
||||
linkifiers = linkifiers_for_realm(linkifiers_key)
|
||||
if linkifiers_key not in linkifier_data or linkifier_data[linkifiers_key] != linkifiers:
|
||||
# Linkifier data has changed, update `linkifier_data` and any
|
||||
# of the existing Markdown engines using this set of linkifiers.
|
||||
linkifier_data[linkifiers_key] = linkifiers
|
||||
for email_gateway_flag in [True, False]:
|
||||
if (realm_filters_key, email_gateway_flag) in md_engines:
|
||||
if (linkifiers_key, email_gateway_flag) in md_engines:
|
||||
# Update only existing engines(if any), don't create new one.
|
||||
make_md_engine(realm_filters_key, email_gateway_flag)
|
||||
make_md_engine(linkifiers_key, email_gateway_flag)
|
||||
|
||||
if (realm_filters_key, email_gateway) not in md_engines:
|
||||
if (linkifiers_key, email_gateway) not in md_engines:
|
||||
# Markdown engine corresponding to this key doesn't exists so create one.
|
||||
make_md_engine(realm_filters_key, email_gateway)
|
||||
make_md_engine(linkifiers_key, email_gateway)
|
||||
|
||||
|
||||
# We want to log Markdown parser failures, but shouldn't log the actual input
|
||||
|
@ -2561,9 +2558,9 @@ def do_convert(
|
|||
if message_realm is None:
|
||||
message_realm = message.get_realm()
|
||||
if message_realm is None:
|
||||
realm_filters_key = DEFAULT_MARKDOWN_KEY
|
||||
linkifiers_key = DEFAULT_MARKDOWN_KEY
|
||||
else:
|
||||
realm_filters_key = message_realm.id
|
||||
linkifiers_key = message_realm.id
|
||||
|
||||
if message and hasattr(message, "id") and message.id:
|
||||
logging_message_id = "id# " + str(message.id)
|
||||
|
@ -2575,16 +2572,16 @@ def do_convert(
|
|||
if message.sending_client.name == "zephyr_mirror":
|
||||
# Use slightly customized Markdown processor for content
|
||||
# delivered via zephyr_mirror
|
||||
realm_filters_key = ZEPHYR_MIRROR_MARKDOWN_KEY
|
||||
linkifiers_key = ZEPHYR_MIRROR_MARKDOWN_KEY
|
||||
|
||||
maybe_update_markdown_engines(realm_filters_key, email_gateway)
|
||||
md_engine_key = (realm_filters_key, email_gateway)
|
||||
maybe_update_markdown_engines(linkifiers_key, email_gateway)
|
||||
md_engine_key = (linkifiers_key, email_gateway)
|
||||
|
||||
if md_engine_key in md_engines:
|
||||
_md_engine = md_engines[md_engine_key]
|
||||
else:
|
||||
if DEFAULT_MARKDOWN_KEY not in md_engines:
|
||||
maybe_update_markdown_engines(realm_filters_key=None, email_gateway=False)
|
||||
maybe_update_markdown_engines(linkifiers_key=None, email_gateway=False)
|
||||
|
||||
_md_engine = md_engines[(DEFAULT_MARKDOWN_KEY, email_gateway)]
|
||||
# Reset the parser; otherwise it will get slower over time.
|
||||
|
|
|
@ -2,9 +2,9 @@ import sys
|
|||
from argparse import ArgumentParser
|
||||
from typing import Any
|
||||
|
||||
from zerver.lib.actions import do_add_realm_filter, do_remove_realm_filter
|
||||
from zerver.lib.actions import do_add_linkifier, do_remove_linkifier
|
||||
from zerver.lib.management import CommandError, ZulipBaseCommand
|
||||
from zerver.models import all_realm_filters
|
||||
from zerver.models import all_linkifiers_for_installation
|
||||
|
||||
|
||||
class Command(ZulipBaseCommand):
|
||||
|
@ -41,7 +41,7 @@ Example: ./manage.py realm_filters --realm=zulip --op=show
|
|||
realm = self.get_realm(options)
|
||||
assert realm is not None # Should be ensured by parser
|
||||
if options["op"] == "show":
|
||||
print(f"{realm.string_id}: {all_realm_filters().get(realm.id, [])}")
|
||||
print(f"{realm.string_id}: {all_linkifiers_for_installation().get(realm.id, [])}")
|
||||
sys.exit(0)
|
||||
|
||||
pattern = options["pattern"]
|
||||
|
@ -54,10 +54,10 @@ Example: ./manage.py realm_filters --realm=zulip --op=show
|
|||
if not url_format_string:
|
||||
self.print_help("./manage.py", "realm_filters")
|
||||
raise CommandError
|
||||
do_add_realm_filter(realm, pattern, url_format_string)
|
||||
do_add_linkifier(realm, pattern, url_format_string)
|
||||
sys.exit(0)
|
||||
elif options["op"] == "remove":
|
||||
do_remove_realm_filter(realm, pattern=pattern)
|
||||
do_remove_linkifier(realm, pattern=pattern)
|
||||
sys.exit(0)
|
||||
else:
|
||||
self.print_help("./manage.py", "realm_filters")
|
||||
|
|
|
@ -887,61 +887,61 @@ class RealmFilter(models.Model):
|
|||
return f"<RealmFilter({self.realm.string_id}): {self.pattern} {self.url_format_string}>"
|
||||
|
||||
|
||||
def get_realm_filters_cache_key(realm_id: int) -> str:
|
||||
return f"{cache.KEY_PREFIX}:all_realm_filters:{realm_id}"
|
||||
def get_linkifiers_cache_key(realm_id: int) -> str:
|
||||
return f"{cache.KEY_PREFIX}:all_linkifiers_for_realm:{realm_id}"
|
||||
|
||||
|
||||
# We have a per-process cache to avoid doing 1000 remote cache queries during page load
|
||||
per_request_realm_filters_cache: Dict[int, List[Tuple[str, str, int]]] = {}
|
||||
per_request_linkifiers_cache: Dict[int, List[Tuple[str, str, int]]] = {}
|
||||
|
||||
|
||||
def realm_in_local_realm_filters_cache(realm_id: int) -> bool:
|
||||
return realm_id in per_request_realm_filters_cache
|
||||
def realm_in_local_linkifiers_cache(realm_id: int) -> bool:
|
||||
return realm_id in per_request_linkifiers_cache
|
||||
|
||||
|
||||
def realm_filters_for_realm(realm_id: int) -> List[Tuple[str, str, int]]:
|
||||
if not realm_in_local_realm_filters_cache(realm_id):
|
||||
per_request_realm_filters_cache[realm_id] = realm_filters_for_realm_remote_cache(realm_id)
|
||||
return per_request_realm_filters_cache[realm_id]
|
||||
def linkifiers_for_realm(realm_id: int) -> List[Tuple[str, str, int]]:
|
||||
if not realm_in_local_linkifiers_cache(realm_id):
|
||||
per_request_linkifiers_cache[realm_id] = linkifiers_for_realm_remote_cache(realm_id)
|
||||
return per_request_linkifiers_cache[realm_id]
|
||||
|
||||
|
||||
@cache_with_key(get_realm_filters_cache_key, timeout=3600 * 24 * 7)
|
||||
def realm_filters_for_realm_remote_cache(realm_id: int) -> List[Tuple[str, str, int]]:
|
||||
@cache_with_key(get_linkifiers_cache_key, timeout=3600 * 24 * 7)
|
||||
def linkifiers_for_realm_remote_cache(realm_id: int) -> List[Tuple[str, str, int]]:
|
||||
filters = []
|
||||
for realm_filter in RealmFilter.objects.filter(realm_id=realm_id):
|
||||
filters.append((realm_filter.pattern, realm_filter.url_format_string, realm_filter.id))
|
||||
for linkifier in RealmFilter.objects.filter(realm_id=realm_id):
|
||||
filters.append((linkifier.pattern, linkifier.url_format_string, linkifier.id))
|
||||
|
||||
return filters
|
||||
|
||||
|
||||
def all_realm_filters() -> Dict[int, List[Tuple[str, str, int]]]:
|
||||
def all_linkifiers_for_installation() -> Dict[int, List[Tuple[str, str, int]]]:
|
||||
filters: DefaultDict[int, List[Tuple[str, str, int]]] = defaultdict(list)
|
||||
for realm_filter in RealmFilter.objects.all():
|
||||
filters[realm_filter.realm_id].append(
|
||||
(realm_filter.pattern, realm_filter.url_format_string, realm_filter.id)
|
||||
for linkifier in RealmFilter.objects.all():
|
||||
filters[linkifier.realm_id].append(
|
||||
(linkifier.pattern, linkifier.url_format_string, linkifier.id)
|
||||
)
|
||||
|
||||
return filters
|
||||
|
||||
|
||||
def flush_realm_filter(sender: Any, **kwargs: Any) -> None:
|
||||
def flush_linkifiers(sender: Any, **kwargs: Any) -> None:
|
||||
realm_id = kwargs["instance"].realm_id
|
||||
cache_delete(get_realm_filters_cache_key(realm_id))
|
||||
cache_delete(get_linkifiers_cache_key(realm_id))
|
||||
try:
|
||||
per_request_realm_filters_cache.pop(realm_id)
|
||||
per_request_linkifiers_cache.pop(realm_id)
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
|
||||
post_save.connect(flush_realm_filter, sender=RealmFilter)
|
||||
post_delete.connect(flush_realm_filter, sender=RealmFilter)
|
||||
post_save.connect(flush_linkifiers, sender=RealmFilter)
|
||||
post_delete.connect(flush_linkifiers, sender=RealmFilter)
|
||||
|
||||
|
||||
def flush_per_request_caches() -> None:
|
||||
global per_request_display_recipient_cache
|
||||
per_request_display_recipient_cache = {}
|
||||
global per_request_realm_filters_cache
|
||||
per_request_realm_filters_cache = {}
|
||||
global per_request_linkifiers_cache
|
||||
per_request_linkifiers_cache = {}
|
||||
|
||||
|
||||
# The Recipient table is used to map Messages to the set of users who
|
||||
|
|
|
@ -12,8 +12,8 @@ from typing import Any, Callable, Dict, List, Optional, Set, Tuple
|
|||
from django.utils.timezone import now as timezone_now
|
||||
|
||||
from zerver.lib.actions import (
|
||||
do_add_linkifier,
|
||||
do_add_reaction,
|
||||
do_add_realm_filter,
|
||||
do_create_user,
|
||||
update_user_presence,
|
||||
)
|
||||
|
@ -253,7 +253,7 @@ def get_temp_user_group_id() -> Dict[str, object]:
|
|||
|
||||
@openapi_param_value_generator(["/realm/filters/{filter_id}:delete"])
|
||||
def remove_realm_filters() -> Dict[str, object]:
|
||||
filter_id = do_add_realm_filter(
|
||||
filter_id = do_add_linkifier(
|
||||
get_realm("zulip"), "#(?P<id>[0-9]{2,8})", "https://github.com/zulip/zulip/pull/%(id)s"
|
||||
)
|
||||
return {
|
||||
|
|
|
@ -24,9 +24,9 @@ from zerver.lib.actions import (
|
|||
check_send_typing_notification,
|
||||
do_add_alert_words,
|
||||
do_add_default_stream,
|
||||
do_add_linkifier,
|
||||
do_add_reaction,
|
||||
do_add_realm_domain,
|
||||
do_add_realm_filter,
|
||||
do_add_streams_to_default_stream_group,
|
||||
do_add_submessage,
|
||||
do_change_avatar_fields,
|
||||
|
@ -64,11 +64,11 @@ from zerver.lib.actions import (
|
|||
do_remove_alert_words,
|
||||
do_remove_default_stream,
|
||||
do_remove_default_stream_group,
|
||||
do_remove_linkifier,
|
||||
do_remove_reaction,
|
||||
do_remove_realm_custom_profile_field,
|
||||
do_remove_realm_domain,
|
||||
do_remove_realm_emoji,
|
||||
do_remove_realm_filter,
|
||||
do_remove_streams_from_default_stream_group,
|
||||
do_rename_stream,
|
||||
do_revoke_multi_use_invite,
|
||||
|
@ -1318,13 +1318,11 @@ class NormalActionsTest(BaseAction):
|
|||
regex = "#(?P<id>[123])"
|
||||
url = "https://realm.com/my_realm_filter/%(id)s"
|
||||
|
||||
events = self.verify_action(
|
||||
lambda: do_add_realm_filter(self.user_profile.realm, regex, url)
|
||||
)
|
||||
events = self.verify_action(lambda: do_add_linkifier(self.user_profile.realm, regex, url))
|
||||
check_realm_filters("events[0]", events[0])
|
||||
|
||||
events = self.verify_action(
|
||||
lambda: do_remove_realm_filter(self.user_profile.realm, "#(?P<id>[123])")
|
||||
lambda: do_remove_linkifier(self.user_profile.realm, "#(?P<id>[123])")
|
||||
)
|
||||
check_realm_filters("events[0]", events[0])
|
||||
|
||||
|
|
|
@ -55,13 +55,13 @@ from zerver.models import (
|
|||
UserGroup,
|
||||
UserMessage,
|
||||
UserProfile,
|
||||
flush_linkifiers,
|
||||
flush_per_request_caches,
|
||||
flush_realm_filter,
|
||||
get_client,
|
||||
get_realm,
|
||||
get_stream,
|
||||
realm_filters_for_realm,
|
||||
realm_in_local_realm_filters_cache,
|
||||
linkifiers_for_realm,
|
||||
realm_in_local_linkifiers_cache,
|
||||
)
|
||||
|
||||
|
||||
|
@ -1429,13 +1429,13 @@ class MarkdownTest(ZulipTestCase):
|
|||
|
||||
import zerver.lib.markdown
|
||||
|
||||
zerver.lib.markdown.realm_filter_data = {}
|
||||
zerver.lib.markdown.linkifier_data = {}
|
||||
maybe_update_markdown_engines(None, False)
|
||||
all_filters = zerver.lib.markdown.realm_filter_data
|
||||
zulip_filters = all_filters[realm.id]
|
||||
self.assertEqual(len(zulip_filters), 1)
|
||||
all_linkifiers = zerver.lib.markdown.linkifier_data
|
||||
zulip_linkifiers = all_linkifiers[realm.id]
|
||||
self.assertEqual(len(zulip_linkifiers), 1)
|
||||
self.assertEqual(
|
||||
zulip_filters[0],
|
||||
zulip_linkifiers[0],
|
||||
("#(?P<id>[0-9]{2,8})", "https://trac.example.com/ticket/%(id)s", linkifier.id),
|
||||
)
|
||||
|
||||
|
@ -1444,7 +1444,7 @@ class MarkdownTest(ZulipTestCase):
|
|||
|
||||
def flush() -> None:
|
||||
"""
|
||||
flush_realm_filter is a post-save hook, so calling it
|
||||
flush_linkifiers is a post-save hook, so calling it
|
||||
directly for testing is kind of awkward
|
||||
"""
|
||||
|
||||
|
@ -1453,30 +1453,28 @@ class MarkdownTest(ZulipTestCase):
|
|||
|
||||
instance = Instance()
|
||||
instance.realm_id = realm.id
|
||||
flush_realm_filter(sender=None, instance=instance)
|
||||
flush_linkifiers(sender=None, instance=instance)
|
||||
|
||||
def save_new_realm_filter() -> None:
|
||||
realm_filter = RealmFilter(
|
||||
realm=realm, pattern=r"whatever", url_format_string="whatever"
|
||||
)
|
||||
realm_filter.save()
|
||||
def save_new_linkifier() -> None:
|
||||
linkifier = RealmFilter(realm=realm, pattern=r"whatever", url_format_string="whatever")
|
||||
linkifier.save()
|
||||
|
||||
# start fresh for our realm
|
||||
flush()
|
||||
self.assertFalse(realm_in_local_realm_filters_cache(realm.id))
|
||||
self.assertFalse(realm_in_local_linkifiers_cache(realm.id))
|
||||
|
||||
# call this just for side effects of populating the cache
|
||||
realm_filters_for_realm(realm.id)
|
||||
self.assertTrue(realm_in_local_realm_filters_cache(realm.id))
|
||||
linkifiers_for_realm(realm.id)
|
||||
self.assertTrue(realm_in_local_linkifiers_cache(realm.id))
|
||||
|
||||
# Saving a new RealmFilter should have the side effect of
|
||||
# flushing the cache.
|
||||
save_new_realm_filter()
|
||||
self.assertFalse(realm_in_local_realm_filters_cache(realm.id))
|
||||
save_new_linkifier()
|
||||
self.assertFalse(realm_in_local_linkifiers_cache(realm.id))
|
||||
|
||||
# and flush it one more time, to make sure we don't get a KeyError
|
||||
flush()
|
||||
self.assertFalse(realm_in_local_realm_filters_cache(realm.id))
|
||||
self.assertFalse(realm_in_local_linkifiers_cache(realm.id))
|
||||
|
||||
def test_realm_patterns_negative(self) -> None:
|
||||
realm = get_realm("zulip")
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import re
|
||||
|
||||
from zerver.lib.actions import do_add_realm_filter
|
||||
from zerver.lib.actions import do_add_linkifier
|
||||
from zerver.lib.test_classes import ZulipTestCase
|
||||
from zerver.models import RealmFilter, get_realm
|
||||
|
||||
|
@ -9,7 +9,7 @@ class RealmFilterTest(ZulipTestCase):
|
|||
def test_list(self) -> None:
|
||||
self.login("iago")
|
||||
realm = get_realm("zulip")
|
||||
do_add_realm_filter(realm, "#(?P<id>[123])", "https://realm.com/my_realm_filter/%(id)s")
|
||||
do_add_linkifier(realm, "#(?P<id>[123])", "https://realm.com/my_realm_filter/%(id)s")
|
||||
result = self.client_get("/json/realm/filters")
|
||||
self.assert_json_success(result)
|
||||
self.assertEqual(200, result.status_code)
|
||||
|
@ -104,13 +104,13 @@ class RealmFilterTest(ZulipTestCase):
|
|||
def test_delete(self) -> None:
|
||||
self.login("iago")
|
||||
realm = get_realm("zulip")
|
||||
filter_id = do_add_realm_filter(
|
||||
linkifier_id = do_add_linkifier(
|
||||
realm, "#(?P<id>[123])", "https://realm.com/my_realm_filter/%(id)s"
|
||||
)
|
||||
filters_count = RealmFilter.objects.count()
|
||||
result = self.client_delete(f"/json/realm/filters/{filter_id + 1}")
|
||||
linkifiers_count = RealmFilter.objects.count()
|
||||
result = self.client_delete(f"/json/realm/filters/{linkifier_id + 1}")
|
||||
self.assert_json_error(result, "Filter not found")
|
||||
|
||||
result = self.client_delete(f"/json/realm/filters/{filter_id}")
|
||||
result = self.client_delete(f"/json/realm/filters/{linkifier_id}")
|
||||
self.assert_json_success(result)
|
||||
self.assertEqual(RealmFilter.objects.count(), filters_count - 1)
|
||||
self.assertEqual(RealmFilter.objects.count(), linkifiers_count - 1)
|
||||
|
|
|
@ -3,41 +3,43 @@ from django.http import HttpRequest, HttpResponse
|
|||
from django.utils.translation import ugettext as _
|
||||
|
||||
from zerver.decorator import require_realm_admin
|
||||
from zerver.lib.actions import do_add_realm_filter, do_remove_realm_filter
|
||||
from zerver.lib.actions import do_add_linkifier, do_remove_linkifier
|
||||
from zerver.lib.request import REQ, has_request_variables
|
||||
from zerver.lib.response import json_error, json_success
|
||||
from zerver.models import RealmFilter, UserProfile, realm_filters_for_realm
|
||||
from zerver.models import RealmFilter, UserProfile, linkifiers_for_realm
|
||||
|
||||
|
||||
# Custom realm filters
|
||||
def list_filters(request: HttpRequest, user_profile: UserProfile) -> HttpResponse:
|
||||
filters = realm_filters_for_realm(user_profile.realm_id)
|
||||
# Custom realm linkifiers
|
||||
def list_linkifiers(request: HttpRequest, user_profile: UserProfile) -> HttpResponse:
|
||||
filters = linkifiers_for_realm(user_profile.realm_id)
|
||||
return json_success({"filters": filters})
|
||||
|
||||
|
||||
@require_realm_admin
|
||||
@has_request_variables
|
||||
def create_filter(
|
||||
def create_linkifier(
|
||||
request: HttpRequest,
|
||||
user_profile: UserProfile,
|
||||
pattern: str = REQ(),
|
||||
url_format_string: str = REQ(),
|
||||
) -> HttpResponse:
|
||||
try:
|
||||
filter_id = do_add_realm_filter(
|
||||
linkifier_id = do_add_linkifier(
|
||||
realm=user_profile.realm,
|
||||
pattern=pattern,
|
||||
url_format_string=url_format_string,
|
||||
)
|
||||
return json_success({"id": filter_id})
|
||||
return json_success({"id": linkifier_id})
|
||||
except ValidationError as e:
|
||||
return json_error(e.messages[0], data={"errors": dict(e)})
|
||||
|
||||
|
||||
@require_realm_admin
|
||||
def delete_filter(request: HttpRequest, user_profile: UserProfile, filter_id: int) -> HttpResponse:
|
||||
def delete_linkifier(
|
||||
request: HttpRequest, user_profile: UserProfile, filter_id: int
|
||||
) -> HttpResponse:
|
||||
try:
|
||||
do_remove_realm_filter(realm=user_profile.realm, id=filter_id)
|
||||
do_remove_linkifier(realm=user_profile.realm, id=filter_id)
|
||||
except RealmFilter.DoesNotExist:
|
||||
return json_error(_("Filter not found"))
|
||||
return json_success()
|
||||
|
|
|
@ -119,7 +119,7 @@ from zerver.views.realm_domains import (
|
|||
from zerver.views.realm_emoji import delete_emoji, list_emoji, upload_emoji
|
||||
from zerver.views.realm_export import delete_realm_export, export_realm, get_realm_exports
|
||||
from zerver.views.realm_icon import delete_icon_backend, get_icon_backend, upload_icon
|
||||
from zerver.views.realm_linkifiers import create_filter, delete_filter, list_filters
|
||||
from zerver.views.realm_linkifiers import create_linkifier, delete_linkifier, list_linkifiers
|
||||
from zerver.views.realm_logo import delete_logo_backend, get_logo_backend, upload_logo
|
||||
from zerver.views.registration import (
|
||||
accounts_home,
|
||||
|
@ -266,8 +266,8 @@ v1_api_and_json_patterns = [
|
|||
# realm/logo -> zerver.views.realm_logo
|
||||
rest_path("realm/logo", POST=upload_logo, DELETE=delete_logo_backend, GET=get_logo_backend),
|
||||
# realm/filters -> zerver.views.realm_linkifiers
|
||||
rest_path("realm/filters", GET=list_filters, POST=create_filter),
|
||||
rest_path("realm/filters/<int:filter_id>", DELETE=delete_filter),
|
||||
rest_path("realm/filters", GET=list_linkifiers, POST=create_linkifier),
|
||||
rest_path("realm/filters/<int:filter_id>", DELETE=delete_linkifier),
|
||||
# realm/profile_fields -> zerver.views.custom_profile_fields
|
||||
rest_path(
|
||||
"realm/profile_fields",
|
||||
|
|
Loading…
Reference in New Issue