mirror of
https://github.com/zulip/zulip.git
synced 2025-11-04 14:03:30 +00:00
python: Normalize quotes with Black.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
committed by
Tim Abbott
parent
11741543da
commit
6e4c3e41dc
@@ -59,7 +59,7 @@ _apns_client: Optional["APNsClient"] = None
|
||||
_apns_client_initialized = False
|
||||
|
||||
|
||||
def get_apns_client() -> 'Optional[APNsClient]':
|
||||
def get_apns_client() -> "Optional[APNsClient]":
|
||||
# We lazily do this import as part of optimizing Zulip's base
|
||||
# import time.
|
||||
from apns2.client import APNsClient
|
||||
@@ -83,20 +83,20 @@ def apns_enabled() -> bool:
|
||||
|
||||
|
||||
def modernize_apns_payload(data: Dict[str, Any]) -> Dict[str, Any]:
|
||||
'''Take a payload in an unknown Zulip version's format, and return in current format.'''
|
||||
"""Take a payload in an unknown Zulip version's format, and return in current format."""
|
||||
# TODO this isn't super robust as is -- if a buggy remote server
|
||||
# sends a malformed payload, we are likely to raise an exception.
|
||||
if 'message_ids' in data:
|
||||
if "message_ids" in data:
|
||||
# The format sent by 1.6.0, from the earliest pre-1.6.0
|
||||
# version with bouncer support up until 613d093d7 pre-1.7.0:
|
||||
# 'alert': str, # just sender, and text about PM/group-PM/mention
|
||||
# 'message_ids': List[int], # always just one
|
||||
return {
|
||||
'alert': data['alert'],
|
||||
'badge': 0,
|
||||
'custom': {
|
||||
'zulip': {
|
||||
'message_ids': data['message_ids'],
|
||||
"alert": data["alert"],
|
||||
"badge": 0,
|
||||
"custom": {
|
||||
"zulip": {
|
||||
"message_ids": data["message_ids"],
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -188,7 +188,7 @@ def send_apple_push_notification(
|
||||
# For some reason, "Unregistered" result values have a
|
||||
# different format, as a tuple of the pair ("Unregistered", 12345132131).
|
||||
result = result[0]
|
||||
if result == 'Success':
|
||||
if result == "Success":
|
||||
logger.info("APNs: Success sending for user %d to device %s", user_id, device.token)
|
||||
elif result in ["Unregistered", "BadDeviceToken", "DeviceTokenNotForTopic"]:
|
||||
logger.info("APNs: Removing invalid/expired token %s (%s)", device.token, result)
|
||||
@@ -220,7 +220,7 @@ def make_gcm_client() -> gcm.GCM: # nocoverage
|
||||
# been using (as long as we're happy with it) -- just monkey-patch in
|
||||
# that one change, because the library's API doesn't anticipate that
|
||||
# as a customization point.
|
||||
gcm.gcm.GCM_URL = 'https://fcm.googleapis.com/fcm/send'
|
||||
gcm.gcm.GCM_URL = "https://fcm.googleapis.com/fcm/send"
|
||||
return gcm.GCM(settings.ANDROID_GCM_API_KEY)
|
||||
|
||||
|
||||
@@ -259,14 +259,14 @@ def parse_gcm_options(options: Dict[str, Any], data: Dict[str, Any]) -> str:
|
||||
|
||||
Returns `priority`.
|
||||
"""
|
||||
priority = options.pop('priority', None)
|
||||
priority = options.pop("priority", None)
|
||||
if priority is None:
|
||||
# An older server. Identify if this seems to be an actual notification.
|
||||
if data.get('event') == 'message':
|
||||
priority = 'high'
|
||||
if data.get("event") == "message":
|
||||
priority = "high"
|
||||
else: # `'event': 'remove'`, presumably
|
||||
priority = 'normal'
|
||||
if priority not in ('normal', 'high'):
|
||||
priority = "normal"
|
||||
if priority not in ("normal", "high"):
|
||||
raise JsonableError(
|
||||
_(
|
||||
"Invalid GCM option to bouncer: priority {!r}",
|
||||
@@ -323,8 +323,8 @@ def send_android_push_notification(
|
||||
logger.warning("Error while pushing to GCM", exc_info=True)
|
||||
return
|
||||
|
||||
if res and 'success' in res:
|
||||
for reg_id, msg_id in res['success'].items():
|
||||
if res and "success" in res:
|
||||
for reg_id, msg_id in res["success"].items():
|
||||
logger.info("GCM: Sent %s as %s", reg_id, msg_id)
|
||||
|
||||
if remote:
|
||||
@@ -336,8 +336,8 @@ def send_android_push_notification(
|
||||
# res.canonical will contain results when there are duplicate registrations for the same
|
||||
# device. The "canonical" registration is the latest registration made by the device.
|
||||
# Ref: https://developer.android.com/google/gcm/adv.html#canonical
|
||||
if 'canonical' in res:
|
||||
for reg_id, new_reg_id in res['canonical'].items():
|
||||
if "canonical" in res:
|
||||
for reg_id, new_reg_id in res["canonical"].items():
|
||||
if reg_id == new_reg_id:
|
||||
# I'm not sure if this should happen. In any case, not really actionable.
|
||||
logger.warning("GCM: Got canonical ref but it already matches our ID %s!", reg_id)
|
||||
@@ -362,9 +362,9 @@ def send_android_push_notification(
|
||||
|
||||
DeviceTokenClass.objects.filter(token=reg_id, kind=DeviceTokenClass.GCM).delete()
|
||||
|
||||
if 'errors' in res:
|
||||
for error, reg_ids in res['errors'].items():
|
||||
if error in ['NotRegistered', 'InvalidRegistration']:
|
||||
if "errors" in res:
|
||||
for error, reg_ids in res["errors"].items():
|
||||
if error in ["NotRegistered", "InvalidRegistration"]:
|
||||
for reg_id in reg_ids:
|
||||
logger.info("GCM: Removing %s", reg_id)
|
||||
# We remove all entries for this token (There
|
||||
@@ -396,13 +396,13 @@ def send_notifications_to_bouncer(
|
||||
gcm_options: Dict[str, Any],
|
||||
) -> None:
|
||||
post_data = {
|
||||
'user_id': user_profile_id,
|
||||
'apns_payload': apns_payload,
|
||||
'gcm_payload': gcm_payload,
|
||||
'gcm_options': gcm_options,
|
||||
"user_id": user_profile_id,
|
||||
"apns_payload": apns_payload,
|
||||
"gcm_payload": gcm_payload,
|
||||
"gcm_options": gcm_options,
|
||||
}
|
||||
# Calls zilencer.views.remote_server_notify_push
|
||||
send_json_to_push_bouncer('POST', 'push/notify', post_data)
|
||||
send_json_to_push_bouncer("POST", "push/notify", post_data)
|
||||
|
||||
|
||||
#
|
||||
@@ -452,18 +452,18 @@ def add_push_device_token(
|
||||
# register this user with them here
|
||||
if uses_notification_bouncer():
|
||||
post_data = {
|
||||
'server_uuid': settings.ZULIP_ORG_ID,
|
||||
'user_id': user_profile.id,
|
||||
'token': token_str,
|
||||
'token_kind': kind,
|
||||
"server_uuid": settings.ZULIP_ORG_ID,
|
||||
"user_id": user_profile.id,
|
||||
"token": token_str,
|
||||
"token_kind": kind,
|
||||
}
|
||||
|
||||
if kind == PushDeviceToken.APNS:
|
||||
post_data['ios_app_id'] = ios_app_id
|
||||
post_data["ios_app_id"] = ios_app_id
|
||||
|
||||
logger.info("Sending new push device to bouncer: %r", post_data)
|
||||
# Calls zilencer.views.register_remote_push_device
|
||||
send_to_push_bouncer('POST', 'push/register', post_data)
|
||||
send_to_push_bouncer("POST", "push/register", post_data)
|
||||
|
||||
return token
|
||||
|
||||
@@ -486,10 +486,10 @@ def remove_push_device_token(user_profile: UserProfile, token_str: str, kind: in
|
||||
if uses_notification_bouncer():
|
||||
# TODO: Make this a remove item
|
||||
post_data = {
|
||||
'server_uuid': settings.ZULIP_ORG_ID,
|
||||
'user_id': user_profile.id,
|
||||
'token': token_str,
|
||||
'token_kind': kind,
|
||||
"server_uuid": settings.ZULIP_ORG_ID,
|
||||
"user_id": user_profile.id,
|
||||
"token": token_str,
|
||||
"token_kind": kind,
|
||||
}
|
||||
# Calls zilencer.views.unregister_remote_push_device
|
||||
send_to_push_bouncer("POST", "push/unregister", post_data)
|
||||
@@ -499,8 +499,8 @@ def clear_push_device_tokens(user_profile_id: int) -> None:
|
||||
# Deletes all of a user's PushDeviceTokens.
|
||||
if uses_notification_bouncer():
|
||||
post_data = {
|
||||
'server_uuid': settings.ZULIP_ORG_ID,
|
||||
'user_id': user_profile_id,
|
||||
"server_uuid": settings.ZULIP_ORG_ID,
|
||||
"user_id": user_profile_id,
|
||||
}
|
||||
send_to_push_bouncer("POST", "push/unregister/all", post_data)
|
||||
return
|
||||
@@ -514,7 +514,7 @@ def clear_push_device_tokens(user_profile_id: int) -> None:
|
||||
|
||||
|
||||
def push_notifications_enabled() -> bool:
|
||||
'''True just if this server has configured a way to send push notifications.'''
|
||||
"""True just if this server has configured a way to send push notifications."""
|
||||
if (
|
||||
uses_notification_bouncer()
|
||||
and settings.ZULIP_ORG_KEY is not None
|
||||
@@ -554,12 +554,12 @@ def get_gcm_alert(message: Message) -> str:
|
||||
Determine what alert string to display based on the missed messages.
|
||||
"""
|
||||
sender_str = message.sender.full_name
|
||||
if message.recipient.type == Recipient.HUDDLE and message.trigger == 'private_message':
|
||||
if message.recipient.type == Recipient.HUDDLE and message.trigger == "private_message":
|
||||
return f"New private group message from {sender_str}"
|
||||
elif message.recipient.type == Recipient.PERSONAL and message.trigger == 'private_message':
|
||||
elif message.recipient.type == Recipient.PERSONAL and message.trigger == "private_message":
|
||||
return f"New private message from {sender_str}"
|
||||
elif message.is_stream_message() and (
|
||||
message.trigger == 'mentioned' or message.trigger == 'wildcard_mentioned'
|
||||
message.trigger == "mentioned" or message.trigger == "wildcard_mentioned"
|
||||
):
|
||||
return f"New mention from {sender_str}"
|
||||
else: # message.is_stream_message() and message.trigger == 'stream_push_notify'
|
||||
@@ -573,17 +573,17 @@ def get_mobile_push_content(rendered_content: str) -> str:
|
||||
if "emoji" in classes:
|
||||
match = re.search(r"emoji-(?P<emoji_code>\S+)", classes)
|
||||
if match:
|
||||
emoji_code = match.group('emoji_code')
|
||||
emoji_code = match.group("emoji_code")
|
||||
char_repr = ""
|
||||
for codepoint in emoji_code.split('-'):
|
||||
for codepoint in emoji_code.split("-"):
|
||||
char_repr += chr(int(codepoint, 16))
|
||||
return char_repr
|
||||
# Handles realm emojis, avatars etc.
|
||||
if elem.tag == "img":
|
||||
return elem.get("alt", "")
|
||||
if elem.tag == 'blockquote':
|
||||
return '' # To avoid empty line before quote text
|
||||
return elem.text or ''
|
||||
if elem.tag == "blockquote":
|
||||
return "" # To avoid empty line before quote text
|
||||
return elem.text or ""
|
||||
|
||||
def format_as_quote(quote_text: str) -> str:
|
||||
return "".join(
|
||||
@@ -592,35 +592,35 @@ def get_mobile_push_content(rendered_content: str) -> str:
|
||||
|
||||
def render_olist(ol: lxml.html.HtmlElement) -> str:
|
||||
items = []
|
||||
counter = int(ol.get('start')) if ol.get('start') else 1
|
||||
nested_levels = len(list(ol.iterancestors('ol')))
|
||||
indent = ('\n' + ' ' * nested_levels) if nested_levels else ''
|
||||
counter = int(ol.get("start")) if ol.get("start") else 1
|
||||
nested_levels = len(list(ol.iterancestors("ol")))
|
||||
indent = ("\n" + " " * nested_levels) if nested_levels else ""
|
||||
|
||||
for li in ol:
|
||||
items.append(indent + str(counter) + '. ' + process(li).strip())
|
||||
items.append(indent + str(counter) + ". " + process(li).strip())
|
||||
counter += 1
|
||||
|
||||
return '\n'.join(items)
|
||||
return "\n".join(items)
|
||||
|
||||
def render_spoiler(elem: lxml.html.HtmlElement) -> str:
|
||||
header = elem.find_class('spoiler-header')[0]
|
||||
header = elem.find_class("spoiler-header")[0]
|
||||
text = process(header).strip()
|
||||
if len(text) == 0:
|
||||
return "(…)\n"
|
||||
return f"{text} (…)\n"
|
||||
|
||||
def process(elem: lxml.html.HtmlElement) -> str:
|
||||
plain_text = ''
|
||||
if elem.tag == 'ol':
|
||||
plain_text = ""
|
||||
if elem.tag == "ol":
|
||||
plain_text = render_olist(elem)
|
||||
elif 'spoiler-block' in elem.get("class", ""):
|
||||
elif "spoiler-block" in elem.get("class", ""):
|
||||
plain_text += render_spoiler(elem)
|
||||
else:
|
||||
plain_text = get_text(elem)
|
||||
sub_text = ''
|
||||
sub_text = ""
|
||||
for child in elem:
|
||||
sub_text += process(child)
|
||||
if elem.tag == 'blockquote':
|
||||
if elem.tag == "blockquote":
|
||||
sub_text = format_as_quote(sub_text)
|
||||
plain_text += sub_text
|
||||
plain_text += elem.tail or ""
|
||||
@@ -645,35 +645,35 @@ def truncate_content(content: str) -> Tuple[str, bool]:
|
||||
|
||||
|
||||
def get_base_payload(user_profile: UserProfile) -> Dict[str, Any]:
|
||||
'''Common fields for all notification payloads.'''
|
||||
"""Common fields for all notification payloads."""
|
||||
data: Dict[str, Any] = {}
|
||||
|
||||
# These will let the app support logging into multiple realms and servers.
|
||||
data['server'] = settings.EXTERNAL_HOST
|
||||
data['realm_id'] = user_profile.realm.id
|
||||
data['realm_uri'] = user_profile.realm.uri
|
||||
data['user_id'] = user_profile.id
|
||||
data["server"] = settings.EXTERNAL_HOST
|
||||
data["realm_id"] = user_profile.realm.id
|
||||
data["realm_uri"] = user_profile.realm.uri
|
||||
data["user_id"] = user_profile.id
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def get_message_payload(user_profile: UserProfile, message: Message) -> Dict[str, Any]:
|
||||
'''Common fields for `message` payloads, for all platforms.'''
|
||||
"""Common fields for `message` payloads, for all platforms."""
|
||||
data = get_base_payload(user_profile)
|
||||
|
||||
# `sender_id` is preferred, but some existing versions use `sender_email`.
|
||||
data['sender_id'] = message.sender.id
|
||||
data['sender_email'] = message.sender.email
|
||||
data["sender_id"] = message.sender.id
|
||||
data["sender_email"] = message.sender.email
|
||||
|
||||
if message.recipient.type == Recipient.STREAM:
|
||||
data['recipient_type'] = "stream"
|
||||
data['stream'] = get_display_recipient(message.recipient)
|
||||
data['topic'] = message.topic_name()
|
||||
data["recipient_type"] = "stream"
|
||||
data["stream"] = get_display_recipient(message.recipient)
|
||||
data["topic"] = message.topic_name()
|
||||
elif message.recipient.type == Recipient.HUDDLE:
|
||||
data['recipient_type'] = "private"
|
||||
data['pm_users'] = huddle_users(message.recipient.id)
|
||||
data["recipient_type"] = "private"
|
||||
data["pm_users"] = huddle_users(message.recipient.id)
|
||||
else: # Recipient.PERSONAL
|
||||
data['recipient_type'] = "private"
|
||||
data["recipient_type"] = "private"
|
||||
|
||||
return data
|
||||
|
||||
@@ -685,7 +685,7 @@ def get_apns_alert_title(message: Message) -> str:
|
||||
if message.recipient.type == Recipient.HUDDLE:
|
||||
recipients = get_display_recipient(message.recipient)
|
||||
assert isinstance(recipients, list)
|
||||
return ', '.join(sorted(r['full_name'] for r in recipients))
|
||||
return ", ".join(sorted(r["full_name"] for r in recipients))
|
||||
elif message.is_stream_message():
|
||||
return f"#{get_display_recipient(message.recipient)} > {message.topic_name()}"
|
||||
# For personal PMs, we just show the sender name.
|
||||
@@ -735,7 +735,7 @@ def get_apns_badge_count_future(
|
||||
|
||||
|
||||
def get_message_payload_apns(user_profile: UserProfile, message: Message) -> Dict[str, Any]:
|
||||
'''A `message` payload for iOS, via APNs.'''
|
||||
"""A `message` payload for iOS, via APNs."""
|
||||
zulip_data = get_message_payload(user_profile, message)
|
||||
zulip_data.update(
|
||||
message_ids=[message.id],
|
||||
@@ -744,14 +744,14 @@ def get_message_payload_apns(user_profile: UserProfile, message: Message) -> Dic
|
||||
assert message.rendered_content is not None
|
||||
content, _ = truncate_content(get_mobile_push_content(message.rendered_content))
|
||||
apns_data = {
|
||||
'alert': {
|
||||
'title': get_apns_alert_title(message),
|
||||
'subtitle': get_apns_alert_subtitle(message),
|
||||
'body': content,
|
||||
"alert": {
|
||||
"title": get_apns_alert_title(message),
|
||||
"subtitle": get_apns_alert_subtitle(message),
|
||||
"body": content,
|
||||
},
|
||||
'sound': 'default',
|
||||
'badge': get_apns_badge_count(user_profile),
|
||||
'custom': {'zulip': zulip_data},
|
||||
"sound": "default",
|
||||
"badge": get_apns_badge_count(user_profile),
|
||||
"custom": {"zulip": zulip_data},
|
||||
}
|
||||
return apns_data
|
||||
|
||||
@@ -760,12 +760,12 @@ def get_message_payload_gcm(
|
||||
user_profile: UserProfile,
|
||||
message: Message,
|
||||
) -> Tuple[Dict[str, Any], Dict[str, Any]]:
|
||||
'''A `message` payload + options, for Android via GCM/FCM.'''
|
||||
"""A `message` payload + options, for Android via GCM/FCM."""
|
||||
data = get_message_payload(user_profile, message)
|
||||
assert message.rendered_content is not None
|
||||
content, truncated = truncate_content(get_mobile_push_content(message.rendered_content))
|
||||
data.update(
|
||||
event='message',
|
||||
event="message",
|
||||
alert=get_gcm_alert(message),
|
||||
zulip_message_id=message.id, # message_id is reserved for CCS
|
||||
time=datetime_to_timestamp(message.date_sent),
|
||||
@@ -774,7 +774,7 @@ def get_message_payload_gcm(
|
||||
sender_full_name=message.sender.full_name,
|
||||
sender_avatar_url=absolute_avatar_url(message.sender),
|
||||
)
|
||||
gcm_options = {'priority': 'high'}
|
||||
gcm_options = {"priority": "high"}
|
||||
return data, gcm_options
|
||||
|
||||
|
||||
@@ -782,28 +782,28 @@ def get_remove_payload_gcm(
|
||||
user_profile: UserProfile,
|
||||
message_ids: List[int],
|
||||
) -> Tuple[Dict[str, Any], Dict[str, Any]]:
|
||||
'''A `remove` payload + options, for Android via GCM/FCM.'''
|
||||
"""A `remove` payload + options, for Android via GCM/FCM."""
|
||||
gcm_payload = get_base_payload(user_profile)
|
||||
gcm_payload.update(
|
||||
event='remove',
|
||||
zulip_message_ids=','.join(str(id) for id in message_ids),
|
||||
event="remove",
|
||||
zulip_message_ids=",".join(str(id) for id in message_ids),
|
||||
# Older clients (all clients older than 2019-02-13) look only at
|
||||
# `zulip_message_id` and ignore `zulip_message_ids`. Do our best.
|
||||
zulip_message_id=message_ids[0],
|
||||
)
|
||||
gcm_options = {'priority': 'normal'}
|
||||
gcm_options = {"priority": "normal"}
|
||||
return gcm_payload, gcm_options
|
||||
|
||||
|
||||
def get_remove_payload_apns(user_profile: UserProfile, message_ids: List[int]) -> Dict[str, Any]:
|
||||
zulip_data = get_base_payload(user_profile)
|
||||
zulip_data.update(
|
||||
event='remove',
|
||||
zulip_message_ids=','.join(str(id) for id in message_ids),
|
||||
event="remove",
|
||||
zulip_message_ids=",".join(str(id) for id in message_ids),
|
||||
)
|
||||
apns_data = {
|
||||
'badge': get_apns_badge_count(user_profile, message_ids),
|
||||
'custom': {'zulip': zulip_data},
|
||||
"badge": get_apns_badge_count(user_profile, message_ids),
|
||||
"custom": {"zulip": zulip_data},
|
||||
}
|
||||
return apns_data
|
||||
|
||||
@@ -836,7 +836,7 @@ def handle_remove_push_notification(user_profile_id: int, message_ids: List[int]
|
||||
UserMessage.objects.filter(
|
||||
user_profile_id=user_profile_id,
|
||||
message_id__in=message_ids,
|
||||
).update(flags=F('flags').bitand(~UserMessage.flags.active_mobile_push_notification))
|
||||
).update(flags=F("flags").bitand(~UserMessage.flags.active_mobile_push_notification))
|
||||
|
||||
|
||||
@statsd_increment("push_notifications")
|
||||
@@ -855,16 +855,16 @@ def handle_push_notification(user_profile_id: int, missed_message: Dict[str, Any
|
||||
return
|
||||
|
||||
try:
|
||||
(message, user_message) = access_message(user_profile, missed_message['message_id'])
|
||||
(message, user_message) = access_message(user_profile, missed_message["message_id"])
|
||||
except JsonableError:
|
||||
if ArchivedMessage.objects.filter(id=missed_message['message_id']).exists():
|
||||
if ArchivedMessage.objects.filter(id=missed_message["message_id"]).exists():
|
||||
# If the cause is a race with the message being deleted,
|
||||
# that's normal and we have no need to log an error.
|
||||
return
|
||||
logging.info(
|
||||
"Unexpected message access failure handling push notifications: %s %s",
|
||||
user_profile.id,
|
||||
missed_message['message_id'],
|
||||
missed_message["message_id"],
|
||||
)
|
||||
return
|
||||
|
||||
@@ -889,12 +889,12 @@ def handle_push_notification(user_profile_id: int, missed_message: Dict[str, Any
|
||||
if not user_profile.long_term_idle:
|
||||
logger.error(
|
||||
"Could not find UserMessage with message_id %s and user_id %s",
|
||||
missed_message['message_id'],
|
||||
missed_message["message_id"],
|
||||
user_profile_id,
|
||||
)
|
||||
return
|
||||
|
||||
message.trigger = missed_message['trigger']
|
||||
message.trigger = missed_message["trigger"]
|
||||
|
||||
apns_payload = get_message_payload_apns(user_profile, message)
|
||||
gcm_payload, gcm_options = get_message_payload_gcm(user_profile, message)
|
||||
|
||||
Reference in New Issue
Block a user