Skip to content

Commit

Permalink
feat: add button for csv downloads
Browse files Browse the repository at this point in the history
Use the secondary button style, as this is not a call to action, and
neither is it a link to another page.
  • Loading branch information
MatMoore committed Nov 8, 2024
1 parent 4fccede commit c572030
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 4 deletions.
3 changes: 0 additions & 3 deletions home/tests.py

This file was deleted.

5 changes: 5 additions & 0 deletions home/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@
views.metadata_specification_view,
name="metadata_specification",
),
path(
"details/<str:result_type>/<str:urn>.csv",
views.details_view_csv,
name="details_csv",
),
path(
"details/<str:result_type>/<str:urn>",
views.details_view,
Expand Down
38 changes: 37 additions & 1 deletion home/views.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import csv
from urllib.parse import urlparse

from data_platform_catalogue.client.exceptions import EntityDoesNotExist
from data_platform_catalogue.search_types import DomainOption
from django.conf import settings
from django.http import Http404, HttpResponseBadRequest
from django.http import Http404, HttpResponse, HttpResponseBadRequest
from django.shortcuts import render
from django.utils.translation import gettext as _
from django.views.decorators.cache import cache_control
Expand All @@ -15,6 +16,11 @@
DatabaseDetailsService,
DatasetDetailsService,
)
from home.service.details_csv import (
DashboardDetailsCsvFormatter,
DatabaseDetailsCsvFormatter,
DatasetDetailsCsvFormatter,
)
from home.service.domain_fetcher import DomainFetcher
from home.service.glossary import GlossaryService
from home.service.metadata_specification import MetadataSpecificationService
Expand Down Expand Up @@ -55,6 +61,36 @@ def details_view(request, result_type, urn):
raise Http404(f"{result_type} '{urn}' does not exist")


@cache_control(max_age=300, private=True)
def details_view_csv(request, result_type, urn) -> HttpResponse:
if result_type == "table":
service = DatasetDetailsService(urn)
csv_formatter = DatasetDetailsCsvFormatter(service)
elif result_type == "database":
service = DatabaseDetailsService(urn)
csv_formatter = DatabaseDetailsCsvFormatter(service)
elif result_type == "dashboard":
service = DashboardDetailsService(urn)
csv_formatter = DashboardDetailsCsvFormatter(service)
else:
raise Http404("CSV not available")

# In case there are any quotes in the filename, remove them in order to
# not to break the header.
unsavoury_characters = str.maketrans({'"': ""})
filename = urn.translate(unsavoury_characters) + ".csv"

response = HttpResponse(
content_type="text/csv",
headers={"Content-Disposition": f'attachment; filename="{filename}"'},
)
writer = csv.writer(response)
writer.writerow(csv_formatter.headers())
writer.writerows(csv_formatter.data())

return response


@cache_control(max_age=60, private=True)
def search_view(request, page: str = "1"):
new_search = request.GET.get("new", "")
Expand Down
5 changes: 5 additions & 0 deletions templates/details_dashboard.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@
{% endfor %}
</tbody>
</table>
<form action="{% url 'home:details_csv' result_type='dashboard' urn=entity.urn %}">
<button type="submit" class="govuk-button govuk-button--secondary" data-module="govuk-button">
{% translate 'Download chart descriptions (CSV format)' %}
</button>
</form>
{% else %}
<h2 class="govuk-heading-m">{% translate "Dashboard content" %}</h2>
<p class="govuk-body">{% translate "This dashboard is missing chart information." %}</p>
Expand Down
5 changes: 5 additions & 0 deletions templates/details_database.html
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@
{% endfor %}
</tbody>
</table>
<form action="{% url 'home:details_csv' result_type='database' urn=entity.urn %}">
<button type="submit" class="govuk-button govuk-button--secondary" data-module="govuk-button">
{% translate 'Download table descriptions (CSV format)' %}
</button>
</form>
{% else %}
<h2 class="govuk-heading-m">{% translate "Database content" %}</h2>
<p class="govuk-body">{% translate "This database is missing table information." %}</p>
Expand Down
6 changes: 6 additions & 0 deletions templates/details_table.html
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@
{% endfor %}
</tbody>
</table>

<form action="{% url 'home:details_csv' result_type='table' urn=entity.urn %}">
<button type="submit" class="govuk-button govuk-button--secondary" data-module="govuk-button">
{% translate 'Download table schema (CSV format)' %}
</button>
</form>
{% else %}
<h2 class="govuk-heading-m">{% translate "Table schema" %}</h2>
<p class="govuk-body">{% translate "The schema for this table is not available." %}</p>
Expand Down
56 changes: 56 additions & 0 deletions tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,65 @@ def test_table(self, client, switch_bool):
response = client.get(
reverse("home:details", kwargs={"urn": "fake", "result_type": "table"})
)

assert response.status_code == 200
assert response.headers["Cache-Control"] == "max-age=300, private"

@pytest.mark.django_db
def test_csv_output(self, client):
response = client.get(
reverse(
"home:details_csv",
kwargs={"urn": "fake", "result_type": "table"},
)
)
assert response.status_code == 200
assert (
response.headers["Content-Disposition"] == 'attachment; filename="fake.csv"'
)
assert response.content == (
b"name,display_name,is_primary_key,type,nullable,description\r\n"
+ b"urn,urn,True,string,False,description **with markdown**\r\n"
)


class TestDatabaseView:
@pytest.mark.django_db
def test_csv_output(self, client):
response = client.get(
reverse(
"home:details_csv",
kwargs={"urn": "fake", "result_type": "database"},
)
)
assert response.status_code == 200
assert (
response.headers["Content-Disposition"] == 'attachment; filename="fake.csv"'
)
assert response.content == (
b"urn,display_name,description\r\n"
+ b"urn:li:dataset:fake_table,fake_table,table description\r\n"
)


class TestDashboardView:
@pytest.mark.django_db
def test_csv_output(self, client):
response = client.get(
reverse(
"home:details_csv",
kwargs={"urn": "fake", "result_type": "dashboard"},
)
)
assert response.status_code == 200
assert (
response.headers["Content-Disposition"] == 'attachment; filename="fake.csv"'
)
assert response.content == (
b"urn,display_name,description\r\n"
+ b"urn:li:chart:fake_chart,fake_chart,chart description\r\n"
)


class TestChartView:
def test_chart(self, client):
Expand Down

0 comments on commit c572030

Please sign in to comment.