python: Migrate most json_error => JsonableError.

JsonableError has two major benefits over json_error:
* It can be raised from anywhere in the codebase, rather than
  being a return value, which is much more convenient for refactoring,
  as one doesn't potentially need to change error handling style when
  extracting a bit of view code to a function.
* It is guaranteed to contain the `code` property, which is helpful
  for API consistency.

Various stragglers are not updated because JsonableError requires
subclassing in order to specify custom data or HTTP status codes.
This commit is contained in:
PIG208 2021-07-01 00:35:50 +08:00 committed by Tim Abbott
parent 322a9b0346
commit dcbb2a78ca
50 changed files with 242 additions and 204 deletions

View File

@ -25,8 +25,8 @@ from zerver.lib.actions import (
do_scrub_realm,
do_send_realm_reactivation_email,
)
from zerver.lib.exceptions import JsonableError
from zerver.lib.realm_icon import realm_icon_url
from zerver.lib.response import json_error
from zerver.lib.subdomains import get_subdomain_from_hostname
from zerver.models import MultiuseInvite, PreregistrationUser, Realm, UserProfile, get_realm
from zerver.views.invite import get_invitee_emails_set
@ -110,7 +110,7 @@ def support(request: HttpRequest) -> HttpResponse:
if "csrfmiddlewaretoken" in keys:
keys.remove("csrfmiddlewaretoken")
if len(keys) != 2:
return json_error(_("Invalid parameters"))
raise JsonableError(_("Invalid parameters"))
realm_id = request.POST.get("realm_id")
realm = Realm.objects.get(id=realm_id)

View File

@ -47,6 +47,7 @@ from zerver.decorator import (
zulip_login_required,
)
from zerver.lib.actions import do_make_user_billing_admin
from zerver.lib.exceptions import JsonableError
from zerver.lib.request import REQ, has_request_variables
from zerver.lib.response import json_error, json_success
from zerver.lib.send_email import FromAddress, send_email
@ -372,12 +373,12 @@ def update_plan(
new_plan, last_ledger_entry = make_end_of_cycle_updates_if_needed(plan, timezone_now())
if new_plan is not None:
return json_error(
raise JsonableError(
_("Unable to update the plan. The plan has been expired and replaced with a new plan.")
)
if last_ledger_entry is None:
return json_error(_("Unable to update the plan. The plan has ended."))
raise JsonableError(_("Unable to update the plan. The plan has ended."))
if status is not None:
if status == CustomerPlan.ACTIVE:
@ -398,19 +399,19 @@ def update_plan(
if licenses is not None:
if plan.automanage_licenses:
return json_error(
raise JsonableError(
_(
"Unable to update licenses manually. Your plan is on automatic license management."
)
)
if last_ledger_entry.licenses == licenses:
return json_error(
raise JsonableError(
_(
"Your plan is already on {licenses} licenses in the current billing period."
).format(licenses=licenses)
)
if last_ledger_entry.licenses > licenses:
return json_error(
raise JsonableError(
_("You cannot decrease the licenses in the current billing period.").format(
licenses=licenses
)
@ -426,13 +427,13 @@ def update_plan(
if licenses_at_next_renewal is not None:
if plan.automanage_licenses:
return json_error(
raise JsonableError(
_(
"Unable to update licenses manually. Your plan is on automatic license management."
)
)
if last_ledger_entry.licenses_at_next_renewal == licenses_at_next_renewal:
return json_error(
raise JsonableError(
_(
"Your plan is already scheduled to renew with {licenses_at_next_renewal} licenses."
).format(licenses_at_next_renewal=licenses_at_next_renewal)
@ -450,7 +451,7 @@ def update_plan(
)
return json_success()
return json_error(_("Nothing to change."))
raise JsonableError(_("Nothing to change."))
@require_billing_access

View File

@ -452,7 +452,7 @@ def human_users_only(view_func: ViewFuncT) -> ViewFuncT:
@wraps(view_func)
def _wrapped_view_func(request: HttpRequest, *args: object, **kwargs: object) -> HttpResponse:
if request.user.is_bot:
return json_error(_("This endpoint does not accept bot requests."))
raise JsonableError(_("This endpoint does not accept bot requests."))
return view_func(request, *args, **kwargs)
return cast(ViewFuncT, _wrapped_view_func) # https://github.com/python/mypy/issues/1927
@ -549,7 +549,7 @@ def require_member_or_admin(view_func: ViewFuncT) -> ViewFuncT:
if user_profile.is_guest:
raise JsonableError(_("Not allowed for guest users"))
if user_profile.is_bot:
return json_error(_("This endpoint does not accept bot requests."))
raise JsonableError(_("This endpoint does not accept bot requests."))
return view_func(request, user_profile, *args, **kwargs)
return cast(ViewFuncT, _wrapped_view_func) # https://github.com/python/mypy/issues/1927
@ -624,7 +624,7 @@ def authenticated_rest_api_view(
auth_type, credentials = request.META["HTTP_AUTHORIZATION"].split()
# case insensitive per RFC 1945
if auth_type.lower() != "basic":
return json_error(_("This endpoint requires HTTP basic authentication."))
raise JsonableError(_("This endpoint requires HTTP basic authentication."))
role, api_key = base64.b64decode(credentials).decode("utf-8").split(":")
except ValueError:
return json_unauthorized(_("Invalid authorization header for basic auth"))

View File

@ -9,7 +9,8 @@ from django.utils.translation import gettext as _
from zerver.filters import clean_data_from_query_parameters
from zerver.lib.actions import internal_send_stream_message
from zerver.lib.response import json_error, json_success
from zerver.lib.exceptions import JsonableError
from zerver.lib.response import json_success
from zerver.models import get_stream, get_system_bot
@ -199,5 +200,5 @@ def do_report_error(type: str, report: Dict[str, Any]) -> HttpResponse:
elif type == "server":
notify_server_error(report)
else:
return json_error(_("Invalid type parameter"))
raise JsonableError(_("Invalid type parameter"))
return json_success()

View File

@ -220,6 +220,7 @@ class TestIntegrationsDevPanel(ZulipTestCase):
"message": {
"msg": "Unknown WordPress webhook action: WordPress action",
"result": "error",
"code": "BAD_REQUEST",
},
"fixture_name": "user_register.txt",
"status_code": 400,
@ -228,6 +229,7 @@ class TestIntegrationsDevPanel(ZulipTestCase):
"message": {
"msg": "Unknown WordPress webhook action: WordPress action",
"result": "error",
"code": "BAD_REQUEST",
},
"fixture_name": "publish_post_no_data_provided.txt",
"status_code": 400,
@ -236,6 +238,7 @@ class TestIntegrationsDevPanel(ZulipTestCase):
"message": {
"msg": "Unknown WordPress webhook action: WordPress action",
"result": "error",
"code": "BAD_REQUEST",
},
"fixture_name": "unknown_action_no_data.txt",
"status_code": 400,
@ -244,6 +247,7 @@ class TestIntegrationsDevPanel(ZulipTestCase):
"message": {
"msg": "Unknown WordPress webhook action: WordPress action",
"result": "error",
"code": "BAD_REQUEST",
},
"fixture_name": "publish_page.txt",
"status_code": 400,
@ -252,6 +256,7 @@ class TestIntegrationsDevPanel(ZulipTestCase):
"message": {
"msg": "Unknown WordPress webhook action: WordPress action",
"result": "error",
"code": "BAD_REQUEST",
},
"fixture_name": "unknown_action_no_hook_provided.txt",
"status_code": 400,
@ -260,6 +265,7 @@ class TestIntegrationsDevPanel(ZulipTestCase):
"message": {
"msg": "Unknown WordPress webhook action: WordPress action",
"result": "error",
"code": "BAD_REQUEST",
},
"fixture_name": "publish_post_type_not_provided.txt",
"status_code": 400,
@ -268,6 +274,7 @@ class TestIntegrationsDevPanel(ZulipTestCase):
"message": {
"msg": "Unknown WordPress webhook action: WordPress action",
"result": "error",
"code": "BAD_REQUEST",
},
"fixture_name": "wp_login.txt",
"status_code": 400,
@ -276,6 +283,7 @@ class TestIntegrationsDevPanel(ZulipTestCase):
"message": {
"msg": "Unknown WordPress webhook action: WordPress action",
"result": "error",
"code": "BAD_REQUEST",
},
"fixture_name": "publish_post.txt",
"status_code": 400,

View File

@ -184,8 +184,9 @@ class RealmExportTest(ZulipTestCase):
)
RealmAuditLog.objects.bulk_create(exports)
result = export_realm(self.client_post, admin)
self.assert_json_error(result, "Exceeded rate limit.")
with self.assertRaises(JsonableError) as error:
export_realm(self.client_post, admin)
self.assertEqual(str(error.exception), "Exceeded rate limit.")
def test_upload_and_message_limit(self) -> None:
admin = self.example_user("iago")

View File

@ -6,7 +6,8 @@ from django.http import HttpRequest, HttpResponse
from django.utils.translation import gettext as _
from zerver.decorator import REQ, has_request_variables, internal_notify_view, process_client
from zerver.lib.response import json_error, json_success
from zerver.lib.exceptions import JsonableError
from zerver.lib.response import json_success
from zerver.lib.validator import (
check_bool,
check_int,
@ -34,7 +35,7 @@ def cleanup_event_queue(
if client is None:
raise BadEventQueueIdError(queue_id)
if user_profile.id != client.user_profile_id:
return json_error(_("You are not authorized to access this queue"))
raise JsonableError(_("You are not authorized to access this queue"))
request._log_data["extra"] = f"[{queue_id}]"
client.cleanup()
return json_success()
@ -102,7 +103,7 @@ def get_events_backend(
),
) -> HttpResponse:
if all_public_streams and not user_profile.can_access_public_streams():
return json_error(_("User not authorized for this query"))
raise JsonableError(_("User not authorized for this query"))
# Extract the Tornado handler from the request
handler: AsyncDjangoHandler = request._tornado_handler

View File

@ -822,7 +822,7 @@ def api_fetch_api_key(
realm = get_realm_from_request(request)
if realm is None:
return json_error(_("Invalid subdomain"))
raise JsonableError(_("Invalid subdomain"))
if not ldap_auth_enabled(realm=realm):
# In case we don't authenticate against LDAP, check for a valid
@ -945,12 +945,12 @@ def json_fetch_api_key(
) -> HttpResponse:
realm = get_realm_from_request(request)
if realm is None:
return json_error(_("Invalid subdomain"))
raise JsonableError(_("Invalid subdomain"))
if password_auth_enabled(user_profile.realm):
if not authenticate(
request=request, username=user_profile.delivery_email, password=password, realm=realm
):
return json_error(_("Your username or password is incorrect."))
raise JsonableError(_("Your username or password is incorrect."))
api_key = get_api_key(user_profile)
return json_success({"api_key": api_key, "email": user_profile.delivery_email})

View File

@ -2,7 +2,8 @@ from django.http import HttpRequest, HttpResponse
from django.utils.translation import gettext as _
from zerver.lib.compatibility import find_mobile_os, version_lt
from zerver.lib.response import json_error, json_success
from zerver.lib.exceptions import JsonableError
from zerver.lib.response import json_success
from zerver.lib.user_agent import parse_user_agent
# Zulip Mobile release 16.2.96 was made 2018-08-22. It fixed a
@ -14,16 +15,16 @@ android_min_app_version = "16.2.96"
def check_global_compatibility(request: HttpRequest) -> HttpResponse:
if request.META.get("HTTP_USER_AGENT") is None:
return json_error(_("User-Agent header missing from request"))
raise JsonableError(_("User-Agent header missing from request"))
# This string should not be tagged for translation, since old
# clients are checking for an extra string.
legacy_compatibility_error_message = "Client is too old"
user_agent = parse_user_agent(request.META["HTTP_USER_AGENT"])
if user_agent["name"] == "ZulipInvalid":
return json_error(legacy_compatibility_error_message)
raise JsonableError(legacy_compatibility_error_message)
if user_agent["name"] == "ZulipMobile":
user_os = find_mobile_os(request.META["HTTP_USER_AGENT"])
if user_os == "android" and version_lt(user_agent["version"], android_min_app_version):
return json_error(legacy_compatibility_error_message)
raise JsonableError(legacy_compatibility_error_message)
return json_success()

View File

@ -19,7 +19,7 @@ from zerver.lib.actions import (
from zerver.lib.exceptions import JsonableError
from zerver.lib.external_accounts import validate_external_account_field_data
from zerver.lib.request import REQ, has_request_variables
from zerver.lib.response import json_error, json_success
from zerver.lib.response import json_success
from zerver.lib.types import ProfileFieldData
from zerver.lib.users import validate_user_custom_profile_data
from zerver.lib.validator import (
@ -124,7 +124,7 @@ def create_realm_custom_profile_field(
)
return json_success({"id": field.id})
except IntegrityError:
return json_error(_("A field with that label already exists."))
raise JsonableError(_("A field with that label already exists."))
@require_realm_admin
@ -134,7 +134,7 @@ def delete_realm_custom_profile_field(
try:
field = CustomProfileField.objects.get(id=field_id)
except CustomProfileField.DoesNotExist:
return json_error(_("Field id {id} not found.").format(id=field_id))
raise JsonableError(_("Field id {id} not found.").format(id=field_id))
do_remove_realm_custom_profile_field(realm=user_profile.realm, field=field)
return json_success()
@ -154,17 +154,17 @@ def update_realm_custom_profile_field(
try:
field = CustomProfileField.objects.get(realm=realm, id=field_id)
except CustomProfileField.DoesNotExist:
return json_error(_("Field id {id} not found.").format(id=field_id))
raise JsonableError(_("Field id {id} not found.").format(id=field_id))
if field.field_type == CustomProfileField.EXTERNAL_ACCOUNT:
if is_default_external_field(field.field_type, orjson.loads(field.field_data)):
return json_error(_("Default custom field cannot be updated."))
raise JsonableError(_("Default custom field cannot be updated."))
validate_custom_profile_field(name, hint, field.field_type, field_data)
try:
try_update_realm_custom_profile_field(realm, field, name, hint=hint, field_data=field_data)
except IntegrityError:
return json_error(_("A field with that label already exists."))
raise JsonableError(_("A field with that label already exists."))
return json_success()

View File

@ -103,7 +103,7 @@ def api_dev_fetch_api_key(request: HttpRequest, username: str = REQ()) -> HttpRe
validate_login_email(username)
realm = get_realm_from_request(request)
if realm is None:
return json_error(_("Invalid subdomain"))
raise JsonableError(_("Invalid subdomain"))
return_data: Dict[str, bool] = {}
user_profile = authenticate(dev_auth_username=username, realm=realm, return_data=return_data)
if return_data.get("inactive_realm"):

View File

@ -6,6 +6,7 @@ from django.http import HttpRequest, HttpResponse
from django.shortcuts import render
from django.test import Client
from zerver.lib.exceptions import JsonableError
from zerver.lib.integrations import WEBHOOK_INTEGRATIONS
from zerver.lib.request import REQ, has_request_variables
from zerver.lib.response import json_error, json_success
@ -104,7 +105,7 @@ def check_send_webhook_fixture_message(
try:
custom_headers_dict = orjson.loads(custom_headers)
except orjson.JSONDecodeError as ve:
return json_error(f"Custom HTTP headers are not in a valid JSON format. {ve}") # nolint
raise JsonableError(f"Custom HTTP headers are not in a valid JSON format. {ve}") # nolint
response = send_webhook_fixture_message(url, body, is_json, custom_headers_dict)
if response.status_code == 200:

View File

@ -2,8 +2,9 @@ from django.http import HttpRequest, HttpResponse
from zerver.decorator import internal_notify_view
from zerver.lib.email_mirror import mirror_email_message
from zerver.lib.exceptions import JsonableError
from zerver.lib.request import REQ, has_request_variables
from zerver.lib.response import json_error, json_success
from zerver.lib.response import json_success
@internal_notify_view(False)
@ -15,5 +16,5 @@ def email_mirror_message(
) -> HttpResponse:
result = mirror_email_message(rcpt_to, msg_base64)
if result["status"] == "error":
return json_error(result["msg"])
raise JsonableError(result["msg"])
return json_success()

View File

@ -4,8 +4,9 @@ from django.http import HttpRequest, HttpResponse
from django.utils.translation import gettext as _
from zerver.lib.events import do_events_register
from zerver.lib.exceptions import JsonableError
from zerver.lib.request import REQ, has_request_variables
from zerver.lib.response import json_error, json_success
from zerver.lib.response import json_success
from zerver.lib.validator import check_bool, check_dict, check_list, check_string
from zerver.models import Stream, UserProfile
@ -70,7 +71,7 @@ def events_register_backend(
queue_lifespan_secs: int = REQ(converter=int, default=0, documentation_pending=True),
) -> HttpResponse:
if all_public_streams and not user_profile.can_access_public_streams():
return json_error(_("User not authorized for this query"))
raise JsonableError(_("User not authorized for this query"))
all_public_streams = _default_all_public_streams(user_profile, all_public_streams)
narrow = _default_narrow(user_profile, narrow)

View File

@ -3,9 +3,10 @@ from django.utils.translation import gettext as _
from zerver.decorator import human_users_only
from zerver.lib.actions import do_mark_hotspot_as_read
from zerver.lib.exceptions import JsonableError
from zerver.lib.hotspots import ALL_HOTSPOTS
from zerver.lib.request import REQ, has_request_variables
from zerver.lib.response import json_error, json_success
from zerver.lib.response import json_success
from zerver.models import UserProfile
@ -15,6 +16,6 @@ def mark_hotspot_as_read(
request: HttpRequest, user: UserProfile, hotspot: str = REQ()
) -> HttpResponse:
if hotspot not in ALL_HOTSPOTS:
return json_error(_("Unknown hotspot: {}").format(hotspot))
raise JsonableError(_("Unknown hotspot: {}").format(hotspot))
do_mark_hotspot_as_read(user, hotspot)
return json_success()

View File

@ -15,7 +15,7 @@ from zerver.lib.actions import (
)
from zerver.lib.exceptions import OrganizationOwnerRequired
from zerver.lib.request import REQ, JsonableError, has_request_variables
from zerver.lib.response import json_error, json_success
from zerver.lib.response import json_success
from zerver.lib.streams import access_stream_by_id
from zerver.lib.validator import check_int, check_list
from zerver.models import MultiuseInvite, PreregistrationUser, Stream, UserProfile
@ -44,7 +44,7 @@ def invite_users_backend(
# be handled by the decorator above.
raise JsonableError(_("Insufficient permission"))
if invite_as not in PreregistrationUser.INVITE_AS.values():
return json_error(_("Must be invited as an valid type of user"))
raise JsonableError(_("Must be invited as an valid type of user"))
check_if_owner_required(invite_as, user_profile)
if (
invite_as
@ -54,11 +54,11 @@ def invite_users_backend(
]
and not user_profile.is_realm_admin
):
return json_error(_("Must be an organization administrator"))
raise JsonableError(_("Must be an organization administrator"))
if not invitee_emails_raw:
return json_error(_("You must specify at least one email address."))
raise JsonableError(_("You must specify at least one email address."))
if not stream_ids:
return json_error(_("You must specify at least one stream for invitees to join."))
raise JsonableError(_("You must specify at least one stream for invitees to join."))
invitee_emails = get_invitee_emails_set(invitee_emails_raw)
@ -67,7 +67,7 @@ def invite_users_backend(
try:
(stream, sub) = access_stream_by_id(user_profile, stream_id)
except JsonableError:
return json_error(
raise JsonableError(
_("Stream does not exist with id: {}. No invites were sent.").format(stream_id)
)
streams.append(stream)
@ -174,7 +174,7 @@ def generate_multiuse_invite_backend(
try:
(stream, sub) = access_stream_by_id(user_profile, stream_id)
except JsonableError:
return json_error(_("Invalid stream id {}. No invites were sent.").format(stream_id))
raise JsonableError(_("Invalid stream id {}. No invites were sent.").format(stream_id))
streams.append(stream)
invite_link = do_create_multiuse_invite_link(user_profile, invite_as, streams)

View File

@ -12,7 +12,7 @@ from zerver.lib.actions import check_update_message, do_delete_messages
from zerver.lib.exceptions import JsonableError
from zerver.lib.html_diff import highlight_html_differences
from zerver.lib.message import access_message
from zerver.lib.response import json_error, json_success
from zerver.lib.response import json_success
from zerver.lib.timestamp import datetime_to_timestamp
from zerver.lib.topic import LEGACY_PREV_TOPIC, REQ_topic
from zerver.lib.validator import check_bool, check_string_in, to_non_negative_int
@ -74,7 +74,7 @@ def get_message_edit_history(
message_id: int = REQ(converter=to_non_negative_int, path_only=True),
) -> HttpResponse:
if not user_profile.realm.allow_edit_history:
return json_error(_("Message edit history is disabled in this organization"))
raise JsonableError(_("Message edit history is disabled in this organization"))
message, ignored_user_message = access_message(user_profile, message_id)
# Extract the message edit history from the message

View File

@ -38,7 +38,7 @@ from zerver.lib.addressee import get_user_profiles, get_user_profiles_by_ids
from zerver.lib.exceptions import ErrorCode, JsonableError, MissingAuthenticationError
from zerver.lib.message import get_first_visible_message_id, messages_for_ids
from zerver.lib.narrow import is_web_public_compatible, is_web_public_narrow
from zerver.lib.response import json_error, json_success
from zerver.lib.response import json_success
from zerver.lib.sqlalchemy_utils import get_sqlalchemy_connection
from zerver.lib.streams import (
can_access_stream_history_by_id,
@ -946,7 +946,7 @@ def get_messages_backend(
) -> HttpResponse:
anchor = parse_anchor_value(anchor_val, use_first_unread_anchor_val)
if num_before + num_after > MAX_MESSAGES_PER_FETCH:
return json_error(
raise JsonableError(
_("Too many messages requested (maximum {}).").format(
MAX_MESSAGES_PER_FETCH,
)

View File

@ -18,8 +18,9 @@ from zerver.lib.actions import (
extract_private_recipients,
extract_stream_indicator,
)
from zerver.lib.exceptions import JsonableError
from zerver.lib.message import render_markdown
from zerver.lib.response import json_error, json_success
from zerver.lib.response import json_success
from zerver.lib.timestamp import convert_to_UTC
from zerver.lib.topic import REQ_topic
from zerver.lib.zcommand import process_zcommands
@ -151,7 +152,7 @@ def handle_deferred_message(
try:
deliver_at = dateparser(defer_until)
except ValueError:
return json_error(_("Invalid time format"))
raise JsonableError(_("Invalid time format"))
deliver_at_usertz = deliver_at
if deliver_at_usertz.tzinfo is None:
@ -160,7 +161,7 @@ def handle_deferred_message(
deliver_at = convert_to_UTC(deliver_at_usertz)
if deliver_at <= timezone_now():
return json_error(_("Time must be in the future."))
raise JsonableError(_("Time must be in the future."))
check_schedule_message(
sender,
@ -223,13 +224,13 @@ def send_message_backend(
client = request.client
can_forge_sender = request.user.can_forge_sender
if forged and not can_forge_sender:
return json_error(_("User not authorized for this query"))
raise JsonableError(_("User not authorized for this query"))
realm = None
if realm_str and realm_str != user_profile.realm.string_id:
# The realm_str parameter does nothing, because it has to match
# the user's realm - but we keep it around for backward compatibility.
return json_error(_("User not authorized for this query"))
raise JsonableError(_("User not authorized for this query"))
if client.name in ["zephyr_mirror", "irc_mirror", "jabber_mirror", "JabberMirror"]:
# Here's how security works for mirroring:
@ -246,14 +247,14 @@ def send_message_backend(
# `create_mirrored_message_users` below, which checks the
# same-realm constraint.
if "sender" not in request.POST:
return json_error(_("Missing sender"))
raise JsonableError(_("Missing sender"))
if message_type_name != "private" and not can_forge_sender:
return json_error(_("User not authorized for this query"))
raise JsonableError(_("User not authorized for this query"))
# For now, mirroring only works with recipient emails, not for
# recipient user IDs.
if not all(isinstance(to_item, str) for to_item in message_to):
return json_error(_("Mirroring not allowed with recipient user IDs"))
raise JsonableError(_("Mirroring not allowed with recipient user IDs"))
# We need this manual cast so that mypy doesn't complain about
# create_mirrored_message_users not being able to accept a Sequence[int]
@ -263,18 +264,18 @@ def send_message_backend(
try:
mirror_sender = create_mirrored_message_users(request, user_profile, message_to)
except InvalidMirrorInput:
return json_error(_("Invalid mirrored message"))
raise JsonableError(_("Invalid mirrored message"))
if client.name == "zephyr_mirror" and not user_profile.realm.is_zephyr_mirror_realm:
return json_error(_("Zephyr mirroring is not allowed in this organization"))
raise JsonableError(_("Zephyr mirroring is not allowed in this organization"))
sender = mirror_sender
else:
if "sender" in request.POST:
return json_error(_("Invalid mirrored message"))
raise JsonableError(_("Invalid mirrored message"))
sender = user_profile
if (delivery_type == "send_later" or delivery_type == "remind") and defer_until is None:
return json_error(_("Missing deliver_at in a request for delayed message delivery"))
raise JsonableError(_("Missing deliver_at in a request for delayed message delivery"))
if (delivery_type == "send_later" or delivery_type == "remind") and defer_until is not None:
return handle_deferred_message(

View File

@ -6,8 +6,9 @@ from django.utils.timezone import now as timezone_now
from django.utils.translation import gettext as _
from zerver.lib.actions import do_mute_topic, do_mute_user, do_unmute_topic, do_unmute_user
from zerver.lib.exceptions import JsonableError
from zerver.lib.request import REQ, has_request_variables
from zerver.lib.response import json_error, json_success
from zerver.lib.response import json_success
from zerver.lib.streams import (
access_stream_by_id,
access_stream_by_name,
@ -36,7 +37,7 @@ def mute_topic(
(stream, sub) = access_stream_by_id(user_profile, stream_id)
if topic_is_muted(user_profile, stream.id, topic_name):
return json_error(_("Topic already muted"))
raise JsonableError(_("Topic already muted"))
do_mute_topic(user_profile, stream, topic_name, date_muted)
return json_success()
@ -54,7 +55,7 @@ def unmute_topic(
stream = access_stream_for_unmute_topic_by_id(user_profile, stream_id, error)
if not topic_is_muted(user_profile, stream.id, topic_name):
return json_error(error)
raise JsonableError(error)
do_unmute_topic(user_profile, stream, topic_name)
return json_success()
@ -91,13 +92,13 @@ def update_muted_topic(
def mute_user(request: HttpRequest, user_profile: UserProfile, muted_user_id: int) -> HttpResponse:
if user_profile.id == muted_user_id:
return json_error(_("Cannot mute self"))
raise JsonableError(_("Cannot mute self"))
muted_user = access_user_by_id(user_profile, muted_user_id, allow_bots=False, for_admin=False)
date_muted = timezone_now()
if get_mute_object(user_profile, muted_user) is not None:
return json_error(_("User already muted"))
raise JsonableError(_("User already muted"))
do_mute_user(user_profile, muted_user, date_muted)
return json_success()
@ -110,7 +111,7 @@ def unmute_user(
mute_object = get_mute_object(user_profile, muted_user)
if mute_object is None:
return json_error(_("User is not muted"))
raise JsonableError(_("User is not muted"))
do_unmute_user(mute_object)
return json_success()

View File

@ -10,7 +10,7 @@ from zerver.decorator import human_users_only
from zerver.lib.actions import do_update_user_status, update_user_presence
from zerver.lib.presence import get_presence_for_user, get_presence_response
from zerver.lib.request import REQ, JsonableError, has_request_variables
from zerver.lib.response import json_error, json_success
from zerver.lib.response import json_success
from zerver.lib.timestamp import datetime_to_timestamp
from zerver.lib.validator import check_bool, check_capped_string
from zerver.models import (
@ -37,14 +37,14 @@ def get_presence_backend(
email = user_id_or_email
target = get_active_user(email, user_profile.realm)
except UserProfile.DoesNotExist:
return json_error(_("No such user"))
raise JsonableError(_("No such user"))
if target.is_bot:
return json_error(_("Presence is not supported for bot users."))
raise JsonableError(_("Presence is not supported for bot users."))
presence_dict = get_presence_for_user(target.id)
if len(presence_dict) == 0:
return json_error(
raise JsonableError(
_("No presence data for {user_id_or_email}").format(user_id_or_email=user_id_or_email)
)
@ -73,7 +73,7 @@ def update_user_status_backend(
status_text = status_text.strip()
if (away is None) and (status_text is None):
return json_error(_("Client did not pass any new values."))
raise JsonableError(_("Client did not pass any new values."))
do_update_user_status(
user_profile=user_profile,

View File

@ -21,7 +21,7 @@ from zerver.lib.actions import (
from zerver.lib.exceptions import OrganizationOwnerRequired
from zerver.lib.i18n import get_available_language_codes
from zerver.lib.request import REQ, JsonableError, has_request_variables
from zerver.lib.response import json_error, json_success
from zerver.lib.response import json_success
from zerver.lib.retention import parse_message_retention_days
from zerver.lib.streams import access_stream_by_id
from zerver.lib.validator import (
@ -131,15 +131,15 @@ def update_realm(
if not user_profile.is_realm_owner:
raise OrganizationOwnerRequired()
if True not in list(authentication_methods.values()):
return json_error(_("At least one authentication method must be enabled."))
raise JsonableError(_("At least one authentication method must be enabled."))
if video_chat_provider is not None and video_chat_provider not in {
p["id"] for p in Realm.VIDEO_CHAT_PROVIDERS.values()
}:
return json_error(_("Invalid video_chat_provider {}").format(video_chat_provider))
raise JsonableError(_("Invalid video_chat_provider {}").format(video_chat_provider))
if giphy_rating is not None and giphy_rating not in {
p["id"] for p in Realm.GIPHY_RATING_OPTIONS.values()
}:
return json_error(_("Invalid giphy_rating {}").format(giphy_rating))
raise JsonableError(_("Invalid giphy_rating {}").format(giphy_rating))
message_retention_days: Optional[int] = None
if message_retention_days_raw is not None:

View File

@ -5,8 +5,9 @@ from django.utils.translation import gettext as _
from zerver.decorator import require_realm_admin
from zerver.lib.actions import do_add_realm_domain, do_change_realm_domain, do_remove_realm_domain
from zerver.lib.domains import validate_domain
from zerver.lib.exceptions import JsonableError
from zerver.lib.request import REQ, has_request_variables
from zerver.lib.response import json_error, json_success
from zerver.lib.response import json_success
from zerver.lib.validator import check_bool
from zerver.models import RealmDomain, UserProfile, get_realm_domains
@ -28,9 +29,9 @@ def create_realm_domain(
try:
validate_domain(domain)
except ValidationError as e:
return json_error(_("Invalid domain: {}").format(e.messages[0]))
raise JsonableError(_("Invalid domain: {}").format(e.messages[0]))
if RealmDomain.objects.filter(realm=user_profile.realm, domain=domain).exists():
return json_error(
raise JsonableError(
_("The domain {domain} is already a part of your organization.").format(domain=domain)
)
realm_domain = do_add_realm_domain(user_profile.realm, domain, allow_subdomains)
@ -49,7 +50,7 @@ def patch_realm_domain(
realm_domain = RealmDomain.objects.get(realm=user_profile.realm, domain=domain)
do_change_realm_domain(realm_domain, allow_subdomains)
except RealmDomain.DoesNotExist:
return json_error(_("No entry found for domain {domain}.").format(domain=domain))
raise JsonableError(_("No entry found for domain {domain}.").format(domain=domain))
return json_success()
@ -62,5 +63,5 @@ def delete_realm_domain(
realm_domain = RealmDomain.objects.get(realm=user_profile.realm, domain=domain)
do_remove_realm_domain(realm_domain, acting_user=user_profile)
except RealmDomain.DoesNotExist:
return json_error(_("No entry found for domain {domain}.").format(domain=domain))
raise JsonableError(_("No entry found for domain {domain}.").format(domain=domain))
return json_success()

View File

@ -6,7 +6,7 @@ from zerver.decorator import require_member_or_admin
from zerver.lib.actions import check_add_realm_emoji, do_remove_realm_emoji
from zerver.lib.emoji import check_emoji_admin, check_valid_emoji_name
from zerver.lib.request import REQ, JsonableError, has_request_variables
from zerver.lib.response import json_error, json_success
from zerver.lib.response import json_success
from zerver.models import RealmEmoji, UserProfile
@ -28,12 +28,12 @@ def upload_emoji(
if RealmEmoji.objects.filter(
realm=user_profile.realm, name=emoji_name, deactivated=False
).exists():
return json_error(_("A custom emoji with this name already exists."))
raise JsonableError(_("A custom emoji with this name already exists."))
if len(request.FILES) != 1:
return json_error(_("You must upload exactly one file."))
raise JsonableError(_("You must upload exactly one file."))
emoji_file = list(request.FILES.values())[0]
if (settings.MAX_EMOJI_FILE_SIZE_MIB * 1024 * 1024) < emoji_file.size:
return json_error(
raise JsonableError(
_("Uploaded file is larger than the allowed limit of {} MiB").format(
settings.MAX_EMOJI_FILE_SIZE_MIB,
)
@ -41,7 +41,7 @@ def upload_emoji(
realm_emoji = check_add_realm_emoji(user_profile.realm, emoji_name, user_profile, emoji_file)
if realm_emoji is None:
return json_error(_("Image file upload failed."))
raise JsonableError(_("Image file upload failed."))
return json_success()

View File

@ -9,9 +9,10 @@ from django.utils.translation import gettext as _
from analytics.models import RealmCount
from zerver.decorator import require_realm_admin
from zerver.lib.actions import do_delete_realm_export, notify_realm_export
from zerver.lib.exceptions import JsonableError
from zerver.lib.export import get_realm_exports_serialized
from zerver.lib.queue import queue_json_publish
from zerver.lib.response import json_error, json_success
from zerver.lib.response import json_success
from zerver.models import RealmAuditLog, UserProfile
@ -36,7 +37,7 @@ def export_realm(request: HttpRequest, user: UserProfile) -> HttpResponse:
realm=realm, event_type=event_type, event_time__gte=event_time_delta
)
if len(limit_check) >= EXPORT_LIMIT:
return json_error(_("Exceeded rate limit."))
raise JsonableError(_("Exceeded rate limit."))
total_messages = sum(
realm_count.value
@ -48,7 +49,7 @@ def export_realm(request: HttpRequest, user: UserProfile) -> HttpResponse:
total_messages > MAX_MESSAGE_HISTORY
or user.realm.currently_used_upload_space_bytes() > MAX_UPLOAD_QUOTA
):
return json_error(
raise JsonableError(
_("Please request a manual export from {email}.").format(
email=settings.ZULIP_ADMINISTRATOR,
)
@ -87,10 +88,10 @@ def delete_realm_export(request: HttpRequest, user: UserProfile, export_id: int)
id=export_id, realm=user.realm, event_type=RealmAuditLog.REALM_EXPORTED
)
except RealmAuditLog.DoesNotExist:
return json_error(_("Invalid data export ID"))
raise JsonableError(_("Invalid data export ID"))
export_data = orjson.loads(audit_log_entry.extra_data)
if "deleted_timestamp" in export_data:
return json_error(_("Export already deleted"))
raise JsonableError(_("Export already deleted"))
do_delete_realm_export(user, audit_log_entry)
return json_success()

View File

@ -5,8 +5,9 @@ from django.utils.translation import gettext as _
from zerver.decorator import require_realm_admin
from zerver.lib.actions import do_change_icon_source
from zerver.lib.exceptions import JsonableError
from zerver.lib.realm_icon import realm_icon_url
from zerver.lib.response import json_error, json_success
from zerver.lib.response import json_success
from zerver.lib.upload import upload_icon_image
from zerver.lib.url_encoding import add_query_arg_to_redirect_url
from zerver.models import UserProfile
@ -16,11 +17,11 @@ from zerver.models import UserProfile
def upload_icon(request: HttpRequest, user_profile: UserProfile) -> HttpResponse:
if len(request.FILES) != 1:
return json_error(_("You must upload exactly one icon."))
raise JsonableError(_("You must upload exactly one icon."))
icon_file = list(request.FILES.values())[0]
if (settings.MAX_ICON_FILE_SIZE_MIB * 1024 * 1024) < icon_file.size:
return json_error(
raise JsonableError(
_("Uploaded file is larger than the allowed limit of {} MiB").format(
settings.MAX_ICON_FILE_SIZE_MIB,
)

View File

@ -4,6 +4,7 @@ from django.utils.translation import gettext as _
from zerver.decorator import require_realm_admin
from zerver.lib.actions import do_add_linkifier, do_remove_linkifier, do_update_linkifier
from zerver.lib.exceptions import JsonableError
from zerver.lib.request import REQ, has_request_variables
from zerver.lib.response import json_error, json_success
from zerver.models import RealmFilter, UserProfile, linkifiers_for_realm
@ -41,7 +42,7 @@ def delete_linkifier(
try:
do_remove_linkifier(realm=user_profile.realm, id=filter_id)
except RealmFilter.DoesNotExist:
return json_error(_("Linkifier not found."))
raise JsonableError(_("Linkifier not found."))
return json_success()
@ -63,6 +64,6 @@ def update_linkifier(
)
return json_success()
except RealmFilter.DoesNotExist:
return json_error(_("Linkifier not found."))
raise JsonableError(_("Linkifier not found."))
except ValidationError as e:
return json_error(e.messages[0], data={"errors": dict(e)})

View File

@ -5,9 +5,10 @@ from django.utils.translation import gettext as _
from zerver.decorator import require_realm_admin
from zerver.lib.actions import do_change_logo_source
from zerver.lib.exceptions import JsonableError
from zerver.lib.realm_logo import get_realm_logo_url
from zerver.lib.request import REQ, has_request_variables
from zerver.lib.response import json_error, json_success
from zerver.lib.response import json_success
from zerver.lib.upload import upload_logo_image
from zerver.lib.url_encoding import add_query_arg_to_redirect_url
from zerver.lib.validator import check_bool
@ -22,10 +23,10 @@ def upload_logo(
user_profile.realm.ensure_not_on_limited_plan()
if len(request.FILES) != 1:
return json_error(_("You must upload exactly one logo."))
raise JsonableError(_("You must upload exactly one logo."))
logo_file = list(request.FILES.values())[0]
if (settings.MAX_LOGO_FILE_SIZE_MIB * 1024 * 1024) < logo_file.size:
return json_error(
raise JsonableError(
_("Uploaded file is larger than the allowed limit of {} MiB").format(
settings.MAX_LOGO_FILE_SIZE_MIB,
)

View File

@ -10,7 +10,8 @@ from zerver.lib.bot_storage import (
remove_bot_storage,
set_bot_storage,
)
from zerver.lib.response import json_error, json_success
from zerver.lib.exceptions import JsonableError
from zerver.lib.response import json_success
from zerver.lib.validator import check_dict, check_list, check_string
from zerver.models import UserProfile
@ -24,7 +25,7 @@ def update_storage(
try:
set_bot_storage(user_profile, list(storage.items()))
except StateError as e: # nocoverage
return json_error(str(e))
raise JsonableError(str(e))
return json_success()
@ -39,7 +40,7 @@ def get_storage(
try:
storage = {key: get_bot_storage(user_profile, key) for key in keys}
except StateError as e:
return json_error(str(e))
raise JsonableError(str(e))
return json_success({"storage": storage})
@ -54,5 +55,5 @@ def remove_storage(
try:
remove_bot_storage(user_profile, keys)
except StateError as e:
return json_error(str(e))
raise JsonableError(str(e))
return json_success()

View File

@ -148,7 +148,7 @@ def add_default_stream(
) -> HttpResponse:
(stream, sub) = access_stream_by_id(user_profile, stream_id)
if stream.invite_only:
return json_error(_("Private streams cannot be made default."))
raise JsonableError(_("Private streams cannot be made default."))
do_add_default_stream(stream)
return json_success()
@ -180,7 +180,7 @@ def update_default_stream_group_info(
new_description: Optional[str] = REQ(default=None),
) -> None:
if not new_group_name and not new_description:
return json_error(_('You must pass "new_description" or "new_group_name".'))
raise JsonableError(_('You must pass "new_description" or "new_group_name".'))
group = access_default_stream_group_by_id(user_profile.realm, group_id)
if new_group_name is not None:
@ -210,7 +210,7 @@ def update_default_stream_group_streams(
elif op == "remove":
do_remove_streams_from_default_stream_group(user_profile.realm, group, streams)
else:
return json_error(_('Invalid value for "op". Specify one of "add" or "remove".'))
raise JsonableError(_('Invalid value for "op". Specify one of "add" or "remove".'))
return json_success()
@ -278,7 +278,7 @@ def update_stream_backend(
if new_name is not None:
new_name = new_name.strip()
if stream.name == new_name:
return json_error(_("Stream already has that name!"))
raise JsonableError(_("Stream already has that name!"))
if stream.name.lower() != new_name.lower():
# Check that the stream name is available (unless we are
# are only changing the casing of the stream name).
@ -301,7 +301,7 @@ def update_stream_backend(
default_stream_ids = {s.id for s in get_default_streams_for_realm(stream.realm_id)}
(stream, sub) = access_stream_by_id(user_profile, stream_id)
if is_private and stream.id in default_stream_ids:
return json_error(_("Default streams cannot be made private."))
raise JsonableError(_("Default streams cannot be made private."))
do_change_stream_invite_only(stream, is_private, history_public_to_subscribers)
return json_success()
@ -340,7 +340,7 @@ def update_subscriptions_backend(
add: Sequence[Mapping[str, str]] = REQ(json_validator=add_subscriptions_schema, default=[]),
) -> HttpResponse:
if not add and not delete:
return json_error(_('Nothing to do. Specify at least one of "add" or "delete".'))
raise JsonableError(_('Nothing to do. Specify at least one of "add" or "delete".'))
thunks = [
lambda: add_subscriptions_backend(request, user_profile, streams_raw=add),
@ -498,7 +498,7 @@ def add_subscriptions_backend(
user_profile, existing_streams
)
if len(unauthorized_streams) > 0 and authorization_errors_fatal:
return json_error(
raise JsonableError(
_("Unable to access stream ({stream_name}).").format(
stream_name=unauthorized_streams[0].name,
)
@ -508,7 +508,7 @@ def add_subscriptions_backend(
if len(principals) > 0:
if realm.is_zephyr_mirror_realm and not all(stream.invite_only for stream in streams):
return json_error(
raise JsonableError(
_("You can only invite other Zephyr mirroring users to private streams.")
)
if not user_profile.can_subscribe_other_users():
@ -865,16 +865,16 @@ def update_subscription_properties_backend(
value = change["value"]
if property not in property_converters:
return json_error(_("Unknown subscription property: {}").format(property))
raise JsonableError(_("Unknown subscription property: {}").format(property))
(stream, sub) = access_stream_by_id(user_profile, stream_id)
if sub is None:
return json_error(_("Not subscribed to stream id {}").format(stream_id))
raise JsonableError(_("Not subscribed to stream id {}").format(stream_id))
try:
value = property_converters[property](property, value)
except ValidationError as error:
return json_error(error.message)
raise JsonableError(error.message)
do_change_subscription_property(
user_profile, sub, stream, property, value, acting_user=user_profile

View File

@ -8,7 +8,7 @@ from zerver.decorator import REQ, has_request_variables
from zerver.lib.actions import do_add_submessage, verify_submessage_sender
from zerver.lib.exceptions import JsonableError
from zerver.lib.message import access_message
from zerver.lib.response import json_error, json_success
from zerver.lib.response import json_success
from zerver.lib.validator import check_int, validate_poll_data, validate_todo_data
from zerver.lib.widget import get_widget_type
from zerver.models import UserProfile
@ -35,7 +35,7 @@ def process_submessage(
try:
widget_data = orjson.loads(content)
except orjson.JSONDecodeError:
return json_error(_("Invalid json for submessage"))
raise JsonableError(_("Invalid json for submessage"))
widget_type = get_widget_type(message_id=message.id)

View File

@ -5,7 +5,8 @@ from django.utils.translation import gettext as _
from zerver.decorator import REQ, has_request_variables
from zerver.lib.actions import check_send_typing_notification, do_send_stream_typing_notification
from zerver.lib.response import json_error, json_success
from zerver.lib.exceptions import JsonableError
from zerver.lib.response import json_success
from zerver.lib.streams import access_stream_by_id, access_stream_for_send_message
from zerver.lib.validator import check_int, check_list, check_string_in
from zerver.models import UserProfile
@ -28,14 +29,14 @@ def send_notification_backend(
to_length = len(notification_to)
if to_length == 0:
return json_error(_("Empty 'to' list"))
raise JsonableError(_("Empty 'to' list"))
if message_type == "stream":
if to_length > 1:
return json_error(_("Cannot send to multiple streams"))
raise JsonableError(_("Cannot send to multiple streams"))
if topic is None:
return json_error(_("Missing topic"))
raise JsonableError(_("Missing topic"))
stream_id = notification_to[0]
# Verify that the user has access to the stream and has

View File

@ -7,7 +7,8 @@ from django.utils.cache import patch_cache_control
from django.utils.translation import gettext as _
from django_sendfile import sendfile
from zerver.lib.response import json_error, json_success
from zerver.lib.exceptions import JsonableError
from zerver.lib.response import json_success
from zerver.lib.upload import (
INLINE_MIME_TYPES,
check_upload_within_quota,
@ -104,23 +105,23 @@ def serve_file(
def serve_local_file_unauthed(request: HttpRequest, token: str, filename: str) -> HttpResponse:
path_id = get_local_file_path_id_from_token(token)
if path_id is None:
return json_error(_("Invalid token"))
raise JsonableError(_("Invalid token"))
if path_id.split("/")[-1] != filename:
return json_error(_("Invalid filename"))
raise JsonableError(_("Invalid filename"))
return serve_local(request, path_id, url_only=False)
def upload_file_backend(request: HttpRequest, user_profile: UserProfile) -> HttpResponse:
if len(request.FILES) == 0:
return json_error(_("You must specify a file to upload"))
raise JsonableError(_("You must specify a file to upload"))
if len(request.FILES) != 1:
return json_error(_("You may only upload one file at a time"))
raise JsonableError(_("You may only upload one file at a time"))
user_file = list(request.FILES.values())[0]
file_size = user_file.size
if settings.MAX_FILE_UPLOAD_SIZE * 1024 * 1024 < file_size:
return json_error(
raise JsonableError(
_("Uploaded file is larger than the allowed limit of {} MiB").format(
settings.MAX_FILE_UPLOAD_SIZE,
)

View File

@ -14,7 +14,7 @@ from zerver.lib.actions import (
)
from zerver.lib.exceptions import JsonableError
from zerver.lib.request import REQ, has_request_variables
from zerver.lib.response import json_error, json_success
from zerver.lib.response import json_success
from zerver.lib.user_groups import (
access_user_group_by_id,
get_memberships_of_users,
@ -58,7 +58,7 @@ def edit_user_group(
description: str = REQ(default=""),
) -> HttpResponse:
if not (name or description):
return json_error(_("No new data supplied"))
raise JsonableError(_("No new data supplied"))
user_group = access_user_group_by_id(user_group_id, user_profile)
@ -93,7 +93,7 @@ def update_user_group_backend(
add: Sequence[int] = REQ(json_validator=check_list(check_int), default=[]),
) -> HttpResponse:
if not add and not delete:
return json_error(_('Nothing to do. Specify at least one of "add" or "delete".'))
raise JsonableError(_('Nothing to do. Specify at least one of "add" or "delete".'))
thunks = [
lambda: add_members_to_group_backend(

View File

@ -39,7 +39,7 @@ from zerver.lib.email_validation import (
from zerver.lib.i18n import get_available_language_codes
from zerver.lib.rate_limiter import RateLimited
from zerver.lib.request import JsonableError
from zerver.lib.response import json_error, json_success
from zerver.lib.response import json_success
from zerver.lib.send_email import FromAddress, send_email
from zerver.lib.upload import upload_avatar_image
from zerver.lib.validator import check_bool, check_int, check_int_in, check_string_in
@ -98,12 +98,12 @@ def json_change_settings(
new_password: str = REQ(default=""),
) -> HttpResponse:
if not (full_name or new_password or email):
return json_error(_("Please fill out all fields."))
raise JsonableError(_("Please fill out all fields."))
if new_password != "":
return_data: Dict[str, Any] = {}
if email_belongs_to_ldap(user_profile.realm, user_profile.delivery_email):
return json_error(_("Your Zulip password is managed in LDAP"))
raise JsonableError(_("Your Zulip password is managed in LDAP"))
try:
if not authenticate(
@ -113,18 +113,18 @@ def json_change_settings(
realm=user_profile.realm,
return_data=return_data,
):
return json_error(_("Wrong password!"))
raise JsonableError(_("Wrong password!"))
except RateLimited as e:
assert e.secs_to_freedom is not None
secs_to_freedom = int(e.secs_to_freedom)
return json_error(
raise JsonableError(
_("You're making too many attempts! Try again in {} seconds.").format(
secs_to_freedom
),
)
if not check_password_strength(new_password):
return json_error(_("New password is too weak!"))
raise JsonableError(_("New password is too weak!"))
do_change_password(user_profile, new_password)
# In Django 1.10, password changes invalidates sessions, see
@ -146,14 +146,14 @@ def json_change_settings(
new_email = email.strip()
if user_profile.delivery_email != new_email and new_email != "":
if user_profile.realm.email_changes_disabled and not user_profile.is_realm_admin:
return json_error(_("Email address changes are disabled in this organization."))
raise JsonableError(_("Email address changes are disabled in this organization."))
error = validate_email_is_valid(
new_email,
get_realm_email_validator(user_profile.realm),
)
if error:
return json_error(error)
raise JsonableError(error)
try:
validate_email_not_already_in_realm(
@ -162,7 +162,7 @@ def json_change_settings(
verbose=False,
)
except ValidationError as e:
return json_error(e.message)
raise JsonableError(e.message)
do_start_email_change_process(user_profile, new_email)
result["account_email"] = _("Check your email for a confirmation link. ")
@ -291,14 +291,14 @@ def json_change_notify_settings(
def set_avatar_backend(request: HttpRequest, user_profile: UserProfile) -> HttpResponse:
if len(request.FILES) != 1:
return json_error(_("You must upload exactly one avatar."))
raise JsonableError(_("You must upload exactly one avatar."))
if avatar_changes_disabled(user_profile.realm) and not user_profile.is_realm_admin:
return json_error(str(AVATAR_CHANGES_DISABLED_ERROR))
raise JsonableError(str(AVATAR_CHANGES_DISABLED_ERROR))
user_file = list(request.FILES.values())[0]
if (settings.MAX_AVATAR_FILE_SIZE_MIB * 1024 * 1024) < user_file.size:
return json_error(
raise JsonableError(
_("Uploaded file is larger than the allowed limit of {} MiB").format(
settings.MAX_AVATAR_FILE_SIZE_MIB,
)
@ -315,7 +315,7 @@ def set_avatar_backend(request: HttpRequest, user_profile: UserProfile) -> HttpR
def delete_avatar_backend(request: HttpRequest, user_profile: UserProfile) -> HttpResponse:
if avatar_changes_disabled(user_profile.realm) and not user_profile.is_realm_admin:
return json_error(str(AVATAR_CHANGES_DISABLED_ERROR))
raise JsonableError(str(AVATAR_CHANGES_DISABLED_ERROR))
do_change_avatar_fields(
user_profile, UserProfile.AVATAR_FROM_GRAVATAR, acting_user=user_profile

View File

@ -32,7 +32,7 @@ from zerver.lib.email_validation import email_allowed_for_realm
from zerver.lib.exceptions import CannotDeactivateLastUserError, OrganizationOwnerRequired
from zerver.lib.integrations import EMBEDDED_BOTS
from zerver.lib.request import REQ, JsonableError, has_request_variables
from zerver.lib.response import json_error, json_success
from zerver.lib.response import json_success
from zerver.lib.streams import access_stream_by_id, access_stream_by_name, subscribed_to_stream
from zerver.lib.types import Validator
from zerver.lib.upload import upload_avatar_image
@ -96,7 +96,7 @@ def deactivate_user_backend(
if target.is_realm_owner and not user_profile.is_realm_owner:
raise OrganizationOwnerRequired()
if check_last_owner(target):
return json_error(_("Cannot deactivate the only organization owner"))
raise JsonableError(_("Cannot deactivate the only organization owner"))
return _deactivate_user_profile_backend(request, user_profile, target)
@ -182,7 +182,7 @@ def update_user_backend(
raise OrganizationOwnerRequired()
if target.role == UserProfile.ROLE_REALM_OWNER and check_last_owner(user_profile):
return json_error(
raise JsonableError(
_("The owner permission cannot be removed from the only organization owner.")
)
do_change_user_role(target, role, acting_user=user_profile)
@ -278,11 +278,11 @@ def patch_bot_backend(
try:
owner = get_user_profile_by_id_in_realm(bot_owner_id, user_profile.realm)
except UserProfile.DoesNotExist:
return json_error(_("Failed to change owner, no such user"))
raise JsonableError(_("Failed to change owner, no such user"))
if not owner.is_active:
return json_error(_("Failed to change owner, user is deactivated"))
raise JsonableError(_("Failed to change owner, user is deactivated"))
if owner.is_bot:
return json_error(_("Failed to change owner, bots can't own other bots"))
raise JsonableError(_("Failed to change owner, bots can't own other bots"))
previous_owner = bot.bot_owner
if previous_owner != owner:
@ -321,7 +321,7 @@ def patch_bot_backend(
avatar_source = UserProfile.AVATAR_FROM_USER
do_change_avatar_fields(bot, avatar_source, acting_user=user_profile)
else:
return json_error(_("You may only upload one file at a time"))
raise JsonableError(_("You may only upload one file at a time"))
json_result = dict(
full_name=bot.full_name,
@ -384,7 +384,7 @@ def add_bot_backend(
try:
email = f"{short_name}@{user_profile.realm.get_bot_domain()}"
except InvalidFakeEmailDomain:
return json_error(
raise JsonableError(
_(
"Can't create bots until FAKE_EMAIL_DOMAIN is correctly configured.\n"
"Please contact your server administrator."
@ -394,16 +394,16 @@ def add_bot_backend(
if bot_type == UserProfile.EMBEDDED_BOT:
if not settings.EMBEDDED_BOTS_ENABLED:
return json_error(_("Embedded bots are not enabled."))
raise JsonableError(_("Embedded bots are not enabled."))
if service_name not in [bot.name for bot in EMBEDDED_BOTS]:
return json_error(_("Invalid embedded bot name."))
raise JsonableError(_("Invalid embedded bot name."))
if not form.is_valid():
# We validate client-side as well
return json_error(_("Bad name or username"))
raise JsonableError(_("Bad name or username"))
try:
get_user_by_delivery_email(email, user_profile.realm)
return json_error(_("Username already in use"))
raise JsonableError(_("Username already in use"))
except UserProfile.DoesNotExist:
pass
@ -419,7 +419,7 @@ def add_bot_backend(
if len(request.FILES) == 0:
avatar_source = UserProfile.AVATAR_FROM_GRAVATAR
elif len(request.FILES) != 1:
return json_error(_("You may only upload one file at a time"))
raise JsonableError(_("You may only upload one file at a time"))
else:
avatar_source = UserProfile.AVATAR_FROM_USER
@ -569,12 +569,12 @@ def create_user_backend(
full_name_raw: str = REQ("full_name"),
) -> HttpResponse:
if not user_profile.can_create_users:
return json_error(_("User not authorized for this query"))
raise JsonableError(_("User not authorized for this query"))
full_name = check_full_name(full_name_raw)
form = CreateUserForm({"full_name": full_name, "email": email})
if not form.is_valid():
return json_error(_("Bad name or username"))
raise JsonableError(_("Bad name or username"))
# Check that the new user's email address belongs to the admin's realm
# (Since this is an admin API, we don't require the user to have been
@ -583,24 +583,24 @@ def create_user_backend(
try:
email_allowed_for_realm(email, user_profile.realm)
except DomainNotAllowedForRealmError:
return json_error(
raise JsonableError(
_("Email '{email}' not allowed in this organization").format(
email=email,
)
)
except DisposableEmailError:
return json_error(_("Disposable email addresses are not allowed in this organization"))
raise JsonableError(_("Disposable email addresses are not allowed in this organization"))
except EmailContainsPlusError:
return json_error(_("Email addresses containing + are not allowed."))
raise JsonableError(_("Email addresses containing + are not allowed."))
try:
get_user_by_delivery_email(email, user_profile.realm)
return json_error(_("Email '{}' already in use").format(email))
raise JsonableError(_("Email '{}' already in use").format(email))
except UserProfile.DoesNotExist:
pass
if not check_password_strength(password):
return json_error(PASSWORD_TOO_WEAK_ERROR)
raise JsonableError(PASSWORD_TOO_WEAK_ERROR)
target_user = do_create_user(email, password, realm, full_name, acting_user=user_profile)
return json_success({"user_id": target_user.id})

View File

@ -25,7 +25,7 @@ from zerver.decorator import REQ, has_request_variables, zulip_login_required
from zerver.lib.actions import do_set_zoom_token
from zerver.lib.exceptions import ErrorCode, JsonableError
from zerver.lib.pysa import mark_sanitized
from zerver.lib.response import json_error, json_success
from zerver.lib.response import json_success
from zerver.lib.subdomains import get_subdomain
from zerver.lib.url_encoding import add_query_arg_to_redirect_url, add_query_to_redirect_url
from zerver.lib.validator import check_dict, check_string
@ -212,7 +212,7 @@ def join_bigbluebutton(
checksum: str = REQ(),
) -> HttpResponse:
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."))
raise JsonableError(_("Big Blue Button is not configured."))
else:
try:
response = requests.get(
@ -230,14 +230,14 @@ def join_bigbluebutton(
)
response.raise_for_status()
except requests.RequestException:
return json_error(_("Error connecting to the Big Blue Button server."))
raise JsonableError(_("Error connecting to the Big Blue Button server."))
payload = ElementTree.fromstring(response.text)
if payload.find("messageKey").text == "checksumError":
return json_error(_("Error authenticating to the Big Blue Button server."))
raise JsonableError(_("Error authenticating to the Big Blue Button server."))
if payload.find("returncode").text != "SUCCESS":
return json_error(_("Big Blue Button server returned an unexpected error."))
raise JsonableError(_("Big Blue Button server returned an unexpected error."))
join_params = urlencode( # type: ignore[type-var] # https://github.com/python/typeshed/issues/4234
{

View File

@ -12,9 +12,10 @@ from django.utils.translation import gettext as _
from zerver.decorator import authenticated_json_view
from zerver.lib.ccache import make_ccache
from zerver.lib.exceptions import JsonableError
from zerver.lib.pysa import mark_sanitized
from zerver.lib.request import REQ, has_request_variables
from zerver.lib.response import json_error, json_success
from zerver.lib.response import json_success
from zerver.lib.users import get_api_key
from zerver.models import UserProfile
@ -32,9 +33,9 @@ def webathena_kerberos_login(
) -> HttpResponse:
global kerberos_alter_egos
if cred is None:
return json_error(_("Could not find Kerberos credential"))
raise JsonableError(_("Could not find Kerberos credential"))
if not user_profile.realm.webathena_enabled:
return json_error(_("Webathena login not enabled"))
raise JsonableError(_("Webathena login not enabled"))
try:
parsed_cred = orjson.loads(cred)
@ -55,7 +56,7 @@ def webathena_kerberos_login(
# credential cache file.
ccache = mark_sanitized(ccache)
except Exception:
return json_error(_("Invalid Kerberos cache"))
raise JsonableError(_("Invalid Kerberos cache"))
# TODO: Send these data via (say) RabbitMQ
try:
@ -71,6 +72,6 @@ def webathena_kerberos_login(
)
except subprocess.CalledProcessError:
logging.exception("Error updating the user's ccache", stack_info=True)
return json_error(_("We were unable to set up mirroring for you"))
raise JsonableError(_("We were unable to set up mirroring for you"))
return json_success()

View File

@ -6,7 +6,8 @@ from django.utils.translation import ugettext as _
from zerver.decorator import REQ, has_request_variables, webhook_view
from zerver.lib.actions import send_rate_limited_pm_notification_to_bot_owner
from zerver.lib.response import json_error, json_success
from zerver.lib.exceptions import JsonableError
from zerver.lib.response import json_success
from zerver.lib.send_email import FromAddress
from zerver.lib.webhooks.common import check_send_webhook_message, get_setup_webhook_message
from zerver.models import UserProfile
@ -84,7 +85,7 @@ def api_freshstatus_webhook(
).strip()
send_rate_limited_pm_notification_to_bot_owner(user_profile, user_profile.realm, message)
return json_error(_("Invalid payload"))
raise JsonableError(_("Invalid payload"))
check_send_webhook_message(request, user_profile, subject, body)
return json_success()

View File

@ -4,8 +4,9 @@ from django.http import HttpRequest, HttpResponse
from django.utils.translation import gettext as _
from zerver.decorator import webhook_view
from zerver.lib.exceptions import JsonableError
from zerver.lib.request import REQ, has_request_variables
from zerver.lib.response import json_error, json_success
from zerver.lib.response import json_success
from zerver.lib.webhooks.common import check_send_webhook_message
from zerver.models import UserProfile
@ -143,7 +144,7 @@ def api_front_webhook(
event = payload["type"]
if event not in EVENT_FUNCTION_MAPPER:
return json_error(_("Unknown webhook request"))
raise JsonableError(_("Unknown webhook request"))
topic = payload["conversation"]["id"]
body = get_body_based_on_event(event)(payload)

View File

@ -4,8 +4,9 @@ from django.http import HttpRequest, HttpResponse
from django.utils.translation import gettext as _
from zerver.decorator import webhook_view
from zerver.lib.exceptions import JsonableError
from zerver.lib.request import REQ, has_request_variables
from zerver.lib.response import json_error, json_success
from zerver.lib.response import json_success
from zerver.lib.webhooks.common import check_send_webhook_message
from zerver.models import UserProfile
@ -23,10 +24,10 @@ def api_iftt_app_webhook(
if topic is None:
topic = payload.get("subject") # Backwards-compatibility
if topic is None:
return json_error(_("Topic can't be empty"))
raise JsonableError(_("Topic can't be empty"))
if content is None:
return json_error(_("Content can't be empty"))
raise JsonableError(_("Content can't be empty"))
check_send_webhook_message(request, user_profile, topic, content)
return json_success()

View File

@ -6,8 +6,9 @@ from django.http import HttpRequest, HttpResponse
from django.utils.translation import gettext as _
from zerver.decorator import webhook_view
from zerver.lib.exceptions import JsonableError
from zerver.lib.request import REQ, has_request_variables
from zerver.lib.response import json_error, json_success
from zerver.lib.response import json_success
from zerver.lib.webhooks.common import check_send_webhook_message
from zerver.models import UserProfile
@ -169,7 +170,7 @@ def api_librato_webhook(
attachments = []
if not attachments and not payload:
return json_error(_("Malformed JSON input"))
raise JsonableError(_("Malformed JSON input"))
message_handler = LibratoWebhookHandler(payload, attachments)
topic = message_handler.generate_topic()
@ -177,7 +178,7 @@ def api_librato_webhook(
try:
content = message_handler.handle()
except Exception as e:
return json_error(str(e))
raise JsonableError(str(e))
check_send_webhook_message(request, user_profile, topic, content)
return json_success()

View File

@ -5,8 +5,9 @@ from django.http import HttpRequest, HttpResponse
from django.utils.translation import gettext as _
from zerver.decorator import webhook_view
from zerver.lib.exceptions import JsonableError
from zerver.lib.request import REQ, has_request_variables
from zerver.lib.response import json_error, json_success
from zerver.lib.response import json_success
from zerver.lib.webhooks.common import check_send_webhook_message, unix_milliseconds_to_timestamp
from zerver.models import UserProfile
@ -46,7 +47,7 @@ def api_newrelic_webhook(
unix_time = payload.get("timestamp", None)
if unix_time is None:
return json_error(_("The newrelic webhook requires timestamp in milliseconds"))
raise JsonableError(_("The newrelic webhook requires timestamp in milliseconds"))
info["iso_timestamp"] = unix_milliseconds_to_timestamp(unix_time, "newrelic")
@ -62,7 +63,7 @@ def api_newrelic_webhook(
elif "closed" in info["status"]:
content = DEFAULT_TEMPLATE.format(**info)
else:
return json_error(
raise JsonableError(
_("The newrelic webhook requires current_state be in [open|acknowledged|closed]")
)

View File

@ -8,9 +8,9 @@ from django.http import HttpRequest, HttpResponse
from django.utils.translation import gettext as _
from zerver.decorator import webhook_view
from zerver.lib.exceptions import UnsupportedWebhookEventType
from zerver.lib.exceptions import JsonableError, UnsupportedWebhookEventType
from zerver.lib.request import has_request_variables
from zerver.lib.response import json_error, json_success
from zerver.lib.response import json_success
from zerver.lib.webhooks.common import check_send_webhook_message
from zerver.models import UserProfile
@ -176,7 +176,7 @@ def api_pivotal_webhook(request: HttpRequest, user_profile: UserProfile) -> Http
subject, content = api_pivotal_webhook_v5(request, user_profile)
if not content:
return json_error(_("Unable to handle Pivotal payload"))
raise JsonableError(_("Unable to handle Pivotal payload"))
check_send_webhook_message(request, user_profile, subject, content)
return json_success()

View File

@ -3,8 +3,9 @@ from django.utils.translation import gettext as _
from zerver.decorator import webhook_view
from zerver.lib.actions import check_send_stream_message
from zerver.lib.exceptions import JsonableError
from zerver.lib.request import REQ, has_request_variables
from zerver.lib.response import json_error, json_success
from zerver.lib.response import json_success
from zerver.models import UserProfile
ZULIP_MESSAGE_TEMPLATE = "**{message_sender}**: `{text}`"
@ -24,7 +25,7 @@ def api_slack_webhook(
) -> HttpRequest:
if channels_map_to_topics not in list(VALID_OPTIONS.values()):
return json_error(_("Error: channels_map_to_topics parameter other than 0 or 1"))
raise JsonableError(_("Error: channels_map_to_topics parameter other than 0 or 1"))
if channels_map_to_topics == VALID_OPTIONS["SHOULD_BE_MAPPED"]:
subject = f"channel: {channel_name}"

View File

@ -5,7 +5,8 @@ from django.utils.translation import ugettext as _
from zerver.decorator import REQ, has_request_variables, webhook_view
from zerver.lib.actions import send_rate_limited_pm_notification_to_bot_owner
from zerver.lib.response import json_error, json_success
from zerver.lib.exceptions import JsonableError
from zerver.lib.response import json_success
from zerver.lib.send_email import FromAddress
from zerver.lib.webhooks.common import check_send_webhook_message
from zerver.models import UserProfile
@ -46,7 +47,7 @@ def api_uptimerobot_webhook(
).strip()
send_rate_limited_pm_notification_to_bot_owner(user_profile, user_profile.realm, message)
return json_error(_("Invalid payload"))
raise JsonableError(_("Invalid payload"))
check_send_webhook_message(request, user_profile, subject, body)
return json_success()

View File

@ -3,8 +3,9 @@ from django.http import HttpRequest, HttpResponse
from django.utils.translation import gettext as _
from zerver.decorator import webhook_view
from zerver.lib.exceptions import JsonableError
from zerver.lib.request import REQ, has_request_variables
from zerver.lib.response import json_error, json_success
from zerver.lib.response import json_success
from zerver.lib.webhooks.common import check_send_webhook_message
from zerver.models import UserProfile
@ -46,7 +47,7 @@ def api_wordpress_webhook(
data = WP_LOGIN_TEMPLATE.format(name=user_login)
else:
return json_error(_("Unknown WordPress webhook action: {}").format(hook))
raise JsonableError(_("Unknown WordPress webhook action: {}").format(hook))
topic = "WordPress notification"

View File

@ -5,7 +5,8 @@ from django.utils.translation import gettext as _
from zerver.decorator import REQ, has_request_variables, webhook_view
from zerver.lib.actions import send_rate_limited_pm_notification_to_bot_owner
from zerver.lib.response import json_error, json_success
from zerver.lib.exceptions import JsonableError
from zerver.lib.response import json_success
from zerver.lib.send_email import FromAddress
from zerver.lib.webhooks.common import check_send_webhook_message
from zerver.models import UserProfile
@ -45,7 +46,7 @@ def api_zabbix_webhook(
).strip()
send_rate_limited_pm_notification_to_bot_owner(user_profile, user_profile.realm, message)
return json_error(_("Invalid payload"))
raise JsonableError(_("Invalid payload"))
check_send_webhook_message(request, user_profile, subject, body)
return json_success()

View File

@ -4,8 +4,9 @@ from django.http import HttpRequest, HttpResponse
from django.utils.translation import gettext as _
from zerver.decorator import webhook_view
from zerver.lib.exceptions import JsonableError
from zerver.lib.request import REQ, has_request_variables
from zerver.lib.response import json_error, json_success
from zerver.lib.response import json_success
from zerver.lib.webhooks.common import check_send_webhook_message
from zerver.models import UserProfile
@ -35,10 +36,10 @@ def api_zapier_webhook(
if topic is None:
topic = payload.get("subject") # Backwards-compatibility
if topic is None:
return json_error(_("Topic can't be empty"))
raise JsonableError(_("Topic can't be empty"))
if content is None:
return json_error(_("Content can't be empty"))
raise JsonableError(_("Content can't be empty"))
check_send_webhook_message(request, user_profile, topic, content)
return json_success()

View File

@ -19,7 +19,7 @@ from zerver.lib.push_notifications import (
send_apple_push_notification,
)
from zerver.lib.request import REQ, has_request_variables
from zerver.lib.response import json_error, json_success
from zerver.lib.response import json_success
from zerver.lib.validator import (
check_bool,
check_capped_string,
@ -147,7 +147,7 @@ def unregister_remote_push_device(
token=token, kind=token_kind, user_id=user_id, server=server
).delete()
if deleted[0] == 0:
return json_error(err_("Token does not exist"))
raise JsonableError(err_("Token does not exist"))
return json_success()