request: Rename validator parameter of REQ to json_validator.

This makes it much more clear that this feature does JSON encoding,
which previously was only indicated in the documentation.

Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
Anders Kaseorg 2021-04-07 13:00:44 -07:00 committed by Tim Abbott
parent 93d2ae8092
commit f0e655f1d8
39 changed files with 291 additions and 259 deletions

View File

@ -123,13 +123,13 @@ def payment_method_string(stripe_customer: stripe.Customer) -> str:
def upgrade( def upgrade(
request: HttpRequest, request: HttpRequest,
user: UserProfile, user: UserProfile,
billing_modality: str = REQ(validator=check_string), billing_modality: str = REQ(json_validator=check_string),
schedule: str = REQ(validator=check_string), schedule: str = REQ(json_validator=check_string),
license_management: Optional[str] = REQ(validator=check_string, default=None), license_management: Optional[str] = REQ(json_validator=check_string, default=None),
licenses: Optional[int] = REQ(validator=check_int, default=None), licenses: Optional[int] = REQ(json_validator=check_int, default=None),
stripe_token: Optional[str] = REQ(validator=check_string, default=None), stripe_token: Optional[str] = REQ(json_validator=check_string, default=None),
signed_seat_count: str = REQ(validator=check_string), signed_seat_count: str = REQ(json_validator=check_string),
salt: str = REQ(validator=check_string), salt: str = REQ(json_validator=check_string),
) -> HttpResponse: ) -> HttpResponse:
try: try:
seat_count = unsign_seat_count(signed_seat_count, salt) seat_count = unsign_seat_count(signed_seat_count, salt)
@ -232,9 +232,9 @@ def initial_upgrade(request: HttpRequest) -> HttpResponse:
def sponsorship( def sponsorship(
request: HttpRequest, request: HttpRequest,
user: UserProfile, user: UserProfile,
organization_type: str = REQ("organization-type", validator=check_string), organization_type: str = REQ("organization-type", json_validator=check_string),
website: str = REQ("website", validator=check_string), website: str = REQ("website", json_validator=check_string),
description: str = REQ("description", validator=check_string), description: str = REQ("description", json_validator=check_string),
) -> HttpResponse: ) -> HttpResponse:
realm = user.realm realm = user.realm
@ -350,7 +350,7 @@ def billing_home(request: HttpRequest) -> HttpResponse:
@require_billing_access @require_billing_access
@has_request_variables @has_request_variables
def change_plan_status( def change_plan_status(
request: HttpRequest, user: UserProfile, status: int = REQ("status", validator=check_int) request: HttpRequest, user: UserProfile, status: int = REQ("status", json_validator=check_int)
) -> HttpResponse: ) -> HttpResponse:
assert status in [ assert status in [
CustomerPlan.ACTIVE, CustomerPlan.ACTIVE,
@ -384,7 +384,7 @@ def change_plan_status(
def replace_payment_source( def replace_payment_source(
request: HttpRequest, request: HttpRequest,
user: UserProfile, user: UserProfile,
stripe_token: str = REQ("stripe_token", validator=check_string), stripe_token: str = REQ("stripe_token", json_validator=check_string),
) -> HttpResponse: ) -> HttpResponse:
try: try:
do_replace_payment_source(user, stripe_token, pay_invoices=True) do_replace_payment_source(user, stripe_token, pay_invoices=True)

View File

@ -415,9 +415,9 @@ annotation).
def update_realm( def update_realm(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
name: Optional[str] = REQ(validator=check_string, default=None), name: Optional[str] = REQ(json_validator=check_string, default=None),
# ... # ...
+ mandatory_topics: Optional[bool] = REQ(validator=check_bool, default=None), + mandatory_topics: Optional[bool] = REQ(json_validator=check_bool, default=None),
# ... # ...
): ):
# ... # ...

View File

@ -178,21 +178,21 @@ in
REQ also helps us with request variable validation. For example: REQ also helps us with request variable validation. For example:
* `msg_ids = REQ(validator=check_list(check_int))` will check that the * `msg_ids = REQ(json_validator=check_list(check_int))` will check
`msg_ids` HTTP parameter is a list of integers, marshalled as JSON, that the `msg_ids` HTTP parameter is a list of integers, marshalled
and pass it into the function as the `msg_ids` Python keyword as JSON, and pass it into the function as the `msg_ids` Python
argument. keyword argument.
* `streams_raw = REQ("subscriptions", * `streams_raw = REQ("subscriptions",
validator=check_list(check_string))` will check that the json_validator=check_list(check_string))` will check that the
"subscriptions" HTTP parameter is a list of strings, marshalled as "subscriptions" HTTP parameter is a list of strings, marshalled as
JSON, and pass it into the function with the Python keyword argument JSON, and pass it into the function with the Python keyword argument
`streams_raw`. `streams_raw`.
* `message_id=REQ(converter=to_non_negative_int)` will check that the * `message_id=REQ(converter=to_non_negative_int)` will check that the
`message_id` HTTP parameter is a string containing a non-negative `message_id` HTTP parameter is a string containing a non-negative
integer (`converter` differs from `validator` in that it does not integer (`converter` differs from `json_validator` in that it does
automatically marshall the input from JSON). not automatically marshall the input from JSON).
See See
[zerver/lib/validator.py](https://github.com/zulip/zulip/blob/master/zerver/lib/validator.py) [zerver/lib/validator.py](https://github.com/zulip/zulip/blob/master/zerver/lib/validator.py)
@ -261,7 +261,7 @@ For example, in [zerver/views/realm.py](https://github.com/zulip/zulip/blob/mast
@has_request_variables @has_request_variables
def update_realm( def update_realm(
request: HttpRequest, user_profile: UserProfile, request: HttpRequest, user_profile: UserProfile,
name: Optional[str]=REQ(validator=check_string, default=None), name: Optional[str]=REQ(json_validator=check_string, default=None),
# ... # ...
): ):
realm = user_profile.realm realm = user_profile.realm

View File

@ -83,7 +83,7 @@ class _REQ(Generic[ResultT]):
*, *,
converter: Optional[Callable[[str], ResultT]] = None, converter: Optional[Callable[[str], ResultT]] = None,
default: Union[_NotSpecified, ResultT, None] = NotSpecified, default: Union[_NotSpecified, ResultT, None] = NotSpecified,
validator: Optional[Validator[ResultT]] = None, json_validator: Optional[Validator[ResultT]] = None,
str_validator: Optional[Validator[ResultT]] = None, str_validator: Optional[Validator[ResultT]] = None,
argument_type: Optional[str] = None, argument_type: Optional[str] = None,
intentionally_undocumented: bool = False, intentionally_undocumented: bool = False,
@ -102,11 +102,12 @@ class _REQ(Generic[ResultT]):
default: a value to be used for the argument if the parameter default: a value to be used for the argument if the parameter
is missing in the request is missing in the request
validator: similar to converter, but takes an already parsed JSON json_validator: similar to converter, but takes an already
data structure. If specified, we will parse the JSON request parsed JSON data structure. If specified, we will parse the
variable value before passing to the function JSON request variable value before passing to the function
str_validator: Like validator, but doesn't parse JSON first. str_validator: Like json_validator, but doesn't parse JSON
first.
argument_type: pass 'body' to extract the parsed JSON argument_type: pass 'body' to extract the parsed JSON
corresponding to the request body corresponding to the request body
@ -115,12 +116,13 @@ class _REQ(Generic[ResultT]):
path_only: Used for parameters included in the URL that we still want path_only: Used for parameters included in the URL that we still want
to validate via REQ's hooks. to validate via REQ's hooks.
""" """
self.post_var_name = whence self.post_var_name = whence
self.func_var_name: Optional[str] = None self.func_var_name: Optional[str] = None
self.converter = converter self.converter = converter
self.validator = validator self.json_validator = json_validator
self.str_validator = str_validator self.str_validator = str_validator
self.default = default self.default = default
self.argument_type = argument_type self.argument_type = argument_type
@ -130,11 +132,11 @@ class _REQ(Generic[ResultT]):
self.path_only = path_only self.path_only = path_only
assert converter is None or ( assert converter is None or (
validator is None and str_validator is None json_validator is None and str_validator is None
), "converter and validator are mutually exclusive" ), "converter and json_validator are mutually exclusive"
assert ( assert (
validator is None or str_validator is None json_validator is None or str_validator is None
), "validator and str_validator are mutually exclusive" ), "json_validator and str_validator are mutually exclusive"
# This factory function ensures that mypy can correctly analyze REQ. # This factory function ensures that mypy can correctly analyze REQ.
@ -163,13 +165,13 @@ def REQ(
... ...
# Overload 2: validator # Overload 2: json_validator
@overload @overload
def REQ( def REQ(
whence: Optional[str] = ..., whence: Optional[str] = ...,
*, *,
default: ResultT = ..., default: ResultT = ...,
validator: Validator[ResultT], json_validator: Validator[ResultT],
intentionally_undocumented: bool = ..., intentionally_undocumented: bool = ...,
documentation_pending: bool = ..., documentation_pending: bool = ...,
aliases: Sequence[str] = ..., aliases: Sequence[str] = ...,
@ -178,7 +180,7 @@ def REQ(
... ...
# Overload 3: no converter/validator, default: str or unspecified, argument_type=None # Overload 3: no converter/json_validator, default: str or unspecified, argument_type=None
@overload @overload
def REQ( def REQ(
whence: Optional[str] = ..., whence: Optional[str] = ...,
@ -229,7 +231,7 @@ def REQ(
*, *,
converter: Optional[Callable[[str], ResultT]] = None, converter: Optional[Callable[[str], ResultT]] = None,
default: Union[_REQ._NotSpecified, ResultT] = _REQ.NotSpecified, default: Union[_REQ._NotSpecified, ResultT] = _REQ.NotSpecified,
validator: Optional[Validator[ResultT]] = None, json_validator: Optional[Validator[ResultT]] = None,
str_validator: Optional[Validator[ResultT]] = None, str_validator: Optional[Validator[ResultT]] = None,
argument_type: Optional[str] = None, argument_type: Optional[str] = None,
intentionally_undocumented: bool = False, intentionally_undocumented: bool = False,
@ -243,7 +245,7 @@ def REQ(
whence, whence,
converter=converter, converter=converter,
default=default, default=default,
validator=validator, json_validator=json_validator,
str_validator=str_validator, str_validator=str_validator,
argument_type=argument_type, argument_type=argument_type,
intentionally_undocumented=intentionally_undocumented, intentionally_undocumented=intentionally_undocumented,
@ -364,19 +366,19 @@ def has_request_variables(view_func: ViewFuncT) -> ViewFuncT:
except Exception: except Exception:
raise RequestVariableConversionError(post_var_name, val) raise RequestVariableConversionError(post_var_name, val)
# Validators are like converters, but they don't handle JSON parsing; we do. # json_validator is like converter, but doesn't handle JSON parsing; we do.
if param.validator is not None and not default_assigned: if param.json_validator is not None and not default_assigned:
try: try:
val = orjson.loads(val) val = orjson.loads(val)
except orjson.JSONDecodeError: except orjson.JSONDecodeError:
raise JsonableError(_('Argument "{}" is not valid JSON.').format(post_var_name)) raise JsonableError(_('Argument "{}" is not valid JSON.').format(post_var_name))
try: try:
val = param.validator(post_var_name, val) val = param.json_validator(post_var_name, val)
except ValidationError as error: except ValidationError as error:
raise JsonableError(error.message) raise JsonableError(error.message)
# str_validators is like validator, but for direct strings (no JSON parsing). # str_validators is like json_validator, but for direct strings (no JSON parsing).
if param.str_validator is not None and not default_assigned: if param.str_validator is not None and not default_assigned:
try: try:
val = param.str_validator(post_var_name, val) val = param.str_validator(post_var_name, val)

View File

@ -202,7 +202,7 @@ class DecoratorTestCase(ZulipTestCase):
def test_REQ_validator(self) -> None: def test_REQ_validator(self) -> None:
@has_request_variables @has_request_variables
def get_total( def get_total(
request: HttpRequest, numbers: Iterable[int] = REQ(validator=check_list(check_int)) request: HttpRequest, numbers: Iterable[int] = REQ(json_validator=check_list(check_int))
) -> int: ) -> int:
return sum(numbers) return sum(numbers)

View File

@ -43,7 +43,7 @@ def cleanup_event_queue(
@internal_notify_view(True) @internal_notify_view(True)
@has_request_variables @has_request_variables
def get_events_internal( def get_events_internal(
request: HttpRequest, user_profile_id: int = REQ(validator=check_int) request: HttpRequest, user_profile_id: int = REQ(json_validator=check_int)
) -> HttpResponse: ) -> HttpResponse:
user_profile = get_user_profile_by_id(user_profile_id) user_profile = get_user_profile_by_id(user_profile_id)
request._requestor_for_logs = user_profile.format_requestor_for_logs() request._requestor_for_logs = user_profile.format_requestor_for_logs()
@ -71,27 +71,31 @@ def get_events_backend(
# endpoint. This is a feature used primarily by get_events_internal # endpoint. This is a feature used primarily by get_events_internal
# and not expected to be used by third-party clients. # and not expected to be used by third-party clients.
apply_markdown: bool = REQ( apply_markdown: bool = REQ(
default=False, validator=check_bool, intentionally_undocumented=True default=False, json_validator=check_bool, intentionally_undocumented=True
), ),
client_gravatar: bool = REQ( client_gravatar: bool = REQ(
default=False, validator=check_bool, intentionally_undocumented=True default=False, json_validator=check_bool, intentionally_undocumented=True
),
slim_presence: bool = REQ(
default=False, json_validator=check_bool, intentionally_undocumented=True
), ),
slim_presence: bool = REQ(default=False, validator=check_bool, intentionally_undocumented=True),
all_public_streams: bool = REQ( all_public_streams: bool = REQ(
default=False, validator=check_bool, intentionally_undocumented=True default=False, json_validator=check_bool, intentionally_undocumented=True
), ),
event_types: Optional[Sequence[str]] = REQ( event_types: Optional[Sequence[str]] = REQ(
default=None, validator=check_list(check_string), intentionally_undocumented=True default=None, json_validator=check_list(check_string), intentionally_undocumented=True
), ),
dont_block: bool = REQ(default=False, validator=check_bool), dont_block: bool = REQ(default=False, json_validator=check_bool),
narrow: Iterable[Sequence[str]] = REQ( narrow: Iterable[Sequence[str]] = REQ(
default=[], validator=check_list(check_list(check_string)), intentionally_undocumented=True default=[],
json_validator=check_list(check_list(check_string)),
intentionally_undocumented=True,
), ),
lifespan_secs: int = REQ( lifespan_secs: int = REQ(
default=0, converter=to_non_negative_int, intentionally_undocumented=True default=0, converter=to_non_negative_int, intentionally_undocumented=True
), ),
bulk_message_deletion: bool = REQ( bulk_message_deletion: bool = REQ(
default=False, validator=check_bool, intentionally_undocumented=True default=False, json_validator=check_bool, intentionally_undocumented=True
), ),
) -> HttpResponse: ) -> HttpResponse:
# Extract the Tornado handler from the request # Extract the Tornado handler from the request

View File

@ -23,7 +23,7 @@ def clean_alert_words(alert_words: List[str]) -> List[str]:
def add_alert_words( def add_alert_words(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
alert_words: List[str] = REQ(validator=check_list(check_capped_string(100))), alert_words: List[str] = REQ(json_validator=check_list(check_capped_string(100))),
) -> HttpResponse: ) -> HttpResponse:
do_add_alert_words(user_profile, clean_alert_words(alert_words)) do_add_alert_words(user_profile, clean_alert_words(alert_words))
return json_success({"alert_words": user_alert_words(user_profile)}) return json_success({"alert_words": user_alert_words(user_profile)})
@ -33,7 +33,7 @@ def add_alert_words(
def remove_alert_words( def remove_alert_words(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
alert_words: List[str] = REQ(validator=check_list(check_string)), alert_words: List[str] = REQ(json_validator=check_list(check_string)),
) -> HttpResponse: ) -> HttpResponse:
do_remove_alert_words(user_profile, alert_words) do_remove_alert_words(user_profile, alert_words)
return json_success({"alert_words": user_alert_words(user_profile)}) return json_success({"alert_words": user_alert_words(user_profile)})

View File

@ -102,7 +102,7 @@ def create_realm_custom_profile_field(
name: str = REQ(default="", converter=lambda x: x.strip()), name: str = REQ(default="", converter=lambda x: x.strip()),
hint: str = REQ(default=""), hint: str = REQ(default=""),
field_data: ProfileFieldData = REQ(default={}, converter=orjson.loads), field_data: ProfileFieldData = REQ(default={}, converter=orjson.loads),
field_type: int = REQ(validator=check_int), field_type: int = REQ(json_validator=check_int),
) -> HttpResponse: ) -> HttpResponse:
validate_custom_profile_field(name, hint, field_type, field_data) validate_custom_profile_field(name, hint, field_type, field_data)
try: try:
@ -173,7 +173,7 @@ def update_realm_custom_profile_field(
def reorder_realm_custom_profile_fields( def reorder_realm_custom_profile_fields(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
order: List[int] = REQ(validator=check_list(check_int)), order: List[int] = REQ(json_validator=check_list(check_int)),
) -> HttpResponse: ) -> HttpResponse:
try_reorder_realm_custom_profile_fields(user_profile.realm, order) try_reorder_realm_custom_profile_fields(user_profile.realm, order)
return json_success() return json_success()
@ -184,7 +184,7 @@ def reorder_realm_custom_profile_fields(
def remove_user_custom_profile_data( def remove_user_custom_profile_data(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
data: List[int] = REQ(validator=check_list(check_int)), data: List[int] = REQ(json_validator=check_list(check_int)),
) -> HttpResponse: ) -> HttpResponse:
for field_id in data: for field_id in data:
check_remove_custom_profile_field_value(user_profile, field_id) check_remove_custom_profile_field_value(user_profile, field_id)
@ -197,7 +197,7 @@ def update_user_custom_profile_data(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
data: List[Dict[str, Union[int, str, List[int]]]] = REQ( data: List[Dict[str, Union[int, str, List[int]]]] = REQ(
validator=check_list( json_validator=check_list(
check_dict_only( check_dict_only(
[ [
("id", check_int), ("id", check_int),

View File

@ -98,7 +98,7 @@ def check_send_webhook_fixture_message(
request: HttpRequest, request: HttpRequest,
url: str = REQ(), url: str = REQ(),
body: str = REQ(), body: str = REQ(),
is_json: bool = REQ(validator=check_bool), is_json: bool = REQ(json_validator=check_bool),
custom_headers: str = REQ(), custom_headers: str = REQ(),
) -> HttpResponse: ) -> HttpResponse:
try: try:

View File

@ -96,7 +96,9 @@ def fetch_drafts(request: HttpRequest, user_profile: UserProfile) -> HttpRespons
def create_drafts( def create_drafts(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
draft_dicts: List[Dict[str, Any]] = REQ("drafts", validator=check_list(draft_dict_validator)), draft_dicts: List[Dict[str, Any]] = REQ(
"drafts", json_validator=check_list(draft_dict_validator)
),
) -> HttpResponse: ) -> HttpResponse:
draft_objects = [] draft_objects = []
for draft_dict in draft_dicts: for draft_dict in draft_dicts:
@ -121,7 +123,7 @@ def edit_draft(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
draft_id: int, draft_id: int,
draft_dict: Dict[str, Any] = REQ("draft", validator=draft_dict_validator), draft_dict: Dict[str, Any] = REQ("draft", json_validator=draft_dict_validator),
) -> HttpResponse: ) -> HttpResponse:
try: try:
draft_object = Draft.objects.get(id=draft_id, user_profile=user_profile) draft_object = Draft.objects.get(id=draft_id, user_profile=user_profile)

View File

@ -34,13 +34,13 @@ NarrowT = Iterable[Sequence[str]]
def events_register_backend( def events_register_backend(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
apply_markdown: bool = REQ(default=False, validator=check_bool), apply_markdown: bool = REQ(default=False, json_validator=check_bool),
client_gravatar: bool = REQ(default=False, validator=check_bool), client_gravatar: bool = REQ(default=False, json_validator=check_bool),
slim_presence: bool = REQ(default=False, validator=check_bool), slim_presence: bool = REQ(default=False, json_validator=check_bool),
all_public_streams: Optional[bool] = REQ(default=None, validator=check_bool), all_public_streams: Optional[bool] = REQ(default=None, json_validator=check_bool),
include_subscribers: bool = REQ(default=False, validator=check_bool), include_subscribers: bool = REQ(default=False, json_validator=check_bool),
client_capabilities: Optional[Dict[str, bool]] = REQ( client_capabilities: Optional[Dict[str, bool]] = REQ(
validator=check_dict( json_validator=check_dict(
[ [
# This field was accidentally made required when it was added in v2.0.0-781; # This field was accidentally made required when it was added in v2.0.0-781;
# this was not realized until after the release of Zulip 2.1.2. (It remains # this was not realized until after the release of Zulip 2.1.2. (It remains
@ -56,11 +56,15 @@ def events_register_backend(
), ),
default=None, default=None,
), ),
event_types: Optional[Iterable[str]] = REQ(validator=check_list(check_string), default=None), event_types: Optional[Iterable[str]] = REQ(
fetch_event_types: Optional[Iterable[str]] = REQ( json_validator=check_list(check_string), default=None
validator=check_list(check_string), default=None ),
fetch_event_types: Optional[Iterable[str]] = REQ(
json_validator=check_list(check_string), default=None
),
narrow: NarrowT = REQ(
json_validator=check_list(check_list(check_string, length=2)), default=[]
), ),
narrow: NarrowT = REQ(validator=check_list(check_list(check_string, length=2)), default=[]),
queue_lifespan_secs: int = REQ(converter=int, default=0, documentation_pending=True), queue_lifespan_secs: int = REQ(converter=int, default=0, documentation_pending=True),
) -> HttpResponse: ) -> HttpResponse:
all_public_streams = _default_all_public_streams(user_profile, all_public_streams) all_public_streams = _default_all_public_streams(user_profile, all_public_streams)

View File

@ -13,7 +13,7 @@ from zerver.models import UserProfile
@human_users_only @human_users_only
@has_request_variables @has_request_variables
def mark_hotspot_as_read( def mark_hotspot_as_read(
request: HttpRequest, user: UserProfile, hotspot: str = REQ(validator=check_string) request: HttpRequest, user: UserProfile, hotspot: str = REQ(json_validator=check_string)
) -> HttpResponse: ) -> HttpResponse:
if hotspot not in ALL_HOTSPOTS: if hotspot not in ALL_HOTSPOTS:
return json_error(_("Unknown hotspot: {}").format(hotspot)) return json_error(_("Unknown hotspot: {}").format(hotspot))

View File

@ -35,8 +35,8 @@ def invite_users_backend(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
invitee_emails_raw: str = REQ("invitee_emails"), invitee_emails_raw: str = REQ("invitee_emails"),
invite_as: int = REQ(validator=check_int, default=PreregistrationUser.INVITE_AS["MEMBER"]), invite_as: int = REQ(json_validator=check_int, default=PreregistrationUser.INVITE_AS["MEMBER"]),
stream_ids: List[int] = REQ(validator=check_list(check_int)), stream_ids: List[int] = REQ(json_validator=check_list(check_int)),
) -> HttpResponse: ) -> HttpResponse:
if not user_profile.can_invite_others_to_realm(): if not user_profile.can_invite_others_to_realm():
@ -167,8 +167,8 @@ def resend_user_invite_email(
def generate_multiuse_invite_backend( def generate_multiuse_invite_backend(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
invite_as: int = REQ(validator=check_int, default=PreregistrationUser.INVITE_AS["MEMBER"]), invite_as: int = REQ(json_validator=check_int, default=PreregistrationUser.INVITE_AS["MEMBER"]),
stream_ids: Sequence[int] = REQ(validator=check_list(check_int), default=[]), stream_ids: Sequence[int] = REQ(json_validator=check_list(check_int), default=[]),
) -> HttpResponse: ) -> HttpResponse:
check_if_owner_required(invite_as, user_profile) check_if_owner_required(invite_as, user_profile)

View File

@ -109,8 +109,8 @@ def update_message_backend(
propagate_mode: Optional[str] = REQ( propagate_mode: Optional[str] = REQ(
default="change_one", str_validator=check_string_in(PROPAGATE_MODE_VALUES) default="change_one", str_validator=check_string_in(PROPAGATE_MODE_VALUES)
), ),
send_notification_to_old_thread: bool = REQ(default=True, validator=check_bool), send_notification_to_old_thread: bool = REQ(default=True, json_validator=check_bool),
send_notification_to_new_thread: bool = REQ(default=True, validator=check_bool), send_notification_to_new_thread: bool = REQ(default=True, json_validator=check_bool),
content: Optional[str] = REQ(default=None), content: Optional[str] = REQ(default=None),
) -> HttpResponse: ) -> HttpResponse:
if not user_profile.realm.allow_message_editing: if not user_profile.realm.allow_message_editing:

View File

@ -927,10 +927,10 @@ def get_messages_backend(
num_after: int = REQ(converter=to_non_negative_int), num_after: int = REQ(converter=to_non_negative_int),
narrow: OptionalNarrowListT = REQ("narrow", converter=narrow_parameter, default=None), narrow: OptionalNarrowListT = REQ("narrow", converter=narrow_parameter, default=None),
use_first_unread_anchor_val: bool = REQ( use_first_unread_anchor_val: bool = REQ(
"use_first_unread_anchor", validator=check_bool, default=False "use_first_unread_anchor", json_validator=check_bool, default=False
), ),
client_gravatar: bool = REQ(validator=check_bool, default=False), client_gravatar: bool = REQ(json_validator=check_bool, default=False),
apply_markdown: bool = REQ(validator=check_bool, default=True), apply_markdown: bool = REQ(json_validator=check_bool, default=True),
) -> HttpResponse: ) -> HttpResponse:
anchor = parse_anchor_value(anchor_val, use_first_unread_anchor_val) anchor = parse_anchor_value(anchor_val, use_first_unread_anchor_val)
if num_before + num_after > MAX_MESSAGES_PER_FETCH: if num_before + num_after > MAX_MESSAGES_PER_FETCH:
@ -1300,7 +1300,7 @@ def post_process_limited_query(
def messages_in_narrow_backend( def messages_in_narrow_backend(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
msg_ids: List[int] = REQ(validator=check_list(check_int)), msg_ids: List[int] = REQ(json_validator=check_list(check_int)),
narrow: OptionalNarrowListT = REQ(converter=narrow_parameter), narrow: OptionalNarrowListT = REQ(converter=narrow_parameter),
) -> HttpResponse: ) -> HttpResponse:

View File

@ -31,7 +31,7 @@ def get_latest_update_message_flag_activity(user_profile: UserProfile) -> Option
def update_message_flags( def update_message_flags(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
messages: List[int] = REQ(validator=check_list(check_int)), messages: List[int] = REQ(json_validator=check_list(check_int)),
operation: str = REQ("op"), operation: str = REQ("op"),
flag: str = REQ(), flag: str = REQ(),
) -> HttpResponse: ) -> HttpResponse:
@ -57,7 +57,7 @@ def mark_all_as_read(request: HttpRequest, user_profile: UserProfile) -> HttpRes
@has_request_variables @has_request_variables
def mark_stream_as_read( def mark_stream_as_read(
request: HttpRequest, user_profile: UserProfile, stream_id: int = REQ(validator=check_int) request: HttpRequest, user_profile: UserProfile, stream_id: int = REQ(json_validator=check_int)
) -> HttpResponse: ) -> HttpResponse:
stream, sub = access_stream_by_id(user_profile, stream_id) stream, sub = access_stream_by_id(user_profile, stream_id)
count = do_mark_stream_messages_as_read(user_profile, stream.recipient_id) count = do_mark_stream_messages_as_read(user_profile, stream.recipient_id)
@ -72,7 +72,7 @@ def mark_stream_as_read(
def mark_topic_as_read( def mark_topic_as_read(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
stream_id: int = REQ(validator=check_int), stream_id: int = REQ(json_validator=check_int),
topic_name: str = REQ(), topic_name: str = REQ(),
) -> HttpResponse: ) -> HttpResponse:
stream, sub = access_stream_by_id(user_profile, stream_id) stream, sub = access_stream_by_id(user_profile, stream_id)

View File

@ -64,7 +64,7 @@ def unmute_topic(
def update_muted_topic( def update_muted_topic(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
stream_id: Optional[int] = REQ(validator=check_int, default=None), stream_id: Optional[int] = REQ(json_validator=check_int, default=None),
stream: Optional[str] = REQ(default=None), stream: Optional[str] = REQ(default=None),
topic: str = REQ(), topic: str = REQ(),
op: str = REQ(), op: str = REQ(),

View File

@ -65,7 +65,7 @@ def get_presence_backend(
def update_user_status_backend( def update_user_status_backend(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
away: Optional[bool] = REQ(validator=check_bool, default=None), away: Optional[bool] = REQ(json_validator=check_bool, default=None),
status_text: Optional[str] = REQ(str_validator=check_capped_string(60), default=None), status_text: Optional[str] = REQ(str_validator=check_capped_string(60), default=None),
) -> HttpResponse: ) -> HttpResponse:
@ -91,9 +91,9 @@ def update_active_status_backend(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
status: str = REQ(), status: str = REQ(),
ping_only: bool = REQ(validator=check_bool, default=False), ping_only: bool = REQ(json_validator=check_bool, default=False),
new_user_input: bool = REQ(validator=check_bool, default=False), new_user_input: bool = REQ(json_validator=check_bool, default=False),
slim_presence: bool = REQ(validator=check_bool, default=False), slim_presence: bool = REQ(json_validator=check_bool, default=False),
) -> HttpResponse: ) -> HttpResponse:
status_val = UserPresence.status_from_string(status) status_val = UserPresence.status_from_string(status)
if status_val is None: if status_val is None:

View File

@ -41,70 +41,74 @@ from zerver.models import Realm, UserProfile
def update_realm( def update_realm(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
name: Optional[str] = REQ(validator=check_string, default=None), name: Optional[str] = REQ(json_validator=check_string, default=None),
description: Optional[str] = REQ(validator=check_string, default=None), description: Optional[str] = REQ(json_validator=check_string, default=None),
emails_restricted_to_domains: Optional[bool] = REQ(validator=check_bool, default=None), emails_restricted_to_domains: Optional[bool] = REQ(json_validator=check_bool, default=None),
disallow_disposable_email_addresses: Optional[bool] = REQ(validator=check_bool, default=None), disallow_disposable_email_addresses: Optional[bool] = REQ(
invite_required: Optional[bool] = REQ(validator=check_bool, default=None), json_validator=check_bool, default=None
invite_to_realm_policy: Optional[int] = REQ(
validator=check_int_in(Realm.COMMON_POLICY_TYPES), default=None
), ),
name_changes_disabled: Optional[bool] = REQ(validator=check_bool, default=None), invite_required: Optional[bool] = REQ(json_validator=check_bool, default=None),
email_changes_disabled: Optional[bool] = REQ(validator=check_bool, default=None), invite_to_realm_policy: Optional[int] = REQ(
avatar_changes_disabled: Optional[bool] = REQ(validator=check_bool, default=None), json_validator=check_int_in(Realm.COMMON_POLICY_TYPES), default=None
inline_image_preview: Optional[bool] = REQ(validator=check_bool, default=None), ),
inline_url_embed_preview: Optional[bool] = REQ(validator=check_bool, default=None), name_changes_disabled: Optional[bool] = REQ(json_validator=check_bool, default=None),
add_emoji_by_admins_only: Optional[bool] = REQ(validator=check_bool, default=None), email_changes_disabled: Optional[bool] = REQ(json_validator=check_bool, default=None),
allow_message_deleting: Optional[bool] = REQ(validator=check_bool, default=None), avatar_changes_disabled: Optional[bool] = REQ(json_validator=check_bool, default=None),
inline_image_preview: Optional[bool] = REQ(json_validator=check_bool, default=None),
inline_url_embed_preview: Optional[bool] = REQ(json_validator=check_bool, default=None),
add_emoji_by_admins_only: Optional[bool] = REQ(json_validator=check_bool, default=None),
allow_message_deleting: Optional[bool] = REQ(json_validator=check_bool, default=None),
message_content_delete_limit_seconds: Optional[int] = REQ( message_content_delete_limit_seconds: Optional[int] = REQ(
converter=to_non_negative_int, default=None converter=to_non_negative_int, default=None
), ),
allow_message_editing: Optional[bool] = REQ(validator=check_bool, default=None), allow_message_editing: Optional[bool] = REQ(json_validator=check_bool, default=None),
allow_community_topic_editing: Optional[bool] = REQ(validator=check_bool, default=None), allow_community_topic_editing: Optional[bool] = REQ(json_validator=check_bool, default=None),
mandatory_topics: Optional[bool] = REQ(validator=check_bool, default=None), mandatory_topics: Optional[bool] = REQ(json_validator=check_bool, default=None),
message_content_edit_limit_seconds: Optional[int] = REQ( message_content_edit_limit_seconds: Optional[int] = REQ(
converter=to_non_negative_int, default=None converter=to_non_negative_int, default=None
), ),
allow_edit_history: Optional[bool] = REQ(validator=check_bool, default=None), allow_edit_history: Optional[bool] = REQ(json_validator=check_bool, default=None),
default_language: Optional[str] = REQ(validator=check_string, default=None), default_language: Optional[str] = REQ(json_validator=check_string, default=None),
waiting_period_threshold: Optional[int] = REQ(converter=to_non_negative_int, default=None), waiting_period_threshold: Optional[int] = REQ(converter=to_non_negative_int, default=None),
authentication_methods: Optional[Dict[str, Any]] = REQ(validator=check_dict([]), default=None), authentication_methods: Optional[Dict[str, Any]] = REQ(
notifications_stream_id: Optional[int] = REQ(validator=check_int, default=None), json_validator=check_dict([]), default=None
signup_notifications_stream_id: Optional[int] = REQ(validator=check_int, default=None),
message_retention_days_raw: Optional[Union[int, str]] = REQ(
"message_retention_days", validator=check_string_or_int, default=None
), ),
send_welcome_emails: Optional[bool] = REQ(validator=check_bool, default=None), notifications_stream_id: Optional[int] = REQ(json_validator=check_int, default=None),
digest_emails_enabled: Optional[bool] = REQ(validator=check_bool, default=None), signup_notifications_stream_id: Optional[int] = REQ(json_validator=check_int, default=None),
message_retention_days_raw: Optional[Union[int, str]] = REQ(
"message_retention_days", json_validator=check_string_or_int, default=None
),
send_welcome_emails: Optional[bool] = REQ(json_validator=check_bool, default=None),
digest_emails_enabled: Optional[bool] = REQ(json_validator=check_bool, default=None),
message_content_allowed_in_email_notifications: Optional[bool] = REQ( message_content_allowed_in_email_notifications: Optional[bool] = REQ(
validator=check_bool, default=None json_validator=check_bool, default=None
), ),
bot_creation_policy: Optional[int] = REQ( bot_creation_policy: Optional[int] = REQ(
validator=check_int_in(Realm.BOT_CREATION_POLICY_TYPES), default=None json_validator=check_int_in(Realm.BOT_CREATION_POLICY_TYPES), default=None
), ),
create_stream_policy: Optional[int] = REQ( create_stream_policy: Optional[int] = REQ(
validator=check_int_in(Realm.COMMON_POLICY_TYPES), default=None json_validator=check_int_in(Realm.COMMON_POLICY_TYPES), default=None
), ),
invite_to_stream_policy: Optional[int] = REQ( invite_to_stream_policy: Optional[int] = REQ(
validator=check_int_in(Realm.COMMON_POLICY_TYPES), default=None json_validator=check_int_in(Realm.COMMON_POLICY_TYPES), default=None
), ),
user_group_edit_policy: Optional[int] = REQ( user_group_edit_policy: Optional[int] = REQ(
validator=check_int_in(Realm.USER_GROUP_EDIT_POLICY_TYPES), default=None json_validator=check_int_in(Realm.USER_GROUP_EDIT_POLICY_TYPES), default=None
), ),
private_message_policy: Optional[int] = REQ( private_message_policy: Optional[int] = REQ(
validator=check_int_in(Realm.PRIVATE_MESSAGE_POLICY_TYPES), default=None json_validator=check_int_in(Realm.PRIVATE_MESSAGE_POLICY_TYPES), default=None
), ),
wildcard_mention_policy: Optional[int] = REQ( wildcard_mention_policy: Optional[int] = REQ(
validator=check_int_in(Realm.WILDCARD_MENTION_POLICY_TYPES), default=None json_validator=check_int_in(Realm.WILDCARD_MENTION_POLICY_TYPES), default=None
), ),
email_address_visibility: Optional[int] = REQ( email_address_visibility: Optional[int] = REQ(
validator=check_int_in(Realm.EMAIL_ADDRESS_VISIBILITY_TYPES), default=None json_validator=check_int_in(Realm.EMAIL_ADDRESS_VISIBILITY_TYPES), default=None
), ),
default_twenty_four_hour_time: Optional[bool] = REQ(validator=check_bool, default=None), default_twenty_four_hour_time: Optional[bool] = REQ(json_validator=check_bool, default=None),
video_chat_provider: Optional[int] = REQ(validator=check_int, default=None), video_chat_provider: Optional[int] = REQ(json_validator=check_int, default=None),
default_code_block_language: Optional[str] = REQ(validator=check_string, default=None), default_code_block_language: Optional[str] = REQ(json_validator=check_string, default=None),
digest_weekday: Optional[int] = REQ( digest_weekday: Optional[int] = REQ(
validator=check_int_in(Realm.DIGEST_WEEKDAY_VALUES), default=None json_validator=check_int_in(Realm.DIGEST_WEEKDAY_VALUES), default=None
), ),
) -> HttpResponse: ) -> HttpResponse:
realm = user_profile.realm realm = user_profile.realm

View File

@ -21,8 +21,8 @@ def list_realm_domains(request: HttpRequest, user_profile: UserProfile) -> HttpR
def create_realm_domain( def create_realm_domain(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
domain: str = REQ(validator=check_string), domain: str = REQ(json_validator=check_string),
allow_subdomains: bool = REQ(validator=check_bool), allow_subdomains: bool = REQ(json_validator=check_bool),
) -> HttpResponse: ) -> HttpResponse:
domain = domain.strip().lower() domain = domain.strip().lower()
try: try:
@ -43,7 +43,7 @@ def patch_realm_domain(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
domain: str, domain: str,
allow_subdomains: bool = REQ(validator=check_bool), allow_subdomains: bool = REQ(json_validator=check_bool),
) -> HttpResponse: ) -> HttpResponse:
try: try:
realm_domain = RealmDomain.objects.get(realm=user_profile.realm, domain=domain) realm_domain = RealmDomain.objects.get(realm=user_profile.realm, domain=domain)

View File

@ -17,7 +17,7 @@ from zerver.models import UserProfile
@require_realm_admin @require_realm_admin
@has_request_variables @has_request_variables
def upload_logo( def upload_logo(
request: HttpRequest, user_profile: UserProfile, night: bool = REQ(validator=check_bool) request: HttpRequest, user_profile: UserProfile, night: bool = REQ(json_validator=check_bool)
) -> HttpResponse: ) -> HttpResponse:
user_profile.realm.ensure_not_on_limited_plan() user_profile.realm.ensure_not_on_limited_plan()
@ -40,7 +40,7 @@ def upload_logo(
@require_realm_admin @require_realm_admin
@has_request_variables @has_request_variables
def delete_logo_backend( def delete_logo_backend(
request: HttpRequest, user_profile: UserProfile, night: bool = REQ(validator=check_bool) request: HttpRequest, user_profile: UserProfile, night: bool = REQ(json_validator=check_bool)
) -> HttpResponse: ) -> HttpResponse:
# We don't actually delete the logo because it might still # We don't actually delete the logo because it might still
# be needed if the URL was cached and it is rewritten # be needed if the URL was cached and it is rewritten
@ -53,7 +53,7 @@ def delete_logo_backend(
@has_request_variables @has_request_variables
def get_logo_backend( def get_logo_backend(
request: HttpRequest, user_profile: UserProfile, night: bool = REQ(validator=check_bool) request: HttpRequest, user_profile: UserProfile, night: bool = REQ(json_validator=check_bool)
) -> HttpResponse: ) -> HttpResponse:
url = get_realm_logo_url(user_profile.realm, night) url = get_realm_logo_url(user_profile.realm, night)

View File

@ -39,8 +39,8 @@ def add_realm_playground(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
name: str = REQ(), name: str = REQ(),
url_prefix: str = REQ(validator=check_url), url_prefix: str = REQ(json_validator=check_url),
pygments_language: str = REQ(validator=check_pygments_language), pygments_language: str = REQ(json_validator=check_pygments_language),
) -> HttpResponse: ) -> HttpResponse:
try: try:
playground_id = do_add_realm_playground( playground_id = do_add_realm_playground(

View File

@ -44,8 +44,8 @@ def report_send_times(
time: int = REQ(converter=to_non_negative_int), time: int = REQ(converter=to_non_negative_int),
received: int = REQ(converter=to_non_negative_int, default=-1), received: int = REQ(converter=to_non_negative_int, default=-1),
displayed: int = REQ(converter=to_non_negative_int, default=-1), displayed: int = REQ(converter=to_non_negative_int, default=-1),
locally_echoed: bool = REQ(validator=check_bool, default=False), locally_echoed: bool = REQ(json_validator=check_bool, default=False),
rendered_content_disparity: bool = REQ(validator=check_bool, default=False), rendered_content_disparity: bool = REQ(json_validator=check_bool, default=False),
) -> HttpResponse: ) -> HttpResponse:
received_str = "(unknown)" received_str = "(unknown)"
if received > 0: if received > 0:
@ -109,11 +109,11 @@ def report_error(
user_profile: UserProfile, user_profile: UserProfile,
message: str = REQ(), message: str = REQ(),
stacktrace: str = REQ(), stacktrace: str = REQ(),
ui_message: bool = REQ(validator=check_bool), ui_message: bool = REQ(json_validator=check_bool),
user_agent: str = REQ(), user_agent: str = REQ(),
href: str = REQ(), href: str = REQ(),
log: str = REQ(), log: str = REQ(),
more_info: Mapping[str, Any] = REQ(validator=check_dict([]), default={}), more_info: Mapping[str, Any] = REQ(json_validator=check_dict([]), default={}),
) -> HttpResponse: ) -> HttpResponse:
"""Accepts an error report and stores in a queue for processing. The """Accepts an error report and stores in a queue for processing. The
actual error reports are later handled by do_report_error""" actual error reports are later handled by do_report_error"""

View File

@ -19,7 +19,7 @@ from zerver.models import UserProfile
def update_storage( def update_storage(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
storage: Dict[str, str] = REQ(validator=check_dict([], value_validator=check_string)), storage: Dict[str, str] = REQ(json_validator=check_dict([], value_validator=check_string)),
) -> HttpResponse: ) -> HttpResponse:
try: try:
set_bot_storage(user_profile, list(storage.items())) set_bot_storage(user_profile, list(storage.items()))
@ -32,7 +32,7 @@ def update_storage(
def get_storage( def get_storage(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
keys: Optional[List[str]] = REQ(validator=check_list(check_string), default=None), keys: Optional[List[str]] = REQ(json_validator=check_list(check_string), default=None),
) -> HttpResponse: ) -> HttpResponse:
keys = keys or get_keys_in_bot_storage(user_profile) keys = keys or get_keys_in_bot_storage(user_profile)
try: try:
@ -46,7 +46,7 @@ def get_storage(
def remove_storage( def remove_storage(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
keys: Optional[List[str]] = REQ(validator=check_list(check_string), default=None), keys: Optional[List[str]] = REQ(json_validator=check_list(check_string), default=None),
) -> HttpResponse: ) -> HttpResponse:
keys = keys or get_keys_in_bot_storage(user_profile) keys = keys or get_keys_in_bot_storage(user_profile)
try: try:

View File

@ -144,7 +144,7 @@ def deactivate_stream_backend(
@require_realm_admin @require_realm_admin
@has_request_variables @has_request_variables
def add_default_stream( def add_default_stream(
request: HttpRequest, user_profile: UserProfile, stream_id: int = REQ(validator=check_int) request: HttpRequest, user_profile: UserProfile, stream_id: int = REQ(json_validator=check_int)
) -> HttpResponse: ) -> HttpResponse:
(stream, sub) = access_stream_by_id(user_profile, stream_id) (stream, sub) = access_stream_by_id(user_profile, stream_id)
if stream.invite_only: if stream.invite_only:
@ -160,7 +160,7 @@ def create_default_stream_group(
user_profile: UserProfile, user_profile: UserProfile,
group_name: str = REQ(), group_name: str = REQ(),
description: str = REQ(), description: str = REQ(),
stream_names: List[str] = REQ(validator=check_list(check_string)), stream_names: List[str] = REQ(json_validator=check_list(check_string)),
) -> None: ) -> None:
streams = [] streams = []
for stream_name in stream_names: for stream_name in stream_names:
@ -176,8 +176,8 @@ def update_default_stream_group_info(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
group_id: int, group_id: int,
new_group_name: Optional[str] = REQ(validator=check_string, default=None), new_group_name: Optional[str] = REQ(json_validator=check_string, default=None),
new_description: Optional[str] = REQ(validator=check_string, default=None), new_description: Optional[str] = REQ(json_validator=check_string, default=None),
) -> None: ) -> None:
if not new_group_name and not new_description: if not new_group_name and not new_description:
return json_error(_('You must pass "new_description" or "new_group_name".')) return json_error(_('You must pass "new_description" or "new_group_name".'))
@ -197,7 +197,7 @@ def update_default_stream_group_streams(
user_profile: UserProfile, user_profile: UserProfile,
group_id: int, group_id: int,
op: str = REQ(), op: str = REQ(),
stream_names: List[str] = REQ(validator=check_list(check_string)), stream_names: List[str] = REQ(json_validator=check_list(check_string)),
) -> None: ) -> None:
group = access_default_stream_group_by_id(user_profile.realm, group_id) group = access_default_stream_group_by_id(user_profile.realm, group_id)
streams = [] streams = []
@ -227,7 +227,7 @@ def remove_default_stream_group(
@require_realm_admin @require_realm_admin
@has_request_variables @has_request_variables
def remove_default_stream( def remove_default_stream(
request: HttpRequest, user_profile: UserProfile, stream_id: int = REQ(validator=check_int) request: HttpRequest, user_profile: UserProfile, stream_id: int = REQ(json_validator=check_int)
) -> HttpResponse: ) -> HttpResponse:
(stream, sub) = access_stream_by_id( (stream, sub) = access_stream_by_id(
user_profile, user_profile,
@ -244,17 +244,17 @@ def update_stream_backend(
user_profile: UserProfile, user_profile: UserProfile,
stream_id: int, stream_id: int,
description: Optional[str] = REQ( description: Optional[str] = REQ(
validator=check_capped_string(Stream.MAX_DESCRIPTION_LENGTH), default=None json_validator=check_capped_string(Stream.MAX_DESCRIPTION_LENGTH), default=None
), ),
is_private: Optional[bool] = REQ(validator=check_bool, default=None), is_private: Optional[bool] = REQ(json_validator=check_bool, default=None),
is_announcement_only: Optional[bool] = REQ(validator=check_bool, default=None), is_announcement_only: Optional[bool] = REQ(json_validator=check_bool, default=None),
stream_post_policy: Optional[int] = REQ( stream_post_policy: Optional[int] = REQ(
validator=check_int_in(Stream.STREAM_POST_POLICY_TYPES), default=None json_validator=check_int_in(Stream.STREAM_POST_POLICY_TYPES), default=None
), ),
history_public_to_subscribers: Optional[bool] = REQ(validator=check_bool, default=None), history_public_to_subscribers: Optional[bool] = REQ(json_validator=check_bool, default=None),
new_name: Optional[str] = REQ(validator=check_string, default=None), new_name: Optional[str] = REQ(json_validator=check_string, default=None),
message_retention_days: Optional[Union[int, str]] = REQ( message_retention_days: Optional[Union[int, str]] = REQ(
validator=check_string_or_int, default=None json_validator=check_string_or_int, default=None
), ),
) -> HttpResponse: ) -> HttpResponse:
# We allow realm administrators to to update the stream name and # We allow realm administrators to to update the stream name and
@ -310,7 +310,7 @@ def update_stream_backend(
def list_subscriptions_backend( def list_subscriptions_backend(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
include_subscribers: bool = REQ(validator=check_bool, default=False), include_subscribers: bool = REQ(json_validator=check_bool, default=False),
) -> HttpResponse: ) -> HttpResponse:
subscribed, _ = gather_subscriptions( subscribed, _ = gather_subscriptions(
user_profile, user_profile,
@ -336,8 +336,8 @@ remove_subscriptions_schema = check_list(check_string)
def update_subscriptions_backend( def update_subscriptions_backend(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
delete: Iterable[str] = REQ(validator=remove_subscriptions_schema, default=[]), delete: Iterable[str] = REQ(json_validator=remove_subscriptions_schema, default=[]),
add: Iterable[Mapping[str, str]] = REQ(validator=add_subscriptions_schema, default=[]), add: Iterable[Mapping[str, str]] = REQ(json_validator=add_subscriptions_schema, default=[]),
) -> HttpResponse: ) -> HttpResponse:
if not add and not delete: if not add and not delete:
return json_error(_('Nothing to do. Specify at least one of "add" or "delete".')) return json_error(_('Nothing to do. Specify at least one of "add" or "delete".'))
@ -380,9 +380,9 @@ check_principals: Validator[Union[List[str], List[int]]] = check_union(
def remove_subscriptions_backend( def remove_subscriptions_backend(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
streams_raw: Iterable[str] = REQ("subscriptions", validator=remove_subscriptions_schema), streams_raw: Iterable[str] = REQ("subscriptions", json_validator=remove_subscriptions_schema),
principals: Optional[Union[List[str], List[int]]] = REQ( principals: Optional[Union[List[str], List[int]]] = REQ(
validator=check_principals, default=None json_validator=check_principals, default=None
), ),
) -> HttpResponse: ) -> HttpResponse:
@ -447,23 +447,23 @@ def add_subscriptions_backend(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
streams_raw: Iterable[Mapping[str, str]] = REQ( streams_raw: Iterable[Mapping[str, str]] = REQ(
"subscriptions", validator=add_subscriptions_schema "subscriptions", json_validator=add_subscriptions_schema
), ),
invite_only: bool = REQ(validator=check_bool, default=False), invite_only: bool = REQ(json_validator=check_bool, default=False),
stream_post_policy: int = REQ( stream_post_policy: int = REQ(
validator=check_int_in(Stream.STREAM_POST_POLICY_TYPES), json_validator=check_int_in(Stream.STREAM_POST_POLICY_TYPES),
default=Stream.STREAM_POST_POLICY_EVERYONE, default=Stream.STREAM_POST_POLICY_EVERYONE,
), ),
history_public_to_subscribers: Optional[bool] = REQ(validator=check_bool, default=None), history_public_to_subscribers: Optional[bool] = REQ(json_validator=check_bool, default=None),
message_retention_days: Union[str, int] = REQ( message_retention_days: Union[str, int] = REQ(
validator=check_string_or_int, default=RETENTION_DEFAULT json_validator=check_string_or_int, default=RETENTION_DEFAULT
), ),
announce: bool = REQ(validator=check_bool, default=False), announce: bool = REQ(json_validator=check_bool, default=False),
principals: Union[Sequence[str], Sequence[int]] = REQ( principals: Union[Sequence[str], Sequence[int]] = REQ(
validator=check_principals, json_validator=check_principals,
default=EMPTY_PRINCIPALS, default=EMPTY_PRINCIPALS,
), ),
authorization_errors_fatal: bool = REQ(validator=check_bool, default=True), authorization_errors_fatal: bool = REQ(json_validator=check_bool, default=True),
) -> HttpResponse: ) -> HttpResponse:
realm = user_profile.realm realm = user_profile.realm
stream_dicts = [] stream_dicts = []
@ -695,12 +695,12 @@ def get_subscribers_backend(
def get_streams_backend( def get_streams_backend(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
include_public: bool = REQ(validator=check_bool, default=True), include_public: bool = REQ(json_validator=check_bool, default=True),
include_web_public: bool = REQ(validator=check_bool, default=False), include_web_public: bool = REQ(json_validator=check_bool, default=False),
include_subscribed: bool = REQ(validator=check_bool, default=True), include_subscribed: bool = REQ(json_validator=check_bool, default=True),
include_all_active: bool = REQ(validator=check_bool, default=False), include_all_active: bool = REQ(json_validator=check_bool, default=False),
include_default: bool = REQ(validator=check_bool, default=False), include_default: bool = REQ(json_validator=check_bool, default=False),
include_owner_subscribed: bool = REQ(validator=check_bool, default=False), include_owner_subscribed: bool = REQ(json_validator=check_bool, default=False),
) -> HttpResponse: ) -> HttpResponse:
streams = do_get_streams( streams = do_get_streams(
@ -780,7 +780,7 @@ def json_stream_exists(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
stream_name: str = REQ("stream"), stream_name: str = REQ("stream"),
autosubscribe: bool = REQ(validator=check_bool, default=False), autosubscribe: bool = REQ(json_validator=check_bool, default=False),
) -> HttpResponse: ) -> HttpResponse:
check_stream_name(stream_name) check_stream_name(stream_name)
@ -817,7 +817,7 @@ def json_get_stream_id(
def update_subscriptions_property( def update_subscriptions_property(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
stream_id: int = REQ(validator=check_int), stream_id: int = REQ(json_validator=check_int),
property: str = REQ(), property: str = REQ(),
value: str = REQ(), value: str = REQ(),
) -> HttpResponse: ) -> HttpResponse:
@ -832,7 +832,7 @@ def update_subscription_properties_backend(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
subscription_data: List[Dict[str, Any]] = REQ( subscription_data: List[Dict[str, Any]] = REQ(
validator=check_list( json_validator=check_list(
check_dict( check_dict(
[ [
("stream_id", check_int), ("stream_id", check_int),

View File

@ -14,7 +14,7 @@ from zerver.models import UserProfile
def process_submessage( def process_submessage(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
message_id: int = REQ(validator=check_int), message_id: int = REQ(json_validator=check_int),
msg_type: str = REQ(), msg_type: str = REQ(),
content: str = REQ(), content: str = REQ(),
) -> HttpResponse: ) -> HttpResponse:

View File

@ -10,7 +10,7 @@ from zerver.models import UserProfile
@human_users_only @human_users_only
@has_request_variables @has_request_variables
def set_tutorial_status( def set_tutorial_status(
request: HttpRequest, user_profile: UserProfile, status: str = REQ(validator=check_string) request: HttpRequest, user_profile: UserProfile, status: str = REQ(json_validator=check_string)
) -> HttpResponse: ) -> HttpResponse:
if status == "started": if status == "started":
user_profile.tutorial_status = UserProfile.TUTORIAL_STARTED user_profile.tutorial_status = UserProfile.TUTORIAL_STARTED

View File

@ -21,7 +21,7 @@ def send_notification_backend(
"type", str_validator=check_string_in(VALID_MESSAGE_TYPES), default="private" "type", str_validator=check_string_in(VALID_MESSAGE_TYPES), default="private"
), ),
operator: str = REQ("op", str_validator=check_string_in(VALID_OPERATOR_TYPES)), operator: str = REQ("op", str_validator=check_string_in(VALID_OPERATOR_TYPES)),
user_ids: List[int] = REQ("to", validator=check_list(check_int)), user_ids: List[int] = REQ("to", json_validator=check_list(check_int)),
) -> HttpResponse: ) -> HttpResponse:
if len(user_ids) == 0: if len(user_ids) == 0:
return json_error(_("Missing parameter: 'to' (recipient)")) return json_error(_("Missing parameter: 'to' (recipient)"))

View File

@ -33,7 +33,7 @@ def add_user_group(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
name: str = REQ(), name: str = REQ(),
members: Sequence[int] = REQ(validator=check_list(check_int), default=[]), members: Sequence[int] = REQ(json_validator=check_list(check_int), default=[]),
description: str = REQ(), description: str = REQ(),
) -> HttpResponse: ) -> HttpResponse:
user_profiles = user_ids_to_users(members, user_profile.realm) user_profiles = user_ids_to_users(members, user_profile.realm)
@ -53,7 +53,7 @@ def get_user_group(request: HttpRequest, user_profile: UserProfile) -> HttpRespo
def edit_user_group( def edit_user_group(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
user_group_id: int = REQ(validator=check_int, path_only=True), user_group_id: int = REQ(json_validator=check_int, path_only=True),
name: str = REQ(default=""), name: str = REQ(default=""),
description: str = REQ(default=""), description: str = REQ(default=""),
) -> HttpResponse: ) -> HttpResponse:
@ -76,7 +76,7 @@ def edit_user_group(
def delete_user_group( def delete_user_group(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
user_group_id: int = REQ(validator=check_int, path_only=True), user_group_id: int = REQ(json_validator=check_int, path_only=True),
) -> HttpResponse: ) -> HttpResponse:
check_delete_user_group(user_group_id, user_profile) check_delete_user_group(user_group_id, user_profile)
@ -88,9 +88,9 @@ def delete_user_group(
def update_user_group_backend( def update_user_group_backend(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
user_group_id: int = REQ(validator=check_int, path_only=True), user_group_id: int = REQ(json_validator=check_int, path_only=True),
delete: Sequence[int] = REQ(validator=check_list(check_int), default=[]), delete: Sequence[int] = REQ(json_validator=check_list(check_int), default=[]),
add: Sequence[int] = REQ(validator=check_list(check_int), default=[]), add: Sequence[int] = REQ(json_validator=check_list(check_int), default=[]),
) -> HttpResponse: ) -> HttpResponse:
if not add and not delete: if not add and not delete:
return json_error(_('Nothing to do. Specify at least one of "add" or "delete".')) return json_error(_('Nothing to do. Specify at least one of "add" or "delete".'))

View File

@ -188,25 +188,27 @@ default_view_options = ["recent_topics", "all_messages"]
def update_display_settings_backend( def update_display_settings_backend(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
twenty_four_hour_time: Optional[bool] = REQ(validator=check_bool, default=None), twenty_four_hour_time: Optional[bool] = REQ(json_validator=check_bool, default=None),
dense_mode: Optional[bool] = REQ(validator=check_bool, default=None), dense_mode: Optional[bool] = REQ(json_validator=check_bool, default=None),
starred_message_counts: Optional[bool] = REQ(validator=check_bool, default=None), starred_message_counts: Optional[bool] = REQ(json_validator=check_bool, default=None),
fluid_layout_width: Optional[bool] = REQ(validator=check_bool, default=None), fluid_layout_width: Optional[bool] = REQ(json_validator=check_bool, default=None),
high_contrast_mode: Optional[bool] = REQ(validator=check_bool, default=None), high_contrast_mode: Optional[bool] = REQ(json_validator=check_bool, default=None),
color_scheme: Optional[int] = REQ( color_scheme: Optional[int] = REQ(
validator=check_int_in(UserProfile.COLOR_SCHEME_CHOICES), default=None json_validator=check_int_in(UserProfile.COLOR_SCHEME_CHOICES), default=None
), ),
translate_emoticons: Optional[bool] = REQ(validator=check_bool, default=None), translate_emoticons: Optional[bool] = REQ(json_validator=check_bool, default=None),
default_language: Optional[str] = REQ(validator=check_string, default=None), default_language: Optional[str] = REQ(json_validator=check_string, default=None),
default_view: Optional[str] = REQ( default_view: Optional[str] = REQ(
validator=check_string_in(default_view_options), default=None json_validator=check_string_in(default_view_options), default=None
), ),
left_side_userlist: Optional[bool] = REQ(validator=check_bool, default=None), left_side_userlist: Optional[bool] = REQ(json_validator=check_bool, default=None),
emojiset: Optional[str] = REQ(validator=check_string_in(emojiset_choices), default=None), emojiset: Optional[str] = REQ(json_validator=check_string_in(emojiset_choices), default=None),
demote_inactive_streams: Optional[int] = REQ( demote_inactive_streams: Optional[int] = REQ(
validator=check_int_in(UserProfile.DEMOTE_STREAMS_CHOICES), default=None json_validator=check_int_in(UserProfile.DEMOTE_STREAMS_CHOICES), default=None
),
timezone: Optional[str] = REQ(
json_validator=check_string_in(pytz.all_timezones_set), default=None
), ),
timezone: Optional[str] = REQ(validator=check_string_in(pytz.all_timezones_set), default=None),
) -> HttpResponse: ) -> HttpResponse:
# We can't use REQ for this widget because # We can't use REQ for this widget because
@ -230,26 +232,38 @@ def update_display_settings_backend(
def json_change_notify_settings( def json_change_notify_settings(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
enable_stream_desktop_notifications: Optional[bool] = REQ(validator=check_bool, default=None), enable_stream_desktop_notifications: Optional[bool] = REQ(
enable_stream_email_notifications: Optional[bool] = REQ(validator=check_bool, default=None), json_validator=check_bool, default=None
enable_stream_push_notifications: Optional[bool] = REQ(validator=check_bool, default=None),
enable_stream_audible_notifications: Optional[bool] = REQ(validator=check_bool, default=None),
wildcard_mentions_notify: Optional[bool] = REQ(validator=check_bool, default=None),
notification_sound: Optional[str] = REQ(validator=check_string, default=None),
enable_desktop_notifications: Optional[bool] = REQ(validator=check_bool, default=None),
enable_sounds: Optional[bool] = REQ(validator=check_bool, default=None),
enable_offline_email_notifications: Optional[bool] = REQ(validator=check_bool, default=None),
enable_offline_push_notifications: Optional[bool] = REQ(validator=check_bool, default=None),
enable_online_push_notifications: Optional[bool] = REQ(validator=check_bool, default=None),
enable_digest_emails: Optional[bool] = REQ(validator=check_bool, default=None),
enable_login_emails: Optional[bool] = REQ(validator=check_bool, default=None),
message_content_in_email_notifications: Optional[bool] = REQ(
validator=check_bool, default=None
), ),
pm_content_in_desktop_notifications: Optional[bool] = REQ(validator=check_bool, default=None), enable_stream_email_notifications: Optional[bool] = REQ(
desktop_icon_count_display: Optional[int] = REQ(validator=check_int, default=None), json_validator=check_bool, default=None
realm_name_in_notifications: Optional[bool] = REQ(validator=check_bool, default=None), ),
presence_enabled: Optional[bool] = REQ(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(json_validator=check_string, 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),
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: ) -> HttpResponse:
result = {} result = {}
@ -326,7 +340,9 @@ def regenerate_api_key(request: HttpRequest, user_profile: UserProfile) -> HttpR
@human_users_only @human_users_only
@has_request_variables @has_request_variables
def change_enter_sends( def change_enter_sends(
request: HttpRequest, user_profile: UserProfile, enter_sends: bool = REQ(validator=check_bool) request: HttpRequest,
user_profile: UserProfile,
enter_sends: bool = REQ(json_validator=check_bool),
) -> HttpResponse: ) -> HttpResponse:
do_change_enter_sends(user_profile, enter_sends) do_change_enter_sends(user_profile, enter_sends)
return json_success() return json_success()

View File

@ -157,16 +157,16 @@ def update_user_backend(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
user_id: int, user_id: int,
full_name: Optional[str] = REQ(default=None, validator=check_string), full_name: Optional[str] = REQ(default=None, json_validator=check_string),
role: Optional[int] = REQ( role: Optional[int] = REQ(
default=None, default=None,
validator=check_int_in( json_validator=check_int_in(
UserProfile.ROLE_TYPES, UserProfile.ROLE_TYPES,
), ),
), ),
profile_data: Optional[List[Dict[str, Optional[Union[int, str, List[int]]]]]] = REQ( profile_data: Optional[List[Dict[str, Optional[Union[int, str, List[int]]]]]] = REQ(
default=None, default=None,
validator=check_profile_data, json_validator=check_profile_data,
), ),
) -> HttpResponse: ) -> HttpResponse:
target = access_user_by_id( target = access_user_by_id(
@ -260,15 +260,15 @@ def patch_bot_backend(
user_profile: UserProfile, user_profile: UserProfile,
bot_id: int, bot_id: int,
full_name: Optional[str] = REQ(default=None), full_name: Optional[str] = REQ(default=None),
bot_owner_id: Optional[int] = REQ(validator=check_int, default=None), bot_owner_id: Optional[int] = REQ(json_validator=check_int, default=None),
config_data: Optional[Dict[str, str]] = REQ( config_data: Optional[Dict[str, str]] = REQ(
default=None, validator=check_dict(value_validator=check_string) default=None, json_validator=check_dict(value_validator=check_string)
), ),
service_payload_url: Optional[str] = REQ(validator=check_url, default=None), service_payload_url: Optional[str] = REQ(json_validator=check_url, default=None),
service_interface: int = REQ(validator=check_int, default=1), service_interface: int = REQ(json_validator=check_int, default=1),
default_sending_stream: Optional[str] = REQ(default=None), default_sending_stream: Optional[str] = REQ(default=None),
default_events_register_stream: Optional[str] = REQ(default=None), default_events_register_stream: Optional[str] = REQ(default=None),
default_all_public_streams: Optional[bool] = REQ(default=None, validator=check_bool), default_all_public_streams: Optional[bool] = REQ(default=None, json_validator=check_bool),
) -> HttpResponse: ) -> HttpResponse:
bot = access_bot_by_id(user_profile, bot_id) bot = access_bot_by_id(user_profile, bot_id)
@ -363,18 +363,18 @@ def add_bot_backend(
user_profile: UserProfile, user_profile: UserProfile,
full_name_raw: str = REQ("full_name"), full_name_raw: str = REQ("full_name"),
short_name_raw: str = REQ("short_name"), short_name_raw: str = REQ("short_name"),
bot_type: int = REQ(validator=check_int, default=UserProfile.DEFAULT_BOT), bot_type: int = REQ(json_validator=check_int, default=UserProfile.DEFAULT_BOT),
payload_url: str = REQ(validator=check_url, default=""), payload_url: str = REQ(json_validator=check_url, default=""),
service_name: Optional[str] = REQ(default=None), service_name: Optional[str] = REQ(default=None),
config_data: Dict[str, str] = REQ( config_data: Dict[str, str] = REQ(
default={}, validator=check_dict(value_validator=check_string) default={}, json_validator=check_dict(value_validator=check_string)
), ),
interface_type: int = REQ(validator=check_int, default=Service.GENERIC), interface_type: int = REQ(json_validator=check_int, default=Service.GENERIC),
default_sending_stream_name: Optional[str] = REQ("default_sending_stream", default=None), default_sending_stream_name: Optional[str] = REQ("default_sending_stream", default=None),
default_events_register_stream_name: Optional[str] = REQ( default_events_register_stream_name: Optional[str] = REQ(
"default_events_register_stream", default=None "default_events_register_stream", default=None
), ),
default_all_public_streams: Optional[bool] = REQ(validator=check_bool, default=None), default_all_public_streams: Optional[bool] = REQ(json_validator=check_bool, default=None),
) -> HttpResponse: ) -> HttpResponse:
short_name = check_short_name(short_name_raw) short_name = check_short_name(short_name_raw)
if bot_type != UserProfile.INCOMING_WEBHOOK_BOT: if bot_type != UserProfile.INCOMING_WEBHOOK_BOT:
@ -522,8 +522,8 @@ def get_members_backend(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
user_id: Optional[int] = None, user_id: Optional[int] = None,
include_custom_profile_fields: bool = REQ(validator=check_bool, default=False), include_custom_profile_fields: bool = REQ(json_validator=check_bool, default=False),
client_gravatar: bool = REQ(validator=check_bool, default=False), client_gravatar: bool = REQ(json_validator=check_bool, default=False),
) -> HttpResponse: ) -> HttpResponse:
""" """
The client_gravatar field here is set to True if clients can compute The client_gravatar field here is set to True if clients can compute
@ -629,8 +629,8 @@ def get_profile_backend(request: HttpRequest, user_profile: UserProfile) -> Http
def get_subscription_backend( def get_subscription_backend(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
user_id: int = REQ(validator=check_int, path_only=True), user_id: int = REQ(json_validator=check_int, path_only=True),
stream_id: int = REQ(validator=check_int, path_only=True), stream_id: int = REQ(json_validator=check_int, path_only=True),
) -> HttpResponse: ) -> HttpResponse:
target_user = access_user_by_id(user_profile, user_id, for_admin=False) target_user = access_user_by_id(user_profile, user_id, for_admin=False)
(stream, sub) = access_stream_by_id(user_profile, stream_id) (stream, sub) = access_stream_by_id(user_profile, stream_id)
@ -645,8 +645,8 @@ def get_user_by_email(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
email: str, email: str,
include_custom_profile_fields: bool = REQ(validator=check_bool, default=False), include_custom_profile_fields: bool = REQ(json_validator=check_bool, default=False),
client_gravatar: bool = REQ(validator=check_bool, default=False), client_gravatar: bool = REQ(json_validator=check_bool, default=False),
) -> HttpResponse: ) -> HttpResponse:
realm = user_profile.realm realm = user_profile.realm

View File

@ -91,7 +91,7 @@ def register_zoom_user(request: HttpRequest) -> HttpResponse:
def complete_zoom_user( def complete_zoom_user(
request: HttpRequest, request: HttpRequest,
state: Dict[str, str] = REQ( state: Dict[str, str] = REQ(
validator=check_dict([("realm", check_string)], value_validator=check_string) json_validator=check_dict([("realm", check_string)], value_validator=check_string)
), ),
) -> HttpResponse: ) -> HttpResponse:
if get_subdomain(request) != state["realm"]: if get_subdomain(request) != state["realm"]:
@ -105,7 +105,7 @@ def complete_zoom_user_in_realm(
request: HttpRequest, request: HttpRequest,
code: str = REQ(), code: str = REQ(),
state: Dict[str, str] = REQ( state: Dict[str, str] = REQ(
validator=check_dict([("sid", check_string)], value_validator=check_string) json_validator=check_dict([("sid", check_string)], value_validator=check_string)
), ),
) -> HttpResponse: ) -> HttpResponse:
if not constant_time_compare(state["sid"], get_zoom_sid(request)): if not constant_time_compare(state["sid"], get_zoom_sid(request)):
@ -207,9 +207,9 @@ def get_bigbluebutton_url(request: HttpRequest, user_profile: UserProfile) -> Ht
@has_request_variables @has_request_variables
def join_bigbluebutton( def join_bigbluebutton(
request: HttpRequest, request: HttpRequest,
meeting_id: str = REQ(validator=check_string), meeting_id: str = REQ(json_validator=check_string),
password: str = REQ(validator=check_string), password: str = REQ(json_validator=check_string),
checksum: str = REQ(validator=check_string), checksum: str = REQ(json_validator=check_string),
) -> HttpResponse: ) -> HttpResponse:
if settings.BIG_BLUE_BUTTON_URL is None or settings.BIG_BLUE_BUTTON_SECRET is None: if settings.BIG_BLUE_BUTTON_URL is None or settings.BIG_BLUE_BUTTON_SECRET is None:
return json_error(_("Big Blue Button is not configured.")) return json_error(_("Big Blue Button is not configured."))

View File

@ -79,7 +79,7 @@ def beanstalk_decoder(view_func: ViewFuncT) -> ViewFuncT:
def api_beanstalk_webhook( def api_beanstalk_webhook(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
payload: Dict[str, Any] = REQ(validator=check_dict([])), payload: Dict[str, Any] = REQ(json_validator=check_dict([])),
branches: Optional[str] = REQ(default=None), branches: Optional[str] = REQ(default=None),
) -> HttpResponse: ) -> HttpResponse:
# Beanstalk supports both SVN and Git repositories # Beanstalk supports both SVN and Git repositories

View File

@ -16,7 +16,7 @@ from zerver.models import UserProfile
def api_bitbucket_webhook( def api_bitbucket_webhook(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
payload: Mapping[str, Any] = REQ(validator=check_dict([])), payload: Mapping[str, Any] = REQ(json_validator=check_dict([])),
branches: Optional[str] = REQ(default=None), branches: Optional[str] = REQ(default=None),
) -> HttpResponse: ) -> HttpResponse:
repository = payload["repository"] repository = payload["repository"]

View File

@ -398,7 +398,7 @@ def api_gitlab_webhook(
user_profile: UserProfile, user_profile: UserProfile,
payload: Dict[str, Any] = REQ(argument_type="body"), payload: Dict[str, Any] = REQ(argument_type="body"),
branches: Optional[str] = REQ(default=None), branches: Optional[str] = REQ(default=None),
use_merge_request_title: bool = REQ(default=True, validator=check_bool), use_merge_request_title: bool = REQ(default=True, json_validator=check_bool),
user_specified_topic: Optional[str] = REQ("topic", default=None), user_specified_topic: Optional[str] = REQ("topic", default=None),
) -> HttpResponse: ) -> HttpResponse:
event = get_event(request, payload, branches) event = get_event(request, payload, branches)

View File

@ -24,7 +24,7 @@ def api_papertrail_webhook(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
payload: Dict[str, Any] = REQ( payload: Dict[str, Any] = REQ(
validator=check_dict( json_validator=check_dict(
[ [
("events", check_list(check_dict([]))), ("events", check_list(check_dict([]))),
( (

View File

@ -20,8 +20,8 @@ def api_transifex_webhook(
project: str = REQ(), project: str = REQ(),
resource: str = REQ(), resource: str = REQ(),
language: str = REQ(), language: str = REQ(),
translated: Optional[int] = REQ(validator=check_int, default=None), translated: Optional[int] = REQ(json_validator=check_int, default=None),
reviewed: Optional[int] = REQ(validator=check_int, default=None), reviewed: Optional[int] = REQ(json_validator=check_int, default=None),
) -> HttpResponse: ) -> HttpResponse:
subject = f"{project} in {language}" subject = f"{project} in {language}"
if translated: if translated:

View File

@ -25,10 +25,10 @@ Details: [changes]({}), [build log]({})"""
def api_travis_webhook( def api_travis_webhook(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
ignore_pull_requests: bool = REQ(validator=check_bool, default=True), ignore_pull_requests: bool = REQ(json_validator=check_bool, default=True),
message: Dict[str, object] = REQ( message: Dict[str, object] = REQ(
"payload", "payload",
validator=check_dict( json_validator=check_dict(
[ [
("author_name", check_string), ("author_name", check_string),
("status_message", check_string), ("status_message", check_string),

View File

@ -109,9 +109,9 @@ def register_remote_server(
def register_remote_push_device( def register_remote_push_device(
request: HttpRequest, request: HttpRequest,
entity: Union[UserProfile, RemoteZulipServer], entity: Union[UserProfile, RemoteZulipServer],
user_id: int = REQ(validator=check_int), user_id: int = REQ(json_validator=check_int),
token: str = REQ(), token: str = REQ(),
token_kind: int = REQ(validator=check_int), token_kind: int = REQ(json_validator=check_int),
ios_app_id: Optional[str] = None, ios_app_id: Optional[str] = None,
) -> HttpResponse: ) -> HttpResponse:
server = validate_bouncer_token_request(entity, token, token_kind) server = validate_bouncer_token_request(entity, token, token_kind)
@ -138,8 +138,8 @@ def unregister_remote_push_device(
request: HttpRequest, request: HttpRequest,
entity: Union[UserProfile, RemoteZulipServer], entity: Union[UserProfile, RemoteZulipServer],
token: str = REQ(), token: str = REQ(),
token_kind: int = REQ(validator=check_int), token_kind: int = REQ(json_validator=check_int),
user_id: int = REQ(validator=check_int), user_id: int = REQ(json_validator=check_int),
ios_app_id: Optional[str] = None, ios_app_id: Optional[str] = None,
) -> HttpResponse: ) -> HttpResponse:
server = validate_bouncer_token_request(entity, token, token_kind) server = validate_bouncer_token_request(entity, token, token_kind)
@ -156,7 +156,7 @@ def unregister_remote_push_device(
def unregister_all_remote_push_devices( def unregister_all_remote_push_devices(
request: HttpRequest, request: HttpRequest,
entity: Union[UserProfile, RemoteZulipServer], entity: Union[UserProfile, RemoteZulipServer],
user_id: int = REQ(validator=check_int), user_id: int = REQ(json_validator=check_int),
) -> HttpResponse: ) -> HttpResponse:
server = validate_entity(entity) server = validate_entity(entity)
RemotePushDeviceToken.objects.filter(user_id=user_id, server=server).delete() RemotePushDeviceToken.objects.filter(user_id=user_id, server=server).delete()
@ -236,7 +236,7 @@ def remote_server_post_analytics(
request: HttpRequest, request: HttpRequest,
entity: Union[UserProfile, RemoteZulipServer], entity: Union[UserProfile, RemoteZulipServer],
realm_counts: List[Dict[str, Any]] = REQ( realm_counts: List[Dict[str, Any]] = REQ(
validator=check_list( json_validator=check_list(
check_dict_only( check_dict_only(
[ [
("property", check_string), ("property", check_string),
@ -250,7 +250,7 @@ def remote_server_post_analytics(
) )
), ),
installation_counts: List[Dict[str, Any]] = REQ( installation_counts: List[Dict[str, Any]] = REQ(
validator=check_list( json_validator=check_list(
check_dict_only( check_dict_only(
[ [
("property", check_string), ("property", check_string),
@ -263,7 +263,7 @@ def remote_server_post_analytics(
) )
), ),
realmauditlog_rows: Optional[List[Dict[str, Any]]] = REQ( realmauditlog_rows: Optional[List[Dict[str, Any]]] = REQ(
validator=check_list( json_validator=check_list(
check_dict_only( check_dict_only(
[ [
("id", check_int), ("id", check_int),