mirror of https://github.com/zulip/zulip.git
update_realm: Allow demo orgs to be converted to regular orgs.
This commit adds support to the `PATCH /realm` endpoint for converting a demo organization to a regular organization. This is a part of #19523.
This commit is contained in:
parent
98415808ba
commit
29b354346b
|
@ -11,6 +11,12 @@ below features are supported.
|
|||
|
||||
## Changes in Zulip 5.0
|
||||
|
||||
**Feature level 104**
|
||||
|
||||
* [`PATCH /realm`]: Added `string_id` parameter for changing an
|
||||
organization's subdomain. Currently, this is only allowed for
|
||||
changing changing a demo organization to a normal one.
|
||||
|
||||
**Feature level 103**
|
||||
|
||||
* [`POST /register`](/api/register-queue): Added `create_web_public_stream_policy`
|
||||
|
|
|
@ -33,7 +33,7 @@ DESKTOP_WARNING_VERSION = "5.4.3"
|
|||
# Changes should be accompanied by documentation explaining what the
|
||||
# new level means in templates/zerver/api/changelog.md, as well as
|
||||
# "**Changes**" entries in the endpoint's documentation in `zulip.yaml`.
|
||||
API_FEATURE_LEVEL = 103
|
||||
API_FEATURE_LEVEL = 104
|
||||
|
||||
# Bump the minor PROVISION_VERSION to indicate that folks should provision
|
||||
# only when going from an old version of the code to a newer version. Bump
|
||||
|
|
|
@ -1116,10 +1116,21 @@ def do_reactivate_realm(realm: Realm) -> None:
|
|||
def do_change_realm_subdomain(
|
||||
realm: Realm, new_subdomain: str, *, acting_user: Optional[UserProfile]
|
||||
) -> None:
|
||||
"""Changing a realm's subdomain is a highly disruptive operation,
|
||||
because all existing clients will need to be updated to point to
|
||||
the new URL. Further, requests to fetch data frmo existing event
|
||||
queues will fail with an authentication error when this change
|
||||
happens (because the old subdomain is no longer associated with
|
||||
the realm), making it hard for us to provide a graceful update
|
||||
experience for clients.
|
||||
"""
|
||||
old_subdomain = realm.subdomain
|
||||
old_uri = realm.uri
|
||||
# If the realm had been a demo organization scheduled for
|
||||
# deleting, clear that state.
|
||||
realm.demo_organization_scheduled_deletion_date = None
|
||||
realm.string_id = new_subdomain
|
||||
realm.save(update_fields=["string_id"])
|
||||
realm.save(update_fields=["string_id", "demo_organization_scheduled_deletion_date"])
|
||||
RealmAuditLog.objects.create(
|
||||
realm=realm,
|
||||
event_type=RealmAuditLog.REALM_SUBDOMAIN_CHANGED,
|
||||
|
|
|
@ -219,7 +219,7 @@ class Realm(models.Model):
|
|||
string_id: str = models.CharField(max_length=MAX_REALM_SUBDOMAIN_LENGTH, unique=True)
|
||||
|
||||
date_created: datetime.datetime = models.DateTimeField(default=timezone_now)
|
||||
demo_organization_scheduled_deletion_date: datetime.datetime = models.DateTimeField(
|
||||
demo_organization_scheduled_deletion_date: Optional[datetime.datetime] = models.DateTimeField(
|
||||
default=None, null=True
|
||||
)
|
||||
deactivated: bool = models.BooleanField(default=False)
|
||||
|
|
|
@ -171,6 +171,37 @@ class RealmTest(ZulipTestCase):
|
|||
realm = get_realm("zulip")
|
||||
self.assertNotEqual(realm.description, new_description)
|
||||
|
||||
def test_realm_convert_demo_realm(self) -> None:
|
||||
data = dict(string_id="coolrealm")
|
||||
|
||||
self.login("iago")
|
||||
result = self.client_patch("/json/realm", data)
|
||||
self.assert_json_error(result, "Must be an organization owner")
|
||||
|
||||
self.login("desdemona")
|
||||
result = self.client_patch("/json/realm", data)
|
||||
self.assert_json_error(result, "Must be a demo organization.")
|
||||
|
||||
data = dict(string_id="lear")
|
||||
self.login("desdemona")
|
||||
realm = get_realm("zulip")
|
||||
realm.demo_organization_scheduled_deletion_date = timezone_now() + datetime.timedelta(
|
||||
days=30
|
||||
)
|
||||
realm.save()
|
||||
result = self.client_patch("/json/realm", data)
|
||||
self.assert_json_error(result, "Subdomain unavailable. Please choose a different one.")
|
||||
|
||||
# Now try to change the string_id to something available.
|
||||
data = dict(string_id="coolrealm")
|
||||
result = self.client_patch("/json/realm", data)
|
||||
self.assert_json_success(result)
|
||||
json = orjson.loads(result.content)
|
||||
self.assertEqual(json["realm_uri"], "http://coolrealm.testserver")
|
||||
realm = get_realm("coolrealm")
|
||||
self.assertIsNone(realm.demo_organization_scheduled_deletion_date)
|
||||
self.assertEqual(realm.string_id, data["string_id"])
|
||||
|
||||
def test_realm_name_length(self) -> None:
|
||||
new_name = "A" * (Realm.MAX_REALM_NAME_LENGTH + 1)
|
||||
data = dict(name=new_name)
|
||||
|
|
|
@ -10,6 +10,7 @@ from confirmation.models import Confirmation, ConfirmationKeyException, get_obje
|
|||
from zerver.decorator import require_realm_admin, require_realm_owner
|
||||
from zerver.forms import check_subdomain_available as check_subdomain
|
||||
from zerver.lib.actions import (
|
||||
do_change_realm_subdomain,
|
||||
do_deactivate_realm,
|
||||
do_reactivate_realm,
|
||||
do_set_realm_authentication_methods,
|
||||
|
@ -133,6 +134,10 @@ def update_realm(
|
|||
digest_weekday: Optional[int] = REQ(
|
||||
json_validator=check_int_in(Realm.DIGEST_WEEKDAY_VALUES), default=None
|
||||
),
|
||||
string_id: Optional[str] = REQ(
|
||||
str_validator=check_capped_string(Realm.MAX_REALM_SUBDOMAIN_LENGTH),
|
||||
default=None,
|
||||
),
|
||||
) -> HttpResponse:
|
||||
realm = user_profile.realm
|
||||
|
||||
|
@ -273,6 +278,21 @@ def update_realm(
|
|||
else:
|
||||
data["default_code_block_language"] = default_code_block_language
|
||||
|
||||
if string_id is not None:
|
||||
if not user_profile.is_realm_owner:
|
||||
raise OrganizationOwnerRequired()
|
||||
|
||||
if realm.demo_organization_scheduled_deletion_date is None:
|
||||
raise JsonableError(_("Must be a demo organization."))
|
||||
|
||||
try:
|
||||
check_subdomain(string_id)
|
||||
except ValidationError as err:
|
||||
raise JsonableError(str(err.message))
|
||||
|
||||
do_change_realm_subdomain(realm, string_id, acting_user=user_profile)
|
||||
data["realm_uri"] = realm.uri
|
||||
|
||||
return json_success(data)
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue