mirror of https://github.com/zulip/zulip.git
push_notifications: Clear PushDeviceToken on API key change.
This includes adding a new endpoint to the push notification bouncer interface, and code to call it appropriately after resetting a user's personal API key. When we add support for a user having multiple API keys, we may need to add an additional key here to support removing keys associated with just one client.
This commit is contained in:
parent
6717daf4a6
commit
6407d0b1f9
|
@ -3336,6 +3336,10 @@ def do_regenerate_api_key(user_profile: UserProfile, acting_user: UserProfile) -
|
||||||
)),
|
)),
|
||||||
bot_owner_user_ids(user_profile))
|
bot_owner_user_ids(user_profile))
|
||||||
|
|
||||||
|
event = {'type': 'clear_push_device_tokens',
|
||||||
|
'user_profile_id': user_profile.id}
|
||||||
|
queue_json_publish("deferred_work", event)
|
||||||
|
|
||||||
return new_api_key
|
return new_api_key
|
||||||
|
|
||||||
def notify_avatar_url_change(user_profile: UserProfile) -> None:
|
def notify_avatar_url_change(user_profile: UserProfile) -> None:
|
||||||
|
|
|
@ -420,6 +420,18 @@ def remove_push_device_token(user_profile: UserProfile, token_str: str, kind: in
|
||||||
except PushDeviceToken.DoesNotExist:
|
except PushDeviceToken.DoesNotExist:
|
||||||
raise JsonableError(_("Token does not exist"))
|
raise JsonableError(_("Token does not exist"))
|
||||||
|
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
send_to_push_bouncer("POST", "push/unregister/all", post_data)
|
||||||
|
return
|
||||||
|
|
||||||
|
PushDeviceToken.objects.filter(user_id=user_profile_id).delete()
|
||||||
|
|
||||||
#
|
#
|
||||||
# Push notifications in general
|
# Push notifications in general
|
||||||
#
|
#
|
||||||
|
|
|
@ -37,7 +37,11 @@ from zerver.models import (
|
||||||
Stream,
|
Stream,
|
||||||
Subscription,
|
Subscription,
|
||||||
)
|
)
|
||||||
from zerver.lib.actions import do_delete_messages, do_mark_stream_messages_as_read
|
from zerver.lib.actions import (
|
||||||
|
do_delete_messages,
|
||||||
|
do_mark_stream_messages_as_read,
|
||||||
|
do_regenerate_api_key,
|
||||||
|
)
|
||||||
from zerver.lib.soft_deactivation import do_soft_deactivate_users
|
from zerver.lib.soft_deactivation import do_soft_deactivate_users
|
||||||
from zerver.lib.push_notifications import (
|
from zerver.lib.push_notifications import (
|
||||||
absolute_avatar_url,
|
absolute_avatar_url,
|
||||||
|
@ -225,6 +229,24 @@ class PushBouncerNotificationTest(BouncerTestCase):
|
||||||
result = self.api_post(self.server_uuid, endpoint, payload)
|
result = self.api_post(self.server_uuid, endpoint, payload)
|
||||||
self.assert_json_error(result, 'Empty or invalid length token')
|
self.assert_json_error(result, 'Empty or invalid length token')
|
||||||
|
|
||||||
|
def test_remote_push_unregister_all(self) -> None:
|
||||||
|
payload = self.get_generic_payload('register')
|
||||||
|
|
||||||
|
# Verify correct results are success
|
||||||
|
result = self.api_post(self.server_uuid,
|
||||||
|
'/api/v1/remotes/push/register', payload)
|
||||||
|
self.assert_json_success(result)
|
||||||
|
|
||||||
|
remote_tokens = RemotePushDeviceToken.objects.filter(token=payload['token'])
|
||||||
|
self.assertEqual(len(remote_tokens), 1)
|
||||||
|
result = self.api_post(self.server_uuid,
|
||||||
|
'/api/v1/remotes/push/unregister/all',
|
||||||
|
dict(user_id=10))
|
||||||
|
self.assert_json_success(result)
|
||||||
|
|
||||||
|
remote_tokens = RemotePushDeviceToken.objects.filter(token=payload['token'])
|
||||||
|
self.assertEqual(len(remote_tokens), 0)
|
||||||
|
|
||||||
def test_invalid_apns_token(self) -> None:
|
def test_invalid_apns_token(self) -> None:
|
||||||
endpoints = [
|
endpoints = [
|
||||||
('/api/v1/remotes/push/register', 'apple-token'),
|
('/api/v1/remotes/push/register', 'apple-token'),
|
||||||
|
@ -307,6 +329,21 @@ class PushBouncerNotificationTest(BouncerTestCase):
|
||||||
server=server))
|
server=server))
|
||||||
self.assertEqual(len(tokens), 0)
|
self.assertEqual(len(tokens), 0)
|
||||||
|
|
||||||
|
# Re-add copies of those tokens
|
||||||
|
for endpoint, token, kind in endpoints:
|
||||||
|
result = self.client_post(endpoint, {'token': token},
|
||||||
|
subdomain="zulip")
|
||||||
|
self.assert_json_success(result)
|
||||||
|
tokens = list(RemotePushDeviceToken.objects.filter(user_id=user.id,
|
||||||
|
server=server))
|
||||||
|
self.assertEqual(len(tokens), 2)
|
||||||
|
|
||||||
|
# Remove it using the bouncer after an API key change
|
||||||
|
do_regenerate_api_key(user, user)
|
||||||
|
tokens = list(RemotePushDeviceToken.objects.filter(user_id=user.id,
|
||||||
|
server=server))
|
||||||
|
self.assertEqual(len(tokens), 0)
|
||||||
|
|
||||||
class AnalyticsBouncerTest(BouncerTestCase):
|
class AnalyticsBouncerTest(BouncerTestCase):
|
||||||
TIME_ZERO = datetime.datetime(1988, 3, 14).replace(tzinfo=timezone_utc)
|
TIME_ZERO = datetime.datetime(1988, 3, 14).replace(tzinfo=timezone_utc)
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ from zerver.lib.queue import SimpleQueueClient, queue_json_publish, retry_event
|
||||||
from zerver.lib.timestamp import timestamp_to_datetime
|
from zerver.lib.timestamp import timestamp_to_datetime
|
||||||
from zerver.lib.email_notifications import handle_missedmessage_emails
|
from zerver.lib.email_notifications import handle_missedmessage_emails
|
||||||
from zerver.lib.push_notifications import handle_push_notification, handle_remove_push_notification, \
|
from zerver.lib.push_notifications import handle_push_notification, handle_remove_push_notification, \
|
||||||
initialize_push_notifications
|
initialize_push_notifications, clear_push_device_tokens
|
||||||
from zerver.lib.actions import do_send_confirmation_email, \
|
from zerver.lib.actions import do_send_confirmation_email, \
|
||||||
do_update_user_activity, do_update_user_activity_interval, do_update_user_presence, \
|
do_update_user_activity, do_update_user_activity_interval, do_update_user_presence, \
|
||||||
internal_send_message, internal_send_private_message, notify_realm_export, \
|
internal_send_message, internal_send_private_message, notify_realm_export, \
|
||||||
|
@ -667,6 +667,8 @@ class DeferredWorker(QueueProcessingWorker):
|
||||||
(stream, recipient, sub) = access_stream_by_id(user_profile, stream_id,
|
(stream, recipient, sub) = access_stream_by_id(user_profile, stream_id,
|
||||||
require_active=False)
|
require_active=False)
|
||||||
do_mark_stream_messages_as_read(user_profile, client, stream)
|
do_mark_stream_messages_as_read(user_profile, client, stream)
|
||||||
|
elif event['type'] == 'clear_push_device_tokens':
|
||||||
|
clear_push_device_tokens(event["user_profile_id"])
|
||||||
elif event['type'] == 'realm_export':
|
elif event['type'] == 'realm_export':
|
||||||
start = time.time()
|
start = time.time()
|
||||||
realm = Realm.objects.get(id=event['realm_id'])
|
realm = Realm.objects.get(id=event['realm_id'])
|
||||||
|
|
|
@ -13,6 +13,8 @@ v1_api_and_json_patterns = [
|
||||||
{'POST': 'zilencer.views.register_remote_push_device'}),
|
{'POST': 'zilencer.views.register_remote_push_device'}),
|
||||||
url('^remotes/push/unregister$', rest_dispatch,
|
url('^remotes/push/unregister$', rest_dispatch,
|
||||||
{'POST': 'zilencer.views.unregister_remote_push_device'}),
|
{'POST': 'zilencer.views.unregister_remote_push_device'}),
|
||||||
|
url('^remotes/push/unregister/all$', rest_dispatch,
|
||||||
|
{'POST': 'zilencer.views.unregister_all_remote_push_devices'}),
|
||||||
url('^remotes/push/notify$', rest_dispatch,
|
url('^remotes/push/notify$', rest_dispatch,
|
||||||
{'POST': 'zilencer.views.remote_server_notify_push'}),
|
{'POST': 'zilencer.views.remote_server_notify_push'}),
|
||||||
|
|
||||||
|
|
|
@ -120,6 +120,14 @@ def unregister_remote_push_device(request: HttpRequest, entity: Union[UserProfil
|
||||||
|
|
||||||
return json_success()
|
return json_success()
|
||||||
|
|
||||||
|
@has_request_variables
|
||||||
|
def unregister_all_remote_push_devices(request: HttpRequest, entity: Union[UserProfile, RemoteZulipServer],
|
||||||
|
user_id: int=REQ(validator=check_int)) -> HttpResponse:
|
||||||
|
server = validate_entity(entity)
|
||||||
|
RemotePushDeviceToken.objects.filter(user_id=user_id,
|
||||||
|
server=server).delete()
|
||||||
|
return json_success()
|
||||||
|
|
||||||
@has_request_variables
|
@has_request_variables
|
||||||
def remote_server_notify_push(request: HttpRequest, entity: Union[UserProfile, RemoteZulipServer],
|
def remote_server_notify_push(request: HttpRequest, entity: Union[UserProfile, RemoteZulipServer],
|
||||||
payload: Dict[str, Any]=REQ(argument_type='body')) -> HttpResponse:
|
payload: Dict[str, Any]=REQ(argument_type='body')) -> HttpResponse:
|
||||||
|
|
Loading…
Reference in New Issue