Skip to content

Commit

Permalink
Stream goods documents from API
Browse files Browse the repository at this point in the history
  • Loading branch information
kevincarrogan committed Feb 12, 2024
1 parent 451f576 commit 605511a
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 5 deletions.
5 changes: 5 additions & 0 deletions exporter/goods/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,11 @@ def get_good_document(request, pk, doc_pk):
return data.json().get("document") if data.status_code == HTTPStatus.OK else None


def stream_good_document(request, pk, doc_pk):
response = client.get(request, f"/goods/{pk}/documents/{doc_pk}/stream/", stream=True)
return response, response.status_code


def get_good_documents(request, pk):
data = client.get(request, f"/goods/{pk}/documents/")
return data.json().get("documents") if data.status_code == HTTPStatus.OK else None
Expand Down
22 changes: 18 additions & 4 deletions exporter/goods/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,16 @@
from django.shortcuts import redirect, render
from django.urls import reverse, reverse_lazy
from django.utils.functional import cached_property
from django.views.generic import FormView, TemplateView
from django.views.generic import FormView, TemplateView, View

from core.auth.views import LoginRequiredMixin
from core.constants import (
CaseStatusEnum,
FirearmsActDocumentType,
FirearmsActSections,
)
from core.file_handler import download_document_from_s3
from core.decorators import expect_status
from core.helpers import stream_document_response

from exporter.applications.helpers.date_fields import format_date
from exporter.applications.services import (
Expand Down Expand Up @@ -81,6 +82,7 @@
post_good_document_availability,
post_good_document_sensitivity,
post_good_documents,
stream_good_document,
)
from lite_content.lite_exporter_frontend import goods
from lite_content.lite_exporter_frontend.goods import AttachDocumentForm, CreateGoodForm
Expand Down Expand Up @@ -1084,13 +1086,25 @@ def post(self, request, **kwargs):
return redirect(reverse("goods:good", kwargs={"pk": good_id}))


class Document(LoginRequiredMixin, TemplateView):
class Document(LoginRequiredMixin, View):
@expect_status(
HTTPStatus.OK,
"Error downloading document",
"Unexpected error downloading document",
)
def stream_good_document(self, request, good_id, file_pk):
return stream_good_document(request, good_id, file_pk)

def get(self, request, **kwargs):
good_id = str(kwargs["pk"])
file_pk = str(kwargs["file_pk"])

document = get_good_document(request, good_id, file_pk)
return download_document_from_s3(document["s3_key"], document["name"])
if not document:
raise Http404()

api_response, _ = self.stream_good_document(request, good_id, file_pk)
return stream_document_response(api_response)


class DeleteDocument(LoginRequiredMixin, TemplateView):
Expand Down
1 change: 0 additions & 1 deletion exporter/organisation/views.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from http import HTTPStatus

from django.http import StreamingHttpResponse
from django.shortcuts import render
from django.urls import reverse, reverse_lazy
from django.views.generic import FormView, TemplateView, RedirectView, View
Expand Down
103 changes: 103 additions & 0 deletions unit_tests/exporter/goods/views/test_good_documents.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import io
import uuid

from pytest_django.asserts import assertContains

from django.http import StreamingHttpResponse
from django.urls import reverse

from core import client


def test_document_download(authorized_client, requests_mock):
good_pk = uuid.uuid4()
file_pk = uuid.uuid4()

goods_document_url = client._build_absolute_uri(f"/goods/{good_pk}/documents/{file_pk}/")
requests_mock.get(
goods_document_url,
json={
"document": {
"id": str(uuid.uuid4()),
},
},
)

goods_document_stream_url = client._build_absolute_uri(f"/goods/{good_pk}/documents/{file_pk}/stream/")
requests_mock.get(
goods_document_stream_url,
body=io.BytesIO(b"test"),
headers={
"Content-Type": "application/doc",
"Content-Disposition": 'attachment; filename="fakefile.doc"',
},
)

url = reverse(
"goods:document",
kwargs={
"pk": good_pk,
"file_pk": file_pk,
},
)
response = authorized_client.get(url)

assert response.status_code == 200
assert isinstance(response, StreamingHttpResponse)
assert response.headers["Content-Type"] == "application/doc"
assert response.headers["Content-Disposition"] == 'attachment; filename="fakefile.doc"'
assert b"".join(response.streaming_content) == b"test"


def test_document_download_no_document_response(authorized_client, requests_mock):
good_pk = uuid.uuid4()
file_pk = uuid.uuid4()

goods_document_url = client._build_absolute_uri(f"/goods/{good_pk}/documents/{file_pk}/")
requests_mock.get(
goods_document_url,
status_code=404,
)

url = reverse(
"goods:document",
kwargs={
"pk": good_pk,
"file_pk": file_pk,
},
)
response = authorized_client.get(url)
assert response.status_code == 404


def test_document_download_no_stream_response(authorized_client, requests_mock):
good_pk = uuid.uuid4()
file_pk = uuid.uuid4()

goods_document_url = client._build_absolute_uri(f"/goods/{good_pk}/documents/{file_pk}/")
requests_mock.get(
goods_document_url,
json={
"document": {
"id": str(uuid.uuid4()),
},
},
)

goods_document_stream_url = client._build_absolute_uri(f"/goods/{good_pk}/documents/{file_pk}/stream/")
requests_mock.get(
goods_document_stream_url,
status_code=404,
)

url = reverse(
"goods:document",
kwargs={
"pk": good_pk,
"file_pk": file_pk,
},
)

response = authorized_client.get(url)
assert response.status_code == 200
assertContains(response, "Unexpected error downloading document")

0 comments on commit 605511a

Please sign in to comment.