Repository: zulip/zulip

Issue:
Add summary statistics to /stats page
At present, it can be hard to find basic statistics about a Zulip organization. They may be hidden deep in the menus, or require careful parsing of graphs.

To address this, we should display summary statistics at the top of the organization's `/stats` page that answer the most common questions an administrator might have about their organization. In particular, we should show:

1) Number of users: Current number of non-deactivated users
2) Number of guests: This is relevant because of the details of [how Zulip Cloud orgs are billed](https://zulip.com/help/zulip-cloud-billing#how-are-guest-accounts-billed-is-there-special-pricing).
2) Total number of messages
4) Number of messages in the last 30 days
5) Storage space in use (currently shown under Personal settings > Uploaded files, e.g. "Organization using 0.0% of 5 GB."

[CZO discussion thread](https://chat.zulip.org/#narrow/stream/2-general/topic/showing.20org.20storage.20use)


Discussion:
Hello @zulip/server-analytics members, this issue was labeled with the "area: analytics" label, so you may want to check it out!

<!-- areaLabelAddition -->

@zulipbot claim
Hello @Parth-Mittal-NITK, it looks like you've currently claimed 1 issue in this repository. We encourage new contributors to focus their efforts on at most 1 issue at a time, so please complete your work on your other claimed issues before trying to claim this issue again.

We look forward to your valuable contributions!

@zulipbot claim
Hi @mittal-parth , any progress on this one?
I am so sorry @alya, got caught up with college work. I had understood the existing code to some extent and was building the layout . Since I will be able to take it up only after a week, I'll leave it for someone else to take it up if interested. If not, I'll resume after a week.
@zulipbot abandon
Hi @alya! This seems like an interesting feature. Do you have any design for the summary stats in mind? It would be wonderful if you can suggest some CSS or existing templates from which we can get some ideas.
@oliver-pham Have you explored the code for the `/stats` page?

Once you have done so, you can post your thoughts and get feedback on chat.zulip.org (in #frontend for more technical discussion, or #design to discuss what it would look like).
Hi @oliver-pham! Since I had gotten some idea about the code around stats, it would be great if you can do the designing and I can fetch the data from the backend. Let me know if that sounds good! 😄 
I'm not a designer myself, but I can try to help you with the design. I've created a topic for this in #frontend on (on chat.zulip.org) and suggested some ideas. Before claiming the issue, can we discuss your approaches in #frontend, @mittal-parth?

Resolving patch:
diff --git a/analytics/management/commands/populate_analytics_db.py b/analytics/management/commands/populate_analytics_db.py
--- a/analytics/management/commands/populate_analytics_db.py
+++ b/analytics/management/commands/populate_analytics_db.py
@@ -92,6 +92,16 @@ def handle(self, *args: Any, **options: Any) -> None:
         )
         do_change_user_role(shylock, UserProfile.ROLE_REALM_OWNER, acting_user=None)
 
+        # Create guest user for set_guest_users_statistic.
+        create_user(
+            "bassanio@analytics.ds",
+            "Bassanio",
+            realm,
+            full_name="Bassanio",
+            role=UserProfile.ROLE_GUEST,
+            force_date_joined=installation_time,
+        )
+
         administrators_user_group = UserGroup.objects.get(
             name=UserGroup.ADMINISTRATORS_GROUP_NAME, realm=realm, is_system_group=True
         )
diff --git a/analytics/views/stats.py b/analytics/views/stats.py
--- a/analytics/views/stats.py
+++ b/analytics/views/stats.py
@@ -55,11 +55,18 @@ def render_stats(
     analytics_ready: bool = True,
 ) -> HttpResponse:
     assert request.user.is_authenticated
+
+    # Same query to get guest user count as in get_seat_count in corporate/lib/stripe.py.
+    guest_users = UserProfile.objects.filter(
+        realm=request.user.realm, is_active=True, is_bot=False, role=UserProfile.ROLE_GUEST
+    ).count()
+
     page_params = dict(
         data_url_suffix=data_url_suffix,
         for_installation=for_installation,
         remote=remote,
         upload_space_used=request.user.realm.currently_used_upload_space_bytes(),
+        guest_users=guest_users,
     )
 
     request_language = get_and_set_request_language(
diff --git a/corporate/lib/stripe.py b/corporate/lib/stripe.py
--- a/corporate/lib/stripe.py
+++ b/corporate/lib/stripe.py
@@ -69,6 +69,8 @@ def get_seat_count(
         .exclude(role=UserProfile.ROLE_GUEST)
         .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


Test patch: