mirror of
				https://github.com/zulip/zulip.git
				synced 2025-10-31 03:53:50 +00:00 
			
		
		
		
	user_settings: Migrate to typed_endpoint.
Migrate `user_settings.py` to `typed_endpoint`. Fix the error messages for the tests. Migrate required validators.
This commit is contained in:
		
				
					committed by
					
						 Tim Abbott
						Tim Abbott
					
				
			
			
				
	
			
			
			
						parent
						
							61ba381c30
						
					
				
				
					commit
					0f692436ca
				
			| @@ -69,6 +69,18 @@ def timezone_or_empty_validator() -> AfterValidator: | ||||
|     return AfterValidator(lambda s: to_timezone_or_empty(s)) | ||||
|  | ||||
|  | ||||
| def check_timezone(s: str) -> str: | ||||
|     try: | ||||
|         zoneinfo.ZoneInfo(canonicalize_timezone(s)) | ||||
|     except (ValueError, zoneinfo.ZoneInfoNotFoundError): | ||||
|         raise ValueError(_("Not a recognized time zone")) | ||||
|     return s | ||||
|  | ||||
|  | ||||
| def timezone_validator() -> AfterValidator: | ||||
|     return AfterValidator(lambda s: check_timezone(s)) | ||||
|  | ||||
|  | ||||
| def to_non_negative_int_or_none(s: str) -> NonNegativeInt | None: | ||||
|     try: | ||||
|         i = int(s) | ||||
|   | ||||
| @@ -29,7 +29,6 @@ for any particular type of object. | ||||
| """ | ||||
|  | ||||
| import re | ||||
| import zoneinfo | ||||
| from collections.abc import Collection, Container, Iterator | ||||
| from dataclasses import dataclass | ||||
| from datetime import datetime, timezone | ||||
| @@ -44,7 +43,6 @@ from pydantic.functional_validators import ModelWrapValidatorHandler | ||||
| from typing_extensions import override | ||||
|  | ||||
| from zerver.lib.exceptions import InvalidJSONError, JsonableError | ||||
| from zerver.lib.timezone import canonicalize_timezone | ||||
| from zerver.lib.types import ProfileFieldData, Validator | ||||
|  | ||||
| ResultT = TypeVar("ResultT") | ||||
| @@ -116,17 +114,6 @@ def check_long_string(var_name: str, val: object) -> str: | ||||
|     return check_capped_string(500)(var_name, val) | ||||
|  | ||||
|  | ||||
| def check_timezone(var_name: str, val: object) -> str: | ||||
|     s = check_string(var_name, val) | ||||
|     try: | ||||
|         zoneinfo.ZoneInfo(canonicalize_timezone(s)) | ||||
|     except (ValueError, zoneinfo.ZoneInfoNotFoundError): | ||||
|         raise ValidationError( | ||||
|             _("{var_name} is not a recognized time zone").format(var_name=var_name) | ||||
|         ) | ||||
|     return s | ||||
|  | ||||
|  | ||||
| def check_date(var_name: str, val: object) -> str: | ||||
|     if not isinstance(val, str): | ||||
|         raise ValidationError(_("{var_name} is not a string").format(var_name=var_name)) | ||||
|   | ||||
| @@ -407,39 +407,86 @@ class ChangeSettingsTest(ZulipTestCase): | ||||
|         self.do_test_change_user_setting("timezone") | ||||
|  | ||||
|     def test_invalid_setting_value(self) -> None: | ||||
|         invalid_values_dict = dict( | ||||
|             default_language="invalid_de", | ||||
|             web_home_view="invalid_view", | ||||
|             emojiset="apple", | ||||
|             timezone="invalid_US/Mountain", | ||||
|             demote_inactive_streams=10, | ||||
|             web_mark_read_on_scroll_policy=10, | ||||
|             web_channel_default_view=10, | ||||
|             user_list_style=10, | ||||
|             web_animate_image_previews="invalid_value", | ||||
|             web_stream_unreads_count_display_policy=10, | ||||
|             color_scheme=10, | ||||
|             notification_sound="invalid_sound", | ||||
|             desktop_icon_count_display=10, | ||||
|         ) | ||||
|  | ||||
|         invalid_values: list[dict[str, Any]] = [ | ||||
|             { | ||||
|                 "setting_name": "default_language", | ||||
|                 "value": "invalid_de", | ||||
|                 "error_msg": "Invalid default_language", | ||||
|             }, | ||||
|             { | ||||
|                 "setting_name": "web_home_view", | ||||
|                 "value": "invalid_view", | ||||
|                 "error_msg": "Invalid web_home_view: Value error, Not in the list of possible values", | ||||
|             }, | ||||
|             { | ||||
|                 "setting_name": "emojiset", | ||||
|                 "value": "apple", | ||||
|                 "error_msg": "Invalid emojiset: Value error, Not in the list of possible values", | ||||
|             }, | ||||
|             { | ||||
|                 "setting_name": "timezone", | ||||
|                 "value": "invalid_US/Mountain", | ||||
|                 "error_msg": "Invalid timezone: Value error, Not a recognized time zone", | ||||
|             }, | ||||
|             { | ||||
|                 "setting_name": "demote_inactive_streams", | ||||
|                 "value": 10, | ||||
|                 "error_msg": "Invalid demote_inactive_streams: Value error, Not in the list of possible values", | ||||
|             }, | ||||
|             { | ||||
|                 "setting_name": "web_mark_read_on_scroll_policy", | ||||
|                 "value": 10, | ||||
|                 "error_msg": "Invalid web_mark_read_on_scroll_policy: Value error, Not in the list of possible values", | ||||
|             }, | ||||
|             { | ||||
|                 "setting_name": "web_channel_default_view", | ||||
|                 "value": 10, | ||||
|                 "error_msg": "Invalid web_channel_default_view: Value error, Not in the list of possible values", | ||||
|             }, | ||||
|             { | ||||
|                 "setting_name": "user_list_style", | ||||
|                 "value": 10, | ||||
|                 "error_msg": "Invalid user_list_style: Value error, Not in the list of possible values", | ||||
|             }, | ||||
|             { | ||||
|                 "setting_name": "web_animate_image_previews", | ||||
|                 "value": "invalid_value", | ||||
|                 "error_msg": "Invalid web_animate_image_previews: Value error, Not in the list of possible values", | ||||
|             }, | ||||
|             { | ||||
|                 "setting_name": "web_stream_unreads_count_display_policy", | ||||
|                 "value": 10, | ||||
|                 "error_msg": "Invalid web_stream_unreads_count_display_policy: Value error, Not in the list of possible values", | ||||
|             }, | ||||
|             { | ||||
|                 "setting_name": "color_scheme", | ||||
|                 "value": 10, | ||||
|                 "error_msg": "Invalid color_scheme: Value error, Not in the list of possible values", | ||||
|             }, | ||||
|             { | ||||
|                 "setting_name": "notification_sound", | ||||
|                 "value": "invalid_sound", | ||||
|                 "error_msg": "Invalid notification sound '\"invalid_sound\"'", | ||||
|             }, | ||||
|             { | ||||
|                 "setting_name": "desktop_icon_count_display", | ||||
|                 "value": 10, | ||||
|                 "error_msg": "Invalid desktop_icon_count_display: Value error, Not in the list of possible values", | ||||
|             }, | ||||
|         ] | ||||
|         self.login("hamlet") | ||||
|         for setting_name in invalid_values_dict: | ||||
|             invalid_value = invalid_values_dict.get(setting_name) | ||||
|             if isinstance(invalid_value, str): | ||||
|                 invalid_value = orjson.dumps(invalid_value).decode() | ||||
|         for invalid_value in invalid_values: | ||||
|             if isinstance(invalid_value["value"], str): | ||||
|                 invalid_value["value"] = orjson.dumps(invalid_value["value"]).decode() | ||||
|  | ||||
|             req = {setting_name: invalid_value} | ||||
|             req = {invalid_value["setting_name"]: invalid_value["value"]} | ||||
|             result = self.client_patch("/json/settings", req) | ||||
|  | ||||
|             expected_error_msg = f"Invalid {setting_name}" | ||||
|             if setting_name == "notification_sound": | ||||
|                 expected_error_msg = f"Invalid notification sound '{invalid_value}'" | ||||
|             elif setting_name == "timezone": | ||||
|                 expected_error_msg = "timezone is not a recognized time zone" | ||||
|             self.assert_json_error(result, expected_error_msg) | ||||
|             self.assert_json_error(result, invalid_value["error_msg"]) | ||||
|             hamlet = self.example_user("hamlet") | ||||
|             self.assertNotEqual(getattr(hamlet, setting_name), invalid_value) | ||||
|             self.assertNotEqual( | ||||
|                 getattr(hamlet, invalid_value["setting_name"]), invalid_value["value"] | ||||
|             ) | ||||
|  | ||||
|     def do_change_emojiset(self, emojiset: str) -> "TestHttpResponse": | ||||
|         self.login("hamlet") | ||||
| @@ -454,7 +501,9 @@ class ChangeSettingsTest(ZulipTestCase): | ||||
|  | ||||
|         for emojiset in banned_emojisets: | ||||
|             result = self.do_change_emojiset(emojiset) | ||||
|             self.assert_json_error(result, "Invalid emojiset") | ||||
|             self.assert_json_error( | ||||
|                 result, "Invalid emojiset: Value error, Not in the list of possible values" | ||||
|             ) | ||||
|  | ||||
|         for emojiset in valid_emojisets: | ||||
|             result = self.do_change_emojiset(emojiset) | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| from email.headerregistry import Address | ||||
| from typing import Any | ||||
| from typing import Annotated, Any | ||||
|  | ||||
| from django.conf import settings | ||||
| from django.contrib.auth import authenticate, update_session_auth_hash | ||||
| @@ -13,6 +13,7 @@ from django.utils.html import escape | ||||
| from django.utils.safestring import SafeString | ||||
| from django.utils.translation import gettext as _ | ||||
| from django.utils.translation import gettext_lazy | ||||
| from pydantic import Json | ||||
|  | ||||
| from confirmation.models import ( | ||||
|     Confirmation, | ||||
| @@ -45,18 +46,16 @@ from zerver.lib.exceptions import ( | ||||
| ) | ||||
| from zerver.lib.i18n import get_available_language_codes | ||||
| from zerver.lib.rate_limiter import RateLimitedUser | ||||
| from zerver.lib.request import REQ, has_request_variables | ||||
| from zerver.lib.response import json_success | ||||
| from zerver.lib.send_email import FromAddress, send_email | ||||
| from zerver.lib.sounds import get_available_notification_sounds | ||||
| from zerver.lib.upload import upload_avatar_image | ||||
| from zerver.lib.validator import ( | ||||
|     check_bool, | ||||
|     check_int, | ||||
|     check_int_in, | ||||
|     check_string_in, | ||||
|     check_timezone, | ||||
| from zerver.lib.typed_endpoint import typed_endpoint, typed_endpoint_without_parameters | ||||
| from zerver.lib.typed_endpoint_validators import ( | ||||
|     check_int_in_validator, | ||||
|     check_string_in_validator, | ||||
|     timezone_validator, | ||||
| ) | ||||
| from zerver.lib.upload import upload_avatar_image | ||||
| from zerver.models import EmailChangeStatus, RealmUserDefault, UserBaseSettings, UserProfile | ||||
| from zerver.models.realms import avatar_changes_disabled, name_changes_disabled | ||||
| from zerver.views.auth import redirect_to_deactivation_notice | ||||
| @@ -223,120 +222,111 @@ def check_information_density_setting_values( | ||||
|  | ||||
|  | ||||
| @human_users_only | ||||
| @has_request_variables | ||||
| @typed_endpoint | ||||
| def json_change_settings( | ||||
|     request: HttpRequest, | ||||
|     user_profile: UserProfile, | ||||
|     full_name: str | None = REQ(default=None), | ||||
|     email: str | None = REQ(default=None), | ||||
|     old_password: str | None = REQ(default=None), | ||||
|     new_password: str | None = REQ(default=None), | ||||
|     twenty_four_hour_time: bool | None = REQ(json_validator=check_bool, default=None), | ||||
|     dense_mode: bool | None = REQ(json_validator=check_bool, default=None), | ||||
|     web_mark_read_on_scroll_policy: int | None = REQ( | ||||
|         json_validator=check_int_in(UserProfile.WEB_MARK_READ_ON_SCROLL_POLICY_CHOICES), | ||||
|         default=None, | ||||
|     ), | ||||
|     web_channel_default_view: int | None = REQ( | ||||
|         json_validator=check_int_in(UserProfile.WEB_CHANNEL_DEFAULT_VIEW_CHOICES), | ||||
|         default=None, | ||||
|     ), | ||||
|     starred_message_counts: bool | None = REQ(json_validator=check_bool, default=None), | ||||
|     receives_typing_notifications: bool | None = REQ(json_validator=check_bool, default=None), | ||||
|     fluid_layout_width: bool | None = REQ(json_validator=check_bool, default=None), | ||||
|     high_contrast_mode: bool | None = REQ(json_validator=check_bool, default=None), | ||||
|     color_scheme: int | None = REQ( | ||||
|         json_validator=check_int_in(UserProfile.COLOR_SCHEME_CHOICES), default=None | ||||
|     ), | ||||
|     web_font_size_px: int | None = REQ(json_validator=check_int, default=None), | ||||
|     web_line_height_percent: int | None = REQ(json_validator=check_int, default=None), | ||||
|     translate_emoticons: bool | None = REQ(json_validator=check_bool, default=None), | ||||
|     display_emoji_reaction_users: bool | None = REQ(json_validator=check_bool, default=None), | ||||
|     default_language: str | None = REQ(default=None), | ||||
|     web_home_view: str | None = REQ( | ||||
|         str_validator=check_string_in(web_home_view_options), default=None | ||||
|     ), | ||||
|     web_escape_navigates_to_home_view: bool | None = REQ(json_validator=check_bool, default=None), | ||||
|     left_side_userlist: bool | None = REQ(json_validator=check_bool, default=None), | ||||
|     emojiset: str | None = REQ(str_validator=check_string_in(emojiset_choices), default=None), | ||||
|     demote_inactive_streams: int | None = REQ( | ||||
|         json_validator=check_int_in(UserProfile.DEMOTE_STREAMS_CHOICES), default=None | ||||
|     ), | ||||
|     web_stream_unreads_count_display_policy: int | None = REQ( | ||||
|         json_validator=check_int_in(UserProfile.WEB_STREAM_UNREADS_COUNT_DISPLAY_POLICY_CHOICES), | ||||
|         default=None, | ||||
|     ), | ||||
|     timezone: str | None = REQ(str_validator=check_timezone, default=None), | ||||
|     email_notifications_batching_period_seconds: int | None = REQ( | ||||
|         json_validator=check_int, default=None | ||||
|     ), | ||||
|     enable_drafts_synchronization: bool | None = REQ(json_validator=check_bool, default=None), | ||||
|     enable_stream_desktop_notifications: bool | None = REQ(json_validator=check_bool, default=None), | ||||
|     enable_stream_email_notifications: bool | None = REQ(json_validator=check_bool, default=None), | ||||
|     enable_stream_push_notifications: bool | None = REQ(json_validator=check_bool, default=None), | ||||
|     enable_stream_audible_notifications: bool | None = REQ(json_validator=check_bool, default=None), | ||||
|     wildcard_mentions_notify: bool | None = REQ(json_validator=check_bool, default=None), | ||||
|     enable_followed_topic_desktop_notifications: bool | None = REQ( | ||||
|         json_validator=check_bool, default=None | ||||
|     ), | ||||
|     enable_followed_topic_email_notifications: bool | None = REQ( | ||||
|         json_validator=check_bool, default=None | ||||
|     ), | ||||
|     enable_followed_topic_push_notifications: bool | None = REQ( | ||||
|         json_validator=check_bool, default=None | ||||
|     ), | ||||
|     enable_followed_topic_audible_notifications: bool | None = REQ( | ||||
|         json_validator=check_bool, default=None | ||||
|     ), | ||||
|     enable_followed_topic_wildcard_mentions_notify: bool | None = REQ( | ||||
|         json_validator=check_bool, default=None | ||||
|     ), | ||||
|     notification_sound: str | None = REQ(default=None), | ||||
|     enable_desktop_notifications: bool | None = REQ(json_validator=check_bool, default=None), | ||||
|     enable_sounds: bool | None = REQ(json_validator=check_bool, default=None), | ||||
|     enable_offline_email_notifications: bool | None = REQ(json_validator=check_bool, default=None), | ||||
|     enable_offline_push_notifications: bool | None = REQ(json_validator=check_bool, default=None), | ||||
|     enable_online_push_notifications: bool | None = REQ(json_validator=check_bool, default=None), | ||||
|     enable_digest_emails: bool | None = REQ(json_validator=check_bool, default=None), | ||||
|     enable_login_emails: bool | None = REQ(json_validator=check_bool, default=None), | ||||
|     enable_marketing_emails: bool | None = REQ(json_validator=check_bool, default=None), | ||||
|     message_content_in_email_notifications: bool | None = REQ( | ||||
|         json_validator=check_bool, default=None | ||||
|     ), | ||||
|     pm_content_in_desktop_notifications: bool | None = REQ(json_validator=check_bool, default=None), | ||||
|     desktop_icon_count_display: int | None = REQ( | ||||
|         json_validator=check_int_in(UserProfile.DESKTOP_ICON_COUNT_DISPLAY_CHOICES), default=None | ||||
|     ), | ||||
|     realm_name_in_email_notifications_policy: int | None = REQ( | ||||
|         json_validator=check_int_in(UserProfile.REALM_NAME_IN_EMAIL_NOTIFICATIONS_POLICY_CHOICES), | ||||
|         default=None, | ||||
|     ), | ||||
|     automatically_follow_topics_policy: int | None = REQ( | ||||
|         json_validator=check_int_in(UserProfile.AUTOMATICALLY_CHANGE_VISIBILITY_POLICY_CHOICES), | ||||
|         default=None, | ||||
|     ), | ||||
|     automatically_unmute_topics_in_muted_streams_policy: int | None = REQ( | ||||
|         json_validator=check_int_in(UserProfile.AUTOMATICALLY_CHANGE_VISIBILITY_POLICY_CHOICES), | ||||
|         default=None, | ||||
|     ), | ||||
|     automatically_follow_topics_where_mentioned: bool | None = REQ( | ||||
|         json_validator=check_bool, default=None | ||||
|     ), | ||||
|     presence_enabled: bool | None = REQ(json_validator=check_bool, default=None), | ||||
|     enter_sends: bool | None = REQ(json_validator=check_bool, default=None), | ||||
|     send_private_typing_notifications: bool | None = REQ(json_validator=check_bool, default=None), | ||||
|     send_stream_typing_notifications: bool | None = REQ(json_validator=check_bool, default=None), | ||||
|     send_read_receipts: bool | None = REQ(json_validator=check_bool, default=None), | ||||
|     user_list_style: int | None = REQ( | ||||
|         json_validator=check_int_in(UserProfile.USER_LIST_STYLE_CHOICES), default=None | ||||
|     ), | ||||
|     web_animate_image_previews: str | None = REQ( | ||||
|         str_validator=check_string_in(web_animate_image_previews_options), default=None | ||||
|     ), | ||||
|     email_address_visibility: int | None = REQ( | ||||
|         json_validator=check_int_in(UserProfile.EMAIL_ADDRESS_VISIBILITY_TYPES), default=None | ||||
|     ), | ||||
|     web_navigate_to_sent_message: bool | None = REQ(json_validator=check_bool, default=None), | ||||
|     *, | ||||
|     full_name: str | None = None, | ||||
|     email: str | None = None, | ||||
|     old_password: str | None = None, | ||||
|     new_password: str | None = None, | ||||
|     twenty_four_hour_time: Json[bool] | None = None, | ||||
|     dense_mode: Json[bool] | None = None, | ||||
|     web_mark_read_on_scroll_policy: Annotated[ | ||||
|         Json[int], check_int_in_validator(UserProfile.WEB_MARK_READ_ON_SCROLL_POLICY_CHOICES) | ||||
|     ] | ||||
|     | None = None, | ||||
|     web_channel_default_view: Annotated[ | ||||
|         Json[int], check_int_in_validator(UserProfile.WEB_CHANNEL_DEFAULT_VIEW_CHOICES) | ||||
|     ] | ||||
|     | None = None, | ||||
|     starred_message_counts: Json[bool] | None = None, | ||||
|     receives_typing_notifications: Json[bool] | None = None, | ||||
|     fluid_layout_width: Json[bool] | None = None, | ||||
|     high_contrast_mode: Json[bool] | None = None, | ||||
|     color_scheme: Annotated[Json[int], check_int_in_validator(UserProfile.COLOR_SCHEME_CHOICES)] | ||||
|     | None = None, | ||||
|     web_font_size_px: Json[int] | None = None, | ||||
|     web_line_height_percent: Json[int] | None = None, | ||||
|     translate_emoticons: Json[bool] | None = None, | ||||
|     display_emoji_reaction_users: Json[bool] | None = None, | ||||
|     default_language: str | None = None, | ||||
|     web_home_view: Annotated[str, check_string_in_validator(web_home_view_options)] | None = None, | ||||
|     web_escape_navigates_to_home_view: Json[bool] | None = None, | ||||
|     left_side_userlist: Json[bool] | None = None, | ||||
|     emojiset: Annotated[str, check_string_in_validator(emojiset_choices)] | None = None, | ||||
|     demote_inactive_streams: Annotated[ | ||||
|         Json[int], check_int_in_validator(UserProfile.DEMOTE_STREAMS_CHOICES) | ||||
|     ] | ||||
|     | None = None, | ||||
|     web_stream_unreads_count_display_policy: Annotated[ | ||||
|         Json[int], | ||||
|         check_int_in_validator(UserProfile.WEB_STREAM_UNREADS_COUNT_DISPLAY_POLICY_CHOICES), | ||||
|     ] | ||||
|     | None = None, | ||||
|     timezone: Annotated[str, timezone_validator()] | None = None, | ||||
|     email_notifications_batching_period_seconds: Json[int] | None = None, | ||||
|     enable_drafts_synchronization: Json[bool] | None = None, | ||||
|     enable_stream_desktop_notifications: Json[bool] | None = None, | ||||
|     enable_stream_email_notifications: Json[bool] | None = None, | ||||
|     enable_stream_push_notifications: Json[bool] | None = None, | ||||
|     enable_stream_audible_notifications: Json[bool] | None = None, | ||||
|     wildcard_mentions_notify: Json[bool] | None = None, | ||||
|     enable_followed_topic_desktop_notifications: Json[bool] | None = None, | ||||
|     enable_followed_topic_email_notifications: Json[bool] | None = None, | ||||
|     enable_followed_topic_push_notifications: Json[bool] | None = None, | ||||
|     enable_followed_topic_audible_notifications: Json[bool] | None = None, | ||||
|     enable_followed_topic_wildcard_mentions_notify: Json[bool] | None = None, | ||||
|     notification_sound: str | None = None, | ||||
|     enable_desktop_notifications: Json[bool] | None = None, | ||||
|     enable_sounds: Json[bool] | None = None, | ||||
|     enable_offline_email_notifications: Json[bool] | None = None, | ||||
|     enable_offline_push_notifications: Json[bool] | None = None, | ||||
|     enable_online_push_notifications: Json[bool] | None = None, | ||||
|     enable_digest_emails: Json[bool] | None = None, | ||||
|     enable_login_emails: Json[bool] | None = None, | ||||
|     enable_marketing_emails: Json[bool] | None = None, | ||||
|     message_content_in_email_notifications: Json[bool] | None = None, | ||||
|     pm_content_in_desktop_notifications: Json[bool] | None = None, | ||||
|     desktop_icon_count_display: Annotated[ | ||||
|         Json[int], check_int_in_validator(UserProfile.DESKTOP_ICON_COUNT_DISPLAY_CHOICES) | ||||
|     ] | ||||
|     | None = None, | ||||
|     realm_name_in_email_notifications_policy: Annotated[ | ||||
|         Json[int], | ||||
|         check_int_in_validator(UserProfile.REALM_NAME_IN_EMAIL_NOTIFICATIONS_POLICY_CHOICES), | ||||
|     ] | ||||
|     | None = None, | ||||
|     automatically_follow_topics_policy: Annotated[ | ||||
|         Json[int], | ||||
|         check_int_in_validator(UserProfile.AUTOMATICALLY_CHANGE_VISIBILITY_POLICY_CHOICES), | ||||
|     ] | ||||
|     | None = None, | ||||
|     automatically_unmute_topics_in_muted_streams_policy: Annotated[ | ||||
|         Json[int], | ||||
|         check_int_in_validator(UserProfile.AUTOMATICALLY_CHANGE_VISIBILITY_POLICY_CHOICES), | ||||
|     ] | ||||
|     | None = None, | ||||
|     automatically_follow_topics_where_mentioned: Json[bool] | None = None, | ||||
|     presence_enabled: Json[bool] | None = None, | ||||
|     enter_sends: Json[bool] | None = None, | ||||
|     send_private_typing_notifications: Json[bool] | None = None, | ||||
|     send_stream_typing_notifications: Json[bool] | None = None, | ||||
|     send_read_receipts: Json[bool] | None = None, | ||||
|     user_list_style: Annotated[ | ||||
|         Json[int], check_int_in_validator(UserProfile.USER_LIST_STYLE_CHOICES) | ||||
|     ] | ||||
|     | None = None, | ||||
|     web_animate_image_previews: Annotated[ | ||||
|         str, check_string_in_validator(web_animate_image_previews_options) | ||||
|     ] | ||||
|     | None = None, | ||||
|     email_address_visibility: Annotated[ | ||||
|         Json[int], check_int_in_validator(UserProfile.EMAIL_ADDRESS_VISIBILITY_TYPES) | ||||
|     ] | ||||
|     | None = None, | ||||
|     web_navigate_to_sent_message: Json[bool] | None = None, | ||||
| ) -> HttpResponse: | ||||
|     # UserProfile object is being refetched here to make sure that we | ||||
|     # do not use stale object from cache which can happen when a | ||||
| @@ -485,7 +475,7 @@ def delete_avatar_backend(request: HttpRequest, user_profile: UserProfile) -> Ht | ||||
|  | ||||
| # We don't use @human_users_only here, because there are use cases for | ||||
| # a bot regenerating its own API key. | ||||
| @has_request_variables | ||||
| @typed_endpoint_without_parameters | ||||
| def regenerate_api_key(request: HttpRequest, user_profile: UserProfile) -> HttpResponse: | ||||
|     new_api_key = do_regenerate_api_key(user_profile, user_profile) | ||||
|     json_result = dict( | ||||
|   | ||||
		Reference in New Issue
	
	Block a user