diff --git a/analytics/tests/test_views.py b/analytics/tests/test_views.py index a9b5df167c..d027342d39 100644 --- a/analytics/tests/test_views.py +++ b/analytics/tests/test_views.py @@ -714,6 +714,31 @@ class TestSupportEndpoint(ZulipTestCase): m.assert_called_once_with(lear_realm) 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: cordelia = self.example_user('cordelia') self.login_user(cordelia) diff --git a/analytics/views.py b/analytics/views.py index b77b075c32..6770ce4657 100644 --- a/analytics/views.py +++ b/analytics/views.py @@ -7,6 +7,7 @@ from collections import defaultdict from datetime import datetime, timedelta, timezone from decimal import Decimal from typing import Any, Callable, Dict, List, Optional, Sequence, Set, Tuple, Type, Union +from urllib.parse import urlencode import pytz from django.conf import settings @@ -14,7 +15,7 @@ from django.core.exceptions import ValidationError from django.core.validators import URLValidator from django.db import connection 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.template import loader from django.urls import reverse @@ -45,8 +46,10 @@ from zerver.decorator import ( to_utc_datetime, zulip_login_required, ) +from zerver.forms import check_subdomain_available from zerver.lib.actions import ( do_change_plan_type, + do_change_realm_subdomain, do_deactivate_realm, do_scrub_realm, do_send_realm_reactivation_email, @@ -1108,6 +1111,11 @@ def get_confirmations(types: List[int], object_ids: List[int], @require_server_admin def support(request: HttpRequest) -> HttpResponse: 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": # We check that request.POST only has two keys in it: The # realm_id and a field to change. @@ -1132,6 +1140,17 @@ def support(request: HttpRequest) -> HttpResponse: attach_discount_to_realm(realm, new_discount) msg = f"Discount of {realm.string_id} changed to {new_discount} from {current_discount} " 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: status = request.POST.get("status") if status == "active": diff --git a/static/styles/portico/activity.css b/static/styles/portico/activity.css index 4e71acea8e..b1df095cce 100644 --- a/static/styles/portico/activity.css +++ b/static/styles/portico/activity.css @@ -76,7 +76,7 @@ tr.admin td:first-child { .support-plan-type-form { position: relative; - top: -25px; + top: -10px; } .sponsorship-pending-form { @@ -86,7 +86,7 @@ tr.admin td:first-child { .current-plan-details { position: relative; - top: -50px; + top: -15px; } .approve-sponsorship-form { @@ -120,7 +120,7 @@ tr.admin td:first-child { .support-submit-button { position: relative; - top: -5px; + top: -3px; border-color: hsl(0, 0%, 83%); border-radius: 2px; } diff --git a/templates/analytics/realm_details.html b/templates/analytics/realm_details.html index aa00338ef5..9be5b16e47 100644 --- a/templates/analytics/realm_details.html +++ b/templates/analytics/realm_details.html @@ -18,6 +18,13 @@ +
+ New subdomain:
+ {{ csrf_input }} + + + +
Plan type:
{{ csrf_input }} diff --git a/templates/analytics/support.html b/templates/analytics/support.html index beda625a0f..4bd256c70b 100644 --- a/templates/analytics/support.html +++ b/templates/analytics/support.html @@ -7,7 +7,6 @@ Info {% endblock %} - {% block content %}

@@ -18,7 +17,13 @@ - {% if success_message %} + {% if error_message %} +
+
+ {{ error_message }} +
+
+ {% elif success_message %}
{{ success_message }}