mirror of
https://github.com/zulip/zulip.git
synced 2026-07-03 21:10:12 +08:00
user_settings: Create _legacy dicts for existing settings.
Since 84742a0, all settings are sent in the `user_settings` dictionary
which were previously sent inline with other fields in /register
response.
In order to simplify the process of adding new personal settings, we
want to transition to a world where new settings only need to consider
the `property_types` object, and code that needs to reference the
legacy behavior interacts with an object with `legacy` in its name.
This way, contributors working on new settings don't need to think
about the legacy code paths at all.
See https://chat.zulip.org/#narrow/stream/378-api-design/topic/user.20settings.20response.20in.20.2Fregister
to understand this better.
This commit is contained in:
parent
fd77ebcc2a
commit
430c5cb8e7
@ -5069,15 +5069,17 @@ def do_change_notification_settings(
|
|||||||
|
|
||||||
send_event(user_profile.realm, event, [user_profile.id])
|
send_event(user_profile.realm, event, [user_profile.id])
|
||||||
|
|
||||||
# This legacy event format is for backwards-compatiblity with
|
if name in UserProfile.notification_settings_legacy:
|
||||||
# clients that don't support the new user_settings event type.
|
# This legacy event format is for backwards-compatiblity with
|
||||||
legacy_event = {
|
# clients that don't support the new user_settings event type.
|
||||||
"type": "update_global_notifications",
|
# We only send this for settings added before Feature level 89.
|
||||||
"user": user_profile.email,
|
legacy_event = {
|
||||||
"notification_name": name,
|
"type": "update_global_notifications",
|
||||||
"setting": value,
|
"user": user_profile.email,
|
||||||
}
|
"notification_name": name,
|
||||||
send_event(user_profile.realm, legacy_event, [user_profile.id])
|
"setting": value,
|
||||||
|
}
|
||||||
|
send_event(user_profile.realm, legacy_event, [user_profile.id])
|
||||||
|
|
||||||
|
|
||||||
def do_set_user_display_setting(
|
def do_set_user_display_setting(
|
||||||
@ -5103,19 +5105,21 @@ def do_set_user_display_setting(
|
|||||||
|
|
||||||
send_event(user_profile.realm, event, [user_profile.id])
|
send_event(user_profile.realm, event, [user_profile.id])
|
||||||
|
|
||||||
# This legacy event format is for backwards-compatiblity with
|
if setting_name in UserProfile.display_settings_legacy or setting_name == "timezone":
|
||||||
# clients that don't support the new user_settings event type.
|
# This legacy event format is for backwards-compatiblity with
|
||||||
legacy_event = {
|
# clients that don't support the new user_settings event type.
|
||||||
"type": "update_display_settings",
|
# We only send this for settings added before Feature level 89.
|
||||||
"user": user_profile.email,
|
legacy_event = {
|
||||||
"setting_name": setting_name,
|
"type": "update_display_settings",
|
||||||
"setting": setting_value,
|
"user": user_profile.email,
|
||||||
}
|
"setting_name": setting_name,
|
||||||
if setting_name == "default_language":
|
"setting": setting_value,
|
||||||
assert isinstance(setting_value, str)
|
}
|
||||||
legacy_event["language_name"] = get_language_name(setting_value)
|
if setting_name == "default_language":
|
||||||
|
assert isinstance(setting_value, str)
|
||||||
|
legacy_event["language_name"] = get_language_name(setting_value)
|
||||||
|
|
||||||
send_event(user_profile.realm, legacy_event, [user_profile.id])
|
send_event(user_profile.realm, legacy_event, [user_profile.id])
|
||||||
|
|
||||||
# Updates to the timezone display setting are sent to all users
|
# Updates to the timezone display setting are sent to all users
|
||||||
if setting_name == "timezone":
|
if setting_name == "timezone":
|
||||||
|
|||||||
@ -1443,11 +1443,8 @@ def check_user_settings_update(
|
|||||||
assert isinstance(setting_name, str)
|
assert isinstance(setting_name, str)
|
||||||
if setting_name == "timezone":
|
if setting_name == "timezone":
|
||||||
assert isinstance(value, str)
|
assert isinstance(value, str)
|
||||||
elif setting_name in UserProfile.property_types:
|
|
||||||
setting_type = UserProfile.property_types[setting_name]
|
|
||||||
assert isinstance(value, setting_type)
|
|
||||||
else:
|
else:
|
||||||
setting_type = UserProfile.notification_setting_types[setting_name]
|
setting_type = UserProfile.property_types[setting_name]
|
||||||
assert isinstance(value, setting_type)
|
assert isinstance(value, setting_type)
|
||||||
|
|
||||||
if setting_name == "default_language":
|
if setting_name == "default_language":
|
||||||
|
|||||||
@ -515,13 +515,13 @@ def fetch_initial_state_data(
|
|||||||
state["stop_words"] = read_stop_words()
|
state["stop_words"] = read_stop_words()
|
||||||
|
|
||||||
if want("update_display_settings") and not user_settings_object:
|
if want("update_display_settings") and not user_settings_object:
|
||||||
for prop in UserProfile.property_types:
|
for prop in UserProfile.display_settings_legacy:
|
||||||
state[prop] = getattr(settings_user, prop)
|
state[prop] = getattr(settings_user, prop)
|
||||||
state["emojiset_choices"] = UserProfile.emojiset_choices()
|
state["emojiset_choices"] = UserProfile.emojiset_choices()
|
||||||
state["timezone"] = settings_user.timezone
|
state["timezone"] = settings_user.timezone
|
||||||
|
|
||||||
if want("update_global_notifications") and not user_settings_object:
|
if want("update_global_notifications") and not user_settings_object:
|
||||||
for notification in UserProfile.notification_setting_types:
|
for notification in UserProfile.notification_settings_legacy:
|
||||||
state[notification] = getattr(settings_user, notification)
|
state[notification] = getattr(settings_user, notification)
|
||||||
state["available_notification_sounds"] = get_available_notification_sounds()
|
state["available_notification_sounds"] = get_available_notification_sounds()
|
||||||
|
|
||||||
@ -530,8 +530,6 @@ def fetch_initial_state_data(
|
|||||||
|
|
||||||
for prop in UserProfile.property_types:
|
for prop in UserProfile.property_types:
|
||||||
state["user_settings"][prop] = getattr(settings_user, prop)
|
state["user_settings"][prop] = getattr(settings_user, prop)
|
||||||
for notification in UserProfile.notification_setting_types:
|
|
||||||
state["user_settings"][notification] = getattr(settings_user, notification)
|
|
||||||
|
|
||||||
state["user_settings"]["emojiset_choices"] = UserProfile.emojiset_choices()
|
state["user_settings"]["emojiset_choices"] = UserProfile.emojiset_choices()
|
||||||
state["user_settings"]["timezone"] = settings_user.timezone
|
state["user_settings"]["timezone"] = settings_user.timezone
|
||||||
@ -1112,20 +1110,16 @@ def apply_event(
|
|||||||
state["realm_playgrounds"] = event["realm_playgrounds"]
|
state["realm_playgrounds"] = event["realm_playgrounds"]
|
||||||
elif event["type"] == "update_display_settings":
|
elif event["type"] == "update_display_settings":
|
||||||
if event["setting_name"] != "timezone":
|
if event["setting_name"] != "timezone":
|
||||||
assert event["setting_name"] in UserProfile.property_types
|
assert event["setting_name"] in UserProfile.display_settings_legacy
|
||||||
state[event["setting_name"]] = event["setting"]
|
state[event["setting_name"]] = event["setting"]
|
||||||
elif event["type"] == "update_global_notifications":
|
elif event["type"] == "update_global_notifications":
|
||||||
assert event["notification_name"] in UserProfile.notification_setting_types
|
assert event["notification_name"] in UserProfile.notification_settings_legacy
|
||||||
state[event["notification_name"]] = event["setting"]
|
state[event["notification_name"]] = event["setting"]
|
||||||
elif event["type"] == "user_settings":
|
elif event["type"] == "user_settings":
|
||||||
# timezone setting is not included in property_types or
|
# timezone setting is not included in property_types dict because
|
||||||
# notification_setting_types dicts, because this setting
|
# this setting is not a part of UserBaseSettings class.
|
||||||
# is not a part of UserBaseSettings class.
|
|
||||||
if event["property"] != "timezone":
|
if event["property"] != "timezone":
|
||||||
assert (
|
assert event["property"] in UserProfile.property_types
|
||||||
event["property"] in UserProfile.property_types
|
|
||||||
or event["property"] in UserProfile.notification_setting_types
|
|
||||||
)
|
|
||||||
state[event["property"]] = event["value"]
|
state[event["property"]] = event["value"]
|
||||||
state["user_settings"][event["property"]] = event["value"]
|
state["user_settings"][event["property"]] = event["value"]
|
||||||
elif event["type"] == "invites_changed":
|
elif event["type"] == "invites_changed":
|
||||||
|
|||||||
@ -1362,8 +1362,7 @@ class UserBaseSettings(models.Model):
|
|||||||
# Whether or not the user wants to sync their drafts.
|
# Whether or not the user wants to sync their drafts.
|
||||||
enable_drafts_synchronization = models.BooleanField(default=True)
|
enable_drafts_synchronization = models.BooleanField(default=True)
|
||||||
|
|
||||||
# Define the types of the various automatically managed properties
|
display_settings_legacy = dict(
|
||||||
property_types = dict(
|
|
||||||
color_scheme=int,
|
color_scheme=int,
|
||||||
default_language=str,
|
default_language=str,
|
||||||
default_view=str,
|
default_view=str,
|
||||||
@ -1380,7 +1379,7 @@ class UserBaseSettings(models.Model):
|
|||||||
twenty_four_hour_time=bool,
|
twenty_four_hour_time=bool,
|
||||||
)
|
)
|
||||||
|
|
||||||
notification_setting_types = dict(
|
notification_settings_legacy = dict(
|
||||||
enable_desktop_notifications=bool,
|
enable_desktop_notifications=bool,
|
||||||
enable_digest_emails=bool,
|
enable_digest_emails=bool,
|
||||||
enable_login_emails=bool,
|
enable_login_emails=bool,
|
||||||
@ -1403,6 +1402,13 @@ class UserBaseSettings(models.Model):
|
|||||||
presence_enabled=bool,
|
presence_enabled=bool,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
notification_setting_types = {
|
||||||
|
**notification_settings_legacy
|
||||||
|
} # Add new notifications settings here.
|
||||||
|
|
||||||
|
# Define the types of the various automatically managed properties
|
||||||
|
property_types = {**display_settings_legacy, **notification_setting_types}
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
|
|||||||
@ -2204,7 +2204,10 @@ class UserDisplayActionTest(BaseAction):
|
|||||||
|
|
||||||
def test_set_user_display_settings(self) -> None:
|
def test_set_user_display_settings(self) -> None:
|
||||||
for prop in UserProfile.property_types:
|
for prop in UserProfile.property_types:
|
||||||
self.do_set_user_display_settings_test(prop)
|
# Notification settings have a separate test suite, which
|
||||||
|
# handles their separate legacy event type.
|
||||||
|
if prop not in UserProfile.notification_settings_legacy:
|
||||||
|
self.do_set_user_display_settings_test(prop)
|
||||||
|
|
||||||
def test_set_user_timezone(self) -> None:
|
def test_set_user_timezone(self) -> None:
|
||||||
values = ["America/Denver", "Pacific/Pago_Pago", "Pacific/Galapagos", ""]
|
values = ["America/Denver", "Pacific/Pago_Pago", "Pacific/Galapagos", ""]
|
||||||
|
|||||||
@ -319,7 +319,7 @@ class ChangeSettingsTest(ZulipTestCase):
|
|||||||
)
|
)
|
||||||
self.assert_json_error(result, "Your Zulip password is managed in LDAP")
|
self.assert_json_error(result, "Your Zulip password is managed in LDAP")
|
||||||
|
|
||||||
def do_test_change_user_display_setting(self, setting_name: str) -> None:
|
def do_test_change_user_setting(self, setting_name: str) -> None:
|
||||||
|
|
||||||
test_changes: Dict[str, Any] = dict(
|
test_changes: Dict[str, Any] = dict(
|
||||||
default_language="de",
|
default_language="de",
|
||||||
@ -366,14 +366,19 @@ class ChangeSettingsTest(ZulipTestCase):
|
|||||||
user_profile = self.example_user("hamlet")
|
user_profile = self.example_user("hamlet")
|
||||||
self.assertNotEqual(getattr(user_profile, setting_name), invalid_value)
|
self.assertNotEqual(getattr(user_profile, setting_name), invalid_value)
|
||||||
|
|
||||||
def test_change_user_display_setting(self) -> None:
|
def test_change_user_setting(self) -> None:
|
||||||
"""Test updating each non-boolean setting in UserProfile property_types"""
|
"""Test updating each non-boolean setting in UserProfile property_types"""
|
||||||
user_settings = (
|
user_settings = (
|
||||||
s for s in UserProfile.property_types if UserProfile.property_types[s] is not bool
|
s
|
||||||
|
for s in UserProfile.property_types
|
||||||
|
if UserProfile.property_types[s] is not bool
|
||||||
|
# Legacy notification settings have a separate test suite, though
|
||||||
|
# we can likely merge that test suite with this one in the future.
|
||||||
|
and s not in UserProfile.notification_settings_legacy
|
||||||
)
|
)
|
||||||
for setting in user_settings:
|
for setting in user_settings:
|
||||||
self.do_test_change_user_display_setting(setting)
|
self.do_test_change_user_setting(setting)
|
||||||
self.do_test_change_user_display_setting("timezone")
|
self.do_test_change_user_setting("timezone")
|
||||||
|
|
||||||
def do_change_emojiset(self, emojiset: str) -> HttpResponse:
|
def do_change_emojiset(self, emojiset: str) -> HttpResponse:
|
||||||
self.login("hamlet")
|
self.login("hamlet")
|
||||||
|
|||||||
@ -259,7 +259,11 @@ def json_change_settings(
|
|||||||
check_change_full_name(user_profile, full_name, user_profile)
|
check_change_full_name(user_profile, full_name, user_profile)
|
||||||
|
|
||||||
# Loop over user_profile.property_types
|
# Loop over user_profile.property_types
|
||||||
request_settings = {k: v for k, v in list(locals().items()) if k in user_profile.property_types}
|
request_settings = {
|
||||||
|
k: v
|
||||||
|
for k, v in list(locals().items())
|
||||||
|
if k in user_profile.property_types and k not in user_profile.notification_setting_types
|
||||||
|
}
|
||||||
for k, v in list(request_settings.items()):
|
for k, v in list(request_settings.items()):
|
||||||
if v is not None and getattr(user_profile, k) != v:
|
if v is not None and getattr(user_profile, k) != v:
|
||||||
do_set_user_display_setting(user_profile, k, v)
|
do_set_user_display_setting(user_profile, k, v)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user