Complete conversion of download views to CBV views using django-downloadview.
This also removes dependency on the filetransfers library.
This commit is contained in:
@@ -3,6 +3,7 @@
|
|||||||
- Remove the installation app
|
- Remove the installation app
|
||||||
- Add support for document page search
|
- Add support for document page search
|
||||||
- Remove recent searches feature
|
- Remove recent searches feature
|
||||||
|
- Remove dependency on the django-filetransfer library
|
||||||
|
|
||||||
2.1.4 (2016-10-28)
|
2.1.4 (2016-10-28)
|
||||||
==================
|
==================
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ Other changes
|
|||||||
- Remove the installation app
|
- Remove the installation app
|
||||||
- Add support for page search
|
- Add support for page search
|
||||||
- Remove recent searches feature
|
- Remove recent searches feature
|
||||||
|
- Remove dependency on the django-filetransfer library
|
||||||
|
|
||||||
Removals
|
Removals
|
||||||
--------
|
--------
|
||||||
@@ -43,6 +44,7 @@ existing installation.
|
|||||||
|
|
||||||
Next upgrade/add the new requirements::
|
Next upgrade/add the new requirements::
|
||||||
|
|
||||||
|
$ pip uninstall -y django-filetransfers
|
||||||
$ pip install --upgrade -r requirements.txt
|
$ pip install --upgrade -r requirements.txt
|
||||||
|
|
||||||
Common steps
|
Common steps
|
||||||
|
|||||||
@@ -10,7 +10,9 @@ from .permissions import permission_acl_view, permission_acl_edit
|
|||||||
|
|
||||||
def get_kwargs_factory(variable_name):
|
def get_kwargs_factory(variable_name):
|
||||||
def get_kwargs(context):
|
def get_kwargs(context):
|
||||||
ContentType = apps.get_model(app_label='django', model_name='ContentType')
|
ContentType = apps.get_model(
|
||||||
|
app_label='contenttypes', model_name='ContentType'
|
||||||
|
)
|
||||||
|
|
||||||
content_type = ContentType.objects.get_for_model(
|
content_type = ContentType.objects.get_for_model(
|
||||||
context[variable_name]
|
context[variable_name]
|
||||||
|
|||||||
@@ -23,7 +23,9 @@
|
|||||||
|
|
||||||
<form action="{% url 'common:multi_object_action_view' %}" class="pure-form" method="get">
|
<form action="{% url 'common:multi_object_action_view' %}" class="pure-form" method="get">
|
||||||
{% if object_list %}
|
{% if object_list %}
|
||||||
{% get_multi_item_links_form object_list %}
|
{% if not hide_multi_item_actions %}
|
||||||
|
{% get_multi_item_links_form object_list %}
|
||||||
|
{% endif %}
|
||||||
{% if multi_item_actions %}
|
{% if multi_item_actions %}
|
||||||
<fieldset>
|
<fieldset>
|
||||||
{{ multi_item_form }}
|
{{ multi_item_form }}
|
||||||
|
|||||||
@@ -482,36 +482,6 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
''')
|
''')
|
||||||
|
|
||||||
Package(label='django-filetransfers', license_text='''
|
|
||||||
Copyright (c) Waldemar Kornewald, Thomas Wanschik, and all contributors.
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer.
|
|
||||||
|
|
||||||
2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer in the
|
|
||||||
documentation and/or other materials provided with the distribution.
|
|
||||||
|
|
||||||
3. Neither the name of All Buttons Pressed nor
|
|
||||||
the names of its contributors may be used to endorse or promote products
|
|
||||||
derived from this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
||||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
||||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
''')
|
|
||||||
|
|
||||||
Package(label='django-pure-pagination', license_text='''
|
Package(label='django-pure-pagination', license_text='''
|
||||||
Copyright (c) James Pacileo and contributors.
|
Copyright (c) James Pacileo and contributors.
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ from __future__ import unicode_literals
|
|||||||
import zipfile
|
import zipfile
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import zlib
|
import zlib # NOQA
|
||||||
COMPRESSION = zipfile.ZIP_DEFLATED
|
COMPRESSION = zipfile.ZIP_DEFLATED
|
||||||
except:
|
except:
|
||||||
COMPRESSION = zipfile.ZIP_STORED
|
COMPRESSION = zipfile.ZIP_STORED
|
||||||
|
|||||||
@@ -14,8 +14,7 @@ from django.views.generic.edit import (
|
|||||||
)
|
)
|
||||||
from django.views.generic.list import ListView
|
from django.views.generic.list import ListView
|
||||||
|
|
||||||
from django_downloadview import VirtualDownloadView
|
from django_downloadview import VirtualDownloadView, VirtualFile
|
||||||
from django_downloadview import VirtualFile
|
|
||||||
from pure_pagination.mixins import PaginationMixin
|
from pure_pagination.mixins import PaginationMixin
|
||||||
|
|
||||||
from .forms import ChoiceForm
|
from .forms import ChoiceForm
|
||||||
|
|||||||
@@ -12,9 +12,16 @@ class Command(management.BaseCommand):
|
|||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
management.call_command('createsettings', interactive=False)
|
management.call_command('createsettings', interactive=False)
|
||||||
try:
|
try:
|
||||||
result = management.call_command('migrate', interactive=False)
|
management.call_command('migrate', interactive=False)
|
||||||
except OperationalError as exception:
|
except OperationalError:
|
||||||
self.stderr.write(self.style.NOTICE('Unable to migrate the database. The initialsetup command is to be used only on new installations. To upgrade existing installations use the performupgrade command.'))
|
self.stderr.write(
|
||||||
|
self.style.NOTICE(
|
||||||
|
'Unable to migrate the database. The initialsetup '
|
||||||
|
'command is to be used only on new installations. To '
|
||||||
|
'upgrade existing installations use the performupgrade '
|
||||||
|
'command.'
|
||||||
|
)
|
||||||
|
)
|
||||||
raise
|
raise
|
||||||
management.call_command('createautoadmin', interactive=False)
|
management.call_command('createautoadmin', interactive=False)
|
||||||
post_initial_setup.send(sender=self)
|
post_initial_setup.send(sender=self)
|
||||||
|
|||||||
@@ -159,12 +159,6 @@ class RedirectionMixin(object):
|
|||||||
post_action_redirect = None
|
post_action_redirect = None
|
||||||
action_cancel_redirect = None
|
action_cancel_redirect = None
|
||||||
|
|
||||||
def get_post_action_redirect(self):
|
|
||||||
return self.post_action_redirect
|
|
||||||
|
|
||||||
def get_action_cancel_redirect(self):
|
|
||||||
return self.action_cancel_redirect
|
|
||||||
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
def dispatch(self, request, *args, **kwargs):
|
||||||
post_action_redirect = self.get_post_action_redirect()
|
post_action_redirect = self.get_post_action_redirect()
|
||||||
action_cancel_redirect = self.get_action_cancel_redirect()
|
action_cancel_redirect = self.get_action_cancel_redirect()
|
||||||
@@ -188,6 +182,9 @@ class RedirectionMixin(object):
|
|||||||
RedirectionMixin, self
|
RedirectionMixin, self
|
||||||
).dispatch(request, *args, **kwargs)
|
).dispatch(request, *args, **kwargs)
|
||||||
|
|
||||||
|
def get_action_cancel_redirect(self):
|
||||||
|
return self.action_cancel_redirect
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super(RedirectionMixin, self).get_context_data(**kwargs)
|
context = super(RedirectionMixin, self).get_context_data(**kwargs)
|
||||||
context.update(
|
context.update(
|
||||||
@@ -199,6 +196,9 @@ class RedirectionMixin(object):
|
|||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
def get_post_action_redirect(self):
|
||||||
|
return self.post_action_redirect
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
return self.next_url or self.previous_url
|
return self.next_url or self.previous_url
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
def skip_file_descriptor_check(func):
|
def skip_file_descriptor_check(func):
|
||||||
def func_wrapper(item):
|
def func_wrapper(item):
|
||||||
item._skip_file_descriptor_test = True
|
item._skip_file_descriptor_test = True
|
||||||
return func(item)
|
return func(item)
|
||||||
return func_wrapper
|
return func_wrapper
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ class TempfileCheckMixin(object):
|
|||||||
msg='Orphan temporary file. The number of temporary files and/or '
|
msg='Orphan temporary file. The number of temporary files and/or '
|
||||||
'directories at the start and at the end of the test are not the '
|
'directories at the start and at the end of the test are not the '
|
||||||
'same. Orphan entries: {}'.format(
|
'same. Orphan entries: {}'.format(
|
||||||
','.join(final_temporary_items-self._temporary_items)
|
','.join(final_temporary_items - self._temporary_items)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
super(TempfileCheckMixin, self).tearDown()
|
super(TempfileCheckMixin, self).tearDown()
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ from django.contrib.auth.models import Group
|
|||||||
from django.core.urlresolvers import clear_url_caches, reverse
|
from django.core.urlresolvers import clear_url_caches, reverse
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
from django.template import Context, Template
|
from django.template import Context, Template
|
||||||
from django.test import TestCase
|
|
||||||
|
|
||||||
from permissions import Permission
|
from permissions import Permission
|
||||||
from permissions.models import Role
|
from permissions.models import Role
|
||||||
|
|||||||
@@ -13,7 +13,9 @@ from .permissions import (
|
|||||||
|
|
||||||
def get_kwargs_factory(variable_name):
|
def get_kwargs_factory(variable_name):
|
||||||
def get_kwargs(context):
|
def get_kwargs(context):
|
||||||
ContentType = apps.get_model(app_label='django', model_name='ContentType')
|
ContentType = apps.get_model(
|
||||||
|
app_label='contenttypes', model_name='ContentType'
|
||||||
|
)
|
||||||
|
|
||||||
content_type = ContentType.objects.get_for_model(
|
content_type = ContentType.objects.get_for_model(
|
||||||
context[variable_name]
|
context[variable_name]
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import logging
|
|||||||
from django.core.exceptions import PermissionDenied
|
from django.core.exceptions import PermissionDenied
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
|
|
||||||
from filetransfers.api import serve_file
|
|
||||||
from rest_framework import generics, status
|
from rest_framework import generics, status
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
|
||||||
@@ -87,7 +86,16 @@ class APIDeletedDocumentRestoreView(generics.GenericAPIView):
|
|||||||
return Response(status=status.HTTP_200_OK)
|
return Response(status=status.HTTP_200_OK)
|
||||||
|
|
||||||
|
|
||||||
class APIDocumentDownloadView(generics.RetrieveAPIView):
|
##############
|
||||||
|
from django_downloadview import VirtualDownloadView
|
||||||
|
from django_downloadview import VirtualFile
|
||||||
|
from django_downloadview import DownloadMixin
|
||||||
|
|
||||||
|
#class SingleObjectDownloadView(ViewPermissionCheckMixin, ObjectPermissionCheckMixin, VirtualDownloadView, SingleObjectMixin):
|
||||||
|
# VirtualFile = VirtualFile
|
||||||
|
|
||||||
|
|
||||||
|
class APIDocumentDownloadView(DownloadMixin, generics.RetrieveAPIView):
|
||||||
"""
|
"""
|
||||||
Download the latest version of a document.
|
Download the latest version of a document.
|
||||||
---
|
---
|
||||||
@@ -105,17 +113,15 @@ class APIDocumentDownloadView(generics.RetrieveAPIView):
|
|||||||
permission_classes = (MayanPermission,)
|
permission_classes = (MayanPermission,)
|
||||||
queryset = Document.objects.all()
|
queryset = Document.objects.all()
|
||||||
|
|
||||||
|
def get_file(self):
|
||||||
|
instance = self.get_object()
|
||||||
|
return VirtualFile(instance.latest_version.file, name=instance.label)
|
||||||
|
|
||||||
def get_serializer_class(self):
|
def get_serializer_class(self):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def retrieve(self, request, *args, **kwargs):
|
def retrieve(self, request, *args, **kwargs):
|
||||||
instance = self.get_object()
|
return self.render_to_response()
|
||||||
return serve_file(
|
|
||||||
request,
|
|
||||||
instance.latest_version.file,
|
|
||||||
save_as='"%s"' % instance.label,
|
|
||||||
content_type=instance.latest_version.mimetype if instance.latest_version.mimetype else 'application/octet-stream'
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class APIDocumentListView(generics.ListCreateAPIView):
|
class APIDocumentListView(generics.ListCreateAPIView):
|
||||||
@@ -146,7 +152,7 @@ class APIDocumentListView(generics.ListCreateAPIView):
|
|||||||
return super(APIDocumentListView, self).post(*args, **kwargs)
|
return super(APIDocumentListView, self).post(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class APIDocumentVersionDownloadView(generics.RetrieveAPIView):
|
class APIDocumentVersionDownloadView(DownloadMixin, generics.RetrieveAPIView):
|
||||||
"""
|
"""
|
||||||
Download a document version.
|
Download a document version.
|
||||||
---
|
---
|
||||||
@@ -164,17 +170,15 @@ class APIDocumentVersionDownloadView(generics.RetrieveAPIView):
|
|||||||
permission_classes = (MayanPermission,)
|
permission_classes = (MayanPermission,)
|
||||||
queryset = DocumentVersion.objects.all()
|
queryset = DocumentVersion.objects.all()
|
||||||
|
|
||||||
|
def get_file(self):
|
||||||
|
instance = self.get_object()
|
||||||
|
return VirtualFile(instance.file, name=unicode(instance))
|
||||||
|
|
||||||
def get_serializer_class(self):
|
def get_serializer_class(self):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def retrieve(self, request, *args, **kwargs):
|
def retrieve(self, request, *args, **kwargs):
|
||||||
instance = self.get_object()
|
return self.render_to_response()
|
||||||
return serve_file(
|
|
||||||
request,
|
|
||||||
instance.file,
|
|
||||||
save_as='"%s"' % instance.document.label,
|
|
||||||
content_type=instance.mimetype if instance.mimetype else 'application/octet-stream'
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class APIDocumentView(generics.RetrieveUpdateDestroyAPIView):
|
class APIDocumentView(generics.RetrieveUpdateDestroyAPIView):
|
||||||
|
|||||||
@@ -66,7 +66,8 @@ from .permissions import (
|
|||||||
permission_document_trash, permission_document_version_revert,
|
permission_document_trash, permission_document_version_revert,
|
||||||
permission_document_view
|
permission_document_view
|
||||||
)
|
)
|
||||||
from .search import document_search, document_page_search
|
# Just import to initialize the search models
|
||||||
|
from .search import document_search, document_page_search # NOQA
|
||||||
from .settings import setting_thumbnail_size
|
from .settings import setting_thumbnail_size
|
||||||
from .statistics import (
|
from .statistics import (
|
||||||
new_documents_per_month, new_document_pages_per_month,
|
new_documents_per_month, new_document_pages_per_month,
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ link_document_document_type_edit = Link(
|
|||||||
)
|
)
|
||||||
link_document_download = Link(
|
link_document_download = Link(
|
||||||
permissions=(permission_document_download,), text=_('Download'),
|
permissions=(permission_document_download,), text=_('Download'),
|
||||||
view='documents:document_download', args='resolved_object.id'
|
view='documents:document_download_form', args='resolved_object.id'
|
||||||
)
|
)
|
||||||
link_document_print = Link(
|
link_document_print = Link(
|
||||||
permissions=(permission_document_print,), text=_('Print'),
|
permissions=(permission_document_print,), text=_('Print'),
|
||||||
@@ -118,7 +118,7 @@ link_document_multiple_document_type_edit = Link(
|
|||||||
view='documents:document_multiple_document_type_edit'
|
view='documents:document_multiple_document_type_edit'
|
||||||
)
|
)
|
||||||
link_document_multiple_download = Link(
|
link_document_multiple_download = Link(
|
||||||
text=_('Download'), view='documents:document_multiple_download'
|
text=_('Download'), view='documents:document_multiple_download_form'
|
||||||
)
|
)
|
||||||
link_document_multiple_update_page_count = Link(
|
link_document_multiple_update_page_count = Link(
|
||||||
text=_('Recalculate page count'),
|
text=_('Recalculate page count'),
|
||||||
@@ -129,7 +129,7 @@ link_document_multiple_restore = Link(
|
|||||||
)
|
)
|
||||||
link_document_version_download = Link(
|
link_document_version_download = Link(
|
||||||
args='resolved_object.pk', permissions=(permission_document_download,),
|
args='resolved_object.pk', permissions=(permission_document_download,),
|
||||||
text=_('Download version'), view='documents:document_version_download'
|
text=_('Download version'), view='documents:document_version_download_form'
|
||||||
)
|
)
|
||||||
|
|
||||||
# Views
|
# Views
|
||||||
|
|||||||
@@ -46,11 +46,14 @@ from .signals import (
|
|||||||
post_document_created, post_document_type_change, post_version_upload
|
post_document_created, post_document_type_change, post_version_upload
|
||||||
)
|
)
|
||||||
|
|
||||||
# document image cache name hash function
|
|
||||||
HASH_FUNCTION = lambda x: hashlib.sha256(x).hexdigest()
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
# document image cache name hash function
|
||||||
|
def HASH_FUNCTION(data):
|
||||||
|
return hashlib.sha256(data).hexdigest()
|
||||||
|
|
||||||
|
|
||||||
def UUID_FUNCTION(*args, **kwargs):
|
def UUID_FUNCTION(*args, **kwargs):
|
||||||
return unicode(uuid.uuid4())
|
return unicode(uuid.uuid4())
|
||||||
|
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ import time
|
|||||||
from json import loads
|
from json import loads
|
||||||
|
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
|
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.test import override_settings
|
from django.test import override_settings
|
||||||
from django.utils.six import BytesIO
|
from django.utils.six import BytesIO
|
||||||
|
|
||||||
|
from django_downloadview import assert_download_response
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
from rest_framework.test import APITestCase
|
from rest_framework.test import APITestCase
|
||||||
|
|
||||||
@@ -21,7 +21,7 @@ from user_management.tests.literals import (
|
|||||||
|
|
||||||
from .literals import (
|
from .literals import (
|
||||||
TEST_DOCUMENT_FILENAME, TEST_DOCUMENT_PATH, TEST_DOCUMENT_TYPE,
|
TEST_DOCUMENT_FILENAME, TEST_DOCUMENT_PATH, TEST_DOCUMENT_TYPE,
|
||||||
TEST_SMALL_DOCUMENT_CHECKSUM, TEST_SMALL_DOCUMENT_PATH,
|
TEST_SMALL_DOCUMENT_FILENAME, TEST_SMALL_DOCUMENT_PATH,
|
||||||
)
|
)
|
||||||
from ..models import Document, DocumentType, HASH_FUNCTION
|
from ..models import Document, DocumentType, HASH_FUNCTION
|
||||||
|
|
||||||
@@ -263,14 +263,13 @@ class DocumentAPITestCase(APITestCase):
|
|||||||
'rest_api:document-download', args=(document.pk,)
|
'rest_api:document-download', args=(document.pk,)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
buf = BytesIO()
|
|
||||||
buf.write(response.content)
|
|
||||||
|
|
||||||
self.assertEqual(
|
with document.open() as file_object:
|
||||||
HASH_FUNCTION(buf.getvalue()), TEST_SMALL_DOCUMENT_CHECKSUM
|
assert_download_response(
|
||||||
)
|
self, response, content=file_object.read(),
|
||||||
|
basename=TEST_SMALL_DOCUMENT_FILENAME,
|
||||||
del(buf)
|
mime_type='{}; charset=utf-8'.format(document.file_mimetype)
|
||||||
|
)
|
||||||
|
|
||||||
def test_document_version_download(self):
|
def test_document_version_download(self):
|
||||||
with open(TEST_SMALL_DOCUMENT_PATH) as file_object:
|
with open(TEST_SMALL_DOCUMENT_PATH) as file_object:
|
||||||
@@ -278,20 +277,22 @@ class DocumentAPITestCase(APITestCase):
|
|||||||
file_object=file_object,
|
file_object=file_object,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
latest_version = document.latest_version
|
||||||
response = self.client.get(
|
response = self.client.get(
|
||||||
reverse(
|
reverse(
|
||||||
'rest_api:documentversion-download',
|
'rest_api:documentversion-download',
|
||||||
args=(document.latest_version.pk,)
|
args=(latest_version.pk,)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
buf = BytesIO()
|
|
||||||
buf.write(response.content)
|
|
||||||
|
|
||||||
self.assertEqual(
|
with latest_version.open() as file_object:
|
||||||
HASH_FUNCTION(buf.getvalue()), TEST_SMALL_DOCUMENT_CHECKSUM
|
assert_download_response(
|
||||||
)
|
self, response, content=file_object.read(),
|
||||||
|
basename='{} - {}'.format(
|
||||||
del(buf)
|
TEST_SMALL_DOCUMENT_FILENAME,
|
||||||
|
latest_version.timestamp
|
||||||
|
), mime_type='application/octet-stream; charset=utf-8'
|
||||||
|
)
|
||||||
|
|
||||||
# TODO: def test_document_set_document_type(self):
|
# TODO: def test_document_set_document_type(self):
|
||||||
# pass
|
# pass
|
||||||
|
|||||||
@@ -3,8 +3,8 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from actstream.models import Action
|
from actstream.models import Action
|
||||||
|
from django_downloadview import assert_download_response
|
||||||
|
|
||||||
from common.tests import skip_file_descriptor_check
|
|
||||||
from user_management.tests.literals import (
|
from user_management.tests.literals import (
|
||||||
TEST_USER_PASSWORD, TEST_USER_USERNAME
|
TEST_USER_PASSWORD, TEST_USER_USERNAME
|
||||||
)
|
)
|
||||||
@@ -14,7 +14,6 @@ from ..permissions import (
|
|||||||
permission_document_download, permission_document_view
|
permission_document_download, permission_document_view
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
from .test_views import GenericDocumentViewTestCase
|
from .test_views import GenericDocumentViewTestCase
|
||||||
|
|
||||||
|
|
||||||
@@ -32,17 +31,14 @@ class DocumentEventsTestCase(GenericDocumentViewTestCase):
|
|||||||
|
|
||||||
Action.objects.all().delete()
|
Action.objects.all().delete()
|
||||||
|
|
||||||
response = self.post(
|
response = self.get(
|
||||||
'documents:document_download', args=(self.document.pk,)
|
'documents:document_download', args=(self.document.pk,)
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 302)
|
self.assertEqual(response.status_code, 403)
|
||||||
self.assertEqual(list(Action.objects.any(obj=self.document)), [])
|
self.assertEqual(list(Action.objects.any(obj=self.document)), [])
|
||||||
|
|
||||||
@skip_file_descriptor_check
|
|
||||||
def test_document_download_event_with_permissions(self):
|
def test_document_download_event_with_permissions(self):
|
||||||
# TODO: Skip this test's file descriptor check until it gets migrate
|
|
||||||
# SingleObjectDownloadView CBV
|
|
||||||
self.login(
|
self.login(
|
||||||
username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD
|
username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD
|
||||||
)
|
)
|
||||||
@@ -53,12 +49,19 @@ class DocumentEventsTestCase(GenericDocumentViewTestCase):
|
|||||||
permission_document_download.stored_permission
|
permission_document_download.stored_permission
|
||||||
)
|
)
|
||||||
|
|
||||||
self.expected_content_type = 'image/png'
|
self.expected_content_type = 'image/png; charset=utf-8'
|
||||||
|
|
||||||
self.post(
|
response = self.get(
|
||||||
'documents:document_download', args=(self.document.pk,),
|
'documents:document_download', args=(self.document.pk,),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Download the file to close the file descriptor
|
||||||
|
with self.document.open() as file_object:
|
||||||
|
assert_download_response(
|
||||||
|
self, response, content=file_object.read(),
|
||||||
|
mime_type=self.document.file_mimetype
|
||||||
|
)
|
||||||
|
|
||||||
event = Action.objects.any(obj=self.document).first()
|
event = Action.objects.any(obj=self.document).first()
|
||||||
|
|
||||||
self.assertEqual(event.verb, event_document_download.name)
|
self.assertEqual(event.verb, event_document_download.name)
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ class DocumentsLinksTestCase(GenericDocumentViewTestCase):
|
|||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
resolved_link.url,
|
resolved_link.url,
|
||||||
reverse(
|
reverse(
|
||||||
'documents:document_version_download',
|
'documents:document_version_download_form',
|
||||||
args=(self.document.latest_version.pk,)
|
args=(self.document.latest_version.pk,)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ from datetime import timedelta
|
|||||||
import time
|
import time
|
||||||
|
|
||||||
from common.tests import BaseTestCase
|
from common.tests import BaseTestCase
|
||||||
from django.test import TestCase, override_settings
|
from django.test import override_settings
|
||||||
|
|
||||||
from ..exceptions import NewDocumentVersionNotAllowed
|
from ..exceptions import NewDocumentVersionNotAllowed
|
||||||
from ..literals import STUB_EXPIRATION_INTERVAL
|
from ..literals import STUB_EXPIRATION_INTERVAL
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ from __future__ import unicode_literals
|
|||||||
|
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.test import override_settings
|
from django.test import override_settings
|
||||||
from django.utils.six import BytesIO
|
|
||||||
|
|
||||||
from common.tests import skip_file_descriptor_check
|
from django_downloadview import assert_download_response
|
||||||
|
|
||||||
from common.tests.test_views import GenericViewTestCase
|
from common.tests.test_views import GenericViewTestCase
|
||||||
from converter.models import Transformation
|
from converter.models import Transformation
|
||||||
from converter.permissions import permission_transformation_delete
|
from converter.permissions import permission_transformation_delete
|
||||||
@@ -15,9 +15,7 @@ from user_management.tests.literals import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from ..literals import DEFAULT_DELETE_PERIOD, DEFAULT_DELETE_TIME_UNIT
|
from ..literals import DEFAULT_DELETE_PERIOD, DEFAULT_DELETE_TIME_UNIT
|
||||||
from ..models import (
|
from ..models import DeletedDocument, Document, DocumentType
|
||||||
DeletedDocument, Document, DocumentType, HASH_FUNCTION
|
|
||||||
)
|
|
||||||
from ..permissions import (
|
from ..permissions import (
|
||||||
permission_document_create, permission_document_delete,
|
permission_document_create, permission_document_delete,
|
||||||
permission_document_download, permission_document_properties_edit,
|
permission_document_download, permission_document_properties_edit,
|
||||||
@@ -30,7 +28,7 @@ from ..permissions import (
|
|||||||
|
|
||||||
from .literals import (
|
from .literals import (
|
||||||
TEST_DOCUMENT_TYPE, TEST_DOCUMENT_TYPE_QUICK_LABEL,
|
TEST_DOCUMENT_TYPE, TEST_DOCUMENT_TYPE_QUICK_LABEL,
|
||||||
TEST_SMALL_DOCUMENT_CHECKSUM, TEST_SMALL_DOCUMENT_PATH
|
TEST_SMALL_DOCUMENT_FILENAME, TEST_SMALL_DOCUMENT_PATH
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -226,113 +224,113 @@ class DocumentsViewsTestCase(GenericDocumentViewTestCase):
|
|||||||
Document.objects.first().document_type, document_type
|
Document.objects.first().document_type, document_type
|
||||||
)
|
)
|
||||||
|
|
||||||
@skip_file_descriptor_check
|
def test_document_download_view_no_permission(self):
|
||||||
def test_document_download_user_view(self):
|
|
||||||
# TODO: Skip this test's file descriptor check until it gets migrate
|
|
||||||
# SingleObjectDownloadView CBV
|
|
||||||
|
|
||||||
self.login(
|
self.login(
|
||||||
username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD
|
username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(Document.objects.count(), 1)
|
response = self.get(
|
||||||
|
|
||||||
response = self.post(
|
|
||||||
'documents:document_download', args=(self.document.pk,)
|
'documents:document_download', args=(self.document.pk,)
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 302)
|
self.assertEqual(response.status_code, 403)
|
||||||
|
|
||||||
|
def test_document_download_view_with_permission(self):
|
||||||
|
self.login(
|
||||||
|
username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD
|
||||||
|
)
|
||||||
|
|
||||||
self.role.permissions.add(
|
self.role.permissions.add(
|
||||||
permission_document_download.stored_permission
|
permission_document_download.stored_permission
|
||||||
)
|
)
|
||||||
|
|
||||||
# Set the expected_content_type for common.tests.mixins.ContentTypeCheckMixin
|
# Set the expected_content_type for
|
||||||
self.expected_content_type = self.document.file_mimetype
|
# common.tests.mixins.ContentTypeCheckMixin
|
||||||
|
self.expected_content_type = '{}; charset=utf-8'.format(
|
||||||
|
self.document.file_mimetype
|
||||||
|
)
|
||||||
|
|
||||||
response = self.post(
|
response = self.get(
|
||||||
'documents:document_download', args=(self.document.pk,)
|
'documents:document_download', args=(self.document.pk,)
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
buf = BytesIO()
|
with self.document.open() as file_object:
|
||||||
buf.write(response.content)
|
assert_download_response(
|
||||||
|
self, response, content=file_object.read(),
|
||||||
self.assertEqual(
|
basename=TEST_SMALL_DOCUMENT_FILENAME,
|
||||||
HASH_FUNCTION(buf.getvalue()), TEST_SMALL_DOCUMENT_CHECKSUM
|
mime_type=self.document.file_mimetype
|
||||||
)
|
)
|
||||||
|
|
||||||
del(buf)
|
|
||||||
|
|
||||||
@skip_file_descriptor_check
|
|
||||||
def test_document_multiple_download_user_view(self):
|
|
||||||
# TODO: Skip this test's file descriptor check until it gets migrate
|
|
||||||
# SingleObjectDownloadView CBV
|
|
||||||
|
|
||||||
|
def test_document_multiple_download_view_no_permission(self):
|
||||||
self.login(
|
self.login(
|
||||||
username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD
|
username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(Document.objects.count(), 1)
|
response = self.get(
|
||||||
|
|
||||||
response = self.post(
|
|
||||||
'documents:document_multiple_download',
|
'documents:document_multiple_download',
|
||||||
data={'id_list': self.document.pk}
|
data={'id_list': self.document.pk}
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 302)
|
self.assertEqual(response.status_code, 403)
|
||||||
|
|
||||||
|
def test_document_multiple_download_view_with_permission(self):
|
||||||
|
self.login(
|
||||||
|
username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD
|
||||||
|
)
|
||||||
|
|
||||||
self.role.permissions.add(
|
self.role.permissions.add(
|
||||||
permission_document_download.stored_permission
|
permission_document_download.stored_permission
|
||||||
)
|
)
|
||||||
|
|
||||||
# Set the expected_content_type for common.tests.mixins.ContentTypeCheckMixin
|
# Set the expected_content_type for
|
||||||
self.expected_content_type = self.document.file_mimetype
|
# common.tests.mixins.ContentTypeCheckMixin
|
||||||
|
self.expected_content_type = '{}; charset=utf-8'.format(
|
||||||
|
self.document.file_mimetype
|
||||||
|
)
|
||||||
|
|
||||||
response = self.post(
|
response = self.get(
|
||||||
'documents:document_multiple_download',
|
'documents:document_multiple_download',
|
||||||
data={'id_list': self.document.pk}
|
data={'id_list': self.document.pk}
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
buf = BytesIO()
|
with self.document.open() as file_object:
|
||||||
buf.write(response.content)
|
assert_download_response(
|
||||||
|
self, response, content=file_object.read(),
|
||||||
self.assertEqual(
|
basename=TEST_SMALL_DOCUMENT_FILENAME,
|
||||||
HASH_FUNCTION(buf.getvalue()), TEST_SMALL_DOCUMENT_CHECKSUM
|
mime_type=self.document.file_mimetype
|
||||||
)
|
)
|
||||||
|
|
||||||
del(buf)
|
|
||||||
|
|
||||||
@skip_file_descriptor_check
|
|
||||||
def test_document_version_download_user_view(self):
|
|
||||||
# TODO: Skip this test's file descriptor check until it gets migrate
|
|
||||||
# SingleObjectDownloadView CBV
|
|
||||||
|
|
||||||
|
def test_document_version_download_view_no_permission(self):
|
||||||
self.login(
|
self.login(
|
||||||
username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD
|
username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(Document.objects.count(), 1)
|
response = self.get(
|
||||||
|
|
||||||
response = self.post(
|
|
||||||
'documents:document_version_download', args=(
|
'documents:document_version_download', args=(
|
||||||
self.document.latest_version.pk,
|
self.document.latest_version.pk,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 302)
|
self.assertEqual(response.status_code, 403)
|
||||||
|
|
||||||
|
def test_document_version_download_view_with_permission(self):
|
||||||
|
self.login(
|
||||||
|
username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD
|
||||||
|
)
|
||||||
|
|
||||||
self.role.permissions.add(
|
self.role.permissions.add(
|
||||||
permission_document_download.stored_permission
|
permission_document_download.stored_permission
|
||||||
)
|
)
|
||||||
|
|
||||||
# Set the expected_content_type for common.tests.mixins.ContentTypeCheckMixin
|
# Set the expected_content_type for
|
||||||
self.expected_content_type = self.document.file_mimetype
|
# common.tests.mixins.ContentTypeCheckMixin
|
||||||
|
self.expected_content_type = 'application/octet-stream; charset=utf-8'
|
||||||
|
|
||||||
response = self.post(
|
response = self.get(
|
||||||
'documents:document_version_download', args=(
|
'documents:document_version_download', args=(
|
||||||
self.document.latest_version.pk,
|
self.document.latest_version.pk,
|
||||||
)
|
)
|
||||||
@@ -340,14 +338,14 @@ class DocumentsViewsTestCase(GenericDocumentViewTestCase):
|
|||||||
|
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
buf = BytesIO()
|
with self.document.open() as file_object:
|
||||||
buf.write(response.content)
|
assert_download_response(
|
||||||
|
self, response, content=file_object.read(),
|
||||||
self.assertEqual(
|
basename='{} - {}'.format(
|
||||||
HASH_FUNCTION(buf.getvalue()), TEST_SMALL_DOCUMENT_CHECKSUM
|
TEST_SMALL_DOCUMENT_FILENAME,
|
||||||
)
|
self.document.latest_version.timestamp
|
||||||
|
), mime_type='application/octet-stream; charset=utf-8'
|
||||||
del(buf)
|
)
|
||||||
|
|
||||||
def test_document_update_page_count_view_no_permission(self):
|
def test_document_update_page_count_view_no_permission(self):
|
||||||
self.login(username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD)
|
self.login(username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD)
|
||||||
@@ -380,7 +378,6 @@ class DocumentsViewsTestCase(GenericDocumentViewTestCase):
|
|||||||
self.assertContains(response, text='queued', status_code=200)
|
self.assertContains(response, text='queued', status_code=200)
|
||||||
self.assertEqual(self.document.pages.count(), page_count)
|
self.assertEqual(self.document.pages.count(), page_count)
|
||||||
|
|
||||||
|
|
||||||
def test_document_multiple_update_page_count_view_no_permission(self):
|
def test_document_multiple_update_page_count_view_no_permission(self):
|
||||||
self.login(username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD)
|
self.login(username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD)
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ from .api_views import (
|
|||||||
from .settings import setting_print_size, setting_display_size
|
from .settings import setting_print_size, setting_display_size
|
||||||
from .views import (
|
from .views import (
|
||||||
ClearImageCacheView, DeletedDocumentDeleteView,
|
ClearImageCacheView, DeletedDocumentDeleteView,
|
||||||
DeletedDocumentDeleteManyView, DeletedDocumentListView, DocumentEditView,
|
DeletedDocumentDeleteManyView, DeletedDocumentListView,
|
||||||
|
DocumentDownloadFormView, DocumentDownloadView, DocumentEditView,
|
||||||
DocumentListView, DocumentPageView, DocumentPageListView,
|
DocumentListView, DocumentPageView, DocumentPageListView,
|
||||||
DocumentPageViewResetView, DocumentPreviewView, DocumentRestoreView,
|
DocumentPageViewResetView, DocumentPreviewView, DocumentRestoreView,
|
||||||
DocumentRestoreManyView, DocumentTrashView, DocumentTrashManyView,
|
DocumentRestoreManyView, DocumentTrashView, DocumentTrashManyView,
|
||||||
@@ -23,6 +24,7 @@ from .views import (
|
|||||||
DocumentTypeDocumentListView, DocumentTypeFilenameCreateView,
|
DocumentTypeDocumentListView, DocumentTypeFilenameCreateView,
|
||||||
DocumentTypeFilenameDeleteView, DocumentTypeFilenameEditView,
|
DocumentTypeFilenameDeleteView, DocumentTypeFilenameEditView,
|
||||||
DocumentTypeFilenameListView, DocumentTypeListView, DocumentTypeEditView,
|
DocumentTypeFilenameListView, DocumentTypeListView, DocumentTypeEditView,
|
||||||
|
DocumentVersionDownloadFormView, DocumentVersionDownloadView,
|
||||||
DocumentVersionListView, DocumentVersionRevertView, DocumentView,
|
DocumentVersionListView, DocumentVersionRevertView, DocumentView,
|
||||||
EmptyTrashCanView, RecentDocumentListView
|
EmptyTrashCanView, RecentDocumentListView
|
||||||
)
|
)
|
||||||
@@ -107,13 +109,20 @@ urlpatterns = patterns(
|
|||||||
'size': setting_print_size.value
|
'size': setting_print_size.value
|
||||||
}, 'document_display_print'
|
}, 'document_display_print'
|
||||||
),
|
),
|
||||||
|
|
||||||
url(
|
url(
|
||||||
r'^(?P<document_id>\d+)/download/$', 'document_download',
|
r'^(?P<pk>\d+)/download/form/$',
|
||||||
|
DocumentDownloadFormView.as_view(), name='document_download_form'
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r'^(?P<pk>\d+)/download/$', DocumentDownloadView.as_view(),
|
||||||
name='document_download'
|
name='document_download'
|
||||||
),
|
),
|
||||||
url(
|
url(
|
||||||
r'^multiple/download/$', 'document_multiple_download',
|
r'^multiple/download/form/$', DocumentDownloadFormView.as_view(),
|
||||||
|
name='document_multiple_download_form'
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r'^multiple/download/$', DocumentDownloadView.as_view(),
|
||||||
name='document_multiple_download'
|
name='document_multiple_download'
|
||||||
),
|
),
|
||||||
url(
|
url(
|
||||||
@@ -127,8 +136,13 @@ urlpatterns = patterns(
|
|||||||
name='document_version_list'
|
name='document_version_list'
|
||||||
),
|
),
|
||||||
url(
|
url(
|
||||||
r'^document/version/(?P<document_version_pk>\d+)/download/$',
|
r'^document/version/(?P<pk>\d+)/download/form/$',
|
||||||
'document_download', name='document_version_download'
|
DocumentVersionDownloadFormView.as_view(),
|
||||||
|
name='document_version_download_form'
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r'^document/version/(?P<pk>\d+)/download/$',
|
||||||
|
DocumentVersionDownloadView.as_view(), name='document_version_download'
|
||||||
),
|
),
|
||||||
url(
|
url(
|
||||||
r'^document/version/(?P<pk>\d+)/revert/$',
|
r'^document/version/(?P<pk>\d+)/revert/$',
|
||||||
|
|||||||
+195
-138
@@ -18,8 +18,9 @@ from django.views.generic import RedirectView
|
|||||||
from acls.models import AccessControlList
|
from acls.models import AccessControlList
|
||||||
from common.compressed_files import CompressedFile
|
from common.compressed_files import CompressedFile
|
||||||
from common.generics import (
|
from common.generics import (
|
||||||
ConfirmView, SimpleView, SingleObjectCreateView, SingleObjectDeleteView,
|
ConfirmView, FormView, SimpleView, SingleObjectCreateView,
|
||||||
SingleObjectDetailView, SingleObjectEditView, SingleObjectListView
|
SingleObjectDeleteView, SingleObjectDetailView, SingleObjectDownloadView,
|
||||||
|
SingleObjectEditView, SingleObjectListView
|
||||||
)
|
)
|
||||||
from common.mixins import MultipleInstanceActionMixin
|
from common.mixins import MultipleInstanceActionMixin
|
||||||
from converter.literals import (
|
from converter.literals import (
|
||||||
@@ -27,7 +28,6 @@ from converter.literals import (
|
|||||||
)
|
)
|
||||||
from converter.models import Transformation
|
from converter.models import Transformation
|
||||||
from converter.permissions import permission_transformation_delete
|
from converter.permissions import permission_transformation_delete
|
||||||
from filetransfers.api import serve_file
|
|
||||||
from permissions import Permission
|
from permissions import Permission
|
||||||
|
|
||||||
from .events import event_document_download, event_document_view
|
from .events import event_document_download, event_document_view
|
||||||
@@ -36,7 +36,9 @@ from .forms import (
|
|||||||
DocumentPropertiesForm, DocumentTypeSelectForm,
|
DocumentPropertiesForm, DocumentTypeSelectForm,
|
||||||
DocumentTypeFilenameForm_create, PrintForm
|
DocumentTypeFilenameForm_create, PrintForm
|
||||||
)
|
)
|
||||||
from .literals import DOCUMENT_IMAGE_TASK_TIMEOUT, PAGE_RANGE_RANGE
|
from .literals import (
|
||||||
|
DOCUMENT_IMAGE_TASK_TIMEOUT, PAGE_RANGE_RANGE, DEFAULT_ZIP_FILENAME
|
||||||
|
)
|
||||||
from .models import (
|
from .models import (
|
||||||
DeletedDocument, Document, DocumentType, DocumentPage,
|
DeletedDocument, Document, DocumentType, DocumentPage,
|
||||||
DocumentTypeFilename, DocumentVersion, RecentDocument
|
DocumentTypeFilename, DocumentVersion, RecentDocument
|
||||||
@@ -771,154 +773,209 @@ def get_document_image(request, document_id, size=setting_preview_size.value):
|
|||||||
return HttpResponse(base64.b64decode(data.partition('base64,')[2]), content_type='image')
|
return HttpResponse(base64.b64decode(data.partition('base64,')[2]), content_type='image')
|
||||||
|
|
||||||
|
|
||||||
def document_download(request, document_id=None, document_id_list=None, document_version_pk=None):
|
class DocumentDownloadFormView(FormView):
|
||||||
previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', reverse(settings.LOGIN_REDIRECT_URL))))
|
form_class = DocumentDownloadForm
|
||||||
|
model = Document
|
||||||
|
multiple_download_view = 'documents:document_multiple_download'
|
||||||
|
single_download_view = 'documents:document_download'
|
||||||
|
|
||||||
if document_id:
|
def get_document_queryset(self):
|
||||||
documents = Document.objects.filter(pk=document_id)
|
id_list = self.request.GET.get(
|
||||||
elif document_id_list:
|
'id_list', self.request.POST.get('id_list', '')
|
||||||
documents = Document.objects.filter(pk__in=document_id_list)
|
|
||||||
elif document_version_pk:
|
|
||||||
documents = Document.objects.filter(
|
|
||||||
pk=get_object_or_404(
|
|
||||||
DocumentVersion, pk=document_version_pk
|
|
||||||
).document.pk
|
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
if not id_list:
|
||||||
Permission.check_permissions(
|
id_list = self.kwargs['pk']
|
||||||
request.user, (permission_document_download,)
|
|
||||||
)
|
|
||||||
except PermissionDenied:
|
|
||||||
documents = AccessControlList.objects.filter_by_access(
|
|
||||||
permission_document_download, request.user, documents
|
|
||||||
)
|
|
||||||
|
|
||||||
if not documents:
|
return self.model.objects.filter(
|
||||||
messages.error(
|
pk__in=id_list.split(',')
|
||||||
request, _('Must provide at least one document or version.')
|
).filter(is_stub=False)
|
||||||
)
|
|
||||||
return HttpResponseRedirect(
|
|
||||||
request.META.get(
|
|
||||||
'HTTP_REFERER', reverse(settings.LOGIN_REDIRECT_URL)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
if document_version_pk:
|
def get_extra_context(self):
|
||||||
queryset = DocumentVersion.objects.filter(pk=document_version_pk)
|
subtemplates_list = [
|
||||||
else:
|
{
|
||||||
queryset = DocumentVersion.objects.filter(
|
'name': 'appearance/generic_list_subtemplate.html',
|
||||||
pk__in=[document.latest_version.pk for document in documents]
|
'context': {
|
||||||
)
|
'object_list': self.queryset,
|
||||||
|
'hide_link': True,
|
||||||
subtemplates_list = []
|
'hide_links': True,
|
||||||
subtemplates_list.append(
|
'hide_multi_item_actions': True,
|
||||||
{
|
}
|
||||||
'name': 'appearance/generic_list_subtemplate.html',
|
|
||||||
'context': {
|
|
||||||
'title': _('Documents to be downloaded'),
|
|
||||||
'object_list': queryset,
|
|
||||||
'hide_link': True,
|
|
||||||
'hide_object': True,
|
|
||||||
'hide_links': True,
|
|
||||||
'scrollable_content': True,
|
|
||||||
'scrollable_content_height': '200px',
|
|
||||||
'extra_columns': (
|
|
||||||
{'name': _('Document'), 'attribute': 'document'},
|
|
||||||
{'name': _('Date and time'), 'attribute': 'timestamp'},
|
|
||||||
{'name': _('MIME type'), 'attribute': 'mimetype'},
|
|
||||||
{'name': _('Encoding'), 'attribute': 'encoding'},
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
context = {
|
||||||
|
'submit_label': _('Download'),
|
||||||
|
'subtemplates_list': subtemplates_list,
|
||||||
|
'title': _('Download documents'),
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
if request.method == 'POST':
|
if self.queryset.count() == 1:
|
||||||
form = DocumentDownloadForm(request.POST, queryset=queryset)
|
context['object'] = self.queryset.first()
|
||||||
if form.is_valid():
|
|
||||||
if form.cleaned_data['compressed'] or queryset.count() > 1:
|
|
||||||
try:
|
|
||||||
compressed_file = CompressedFile()
|
|
||||||
for document_version in queryset:
|
|
||||||
descriptor = document_version.open()
|
|
||||||
compressed_file.add_file(
|
|
||||||
descriptor,
|
|
||||||
arcname=document_version.document.label
|
|
||||||
)
|
|
||||||
descriptor.close()
|
|
||||||
event_document_download.commit(
|
|
||||||
actor=request.user,
|
|
||||||
target=document_version.document
|
|
||||||
)
|
|
||||||
|
|
||||||
compressed_file.close()
|
return context
|
||||||
|
|
||||||
return serve_file(
|
def get_form_kwargs(self):
|
||||||
request,
|
kwargs = super(DocumentDownloadFormView, self).get_form_kwargs()
|
||||||
compressed_file.as_file(
|
self.queryset = self.get_queryset()
|
||||||
form.cleaned_data['zip_filename']
|
kwargs.update({'queryset': self.queryset})
|
||||||
),
|
return kwargs
|
||||||
save_as='"%s"' % form.cleaned_data['zip_filename'],
|
|
||||||
content_type='application/zip'
|
def form_valid(self, form):
|
||||||
)
|
querystring = urlencode(
|
||||||
except Exception as exception:
|
{
|
||||||
if settings.DEBUG:
|
'compressed': form.cleaned_data['compressed'],
|
||||||
raise
|
'zip_filename': form.cleaned_data['zip_filename'],
|
||||||
else:
|
'id_list': ','.join(
|
||||||
messages.error(request, exception)
|
map(str, self.queryset.values_list('pk', flat=True))
|
||||||
return HttpResponseRedirect(
|
)
|
||||||
request.META['HTTP_REFERER']
|
}, doseq=True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if self.queryset.count() > 1:
|
||||||
|
url = reverse(self.multiple_download_view)
|
||||||
|
else:
|
||||||
|
url = reverse(
|
||||||
|
self.single_download_view, args=(self.queryset.first().pk,)
|
||||||
|
)
|
||||||
|
|
||||||
|
return HttpResponseRedirect('{}?{}'.format(url, querystring))
|
||||||
|
|
||||||
|
def get_post_action_redirect(self):
|
||||||
|
return self.post_action_redirect
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
queryset = self.get_document_queryset()
|
||||||
|
|
||||||
|
try:
|
||||||
|
Permission.check_permissions(
|
||||||
|
self.request.user, (permission_document_download,)
|
||||||
|
)
|
||||||
|
except PermissionDenied:
|
||||||
|
return AccessControlList.objects.filter_by_access(
|
||||||
|
permission_document_download, self.request.user, queryset
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return queryset
|
||||||
|
|
||||||
|
|
||||||
|
class DocumentDownloadView(SingleObjectDownloadView):
|
||||||
|
model = Document
|
||||||
|
# Set to None to disable the .get_object call
|
||||||
|
object_permission = None
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def commit_event(item, request):
|
||||||
|
if isinstance(item, Document):
|
||||||
|
event_document_download.commit(
|
||||||
|
actor=request.user,
|
||||||
|
target=item
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# TODO: Improve by adding a document version download event
|
||||||
|
event_document_download.commit(
|
||||||
|
actor=request.user,
|
||||||
|
target=item.document
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_item_file(item):
|
||||||
|
if isinstance(item, Document):
|
||||||
|
return item.open()
|
||||||
|
else:
|
||||||
|
return item.file
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_item_label(item):
|
||||||
|
if isinstance(item, Document):
|
||||||
|
return item.label
|
||||||
|
else:
|
||||||
|
return unicode(item)
|
||||||
|
|
||||||
|
def get_document_queryset(self):
|
||||||
|
id_list = self.request.GET.get(
|
||||||
|
'id_list', self.request.POST.get('id_list', '')
|
||||||
|
)
|
||||||
|
|
||||||
|
if not id_list:
|
||||||
|
id_list = self.kwargs['pk']
|
||||||
|
|
||||||
|
queryset = self.model.objects.filter(pk__in=id_list.split(','))
|
||||||
|
|
||||||
|
try:
|
||||||
|
Permission.check_permissions(
|
||||||
|
self.request.user, (permission_document_download,)
|
||||||
|
)
|
||||||
|
except PermissionDenied:
|
||||||
|
return AccessControlList.objects.filter_by_access(
|
||||||
|
permission_document_download, self.request.user, queryset
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return queryset
|
||||||
|
|
||||||
|
def get_file(self):
|
||||||
|
queryset = self.get_document_queryset()
|
||||||
|
zip_filename = self.request.GET.get(
|
||||||
|
'zip_filename', DEFAULT_ZIP_FILENAME
|
||||||
|
)
|
||||||
|
|
||||||
|
if self.request.GET.get('compressed') == 'True' or queryset.count() > 1:
|
||||||
|
compressed_file = CompressedFile()
|
||||||
|
for item in queryset:
|
||||||
|
descriptor = item.open()
|
||||||
|
compressed_file.add_file(
|
||||||
|
descriptor,
|
||||||
|
arcname=DocumentDownloadView.get_item_label(item=item)
|
||||||
|
)
|
||||||
|
descriptor.close()
|
||||||
|
DocumentDownloadView.commit_event(
|
||||||
|
item=item, request=self.request
|
||||||
|
)
|
||||||
|
|
||||||
|
compressed_file.close()
|
||||||
|
|
||||||
|
return DocumentDownloadView.VirtualFile(
|
||||||
|
compressed_file.as_file(zip_filename),
|
||||||
|
name=zip_filename
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
item = queryset.first()
|
||||||
|
if item:
|
||||||
|
DocumentDownloadView.commit_event(
|
||||||
|
item=item, request=self.request
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
try:
|
raise PermissionDenied
|
||||||
# Test permissions and trigger exception
|
|
||||||
fd = queryset.first().open()
|
|
||||||
fd.close()
|
|
||||||
event_document_download.commit(
|
|
||||||
actor=request.user, target=queryset.first().document
|
|
||||||
)
|
|
||||||
return serve_file(
|
|
||||||
request,
|
|
||||||
queryset.first().file,
|
|
||||||
save_as='"%s"' % queryset.first().document.label,
|
|
||||||
content_type=queryset.first().mimetype if queryset.first().mimetype else 'application/octet-stream'
|
|
||||||
)
|
|
||||||
except Exception as exception:
|
|
||||||
if settings.DEBUG:
|
|
||||||
raise
|
|
||||||
else:
|
|
||||||
messages.error(request, exception)
|
|
||||||
return HttpResponseRedirect(
|
|
||||||
request.META['HTTP_REFERER']
|
|
||||||
)
|
|
||||||
|
|
||||||
else:
|
return DocumentDownloadView.VirtualFile(
|
||||||
form = DocumentDownloadForm(queryset=queryset)
|
DocumentDownloadView.get_item_file(item=item),
|
||||||
|
name=DocumentDownloadView.get_item_label(
|
||||||
context = {
|
item=item
|
||||||
'form': form,
|
)
|
||||||
'previous': previous,
|
)
|
||||||
'submit_label': _('Download'),
|
|
||||||
'subtemplates_list': subtemplates_list,
|
|
||||||
'title': _('Download documents'),
|
|
||||||
}
|
|
||||||
|
|
||||||
if queryset.count() == 1:
|
|
||||||
context['object'] = queryset.first().document
|
|
||||||
|
|
||||||
return render_to_response(
|
|
||||||
'appearance/generic_form.html',
|
|
||||||
context,
|
|
||||||
context_instance=RequestContext(request)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def document_multiple_download(request):
|
class DocumentVersionDownloadFormView(DocumentDownloadFormView):
|
||||||
return document_download(
|
model = DocumentVersion
|
||||||
request, document_id_list=request.GET.get(
|
multiple_download_view = None
|
||||||
'id_list', request.POST.get('id_list', '')
|
single_download_view = 'documents:document_version_download'
|
||||||
).split(',')
|
|
||||||
)
|
def get_document_queryset(self):
|
||||||
|
id_list = self.request.GET.get(
|
||||||
|
'id_list', self.request.POST.get('id_list', '')
|
||||||
|
)
|
||||||
|
|
||||||
|
if not id_list:
|
||||||
|
id_list = self.kwargs['pk']
|
||||||
|
|
||||||
|
return self.model.objects.filter(
|
||||||
|
pk__in=id_list.split(',')
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class DocumentVersionDownloadView(DocumentDownloadView):
|
||||||
|
model = DocumentVersion
|
||||||
|
object_permission = permission_document_download
|
||||||
|
|
||||||
|
|
||||||
def document_update_page_count(request, document_id=None, document_id_list=None):
|
def document_update_page_count(request, document_id=None, document_id_list=None):
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ from .permissions import permission_events_view
|
|||||||
def get_kwargs_factory(variable_name):
|
def get_kwargs_factory(variable_name):
|
||||||
def get_kwargs(context):
|
def get_kwargs(context):
|
||||||
ContentType = apps.get_model(
|
ContentType = apps.get_model(
|
||||||
app_label='django', model_name='ContentType'
|
app_label='contenttypes', model_name='ContentType'
|
||||||
)
|
)
|
||||||
|
|
||||||
content_type = ContentType.objects.get_for_model(
|
content_type = ContentType.objects.get_for_model(
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ from __future__ import absolute_import, unicode_literals
|
|||||||
|
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
|
|
||||||
from acls.models import AccessControlList
|
|
||||||
from documents.tests.test_views import GenericDocumentViewTestCase
|
from documents.tests.test_views import GenericDocumentViewTestCase
|
||||||
from user_management.tests import (
|
from user_management.tests import (
|
||||||
TEST_USER_USERNAME, TEST_USER_PASSWORD
|
TEST_USER_USERNAME, TEST_USER_PASSWORD
|
||||||
|
|||||||
@@ -13,12 +13,37 @@ class Migration(migrations.Migration):
|
|||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='MessageOfTheDay',
|
name='MessageOfTheDay',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
(
|
||||||
('label', models.CharField(max_length=32, verbose_name='Label')),
|
'id', models.AutoField(
|
||||||
('message', models.TextField(verbose_name='Message', blank=True)),
|
verbose_name='ID', serialize=False, auto_created=True,
|
||||||
('enabled', models.BooleanField(default=True, verbose_name='Enabled')),
|
primary_key=True
|
||||||
('start_datetime', models.DateTimeField(verbose_name='Start date time', blank=True)),
|
)
|
||||||
('end_datetime', models.DateTimeField(verbose_name='End date time', blank=True)),
|
),
|
||||||
|
(
|
||||||
|
'label', models.CharField(
|
||||||
|
max_length=32, verbose_name='Label'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'message', models.TextField(
|
||||||
|
verbose_name='Message', blank=True
|
||||||
|
)
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'enabled', models.BooleanField(
|
||||||
|
default=True, verbose_name='Enabled'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'start_datetime', models.DateTimeField(
|
||||||
|
verbose_name='Start date time', blank=True
|
||||||
|
)
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'end_datetime', models.DateTimeField(
|
||||||
|
verbose_name='End date time', blank=True
|
||||||
|
)
|
||||||
|
),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'Message of the day',
|
'verbose_name': 'Message of the day',
|
||||||
|
|||||||
@@ -14,11 +14,15 @@ class Migration(migrations.Migration):
|
|||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='messageoftheday',
|
model_name='messageoftheday',
|
||||||
name='end_datetime',
|
name='end_datetime',
|
||||||
field=models.DateTimeField(null=True, verbose_name='End date time', blank=True),
|
field=models.DateTimeField(
|
||||||
|
null=True, verbose_name='End date time', blank=True
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='messageoftheday',
|
model_name='messageoftheday',
|
||||||
name='start_datetime',
|
name='start_datetime',
|
||||||
field=models.DateTimeField(null=True, verbose_name='Start date time', blank=True),
|
field=models.DateTimeField(
|
||||||
|
null=True, verbose_name='Start date time', blank=True
|
||||||
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -14,21 +14,35 @@ class Migration(migrations.Migration):
|
|||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='message',
|
model_name='message',
|
||||||
name='end_datetime',
|
name='end_datetime',
|
||||||
field=models.DateTimeField(help_text='Date and time until when this message is to be displayed.', null=True, verbose_name='End date time', blank=True),
|
field=models.DateTimeField(
|
||||||
|
help_text='Date and time until when this message is to be '
|
||||||
|
'displayed.', null=True, verbose_name='End date time',
|
||||||
|
blank=True
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='message',
|
model_name='message',
|
||||||
name='label',
|
name='label',
|
||||||
field=models.CharField(help_text='Short description of this message.', max_length=32, verbose_name='Label'),
|
field=models.CharField(
|
||||||
|
help_text='Short description of this message.', max_length=32,
|
||||||
|
verbose_name='Label'
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='message',
|
model_name='message',
|
||||||
name='message',
|
name='message',
|
||||||
field=models.TextField(help_text='The actual message to be displayed.', verbose_name='Message'),
|
field=models.TextField(
|
||||||
|
help_text='The actual message to be displayed.',
|
||||||
|
verbose_name='Message'
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='message',
|
model_name='message',
|
||||||
name='start_datetime',
|
name='start_datetime',
|
||||||
field=models.DateTimeField(help_text='Date and time after which this message will be displayed.', null=True, verbose_name='Start date time', blank=True),
|
field=models.DateTimeField(
|
||||||
|
help_text='Date and time after which this message will be '
|
||||||
|
'displayed.', null=True, verbose_name='Start date time',
|
||||||
|
blank=True
|
||||||
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -10,7 +10,9 @@ urlpatterns = patterns(
|
|||||||
'',
|
'',
|
||||||
url(r'^list/$', MessageListView.as_view(), name='message_list'),
|
url(r'^list/$', MessageListView.as_view(), name='message_list'),
|
||||||
url(r'^create/$', MessageCreateView.as_view(), name='message_create'),
|
url(r'^create/$', MessageCreateView.as_view(), name='message_create'),
|
||||||
url(r'^(?P<pk>\d+)/edit/$', MessageEditView.as_view(), name='message_edit'),
|
url(
|
||||||
|
r'^(?P<pk>\d+)/edit/$', MessageEditView.as_view(), name='message_edit'
|
||||||
|
),
|
||||||
url(
|
url(
|
||||||
r'^(?P<pk>\d+)/delete/$', MessageDeleteView.as_view(),
|
r'^(?P<pk>\d+)/delete/$', MessageDeleteView.as_view(),
|
||||||
name='message_delete'
|
name='message_delete'
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ from __future__ import unicode_literals
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from kombu import Exchange, Queue
|
from kombu import Exchange, Queue
|
||||||
import sh
|
|
||||||
|
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
from django.db.models.signals import post_save
|
from django.db.models.signals import post_save
|
||||||
@@ -29,9 +28,6 @@ from .links import (
|
|||||||
link_document_type_submit, link_entry_list
|
link_document_type_submit, link_entry_list
|
||||||
)
|
)
|
||||||
from .permissions import permission_ocr_document, permission_ocr_content_view
|
from .permissions import permission_ocr_document, permission_ocr_content_view
|
||||||
from .settings import (
|
|
||||||
setting_pdftotext_path, setting_tesseract_path
|
|
||||||
)
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import subprocess
|
|||||||
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from common.settings import setting_temporary_directory
|
|
||||||
from common.utils import copyfile, fs_cleanup, mkstemp
|
from common.utils import copyfile, fs_cleanup, mkstemp
|
||||||
|
|
||||||
from .exceptions import ParserError, NoMIMETypeMatch
|
from .exceptions import ParserError, NoMIMETypeMatch
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import psutil
|
|
||||||
|
|
||||||
from django.core.files.base import File
|
from django.core.files.base import File
|
||||||
from django.test import override_settings
|
from django.test import override_settings
|
||||||
|
|
||||||
from common.settings import setting_temporary_directory
|
|
||||||
from common.tests import BaseTestCase
|
from common.tests import BaseTestCase
|
||||||
from documents.models import DocumentType
|
from documents.models import DocumentType
|
||||||
from documents.tests import (
|
from documents.tests import (
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ class StatisticsViewTestCase(GenericViewTestCase):
|
|||||||
|
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
|
||||||
def test_statistic_namespace_list_view_no_permissions(self):
|
def test_statistic_namespace_list_view_no_permissions(self):
|
||||||
self.login(username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD)
|
self.login(username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD)
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import os
|
|||||||
import zipfile
|
import zipfile
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import zlib
|
import zlib # NOQA
|
||||||
COMPRESSION = zipfile.ZIP_DEFLATED
|
COMPRESSION = zipfile.ZIP_DEFLATED
|
||||||
except:
|
except:
|
||||||
COMPRESSION = zipfile.ZIP_STORED
|
COMPRESSION = zipfile.ZIP_STORED
|
||||||
|
|||||||
@@ -55,7 +55,6 @@ INSTALLED_APPS = (
|
|||||||
'compressor',
|
'compressor',
|
||||||
'corsheaders',
|
'corsheaders',
|
||||||
'djcelery',
|
'djcelery',
|
||||||
'filetransfers',
|
|
||||||
'formtools',
|
'formtools',
|
||||||
'mptt',
|
'mptt',
|
||||||
'pure_pagination',
|
'pure_pagination',
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ django-colorful==1.2
|
|||||||
django-compressor==2.1
|
django-compressor==2.1
|
||||||
django-cors-headers==1.2.2
|
django-cors-headers==1.2.2
|
||||||
django-downloadview==1.9
|
django-downloadview==1.9
|
||||||
django-filetransfers==0.1.0
|
|
||||||
django-formtools==1.0
|
django-formtools==1.0
|
||||||
django-pure-pagination==0.3.0
|
django-pure-pagination==0.3.0
|
||||||
django-model-utils==2.6
|
django-model-utils==2.6
|
||||||
|
|||||||
Reference in New Issue
Block a user