mirror of https://github.com/zulip/zulip.git
remote_billing_page: Show error page for registration mismatch.
When a self-hosted Zulip server does a data export and then import process into a different hosting environment (i.e. not sharing the RemoteZulipServer with the original, we'll have various things that fail where we look up the RemoteRealm by UUID and find it but the RemoteZulipServer it is associated with is the wrong one. Right now, we ask user to contact support via an error page but might develop UI to help user do the migration directly.
This commit is contained in:
parent
82db8e7ac5
commit
ac8d5a5f0b
|
@ -34,6 +34,7 @@ from zerver.lib.exceptions import (
|
|||
JsonableError,
|
||||
MissingRemoteRealmError,
|
||||
RemoteBillingAuthenticationError,
|
||||
RemoteRealmServerMismatchError,
|
||||
)
|
||||
from zerver.lib.remote_server import RealmDataForAnalytics, UserDataForRemoteBilling
|
||||
from zerver.lib.response import json_success
|
||||
|
@ -72,10 +73,18 @@ def remote_realm_billing_entry(
|
|||
) -> HttpResponse:
|
||||
if not settings.DEVELOPMENT:
|
||||
return render(request, "404.html", status=404)
|
||||
|
||||
try:
|
||||
remote_realm = RemoteRealm.objects.get(uuid=realm.uuid, server=remote_server)
|
||||
except RemoteRealm.DoesNotExist:
|
||||
if RemoteRealm.objects.filter(uuid=realm.uuid).exists(): # nocoverage
|
||||
billing_logger.warning(
|
||||
"%s: Realm %s exists, but not registered to server %s",
|
||||
request.path,
|
||||
realm.uuid,
|
||||
remote_server.id,
|
||||
)
|
||||
raise RemoteRealmServerMismatchError
|
||||
else:
|
||||
# This error will prod the remote server to submit its realm info, which
|
||||
# should lead to the creation of this missing RemoteRealm registration.
|
||||
raise MissingRemoteRealmError
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
{% extends "zerver/portico.html" %}
|
||||
|
||||
{% block title %}
|
||||
<title>{{ _("Error") }} | Zulip</title>
|
||||
{% endblock %}
|
||||
|
||||
{% block portico_class_name %}error{% endblock %}
|
||||
|
||||
{% block portico_content %}
|
||||
<div class="error_page">
|
||||
<div class="container">
|
||||
<div class="row-fluid">
|
||||
<img src="{{ static('images/errors/400art.svg') }}" alt=""/>
|
||||
<div class="errorbox">
|
||||
<div class="errorcontent">
|
||||
<h1 class="lead">{{ _("Unexpected Zulip server registration") }}</h1>
|
||||
<p>
|
||||
{% trans %}
|
||||
Your Zulip organization is registered as associated with a
|
||||
different Zulip server installation.
|
||||
|
||||
Please <a href="mailto:{{ support_email }}">contact Zulip support</a>
|
||||
for assistance in resolving this issue.
|
||||
{% endtrans %}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -50,6 +50,7 @@ class ErrorCode(Enum):
|
|||
TOPIC_WILDCARD_MENTION_NOT_ALLOWED = auto()
|
||||
STREAM_WILDCARD_MENTION_NOT_ALLOWED = auto()
|
||||
REMOTE_BILLING_UNAUTHENTICATED_USER = auto()
|
||||
REMOTE_REALM_SERVER_MISMATCH_ERROR = auto()
|
||||
|
||||
|
||||
class JsonableError(Exception):
|
||||
|
@ -592,6 +593,21 @@ class ServerNotReadyError(JsonableError):
|
|||
http_status_code = 500
|
||||
|
||||
|
||||
class RemoteRealmServerMismatchError(JsonableError): # nocoverage
|
||||
code = ErrorCode.REMOTE_REALM_SERVER_MISMATCH_ERROR
|
||||
http_status_code = 403
|
||||
|
||||
def __init__(self) -> None:
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
@override
|
||||
def msg_format() -> str:
|
||||
return _(
|
||||
"Your organization is registered to a different Zulip server. Please contact Zulip support for assistance in resolving this issue."
|
||||
)
|
||||
|
||||
|
||||
class MissingRemoteRealmError(JsonableError): # nocoverage
|
||||
code: ErrorCode = ErrorCode.MISSING_REMOTE_REALM
|
||||
http_status_code = 403
|
||||
|
|
|
@ -11,7 +11,11 @@ from pydantic import UUID4, BaseModel, ConfigDict, Field, Json, field_validator
|
|||
|
||||
from analytics.models import InstallationCount, RealmCount
|
||||
from version import API_FEATURE_LEVEL, ZULIP_VERSION
|
||||
from zerver.lib.exceptions import JsonableError, MissingRemoteRealmError
|
||||
from zerver.lib.exceptions import (
|
||||
JsonableError,
|
||||
MissingRemoteRealmError,
|
||||
RemoteRealmServerMismatchError,
|
||||
)
|
||||
from zerver.lib.outgoing_http import OutgoingSession
|
||||
from zerver.lib.queue import queue_json_publish
|
||||
from zerver.lib.types import RemoteRealmDictValue
|
||||
|
@ -195,6 +199,14 @@ def send_to_push_bouncer(
|
|||
# The callers requesting this endpoint want the exception to propagate
|
||||
# so they can catch it.
|
||||
raise MissingRemoteRealmError
|
||||
elif (
|
||||
endpoint == "server/billing"
|
||||
and "code" in result_dict
|
||||
and result_dict["code"] == "REMOTE_REALM_SERVER_MISMATCH_ERROR"
|
||||
): # nocoverage
|
||||
# The callers requesting this endpoint want the exception to propagate
|
||||
# so they can catch it.
|
||||
raise RemoteRealmServerMismatchError
|
||||
else:
|
||||
# But most other errors coming from the push bouncer
|
||||
# server are client errors (e.g. never-registered token)
|
||||
|
|
|
@ -816,8 +816,8 @@ class PushBouncerNotificationTest(BouncerTestCase):
|
|||
# is processing the token registration request, it will find a RemoteRealm matching
|
||||
# the realm_uuid in the request, but that RemoteRealm will be registered to a
|
||||
# different server than the one making the request (self.server).
|
||||
# This will make it log a warning and register the token, but of course without
|
||||
# assigning the token registration to that RemoteRealm.
|
||||
# This will make it log a warning, raise an exception when trying to get
|
||||
# remote realm via get_remote_realm_helper and thus, not register the token.
|
||||
second_server = RemoteZulipServer.objects.create(
|
||||
uuid=uuid.uuid4(),
|
||||
api_key="magic_secret_api_key2",
|
||||
|
@ -835,7 +835,10 @@ class PushBouncerNotificationTest(BouncerTestCase):
|
|||
result = self.client_post(
|
||||
endpoint, {"token": token, "appid": "org.zulip.Zulip"}, subdomain="zulip"
|
||||
)
|
||||
self.assert_json_success(result)
|
||||
self.assert_json_error_contains(
|
||||
result,
|
||||
"Your organization is registered to a different Zulip server. Please contact Zulip support",
|
||||
)
|
||||
self.assertEqual(
|
||||
warn_log.output,
|
||||
[
|
||||
|
@ -844,10 +847,7 @@ class PushBouncerNotificationTest(BouncerTestCase):
|
|||
],
|
||||
)
|
||||
|
||||
remote_token = RemotePushDeviceToken.objects.get(token=token)
|
||||
self.assertEqual(remote_token.server, self.server)
|
||||
self.assertEqual(remote_token.user_uuid, user.uuid)
|
||||
self.assertEqual(remote_token.remote_realm, None)
|
||||
self.assert_length(RemotePushDeviceToken.objects.filter(token=token), 0)
|
||||
|
||||
@override_settings(PUSH_NOTIFICATION_BOUNCER_URL="https://push.zulip.org.example.com")
|
||||
@responses.activate
|
||||
|
|
|
@ -11,6 +11,7 @@ from zerver.lib.exceptions import (
|
|||
JsonableError,
|
||||
MissingRemoteRealmError,
|
||||
OrganizationOwnerRequiredError,
|
||||
RemoteRealmServerMismatchError,
|
||||
)
|
||||
from zerver.lib.push_notifications import (
|
||||
InvalidPushDeviceTokenError,
|
||||
|
@ -163,6 +164,8 @@ def self_hosting_auth_redirect(
|
|||
# Upload realm info and re-try. It should work now.
|
||||
send_realms_only_to_push_bouncer()
|
||||
result = send_to_push_bouncer("POST", "server/billing", post_data)
|
||||
except RemoteRealmServerMismatchError:
|
||||
return render(request, "zilencer/remote_realm_server_mismatch_error.html", status=403)
|
||||
|
||||
if result["result"] != "success":
|
||||
raise JsonableError(_("Error returned by the bouncer: {result}").format(result=result))
|
||||
|
|
|
@ -26,7 +26,7 @@ from analytics.lib.counts import (
|
|||
from corporate.lib.stripe import RemoteRealmBillingSession, do_deactivate_remote_server
|
||||
from corporate.models import CustomerPlan, get_current_plan_by_customer
|
||||
from zerver.decorator import require_post
|
||||
from zerver.lib.exceptions import JsonableError
|
||||
from zerver.lib.exceptions import JsonableError, RemoteRealmServerMismatchError
|
||||
from zerver.lib.push_notifications import (
|
||||
InvalidRemotePushDeviceTokenError,
|
||||
UserPushIdentityCompat,
|
||||
|
@ -375,7 +375,7 @@ def get_remote_realm_helper(
|
|||
realm_uuid,
|
||||
server.id,
|
||||
)
|
||||
return None
|
||||
raise RemoteRealmServerMismatchError
|
||||
|
||||
return remote_realm
|
||||
|
||||
|
|
Loading…
Reference in New Issue