mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-07-30 18:27:45 -05:00
Format Python code with black
This commit is contained in:
@@ -26,27 +26,26 @@ from rest_framework.mixins import (
|
||||
DestroyModelMixin,
|
||||
ListModelMixin,
|
||||
RetrieveModelMixin,
|
||||
UpdateModelMixin
|
||||
UpdateModelMixin,
|
||||
)
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
from rest_framework.viewsets import (
|
||||
GenericViewSet,
|
||||
ModelViewSet,
|
||||
ViewSet
|
||||
)
|
||||
from rest_framework.viewsets import GenericViewSet, ModelViewSet, ViewSet
|
||||
|
||||
from paperless.db import GnuPG
|
||||
from paperless.views import StandardPagination
|
||||
from .bulk_download import OriginalAndArchiveStrategy, OriginalsOnlyStrategy, \
|
||||
ArchiveOnlyStrategy
|
||||
from .bulk_download import (
|
||||
OriginalAndArchiveStrategy,
|
||||
OriginalsOnlyStrategy,
|
||||
ArchiveOnlyStrategy,
|
||||
)
|
||||
from .classifier import load_classifier
|
||||
from .filters import (
|
||||
CorrespondentFilterSet,
|
||||
DocumentFilterSet,
|
||||
TagFilterSet,
|
||||
DocumentTypeFilterSet
|
||||
DocumentTypeFilterSet,
|
||||
)
|
||||
from .matching import match_correspondents, match_tags, match_document_types
|
||||
from .models import Correspondent, Document, Tag, DocumentType, SavedView
|
||||
@@ -61,7 +60,7 @@ from .serialisers import (
|
||||
SavedViewSerializer,
|
||||
BulkEditSerializer,
|
||||
DocumentListSerializer,
|
||||
BulkDownloadSerializer
|
||||
BulkDownloadSerializer,
|
||||
)
|
||||
|
||||
logger = logging.getLogger("paperless.api")
|
||||
@@ -77,23 +76,29 @@ class IndexView(TemplateView):
|
||||
# this translates between these two forms.
|
||||
lang = get_language()
|
||||
if "-" in lang:
|
||||
first = lang[:lang.index("-")]
|
||||
second = lang[lang.index("-")+1:]
|
||||
first = lang[: lang.index("-")]
|
||||
second = lang[lang.index("-") + 1 :]
|
||||
return f"{first}-{second.upper()}"
|
||||
else:
|
||||
return lang
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['cookie_prefix'] = settings.COOKIE_PREFIX
|
||||
context['username'] = self.request.user.username
|
||||
context['full_name'] = self.request.user.get_full_name()
|
||||
context['styles_css'] = f"frontend/{self.get_language()}/styles.css"
|
||||
context['runtime_js'] = f"frontend/{self.get_language()}/runtime.js"
|
||||
context['polyfills_js'] = f"frontend/{self.get_language()}/polyfills.js" # NOQA: E501
|
||||
context['main_js'] = f"frontend/{self.get_language()}/main.js"
|
||||
context['webmanifest'] = f"frontend/{self.get_language()}/manifest.webmanifest" # NOQA: E501
|
||||
context['apple_touch_icon'] = f"frontend/{self.get_language()}/apple-touch-icon.png" # NOQA: E501
|
||||
context["cookie_prefix"] = settings.COOKIE_PREFIX
|
||||
context["username"] = self.request.user.username
|
||||
context["full_name"] = self.request.user.get_full_name()
|
||||
context["styles_css"] = f"frontend/{self.get_language()}/styles.css"
|
||||
context["runtime_js"] = f"frontend/{self.get_language()}/runtime.js"
|
||||
context[
|
||||
"polyfills_js"
|
||||
] = f"frontend/{self.get_language()}/polyfills.js" # NOQA: E501
|
||||
context["main_js"] = f"frontend/{self.get_language()}/main.js"
|
||||
context[
|
||||
"webmanifest"
|
||||
] = f"frontend/{self.get_language()}/manifest.webmanifest" # NOQA: E501
|
||||
context[
|
||||
"apple_touch_icon"
|
||||
] = f"frontend/{self.get_language()}/apple-touch-icon.png" # NOQA: E501
|
||||
return context
|
||||
|
||||
|
||||
@@ -101,8 +106,8 @@ class CorrespondentViewSet(ModelViewSet):
|
||||
model = Correspondent
|
||||
|
||||
queryset = Correspondent.objects.annotate(
|
||||
document_count=Count('documents'),
|
||||
last_correspondence=Max('documents__created')).order_by(Lower('name'))
|
||||
document_count=Count("documents"), last_correspondence=Max("documents__created")
|
||||
).order_by(Lower("name"))
|
||||
|
||||
serializer_class = CorrespondentSerializer
|
||||
pagination_class = StandardPagination
|
||||
@@ -114,14 +119,16 @@ class CorrespondentViewSet(ModelViewSet):
|
||||
"matching_algorithm",
|
||||
"match",
|
||||
"document_count",
|
||||
"last_correspondence")
|
||||
"last_correspondence",
|
||||
)
|
||||
|
||||
|
||||
class TagViewSet(ModelViewSet):
|
||||
model = Tag
|
||||
|
||||
queryset = Tag.objects.annotate(
|
||||
document_count=Count('documents')).order_by(Lower('name'))
|
||||
queryset = Tag.objects.annotate(document_count=Count("documents")).order_by(
|
||||
Lower("name")
|
||||
)
|
||||
|
||||
def get_serializer_class(self):
|
||||
if int(self.request.version) == 1:
|
||||
@@ -140,7 +147,8 @@ class DocumentTypeViewSet(ModelViewSet):
|
||||
model = DocumentType
|
||||
|
||||
queryset = DocumentType.objects.annotate(
|
||||
document_count=Count('documents')).order_by(Lower('name'))
|
||||
document_count=Count("documents")
|
||||
).order_by(Lower("name"))
|
||||
|
||||
serializer_class = DocumentTypeSerializer
|
||||
pagination_class = StandardPagination
|
||||
@@ -150,11 +158,13 @@ class DocumentTypeViewSet(ModelViewSet):
|
||||
ordering_fields = ("name", "matching_algorithm", "match", "document_count")
|
||||
|
||||
|
||||
class DocumentViewSet(RetrieveModelMixin,
|
||||
UpdateModelMixin,
|
||||
DestroyModelMixin,
|
||||
ListModelMixin,
|
||||
GenericViewSet):
|
||||
class DocumentViewSet(
|
||||
RetrieveModelMixin,
|
||||
UpdateModelMixin,
|
||||
DestroyModelMixin,
|
||||
ListModelMixin,
|
||||
GenericViewSet,
|
||||
):
|
||||
model = Document
|
||||
queryset = Document.objects.all()
|
||||
serializer_class = DocumentSerializer
|
||||
@@ -171,47 +181,51 @@ class DocumentViewSet(RetrieveModelMixin,
|
||||
"created",
|
||||
"modified",
|
||||
"added",
|
||||
"archive_serial_number")
|
||||
"archive_serial_number",
|
||||
)
|
||||
|
||||
def get_queryset(self):
|
||||
return Document.objects.distinct()
|
||||
|
||||
def get_serializer(self, *args, **kwargs):
|
||||
fields_param = self.request.query_params.get('fields', None)
|
||||
fields_param = self.request.query_params.get("fields", None)
|
||||
if fields_param:
|
||||
fields = fields_param.split(",")
|
||||
else:
|
||||
fields = None
|
||||
serializer_class = self.get_serializer_class()
|
||||
kwargs.setdefault('context', self.get_serializer_context())
|
||||
kwargs.setdefault('fields', fields)
|
||||
kwargs.setdefault("context", self.get_serializer_context())
|
||||
kwargs.setdefault("fields", fields)
|
||||
return serializer_class(*args, **kwargs)
|
||||
|
||||
def update(self, request, *args, **kwargs):
|
||||
response = super(DocumentViewSet, self).update(
|
||||
request, *args, **kwargs)
|
||||
response = super(DocumentViewSet, self).update(request, *args, **kwargs)
|
||||
from documents import index
|
||||
|
||||
index.add_or_update_document(self.get_object())
|
||||
return response
|
||||
|
||||
def destroy(self, request, *args, **kwargs):
|
||||
from documents import index
|
||||
|
||||
index.remove_document_from_index(self.get_object())
|
||||
return super(DocumentViewSet, self).destroy(request, *args, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def original_requested(request):
|
||||
return (
|
||||
'original' in request.query_params and
|
||||
request.query_params['original'] == 'true'
|
||||
"original" in request.query_params
|
||||
and request.query_params["original"] == "true"
|
||||
)
|
||||
|
||||
def file_response(self, pk, request, disposition):
|
||||
doc = Document.objects.get(id=pk)
|
||||
if not self.original_requested(request) and doc.has_archive_version: # NOQA: E501
|
||||
if (
|
||||
not self.original_requested(request) and doc.has_archive_version
|
||||
): # NOQA: E501
|
||||
file_handle = doc.archive_file
|
||||
filename = doc.get_public_filename(archive=True)
|
||||
mime_type = 'application/pdf'
|
||||
mime_type = "application/pdf"
|
||||
else:
|
||||
file_handle = doc.source_file
|
||||
filename = doc.get_public_filename()
|
||||
@@ -224,12 +238,13 @@ class DocumentViewSet(RetrieveModelMixin,
|
||||
# Firefox is not able to handle unicode characters in filename field
|
||||
# RFC 5987 addresses this issue
|
||||
# see https://datatracker.ietf.org/doc/html/rfc5987#section-4.2
|
||||
filename_normalized = normalize("NFKD", filename)\
|
||||
.encode('ascii', 'ignore')
|
||||
filename_normalized = normalize("NFKD", filename).encode("ascii", "ignore")
|
||||
filename_encoded = quote_plus(filename)
|
||||
content_disposition = f'{disposition}; ' \
|
||||
f'filename="{filename_normalized}"; ' \
|
||||
f'filename*=utf-8\'\'{filename_encoded}'
|
||||
content_disposition = (
|
||||
f"{disposition}; "
|
||||
f'filename="{filename_normalized}"; '
|
||||
f"filename*=utf-8''{filename_encoded}"
|
||||
)
|
||||
response["Content-Disposition"] = content_disposition
|
||||
return response
|
||||
|
||||
@@ -255,7 +270,7 @@ class DocumentViewSet(RetrieveModelMixin,
|
||||
else:
|
||||
return None
|
||||
|
||||
@action(methods=['get'], detail=True)
|
||||
@action(methods=["get"], detail=True)
|
||||
def metadata(self, request, pk=None):
|
||||
try:
|
||||
doc = Document.objects.get(pk=pk)
|
||||
@@ -268,23 +283,23 @@ class DocumentViewSet(RetrieveModelMixin,
|
||||
"original_mime_type": doc.mime_type,
|
||||
"media_filename": doc.filename,
|
||||
"has_archive_version": doc.has_archive_version,
|
||||
"original_metadata": self.get_metadata(
|
||||
doc.source_path, doc.mime_type),
|
||||
"original_metadata": self.get_metadata(doc.source_path, doc.mime_type),
|
||||
"archive_checksum": doc.archive_checksum,
|
||||
"archive_media_filename": doc.archive_filename
|
||||
"archive_media_filename": doc.archive_filename,
|
||||
}
|
||||
|
||||
if doc.has_archive_version:
|
||||
meta['archive_size'] = self.get_filesize(doc.archive_path)
|
||||
meta['archive_metadata'] = self.get_metadata(
|
||||
doc.archive_path, "application/pdf")
|
||||
meta["archive_size"] = self.get_filesize(doc.archive_path)
|
||||
meta["archive_metadata"] = self.get_metadata(
|
||||
doc.archive_path, "application/pdf"
|
||||
)
|
||||
else:
|
||||
meta['archive_size'] = None
|
||||
meta['archive_metadata'] = None
|
||||
meta["archive_size"] = None
|
||||
meta["archive_metadata"] = None
|
||||
|
||||
return Response(meta)
|
||||
|
||||
@action(methods=['get'], detail=True)
|
||||
@action(methods=["get"], detail=True)
|
||||
def suggestions(self, request, pk=None):
|
||||
try:
|
||||
doc = Document.objects.get(pk=pk)
|
||||
@@ -293,26 +308,25 @@ class DocumentViewSet(RetrieveModelMixin,
|
||||
|
||||
classifier = load_classifier()
|
||||
|
||||
return Response({
|
||||
"correspondents": [
|
||||
c.id for c in match_correspondents(doc, classifier)
|
||||
],
|
||||
"tags": [t.id for t in match_tags(doc, classifier)],
|
||||
"document_types": [
|
||||
dt.id for dt in match_document_types(doc, classifier)
|
||||
]
|
||||
})
|
||||
return Response(
|
||||
{
|
||||
"correspondents": [c.id for c in match_correspondents(doc, classifier)],
|
||||
"tags": [t.id for t in match_tags(doc, classifier)],
|
||||
"document_types": [
|
||||
dt.id for dt in match_document_types(doc, classifier)
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
@action(methods=['get'], detail=True)
|
||||
@action(methods=["get"], detail=True)
|
||||
def preview(self, request, pk=None):
|
||||
try:
|
||||
response = self.file_response(
|
||||
pk, request, "inline")
|
||||
response = self.file_response(pk, request, "inline")
|
||||
return response
|
||||
except (FileNotFoundError, Document.DoesNotExist):
|
||||
raise Http404()
|
||||
|
||||
@action(methods=['get'], detail=True)
|
||||
@action(methods=["get"], detail=True)
|
||||
@cache_control(public=False, max_age=315360000)
|
||||
def thumb(self, request, pk=None):
|
||||
try:
|
||||
@@ -323,37 +337,34 @@ class DocumentViewSet(RetrieveModelMixin,
|
||||
handle = doc.thumbnail_file
|
||||
# TODO: Send ETag information and use that to send new thumbnails
|
||||
# if available
|
||||
return HttpResponse(handle,
|
||||
content_type='image/png')
|
||||
return HttpResponse(handle, content_type="image/png")
|
||||
except (FileNotFoundError, Document.DoesNotExist):
|
||||
raise Http404()
|
||||
|
||||
@action(methods=['get'], detail=True)
|
||||
@action(methods=["get"], detail=True)
|
||||
def download(self, request, pk=None):
|
||||
try:
|
||||
return self.file_response(
|
||||
pk, request, "attachment")
|
||||
return self.file_response(pk, request, "attachment")
|
||||
except (FileNotFoundError, Document.DoesNotExist):
|
||||
raise Http404()
|
||||
|
||||
|
||||
class SearchResultSerializer(DocumentSerializer):
|
||||
|
||||
def to_representation(self, instance):
|
||||
doc = Document.objects.get(id=instance['id'])
|
||||
doc = Document.objects.get(id=instance["id"])
|
||||
r = super(SearchResultSerializer, self).to_representation(doc)
|
||||
r['__search_hit__'] = {
|
||||
r["__search_hit__"] = {
|
||||
"score": instance.score,
|
||||
"highlights": instance.highlights("content",
|
||||
text=doc.content) if doc else None, # NOQA: E501
|
||||
"rank": instance.rank
|
||||
"highlights": instance.highlights("content", text=doc.content)
|
||||
if doc
|
||||
else None, # NOQA: E501
|
||||
"rank": instance.rank,
|
||||
}
|
||||
|
||||
return r
|
||||
|
||||
|
||||
class UnifiedSearchViewSet(DocumentViewSet):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(UnifiedSearchViewSet, self).__init__(*args, **kwargs)
|
||||
self.searcher = None
|
||||
@@ -365,8 +376,10 @@ class UnifiedSearchViewSet(DocumentViewSet):
|
||||
return DocumentSerializer
|
||||
|
||||
def _is_search_request(self):
|
||||
return ("query" in self.request.query_params or
|
||||
"more_like_id" in self.request.query_params)
|
||||
return (
|
||||
"query" in self.request.query_params
|
||||
or "more_like_id" in self.request.query_params
|
||||
)
|
||||
|
||||
def filter_queryset(self, queryset):
|
||||
if self._is_search_request():
|
||||
@@ -382,13 +395,15 @@ class UnifiedSearchViewSet(DocumentViewSet):
|
||||
return query_class(
|
||||
self.searcher,
|
||||
self.request.query_params,
|
||||
self.paginator.get_page_size(self.request))
|
||||
self.paginator.get_page_size(self.request),
|
||||
)
|
||||
else:
|
||||
return super(UnifiedSearchViewSet, self).filter_queryset(queryset)
|
||||
|
||||
def list(self, request, *args, **kwargs):
|
||||
if self._is_search_request():
|
||||
from documents import index
|
||||
|
||||
try:
|
||||
with index.open_index_searcher() as s:
|
||||
self.searcher = s
|
||||
@@ -474,34 +489,36 @@ class PostDocumentView(GenericAPIView):
|
||||
serializer = self.get_serializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
doc_name, doc_data = serializer.validated_data.get('document')
|
||||
correspondent_id = serializer.validated_data.get('correspondent')
|
||||
document_type_id = serializer.validated_data.get('document_type')
|
||||
tag_ids = serializer.validated_data.get('tags')
|
||||
title = serializer.validated_data.get('title')
|
||||
doc_name, doc_data = serializer.validated_data.get("document")
|
||||
correspondent_id = serializer.validated_data.get("correspondent")
|
||||
document_type_id = serializer.validated_data.get("document_type")
|
||||
tag_ids = serializer.validated_data.get("tags")
|
||||
title = serializer.validated_data.get("title")
|
||||
|
||||
t = int(mktime(datetime.now().timetuple()))
|
||||
|
||||
os.makedirs(settings.SCRATCH_DIR, exist_ok=True)
|
||||
|
||||
with tempfile.NamedTemporaryFile(prefix="paperless-upload-",
|
||||
dir=settings.SCRATCH_DIR,
|
||||
delete=False) as f:
|
||||
with tempfile.NamedTemporaryFile(
|
||||
prefix="paperless-upload-", dir=settings.SCRATCH_DIR, delete=False
|
||||
) as f:
|
||||
f.write(doc_data)
|
||||
os.utime(f.name, times=(t, t))
|
||||
temp_filename = f.name
|
||||
|
||||
task_id = str(uuid.uuid4())
|
||||
|
||||
async_task("documents.tasks.consume_file",
|
||||
temp_filename,
|
||||
override_filename=doc_name,
|
||||
override_title=title,
|
||||
override_correspondent_id=correspondent_id,
|
||||
override_document_type_id=document_type_id,
|
||||
override_tag_ids=tag_ids,
|
||||
task_id=task_id,
|
||||
task_name=os.path.basename(doc_name)[:100])
|
||||
async_task(
|
||||
"documents.tasks.consume_file",
|
||||
temp_filename,
|
||||
override_filename=doc_name,
|
||||
override_title=title,
|
||||
override_correspondent_id=correspondent_id,
|
||||
override_document_type_id=document_type_id,
|
||||
override_tag_ids=tag_ids,
|
||||
task_id=task_id,
|
||||
task_name=os.path.basename(doc_name)[:100],
|
||||
)
|
||||
|
||||
return Response("OK")
|
||||
|
||||
@@ -516,38 +533,40 @@ class SelectionDataView(GenericAPIView):
|
||||
serializer = self.get_serializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
ids = serializer.validated_data.get('documents')
|
||||
ids = serializer.validated_data.get("documents")
|
||||
|
||||
correspondents = Correspondent.objects.annotate(
|
||||
document_count=Count(Case(
|
||||
When(documents__id__in=ids, then=1),
|
||||
output_field=IntegerField()
|
||||
)))
|
||||
document_count=Count(
|
||||
Case(When(documents__id__in=ids, then=1), output_field=IntegerField())
|
||||
)
|
||||
)
|
||||
|
||||
tags = Tag.objects.annotate(document_count=Count(Case(
|
||||
When(documents__id__in=ids, then=1),
|
||||
output_field=IntegerField()
|
||||
)))
|
||||
tags = Tag.objects.annotate(
|
||||
document_count=Count(
|
||||
Case(When(documents__id__in=ids, then=1), output_field=IntegerField())
|
||||
)
|
||||
)
|
||||
|
||||
types = DocumentType.objects.annotate(document_count=Count(Case(
|
||||
When(documents__id__in=ids, then=1),
|
||||
output_field=IntegerField()
|
||||
)))
|
||||
types = DocumentType.objects.annotate(
|
||||
document_count=Count(
|
||||
Case(When(documents__id__in=ids, then=1), output_field=IntegerField())
|
||||
)
|
||||
)
|
||||
|
||||
r = Response({
|
||||
"selected_correspondents": [{
|
||||
"id": t.id,
|
||||
"document_count": t.document_count
|
||||
} for t in correspondents],
|
||||
"selected_tags": [{
|
||||
"id": t.id,
|
||||
"document_count": t.document_count
|
||||
} for t in tags],
|
||||
"selected_document_types": [{
|
||||
"id": t.id,
|
||||
"document_count": t.document_count
|
||||
} for t in types]
|
||||
})
|
||||
r = Response(
|
||||
{
|
||||
"selected_correspondents": [
|
||||
{"id": t.id, "document_count": t.document_count}
|
||||
for t in correspondents
|
||||
],
|
||||
"selected_tags": [
|
||||
{"id": t.id, "document_count": t.document_count} for t in tags
|
||||
],
|
||||
"selected_document_types": [
|
||||
{"id": t.id, "document_count": t.document_count} for t in types
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
return r
|
||||
|
||||
@@ -557,13 +576,13 @@ class SearchAutoCompleteView(APIView):
|
||||
permission_classes = (IsAuthenticated,)
|
||||
|
||||
def get(self, request, format=None):
|
||||
if 'term' in request.query_params:
|
||||
term = request.query_params['term']
|
||||
if "term" in request.query_params:
|
||||
term = request.query_params["term"]
|
||||
else:
|
||||
return HttpResponseBadRequest("Term required")
|
||||
|
||||
if 'limit' in request.query_params:
|
||||
limit = int(request.query_params['limit'])
|
||||
if "limit" in request.query_params:
|
||||
limit = int(request.query_params["limit"])
|
||||
if limit <= 0:
|
||||
return HttpResponseBadRequest("Invalid limit")
|
||||
else:
|
||||
@@ -583,15 +602,18 @@ class StatisticsView(APIView):
|
||||
def get(self, request, format=None):
|
||||
documents_total = Document.objects.all().count()
|
||||
if Tag.objects.filter(is_inbox_tag=True).exists():
|
||||
documents_inbox = Document.objects.filter(
|
||||
tags__is_inbox_tag=True).distinct().count()
|
||||
documents_inbox = (
|
||||
Document.objects.filter(tags__is_inbox_tag=True).distinct().count()
|
||||
)
|
||||
else:
|
||||
documents_inbox = None
|
||||
|
||||
return Response({
|
||||
'documents_total': documents_total,
|
||||
'documents_inbox': documents_inbox,
|
||||
})
|
||||
return Response(
|
||||
{
|
||||
"documents_total": documents_total,
|
||||
"documents_inbox": documents_inbox,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
class BulkDownloadView(GenericAPIView):
|
||||
@@ -604,19 +626,18 @@ class BulkDownloadView(GenericAPIView):
|
||||
serializer = self.get_serializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
ids = serializer.validated_data.get('documents')
|
||||
compression = serializer.validated_data.get('compression')
|
||||
content = serializer.validated_data.get('content')
|
||||
ids = serializer.validated_data.get("documents")
|
||||
compression = serializer.validated_data.get("compression")
|
||||
content = serializer.validated_data.get("content")
|
||||
|
||||
os.makedirs(settings.SCRATCH_DIR, exist_ok=True)
|
||||
temp = tempfile.NamedTemporaryFile(
|
||||
dir=settings.SCRATCH_DIR,
|
||||
suffix="-compressed-archive",
|
||||
delete=False)
|
||||
dir=settings.SCRATCH_DIR, suffix="-compressed-archive", delete=False
|
||||
)
|
||||
|
||||
if content == 'both':
|
||||
if content == "both":
|
||||
strategy_class = OriginalAndArchiveStrategy
|
||||
elif content == 'originals':
|
||||
elif content == "originals":
|
||||
strategy_class = OriginalsOnlyStrategy
|
||||
else:
|
||||
strategy_class = ArchiveOnlyStrategy
|
||||
@@ -630,6 +651,7 @@ class BulkDownloadView(GenericAPIView):
|
||||
with open(temp.name, "rb") as f:
|
||||
response = HttpResponse(f, content_type="application/zip")
|
||||
response["Content-Disposition"] = '{}; filename="{}"'.format(
|
||||
"attachment", "documents.zip")
|
||||
"attachment", "documents.zip"
|
||||
)
|
||||
|
||||
return response
|
||||
|
Reference in New Issue
Block a user