diff --git a/zerver/actions/realm_linkifiers.py b/zerver/actions/realm_linkifiers.py new file mode 100644 index 0000000000..d208f35912 --- /dev/null +++ b/zerver/actions/realm_linkifiers.py @@ -0,0 +1,59 @@ +from typing import Dict, Optional + +from zerver.models import ( + Realm, + RealmFilter, + active_user_ids, + linkifiers_for_realm, + realm_filters_for_realm, +) +from zerver.tornado.django_api import send_event + + +def notify_linkifiers(realm: Realm) -> None: + realm_linkifiers = linkifiers_for_realm(realm.id) + event: Dict[str, object] = dict(type="realm_linkifiers", realm_linkifiers=realm_linkifiers) + send_event(realm, event, active_user_ids(realm.id)) + + # Below is code for backwards compatibility. The now deprecated + # "realm_filters" event-type is used by older clients, and uses + # tuples. + realm_filters = realm_filters_for_realm(realm.id) + event = dict(type="realm_filters", realm_filters=realm_filters) + send_event(realm, event, active_user_ids(realm.id)) + + +# NOTE: Regexes must be simple enough that they can be easily translated to JavaScript +# 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_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_linkifiers(realm) + + return linkifier.id + + +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, id=id).delete() + notify_linkifiers(realm) + + +def do_update_linkifier(realm: Realm, id: int, pattern: str, url_format_string: str) -> None: + pattern = pattern.strip() + url_format_string = url_format_string.strip() + linkifier = RealmFilter.objects.get(realm=realm, id=id) + linkifier.pattern = pattern + linkifier.url_format_string = url_format_string + linkifier.full_clean() + linkifier.save(update_fields=["pattern", "url_format_string"]) + notify_linkifiers(realm) diff --git a/zerver/lib/actions.py b/zerver/lib/actions.py index 4a4dbad8be..ab58beac68 100644 --- a/zerver/lib/actions.py +++ b/zerver/lib/actions.py @@ -239,7 +239,6 @@ from zerver.models import ( RealmAuditLog, RealmDomain, RealmEmoji, - RealmFilter, RealmUserDefault, Recipient, ScheduledEmail, @@ -279,9 +278,7 @@ from zerver.models import ( get_user_by_delivery_email, 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 @@ -7718,55 +7715,6 @@ def do_mark_hotspot_as_read(user: UserProfile, hotspot: str) -> None: send_event(user.realm, event, [user.id]) -def notify_linkifiers(realm: Realm) -> None: - realm_linkifiers = linkifiers_for_realm(realm.id) - event: Dict[str, object] = dict(type="realm_linkifiers", realm_linkifiers=realm_linkifiers) - send_event(realm, event, active_user_ids(realm.id)) - - # Below is code for backwards compatibility. The now deprecated - # "realm_filters" event-type is used by older clients, and uses - # tuples. - realm_filters = realm_filters_for_realm(realm.id) - event = dict(type="realm_filters", realm_filters=realm_filters) - send_event(realm, event, active_user_ids(realm.id)) - - -# NOTE: Regexes must be simple enough that they can be easily translated to JavaScript -# 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_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_linkifiers(realm) - - return linkifier.id - - -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, id=id).delete() - notify_linkifiers(realm) - - -def do_update_linkifier(realm: Realm, id: int, pattern: str, url_format_string: str) -> None: - pattern = pattern.strip() - url_format_string = url_format_string.strip() - linkifier = RealmFilter.objects.get(realm=realm, id=id) - linkifier.pattern = pattern - linkifier.url_format_string = url_format_string - linkifier.full_clean() - linkifier.save(update_fields=["pattern", "url_format_string"]) - notify_linkifiers(realm) - - @transaction.atomic(durable=True) def do_add_realm_domain( realm: Realm, domain: str, allow_subdomains: bool, *, acting_user: Optional[UserProfile] diff --git a/zerver/management/commands/edit_linkifiers.py b/zerver/management/commands/edit_linkifiers.py index 1e771c2c8a..9c6aceb857 100644 --- a/zerver/management/commands/edit_linkifiers.py +++ b/zerver/management/commands/edit_linkifiers.py @@ -4,7 +4,7 @@ from typing import Any from django.core.management.base import CommandError -from zerver.lib.actions import do_add_linkifier, do_remove_linkifier +from zerver.actions.realm_linkifiers import do_add_linkifier, do_remove_linkifier from zerver.lib.management import ZulipBaseCommand from zerver.models import linkifiers_for_realm diff --git a/zerver/openapi/curl_param_value_generators.py b/zerver/openapi/curl_param_value_generators.py index c02ef8cec6..8bfdbc4c3b 100644 --- a/zerver/openapi/curl_param_value_generators.py +++ b/zerver/openapi/curl_param_value_generators.py @@ -10,13 +10,9 @@ from typing import Any, Callable, Dict, List, Optional, Set, Tuple from django.utils.timezone import now as timezone_now +from zerver.actions.realm_linkifiers import do_add_linkifier from zerver.actions.realm_playgrounds import do_add_realm_playground -from zerver.lib.actions import ( - do_add_linkifier, - do_add_reaction, - do_create_user, - update_user_presence, -) +from zerver.lib.actions import do_add_reaction, do_create_user, update_user_presence from zerver.lib.events import do_events_register from zerver.lib.initial_password import initial_password from zerver.lib.test_classes import ZulipTestCase diff --git a/zerver/tests/test_events.py b/zerver/tests/test_events.py index f14ca1fa33..dd3c965d50 100644 --- a/zerver/tests/test_events.py +++ b/zerver/tests/test_events.py @@ -13,6 +13,11 @@ from unittest import mock import orjson from django.utils.timezone import now as timezone_now +from zerver.actions.realm_linkifiers import ( + do_add_linkifier, + do_remove_linkifier, + do_update_linkifier, +) from zerver.actions.realm_playgrounds import do_add_realm_playground, do_remove_realm_playground from zerver.actions.submessage import do_add_submessage from zerver.actions.typing import check_send_typing_notification, do_send_stream_typing_notification @@ -31,7 +36,6 @@ from zerver.lib.actions import ( check_add_realm_emoji, do_add_alert_words, do_add_default_stream, - do_add_linkifier, do_add_reaction, do_add_realm_domain, do_add_streams_to_default_stream_group, @@ -72,7 +76,6 @@ 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, @@ -90,7 +93,6 @@ from zerver.lib.actions import ( do_unmute_topic, do_unmute_user, do_update_embedded_data, - do_update_linkifier, do_update_message, do_update_message_flags, do_update_outgoing_webhook_service, diff --git a/zerver/views/realm_linkifiers.py b/zerver/views/realm_linkifiers.py index 9cbc7c02a8..4592fc7771 100644 --- a/zerver/views/realm_linkifiers.py +++ b/zerver/views/realm_linkifiers.py @@ -2,8 +2,12 @@ from django.core.exceptions import ValidationError from django.http import HttpRequest, HttpResponse from django.utils.translation import gettext as _ +from zerver.actions.realm_linkifiers import ( + do_add_linkifier, + do_remove_linkifier, + do_update_linkifier, +) from zerver.decorator import require_realm_admin -from zerver.lib.actions import do_add_linkifier, do_remove_linkifier, do_update_linkifier from zerver.lib.exceptions import JsonableError, ValidationFailureError from zerver.lib.request import REQ, has_request_variables from zerver.lib.response import json_success