mirror of https://github.com/zulip/zulip.git
support: Add basic information about realm.
Adds non-form section to Zulip Cloud support view with some basic realm information: organization type, plan type, non-guest user count and guest user count. Uses a shared template for the basic realm data and adds a shared support context dict for variables that are used in both remote and Zulip Cloud support views.
This commit is contained in:
parent
349954e4fc
commit
44e73eecc1
|
@ -154,23 +154,27 @@ def get_cached_seat_count(realm: Realm) -> int:
|
||||||
return get_latest_seat_count(realm)
|
return get_latest_seat_count(realm)
|
||||||
|
|
||||||
|
|
||||||
def get_seat_count(
|
def get_non_guest_user_count(realm: Realm) -> int:
|
||||||
realm: Realm, extra_non_guests_count: int = 0, extra_guests_count: int = 0
|
return (
|
||||||
) -> int:
|
|
||||||
non_guests = (
|
|
||||||
UserProfile.objects.filter(realm=realm, is_active=True, is_bot=False)
|
UserProfile.objects.filter(realm=realm, is_active=True, is_bot=False)
|
||||||
.exclude(role=UserProfile.ROLE_GUEST)
|
.exclude(role=UserProfile.ROLE_GUEST)
|
||||||
.count()
|
.count()
|
||||||
) + extra_non_guests_count
|
|
||||||
|
|
||||||
# This guest count calculation should match the similar query in render_stats().
|
|
||||||
guests = (
|
|
||||||
UserProfile.objects.filter(
|
|
||||||
realm=realm, is_active=True, is_bot=False, role=UserProfile.ROLE_GUEST
|
|
||||||
).count()
|
|
||||||
+ extra_guests_count
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get_guest_user_count(realm: Realm) -> int:
|
||||||
|
# Same query to get guest user count as in render_stats in analytics/views/stats.py.
|
||||||
|
return UserProfile.objects.filter(
|
||||||
|
realm=realm, is_active=True, is_bot=False, role=UserProfile.ROLE_GUEST
|
||||||
|
).count()
|
||||||
|
|
||||||
|
|
||||||
|
def get_seat_count(
|
||||||
|
realm: Realm, extra_non_guests_count: int = 0, extra_guests_count: int = 0
|
||||||
|
) -> int:
|
||||||
|
non_guests = get_non_guest_user_count(realm) + extra_non_guests_count
|
||||||
|
guests = get_guest_user_count(realm) + extra_guests_count
|
||||||
|
|
||||||
# This formula achieves the pricing of the first 5*N guests
|
# This formula achieves the pricing of the first 5*N guests
|
||||||
# being free of charge (where N is the number of non-guests in the organization)
|
# being free of charge (where N is the number of non-guests in the organization)
|
||||||
# and each consecutive one being worth 1/5 the non-guest price.
|
# and each consecutive one being worth 1/5 the non-guest price.
|
||||||
|
|
|
@ -15,6 +15,8 @@ from corporate.lib.stripe import (
|
||||||
RemoteRealmBillingSession,
|
RemoteRealmBillingSession,
|
||||||
RemoteServerBillingSession,
|
RemoteServerBillingSession,
|
||||||
get_configured_fixed_price_plan_offer,
|
get_configured_fixed_price_plan_offer,
|
||||||
|
get_guest_user_count,
|
||||||
|
get_non_guest_user_count,
|
||||||
get_price_per_license,
|
get_price_per_license,
|
||||||
get_push_status_for_remote_request,
|
get_push_status_for_remote_request,
|
||||||
start_of_next_billing_cycle,
|
start_of_next_billing_cycle,
|
||||||
|
@ -110,10 +112,17 @@ class RemoteSupportData:
|
||||||
mobile_push_data: MobilePushData
|
mobile_push_data: MobilePushData
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class UserData:
|
||||||
|
guest_user_count: int
|
||||||
|
non_guest_user_count: int
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class CloudSupportData:
|
class CloudSupportData:
|
||||||
plan_data: PlanData
|
plan_data: PlanData
|
||||||
sponsorship_data: SponsorshipData
|
sponsorship_data: SponsorshipData
|
||||||
|
user_data: UserData
|
||||||
|
|
||||||
|
|
||||||
def get_stripe_customer_url(stripe_id: str) -> str:
|
def get_stripe_customer_url(stripe_id: str) -> str:
|
||||||
|
@ -129,6 +138,15 @@ def get_realm_support_url(realm: Realm) -> str:
|
||||||
return support_url
|
return support_url
|
||||||
|
|
||||||
|
|
||||||
|
def get_realm_user_data(realm: Realm) -> UserData:
|
||||||
|
non_guests = get_non_guest_user_count(realm)
|
||||||
|
guests = get_guest_user_count(realm)
|
||||||
|
return UserData(
|
||||||
|
guest_user_count=guests,
|
||||||
|
non_guest_user_count=non_guests,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_customer_sponsorship_data(customer: Customer) -> SponsorshipData:
|
def get_customer_sponsorship_data(customer: Customer) -> SponsorshipData:
|
||||||
pending = customer.sponsorship_pending
|
pending = customer.sponsorship_pending
|
||||||
licenses = customer.minimum_licenses
|
licenses = customer.minimum_licenses
|
||||||
|
@ -421,6 +439,7 @@ def get_data_for_remote_support_view(billing_session: BillingSession) -> RemoteS
|
||||||
|
|
||||||
def get_data_for_cloud_support_view(billing_session: BillingSession) -> CloudSupportData:
|
def get_data_for_cloud_support_view(billing_session: BillingSession) -> CloudSupportData:
|
||||||
assert isinstance(billing_session, RealmBillingSession)
|
assert isinstance(billing_session, RealmBillingSession)
|
||||||
|
user_data = get_realm_user_data(billing_session.realm)
|
||||||
plan_data = get_plan_data_for_support_view(billing_session)
|
plan_data = get_plan_data_for_support_view(billing_session)
|
||||||
if plan_data.customer is not None:
|
if plan_data.customer is not None:
|
||||||
sponsorship_data = get_customer_sponsorship_data(plan_data.customer)
|
sponsorship_data = get_customer_sponsorship_data(plan_data.customer)
|
||||||
|
@ -430,4 +449,5 @@ def get_data_for_cloud_support_view(billing_session: BillingSession) -> CloudSup
|
||||||
return CloudSupportData(
|
return CloudSupportData(
|
||||||
plan_data=plan_data,
|
plan_data=plan_data,
|
||||||
sponsorship_data=sponsorship_data,
|
sponsorship_data=sponsorship_data,
|
||||||
|
user_data=user_data,
|
||||||
)
|
)
|
||||||
|
|
|
@ -747,7 +747,7 @@ class TestSupportEndpoint(ZulipTestCase):
|
||||||
def test_realm_support_view_queries(self) -> None:
|
def test_realm_support_view_queries(self) -> None:
|
||||||
iago = self.example_user("iago")
|
iago = self.example_user("iago")
|
||||||
self.login_user(iago)
|
self.login_user(iago)
|
||||||
with self.assert_database_query_count(16):
|
with self.assert_database_query_count(18):
|
||||||
result = self.client_get("/activity/support", {"q": "zulip"}, subdomain="zulip")
|
result = self.client_get("/activity/support", {"q": "zulip"}, subdomain="zulip")
|
||||||
self.assertEqual(result.status_code, 200)
|
self.assertEqual(result.status_code, 200)
|
||||||
|
|
||||||
|
|
|
@ -344,6 +344,12 @@ VALID_BILLING_MODALITY_VALUES = Literal[
|
||||||
"charge_automatically",
|
"charge_automatically",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
SHARED_SUPPORT_CONTEXT = {
|
||||||
|
"get_org_type_display_name": get_org_type_display_name,
|
||||||
|
"get_plan_type_name": get_plan_type_string,
|
||||||
|
"dollar_amount": cents_to_dollar_string,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@require_server_admin
|
@require_server_admin
|
||||||
@typed_endpoint
|
@typed_endpoint
|
||||||
|
@ -368,7 +374,7 @@ def support(
|
||||||
org_type: Json[NonNegativeInt] | None = None,
|
org_type: Json[NonNegativeInt] | None = None,
|
||||||
max_invites: Json[NonNegativeInt] | None = None,
|
max_invites: Json[NonNegativeInt] | None = None,
|
||||||
) -> HttpResponse:
|
) -> HttpResponse:
|
||||||
context: dict[str, Any] = {}
|
context: dict[str, Any] = {**SHARED_SUPPORT_CONTEXT}
|
||||||
|
|
||||||
if "success_message" in request.session:
|
if "success_message" in request.session:
|
||||||
context["success_message"] = request.session["success_message"]
|
context["success_message"] = request.session["success_message"]
|
||||||
|
@ -602,7 +608,6 @@ def support(
|
||||||
|
|
||||||
context["get_realm_owner_emails_as_string"] = get_realm_owner_emails_as_string
|
context["get_realm_owner_emails_as_string"] = get_realm_owner_emails_as_string
|
||||||
context["get_realm_admin_emails_as_string"] = get_realm_admin_emails_as_string
|
context["get_realm_admin_emails_as_string"] = get_realm_admin_emails_as_string
|
||||||
context["dollar_amount"] = cents_to_dollar_string
|
|
||||||
context["realm_icon_url"] = realm_icon_url
|
context["realm_icon_url"] = realm_icon_url
|
||||||
context["Confirmation"] = Confirmation
|
context["Confirmation"] = Confirmation
|
||||||
context["REALM_PLAN_TYPES"] = get_realm_plan_type_options()
|
context["REALM_PLAN_TYPES"] = get_realm_plan_type_options()
|
||||||
|
@ -691,7 +696,7 @@ def remote_servers_support(
|
||||||
]
|
]
|
||||||
| None = None,
|
| None = None,
|
||||||
) -> HttpResponse:
|
) -> HttpResponse:
|
||||||
context: dict[str, Any] = {}
|
context: dict[str, Any] = {**SHARED_SUPPORT_CONTEXT}
|
||||||
|
|
||||||
if "success_message" in request.session:
|
if "success_message" in request.session:
|
||||||
context["success_message"] = request.session["success_message"]
|
context["success_message"] = request.session["success_message"]
|
||||||
|
@ -876,10 +881,7 @@ def remote_servers_support(
|
||||||
context["remote_server_to_max_monthly_messages"] = remote_server_to_max_monthly_messages
|
context["remote_server_to_max_monthly_messages"] = remote_server_to_max_monthly_messages
|
||||||
context["remote_realms"] = remote_realms
|
context["remote_realms"] = remote_realms
|
||||||
context["remote_realms_support_data"] = realm_support_data
|
context["remote_realms_support_data"] = realm_support_data
|
||||||
context["get_plan_type_name"] = get_plan_type_string
|
|
||||||
context["get_org_type_display_name"] = get_org_type_display_name
|
|
||||||
context["format_optional_datetime"] = format_optional_datetime
|
context["format_optional_datetime"] = format_optional_datetime
|
||||||
context["dollar_amount"] = cents_to_dollar_string
|
|
||||||
context["server_analytics_link"] = remote_installation_stats_link
|
context["server_analytics_link"] = remote_installation_stats_link
|
||||||
context["REMOTE_PLAN_TIERS"] = get_remote_plan_tier_options()
|
context["REMOTE_PLAN_TIERS"] = get_remote_plan_tier_options()
|
||||||
context["get_remote_server_billing_user_emails"] = (
|
context["get_remote_server_billing_user_emails"] = (
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
<b>Organization type</b>: {{ get_org_type_display_name(realm.org_type) }}<br />
|
||||||
|
<b>Plan type</b>: {{ get_plan_type_name(realm.plan_type) }}<br />
|
||||||
|
<b>Non-guest user count</b>: {{ user_data.non_guest_user_count }}<br />
|
||||||
|
<b>Guest user count</b>: {{ user_data.guest_user_count }}<br />
|
|
@ -33,9 +33,17 @@
|
||||||
<a title="Copy emails" class="copy-button" data-clipboard-text="{{ first_human_user.delivery_email }}">
|
<a title="Copy emails" class="copy-button" data-clipboard-text="{{ first_human_user.delivery_email }}">
|
||||||
<i class="fa fa-copy"></i>
|
<i class="fa fa-copy"></i>
|
||||||
</a>
|
</a>
|
||||||
|
<br />
|
||||||
{% else %}
|
{% else %}
|
||||||
<b>First human user</b>:
|
<b>First human user</b>:
|
||||||
|
<br />
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
<br />
|
||||||
|
{% with %}
|
||||||
|
{% set realm = realm %}
|
||||||
|
{% set user_data = realm_support_data[realm.id].user_data %}
|
||||||
|
{% include 'corporate/support/basic_realm_data.html' %}
|
||||||
|
{% endwith %}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div class="realm-management-actions">
|
<div class="realm-management-actions">
|
||||||
|
|
|
@ -29,10 +29,11 @@
|
||||||
<b>Date created</b>: {{ support_data[remote_realm.id].date_created.strftime('%d %B %Y') }}<br />
|
<b>Date created</b>: {{ support_data[remote_realm.id].date_created.strftime('%d %B %Y') }}<br />
|
||||||
<b>UUID</b>: {{ remote_realm.uuid }}<br />
|
<b>UUID</b>: {{ remote_realm.uuid }}<br />
|
||||||
<br />
|
<br />
|
||||||
<b>Organization type</b>: {{ get_org_type_display_name(remote_realm.org_type) }}<br />
|
{% with %}
|
||||||
<b>Plan type</b>: {{ get_plan_type_name(remote_realm.plan_type) }}<br />
|
{% set realm = remote_realm %}
|
||||||
<b>Non-guest user count</b>: {{ support_data[remote_realm.id].user_data.non_guest_user_count }}<br />
|
{% set user_data = support_data[remote_realm.id].user_data %}
|
||||||
<b>Guest user count</b>: {{ support_data[remote_realm.id].user_data.guest_user_count }}<br />
|
{% include 'corporate/support/basic_realm_data.html' %}
|
||||||
|
{% endwith %}
|
||||||
<br />
|
<br />
|
||||||
<b>Mobile user count</b>: {{ support_data[remote_realm.id].mobile_push_data.total_mobile_users }}<br />
|
<b>Mobile user count</b>: {{ support_data[remote_realm.id].mobile_push_data.total_mobile_users }}<br />
|
||||||
<b>7-day mobile pushes count</b>: {{ support_data[remote_realm.id].mobile_push_data.mobile_pushes_forwarded }}<br />
|
<b>7-day mobile pushes count</b>: {{ support_data[remote_realm.id].mobile_push_data.mobile_pushes_forwarded }}<br />
|
||||||
|
|
Loading…
Reference in New Issue