diff --git a/zerver/lib/actions.py b/zerver/lib/actions.py index d78a30b1ad..ecdb5e9c5d 100644 --- a/zerver/lib/actions.py +++ b/zerver/lib/actions.py @@ -2233,120 +2233,28 @@ system-generated notifications.""" % (stream_name,) "signups", string_id, signup_message) return (realm, created) -def do_change_enable_stream_desktop_notifications(user_profile, - enable_stream_desktop_notifications, - log=True): - # type: (UserProfile, bool, bool) -> None - user_profile.enable_stream_desktop_notifications = enable_stream_desktop_notifications - user_profile.save(update_fields=["enable_stream_desktop_notifications"]) - event = {'type': 'update_global_notifications', - 'user': user_profile.email, - 'notification_name': 'enable_stream_desktop_notifications', - 'setting': enable_stream_desktop_notifications} - if log: - log_event(event) - send_event(event, [user_profile.id]) +def do_change_notification_settings(user_profile, name, value, log=True): + # type: (UserProfile, str, bool, bool) -> None + """Takes in a UserProfile object, the name of a global notification + preference to update, and the value to update to + """ -def do_change_enable_stream_sounds(user_profile, enable_stream_sounds, log=True): - # type: (UserProfile, bool, bool) -> None - user_profile.enable_stream_sounds = enable_stream_sounds - user_profile.save(update_fields=["enable_stream_sounds"]) - event = {'type': 'update_global_notifications', - 'user': user_profile.email, - 'notification_name': 'enable_stream_sounds', - 'setting': enable_stream_sounds} - if log: - log_event(event) - send_event(event, [user_profile.id]) + notification_setting_type = UserProfile.notification_setting_types[name] + assert isinstance(value, notification_setting_type), ( + 'Cannot update %s: %s is not an instance of %s' % ( + name, value, notification_setting_type,)) -def do_change_enable_desktop_notifications(user_profile, enable_desktop_notifications, log=True): - # type: (UserProfile, bool, bool) -> None - user_profile.enable_desktop_notifications = enable_desktop_notifications - user_profile.save(update_fields=["enable_desktop_notifications"]) - event = {'type': 'update_global_notifications', - 'user': user_profile.email, - 'notification_name': 'enable_desktop_notifications', - 'setting': enable_desktop_notifications} - if log: - log_event(event) - send_event(event, [user_profile.id]) + setattr(user_profile, name, value) -def do_change_pm_content_in_desktop_notifications(user_profile, - pm_content_in_desktop_notifications, log=True): - # type: (UserProfile, bool, bool) -> None - user_profile.pm_content_in_desktop_notifications \ - = pm_content_in_desktop_notifications - user_profile.save(update_fields=["pm_content_in_desktop_notifications"]) - event = {'type': 'update_global_notifications', - 'user': user_profile.email, - 'notification_name': 'pm_content_in_desktop_notifications', - 'setting': pm_content_in_desktop_notifications} - if log: - log_event(event) - send_event(event, [user_profile.id]) - - -def do_change_enable_sounds(user_profile, enable_sounds, log=True): - # type: (UserProfile, bool, bool) -> None - user_profile.enable_sounds = enable_sounds - user_profile.save(update_fields=["enable_sounds"]) - event = {'type': 'update_global_notifications', - 'user': user_profile.email, - 'notification_name': 'enable_sounds', - 'setting': enable_sounds} - if log: - log_event(event) - send_event(event, [user_profile.id]) - -def do_change_enable_offline_email_notifications(user_profile, offline_email_notifications, log=True): - # type: (UserProfile, bool, bool) -> None - user_profile.enable_offline_email_notifications = offline_email_notifications - user_profile.save(update_fields=["enable_offline_email_notifications"]) - event = {'type': 'update_global_notifications', - 'user': user_profile.email, - 'notification_name': 'enable_offline_email_notifications', - 'setting': offline_email_notifications} - if log: - log_event(event) - send_event(event, [user_profile.id]) - -def do_change_enable_offline_push_notifications(user_profile, offline_push_notifications, log=True): - # type: (UserProfile, bool, bool) -> None - user_profile.enable_offline_push_notifications = offline_push_notifications - user_profile.save(update_fields=["enable_offline_push_notifications"]) - event = {'type': 'update_global_notifications', - 'user': user_profile.email, - 'notification_name': 'enable_offline_push_notifications', - 'setting': offline_push_notifications} - if log: - log_event(event) - send_event(event, [user_profile.id]) - -def do_change_enable_online_push_notifications(user_profile, enable_online_push_notifications, log=True): - # type: (UserProfile, bool, bool) -> None - user_profile.enable_online_push_notifications = enable_online_push_notifications - user_profile.save(update_fields=["enable_online_push_notifications"]) - event = {'type': 'update_global_notifications', - 'user': user_profile.email, - 'notification_name': 'enable_online_push_notifications', - 'setting': enable_online_push_notifications} - if log: - log_event(event) - send_event(event, [user_profile.id]) - -def do_change_enable_digest_emails(user_profile, enable_digest_emails, log=True): - # type: (UserProfile, bool, bool) -> None - user_profile.enable_digest_emails = enable_digest_emails - user_profile.save(update_fields=["enable_digest_emails"]) - - if not enable_digest_emails: - # Remove any digest emails that have been enqueued. + # Disabling digest emails should clear a user's email queue + if name == 'enable_digest_emails' and value == False: clear_followup_emails_queue(user_profile.email) + user_profile.save(update_fields=[name]) event = {'type': 'update_global_notifications', 'user': user_profile.email, - 'notification_name': 'enable_digest_emails', - 'setting': enable_digest_emails} + 'notification_name': name, + 'setting': value} if log: log_event(event) send_event(event, [user_profile.id]) diff --git a/zerver/management/commands/turn_off_digests.py b/zerver/management/commands/turn_off_digests.py index 8b37f3eea5..ecf822b0b2 100644 --- a/zerver/management/commands/turn_off_digests.py +++ b/zerver/management/commands/turn_off_digests.py @@ -7,7 +7,7 @@ from optparse import make_option from django.core.management.base import BaseCommand, CommandParser -from zerver.lib.actions import do_change_enable_digest_emails +from zerver.lib.actions import do_change_notification_settings from zerver.models import Realm, UserProfile, get_realm, get_user_profile_by_email class Command(BaseCommand): @@ -45,7 +45,7 @@ class Command(BaseCommand): for user_profile in user_profiles: already_disabled_prefix = "" if user_profile.enable_digest_emails: - do_change_enable_digest_emails(user_profile, False) + do_change_notification_settings(user_profile, 'enable_digest_emails', False) else: already_disabled_prefix = "(already off) " print("%s%s <%s>" % (already_disabled_prefix, user_profile.full_name, diff --git a/zerver/models.py b/zerver/models.py index 6c56be4f11..e228fc01e5 100644 --- a/zerver/models.py +++ b/zerver/models.py @@ -661,6 +661,18 @@ class UserProfile(ModelReprMixin, AbstractBaseUser, PermissionsMixin): twenty_four_hour_time=bool, ) + notification_setting_types = dict( + enable_desktop_notifications=bool, + enable_digest_emails=bool, + enable_offline_email_notifications=bool, + enable_offline_push_notifications=bool, + enable_online_push_notifications=bool, + enable_sounds=bool, + enable_stream_desktop_notifications=bool, + enable_stream_sounds=bool, + pm_content_in_desktop_notifications=bool, + ) + @property def profile_data(self): # type: () -> List[Dict[str, Union[int, float, Text]]] diff --git a/zerver/tests/test_events.py b/zerver/tests/test_events.py index 15025c7d29..b8137fcdd3 100644 --- a/zerver/tests/test_events.py +++ b/zerver/tests/test_events.py @@ -59,15 +59,7 @@ from zerver.lib.actions import ( do_update_pointer, do_update_user_presence, do_set_user_display_setting, - do_change_enable_stream_desktop_notifications, - do_change_enable_stream_sounds, - do_change_enable_desktop_notifications, - do_change_enable_sounds, - do_change_enable_offline_email_notifications, - do_change_enable_offline_push_notifications, - do_change_enable_online_push_notifications, - do_change_pm_content_in_desktop_notifications, - do_change_enable_digest_emails, + do_change_notification_settings, do_add_realm_domain, do_change_realm_domain, do_remove_realm_domain, @@ -1037,136 +1029,21 @@ class EventsRegisterTest(ZulipTestCase): # type: () -> None self.do_set_user_display_settings_test("timezone", [u'US/Mountain', u'US/Samoa', u'Pacific/Galapagos', u'']) - def test_change_enable_stream_desktop_notifications(self): + def test_change_notification_settings(self): # type: () -> None - schema_checker = self.check_events_dict([ - ('type', equals('update_global_notifications')), - ('notification_name', equals('enable_stream_desktop_notifications')), - ('user', check_string), - ('setting', check_bool), - ]) - do_change_enable_stream_desktop_notifications(self.user_profile, False) - for setting_value in [True, False]: - events = self.do_test(lambda: do_change_enable_stream_desktop_notifications(self.user_profile, setting_value, log=False)) - error = schema_checker('events[0]', events[0]) - self.assert_on_error(error) - - def test_change_enable_stream_sounds(self): - # type: () -> None - schema_checker = self.check_events_dict([ - ('type', equals('update_global_notifications')), - ('notification_name', equals('enable_stream_sounds')), - ('user', check_string), - ('setting', check_bool), - ]) - do_change_enable_stream_sounds(self.user_profile, False) - for setting_value in [True, False]: - events = self.do_test(lambda: do_change_enable_stream_sounds(self.user_profile, setting_value, log=False)) - error = schema_checker('events[0]', events[0]) - self.assert_on_error(error) - - def test_change_enable_desktop_notifications(self): - # type: () -> None - schema_checker = self.check_events_dict([ - ('type', equals('update_global_notifications')), - ('notification_name', equals('enable_desktop_notifications')), - ('user', check_string), - ('setting', check_bool), - ]) - do_change_enable_desktop_notifications(self.user_profile, False) - for setting_value in [True, False]: - events = self.do_test(lambda: do_change_enable_desktop_notifications(self.user_profile, setting_value, log=False)) - error = schema_checker('events[0]', events[0]) - self.assert_on_error(error) - - def test_change_enable_sounds(self): - # type: () -> None - schema_checker = self.check_events_dict([ - ('type', equals('update_global_notifications')), - ('notification_name', equals('enable_sounds')), - ('user', check_string), - ('setting', check_bool), - ]) - do_change_enable_sounds(self.user_profile, False) - for setting_value in [True, False]: - events = self.do_test(lambda: do_change_enable_sounds(self.user_profile, setting_value, log=False)) - error = schema_checker('events[0]', events[0]) - self.assert_on_error(error) - - def test_change_enable_offline_email_notifications(self): - # type: () -> None - schema_checker = self.check_events_dict([ - ('type', equals('update_global_notifications')), - ('notification_name', equals('enable_offline_email_notifications')), - ('user', check_string), - ('setting', check_bool), - ]) - do_change_enable_offline_email_notifications(self.user_profile, False) - for setting_value in [True, False]: - events = self.do_test(lambda: do_change_enable_offline_email_notifications(self.user_profile, setting_value, log=False)) - error = schema_checker('events[0]', events[0]) - self.assert_on_error(error) - - def test_change_enable_offline_push_notifications(self): - # type: () -> None - schema_checker = self.check_events_dict([ - ('type', equals('update_global_notifications')), - ('notification_name', equals('enable_offline_push_notifications')), - ('user', check_string), - ('setting', check_bool), - ]) - do_change_enable_offline_push_notifications(self.user_profile, False) - for setting_value in [True, False]: - events = self.do_test(lambda: do_change_enable_offline_push_notifications(self.user_profile, setting_value, log=False)) - error = schema_checker('events[0]', events[0]) - self.assert_on_error(error) - - def test_change_enable_online_push_notifications(self): - # type: () -> None - schema_checker = self.check_events_dict([ - ('type', equals('update_global_notifications')), - ('notification_name', equals('enable_online_push_notifications')), - ('user', check_string), - ('setting', check_bool), - ]) - - do_change_enable_online_push_notifications(self.user_profile, False) - for setting_value in [True, False]: - events = self.do_test(lambda: do_change_enable_online_push_notifications(self.user_profile, setting_value, log=False)) - error = schema_checker('events[0]', events[0]) - self.assert_on_error(error) - - def test_change_pm_content_in_desktop_notifications(self): - # type: () -> None - schema_checker = self.check_events_dict([ - ('type', equals('update_global_notifications')), - ('notification_name', equals('pm_content_in_desktop_notifications')), - ('user', check_string), - ('setting', check_bool), - ]) - do_change_pm_content_in_desktop_notifications(self.user_profile, False) - for setting_value in [True, False]: - events = self.do_test( - lambda: do_change_pm_content_in_desktop_notifications(self.user_profile, - setting_value, - log=False), - ) - error = schema_checker('events[0]', events[0]) - self.assert_on_error(error) - - def test_change_enable_digest_emails(self): - # type: () -> None - schema_checker = self.check_events_dict([ - ('type', equals('update_global_notifications')), - ('notification_name', equals('enable_digest_emails')), - ('user', check_string), - ('setting', check_bool), - ]) - do_change_enable_digest_emails(self.user_profile, False) - for setting_value in [True, False]: - events = self.do_test(lambda: do_change_enable_digest_emails(self.user_profile, setting_value, log=False)) - error = schema_checker('events[0]', events[0]) - self.assert_on_error(error) + for notification_setting, v in self.user_profile.notification_setting_types.items(): + schema_checker = self.check_events_dict([ + ('type', equals('update_global_notifications')), + ('notification_name', equals(notification_setting)), + ('user', check_string), + ('setting', check_bool), + ]) + do_change_notification_settings(self.user_profile, notification_setting, False) + for setting_value in [True, False]: + events = self.do_test(lambda: do_change_notification_settings( + self.user_profile, notification_setting, setting_value, log=False)) + error = schema_checker('events[0]', events[0]) + self.assert_on_error(error) def test_realm_emoji_events(self): # type: () -> None diff --git a/zerver/views/unsubscribe.py b/zerver/views/unsubscribe.py index 94a379a557..06872f4d6a 100644 --- a/zerver/views/unsubscribe.py +++ b/zerver/views/unsubscribe.py @@ -6,8 +6,7 @@ from django.shortcuts import render from typing import Callable from confirmation.models import Confirmation -from zerver.lib.actions import do_change_enable_offline_email_notifications, \ - do_change_enable_digest_emails, clear_followup_emails_queue +from zerver.lib.actions import do_change_notification_settings, clear_followup_emails_queue from zerver.models import UserProfile from zerver.context_processors import common_context @@ -29,7 +28,7 @@ def process_unsubscribe(request, token, subscription_type, unsubscribe_function) def do_missedmessage_unsubscribe(user_profile): # type: (UserProfile) -> None - do_change_enable_offline_email_notifications(user_profile, False) + do_change_notification_settings(user_profile, 'enable_offline_email_notifications', False) def do_welcome_unsubscribe(user_profile): # type: (UserProfile) -> None @@ -37,7 +36,7 @@ def do_welcome_unsubscribe(user_profile): def do_digest_unsubscribe(user_profile): # type: (UserProfile) -> None - do_change_enable_digest_emails(user_profile, False) + do_change_notification_settings(user_profile, 'enable_digest_emails', False) # The keys are part of the URL for the unsubscribe link and must be valid # without encoding. diff --git a/zerver/views/user_settings.py b/zerver/views/user_settings.py index ca0d0827fb..a395beb714 100644 --- a/zerver/views/user_settings.py +++ b/zerver/views/user_settings.py @@ -12,15 +12,10 @@ from django.urls import reverse from zerver.decorator import authenticated_json_post_view, has_request_variables, \ zulip_login_required, REQ, human_users_only from zerver.lib.actions import do_change_password, \ - do_change_enable_desktop_notifications, \ - do_change_enter_sends, do_change_enable_sounds, \ - do_change_enable_offline_email_notifications, do_change_enable_digest_emails, \ - do_change_enable_offline_push_notifications, do_change_enable_online_push_notifications, \ + do_change_enter_sends, do_change_notification_settings, \ do_change_default_desktop_notifications, do_change_autoscroll_forever, \ - do_change_enable_stream_desktop_notifications, do_change_enable_stream_sounds, \ do_regenerate_api_key, do_change_avatar_fields, do_set_user_display_setting, \ - do_change_pm_content_in_desktop_notifications, validate_email, \ - do_change_user_email, do_start_email_change_process + validate_email, do_change_user_email, do_start_email_change_process from zerver.lib.avatar import avatar_url from zerver.lib.send_email import send_email, display_email from zerver.lib.i18n import get_available_language_codes @@ -206,53 +201,12 @@ def json_change_notify_settings(request, user_profile, # Stream notification settings. - if enable_stream_desktop_notifications is not None and \ - user_profile.enable_stream_desktop_notifications != enable_stream_desktop_notifications: - do_change_enable_stream_desktop_notifications( - user_profile, enable_stream_desktop_notifications) - result['enable_stream_desktop_notifications'] = enable_stream_desktop_notifications + req_vars = {k: v for k, v in list(locals().items()) if k in user_profile.notification_setting_types} - if enable_stream_sounds is not None and \ - user_profile.enable_stream_sounds != enable_stream_sounds: - do_change_enable_stream_sounds(user_profile, enable_stream_sounds) - result['enable_stream_sounds'] = enable_stream_sounds - - # PM and @-mention settings. - - if enable_desktop_notifications is not None and \ - user_profile.enable_desktop_notifications != enable_desktop_notifications: - do_change_enable_desktop_notifications(user_profile, enable_desktop_notifications) - result['enable_desktop_notifications'] = enable_desktop_notifications - - if enable_sounds is not None and \ - user_profile.enable_sounds != enable_sounds: - do_change_enable_sounds(user_profile, enable_sounds) - result['enable_sounds'] = enable_sounds - - if enable_offline_email_notifications is not None and \ - user_profile.enable_offline_email_notifications != enable_offline_email_notifications: - do_change_enable_offline_email_notifications(user_profile, enable_offline_email_notifications) - result['enable_offline_email_notifications'] = enable_offline_email_notifications - - if enable_offline_push_notifications is not None and \ - user_profile.enable_offline_push_notifications != enable_offline_push_notifications: - do_change_enable_offline_push_notifications(user_profile, enable_offline_push_notifications) - result['enable_offline_push_notifications'] = enable_offline_push_notifications - - if enable_online_push_notifications is not None and \ - user_profile.enable_online_push_notifications != enable_online_push_notifications: - do_change_enable_online_push_notifications(user_profile, enable_online_push_notifications) - result['enable_online_push_notifications'] = enable_online_push_notifications - - if enable_digest_emails is not None and \ - user_profile.enable_digest_emails != enable_digest_emails: - do_change_enable_digest_emails(user_profile, enable_digest_emails) - result['enable_digest_emails'] = enable_digest_emails - - if pm_content_in_desktop_notifications is not None and \ - user_profile.pm_content_in_desktop_notifications != pm_content_in_desktop_notifications: - do_change_pm_content_in_desktop_notifications(user_profile, pm_content_in_desktop_notifications) - result['pm_content_in_desktop_notifications'] = pm_content_in_desktop_notifications + for k, v in list(req_vars.items()): + if v is not None and getattr(user_profile, k) != v: + do_change_notification_settings(user_profile, k, v) + result[k] = v return json_success(result)