mirror of https://github.com/zulip/zulip.git
analytics/support: Add ability to edit realm org type.
This commit is contained in:
parent
bac64070c1
commit
f25230c7d4
|
@ -71,12 +71,10 @@ class TestSupportEndpoint(ZulipTestCase):
|
||||||
|
|
||||||
def check_zulip_realm_query_result(result: HttpResponse) -> None:
|
def check_zulip_realm_query_result(result: HttpResponse) -> None:
|
||||||
zulip_realm = get_realm("zulip")
|
zulip_realm = get_realm("zulip")
|
||||||
org_type_display_name = get_org_type_display_name(zulip_realm.org_type)
|
|
||||||
first_human_user = zulip_realm.get_first_human_user()
|
first_human_user = zulip_realm.get_first_human_user()
|
||||||
assert first_human_user is not None
|
assert first_human_user is not None
|
||||||
self.assert_in_success_response(
|
self.assert_in_success_response(
|
||||||
[
|
[
|
||||||
f"<b>Organization type</b>: {org_type_display_name}",
|
|
||||||
f"<b>First human user</b>: {first_human_user.delivery_email}\n",
|
f"<b>First human user</b>: {first_human_user.delivery_email}\n",
|
||||||
f'<input type="hidden" name="realm_id" value="{zulip_realm.id}"',
|
f'<input type="hidden" name="realm_id" value="{zulip_realm.id}"',
|
||||||
"Zulip Dev</h3>",
|
"Zulip Dev</h3>",
|
||||||
|
@ -85,6 +83,7 @@ class TestSupportEndpoint(ZulipTestCase):
|
||||||
'input type="number" name="discount" value="None"',
|
'input type="number" name="discount" value="None"',
|
||||||
'<option value="active" selected>Active</option>',
|
'<option value="active" selected>Active</option>',
|
||||||
'<option value="deactivated" >Deactivated</option>',
|
'<option value="deactivated" >Deactivated</option>',
|
||||||
|
f'<option value="{zulip_realm.org_type}" selected>',
|
||||||
'scrub-realm-button">',
|
'scrub-realm-button">',
|
||||||
'data-string-id="zulip"',
|
'data-string-id="zulip"',
|
||||||
],
|
],
|
||||||
|
@ -357,6 +356,28 @@ class TestSupportEndpoint(ZulipTestCase):
|
||||||
["Plan type of zulip changed from self hosted to limited"], result
|
["Plan type of zulip changed from self hosted to limited"], result
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_change_org_type(self) -> None:
|
||||||
|
cordelia = self.example_user("cordelia")
|
||||||
|
self.login_user(cordelia)
|
||||||
|
|
||||||
|
result = self.client_post(
|
||||||
|
"/activity/support", {"realm_id": f"{cordelia.realm_id}", "org_type": "70"}
|
||||||
|
)
|
||||||
|
self.assertEqual(result.status_code, 302)
|
||||||
|
self.assertEqual(result["Location"], "/login/")
|
||||||
|
|
||||||
|
iago = self.example_user("iago")
|
||||||
|
self.login_user(iago)
|
||||||
|
|
||||||
|
with mock.patch("analytics.views.support.do_change_realm_org_type") as m:
|
||||||
|
result = self.client_post(
|
||||||
|
"/activity/support", {"realm_id": f"{iago.realm_id}", "org_type": "70"}
|
||||||
|
)
|
||||||
|
m.assert_called_once_with(get_realm("zulip"), 70, acting_user=iago)
|
||||||
|
self.assert_in_success_response(
|
||||||
|
["Org type of zulip changed from Business to Government"], result
|
||||||
|
)
|
||||||
|
|
||||||
def test_attach_discount(self) -> None:
|
def test_attach_discount(self) -> None:
|
||||||
cordelia = self.example_user("cordelia")
|
cordelia = self.example_user("cordelia")
|
||||||
lear_realm = get_realm("lear")
|
lear_realm = get_realm("lear")
|
||||||
|
|
|
@ -20,6 +20,7 @@ from zerver.decorator import require_server_admin
|
||||||
from zerver.forms import check_subdomain_available
|
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_org_type,
|
||||||
do_change_realm_subdomain,
|
do_change_realm_subdomain,
|
||||||
do_deactivate_realm,
|
do_deactivate_realm,
|
||||||
do_scrub_realm,
|
do_scrub_realm,
|
||||||
|
@ -139,6 +140,7 @@ def support(
|
||||||
),
|
),
|
||||||
scrub_realm: Optional[bool] = REQ(default=None, json_validator=check_bool),
|
scrub_realm: Optional[bool] = REQ(default=None, json_validator=check_bool),
|
||||||
query: Optional[str] = REQ("q", default=None),
|
query: Optional[str] = REQ("q", default=None),
|
||||||
|
org_type: Optional[int] = REQ(default=None, converter=to_non_negative_int),
|
||||||
) -> HttpResponse:
|
) -> HttpResponse:
|
||||||
context: Dict[str, Any] = {}
|
context: Dict[str, Any] = {}
|
||||||
|
|
||||||
|
@ -164,6 +166,11 @@ def support(
|
||||||
do_change_plan_type(realm, plan_type, acting_user=acting_user)
|
do_change_plan_type(realm, plan_type, acting_user=acting_user)
|
||||||
msg = f"Plan type of {realm.string_id} changed from {get_plan_name(current_plan_type)} to {get_plan_name(plan_type)} "
|
msg = f"Plan type of {realm.string_id} changed from {get_plan_name(current_plan_type)} to {get_plan_name(plan_type)} "
|
||||||
context["success_message"] = msg
|
context["success_message"] = msg
|
||||||
|
elif org_type is not None:
|
||||||
|
current_realm_type = realm.org_type
|
||||||
|
do_change_realm_org_type(realm, org_type, acting_user=acting_user)
|
||||||
|
msg = f"Org type of {realm.string_id} changed from {get_org_type_display_name(current_realm_type)} to {get_org_type_display_name(org_type)} "
|
||||||
|
context["success_message"] = msg
|
||||||
elif discount is not None:
|
elif discount is not None:
|
||||||
current_discount = get_discount_for_realm(realm) or 0
|
current_discount = get_discount_for_realm(realm) or 0
|
||||||
attach_discount_to_realm(realm, discount, acting_user=acting_user)
|
attach_discount_to_realm(realm, discount, acting_user=acting_user)
|
||||||
|
@ -321,4 +328,8 @@ def support(
|
||||||
context["get_org_type_display_name"] = get_org_type_display_name
|
context["get_org_type_display_name"] = get_org_type_display_name
|
||||||
context["realm_icon_url"] = realm_icon_url
|
context["realm_icon_url"] = realm_icon_url
|
||||||
context["Confirmation"] = Confirmation
|
context["Confirmation"] = Confirmation
|
||||||
|
context["sorted_realm_types"] = sorted(
|
||||||
|
Realm.ORG_TYPES.values(), key=lambda d: d["display_order"]
|
||||||
|
)
|
||||||
|
|
||||||
return render(request, "analytics/support.html", context=context)
|
return render(request, "analytics/support.html", context=context)
|
||||||
|
|
|
@ -4,8 +4,6 @@
|
||||||
<a target="_blank" rel="noopener noreferrer" href="/stats/realm/{{ realm.string_id }}/">stats</a> |
|
<a target="_blank" rel="noopener noreferrer" href="/stats/realm/{{ realm.string_id }}/">stats</a> |
|
||||||
<a target="_blank" rel="noopener noreferrer" href="/realm_activity/{{ realm.string_id }}/">activity</a><br />
|
<a target="_blank" rel="noopener noreferrer" href="/realm_activity/{{ realm.string_id }}/">activity</a><br />
|
||||||
<b>Date created</b>: {{ realm.date_created|timesince }} ago<br />
|
<b>Date created</b>: {{ realm.date_created|timesince }} ago<br />
|
||||||
{% set org_type_display_name = get_org_type_display_name(realm.org_type) %}
|
|
||||||
<b>Organization type</b>: {{ org_type_display_name }}<br />
|
|
||||||
{% set owner_emails_string = get_realm_owner_emails_as_string(realm) %}
|
{% set owner_emails_string = get_realm_owner_emails_as_string(realm) %}
|
||||||
<b>Owners</b>: {{ owner_emails_string }}
|
<b>Owners</b>: {{ owner_emails_string }}
|
||||||
{% if owner_emails_string %}
|
{% if owner_emails_string %}
|
||||||
|
@ -49,6 +47,21 @@
|
||||||
<input type="text" name="new_subdomain" required />
|
<input type="text" name="new_subdomain" required />
|
||||||
<button type="submit" class="btn btn-default support-submit-button">Update</button>
|
<button type="submit" class="btn btn-default support-submit-button">Update</button>
|
||||||
</form>
|
</form>
|
||||||
|
<form method="POST">
|
||||||
|
<b>Org type</b>:<br />
|
||||||
|
{{ csrf_input }}
|
||||||
|
<input type="hidden" name="realm_id" value="{{ realm.id }}" />
|
||||||
|
<select name="org_type" id="org_type">
|
||||||
|
{% for realm_type in sorted_realm_types %}
|
||||||
|
{% if not realm_type.hidden %}
|
||||||
|
<option value="{{ realm_type.id }}" {% if realm.org_type == realm_type.id %}selected{% endif %}>
|
||||||
|
{{ _(realm_type.name) }}
|
||||||
|
</option>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
<button type="submit" class="btn btn-default 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 }}
|
||||||
|
|
|
@ -4582,6 +4582,24 @@ def do_change_logo_source(
|
||||||
send_event(realm, event, active_user_ids(realm.id))
|
send_event(realm, event, active_user_ids(realm.id))
|
||||||
|
|
||||||
|
|
||||||
|
def do_change_realm_org_type(
|
||||||
|
realm: Realm,
|
||||||
|
org_type: int,
|
||||||
|
acting_user: Optional[UserProfile],
|
||||||
|
) -> None:
|
||||||
|
old_value = realm.org_type
|
||||||
|
realm.org_type = org_type
|
||||||
|
realm.save(update_fields=["org_type"])
|
||||||
|
|
||||||
|
RealmAuditLog.objects.create(
|
||||||
|
event_type=RealmAuditLog.REALM_ORG_TYPE_CHANGED,
|
||||||
|
realm=realm,
|
||||||
|
event_time=timezone_now(),
|
||||||
|
acting_user=acting_user,
|
||||||
|
extra_data={"old_value": old_value, "new_value": org_type},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def do_change_plan_type(
|
def do_change_plan_type(
|
||||||
realm: Realm, plan_type: int, *, acting_user: Optional[UserProfile]
|
realm: Realm, plan_type: int, *, acting_user: Optional[UserProfile]
|
||||||
) -> None:
|
) -> None:
|
||||||
|
|
|
@ -3769,6 +3769,7 @@ class AbstractRealmAuditLog(models.Model):
|
||||||
REALM_SUBDOMAIN_CHANGED = 214
|
REALM_SUBDOMAIN_CHANGED = 214
|
||||||
REALM_CREATED = 215
|
REALM_CREATED = 215
|
||||||
REALM_DEFAULT_USER_SETTINGS_CHANGED = 216
|
REALM_DEFAULT_USER_SETTINGS_CHANGED = 216
|
||||||
|
REALM_ORG_TYPE_CHANGED = 217
|
||||||
|
|
||||||
SUBSCRIPTION_CREATED = 301
|
SUBSCRIPTION_CREATED = 301
|
||||||
SUBSCRIPTION_ACTIVATED = 302
|
SUBSCRIPTION_ACTIVATED = 302
|
||||||
|
|
|
@ -11,6 +11,7 @@ from confirmation.models import Confirmation, create_confirmation_link
|
||||||
from zerver.lib.actions import (
|
from zerver.lib.actions import (
|
||||||
do_add_deactivated_redirect,
|
do_add_deactivated_redirect,
|
||||||
do_change_plan_type,
|
do_change_plan_type,
|
||||||
|
do_change_realm_org_type,
|
||||||
do_change_realm_subdomain,
|
do_change_realm_subdomain,
|
||||||
do_create_realm,
|
do_create_realm,
|
||||||
do_deactivate_realm,
|
do_deactivate_realm,
|
||||||
|
@ -611,6 +612,25 @@ class RealmTest(ZulipTestCase):
|
||||||
self.assertEqual(get_realm("onpremise").message_visibility_limit, None)
|
self.assertEqual(get_realm("onpremise").message_visibility_limit, None)
|
||||||
self.assertEqual(get_realm("onpremise").upload_quota_gb, None)
|
self.assertEqual(get_realm("onpremise").upload_quota_gb, None)
|
||||||
|
|
||||||
|
def test_change_org_type(self) -> None:
|
||||||
|
realm = get_realm("zulip")
|
||||||
|
iago = self.example_user("iago")
|
||||||
|
self.assertEqual(realm.org_type, Realm.ORG_TYPES["business"]["id"])
|
||||||
|
|
||||||
|
do_change_realm_org_type(realm, Realm.ORG_TYPES["government"]["id"], acting_user=iago)
|
||||||
|
realm = get_realm("zulip")
|
||||||
|
realm_audit_log = RealmAuditLog.objects.filter(
|
||||||
|
event_type=RealmAuditLog.REALM_ORG_TYPE_CHANGED
|
||||||
|
).last()
|
||||||
|
assert realm_audit_log is not None
|
||||||
|
expected_extra_data = {
|
||||||
|
"old_value": Realm.ORG_TYPES["business"]["id"],
|
||||||
|
"new_value": Realm.ORG_TYPES["government"]["id"],
|
||||||
|
}
|
||||||
|
self.assertEqual(realm_audit_log.extra_data, str(expected_extra_data))
|
||||||
|
self.assertEqual(realm_audit_log.acting_user, iago)
|
||||||
|
self.assertEqual(realm.org_type, Realm.ORG_TYPES["government"]["id"])
|
||||||
|
|
||||||
def test_change_plan_type(self) -> None:
|
def test_change_plan_type(self) -> None:
|
||||||
realm = get_realm("zulip")
|
realm = get_realm("zulip")
|
||||||
iago = self.example_user("iago")
|
iago = self.example_user("iago")
|
||||||
|
|
Loading…
Reference in New Issue