feat(cache): add targeted server-side response caching
This commit is contained in:
@@ -23,6 +23,10 @@ from apps.reports.services import (
|
||||
load_report_filters,
|
||||
)
|
||||
from apps.reports.tasks import generate_report_export_task
|
||||
from core.services.cache import CACHE_NAMESPACE_REPORTS, get_or_set_cache_payload
|
||||
|
||||
|
||||
REPORT_CACHE_TTL_SECONDS = 90
|
||||
|
||||
|
||||
class ReportChartView(APIView):
|
||||
@@ -30,7 +34,17 @@ class ReportChartView(APIView):
|
||||
|
||||
@extend_schema(responses=dict)
|
||||
def get(self, request):
|
||||
return Response(build_chart_report(request.user, request.query_params))
|
||||
workspace_id = request.query_params.get("workspace")
|
||||
payload = get_or_set_cache_payload(
|
||||
CACHE_NAMESPACE_REPORTS,
|
||||
ttl_seconds=REPORT_CACHE_TTL_SECONDS,
|
||||
builder=lambda: build_chart_report(request.user, request.query_params),
|
||||
resource="chart",
|
||||
user_id=request.user.id,
|
||||
workspace_id=workspace_id,
|
||||
params=request.query_params,
|
||||
)
|
||||
return Response(payload)
|
||||
|
||||
|
||||
class ReportTableView(APIView):
|
||||
@@ -38,7 +52,17 @@ class ReportTableView(APIView):
|
||||
|
||||
@extend_schema(responses=dict)
|
||||
def get(self, request):
|
||||
return Response(build_table_report(request.user, request.query_params))
|
||||
workspace_id = request.query_params.get("workspace")
|
||||
payload = get_or_set_cache_payload(
|
||||
CACHE_NAMESPACE_REPORTS,
|
||||
ttl_seconds=REPORT_CACHE_TTL_SECONDS,
|
||||
builder=lambda: build_table_report(request.user, request.query_params),
|
||||
resource="table",
|
||||
user_id=request.user.id,
|
||||
workspace_id=workspace_id,
|
||||
params=request.query_params,
|
||||
)
|
||||
return Response(payload)
|
||||
|
||||
|
||||
class ReportDayDetailsView(APIView):
|
||||
@@ -46,7 +70,17 @@ class ReportDayDetailsView(APIView):
|
||||
|
||||
@extend_schema(responses=dict)
|
||||
def get(self, request):
|
||||
return Response(build_day_details_report(request.user, request.query_params))
|
||||
workspace_id = request.query_params.get("workspace")
|
||||
payload = get_or_set_cache_payload(
|
||||
CACHE_NAMESPACE_REPORTS,
|
||||
ttl_seconds=REPORT_CACHE_TTL_SECONDS,
|
||||
builder=lambda: build_day_details_report(request.user, request.query_params),
|
||||
resource="day-details",
|
||||
user_id=request.user.id,
|
||||
workspace_id=workspace_id,
|
||||
params=request.query_params,
|
||||
)
|
||||
return Response(payload)
|
||||
|
||||
|
||||
class ReportExportJobViewSet(
|
||||
|
||||
@@ -2,6 +2,7 @@ from datetime import date, timedelta
|
||||
from decimal import Decimal
|
||||
from unittest.mock import patch
|
||||
|
||||
from django.core.cache import cache
|
||||
from rest_framework.test import APITestCase
|
||||
|
||||
from apps.clients.models import Client
|
||||
@@ -82,6 +83,9 @@ class ReportViewTests(APITestCase):
|
||||
)
|
||||
entry_member.tags.add(cls.tag)
|
||||
|
||||
def setUp(self):
|
||||
cache.clear()
|
||||
|
||||
def test_member_only_sees_own_chart_report(self):
|
||||
self.client.force_authenticate(user=self.member)
|
||||
|
||||
@@ -208,3 +212,27 @@ class ReportViewTests(APITestCase):
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.data["summary"]["total_duration"], "02:00:00")
|
||||
self.assertEqual(response.data["scope"]["from_date"], "2026-04-21")
|
||||
|
||||
def test_table_report_cache_stays_until_time_entry_invalidation(self):
|
||||
self.client.force_authenticate(user=self.owner)
|
||||
url = "/api/reports/table/"
|
||||
params = {"workspace": str(self.workspace.id), "period": "this_month"}
|
||||
|
||||
first_response = self.client.get(url, params)
|
||||
self.assertEqual(first_response.status_code, 200)
|
||||
self.assertEqual(first_response.data["summary"]["total_duration"], "03:00:00")
|
||||
|
||||
member_entry = TimeEntry.objects.get(description="Member work")
|
||||
TimeEntry.objects.filter(id=member_entry.id).update(duration=timedelta(hours=5))
|
||||
|
||||
cached_response = self.client.get(url, params)
|
||||
self.assertEqual(cached_response.status_code, 200)
|
||||
self.assertEqual(cached_response.data["summary"]["total_duration"], "03:00:00")
|
||||
|
||||
member_entry.refresh_from_db()
|
||||
member_entry.description = "Member work updated"
|
||||
member_entry.save(update_fields=["description"])
|
||||
|
||||
fresh_response = self.client.get(url, params)
|
||||
self.assertEqual(fresh_response.status_code, 200)
|
||||
self.assertEqual(fresh_response.data["summary"]["total_duration"], "07:00:00")
|
||||
|
||||
Reference in New Issue
Block a user