diff --git a/squad/api/rest.py b/squad/api/rest.py index da424b97..1ffba588 100644 --- a/squad/api/rest.py +++ b/squad/api/rest.py @@ -1,4 +1,5 @@ import json +import urllib.parse import yaml from django.db.models import Q, F, Value as V, CharField, Prefetch @@ -1310,9 +1311,19 @@ class StatusViewSet(NestedViewSetMixin, ModelViewSet): class AttachmentSerializer(serializers.ModelSerializer): + download_url = serializers.SerializerMethodField() + class Meta: model = Attachment - fields = ('filename', 'mimetype', 'length') + fields = ('download_url', 'filename', 'mimetype', 'length') + + def get_download_url(self, attachment): + request = self.context.get('request') + if request is None: + return None + base_url = rest_reverse('testrun-detail', args=[attachment.test_run.pk], request=request) + filename_url_encoded = urllib.parse.quote(attachment.filename, safe='') + return f'{base_url}attachments/?filename={filename_url_encoded}' class TestRunSerializer(DynamicFieldsModelSerializer, serializers.HyperlinkedModelSerializer): diff --git a/test/api/test_rest.py b/test/api/test_rest.py index 1b68eb3b..6516a233 100644 --- a/test/api/test_rest.py +++ b/test/api/test_rest.py @@ -1139,6 +1139,7 @@ def test_testruns_attachments(self): data = self.hit('/api/testruns/%d/' % self.testrun.id) expected = { + 'download_url': 'http://testserver/api/testruns/%d/attachments/?filename=%s' % (self.testrun.id, filename), 'filename': filename, 'length': 147, 'mimetype': 'application/octet-stream' diff --git a/test/frontend/test_basics.py b/test/frontend/test_basics.py index 89503680..97abffbf 100644 --- a/test/frontend/test_basics.py +++ b/test/frontend/test_basics.py @@ -249,6 +249,16 @@ def test_attachment(self): self.assertEqual('text/plain', response['Content-Type']) self.assertEqual(b'text file', response.content) + def test_attachment_download_url(self): + data = bytes('text file', 'utf-8') + filename = 'foo.txt' + attachment = self.test_run.attachments.create(filename=filename, length=len(data), mimetype="text/plain") + attachment.save_file(filename, data) + # NOTE: /api/testruns/%s/attachments?filename=foo.txt redirects to /api/testruns/%s/attachments/?filename=foo.txt + response = self.hit('/api/testruns/%s/attachments/?filename=foo.txt' % (self.test_run.id)) + self.assertEqual('text/plain', response['Content-Type']) + self.assertEqual(b'text file', response.content) + def test_log(self): response = self.hit('/mygroup/myproject/build/1.0/testrun/%s/suite/%s/test/%s/log' % (self.test_run.id, self.suite.slug, self.test.name)) self.assertEqual('text/plain', response['Content-Type'])