support: Add ability to change subdomain of realms.

This commit is contained in:
Siddharth Asthana 2020-11-17 23:48:22 +05:30
parent d64a9504d0
commit 41cb047645
5 changed files with 62 additions and 6 deletions

View File

@ -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)

View File

@ -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":

View File

@ -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;
} }

View File

@ -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 }}

View File

@ -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 }}