mirror of https://github.com/zulip/zulip.git
support: Add ability to change subdomain of realms.
This commit is contained in:
parent
37e158b9ba
commit
6f962c1815
|
@ -714,6 +714,31 @@ class TestSupportEndpoint(ZulipTestCase):
|
||||||
m.assert_called_once_with(lear_realm)
|
m.assert_called_once_with(lear_realm)
|
||||||
self.assert_in_success_response(["Realm reactivation email sent to admins of lear"], result)
|
self.assert_in_success_response(["Realm reactivation email sent to admins of lear"], result)
|
||||||
|
|
||||||
|
def test_change_subdomain(self) -> None:
|
||||||
|
cordelia = self.example_user('cordelia')
|
||||||
|
lear_realm = get_realm('lear')
|
||||||
|
self.login_user(cordelia)
|
||||||
|
|
||||||
|
result = self.client_post("/activity/support", {"realm_id": f"{lear_realm.id}",
|
||||||
|
"new_subdomain": "new_name"})
|
||||||
|
self.assertEqual(result.status_code, 302)
|
||||||
|
self.assertEqual(result["Location"], "/login/")
|
||||||
|
self.login('iago')
|
||||||
|
|
||||||
|
result = self.client_post("/activity/support", {"realm_id": f"{lear_realm.id}", "new_subdomain": "new-name"})
|
||||||
|
self.assertEqual(result.status_code, 302)
|
||||||
|
self.assertEqual(result["Location"], "/activity/support?q=new-name")
|
||||||
|
realm_id = lear_realm.id
|
||||||
|
lear_realm = get_realm('new-name')
|
||||||
|
self.assertEqual(lear_realm.id, realm_id)
|
||||||
|
self.assertFalse(Realm.objects.filter(string_id='lear').exists())
|
||||||
|
|
||||||
|
result = self.client_post("/activity/support", {"realm_id": f"{lear_realm.id}", "new_subdomain": "new-name"})
|
||||||
|
self.assert_in_success_response(["Subdomain unavailable. Please choose a different one."], result)
|
||||||
|
|
||||||
|
result = self.client_post("/activity/support", {"realm_id": f"{lear_realm.id}", "new_subdomain": "zulip"})
|
||||||
|
self.assert_in_success_response(["Subdomain unavailable. Please choose a different one."], result)
|
||||||
|
|
||||||
def test_downgrade_realm(self) -> None:
|
def test_downgrade_realm(self) -> None:
|
||||||
cordelia = self.example_user('cordelia')
|
cordelia = self.example_user('cordelia')
|
||||||
self.login_user(cordelia)
|
self.login_user(cordelia)
|
||||||
|
|
|
@ -7,6 +7,7 @@ from collections import defaultdict
|
||||||
from datetime import datetime, timedelta, timezone
|
from datetime import datetime, timedelta, timezone
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
from typing import Any, Callable, Dict, List, Optional, Sequence, Set, Tuple, Type, Union
|
from typing import Any, Callable, Dict, List, Optional, Sequence, Set, Tuple, Type, Union
|
||||||
|
from urllib.parse import urlencode
|
||||||
|
|
||||||
import pytz
|
import pytz
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
@ -14,7 +15,7 @@ from django.core.exceptions import ValidationError
|
||||||
from django.core.validators import URLValidator
|
from django.core.validators import URLValidator
|
||||||
from django.db import connection
|
from django.db import connection
|
||||||
from django.db.models.query import QuerySet
|
from django.db.models.query import QuerySet
|
||||||
from django.http import HttpRequest, HttpResponse, HttpResponseNotFound
|
from django.http import HttpRequest, HttpResponse, HttpResponseNotFound, HttpResponseRedirect
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
from django.template import loader
|
from django.template import loader
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
@ -45,8 +46,10 @@ from zerver.decorator import (
|
||||||
to_utc_datetime,
|
to_utc_datetime,
|
||||||
zulip_login_required,
|
zulip_login_required,
|
||||||
)
|
)
|
||||||
|
from zerver.forms import check_subdomain_available
|
||||||
from zerver.lib.actions import (
|
from zerver.lib.actions import (
|
||||||
do_change_plan_type,
|
do_change_plan_type,
|
||||||
|
do_change_realm_subdomain,
|
||||||
do_deactivate_realm,
|
do_deactivate_realm,
|
||||||
do_scrub_realm,
|
do_scrub_realm,
|
||||||
do_send_realm_reactivation_email,
|
do_send_realm_reactivation_email,
|
||||||
|
@ -1108,6 +1111,11 @@ def get_confirmations(types: List[int], object_ids: List[int],
|
||||||
@require_server_admin
|
@require_server_admin
|
||||||
def support(request: HttpRequest) -> HttpResponse:
|
def support(request: HttpRequest) -> HttpResponse:
|
||||||
context: Dict[str, Any] = {}
|
context: Dict[str, Any] = {}
|
||||||
|
|
||||||
|
if "success_message" in request.session:
|
||||||
|
context["success_message"] = request.session["success_message"]
|
||||||
|
del request.session["success_message"]
|
||||||
|
|
||||||
if settings.BILLING_ENABLED and request.method == "POST":
|
if settings.BILLING_ENABLED and request.method == "POST":
|
||||||
# We check that request.POST only has two keys in it: The
|
# We check that request.POST only has two keys in it: The
|
||||||
# realm_id and a field to change.
|
# realm_id and a field to change.
|
||||||
|
@ -1132,6 +1140,17 @@ def support(request: HttpRequest) -> HttpResponse:
|
||||||
attach_discount_to_realm(realm, new_discount)
|
attach_discount_to_realm(realm, new_discount)
|
||||||
msg = f"Discount of {realm.string_id} changed to {new_discount} from {current_discount} "
|
msg = f"Discount of {realm.string_id} changed to {new_discount} from {current_discount} "
|
||||||
context["success_message"] = msg
|
context["success_message"] = msg
|
||||||
|
elif request.POST.get("new_subdomain", None) is not None:
|
||||||
|
new_subdomain = request.POST.get("new_subdomain")
|
||||||
|
old_subdomain = realm.string_id
|
||||||
|
try:
|
||||||
|
check_subdomain_available(new_subdomain)
|
||||||
|
except ValidationError as error:
|
||||||
|
context["error_message"] = error.message
|
||||||
|
else:
|
||||||
|
do_change_realm_subdomain(realm, new_subdomain)
|
||||||
|
request.session["success_message"] = f"Subdomain changed from {old_subdomain} to {new_subdomain}"
|
||||||
|
return HttpResponseRedirect(reverse('support') + '?' + urlencode({'q': new_subdomain}))
|
||||||
elif request.POST.get("status", None) is not None:
|
elif request.POST.get("status", None) is not None:
|
||||||
status = request.POST.get("status")
|
status = request.POST.get("status")
|
||||||
if status == "active":
|
if status == "active":
|
||||||
|
|
|
@ -76,7 +76,7 @@ tr.admin td:first-child {
|
||||||
|
|
||||||
.support-plan-type-form {
|
.support-plan-type-form {
|
||||||
position: relative;
|
position: relative;
|
||||||
top: -25px;
|
top: -10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sponsorship-pending-form {
|
.sponsorship-pending-form {
|
||||||
|
@ -86,7 +86,7 @@ tr.admin td:first-child {
|
||||||
|
|
||||||
.current-plan-details {
|
.current-plan-details {
|
||||||
position: relative;
|
position: relative;
|
||||||
top: -50px;
|
top: -15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.approve-sponsorship-form {
|
.approve-sponsorship-form {
|
||||||
|
@ -120,7 +120,7 @@ tr.admin td:first-child {
|
||||||
|
|
||||||
.support-submit-button {
|
.support-submit-button {
|
||||||
position: relative;
|
position: relative;
|
||||||
top: -5px;
|
top: -3px;
|
||||||
border-color: hsl(0, 0%, 83%);
|
border-color: hsl(0, 0%, 83%);
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,13 @@
|
||||||
</select>
|
</select>
|
||||||
<button type="submit" class="button rounded small support-submit-button">Update</button>
|
<button type="submit" class="button rounded small support-submit-button">Update</button>
|
||||||
</form>
|
</form>
|
||||||
|
<form method="POST">
|
||||||
|
<b>New subdomain</b>:<br>
|
||||||
|
{{ csrf_input }}
|
||||||
|
<input type="hidden" name="realm_id" value="{{ realm.id }}" />
|
||||||
|
<input type="text" name="new_subdomain" required>
|
||||||
|
<button type="submit" class="button rounded small support-submit-button">Update</button>
|
||||||
|
</form>
|
||||||
<form method="POST" class="support-plan-type-form">
|
<form method="POST" class="support-plan-type-form">
|
||||||
<b>Plan type</b>:<br>
|
<b>Plan type</b>:<br>
|
||||||
{{ csrf_input }}
|
{{ csrf_input }}
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
<title>Info</title>
|
<title>Info</title>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<br>
|
<br>
|
||||||
|
@ -18,7 +17,13 @@
|
||||||
</center>
|
</center>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
{% if success_message %}
|
{% if error_message %}
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<center>
|
||||||
|
{{ error_message }}
|
||||||
|
</center>
|
||||||
|
</div>
|
||||||
|
{% elif success_message %}
|
||||||
<div class="alert alert-success">
|
<div class="alert alert-success">
|
||||||
<center>
|
<center>
|
||||||
{{ success_message }}
|
{{ success_message }}
|
||||||
|
|
Loading…
Reference in New Issue