diff --git a/templates/zerver/api/changelog.md b/templates/zerver/api/changelog.md index e58e15f8dd..90e8a3858f 100644 --- a/templates/zerver/api/changelog.md +++ b/templates/zerver/api/changelog.md @@ -11,6 +11,14 @@ below features are supported. ## Changes in Zulip 5.0 +**Feature level 80** + +* [`PATCH /settings`](/api/update-settings): The + `/settings/notifications` and `/settings/display` endpoints were + merged into the main `/settings` endpoint; now all personal settings + should be edited using that single endpoint. The old URLs are + preserved as deprecated aliases for backwards compatibility. + **Feature level 79** * [`GET /users/me/subscriptions`](/api/get-subscriptions): The @@ -22,12 +30,13 @@ below features are supported. **Feature level 78** -* `PATCH /settings`: Added `ignored_parameters_unsupported` field, - which is a list of parameters that were ignored by the endpoint, - to the response object. +* [`PATCH /settings`](/api/update-settings): Added + `ignored_parameters_unsupported` field, which is a list of + parameters that were ignored by the endpoint, to the response + object. -* `PATCH /settings`: Removed `full_name` and `account_email` fields - from the response object. +* [`PATCH /settings`](/api/update-settings): Removed `full_name` and + `account_email` fields from the response object. **Feature level 77** diff --git a/templates/zerver/help/include/rest-endpoints.md b/templates/zerver/help/include/rest-endpoints.md index 14f161df2f..f6cde3b639 100644 --- a/templates/zerver/help/include/rest-endpoints.md +++ b/templates/zerver/help/include/rest-endpoints.md @@ -44,8 +44,7 @@ * [Set "typing" status](/api/set-typing-status) * [Get user presence](/api/get-user-presence) * [Get attachments](/api/get-attachments) -* [Update display settings](/api/update-display-settings) -* [Update notification settings](/api/update-notification-settings) +* [Update settings](/api/update-settings) * [Get user groups](/api/get-user-groups) * [Create a user group](/api/create-user-group) * [Update a user group](/api/update-user-group) diff --git a/tools/linter_lib/custom_check.py b/tools/linter_lib/custom_check.py index c82a0a37a9..247d277940 100644 --- a/tools/linter_lib/custom_check.py +++ b/tools/linter_lib/custom_check.py @@ -820,7 +820,6 @@ markdown_docs_length_exclude = { "templates/zerver/api/get-messages.md", # This macro has a long indented URL "templates/zerver/help/include/git-webhook-url-with-branches-indented.md", - "templates/zerver/api/update-notification-settings.md", # These two are the same file and have some too-long lines for GitHub badges "README.md", "docs/overview/readme.md", diff --git a/version.py b/version.py index f2ff8a245b..d6d3e60fbe 100644 --- a/version.py +++ b/version.py @@ -33,7 +33,7 @@ DESKTOP_WARNING_VERSION = "5.4.3" # Changes should be accompanied by documentation explaining what the # new level means in templates/zerver/api/changelog.md, as well as # "**Changes**" entries in the endpoint's documentation in `zulip.yaml`. -API_FEATURE_LEVEL = 79 +API_FEATURE_LEVEL = 80 # 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 diff --git a/zerver/openapi/openapi.py b/zerver/openapi/openapi.py index b39e89c8fd..5f7daa11d9 100644 --- a/zerver/openapi/openapi.py +++ b/zerver/openapi/openapi.py @@ -28,9 +28,7 @@ EXCLUDE_UNDOCUMENTED_ENDPOINTS = { } # Consists of endpoints with some documentation remaining. # These are skipped but return true as the validator cannot exclude objects -EXCLUDE_DOCUMENTED_ENDPOINTS = { - ("/settings/notifications", "patch"), -} +EXCLUDE_DOCUMENTED_ENDPOINTS: Set[Tuple[str, str]] = set([]) # Most of our code expects allOf to be preprocessed away because that is what # yamole did. Its algorithm for doing so is not standards compliant, but we diff --git a/zerver/openapi/python_examples.py b/zerver/openapi/python_examples.py index 1bf726800f..7e01549bc4 100644 --- a/zerver/openapi/python_examples.py +++ b/zerver/openapi/python_examples.py @@ -1132,35 +1132,20 @@ def get_server_settings(client: Client) -> None: validate_against_openapi_schema(result, "/server_settings", "get", "200") -@openapi_test_function("/settings/notifications:patch") -def update_notification_settings(client: Client) -> None: +@openapi_test_function("/settings:patch") +def update_settings(client: Client) -> None: # {code_example|start} - # Enable push notifications even when online + # Enable push notifications even when online and change emojiset request = { "enable_offline_push_notifications": True, "enable_online_push_notifications": True, - } - result = client.update_notification_settings(request) - # {code_example|end} - - validate_against_openapi_schema(result, "/settings/notifications", "patch", "200") - - -@openapi_test_function("/settings/display:patch") -def update_display_settings(client: Client) -> None: - - # {code_example|start} - # Show user list on left sidebar in narrow windows. - # Change emoji set used for display to Google modern. - request = { - "left_side_userlist": True, "emojiset": "google", } - result = client.call_endpoint("settings/display", method="PATCH", request=request) + result = client.call_endpoint("/settings", method="PATCH", request=request) # {code_example|end} - validate_against_openapi_schema(result, "/settings/display", "patch", "200") + validate_against_openapi_schema(result, "/settings", "patch", "200") @openapi_test_function("/user_uploads:post") @@ -1488,8 +1473,7 @@ def test_users(client: Client, owner_client: Client) -> None: get_user_by_email(client) get_subscription_status(client) get_profile(client) - update_notification_settings(client) - update_display_settings(client) + update_settings(client) upload_file(client) get_attachments(client) set_typing_status(client) @@ -1520,7 +1504,6 @@ def test_streams(client: Client, nonadmin_client: Client) -> None: remove_subscriptions(client) toggle_mute_topic(client) update_subscription_settings(client) - update_notification_settings(client) get_stream_topics(client, 1) archive_stream(client, stream_id) diff --git a/zerver/openapi/zulip.yaml b/zerver/openapi/zulip.yaml index cb4384f08f..799db38b58 100644 --- a/zerver/openapi/zulip.yaml +++ b/zerver/openapi/zulip.yaml @@ -279,7 +279,7 @@ paths: - type: object description: | Event sent to a user's clients when that user's [notification - settings](/api/update-notification-settings) have changed. + settings](/api/update-settings) have changed. properties: id: $ref: "#/components/schemas/EventIdSchema" @@ -8423,152 +8423,152 @@ paths: Present if `update_global_notifications` is present in `fetch_event_types`. The current value of this global notification setting for the user. - See [update-notification-settings](/api/update-notification-settings) - for details on notification settings. + See [PATCH /settings](/api/update-settings) for details on + the meaning of this setting. enable_digest_emails: type: boolean description: | Present if `update_global_notifications` is present in `fetch_event_types`. The current value of this global notification setting for the user. - See [update-notification-settings](/api/update-notification-settings) - for details on notification settings. + See [PATCH /settings](/api/update-settings) for details on + the meaning of this setting. enable_login_emails: type: boolean description: | Present if `update_global_notifications` is present in `fetch_event_types`. The current value of this global notification setting for the user. - See [update-notification-settings](/api/update-notification-settings) - for details on notification settings. + See [PATCH /settings](/api/update-settings) for details on + the meaning of this setting. enable_marketing_emails: type: boolean description: | Present if `update_global_notifications` is present in `fetch_event_types`. The current value of this global notification setting for the user. - See [update-notification-settings](/api/update-notification-settings) - for details on notification settings. + See [PATCH /settings](/api/update-settings) for details on + the meaning of this setting. enable_offline_email_notifications: type: boolean description: | Present if `update_global_notifications` is present in `fetch_event_types`. The current value of this global notification setting for the user. - See [update-notification-settings](/api/update-notification-settings) - for details on notification settings. + See [PATCH /settings](/api/update-settings) for details on + the meaning of this setting. enable_offline_push_notifications: type: boolean description: | Present if `update_global_notifications` is present in `fetch_event_types`. The current value of this global notification setting for the user. - See [update-notification-settings](/api/update-notification-settings) - for details on notification settings. + See [PATCH /settings](/api/update-settings) for details on + the meaning of this setting. enable_online_push_notifications: type: boolean description: | Present if `update_global_notifications` is present in `fetch_event_types`. The current value of this global notification setting for the user. - See [update-notification-settings](/api/update-notification-settings) - for details on notification settings. + See [PATCH /settings](/api/update-settings) for details on + the meaning of this setting. enable_sounds: type: boolean description: | Present if `update_global_notifications` is present in `fetch_event_types`. The current value of this global notification setting for the user. - See [update-notification-settings](/api/update-notification-settings) - for details on notification settings. + See [PATCH /settings](/api/update-settings) for details on + the meaning of this setting. enable_stream_desktop_notifications: type: boolean description: | Present if `update_global_notifications` is present in `fetch_event_types`. The current value of this global notification setting for the user. - See [update-notification-settings](/api/update-notification-settings) - for details on notification settings. + See [PATCH /settings](/api/update-settings) for details on + the meaning of this setting. enable_stream_email_notifications: type: boolean description: | Present if `update_global_notifications` is present in `fetch_event_types`. The current value of this global notification setting for the user. - See [update-notification-settings](/api/update-notification-settings) - for details on notification settings. + See [PATCH /settings](/api/update-settings) for details on + the meaning of this setting. enable_stream_push_notifications: type: boolean description: | Present if `update_global_notifications` is present in `fetch_event_types`. The current value of this global notification setting for the user. - See [update-notification-settings](/api/update-notification-settings) - for details on notification settings. + See [PATCH /settings](/api/update-settings) for details on + the meaning of this setting. enable_stream_audible_notifications: type: boolean description: | Present if `update_global_notifications` is present in `fetch_event_types`. The current value of this global notification setting for the user. - See [update-notification-settings](/api/update-notification-settings) - for details on notification settings. + See [PATCH /settings](/api/update-settings) for details on + the meaning of this setting. wildcard_mentions_notify: type: boolean description: | Present if `update_global_notifications` is present in `fetch_event_types`. The current value of this global notification setting for the user. - See [update-notification-settings](/api/update-notification-settings) - for details on notification settings. + See [PATCH /settings](/api/update-settings) for details on + the meaning of this setting. message_content_in_email_notifications: type: boolean description: | Present if `update_global_notifications` is present in `fetch_event_types`. The current value of this global notification setting for the user. - See [update-notification-settings](/api/update-notification-settings) - for details on notification settings. + See [PATCH /settings](/api/update-settings) for details on + the meaning of this setting. notification_sound: type: string description: | Present if `update_global_notifications` is present in `fetch_event_types`. The current value of this global notification setting for the user. - See [update-notification-settings](/api/update-notification-settings) - for details on notification settings. + See [PATCH /settings](/api/update-settings) for details on + the meaning of this setting. pm_content_in_desktop_notifications: type: boolean description: | Present if `update_global_notifications` is present in `fetch_event_types`. The current value of this global notification setting for the user. - See [update-notification-settings](/api/update-notification-settings) - for details on notification settings. + See [PATCH /settings](/api/update-settings) for details on + the meaning of this setting. desktop_icon_count_display: type: integer description: | Present if `update_global_notifications` is present in `fetch_event_types`. The current value of this global notification setting for the user. - See [update-notification-settings](/api/update-notification-settings) - for details on notification settings. + See [PATCH /settings](/api/update-settings) for details on + the meaning of this setting. realm_name_in_notifications: type: boolean description: | Present if `update_global_notifications` is present in `fetch_event_types`. The current value of this global notification setting for the user. - See [update-notification-settings](/api/update-notification-settings) - for details on notification settings. + See [PATCH /settings](/api/update-settings) for details on + the meaning of this setting. presence_enabled: type: boolean description: | Present if `update_global_notifications` is present in `fetch_event_types`. The current value of this global notification setting for the user. - See [update-notification-settings](/api/update-notification-settings) - for details on notification settings. + See [PATCH /settings](/api/update-settings) for details on + the meaning of this setting. available_notification_sounds: type: array items: @@ -8586,8 +8586,8 @@ paths: The color scheme selected by the user. - See [PATCH /settings/display](/api/update-display-settings) - for api details on display settings. + See [PATCH /settings](/api/update-settings) for details on + the meaning of this setting. default_language: type: string description: | @@ -8595,8 +8595,8 @@ paths: The default language chosen by the user. - See [PATCH /settings/display](/api/update-display-settings) - for api details on display settings. + See [PATCH /settings](/api/update-settings) for details on + the meaning of this setting. demote_inactive_streams: type: integer description: | @@ -8604,8 +8604,8 @@ paths: Whether the user has chosen to demote inactive streams. - See [PATCH /settings/display](/api/update-display-settings) - for api details on display settings. + See [PATCH /settings](/api/update-settings) for details on + the meaning of this setting. dense_mode: type: boolean description: | @@ -8614,8 +8614,8 @@ paths: Whether the user has switched on dense mode. Dense mode is an experimental feature that is only available in development environments. - See [PATCH /settings/display](/api/update-display-settings) - for api details on display settings. + See [PATCH /settings](/api/update-settings) for details on + the meaning of this setting. emojiset: type: string description: | @@ -8623,8 +8623,8 @@ paths: The name of the emojiset that the user has chosen. - See [PATCH /settings/display](/api/update-display-settings) - for api details on display settings. + See [PATCH /settings](/api/update-settings) for details on + the meaning of this setting. fluid_layout_width: type: boolean description: | @@ -8632,8 +8632,8 @@ paths: Whether the user has chosen for the layout width to be fluid. - See [PATCH /settings/display](/api/update-display-settings) - for api details on display settings. + See [PATCH /settings](/api/update-settings) for details on + the meaning of this setting. default_view: type: string description: | @@ -8644,8 +8644,8 @@ paths: Currently supported values are `all_messages` and `recent_topics`. - See [PATCH /settings/display](/api/update-display-settings) - for api details on display settings. + See [PATCH /settings](/api/update-settings) for details on + the meaning of this setting. high_contrast_mode: type: boolean description: | @@ -8653,8 +8653,8 @@ paths: Whether has switched on high contrast mode. - See [PATCH /settings/display](/api/update-display-settings) - for api details on display settings. + See [PATCH /settings](/api/update-settings) for details on + the meaning of this setting. left_side_userlist: type: boolean description: | @@ -8664,8 +8664,8 @@ paths: on the left side of the screen (for desktop app and web app) in narrow windows. - See [PATCH /settings/display](/api/update-display-settings) - for api details on display settings. + See [PATCH /settings](/api/update-settings) for details on + the meaning of this setting. starred_message_counts: type: boolean description: | @@ -8674,8 +8674,8 @@ paths: Whether the user has chosen the number of starred messages to be displayed similar to unread counts. - See [PATCH /settings/display](/api/update-display-settings) - for api details on display settings. + See [PATCH /settings](/api/update-settings) for details on + the meaning of this setting. timezone: type: string description: | @@ -8684,8 +8684,8 @@ paths: The timezone configured for the user. This is used primarily to display the user's timezone to other users. - See [PATCH /settings/display](/api/update-display-settings) - for api details on display settings. + See [PATCH /settings](/api/update-settings) for details on + the meaning of this setting. translate_emoticons: type: boolean description: | @@ -8694,8 +8694,8 @@ paths: Whether the user has chosen for emoticons to be translated into emoji in the Zulip compose box. - See [PATCH /settings/display](/api/update-display-settings) - for api details on display settings. + See [PATCH /settings](/api/update-settings) for details on + the meaning of this setting. twenty_four_hour_time: type: boolean description: | @@ -8704,8 +8704,8 @@ paths: Whether the user has chosen a twenty four hour time display (true) or a twelve hour one (false). - See [PATCH /settings/display](/api/update-display-settings) - for api details on display settings. + See [PATCH /settings](/api/update-settings) for details on + the meaning of this setting. emojiset_choices: description: | Present if `update_display_settings` is present in `fetch_event_types`. @@ -8716,8 +8716,8 @@ paths: Only relevant to clients with configuration UI for choosing an emojiset; the currently selected emojiset is available in the `emojiset` key. - See [PATCH /settings/display](/api/update-display-settings) - for api details on display settings. + See [PATCH /settings](/api/update-settings) for details on + the meaning of this setting. type: array items: type: object @@ -9926,263 +9926,32 @@ paths: }, ], } - /settings/notifications: + /settings: patch: - operationId: update-notification-settings - summary: Update notification settings + operationId: update-settings + summary: Update settings tags: ["users"] description: | - This endpoint is used to edit the user's global notification settings. - See [this endpoint](/api/update-subscription-settings) for - per-stream notification settings. + This endpoint is used to edit the current user's settings. - `PATCH {{ api_url }}/v1/settings/notifications` - x-curl-examples-parameters: - oneOf: - - type: include - parameters: - enum: - - enable_offline_push_notifications - - enable_online_push_notifications - parameters: - - name: enable_stream_desktop_notifications - in: query - description: | - Enable visual desktop notifications for stream messages. - schema: - type: boolean - example: true - - name: enable_stream_email_notifications - in: query - description: | - Enable email notifications for stream messages. - schema: - type: boolean - example: true - - name: enable_stream_push_notifications - in: query - description: | - Enable mobile notifications for stream messages. - schema: - type: boolean - example: true - - name: enable_stream_audible_notifications - in: query - description: | - Enable audible desktop notifications for stream messages. - schema: - type: boolean - example: true - - name: notification_sound - in: query - description: | - Notification sound name. + `PATCH {{ api_url }}/v1/settings` - **Changes**: Removed unnecessary JSON-encoding of parameter in Zulip 4.0 (feature level 63). - schema: - type: string - example: ding - - name: enable_desktop_notifications - in: query - description: | - Enable visual desktop notifications for private messages and @-mentions. - schema: - type: boolean - example: true - - name: enable_sounds - in: query - description: | - Enable audible desktop notifications for private messages and - @-mentions. - schema: - type: boolean - example: true - - name: enable_offline_email_notifications - in: query - description: | - Enable email notifications for private messages and @-mentions received - when the user is offline. - schema: - type: boolean - example: true - - name: enable_offline_push_notifications - in: query - description: | - Enable mobile notification for private messages and @-mentions received - when the user is offline. - schema: - type: boolean - example: true - - name: enable_online_push_notifications - in: query - description: | - Enable mobile notification for private messages and @-mentions received - when the user is online. - schema: - type: boolean - example: true - - name: enable_digest_emails - in: query - description: | - Enable digest emails when the user is away. - schema: - type: boolean - example: true - - name: enable_marketing_emails - in: query - description: | - Enable marketing emails. Has no function outside Zulip Cloud. - schema: - type: boolean - example: true - - name: enable_login_emails - in: query - description: | - Enable email notifications for new logins to account. - schema: - type: boolean - example: true - - name: message_content_in_email_notifications - in: query - description: | - Include the message's content in email notifications for new messages. - schema: - type: boolean - example: true - - name: pm_content_in_desktop_notifications - in: query - description: | - Include content of private messages in desktop notifications. - schema: - type: boolean - example: true - - name: wildcard_mentions_notify - in: query - description: | - Whether wildcard mentions (E.g. @**all**) should send notifications - like a personal mention. - schema: - type: boolean - example: true - - name: desktop_icon_count_display - in: query - description: | - Unread count summary (appears in desktop sidebar and browser tab) + **Changes**: Prior to Zulip 5.0 (feature level 80), this + endpoint only supported the `full_name`, `email`, + `old_password`, and `new_password` parameters. Notification + settings were managed by `PATCH /settings/notifications`, and + all other settings by `PATCH /settings/display`. The feature level + 80 migration to merge these endpoints did not change how request + parameters are encoded. Note, however, that it did change the + handling of any invalid parameters present in a request to change + notification or display settings, since the merged endpoint uses + the new response format that was introduced for `/settings` in + Zulip 5.0 (feature level 78). - * 1 - All unreads - * 2 - Private messages and mentions - * 3 - None - content: - application/json: - schema: - type: integer - enum: - - 1 - - 2 - - 3 - example: 1 - - name: realm_name_in_notifications - in: query - description: | - Include organization name in subject of message notification emails. - schema: - type: boolean - example: true - - name: presence_enabled - in: query - description: | - Display the presence status to other users when online. - schema: - type: boolean - example: true - x-response-description: | - The server will return the settings that have been changed after the request, - with their new value. Please note that this doesn't necessarily mean that it - will return all the settings passed as parameters in the request, but only - those ones that were different than the already existing setting. - responses: - "200": - description: Success. - content: - application/json: - schema: - allOf: - - $ref: "#/components/schemas/JsonSuccessBase" - - $ref: "#/components/schemas/SuccessDescription" - - additionalProperties: false - properties: - result: {} - msg: {} - enable_desktop_notifications: - type: boolean - description: | - The setting for `enable_desktop_notifications`, if it was changed in - this request. - enable_digest_emails: - type: boolean - description: | - The setting for `enable_digest_emails`, if it was changed in this - request. - enable_marketing_emails: - type: boolean - description: | - The setting for `enable_marketing_emails`, if it was changed in this - request. - enable_offline_email_notifications: - type: boolean - description: | - The setting for `enable_offline_email_notifications`, if it was changed - in this request. - enable_offline_push_notifications: - type: boolean - description: | - The setting for `enable_offline_push_notifications`, if it was changed - in this request. - enable_online_push_notifications: - type: boolean - description: | - The setting for `enable_online_push_notifications`, if it was changed in - this request. - enable_sounds: - type: boolean - description: | - The setting for `enable_sounds`, if it was changed in this request. - enable_stream_email_notifications: - type: boolean - description: | - The setting for `enable_stream_email_notifications`, if it was changed - in this request. - enable_stream_push_notifications: - type: boolean - description: | - The setting for `enable_stream_push_notifications`, if it was changed in - this request. - enable_stream_audible_notifications: - type: boolean - description: | - The setting for `enable_stream_audible_notifications`, if it was changed - in this request. - message_content_in_email_notifications: - type: boolean - description: | - The setting for `message_content_in_email_notifications`, if it was - changed in this request. - example: - { - "enable_offline_push_notifications": true, - "enable_online_push_notifications": true, - "msg": "", - "result": "success", - } - /settings/display: - patch: - operationId: update-display-settings - summary: Update display settings - tags: ["users"] - description: | - This endpoint is used to edit the current user's user interface settings. - - `PATCH {{ api_url }}/v1/settings/display` + The `/settings/display` and `/settings/notifications` + endpoints are now deprecated aliases for this endpoint for + backwards-compatibility, and will be removed once clients have + migrated to use this endpoint. x-curl-examples-parameters: oneOf: - type: include @@ -10190,18 +9959,48 @@ paths: enum: - left_side_userlist - emojiset - x-response-description: | - #### Return values - - The server will return the settings that have been changed after the request, - with their new value. Please note that this doesn't necessarily mean that it - will return all the settings passed as parameters in the request, but only - those ones that were different from the already existing setting. parameters: + - name: full_name + in: query + description: | + A new display name for the user. + schema: + type: string + example: NewName + - name: email + in: query + description: | + Asks the server to initiate a confirmation sequence to change the user's email + address to the indicated value. The user will need to demonstrate control of the + new email address by clicking a confirmation link sent to that address. + schema: + type: string + example: newname@example.com + - name: old_password + in: query + description: | + The user's old Zulip password (or LDAP password, if LDAP authentication is in use). + + Required only when sending the `new_password` parameter. + schema: + type: string + example: old12345 + - name: new_password + in: query + description: | + The user's new Zulip password (or LDAP password, if LDAP authentication is in use). + + The `old_password` parameter must be included in the request. + schema: + type: string + example: new12345 - name: twenty_four_hour_time in: query description: | Whether time should be [displayed in 24-hour notation](/help/change-the-time-format). + + **Changes**: Before Zulip 5.0 (feature level 80), this setting was managed by + the `PATCH /settings/display` endpoint. schema: type: boolean example: true @@ -10210,6 +10009,9 @@ paths: description: | This setting has no effect at present. It is reserved for use in controlling the default font size in Zulip. + + **Changes**: Before Zulip 5.0 (feature level 80), this setting was managed by + the `PATCH /settings/display` endpoint. schema: type: boolean example: true @@ -10218,6 +10020,9 @@ paths: description: | Whether clients should display the [number of starred messages](/help/star-a-message#display-the-number-of-starred-messages). + + **Changes**: Before Zulip 5.0 (feature level 80), this setting was managed by + the `PATCH /settings/display` endpoint. schema: type: boolean example: true @@ -10226,6 +10031,9 @@ paths: description: | Whether to use the [maximum available screen width](/help/enable-full-width-display) for the web app's center panel (message feed, recent topics) on wide screens. + + **Changes**: Before Zulip 5.0 (feature level 80), this setting was managed by + the `PATCH /settings/display` endpoint. schema: type: boolean example: true @@ -10234,6 +10042,9 @@ paths: description: | This setting is reserved for use to control variations in Zulip's design to help visually impaired users. + + **Changes**: Before Zulip 5.0 (feature level 80), this setting was managed by + the `PATCH /settings/display` endpoint. schema: type: boolean example: true @@ -10248,6 +10059,9 @@ paths: Automatic detection is implementing using the standard `prefers-color-scheme` media query. + + **Changes**: Before Zulip 5.0 (feature level 80), this setting was managed by + the `PATCH /settings/display` endpoint. content: application/json: schema: @@ -10262,6 +10076,9 @@ paths: description: | Whether to [translate emoticons to emoji](/help/enable-emoticon-translations) in messages the user sends. + + **Changes**: Before Zulip 5.0 (feature level 80), this setting was managed by + the `PATCH /settings/display` endpoint. schema: type: boolean example: true @@ -10275,7 +10092,10 @@ paths: The value needs to be a standard language code that the Zulip server has translation data for; for example, `"en"` for English or `"de"` for German. - **Changes**: Removed unnecessary JSON-encoding of parameter in Zulip 4.0 (feature level 63). + **Changes**: Before Zulip 5.0 (feature level 80), this setting was managed by + the `PATCH /settings/display` endpoint. + + Unnecessary JSON-encoding of this parameter was removed in Zulip 4.0 (feature level 63). schema: type: string example: en @@ -10288,7 +10108,10 @@ paths: * "recent_topics" - Recent topics view * "all_messages" - All messages view - **Changes**: Removed unnecessary JSON-encoding of parameter in Zulip 4.0 (feature level 64). + **Changes**: Before Zulip 5.0 (feature level 80), this setting was managed by + the `PATCH /settings/display` endpoint. + + Unnecessary JSON-encoding of this parameter was removed in Zulip 4.0 (feature level 64). schema: type: string example: all_messages @@ -10298,6 +10121,9 @@ paths: Whether the users list on left sidebar in narrow windows. This feature is not heavily used and is likely to be reworked. + + **Changes**: Before Zulip 5.0 (feature level 80), this setting was managed by + the `PATCH /settings/display` endpoint. schema: type: boolean example: true @@ -10312,7 +10138,10 @@ paths: * "twitter" - Twitter * "text" - Plain text - **Changes**: Removed unnecessary JSON-encoding of parameter in Zulip 4.0 (feature level 64). + **Changes**: Before Zulip 5.0 (feature level 80), this setting was managed by + the `PATCH /settings/display` endpoint. + + Unnecessary JSON-encoding of this parameter was removed in Zulip 4.0 (feature level 64). schema: type: string example: "google" @@ -10324,6 +10153,9 @@ paths: * 1 - Automatic * 2 - Always * 3 - Never + + **Changes**: Before Zulip 5.0 (feature level 80), this setting was managed by + the `PATCH /settings/display` endpoint. content: application/json: schema: @@ -10341,10 +10173,220 @@ paths: Timezone values supported by the server are served at [/static/generated/timezones.json](/static/generated/timezones.json). - **Changes**: Removed unnecessary JSON-encoding of parameter in Zulip 4.0 (feature level 64). + **Changes**: Before Zulip 5.0 (feature level 80), this setting was managed by + the `PATCH /settings/display` endpoint. + + Unnecessary JSON-encoding of this parameter was removed in Zulip 4.0 (feature level 64). schema: type: string example: "Asia/Kolkata" + - name: enable_stream_desktop_notifications + in: query + description: | + Enable visual desktop notifications for stream messages. + + **Changes**: Before Zulip 5.0 (feature level 80), this setting was managed by + the `PATCH /settings/notifications` endpoint. + schema: + type: boolean + example: true + - name: enable_stream_email_notifications + in: query + description: | + Enable email notifications for stream messages. + + **Changes**: Before Zulip 5.0 (feature level 80), this setting was managed by + the `PATCH /settings/notifications` endpoint. + schema: + type: boolean + example: true + - name: enable_stream_push_notifications + in: query + description: | + Enable mobile notifications for stream messages. + + **Changes**: Before Zulip 5.0 (feature level 80), this setting was managed by + the `PATCH /settings/notifications` endpoint. + schema: + type: boolean + example: true + - name: enable_stream_audible_notifications + in: query + description: | + Enable audible desktop notifications for stream messages. + + **Changes**: Before Zulip 5.0 (feature level 80), this setting was managed by + the `PATCH /settings/notifications` endpoint. + schema: + type: boolean + example: true + - name: notification_sound + in: query + description: | + Notification sound name. + + **Changes**: Before Zulip 5.0 (feature level 80), this setting was managed by + the `PATCH /settings/notifications` endpoint. + + Unnecessary JSON-encoding of this parameter was removed in Zulip 4.0 (feature level 63). + schema: + type: string + example: ding + - name: enable_desktop_notifications + in: query + description: | + Enable visual desktop notifications for private messages and @-mentions. + + **Changes**: Before Zulip 5.0 (feature level 80), this setting was managed by + the `PATCH /settings/notifications` endpoint. + schema: + type: boolean + example: true + - name: enable_sounds + in: query + description: | + Enable audible desktop notifications for private messages and + @-mentions. + + **Changes**: Before Zulip 5.0 (feature level 80), this setting was managed by + the `PATCH /settings/notifications` endpoint. + schema: + type: boolean + example: true + - name: enable_offline_email_notifications + in: query + description: | + Enable email notifications for private messages and @-mentions received + when the user is offline. + + **Changes**: Before Zulip 5.0 (feature level 80), this setting was managed by + the `PATCH /settings/notifications` endpoint. + schema: + type: boolean + example: true + - name: enable_offline_push_notifications + in: query + description: | + Enable mobile notification for private messages and @-mentions received + when the user is offline. + + **Changes**: Before Zulip 5.0 (feature level 80), this setting was managed by + the `PATCH /settings/notifications` endpoint. + schema: + type: boolean + example: true + - name: enable_online_push_notifications + in: query + description: | + Enable mobile notification for private messages and @-mentions received + when the user is online. + + **Changes**: Before Zulip 5.0 (feature level 80), this setting was managed by + the `PATCH /settings/notifications` endpoint. + schema: + type: boolean + example: true + - name: enable_digest_emails + in: query + description: | + Enable digest emails when the user is away. + + **Changes**: Before Zulip 5.0 (feature level 80), this setting was managed by + the `PATCH /settings/notifications` endpoint. + schema: + type: boolean + example: true + - name: enable_marketing_emails + in: query + description: | + Enable marketing emails. Has no function outside Zulip Cloud. + + **Changes**: Before Zulip 5.0 (feature level 80), this setting was managed by + the `PATCH /settings/notifications` endpoint. + schema: + type: boolean + example: true + - name: enable_login_emails + in: query + description: | + Enable email notifications for new logins to account. + + **Changes**: Before Zulip 5.0 (feature level 80), this setting was managed by + the `PATCH /settings/notifications` endpoint. + schema: + type: boolean + example: true + - name: message_content_in_email_notifications + in: query + description: | + Include the message's content in email notifications for new messages. + + **Changes**: Before Zulip 5.0 (feature level 80), this setting was managed by + the `PATCH /settings/notifications` endpoint. + schema: + type: boolean + example: true + - name: pm_content_in_desktop_notifications + in: query + description: | + Include content of private messages in desktop notifications. + + **Changes**: Before Zulip 5.0 (feature level 80), this setting was managed by + the `PATCH /settings/notifications` endpoint. + schema: + type: boolean + example: true + - name: wildcard_mentions_notify + in: query + description: | + Whether wildcard mentions (E.g. @**all**) should send notifications + like a personal mention. + + **Changes**: Before Zulip 5.0 (feature level 80), this setting was managed by + the `PATCH /settings/notifications` endpoint. + schema: + type: boolean + example: true + - name: desktop_icon_count_display + in: query + description: | + Unread count summary (appears in desktop sidebar and browser tab) + + * 1 - All unreads + * 2 - Private messages and mentions + * 3 - None + + **Changes**: Before Zulip 5.0 (feature level 80), this setting was managed by + the `PATCH /settings/notifications` endpoint. + content: + application/json: + schema: + type: integer + enum: + - 1 + - 2 + - 3 + example: 1 + - name: realm_name_in_notifications + in: query + description: | + Include organization name in subject of message notification emails. + + **Changes**: Before Zulip 5.0 (feature level 80), this setting was managed by + the `PATCH /settings/notifications` endpoint. + schema: + type: boolean + example: true + - name: presence_enabled + in: query + description: | + Display the presence status to other users when online. + + **Changes**: Before Zulip 5.0 (feature level 80), this setting was managed by + the `PATCH /settings/notifications` endpoint. + schema: + type: boolean + example: true responses: "200": description: Success @@ -10358,69 +10400,32 @@ paths: properties: result: {} msg: {} - twenty_four_hour_time: - type: boolean + ignored_parameters_unsupported: + type: array + items: + type: string description: | - The setting for `twenty_four_hour_time`, if it was changed in this request. - dense_mode: - type: boolean - description: | - The setting for `dense_mode`, if it was changed in this request. - This setting is however reserved for future, and can not be - modified in production environment. - starred_message_counts: - type: boolean - description: | - The setting for `starred_message_counts`, if it was changed - in this request. - fluid_layout_width: - type: boolean - description: | - The setting for `fluid_layout_width`, if it was changed - in this request. - high_contrast_mode: - type: boolean - description: | - The setting for `high_contrast_mode`, if it was changed in - this request. - This setting is however reserved for future, and can not be - modified in production environment. - color_scheme: - type: integer - description: | - The numerical key corresponding to new `color_scheme` if it was changed in this request. - translate_emoticons: - type: boolean - description: | - The setting for `translate_emoticons`, if it was changed in this request. - default_language: - type: string - description: | - The language code corresponding to new `default_language` if it was changed in this request. - default_view: - type: string - description: | - The new setting for `default_view`, if it was changed in this request. - left_side_userlist: - type: boolean - description: | - The setting for `left_side_userlist`, if it was changed in this request. - emojiset: - type: string - description: | - The string identifier corresponding to new `emojiset` if it was changed in this request. - demote_inactive_streams: - type: integer - description: | - The numerical key corresponding to new `demote_inactive_streams` setting if it was changed in this request. - timezone: - type: string - description: | - The setting for `timezone`, if it was changed in this request. + This field lists any parameters sent in the request that are not + supported by the endpoint. While this can be expected, e.g. when sending + both current and legacy names for a parameter to a Zulip server of + unknown version, this often indicates a bug in the client + implementation or an attempt to configure a new feature, while + connected to an older Zulip server that does not support the feature. + + **Changes**: New in Zulip 5.0 (feature level 78). Previously, + the `/settings` endpoint indicated which parameters it had + processed by including in the response object `"key": value` + entries for values successfully changed by the request. + + The `/settings/notifications` and `/settings/display` endpoints + also had this behavior before they became aliases of `/settings` + in Zulip 5.0 (feature level 80). + + Before those changes, request parameters that were not supported + or were unchanged were silently ignored. example: { - "emojiset": "google", - "left_side_userlist": true, + "ignored_parameters_unsupported": ["name", "password"], "msg": "", "result": "success", } diff --git a/zerver/tests/test_openapi.py b/zerver/tests/test_openapi.py index 7f06ba83a9..c06d2c2061 100644 --- a/zerver/tests/test_openapi.py +++ b/zerver/tests/test_openapi.py @@ -253,7 +253,6 @@ class OpenAPIArgumentsTest(ZulipTestCase): "/users/me/android_gcm_reg_id", "/users/me/apns_device_token", #### These personal settings endpoints have modest value to document: - "/settings", "/users/me/avatar", "/users/me/api_key/regenerate", # Much more valuable would be an org admin bulk-upload feature. diff --git a/zerver/tests/test_settings.py b/zerver/tests/test_settings.py index 4357afac01..0c77e484d8 100644 --- a/zerver/tests/test_settings.py +++ b/zerver/tests/test_settings.py @@ -158,12 +158,10 @@ class ChangeSettingsTest(ZulipTestCase): # # TODO: Make this work more like do_test_realm_update_api if notification_setting != "notification_sound": - self.check_for_toggle_param_patch( - "/json/settings/notifications", notification_setting - ) + self.check_for_toggle_param_patch("/json/settings", notification_setting) def test_change_notification_sound(self) -> None: - pattern = "/json/settings/notifications" + pattern = "/json/settings" param = "notification_sound" user_profile = self.example_user("hamlet") self.login_user(user_profile) @@ -191,7 +189,7 @@ class ChangeSettingsTest(ZulipTestCase): s for s in UserProfile.property_types if UserProfile.property_types[s] is bool ) for display_setting in boolean_settings: - self.check_for_toggle_param_patch("/json/settings/display", display_setting) + self.check_for_toggle_param_patch("/json/settings", display_setting) def test_enter_sends_setting(self) -> None: self.check_for_toggle_param("/json/users/me/enter-sends", "enter_sends") @@ -344,7 +342,7 @@ class ChangeSettingsTest(ZulipTestCase): else: data = {setting_name: orjson.dumps(test_value).decode()} - result = self.client_patch("/json/settings/display", data) + result = self.client_patch("/json/settings", data) self.assert_json_success(result) user_profile = self.example_user("hamlet") self.assertEqual(getattr(user_profile, setting_name), test_value) @@ -356,7 +354,7 @@ class ChangeSettingsTest(ZulipTestCase): else: data = {setting_name: orjson.dumps(invalid_value).decode()} - result = self.client_patch("/json/settings/display", data) + result = self.client_patch("/json/settings", data) # the json error for multiple word setting names (ex: default_language) # displays as 'Invalid language'. Using setting_name.split('_') to format. self.assert_json_error(result, f"Invalid {setting_name}") @@ -376,7 +374,7 @@ class ChangeSettingsTest(ZulipTestCase): def do_change_emojiset(self, emojiset: str) -> HttpResponse: self.login("hamlet") data = {"emojiset": emojiset} - result = self.client_patch("/json/settings/display", data) + result = self.client_patch("/json/settings", data) return result def test_emojiset(self) -> None: @@ -415,6 +413,35 @@ class ChangeSettingsTest(ZulipTestCase): self.assertIn("ignored_parameters_unsupported", result) self.assertEqual(result["ignored_parameters_unsupported"], ["invalid_setting"]) + def test_changing_setting_using_display_setting_endpoint(self) -> None: + """ + This test is just for adding coverage for `/settings/display` endpoint which is + now depreceated. + """ + self.login("hamlet") + + result = self.client_patch( + "/json/settings/display", dict(color_scheme=UserProfile.COLOR_SCHEME_NIGHT) + ) + self.assert_json_success(result) + hamlet = self.example_user("hamlet") + self.assertEqual(hamlet.color_scheme, UserProfile.COLOR_SCHEME_NIGHT) + + def test_changing_setting_using_notification_setting_endpoint(self) -> None: + """ + This test is just for adding coverage for `/settings/notifications` endpoint which is + now depreceated. + """ + self.login("hamlet") + + result = self.client_patch( + "/json/settings/notifications", + dict(enable_stream_desktop_notifications=orjson.dumps(True).decode()), + ) + self.assert_json_success(result) + hamlet = self.example_user("hamlet") + self.assertEqual(hamlet.enable_stream_desktop_notifications, True) + class UserChangesTest(ZulipTestCase): def test_update_api_key(self) -> None: diff --git a/zerver/views/user_settings.py b/zerver/views/user_settings.py index d362f756d7..2a4e313b07 100644 --- a/zerver/views/user_settings.py +++ b/zerver/views/user_settings.py @@ -87,6 +87,10 @@ def confirm_email_change(request: HttpRequest, confirmation_key: str) -> HttpRes return render(request, "confirmation/confirm_email_change.html", context=ctx) +emojiset_choices = {emojiset["key"] for emojiset in UserProfile.emojiset_choices()} +default_view_options = ["recent_topics", "all_messages"] + + @human_users_only @has_request_variables def json_change_settings( @@ -96,7 +100,74 @@ def json_change_settings( email: str = REQ(default=""), old_password: str = REQ(default=""), new_password: str = REQ(default=""), + twenty_four_hour_time: Optional[bool] = REQ(json_validator=check_bool, default=None), + dense_mode: Optional[bool] = REQ(json_validator=check_bool, default=None), + starred_message_counts: Optional[bool] = REQ(json_validator=check_bool, default=None), + fluid_layout_width: Optional[bool] = REQ(json_validator=check_bool, default=None), + high_contrast_mode: Optional[bool] = REQ(json_validator=check_bool, default=None), + color_scheme: Optional[int] = REQ( + json_validator=check_int_in(UserProfile.COLOR_SCHEME_CHOICES), default=None + ), + translate_emoticons: Optional[bool] = REQ(json_validator=check_bool, default=None), + default_language: Optional[str] = REQ(default=None), + default_view: Optional[str] = REQ( + str_validator=check_string_in(default_view_options), default=None + ), + left_side_userlist: Optional[bool] = REQ(json_validator=check_bool, default=None), + emojiset: Optional[str] = REQ(str_validator=check_string_in(emojiset_choices), default=None), + demote_inactive_streams: Optional[int] = REQ( + json_validator=check_int_in(UserProfile.DEMOTE_STREAMS_CHOICES), default=None + ), + timezone: Optional[str] = REQ( + str_validator=check_string_in(pytz.all_timezones_set), default=None + ), + enable_stream_desktop_notifications: Optional[bool] = REQ( + json_validator=check_bool, default=None + ), + enable_stream_email_notifications: Optional[bool] = REQ( + json_validator=check_bool, default=None + ), + enable_stream_push_notifications: Optional[bool] = REQ(json_validator=check_bool, default=None), + enable_stream_audible_notifications: Optional[bool] = REQ( + json_validator=check_bool, default=None + ), + wildcard_mentions_notify: Optional[bool] = REQ(json_validator=check_bool, default=None), + notification_sound: Optional[str] = REQ(default=None), + enable_desktop_notifications: Optional[bool] = REQ(json_validator=check_bool, default=None), + enable_sounds: Optional[bool] = REQ(json_validator=check_bool, default=None), + enable_offline_email_notifications: Optional[bool] = REQ( + json_validator=check_bool, default=None + ), + enable_offline_push_notifications: Optional[bool] = REQ( + json_validator=check_bool, default=None + ), + enable_online_push_notifications: Optional[bool] = REQ(json_validator=check_bool, default=None), + enable_digest_emails: Optional[bool] = REQ(json_validator=check_bool, default=None), + enable_login_emails: Optional[bool] = REQ(json_validator=check_bool, default=None), + enable_marketing_emails: Optional[bool] = REQ(json_validator=check_bool, default=None), + message_content_in_email_notifications: Optional[bool] = REQ( + json_validator=check_bool, default=None + ), + pm_content_in_desktop_notifications: Optional[bool] = REQ( + json_validator=check_bool, default=None + ), + desktop_icon_count_display: Optional[int] = REQ(json_validator=check_int, default=None), + realm_name_in_notifications: Optional[bool] = REQ(json_validator=check_bool, default=None), + presence_enabled: Optional[bool] = REQ(json_validator=check_bool, default=None), ) -> HttpResponse: + # We can't use REQ for this widget because + # get_available_language_codes requires provisioning to be + # complete. + if default_language is not None and default_language not in get_available_language_codes(): + raise JsonableError(_("Invalid default_language")) + + if ( + notification_sound is not None + and notification_sound not in get_available_notification_sounds() + and notification_sound != "none" + ): + raise JsonableError(_("Invalid notification sound '{}'").format(notification_sound)) + if new_password != "": return_data: Dict[str, Any] = {} if email_belongs_to_ldap(user_profile.realm, user_profile.delivery_email): @@ -172,6 +243,23 @@ def json_change_settings( # Note that check_change_full_name strips the passed name automatically check_change_full_name(user_profile, full_name, user_profile) + # Loop over user_profile.property_types + request_settings = {k: v for k, v in list(locals().items()) if k in user_profile.property_types} + for k, v in list(request_settings.items()): + if v is not None and getattr(user_profile, k) != v: + do_set_user_display_setting(user_profile, k, v) + + req_vars = { + k: v for k, v in list(locals().items()) if k in user_profile.notification_setting_types + } + + 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, acting_user=user_profile) + + if timezone is not None and user_profile.timezone != timezone: + do_set_user_display_setting(user_profile, "timezone", timezone) + # TODO: Do this more generally. from zerver.lib.request import get_request_notes @@ -186,120 +274,6 @@ def json_change_settings( return json_success(result) -emojiset_choices = {emojiset["key"] for emojiset in UserProfile.emojiset_choices()} -default_view_options = ["recent_topics", "all_messages"] - - -@human_users_only -@has_request_variables -def update_display_settings_backend( - request: HttpRequest, - user_profile: UserProfile, - twenty_four_hour_time: Optional[bool] = REQ(json_validator=check_bool, default=None), - dense_mode: Optional[bool] = REQ(json_validator=check_bool, default=None), - starred_message_counts: Optional[bool] = REQ(json_validator=check_bool, default=None), - fluid_layout_width: Optional[bool] = REQ(json_validator=check_bool, default=None), - high_contrast_mode: Optional[bool] = REQ(json_validator=check_bool, default=None), - color_scheme: Optional[int] = REQ( - json_validator=check_int_in(UserProfile.COLOR_SCHEME_CHOICES), default=None - ), - translate_emoticons: Optional[bool] = REQ(json_validator=check_bool, default=None), - default_language: Optional[str] = REQ(default=None), - default_view: Optional[str] = REQ( - str_validator=check_string_in(default_view_options), default=None - ), - left_side_userlist: Optional[bool] = REQ(json_validator=check_bool, default=None), - emojiset: Optional[str] = REQ(str_validator=check_string_in(emojiset_choices), default=None), - demote_inactive_streams: Optional[int] = REQ( - json_validator=check_int_in(UserProfile.DEMOTE_STREAMS_CHOICES), default=None - ), - timezone: Optional[str] = REQ( - str_validator=check_string_in(pytz.all_timezones_set), default=None - ), -) -> HttpResponse: - - # We can't use REQ for this widget because - # get_available_language_codes requires provisioning to be - # complete. - if default_language is not None and default_language not in get_available_language_codes(): - raise JsonableError(_("Invalid default_language")) - - request_settings = {k: v for k, v in list(locals().items()) if k in user_profile.property_types} - result: Dict[str, Any] = {} - for k, v in list(request_settings.items()): - if v is not None and getattr(user_profile, k) != v: - do_set_user_display_setting(user_profile, k, v) - result[k] = v - - if timezone is not None and user_profile.timezone != timezone: - do_set_user_display_setting(user_profile, "timezone", timezone) - result["timezone"] = timezone - - return json_success(result) - - -@human_users_only -@has_request_variables -def json_change_notify_settings( - request: HttpRequest, - user_profile: UserProfile, - enable_stream_desktop_notifications: Optional[bool] = REQ( - json_validator=check_bool, default=None - ), - enable_stream_email_notifications: Optional[bool] = REQ( - json_validator=check_bool, default=None - ), - enable_stream_push_notifications: Optional[bool] = REQ(json_validator=check_bool, default=None), - enable_stream_audible_notifications: Optional[bool] = REQ( - json_validator=check_bool, default=None - ), - wildcard_mentions_notify: Optional[bool] = REQ(json_validator=check_bool, default=None), - notification_sound: Optional[str] = REQ(default=None), - enable_desktop_notifications: Optional[bool] = REQ(json_validator=check_bool, default=None), - enable_sounds: Optional[bool] = REQ(json_validator=check_bool, default=None), - enable_offline_email_notifications: Optional[bool] = REQ( - json_validator=check_bool, default=None - ), - enable_offline_push_notifications: Optional[bool] = REQ( - json_validator=check_bool, default=None - ), - enable_online_push_notifications: Optional[bool] = REQ(json_validator=check_bool, default=None), - enable_digest_emails: Optional[bool] = REQ(json_validator=check_bool, default=None), - enable_login_emails: Optional[bool] = REQ(json_validator=check_bool, default=None), - enable_marketing_emails: Optional[bool] = REQ(json_validator=check_bool, default=None), - message_content_in_email_notifications: Optional[bool] = REQ( - json_validator=check_bool, default=None - ), - pm_content_in_desktop_notifications: Optional[bool] = REQ( - json_validator=check_bool, default=None - ), - desktop_icon_count_display: Optional[int] = REQ(json_validator=check_int, default=None), - realm_name_in_notifications: Optional[bool] = REQ(json_validator=check_bool, default=None), - presence_enabled: Optional[bool] = REQ(json_validator=check_bool, default=None), -) -> HttpResponse: - result = {} - - # Stream notification settings. - - if ( - notification_sound is not None - and notification_sound not in get_available_notification_sounds() - and notification_sound != "none" - ): - raise JsonableError(_("Invalid notification sound '{}'").format(notification_sound)) - - req_vars = { - k: v for k, v in list(locals().items()) if k in user_profile.notification_setting_types - } - - 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, acting_user=user_profile) - result[k] = v - - return json_success(result) - - def set_avatar_backend(request: HttpRequest, user_profile: UserProfile) -> HttpResponse: if len(request.FILES) != 1: raise JsonableError(_("You must upload exactly one avatar.")) diff --git a/zproject/urls.py b/zproject/urls.py index 8c7f487707..54e20e17bd 100644 --- a/zproject/urls.py +++ b/zproject/urls.py @@ -182,11 +182,9 @@ from zerver.views.user_settings import ( change_enter_sends, confirm_email_change, delete_avatar_backend, - json_change_notify_settings, json_change_settings, regenerate_api_key, set_avatar_backend, - update_display_settings_backend, ) from zerver.views.users import ( add_bot_backend, @@ -414,8 +412,13 @@ v1_api_and_json_patterns = [ ), # settings -> zerver.views.user_settings rest_path("settings", PATCH=json_change_settings), - rest_path("settings/display", PATCH=update_display_settings_backend), - rest_path("settings/notifications", PATCH=json_change_notify_settings), + # These next two are legacy aliases for /settings, from before + # we merged the endpoints. They are documented in the `/json/settings` + # documentation, rather than having dedicated pages. + rest_path("settings/display", PATCH=(json_change_settings, {"intentionally_undocumented"})), + rest_path( + "settings/notifications", PATCH=(json_change_settings, {"intentionally_undocumented"}) + ), # users/me/alert_words -> zerver.views.alert_words rest_path( "users/me/alert_words",