Skip to content

Commit

Permalink
incorporate new renderer improvements into old views and make file fi…
Browse files Browse the repository at this point in the history
…lename more generic
  • Loading branch information
John Tordoff committed Oct 24, 2024
1 parent 09370fe commit a6fe0f4
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 35 deletions.
2 changes: 1 addition & 1 deletion api/base/settings/defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@

MAX_SIZE_OF_ES_QUERY = 10000
DEFAULT_ES_NULL_VALUE = 'N/A'
USER_INSTITUTION_REPORT_FILENAME = 'institution_user_report_{institution_id}_{date_created}.{format_type}'
REPORT_FILENAME_FORMAT = 'osf_report_{date_created}.{format_type}'

CI_ENV = False

Expand Down
5 changes: 2 additions & 3 deletions api/metrics/renderers.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import csv
import io
import json
from api.base.settings.defaults import USER_INSTITUTION_REPORT_FILENAME, MAX_SIZE_OF_ES_QUERY
from api.base.settings.defaults import REPORT_FILENAME_FORMAT, MAX_SIZE_OF_ES_QUERY
import datetime

from django.http import Http404
Expand Down Expand Up @@ -64,9 +64,8 @@ def get_filename(self, renderer_context: dict, format_type: str) -> str:
"""Generate the filename for the CSV/TSV file based on institution and current date."""
if renderer_context and 'view' in renderer_context:
current_date = datetime.datetime.now().strftime('%Y-%m') # Format as 'YYYY-MM'
return USER_INSTITUTION_REPORT_FILENAME.format(
return REPORT_FILENAME_FORMAT.format(
date_created=current_date,
institution_id=renderer_context['view'].kwargs['institution_id'],
format_type=format_type,
)
else:
Expand Down
66 changes: 43 additions & 23 deletions api/metrics/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -320,51 +320,69 @@ class RecentReportList(JSONAPIBaseView):
MetricsReportsTsvRenderer,
)

def get(self, request, *args, report_name):
def get_default_search(self):
try:
report_class = VIEWABLE_REPORTS[report_name]
report_class = VIEWABLE_REPORTS[self.kwargs['report_name']]
except KeyError:
return Response(
{
'errors': [{
'title': 'unknown report name',
'detail': f'unknown report: "{report_name}"',
}],
},
status=404,
)
return None

is_daily = issubclass(report_class, reports.DailyReport)
days_back = request.GET.get('days_back', self.DEFAULT_DAYS_BACK if is_daily else None)
is_monthly = issubclass(report_class, reports.MonthlyReport)

request = self.get_renderer_context()['request']
days_back = request.GET.get('days_back', self.DEFAULT_DAYS_BACK if is_daily else None)

if is_daily:
serializer_class = DailyReportSerializer
range_field_name = 'report_date'
elif is_monthly:
serializer_class = MonthlyReportSerializer
range_field_name = 'report_yearmonth'
else:
raise ValueError(f'report class must subclass DailyReport or MonthlyReport: {report_class}')

range_filter = parse_date_range(request.GET, is_monthly=is_monthly)
search_recent = (
report_class.search()
.filter('range', **{range_field_name: range_filter})
.sort(range_field_name)
[:self.MAX_COUNT]
search_recent = report_class.search().filter(
'range',
**{range_field_name: range_filter}
).sort(
range_field_name
)[:self.MAX_COUNT]

if is_daily and days_back:
search_recent = search_recent.filter('range', report_date={'gte': f'now/d-{days_back}d'})

return search_recent

def get(self, request, *args, report_name):
search_response = self.get_default_search()

if search_response is None:
return Response(
{
'errors': [{
'title': 'unknown report name',
'detail': f'unknown report: "{report_name}"',
}],
},
status=404,
)

report_class = VIEWABLE_REPORTS[report_name]
serializer_class = (
DailyReportSerializer if issubclass(report_class, reports.DailyReport)
else MonthlyReportSerializer
)
if days_back:
search_recent.filter('range', report_date={'gte': f'now/d-{days_back}d'})

report_date_range = parse_date_range(request.GET)
search_response = search_recent.execute()
serializer = serializer_class(
search_response,
many=True,
context={'report_name': report_name},
)

accepted_format = request.accepted_renderer.format
response_headers = {}

if accepted_format in ('tsv', 'csv'):
report_date_range = parse_date_range(request.GET)
from_date = report_date_range['gte']
until_date = report_date_range['lte']
filename = (
Expand All @@ -373,6 +391,8 @@ def get(self, request, *args, report_name):
f'from_{from_date}.{accepted_format}'
)
response_headers['Content-Disposition'] = f'attachment; filename={filename}'

# Return the response with serialized data
return Response(
{'data': serializer.data},
headers=response_headers,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import pytest
from waffle.testutils import override_flag

from api.base.settings.defaults import API_BASE, DEFAULT_ES_NULL_VALUE, USER_INSTITUTION_REPORT_FILENAME
from api.base.settings.defaults import API_BASE, DEFAULT_ES_NULL_VALUE, REPORT_FILENAME_FORMAT
import osf.features
from osf_tests.factories import (
InstitutionFactory,
Expand Down Expand Up @@ -435,9 +435,8 @@ def test_get_report_formats_csv_tsv(self, app, url, institutional_admin, institu
assert resp.headers['Content-Type'] == content_type

current_date = datetime.datetime.now().strftime('%Y-%m')
expected_filename = USER_INSTITUTION_REPORT_FILENAME.format(
expected_filename = REPORT_FILENAME_FORMAT.format(
date_created=current_date,
institution_id=institution._id,
format_type=format_type
)
assert resp.headers['Content-Disposition'] == f'attachment; filename="{expected_filename}"'
Expand All @@ -462,7 +461,7 @@ def test_get_report_formats_csv_tsv(self, app, url, institutional_admin, institu
'month_last_active',
'month_last_login',
'timestamp'
],
],
[
'2024-08',
institution._id,
Expand Down Expand Up @@ -516,9 +515,8 @@ def test_get_report_format_json(self, app, url, institutional_admin, institution
assert resp.headers['Content-Type'] == 'application/json; charset=utf-8'

current_date = datetime.datetime.now().strftime('%Y-%m')
expected_filename = USER_INSTITUTION_REPORT_FILENAME.format(
expected_filename = REPORT_FILENAME_FORMAT.format(
date_created=current_date,
institution_id=institution._id,
format_type='json'
)
assert resp.headers['Content-Disposition'] == f'attachment; filename="{expected_filename}"'
Expand Down Expand Up @@ -602,9 +600,8 @@ def test_csv_tsv_ignores_pagination(self, app, url, institutional_admin, institu
assert resp.headers['Content-Type'] == content_type

current_date = datetime.datetime.now().strftime('%Y-%m')
expected_filename = USER_INSTITUTION_REPORT_FILENAME.format(
expected_filename = REPORT_FILENAME_FORMAT.format(
date_created=current_date,
institution_id=institution._id,
format_type=format_type
)
assert resp.headers['Content-Disposition'] == f'attachment; filename="{expected_filename}"'
Expand Down

0 comments on commit a6fe0f4

Please sign in to comment.