zilencer: Truncate "remove" notifications from remote servers.

This is 4d055a6695, but for notifications which are received from
remote hosts.
This commit is contained in:
Alex Vandiver 2021-11-08 16:32:19 -08:00 committed by Alex Vandiver
parent 6046f94521
commit 6c14978cd1
2 changed files with 46 additions and 10 deletions

View File

@ -279,28 +279,36 @@ class PushBouncerNotificationTest(BouncerTestCase):
hamlet = self.example_user("hamlet") hamlet = self.example_user("hamlet")
server = RemoteZulipServer.objects.get(uuid=self.server_uuid) server = RemoteZulipServer.objects.get(uuid=self.server_uuid)
token = "aaaa" token = "aaaa"
android_tokens = []
for i in ["aa", "bb"]: for i in ["aa", "bb"]:
RemotePushDeviceToken.objects.create( android_tokens.append(
kind=RemotePushDeviceToken.GCM, RemotePushDeviceToken.objects.create(
token=hex_to_b64(token + i), kind=RemotePushDeviceToken.GCM,
user_id=hamlet.id, token=hex_to_b64(token + i),
server=server, user_id=hamlet.id,
server=server,
)
) )
RemotePushDeviceToken.objects.create( apple_token = RemotePushDeviceToken.objects.create(
kind=RemotePushDeviceToken.APNS, kind=RemotePushDeviceToken.APNS,
token=hex_to_b64(token), token=hex_to_b64(token),
user_id=hamlet.id, user_id=hamlet.id,
server=server, server=server,
) )
many_ids = ",".join(str(i) for i in range(1, 250))
payload = { payload = {
"user_id": hamlet.id, "user_id": hamlet.id,
"gcm_payload": "test", "gcm_payload": {"event": "remove", "zulip_message_ids": many_ids},
"apns_payload": "test", "apns_payload": {"event": "remove", "zulip_message_ids": many_ids},
"gcm_options": {}, "gcm_options": {},
} }
with mock.patch("zilencer.views.send_android_push_notification"), mock.patch( with mock.patch(
"zilencer.views.send_android_push_notification"
) as android_push, mock.patch(
"zilencer.views.send_apple_push_notification" "zilencer.views.send_apple_push_notification"
), self.assertLogs("zilencer.views", level="INFO") as logger: ) as apple_push, self.assertLogs(
"zilencer.views", level="INFO"
) as logger:
result = self.uuid_post( result = self.uuid_post(
self.server_uuid, self.server_uuid,
"/api/v1/remotes/push/notify", "/api/v1/remotes/push/notify",
@ -321,6 +329,19 @@ class PushBouncerNotificationTest(BouncerTestCase):
"2 via FCM devices, 1 via APNs devices" "2 via FCM devices, 1 via APNs devices"
], ],
) )
apple_push.assert_called_once_with(
hamlet.id,
[apple_token],
{"event": "remove", "zulip_message_ids": ",".join(str(i) for i in range(50, 250))},
remote=server,
)
android_push.assert_called_once_with(
hamlet.id,
list(reversed(android_tokens)),
{"event": "remove", "zulip_message_ids": ",".join(str(i) for i in range(50, 250))},
{},
remote=server,
)
def test_remote_push_unregister_all(self) -> None: def test_remote_push_unregister_all(self) -> None:
payload = self.get_generic_payload("register") payload = self.get_generic_payload("register")

View File

@ -202,10 +202,25 @@ def remote_server_notify_push(
len(apple_devices), len(apple_devices),
) )
# Truncate incoming pushes to 200, due to APNs maximum message
# sizes; see handle_remove_push_notification for the version of
# this for notifications generated natively on the server. We
# apply this to remote-server pushes in case they predate that
# commit.
def truncate_payload(payload: Dict[str, Any]) -> Dict[str, Any]:
MAX_MESSAGE_IDS = 200
if payload and payload.get("event") == "remove" and payload.get("zulip_message_ids"):
ids = [int(id) for id in payload["zulip_message_ids"].split(",")]
truncated_ids = list(sorted(ids))[-MAX_MESSAGE_IDS:]
payload["zulip_message_ids"] = ",".join(str(id) for id in truncated_ids)
return payload
gcm_payload = truncate_payload(gcm_payload)
send_android_push_notification( send_android_push_notification(
user_id, android_devices, gcm_payload, gcm_options, remote=server user_id, android_devices, gcm_payload, gcm_options, remote=server
) )
apns_payload = truncate_payload(apns_payload)
send_apple_push_notification(user_id, apple_devices, apns_payload, remote=server) send_apple_push_notification(user_id, apple_devices, apns_payload, remote=server)
return json_success( return json_success(