From 5479053a9f8d68edf748fec3d323374a3ed75865 Mon Sep 17 00:00:00 2001 From: Lauryn Menard Date: Mon, 5 Feb 2024 19:07:13 +0100 Subject: [PATCH] remote-support: Add server data for last audit log update time. This is useful in the support view in case the audit log data is stale and user counts are not updated for billing. Also, renames formatting function for optional datetimes that is used in the support and activity views/charts. And instead of showing these datetime strings in the eastern US timezone, we now show and label them as UTC. --- corporate/lib/activity.py | 14 ++++---------- corporate/views/installation_activity.py | 8 ++++---- corporate/views/realm_activity.py | 10 +++++----- corporate/views/remote_activity.py | 6 +++--- corporate/views/support.py | 3 ++- corporate/views/user_activity.py | 6 +++--- .../corporate/support/remote_server_support.html | 1 + 7 files changed, 22 insertions(+), 26 deletions(-) diff --git a/corporate/lib/activity.py b/corporate/lib/activity.py index b1111cfbbe..29db65cbfb 100644 --- a/corporate/lib/activity.py +++ b/corporate/lib/activity.py @@ -1,4 +1,3 @@ -import sys from collections import defaultdict from dataclasses import dataclass from datetime import datetime @@ -34,13 +33,6 @@ from zilencer.models import ( get_remote_customer_user_count, ) -if sys.version_info < (3, 9): # nocoverage - from backports import zoneinfo -else: # nocoverage - import zoneinfo - -eastern_tz = zoneinfo.ZoneInfo("America/New_York") - @dataclass class RemoteActivityPlanData: @@ -100,9 +92,11 @@ def dictfetchall(cursor: CursorWrapper) -> List[Dict[str, Any]]: return [dict(zip((col[0] for col in desc), row)) for row in cursor.fetchall()] -def format_date_for_activity_reports(date: Optional[datetime]) -> str: +def format_optional_datetime(date: Optional[datetime], display_none: bool = False) -> str: if date: - return date.astimezone(eastern_tz).strftime("%Y-%m-%d %H:%M") + return date.strftime("%Y-%m-%d %H:%M") + elif display_none: + return "None" else: return "" diff --git a/corporate/views/installation_activity.py b/corporate/views/installation_activity.py index 491cef1e3c..a9bc5a00b8 100644 --- a/corporate/views/installation_activity.py +++ b/corporate/views/installation_activity.py @@ -15,7 +15,7 @@ from corporate.lib.activity import ( dictfetchall, estimate_annual_recurring_revenue_by_realm, fix_rows, - format_date_for_activity_reports, + format_optional_datetime, get_query_data, get_realms_with_default_discount_dict, make_table, @@ -331,15 +331,15 @@ def get_integrations_activity(request: HttpRequest) -> HttpResponse: "Client", "Realm", "Hits", - "Last time", + "Last time (UTC)", ] rows = get_query_data(query) for i, col in enumerate(cols): if col == "Realm": fix_rows(rows, i, realm_activity_link) - elif col == "Last time": - fix_rows(rows, i, format_date_for_activity_reports) + elif col == "Last time (UTC)": + fix_rows(rows, i, format_optional_datetime) content = make_table(title, cols, rows) return render( diff --git a/corporate/views/realm_activity.py b/corporate/views/realm_activity.py index 0ef67e3816..648a369bb3 100644 --- a/corporate/views/realm_activity.py +++ b/corporate/views/realm_activity.py @@ -11,7 +11,7 @@ from django.utils.timezone import now as timezone_now from markupsafe import Markup from corporate.lib.activity import ( - format_date_for_activity_reports, + format_optional_datetime, make_table, realm_stats_link, user_activity_link, @@ -116,8 +116,8 @@ def realm_user_summary_table( "Email", "User type", "Messages sent", - "Last heard from", - "Last message sent", + "Last heard from (UTC)", + "Last message sent (UTC)", ] rows = [] @@ -129,8 +129,8 @@ def realm_user_summary_table( user_summary.user_type, user_summary.messages_sent, ] - cells.append(format_date_for_activity_reports(user_summary.last_heard_from)) - cells.append(format_date_for_activity_reports(user_summary.last_message_sent)) + cells.append(format_optional_datetime(user_summary.last_heard_from)) + cells.append(format_optional_datetime(user_summary.last_message_sent)) row_class = "" if user_summary.last_heard_from and is_recent(user_summary.last_heard_from): diff --git a/corporate/views/remote_activity.py b/corporate/views/remote_activity.py index 3023c8d933..917cada65a 100644 --- a/corporate/views/remote_activity.py +++ b/corporate/views/remote_activity.py @@ -4,8 +4,8 @@ from psycopg2.sql import SQL from corporate.lib.activity import ( fix_rows, - format_date_for_activity_reports, format_none_as_zero, + format_optional_datetime, get_plan_data_by_remote_realm, get_plan_data_by_remote_server, get_query_data, @@ -85,7 +85,7 @@ def get_remote_server_activity(request: HttpRequest) -> HttpResponse: "Realm host or server hostname", "Server contact email", "Server Zulip version", - "Server last audit log update", + "Server last audit log update (UTC)", "Server mobile users", "Server mobile pushes", "Realm organization type", @@ -199,7 +199,7 @@ def get_remote_server_activity(request: HttpRequest) -> HttpResponse: # Format column data and add total row for i, col in enumerate(cols): if i == LAST_AUDIT_LOG_DATE: - fix_rows(rows, i, format_date_for_activity_reports) + fix_rows(rows, i, format_optional_datetime) if i in [MOBILE_USER_COUNT, MOBILE_PUSH_COUNT]: fix_rows(rows, i, format_none_as_zero) if i == SERVER_AND_REALM_IDS: diff --git a/corporate/views/support.py b/corporate/views/support.py index 3ff997fcb2..01299cf146 100644 --- a/corporate/views/support.py +++ b/corporate/views/support.py @@ -19,7 +19,7 @@ from django.utils.translation import gettext as _ from confirmation.models import Confirmation, confirmation_url from confirmation.settings import STATUS_USED -from corporate.lib.activity import remote_installation_stats_link +from corporate.lib.activity import format_optional_datetime, remote_installation_stats_link from corporate.lib.stripe import ( RealmBillingSession, RemoteRealmBillingSession, @@ -638,6 +638,7 @@ def remote_servers_support( context["get_plan_type_name"] = get_plan_type_string context["get_org_type_display_name"] = get_org_type_display_name context["format_discount"] = format_discount_percentage + context["format_optional_datetime"] = format_optional_datetime context["dollar_amount"] = cents_to_dollar_string context["server_analytics_link"] = remote_installation_stats_link context["REMOTE_PLAN_TIERS"] = get_remote_plan_tier_options() diff --git a/corporate/views/user_activity.py b/corporate/views/user_activity.py index 29df5b7160..b38647f795 100644 --- a/corporate/views/user_activity.py +++ b/corporate/views/user_activity.py @@ -4,7 +4,7 @@ from django.db.models import QuerySet from django.http import HttpRequest, HttpResponse from django.shortcuts import render -from corporate.lib.activity import format_date_for_activity_reports, make_table +from corporate.lib.activity import format_optional_datetime, make_table from zerver.decorator import require_server_admin from zerver.models import UserActivity, UserProfile from zerver.models.users import get_user_profile_by_id @@ -40,7 +40,7 @@ def get_user_activity(request: HttpRequest, user_profile_id: int) -> HttpRespons "Query", "Client", "Count", - "Last visit", + "Last visit (UTC)", ] def row(record: UserActivity) -> List[Any]: @@ -48,7 +48,7 @@ def get_user_activity(request: HttpRequest, user_profile_id: int) -> HttpRespons record.query, record.client.name, record.count, - format_date_for_activity_reports(record.last_visit), + format_optional_datetime(record.last_visit), ] rows = list(map(row, records)) diff --git a/templates/corporate/support/remote_server_support.html b/templates/corporate/support/remote_server_support.html index 8b4fc42dfb..90528ab77e 100644 --- a/templates/corporate/support/remote_server_support.html +++ b/templates/corporate/support/remote_server_support.html @@ -55,6 +55,7 @@ Has remote realms: {{ remote_realms[remote_server.id] != [] }}

Max monthly messages: {{ remote_server_to_max_monthly_messages[remote_server.id] }}
+ Last audit log update (UTC): {{ format_optional_datetime(remote_server.last_audit_log_update, True) }}
Plan type: {{ get_plan_type_name(remote_server.plan_type) }}
Non-guest user count: {{ remote_servers_support_data[remote_server.id].user_data.non_guest_user_count }}
Guest user count: {{ remote_servers_support_data[remote_server.id].user_data.guest_user_count }}