2019-01-27 18:57:15 +01:00
|
|
|
import os
|
2021-04-30 00:15:33 +02:00
|
|
|
from typing import Any, Callable, Collection, Dict, Iterable, List, Mapping, Optional, Sequence
|
2019-01-27 18:57:15 +01:00
|
|
|
|
|
|
|
from django.conf import settings
|
2021-04-16 00:57:30 +02:00
|
|
|
from django.utils.translation import gettext as _
|
2016-05-25 15:02:02 +02:00
|
|
|
|
2021-07-16 22:11:10 +02:00
|
|
|
from zerver.lib.exceptions import JsonableError
|
2021-07-13 20:23:36 +02:00
|
|
|
from zerver.lib.topic import RESOLVED_TOPIC_PREFIX, get_topic_from_message_info
|
2019-01-27 18:57:15 +01:00
|
|
|
|
python: Convert assignment type annotations to Python 3.6 style.
This commit was split by tabbott; this piece covers the vast majority
of files in Zulip, but excludes scripts/, tools/, and puppet/ to help
ensure we at least show the right error messages for Xenial systems.
We can likely further refine the remaining pieces with some testing.
Generated by com2ann, with whitespace fixes and various manual fixes
for runtime issues:
- invoiced_through: Optional[LicenseLedger] = models.ForeignKey(
+ invoiced_through: Optional["LicenseLedger"] = models.ForeignKey(
-_apns_client: Optional[APNsClient] = None
+_apns_client: Optional["APNsClient"] = None
- notifications_stream: Optional[Stream] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE)
- signup_notifications_stream: Optional[Stream] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE)
+ notifications_stream: Optional["Stream"] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE)
+ signup_notifications_stream: Optional["Stream"] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE)
- author: Optional[UserProfile] = models.ForeignKey('UserProfile', blank=True, null=True, on_delete=CASCADE)
+ author: Optional["UserProfile"] = models.ForeignKey('UserProfile', blank=True, null=True, on_delete=CASCADE)
- bot_owner: Optional[UserProfile] = models.ForeignKey('self', null=True, on_delete=models.SET_NULL)
+ bot_owner: Optional["UserProfile"] = models.ForeignKey('self', null=True, on_delete=models.SET_NULL)
- default_sending_stream: Optional[Stream] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE)
- default_events_register_stream: Optional[Stream] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE)
+ default_sending_stream: Optional["Stream"] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE)
+ default_events_register_stream: Optional["Stream"] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE)
-descriptors_by_handler_id: Dict[int, ClientDescriptor] = {}
+descriptors_by_handler_id: Dict[int, "ClientDescriptor"] = {}
-worker_classes: Dict[str, Type[QueueProcessingWorker]] = {}
-queues: Dict[str, Dict[str, Type[QueueProcessingWorker]]] = {}
+worker_classes: Dict[str, Type["QueueProcessingWorker"]] = {}
+queues: Dict[str, Dict[str, Type["QueueProcessingWorker"]]] = {}
-AUTH_LDAP_REVERSE_EMAIL_SEARCH: Optional[LDAPSearch] = None
+AUTH_LDAP_REVERSE_EMAIL_SEARCH: Optional["LDAPSearch"] = None
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-04-22 01:09:50 +02:00
|
|
|
stop_words_list: Optional[List[str]] = None
|
2021-02-12 08:19:30 +01:00
|
|
|
|
|
|
|
|
2019-01-27 18:57:15 +01:00
|
|
|
def read_stop_words() -> List[str]:
|
|
|
|
global stop_words_list
|
|
|
|
if stop_words_list is None:
|
2021-02-12 08:19:30 +01:00
|
|
|
file_path = os.path.join(
|
|
|
|
settings.DEPLOY_ROOT, "puppet/zulip/files/postgresql/zulip_english.stop"
|
|
|
|
)
|
2020-04-09 21:51:58 +02:00
|
|
|
with open(file_path) as f:
|
2019-01-27 18:57:15 +01:00
|
|
|
stop_words_list = f.read().splitlines()
|
2016-06-04 20:38:42 +02:00
|
|
|
|
2019-01-27 18:57:15 +01:00
|
|
|
return stop_words_list
|
2013-12-10 16:28:16 +01:00
|
|
|
|
2021-02-12 08:19:30 +01:00
|
|
|
|
2018-05-10 19:13:36 +02:00
|
|
|
def check_supported_events_narrow_filter(narrow: Iterable[Sequence[str]]) -> None:
|
2013-12-10 16:28:16 +01:00
|
|
|
for element in narrow:
|
|
|
|
operator = element[0]
|
|
|
|
if operator not in ["stream", "topic", "sender", "is"]:
|
2020-06-15 23:22:24 +02:00
|
|
|
raise JsonableError(_("Operator {} not supported.").format(operator))
|
2013-12-10 16:28:16 +01:00
|
|
|
|
2021-02-12 08:19:30 +01:00
|
|
|
|
2021-09-04 04:03:07 +02:00
|
|
|
def is_spectator_compatible(narrow: Iterable[Dict[str, Any]]) -> bool:
|
2022-02-08 00:13:33 +01:00
|
|
|
# This implementation should agree with the similar function in static/js/hash_util.js.
|
2018-05-21 17:44:00 +02:00
|
|
|
for element in narrow:
|
2021-02-12 08:20:45 +01:00
|
|
|
operator = element["operator"]
|
|
|
|
if "operand" not in element:
|
2018-05-21 17:44:00 +02:00
|
|
|
return False
|
2019-08-13 20:20:36 +02:00
|
|
|
if operator not in ["streams", "stream", "topic", "sender", "has", "search", "near", "id"]:
|
2018-05-21 17:44:00 +02:00
|
|
|
return False
|
|
|
|
return True
|
|
|
|
|
2021-02-12 08:19:30 +01:00
|
|
|
|
2020-08-04 19:33:43 +02:00
|
|
|
def is_web_public_narrow(narrow: Optional[Iterable[Dict[str, Any]]]) -> bool:
|
|
|
|
if narrow is None:
|
|
|
|
return False
|
|
|
|
|
|
|
|
for term in narrow:
|
2022-01-29 00:54:13 +01:00
|
|
|
# Web-public queries are only allowed for limited types of narrows.
|
2020-08-04 19:33:43 +02:00
|
|
|
# term == {'operator': 'streams', 'operand': 'web-public', 'negated': False}
|
2021-02-12 08:19:30 +01:00
|
|
|
if (
|
2021-02-12 08:20:45 +01:00
|
|
|
term["operator"] == "streams"
|
|
|
|
and term["operand"] == "web-public"
|
|
|
|
and term["negated"] is False
|
2021-02-12 08:19:30 +01:00
|
|
|
):
|
2020-08-04 19:33:43 +02:00
|
|
|
return True
|
|
|
|
|
|
|
|
return False
|
|
|
|
|
2021-02-12 08:19:30 +01:00
|
|
|
|
2021-04-30 00:15:33 +02:00
|
|
|
def build_narrow_filter(narrow: Collection[Sequence[str]]) -> Callable[[Mapping[str, Any]], bool]:
|
2016-07-20 23:16:28 +02:00
|
|
|
"""Changes to this function should come with corresponding changes to
|
|
|
|
BuildNarrowFilterTest."""
|
2013-12-10 16:28:16 +01:00
|
|
|
check_supported_events_narrow_filter(narrow)
|
2016-11-29 07:22:02 +01:00
|
|
|
|
2017-11-05 11:15:10 +01:00
|
|
|
def narrow_filter(event: Mapping[str, Any]) -> bool:
|
2013-12-10 16:28:16 +01:00
|
|
|
message = event["message"]
|
|
|
|
flags = event["flags"]
|
|
|
|
for element in narrow:
|
|
|
|
operator = element[0]
|
|
|
|
operand = element[1]
|
|
|
|
if operator == "stream":
|
|
|
|
if message["type"] != "stream":
|
|
|
|
return False
|
|
|
|
if operand.lower() != message["display_recipient"].lower():
|
|
|
|
return False
|
|
|
|
elif operator == "topic":
|
|
|
|
if message["type"] != "stream":
|
|
|
|
return False
|
2018-11-10 22:50:28 +01:00
|
|
|
topic_name = get_topic_from_message_info(message)
|
|
|
|
if operand.lower() != topic_name.lower():
|
2013-12-10 16:28:16 +01:00
|
|
|
return False
|
|
|
|
elif operator == "sender":
|
|
|
|
if operand.lower() != message["sender_email"].lower():
|
|
|
|
return False
|
|
|
|
elif operator == "is" and operand == "private":
|
|
|
|
if message["type"] != "private":
|
|
|
|
return False
|
|
|
|
elif operator == "is" and operand in ["starred"]:
|
|
|
|
if operand not in flags:
|
|
|
|
return False
|
2017-06-19 03:21:48 +02:00
|
|
|
elif operator == "is" and operand == "unread":
|
|
|
|
if "read" in flags:
|
|
|
|
return False
|
2013-12-10 16:28:16 +01:00
|
|
|
elif operator == "is" and operand in ["alerted", "mentioned"]:
|
|
|
|
if "mentioned" not in flags:
|
|
|
|
return False
|
2021-07-13 20:23:36 +02:00
|
|
|
elif operator == "is" and operand == "resolved":
|
|
|
|
if message["type"] != "stream":
|
|
|
|
return False
|
|
|
|
topic_name = get_topic_from_message_info(message)
|
|
|
|
if not topic_name.startswith(RESOLVED_TOPIC_PREFIX):
|
|
|
|
return False
|
2013-12-10 16:28:16 +01:00
|
|
|
|
|
|
|
return True
|
2021-02-12 08:19:30 +01:00
|
|
|
|
2013-12-10 16:28:16 +01:00
|
|
|
return narrow_filter
|