mirror of https://github.com/zulip/zulip.git
events: Add new event type 'user_settings' for updating user settings.
We send a event with type 'user_settings' on updating user's display and notification settings. The old event types - 'update_global_notifications' and 'update_display_settings', are still supported for backwards compatibility.
This commit is contained in:
parent
e73d2fff97
commit
7959ae3fab
|
@ -11,6 +11,13 @@ below features are supported.
|
||||||
|
|
||||||
## Changes in Zulip 5.0
|
## Changes in Zulip 5.0
|
||||||
|
|
||||||
|
**Feature level 89**
|
||||||
|
|
||||||
|
* [`GET /events`](/api/get-events): Introduced new event type
|
||||||
|
`user_settings`. The previous `update_display_settings` and
|
||||||
|
`update_global_notifications` event types are still supported
|
||||||
|
for backwards compatibility, but will be removed in future.
|
||||||
|
|
||||||
**Feature level 88**
|
**Feature level 88**
|
||||||
|
|
||||||
* [`POST /register`](/api/register-queue): Added `zulip_merge_base`
|
* [`POST /register`](/api/register-queue): Added `zulip_merge_base`
|
||||||
|
|
|
@ -33,7 +33,7 @@ DESKTOP_WARNING_VERSION = "5.4.3"
|
||||||
# Changes should be accompanied by documentation explaining what the
|
# Changes should be accompanied by documentation explaining what the
|
||||||
# new level means in templates/zerver/api/changelog.md, as well as
|
# new level means in templates/zerver/api/changelog.md, as well as
|
||||||
# "**Changes**" entries in the endpoint's documentation in `zulip.yaml`.
|
# "**Changes**" entries in the endpoint's documentation in `zulip.yaml`.
|
||||||
API_FEATURE_LEVEL = 88
|
API_FEATURE_LEVEL = 89
|
||||||
|
|
||||||
# Bump the minor PROVISION_VERSION to indicate that folks should provision
|
# Bump the minor PROVISION_VERSION to indicate that folks should provision
|
||||||
# only when going from an old version of the code to a newer version. Bump
|
# only when going from an old version of the code to a newer version. Bump
|
||||||
|
|
|
@ -5043,10 +5043,10 @@ def do_change_notification_settings(
|
||||||
|
|
||||||
user_profile.save(update_fields=[name])
|
user_profile.save(update_fields=[name])
|
||||||
event = {
|
event = {
|
||||||
"type": "update_global_notifications",
|
"type": "user_settings",
|
||||||
"user": user_profile.email,
|
"op": "update",
|
||||||
"notification_name": name,
|
"property": name,
|
||||||
"setting": value,
|
"value": value,
|
||||||
}
|
}
|
||||||
event_time = timezone_now()
|
event_time = timezone_now()
|
||||||
RealmAuditLog.objects.create(
|
RealmAuditLog.objects.create(
|
||||||
|
@ -5066,6 +5066,16 @@ 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
|
||||||
|
# clients that don't support the new user_settings event type.
|
||||||
|
legacy_event = {
|
||||||
|
"type": "update_global_notifications",
|
||||||
|
"user": user_profile.email,
|
||||||
|
"notification_name": name,
|
||||||
|
"setting": value,
|
||||||
|
}
|
||||||
|
send_event(user_profile.realm, legacy_event, [user_profile.id])
|
||||||
|
|
||||||
|
|
||||||
def do_set_user_display_setting(
|
def do_set_user_display_setting(
|
||||||
user_profile: UserProfile, setting_name: str, setting_value: Union[bool, str, int]
|
user_profile: UserProfile, setting_name: str, setting_value: Union[bool, str, int]
|
||||||
|
@ -5077,7 +5087,22 @@ def do_set_user_display_setting(
|
||||||
assert isinstance(setting_value, property_type)
|
assert isinstance(setting_value, property_type)
|
||||||
setattr(user_profile, setting_name, setting_value)
|
setattr(user_profile, setting_name, setting_value)
|
||||||
user_profile.save(update_fields=[setting_name])
|
user_profile.save(update_fields=[setting_name])
|
||||||
|
|
||||||
event = {
|
event = {
|
||||||
|
"type": "user_settings",
|
||||||
|
"op": "update",
|
||||||
|
"property": setting_name,
|
||||||
|
"value": setting_value,
|
||||||
|
}
|
||||||
|
if setting_name == "default_language":
|
||||||
|
assert isinstance(setting_value, str)
|
||||||
|
event["language_name"] = get_language_name(setting_value)
|
||||||
|
|
||||||
|
send_event(user_profile.realm, event, [user_profile.id])
|
||||||
|
|
||||||
|
# This legacy event format is for backwards-compatiblity with
|
||||||
|
# clients that don't support the new user_settings event type.
|
||||||
|
legacy_event = {
|
||||||
"type": "update_display_settings",
|
"type": "update_display_settings",
|
||||||
"user": user_profile.email,
|
"user": user_profile.email,
|
||||||
"setting_name": setting_name,
|
"setting_name": setting_name,
|
||||||
|
@ -5085,9 +5110,9 @@ def do_set_user_display_setting(
|
||||||
}
|
}
|
||||||
if setting_name == "default_language":
|
if setting_name == "default_language":
|
||||||
assert isinstance(setting_value, str)
|
assert isinstance(setting_value, str)
|
||||||
event["language_name"] = get_language_name(setting_value)
|
legacy_event["language_name"] = get_language_name(setting_value)
|
||||||
|
|
||||||
send_event(user_profile.realm, 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":
|
||||||
|
|
|
@ -1398,6 +1398,21 @@ update_display_settings_event = event_dict_type(
|
||||||
)
|
)
|
||||||
_check_update_display_settings = make_checker(update_display_settings_event)
|
_check_update_display_settings = make_checker(update_display_settings_event)
|
||||||
|
|
||||||
|
user_settings_update_event = event_dict_type(
|
||||||
|
required_keys=[
|
||||||
|
("type", Equals("user_settings")),
|
||||||
|
("op", Equals("update")),
|
||||||
|
("property", str),
|
||||||
|
("value", value_type),
|
||||||
|
],
|
||||||
|
optional_keys=[
|
||||||
|
# force vertical
|
||||||
|
("language_name", str),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
_check_user_settings_update = make_checker(user_settings_update_event)
|
||||||
|
|
||||||
|
|
||||||
def check_update_display_settings(
|
def check_update_display_settings(
|
||||||
var_name: str,
|
var_name: str,
|
||||||
|
@ -1425,6 +1440,30 @@ def check_update_display_settings(
|
||||||
assert "language_name" not in event.keys()
|
assert "language_name" not in event.keys()
|
||||||
|
|
||||||
|
|
||||||
|
def check_user_settings_update(
|
||||||
|
var_name: str,
|
||||||
|
event: Dict[str, object],
|
||||||
|
) -> None:
|
||||||
|
_check_user_settings_update(var_name, event)
|
||||||
|
setting_name = event["property"]
|
||||||
|
value = event["value"]
|
||||||
|
|
||||||
|
assert isinstance(setting_name, str)
|
||||||
|
if setting_name == "timezone":
|
||||||
|
assert isinstance(value, str)
|
||||||
|
elif setting_name in UserProfile.property_types:
|
||||||
|
setting_type = UserProfile.property_types[setting_name]
|
||||||
|
assert isinstance(value, setting_type)
|
||||||
|
else:
|
||||||
|
setting_type = UserProfile.notification_setting_types[setting_name]
|
||||||
|
assert isinstance(value, setting_type)
|
||||||
|
|
||||||
|
if setting_name == "default_language":
|
||||||
|
assert "language_name" in event.keys()
|
||||||
|
else:
|
||||||
|
assert "language_name" not in event.keys()
|
||||||
|
|
||||||
|
|
||||||
update_global_notifications_event = event_dict_type(
|
update_global_notifications_event = event_dict_type(
|
||||||
required_keys=[
|
required_keys=[
|
||||||
("type", Equals("update_global_notifications")),
|
("type", Equals("update_global_notifications")),
|
||||||
|
|
|
@ -1102,6 +1102,16 @@ def apply_event(
|
||||||
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_setting_types
|
||||||
state[event["notification_name"]] = event["setting"]
|
state[event["notification_name"]] = event["setting"]
|
||||||
|
elif event["type"] == "user_settings":
|
||||||
|
# timezone setting is not included in property_types or
|
||||||
|
# notification_setting_types dicts, because this setting
|
||||||
|
# is not a part of UserBaseSettings class.
|
||||||
|
if event["property"] != "timezone":
|
||||||
|
assert (
|
||||||
|
event["property"] in UserProfile.property_types
|
||||||
|
or event["property"] in UserProfile.notification_setting_types
|
||||||
|
)
|
||||||
|
state[event["property"]] = event["value"]
|
||||||
elif event["type"] == "invites_changed":
|
elif event["type"] == "invites_changed":
|
||||||
pass
|
pass
|
||||||
elif event["type"] == "user_group":
|
elif event["type"] == "user_group":
|
||||||
|
|
|
@ -243,6 +243,10 @@ paths:
|
||||||
description: |
|
description: |
|
||||||
Event sent to a user's clients when that user's display settings
|
Event sent to a user's clients when that user's display settings
|
||||||
have changed.
|
have changed.
|
||||||
|
|
||||||
|
**Changes**: Deprecated in Zulip 5.0 (feature level 89), replaced by
|
||||||
|
the `user_settings` event type.
|
||||||
|
deprecated: true
|
||||||
properties:
|
properties:
|
||||||
id:
|
id:
|
||||||
$ref: "#/components/schemas/EventIdSchema"
|
$ref: "#/components/schemas/EventIdSchema"
|
||||||
|
@ -280,6 +284,10 @@ paths:
|
||||||
description: |
|
description: |
|
||||||
Event sent to a user's clients when that user's [notification
|
Event sent to a user's clients when that user's [notification
|
||||||
settings](/api/update-settings) have changed.
|
settings](/api/update-settings) have changed.
|
||||||
|
|
||||||
|
**Changes**: Deprecated in Zulip 5.0 (feature level 89), replaced by
|
||||||
|
the `user_settings` event type.
|
||||||
|
deprecated: true
|
||||||
properties:
|
properties:
|
||||||
id:
|
id:
|
||||||
$ref: "#/components/schemas/EventIdSchema"
|
$ref: "#/components/schemas/EventIdSchema"
|
||||||
|
@ -307,6 +315,52 @@ paths:
|
||||||
"setting": true,
|
"setting": true,
|
||||||
"id": 0,
|
"id": 0,
|
||||||
}
|
}
|
||||||
|
- type: object
|
||||||
|
description: |
|
||||||
|
Event sent to a user's clients when that user's settings
|
||||||
|
have changed.
|
||||||
|
|
||||||
|
**Changes**: New in Zulip 5.0 (feature level 89), replacing the
|
||||||
|
previous `update_display_settings` and `update_global_notifications`
|
||||||
|
event types, which are still present for backwards compatibility reasons.
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
$ref: "#/components/schemas/EventIdSchema"
|
||||||
|
type:
|
||||||
|
allOf:
|
||||||
|
- $ref: "#/components/schemas/EventTypeSchema"
|
||||||
|
- enum:
|
||||||
|
- user_settings
|
||||||
|
op:
|
||||||
|
type: string
|
||||||
|
enum:
|
||||||
|
- update
|
||||||
|
property:
|
||||||
|
type: string
|
||||||
|
description: |
|
||||||
|
Name of the changed setting.
|
||||||
|
value:
|
||||||
|
description: |
|
||||||
|
New value of the changed setting.
|
||||||
|
oneOf:
|
||||||
|
- type: boolean
|
||||||
|
- type: integer
|
||||||
|
- type: string
|
||||||
|
language_name:
|
||||||
|
description: |
|
||||||
|
Present only if the setting to be changed is
|
||||||
|
`default_language`. Contains the name of the
|
||||||
|
new default language in English.
|
||||||
|
type: string
|
||||||
|
additionalProperties: false
|
||||||
|
example:
|
||||||
|
{
|
||||||
|
"type": "user_settings",
|
||||||
|
"op": "update",
|
||||||
|
"property": "high_contrast_mode",
|
||||||
|
"value": false,
|
||||||
|
"id": 0,
|
||||||
|
}
|
||||||
- type: object
|
- type: object
|
||||||
description: |
|
description: |
|
||||||
Event sent generally to all users in an organization for changes
|
Event sent generally to all users in an organization for changes
|
||||||
|
|
|
@ -161,6 +161,7 @@ from zerver.lib.event_schema import (
|
||||||
check_user_group_remove,
|
check_user_group_remove,
|
||||||
check_user_group_remove_members,
|
check_user_group_remove_members,
|
||||||
check_user_group_update,
|
check_user_group_update,
|
||||||
|
check_user_settings_update,
|
||||||
check_user_status,
|
check_user_status,
|
||||||
)
|
)
|
||||||
from zerver.lib.events import (
|
from zerver.lib.events import (
|
||||||
|
@ -1430,9 +1431,11 @@ class NormalActionsTest(BaseAction):
|
||||||
notification_setting,
|
notification_setting,
|
||||||
setting_value,
|
setting_value,
|
||||||
acting_user=self.user_profile,
|
acting_user=self.user_profile,
|
||||||
|
),
|
||||||
|
num_events=2,
|
||||||
)
|
)
|
||||||
)
|
check_user_settings_update("events[0]", events[0])
|
||||||
check_update_global_notifications("events[0]", events[0], setting_value)
|
check_update_global_notifications("events[1]", events[1], setting_value)
|
||||||
|
|
||||||
# Also test with notification_settings_null=True
|
# Also test with notification_settings_null=True
|
||||||
events = self.verify_action(
|
events = self.verify_action(
|
||||||
|
@ -1444,8 +1447,10 @@ class NormalActionsTest(BaseAction):
|
||||||
),
|
),
|
||||||
notification_settings_null=True,
|
notification_settings_null=True,
|
||||||
state_change_expected=False,
|
state_change_expected=False,
|
||||||
|
num_events=2,
|
||||||
)
|
)
|
||||||
check_update_global_notifications("events[0]", events[0], setting_value)
|
check_user_settings_update("events[0]", events[0])
|
||||||
|
check_update_global_notifications("events[1]", events[1], setting_value)
|
||||||
|
|
||||||
def test_change_notification_sound(self) -> None:
|
def test_change_notification_sound(self) -> None:
|
||||||
notification_setting = "notification_sound"
|
notification_setting = "notification_sound"
|
||||||
|
@ -1453,9 +1458,11 @@ class NormalActionsTest(BaseAction):
|
||||||
events = self.verify_action(
|
events = self.verify_action(
|
||||||
lambda: do_change_notification_settings(
|
lambda: do_change_notification_settings(
|
||||||
self.user_profile, notification_setting, "ding", acting_user=self.user_profile
|
self.user_profile, notification_setting, "ding", acting_user=self.user_profile
|
||||||
|
),
|
||||||
|
num_events=2,
|
||||||
)
|
)
|
||||||
)
|
check_user_settings_update("events[0]", events[0])
|
||||||
check_update_global_notifications("events[0]", events[0], "ding")
|
check_update_global_notifications("events[1]", events[1], "ding")
|
||||||
|
|
||||||
def test_change_desktop_icon_count_display(self) -> None:
|
def test_change_desktop_icon_count_display(self) -> None:
|
||||||
notification_setting = "desktop_icon_count_display"
|
notification_setting = "desktop_icon_count_display"
|
||||||
|
@ -1463,16 +1470,20 @@ class NormalActionsTest(BaseAction):
|
||||||
events = self.verify_action(
|
events = self.verify_action(
|
||||||
lambda: do_change_notification_settings(
|
lambda: do_change_notification_settings(
|
||||||
self.user_profile, notification_setting, 2, acting_user=self.user_profile
|
self.user_profile, notification_setting, 2, acting_user=self.user_profile
|
||||||
|
),
|
||||||
|
num_events=2,
|
||||||
)
|
)
|
||||||
)
|
check_user_settings_update("events[0]", events[0])
|
||||||
check_update_global_notifications("events[0]", events[0], 2)
|
check_update_global_notifications("events[1]", events[1], 2)
|
||||||
|
|
||||||
events = self.verify_action(
|
events = self.verify_action(
|
||||||
lambda: do_change_notification_settings(
|
lambda: do_change_notification_settings(
|
||||||
self.user_profile, notification_setting, 1, acting_user=self.user_profile
|
self.user_profile, notification_setting, 1, acting_user=self.user_profile
|
||||||
|
),
|
||||||
|
num_events=2,
|
||||||
)
|
)
|
||||||
)
|
check_user_settings_update("events[0]", events[0])
|
||||||
check_update_global_notifications("events[0]", events[0], 1)
|
check_update_global_notifications("events[1]", events[1], 1)
|
||||||
|
|
||||||
def test_realm_update_plan_type(self) -> None:
|
def test_realm_update_plan_type(self) -> None:
|
||||||
realm = self.user_profile.realm
|
realm = self.user_profile.realm
|
||||||
|
@ -2142,7 +2153,7 @@ class UserDisplayActionTest(BaseAction):
|
||||||
color_scheme=[2, 3, 1],
|
color_scheme=[2, 3, 1],
|
||||||
)
|
)
|
||||||
|
|
||||||
num_events = 1
|
num_events = 2
|
||||||
values = test_changes.get(setting_name)
|
values = test_changes.get(setting_name)
|
||||||
|
|
||||||
property_type = UserProfile.property_types[setting_name]
|
property_type = UserProfile.property_types[setting_name]
|
||||||
|
@ -2161,7 +2172,8 @@ class UserDisplayActionTest(BaseAction):
|
||||||
num_events=num_events,
|
num_events=num_events,
|
||||||
)
|
)
|
||||||
|
|
||||||
check_update_display_settings("events[0]", events[0])
|
check_user_settings_update("events[0]", events[0])
|
||||||
|
check_update_display_settings("events[1]", events[1])
|
||||||
|
|
||||||
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:
|
||||||
|
@ -2169,7 +2181,7 @@ class UserDisplayActionTest(BaseAction):
|
||||||
|
|
||||||
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", ""]
|
||||||
num_events = 2
|
num_events = 3
|
||||||
|
|
||||||
for value in values:
|
for value in values:
|
||||||
events = self.verify_action(
|
events = self.verify_action(
|
||||||
|
@ -2177,8 +2189,9 @@ class UserDisplayActionTest(BaseAction):
|
||||||
num_events=num_events,
|
num_events=num_events,
|
||||||
)
|
)
|
||||||
|
|
||||||
check_update_display_settings("events[0]", events[0])
|
check_user_settings_update("events[0]", events[0])
|
||||||
check_realm_user_update("events[1]", events[1], "timezone")
|
check_update_display_settings("events[1]", events[1])
|
||||||
|
check_realm_user_update("events[2]", events[2], "timezone")
|
||||||
|
|
||||||
|
|
||||||
class SubscribeActionTest(BaseAction):
|
class SubscribeActionTest(BaseAction):
|
||||||
|
|
Loading…
Reference in New Issue