Skip to content

Commit 621139d

Browse files
authored
feat(userReports): add last_updated to API response DEV-1267 (#6460)
### 📣 Summary This PR exposes the latest snapshot update timestamp (`BillingAndUsageSnapshot.date_modified`) as `last_updated` in the `/api/v2/user-reports/` endpoint.
1 parent a32e5cd commit 621139d

File tree

8 files changed

+15
-3
lines changed

8 files changed

+15
-3
lines changed

jsapp/js/api/react-query/server-logs-superusers.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -940,6 +940,7 @@ Supports exact matching and range operators (e.g., gte, lte)
940940
941941
- date_joined
942942
- last_login
943+
- last_updated (Represents the last modified timestamp of the materialized view)
943944
- extra_details__date_removal_requested
944945
- extra_details__date_removed
945946
- extra_details_password_date_changed

kobo/apps/user_reports/migrations/0002_create_user_reports_mv.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@
5454
bus.mt_characters_limit,
5555
COALESCE(bus.total_storage_bytes, 0) as total_storage_bytes,
5656
COALESCE(bus.total_submission_count_all_time, 0) as total_submission_count_all_time,
57-
COALESCE(bus.total_submission_count_current_period, 0) as total_submission_count_current_period
57+
COALESCE(bus.total_submission_count_current_period, 0) as total_submission_count_current_period,
58+
bus.date_modified
5859
FROM auth_user au
5960
LEFT JOIN organizations_organizationuser ou ON au.id = ou.user_id
6061
LEFT JOIN user_reports_billingandusagesnapshot bus ON ou.organization_id = bus.organization_id
@@ -98,6 +99,7 @@
9899
au.is_staff,
99100
au.is_active,
100101
TO_CHAR(au.date_joined AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS"Z"') AS date_joined,
102+
TO_CHAR(ubau.date_modified AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS"Z"') AS last_updated,
101103
CASE
102104
WHEN au.last_login IS NOT NULL THEN TO_CHAR(au.last_login AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')
103105
ELSE NULL
@@ -281,7 +283,8 @@
281283
ubau.mt_characters_limit,
282284
ubau.total_storage_bytes,
283285
ubau.total_submission_count_all_time,
284-
ubau.total_submission_count_current_period;
286+
ubau.total_submission_count_current_period,
287+
ubau.date_modified;
285288
"""
286289

287290
STRIPE_SUBSCRIPTIONS = """

kobo/apps/user_reports/models.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,8 @@ class UserReports(models.Model):
122122
current_period_end = models.DateTimeField(null=True, blank=True)
123123
service_usage = models.JSONField(null=True, blank=True)
124124

125+
last_updated = models.CharField()
126+
125127
class Meta:
126128
managed = False
127129
db_table = 'user_reports_userreportsmv'

kobo/apps/user_reports/seralizers.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ class Meta:
4141
'account_restricted',
4242
'asset_count',
4343
'deployed_asset_count',
44+
'last_updated',
4445
]
4546

4647
def get_account_restricted(self, obj) -> bool:

kobo/apps/user_reports/utils/snapshot_refresh_helpers.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from django.db import connection
44
from django.db.models import Q
55
from django.db.models.query import QuerySet
6+
from django.utils import timezone
67

78
from kobo.apps.organizations.models import Organization
89
from kobo.apps.user_reports.models import (
@@ -94,6 +95,7 @@ def process_chunk(
9495
mt_characters_limit=_normalize_limit(
9596
org_limits.get('mt_characters_limit')
9697
),
98+
date_modified=timezone.now(),
9799
)
98100
)
99101

@@ -113,6 +115,7 @@ def process_chunk(
113115
'storage_bytes_limit',
114116
'asr_seconds_limit',
115117
'mt_characters_limit',
118+
'date_modified',
116119
],
117120
unique_fields=['organization_id'],
118121
)

kpi/docs/api/v2/user_reports/list.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ Supports exact matching and range operators (e.g., gte, lte)
5757

5858
- date_joined
5959
- last_login
60+
- last_updated (Represents the last modified timestamp of the materialized view)
6061
- extra_details__date_removal_requested
6162
- extra_details__date_removed
6263
- extra_details_password_date_changed

static/openapi/schema_v2.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11647,7 +11647,7 @@
1164711647
"/api/v2/user-reports/": {
1164811648
"get": {
1164911649
"operationId": "api_v2_user_reports_list",
11650-
"description": "# List user reports\n\n⚠️ _Only available to superusers_\n\n## Filterable fields by string:\n\nSupports partial filtering\n- username\n- first_name\n- last_name\n- email\n- user_uid\n- organization__name\n- organization__role (e.g., admin, member, owner)\n- organization__website\n- extra_details__data__organization_type\n- `extra_details__data__<field>` (other string fields, e.g., name, sector, country...)\n\n## Filterable fields by int:\n\nSupports exact matching and range operators (e.g., gte, lte)\n\n**Total NLP Usage**\n- service_usage__total_nlp_usage__asr_seconds_all_time\n- service_usage__total_nlp_usage__mt_characters_all_time\n- service_usage__total_nlp_usage__asr_seconds_current_period\n- service_usage__total_nlp_usage__mt_characters_current_period\n\n**Total Storage/Submissions**\n- service_usage__total_storage_bytes\n- service_usage__total_submission_count__all_time\n- service_usage__total_submission_count__current_period\n\n**Service Usage Balances**\n\nPrefix: `service_usage__balances__<metric>__<value>`\n\nMetric:\n- submission\n- asr_seconds\n- mt_characters\n- storage_bytes\n\nValue:\n- balance_value\n- balance_percent\n- effective_limit\n\nEx: `service_usage__balances__submission__balance_value`\n\n**Asset Count**\n- asset_count\n- deployed_asset_count\n\n## Filterable fields by date:\nSupports exact matching and range operators (e.g., gte, lte)\n\n- date_joined\n- last_login\n- extra_details__date_removal_requested\n- extra_details__date_removed\n- extra_details_password_date_changed\n\n## Filterable fields by boolean:\n\n- is_superuser\n- is_staff\n- is_active\n- validated_email\n- extra_details__validated_password\n- mfa_is_active\n- sso_is_active\n- accepted_tos\n- extra_details__data__newsletter_subscription\n- service_usage__balances__*metric*__exceeded (metric: submission, asr_seconds, mt_characters, storage_bytes)\n- account_restricted\n\n## Filterable fields by list:\n\nSubscription filtering:\n\nHas subscriptions\n\n`?q=subscriptions__0__id__isnull:False`\n\nNo subscriptions\n\n`?q=subscriptions__0__id__isnull:True`\n\nSubscription id\n\n`?q=subscriptions[]__id:sub_1QwPItAR39rDI89stzLJ040p`\n\nActive subscriptions\n\n`?q=subscriptions[]__status:active`\n",
11650+
"description": "# List user reports\n\n⚠️ _Only available to superusers_\n\n## Filterable fields by string:\n\nSupports partial filtering\n- username\n- first_name\n- last_name\n- email\n- user_uid\n- organization__name\n- organization__role (e.g., admin, member, owner)\n- organization__website\n- extra_details__data__organization_type\n- `extra_details__data__<field>` (other string fields, e.g., name, sector, country...)\n\n## Filterable fields by int:\n\nSupports exact matching and range operators (e.g., gte, lte)\n\n**Total NLP Usage**\n- service_usage__total_nlp_usage__asr_seconds_all_time\n- service_usage__total_nlp_usage__mt_characters_all_time\n- service_usage__total_nlp_usage__asr_seconds_current_period\n- service_usage__total_nlp_usage__mt_characters_current_period\n\n**Total Storage/Submissions**\n- service_usage__total_storage_bytes\n- service_usage__total_submission_count__all_time\n- service_usage__total_submission_count__current_period\n\n**Service Usage Balances**\n\nPrefix: `service_usage__balances__<metric>__<value>`\n\nMetric:\n- submission\n- asr_seconds\n- mt_characters\n- storage_bytes\n\nValue:\n- balance_value\n- balance_percent\n- effective_limit\n\nEx: `service_usage__balances__submission__balance_value`\n\n**Asset Count**\n- asset_count\n- deployed_asset_count\n\n## Filterable fields by date:\nSupports exact matching and range operators (e.g., gte, lte)\n\n- date_joined\n- last_login\n- last_updated (Represents the last modified timestamp of the materialized view)\n- extra_details__date_removal_requested\n- extra_details__date_removed\n- extra_details_password_date_changed\n\n## Filterable fields by boolean:\n\n- is_superuser\n- is_staff\n- is_active\n- validated_email\n- extra_details__validated_password\n- mfa_is_active\n- sso_is_active\n- accepted_tos\n- extra_details__data__newsletter_subscription\n- service_usage__balances__*metric*__exceeded (metric: submission, asr_seconds, mt_characters, storage_bytes)\n- account_restricted\n\n## Filterable fields by list:\n\nSubscription filtering:\n\nHas subscriptions\n\n`?q=subscriptions__0__id__isnull:False`\n\nNo subscriptions\n\n`?q=subscriptions__0__id__isnull:True`\n\nSubscription id\n\n`?q=subscriptions[]__id:sub_1QwPItAR39rDI89stzLJ040p`\n\nActive subscriptions\n\n`?q=subscriptions[]__status:active`\n",
1165111651
"parameters": [
1165211652
{
1165311653
"name": "limit",

static/openapi/schema_v2.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8484,6 +8484,7 @@ paths:
84848484
84858485
- date_joined
84868486
- last_login
8487+
- last_updated (Represents the last modified timestamp of the materialized view)
84878488
- extra_details__date_removal_requested
84888489
- extra_details__date_removed
84898490
- extra_details_password_date_changed

0 commit comments

Comments
 (0)