Compare commits

..

1 Commits

Author SHA1 Message Date
Roberto Rosario
d29fb86c55 Initial commit to support filename generators
Signed-off-by: Roberto Rosario <roberto.rosario@mayan-edms.com>
2019-09-25 00:08:32 -04:00
36 changed files with 718 additions and 782 deletions

View File

@@ -1,4 +1,4 @@
3.2.8 (2019-10-01) 3.2.8 (2019-XX-XX)
================== ==================
- Fix error when accessing some API entry points without - Fix error when accessing some API entry points without
being authenticated. being authenticated.
@@ -17,7 +17,6 @@
of selection of documents. of selection of documents.
- Add parsed content deleted event. - Add parsed content deleted event.
- Allow scaling of UI on mobile devices. - Allow scaling of UI on mobile devices.
- Add Chinese fonts to the Docker image
3.2.7 (2019-08-28) 3.2.7 (2019-08-28)
================== ==================

View File

@@ -23,8 +23,6 @@ RUN set -x \
apt-get update \ apt-get update \
&& apt-get install -y --no-install-recommends \ && apt-get install -y --no-install-recommends \
exiftool \ exiftool \
fonts-arphic-uming \
fonts-arphic-ukai \
ghostscript \ ghostscript \
gpgv \ gpgv \
gnupg1 \ gnupg1 \
@@ -62,6 +60,7 @@ echo "save \"\"" >> /etc/redis/redis.conf \
# Only provision 1 database # Only provision 1 database
&& echo "databases 1" >> /etc/redis/redis.conf && echo "databases 1" >> /etc/redis/redis.conf
#### ####
# BUILDER_IMAGE - This image buildS the Python package and is discarded afterwards # BUILDER_IMAGE - This image buildS the Python package and is discarded afterwards
#### ####

View File

@@ -1 +1 @@
3.2.8 3.2.7

View File

@@ -533,7 +533,7 @@ Release using GitLab CI
:: ::
git checkout releases/all git checkout releases/all
git merge <corresponding branch> git merge versions/next
#. Push code to trigger builds: #. Push code to trigger builds:
:: ::

View File

@@ -233,12 +233,6 @@ and will exhaust the available Postgres connections available if a number
other than 0 is used. Reference: https://serverfault.com/questions/635100/django-conn-max-age-persists-connections-but-doesnt-reuse-them-with-postgresq other than 0 is used. Reference: https://serverfault.com/questions/635100/django-conn-max-age-persists-connections-but-doesnt-reuse-them-with-postgresq
and https://github.com/benoitc/gunicorn/issues/996 and https://github.com/benoitc/gunicorn/issues/996
``MAYAN_GUNICORN_TIMEOUT``
Optional. Changes the amount of time the frontend worker will wait for a
request to finish before raising a timeout error. The default is 120
seconds.
``MAYAN_GUNICORN_WORKERS`` ``MAYAN_GUNICORN_WORKERS``
Optional. This environment variable controls the number of frontend workers Optional. This environment variable controls the number of frontend workers

View File

@@ -1,21 +1,12 @@
Version 3.2.8 Version 3.2.8
============= =============
Released: October 1, 2019 Released: XX, 2019
Changes Changes
------- -------
API
^^^
Fix an error when accessing some API entry points without
being authenticated. Accessing API endpoints without being authenticated
will now always return empty results.
Cabinets Cabinets
^^^^^^^^ ^^^^^^^^
@@ -23,43 +14,25 @@ Tweaked the jstree component's appearance to cope with long labels.
Added a scrollbar, reduced the font size, switched to a sans serif font, Added a scrollbar, reduced the font size, switched to a sans serif font,
and reduced padding. Thanks for forum user @briboe for the report. and reduced padding. Thanks for forum user @briboe for the report.
Workflow actions to add and remove documents from cabinets was added.
Other changes
^^^^^^^^^^^^^
Dependencies - Fix error when accessing some API entry points without
^^^^^^^^^^^^ being authenticated.
- Add cabinet add and remove workflow actions.
The Django version used was updated to version 1.11.24. The jQuery version - Update Django to version 1.11.24.
used was updated to version 3.4.1. Both as fully backwards compatible with - Update jQuery to version 3.4.1
their previous versions. - Add support for deleting the OCR content of a document
or selection of documents.
- Add OCR content deleted event.
OCR - Add missing recursive option to Docker entrypoint
^^^ chown. GitLab issue #668. Thanks to John Wice (@brilthor)
for the report.
Support was added to delete the content of document's OCR or parsed content. - Add support for deleting the parsed content of a document
Events for both situations was added allowing content deletion to be used of selection of documents.
as workflow transition triggers. - Add parsed content deleted event.
- Allow scaling of UI on mobile devices.
Docker
^^^^^^
A missing recursive option was added to the Docker entrypoint
command "chown" to change the ownership of files when specifying a custom
UID or GID. Closes GitLab issue #668. Thanks to John Wice (@brilthor)
for the report.
Two fonts were added to the Docker image to support rendering Chinese office
documents. Closes GitLab issue #666. Thanks to javawcy (@javawcy) and forum
user @leoliu for the report and help closing this issue.
Usability
^^^^^^^^^
Descriptions for screenreaders was added via image alt tag. The user interface
will also now allow scaling.
Removals Removals
@@ -153,9 +126,7 @@ Backward incompatible changes
Bugs fixed or issues closed Bugs fixed or issues closed
--------------------------- ---------------------------
- :gitlab-issue:`666` Chinese document such as .doc can't display well.
- :gitlab-issue:`668` Permission denied errors with custom uid persist (650 needs re-open) - :gitlab-issue:`668` Permission denied errors with custom uid persist (650 needs re-open)
- :forum-topic:`1120` Cabinet Presentation - :forum-topic:`1120` Cabinet Presentation
- :forum-topic:`2202` Cannot display Chinese character and cannot identify Excel files
.. _PyPI: https://pypi.python.org/pypi/mayan-edms/ .. _PyPI: https://pypi.python.org/pypi/mayan-edms/

View File

@@ -1,9 +1,9 @@
from __future__ import unicode_literals from __future__ import unicode_literals
__title__ = 'Mayan EDMS' __title__ = 'Mayan EDMS'
__version__ = '3.2.8' __version__ = '3.2.7'
__build__ = 0x030208 __build__ = 0x030207
__build_string__ = 'v3.2.8_Tue Oct 1 13:31:40 2019 -0400' __build_string__ = 'v3.2.7_Wed Aug 28 17:31:08 2019 -0400'
__django_version__ = '1.11' __django_version__ = '1.11'
__author__ = 'Roberto Rosario' __author__ = 'Roberto Rosario'
__author_email__ = 'roberto.rosario@mayan-edms.com' __author_email__ = 'roberto.rosario@mayan-edms.com'

View File

@@ -418,4 +418,5 @@ a i {
font: 11px Verdana, sans-serif; font: 11px Verdana, sans-serif;
padding: 0px; padding: 0px;
padding-bottom: 10px; /* Padding for scrollbar */ padding-bottom: 10px; /* Padding for scrollbar */
border-radius: 5px;
} }

View File

@@ -13,7 +13,7 @@
{% block content %} {% block content %}
<div class="row"> <div class="row">
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-2" style="margin-right: -25px;">{# Remove gutter #} <div class="col-xs-12 col-sm-12 col-md-12 col-lg-2">
<h4>{% trans 'Navigation:' %}</h4> <h4>{% trans 'Navigation:' %}</h4>
<div id="jstree"></div> <div id="jstree"></div>
</div> </div>

View File

@@ -1 +0,0 @@
TEST FILE SPECIAL CHARACTERS FILENAME

View File

@@ -11,7 +11,6 @@ TEST_VIEW_NAME = 'test view name'
TEST_VIEW_URL = 'test-view-url' TEST_VIEW_URL = 'test-view-url'
# Filenames # Filenames
TEST_ARCHIVE_ZIP_SPECIAL_CHARACTERS_FILENAME_MEMBER = 'test_archvive_with_special_characters_filename_member.zip'
TEST_FILENAME1 = 'test_file1.txt' TEST_FILENAME1 = 'test_file1.txt'
TEST_FILENAME2 = 'test_file2.txt' TEST_FILENAME2 = 'test_file2.txt'
TEST_FILENAME3 = 'test_file3.txt' TEST_FILENAME3 = 'test_file3.txt'
@@ -24,10 +23,6 @@ TEST_ZIP_FILE = 'test_file.zip'
TEST_COMPRESSED_FILE_CONTENTS = [TEST_FILENAME1, TEST_FILENAME2] TEST_COMPRESSED_FILE_CONTENTS = [TEST_FILENAME1, TEST_FILENAME2]
# File paths # File paths
TEST_ARCHIVE_ZIP_SPECIAL_CHARACTERS_FILENAME_MEMBER_PATH = os.path.join(
settings.BASE_DIR, 'apps', 'common', 'tests', 'contrib',
TEST_ARCHIVE_ZIP_SPECIAL_CHARACTERS_FILENAME_MEMBER
)
TEST_FILE3_PATH = os.path.join( TEST_FILE3_PATH = os.path.join(
settings.BASE_DIR, 'apps', 'common', 'tests', 'contrib', TEST_FILENAME3 settings.BASE_DIR, 'apps', 'common', 'tests', 'contrib', TEST_FILENAME3
) )

View File

@@ -5,7 +5,6 @@ from mayan.apps.common.tests import BaseTestCase
from ..compressed_files import Archive, TarArchive, ZipArchive from ..compressed_files import Archive, TarArchive, ZipArchive
from .literals import ( from .literals import (
TEST_ARCHIVE_ZIP_SPECIAL_CHARACTERS_FILENAME_MEMBER_PATH,
TEST_COMPRESSED_FILE_CONTENTS, TEST_FILE_CONTENTS_1, TEST_FILE3_PATH, TEST_COMPRESSED_FILE_CONTENTS, TEST_FILE_CONTENTS_1, TEST_FILE3_PATH,
TEST_FILENAME1, TEST_FILENAME3, TEST_TAR_BZ2_FILE_PATH, TEST_FILENAME1, TEST_FILENAME3, TEST_TAR_BZ2_FILE_PATH,
TEST_TAR_FILE_PATH, TEST_TAR_GZ_FILE_PATH, TEST_ZIP_FILE_PATH TEST_TAR_FILE_PATH, TEST_TAR_GZ_FILE_PATH, TEST_ZIP_FILE_PATH
@@ -59,11 +58,6 @@ class ZipArchiveClassTestCase(TarArchiveClassTestCase):
archive_path = TEST_ZIP_FILE_PATH archive_path = TEST_ZIP_FILE_PATH
cls = ZipArchive cls = ZipArchive
def test_open_member_with_special_characters_filename(self):
with open(TEST_ARCHIVE_ZIP_SPECIAL_CHARACTERS_FILENAME_MEMBER_PATH, mode='rb') as file_object:
archive = Archive.open(file_object=file_object)
list(archive.get_members())
class TarGzArchiveClassTestCase(TarArchiveClassTestCase): class TarGzArchiveClassTestCase(TarArchiveClassTestCase):
archive_path = TEST_TAR_GZ_FILE_PATH archive_path = TEST_TAR_GZ_FILE_PATH

View File

@@ -13,28 +13,19 @@ from .literals import TEST_KEY_DATA, TEST_KEY_FINGERPRINT
from .mixins import KeyTestMixin from .mixins import KeyTestMixin
class KeyAPIViewTestMixin(object): class KeyAPITestCase(KeyTestMixin, BaseAPITestCase):
def _request_test_key_create_view(self):
# Key creation by upload
def _request_key_create_view(self):
return self.post( return self.post(
viewname='rest_api:key-list', data={ viewname='rest_api:key-list', data={
'key_data': TEST_KEY_DATA 'key_data': TEST_KEY_DATA
} }
) )
def _request_test_key_delete_view(self):
return self.delete(
viewname='rest_api:key-detail', kwargs={'pk': self.test_key.pk}
)
def _request_test_key_detail_view(self):
return self.get(
viewname='rest_api:key-detail', kwargs={'pk': self.test_key.pk}
)
class KeyAPITestCase(KeyTestMixin, KeyAPIViewTestMixin, BaseAPITestCase):
def test_key_create_view_no_permission(self): def test_key_create_view_no_permission(self):
response = self._request_test_key_create_view() response = self._request_key_create_view()
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
self.assertEqual(Key.objects.all().count(), 0) self.assertEqual(Key.objects.all().count(), 0)
@@ -42,7 +33,7 @@ class KeyAPITestCase(KeyTestMixin, KeyAPIViewTestMixin, BaseAPITestCase):
def test_key_create_view_with_permission(self): def test_key_create_view_with_permission(self):
self.grant_permission(permission=permission_key_upload) self.grant_permission(permission=permission_key_upload)
response = self._request_test_key_create_view() response = self._request_key_create_view()
self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(response.data['fingerprint'], TEST_KEY_FINGERPRINT) self.assertEqual(response.data['fingerprint'], TEST_KEY_FINGERPRINT)
@@ -50,10 +41,17 @@ class KeyAPITestCase(KeyTestMixin, KeyAPIViewTestMixin, BaseAPITestCase):
self.assertEqual(Key.objects.count(), 1) self.assertEqual(Key.objects.count(), 1)
self.assertEqual(key.fingerprint, TEST_KEY_FINGERPRINT) self.assertEqual(key.fingerprint, TEST_KEY_FINGERPRINT)
# Key deletion
def _request_key_delete_view(self):
return self.delete(
viewname='rest_api:key-detail', kwargs={'pk': self.test_key.pk}
)
def test_key_delete_view_no_access(self): def test_key_delete_view_no_access(self):
self._create_test_key() self._create_test_key()
response = self._request_test_key_delete_view() response = self._request_key_delete_view()
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
self.assertEqual(Key.objects.count(), 1) self.assertEqual(Key.objects.count(), 1)
@@ -64,15 +62,22 @@ class KeyAPITestCase(KeyTestMixin, KeyAPIViewTestMixin, BaseAPITestCase):
obj=self.test_key, permission=permission_key_delete obj=self.test_key, permission=permission_key_delete
) )
response = self._request_test_key_delete_view() response = self._request_key_delete_view()
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
self.assertEqual(Key.objects.count(), 0) self.assertEqual(Key.objects.count(), 0)
# Key detail
def _request_key_detail_view(self):
return self.get(
viewname='rest_api:key-detail', kwargs={'pk': self.test_key.pk}
)
def test_key_detail_view_no_access(self): def test_key_detail_view_no_access(self):
self._create_test_key() self._create_test_key()
response = self._request_test_key_detail_view() response = self._request_key_detail_view()
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
def test_key_detail_view_with_access(self): def test_key_detail_view_with_access(self):
@@ -81,7 +86,7 @@ class KeyAPITestCase(KeyTestMixin, KeyAPIViewTestMixin, BaseAPITestCase):
obj=self.test_key, permission=permission_key_view obj=self.test_key, permission=permission_key_view
) )
response = self._request_test_key_detail_view() response = self._request_key_detail_view()
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual( self.assertEqual(
response.data['fingerprint'], self.test_key.fingerprint response.data['fingerprint'], self.test_key.fingerprint

View File

@@ -11,23 +11,13 @@ from .literals import TEST_KEY_DATA, TEST_KEY_FINGERPRINT
from .mixins import KeyTestMixin from .mixins import KeyTestMixin
class KeyViewTestMixin(object): class KeyViewTestCase(KeyTestMixin, GenericViewTestCase):
def _request_test_key_download_view(self):
return self.get(
viewname='django_gpg:key_download', kwargs={'pk': self.test_key.pk}
)
def _request_test_key_upload_view(self):
return self.post(
viewname='django_gpg:key_upload', data={'key_data': TEST_KEY_DATA}
)
class KeyViewTestCase(KeyTestMixin, KeyViewTestMixin, GenericViewTestCase):
def test_key_download_view_no_permission(self): def test_key_download_view_no_permission(self):
self._create_test_key() self._create_test_key()
response = self._request_test_key_download_view() response = self.get(
viewname='django_gpg:key_download', kwargs={'pk': self.test_key.pk}
)
self.assertEqual(response.status_code, 403) self.assertEqual(response.status_code, 403)
def test_key_download_view_with_permission(self): def test_key_download_view_with_permission(self):
@@ -35,18 +25,20 @@ class KeyViewTestCase(KeyTestMixin, KeyViewTestMixin, GenericViewTestCase):
self._create_test_key() self._create_test_key()
self.grant_access( self.grant_access(obj=self.test_key, permission=permission_key_download)
obj=self.test_key, permission=permission_key_download
)
response = self._request_test_key_download_view() response = self.get(
viewname='django_gpg:key_download', kwargs={'pk': self.test_key.pk}
)
assert_download_response( assert_download_response(
self, response=response, content=self.test_key.key_data, self, response=response, content=self.test_key.key_data,
basename=self.test_key.key_id, basename=self.test_key.key_id,
) )
def test_key_upload_view_no_permission(self): def test_key_upload_view_no_permission(self):
response = self._request_test_key_upload_view() response = self.post(
viewname='django_gpg:key_upload', data={'key_data': TEST_KEY_DATA}
)
self.assertEqual(response.status_code, 403) self.assertEqual(response.status_code, 403)
self.assertEqual(Key.objects.count(), 0) self.assertEqual(Key.objects.count(), 0)
@@ -54,10 +46,12 @@ class KeyViewTestCase(KeyTestMixin, KeyViewTestMixin, GenericViewTestCase):
def test_key_upload_view_with_permission(self): def test_key_upload_view_with_permission(self):
self.grant_permission(permission=permission_key_upload) self.grant_permission(permission=permission_key_upload)
response = self._request_test_key_upload_view() response = self.post(
self.assertEqual(response.status_code, 302) viewname='django_gpg:key_upload', data={'key_data': TEST_KEY_DATA},
follow=True
)
self.assertContains(response=response, text='created', status_code=200)
self.assertEqual(Key.objects.count(), 1) self.assertEqual(Key.objects.count(), 1)
self.assertEqual( self.assertEqual(Key.objects.first().fingerprint, TEST_KEY_FINGERPRINT)
Key.objects.first().fingerprint, TEST_KEY_FINGERPRINT
)

View File

@@ -15,7 +15,9 @@ from .literals import TEST_COMMENT_TEXT, TEST_COMMENT_TEXT_EDITED
from .mixins import DocumentCommentTestMixin from .mixins import DocumentCommentTestMixin
class CommentAPIViewTestMixin(object): class CommentAPITestCase(
DocumentCommentTestMixin, DocumentTestMixin, BaseAPITestCase
):
def _request_test_comment_create_api_view(self): def _request_test_comment_create_api_view(self):
return self.post( return self.post(
viewname='rest_api:comment-list', kwargs={ viewname='rest_api:comment-list', kwargs={
@@ -25,42 +27,6 @@ class CommentAPIViewTestMixin(object):
} }
) )
def _request_test_comment_delete_api_view(self):
return self.delete(
viewname='rest_api:comment-detail', kwargs={
'document_pk': self.test_document.pk,
'comment_pk': self.test_document_comment.pk,
}
)
def _request_test_comment_detail_api_view(self):
return self.get(
viewname='rest_api:comment-detail', kwargs={
'document_pk': self.test_document.pk,
'comment_pk': self.test_document_comment.pk
}
)
def _request_test_comment_edit_patch_api_view(self):
return self.patch(
viewname='rest_api:comment-detail', kwargs={
'document_pk': self.test_document.pk,
'comment_pk': self.test_document_comment.pk,
}, data={'comment': TEST_COMMENT_TEXT_EDITED}
)
def _request_test_comment_list_api_view(self):
return self.get(
viewname='rest_api:comment-list', kwargs={
'document_pk': self.test_document.pk
}
)
class CommentAPIViewTestCase(
CommentAPIViewTestMixin, DocumentCommentTestMixin, DocumentTestMixin,
BaseAPITestCase
):
def test_comment_create_view_no_access(self): def test_comment_create_view_no_access(self):
response = self._request_test_comment_create_api_view() response = self._request_test_comment_create_api_view()
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
@@ -79,6 +45,14 @@ class CommentAPIViewTestCase(
self.assertEqual(Comment.objects.count(), 1) self.assertEqual(Comment.objects.count(), 1)
self.assertEqual(response.data['id'], comment.pk) self.assertEqual(response.data['id'], comment.pk)
def _request_test_comment_delete_api_view(self):
return self.delete(
viewname='rest_api:comment-detail', kwargs={
'document_pk': self.test_document.pk,
'comment_pk': self.test_document_comment.pk,
}
)
def test_comment_delete_view_no_access(self): def test_comment_delete_view_no_access(self):
self._create_test_comment() self._create_test_comment()
@@ -98,11 +72,19 @@ class CommentAPIViewTestCase(
self.assertFalse(self.test_document_comment in Comment.objects.all()) self.assertFalse(self.test_document_comment in Comment.objects.all())
def _request_comment_edit_patch_api_view(self):
return self.patch(
viewname='rest_api:comment-detail', kwargs={
'document_pk': self.test_document.pk,
'comment_pk': self.test_document_comment.pk,
}, data={'comment': TEST_COMMENT_TEXT_EDITED}
)
def test_comment_edit_view_no_access(self): def test_comment_edit_view_no_access(self):
self._create_test_comment() self._create_test_comment()
comment_text = self.test_document_comment.comment comment_text = self.test_document_comment.comment
response = self._request_test_comment_edit_patch_api_view() response = self._request_comment_edit_patch_api_view()
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
self.test_document_comment.refresh_from_db() self.test_document_comment.refresh_from_db()
@@ -115,16 +97,24 @@ class CommentAPIViewTestCase(
) )
comment_text = self.test_document_comment.comment comment_text = self.test_document_comment.comment
response = self._request_test_comment_edit_patch_api_view() response = self._request_comment_edit_patch_api_view()
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)
self.test_document_comment.refresh_from_db() self.test_document_comment.refresh_from_db()
self.assertNotEqual(self.test_document_comment.comment, comment_text) self.assertNotEqual(self.test_document_comment.comment, comment_text)
def _request_test_comment_api_view(self):
return self.get(
viewname='rest_api:comment-detail', kwargs={
'document_pk': self.test_document.pk,
'comment_pk': self.test_document_comment.pk
}
)
def test_comment_detail_view_no_access(self): def test_comment_detail_view_no_access(self):
self._create_test_comment() self._create_test_comment()
response = self._request_test_comment_detail_api_view() response = self._request_test_comment_api_view()
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
def test_comment_detail_view_with_access(self): def test_comment_detail_view_with_access(self):
@@ -133,11 +123,18 @@ class CommentAPIViewTestCase(
obj=self.test_document, permission=permission_document_comment_view obj=self.test_document, permission=permission_document_comment_view
) )
response = self._request_test_comment_detail_api_view() response = self._request_test_comment_api_view()
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['comment'], self.test_document_comment.comment) self.assertEqual(response.data['comment'], self.test_document_comment.comment)
def _request_test_comment_list_api_view(self):
return self.get(
viewname='rest_api:comment-list', kwargs={
'document_pk': self.test_document.pk
}
)
def test_comment_list_view_no_access(self): def test_comment_list_view_no_access(self):
self._create_test_comment() self._create_test_comment()

View File

@@ -13,8 +13,7 @@ class IndexTestMixin(object):
self.test_index = Index.objects.create(label=TEST_INDEX_LABEL) self.test_index = Index.objects.create(label=TEST_INDEX_LABEL)
# Add our document type to the new index # Add our document type to the new index
if hasattr(self, 'test_document_type'): self.test_index.document_types.add(self.test_document_type)
self.test_index.document_types.add(self.test_document_type)
# Rebuild indexes # Rebuild indexes
if rebuild: if rebuild:

View File

@@ -15,8 +15,10 @@ from .literals import TEST_INDEX_LABEL, TEST_INDEX_SLUG
from .mixins import IndexTestMixin from .mixins import IndexTestMixin
class DocumentIndexingAPIViewTestMixin(object): class DocumentIndexingAPITestCase(IndexTestMixin, DocumentTestMixin, BaseAPITestCase):
def _request_test_index_create_api_view(self): auto_upload_document = False
def _request_index_create_api_view(self):
return self.post( return self.post(
viewname='rest_api:index-list', data={ viewname='rest_api:index-list', data={
'label': TEST_INDEX_LABEL, 'slug': TEST_INDEX_SLUG, 'label': TEST_INDEX_LABEL, 'slug': TEST_INDEX_SLUG,
@@ -24,29 +26,8 @@ class DocumentIndexingAPIViewTestMixin(object):
} }
) )
def _request_test_index_delete_api_view(self):
return self.delete(
viewname='rest_api:index-detail', kwargs={
'pk': self.test_index.pk
}
)
def _request_test_index_detail_api_view(self):
return self.get(
viewname='rest_api:index-detail', kwargs={
'pk': self.test_index.pk
}
)
class DocumentIndexingAPITestCase(
IndexTestMixin, DocumentIndexingAPIViewTestMixin, DocumentTestMixin,
BaseAPITestCase
):
auto_upload_document = False
def test_index_create_api_view_no_permission(self): def test_index_create_api_view_no_permission(self):
response = self._request_test_index_create_api_view() response = self._request_index_create_api_view()
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
self.assertEqual(Index.objects.count(), 0) self.assertEqual(Index.objects.count(), 0)
@@ -54,7 +35,7 @@ class DocumentIndexingAPITestCase(
def test_index_create_api_view_with_permission(self): def test_index_create_api_view_with_permission(self):
self.grant_permission(permission=permission_document_indexing_create) self.grant_permission(permission=permission_document_indexing_create)
response = self._request_test_index_create_api_view() response = self._request_index_create_api_view()
self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(response.status_code, status.HTTP_201_CREATED)
index = Index.objects.first() index = Index.objects.first()
@@ -65,10 +46,17 @@ class DocumentIndexingAPITestCase(
self.assertEqual(Index.objects.count(), 1) self.assertEqual(Index.objects.count(), 1)
self.assertEqual(index.label, TEST_INDEX_LABEL) self.assertEqual(index.label, TEST_INDEX_LABEL)
def _request_index_delete_api_view(self):
return self.delete(
viewname='rest_api:index-detail', kwargs={
'pk': self.test_index.pk
}
)
def test_index_delete_api_view_no_permission(self): def test_index_delete_api_view_no_permission(self):
self._create_test_index() self._create_test_index()
response = self._request_test_index_delete_api_view() response = self._request_index_delete_api_view()
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
self.assertTrue(self.test_index in Index.objects.all()) self.assertTrue(self.test_index in Index.objects.all())
@@ -80,15 +68,22 @@ class DocumentIndexingAPITestCase(
obj=self.test_index, permission=permission_document_indexing_delete obj=self.test_index, permission=permission_document_indexing_delete
) )
response = self._request_test_index_delete_api_view() response = self._request_index_delete_api_view()
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
self.assertTrue(self.test_index not in Index.objects.all()) self.assertTrue(self.test_index not in Index.objects.all())
def _request_index_detail_api_view(self):
return self.get(
viewname='rest_api:index-detail', kwargs={
'pk': self.test_index.pk
}
)
def test_index_detail_api_view_no_access(self): def test_index_detail_api_view_no_access(self):
self._create_test_index() self._create_test_index()
response = self._request_test_index_detail_api_view() response = self._request_index_detail_api_view()
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
self.assertTrue('id' not in response.data) self.assertTrue('id' not in response.data)
@@ -100,7 +95,7 @@ class DocumentIndexingAPITestCase(
obj=self.test_index, permission=permission_document_indexing_view obj=self.test_index, permission=permission_document_indexing_view
) )
response = self._request_test_index_detail_api_view() response = self._request_index_detail_api_view()
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual( self.assertEqual(

View File

@@ -1,6 +1,5 @@
from __future__ import absolute_import, unicode_literals from __future__ import absolute_import, unicode_literals
from mayan.apps.common.tests import GenericViewTestCase
from mayan.apps.documents.tests import GenericDocumentViewTestCase from mayan.apps.documents.tests import GenericDocumentViewTestCase
from ..models import Index, IndexInstanceNode from ..models import Index, IndexInstanceNode
@@ -19,8 +18,10 @@ from .mixins import IndexTestMixin, IndexViewTestMixin
class IndexViewTestCase( class IndexViewTestCase(
IndexTestMixin, IndexViewTestMixin, GenericViewTestCase IndexTestMixin, IndexViewTestMixin, GenericDocumentViewTestCase
): ):
auto_upload_document = False
def test_index_create_view_no_permission(self): def test_index_create_view_no_permission(self):
response = self._request_test_index_create_view() response = self._request_test_index_create_view()
self.assertEqual(response.status_code, 403) self.assertEqual(response.status_code, 403)
@@ -79,7 +80,9 @@ class IndexViewTestCase(
self.assertEqual(self.test_index.label, TEST_INDEX_LABEL_EDITED) self.assertEqual(self.test_index.label, TEST_INDEX_LABEL_EDITED)
class IndexInstaceViewTestMixin(object): class IndexInstaceViewTestCase(
IndexTestMixin, IndexViewTestMixin, GenericDocumentViewTestCase
):
def _create_index_template_node(self): def _create_index_template_node(self):
self.test_index.node_templates.create( self.test_index.node_templates.create(
parent=self.test_index.template_root, parent=self.test_index.template_root,
@@ -87,18 +90,6 @@ class IndexInstaceViewTestMixin(object):
link_documents=True link_documents=True
) )
def _request_test_index_instance_node_view(self, index_instance_node):
return self.get(
viewname='indexing:index_instance_node_view', kwargs={
'pk': index_instance_node.pk
}
)
class IndexInstaceViewTestCase(
IndexTestMixin, IndexViewTestMixin, IndexInstaceViewTestMixin,
GenericDocumentViewTestCase
):
def test_index_rebuild_view_no_permission(self): def test_index_rebuild_view_no_permission(self):
self.upload_document() self.upload_document()
self._create_test_index() self._create_test_index()
@@ -124,10 +115,17 @@ class IndexInstaceViewTestCase(
self.assertNotEqual(IndexInstanceNode.objects.count(), 0) self.assertNotEqual(IndexInstanceNode.objects.count(), 0)
def _request_index_instance_node_view(self, index_instance_node):
return self.get(
viewname='indexing:index_instance_node_view', kwargs={
'pk': index_instance_node.pk
}
)
def test_index_instance_node_view_no_permission(self): def test_index_instance_node_view_no_permission(self):
self._create_test_index() self._create_test_index()
response = self._request_test_index_instance_node_view( response = self._request_index_instance_node_view(
index_instance_node=self.test_index.instance_root index_instance_node=self.test_index.instance_root
) )
self.assertEqual(response.status_code, 403) self.assertEqual(response.status_code, 403)
@@ -140,13 +138,15 @@ class IndexInstaceViewTestCase(
permission=permission_document_indexing_instance_view permission=permission_document_indexing_instance_view
) )
response = self._request_test_index_instance_node_view( response = self._request_index_instance_node_view(
index_instance_node=self.test_index.instance_root index_instance_node=self.test_index.instance_root
) )
self.assertContains(response, text=TEST_INDEX_LABEL, status_code=200) self.assertContains(response, text=TEST_INDEX_LABEL, status_code=200)
class IndexToolsViewTestMixin(object): class IndexToolsViewTestCase(
IndexTestMixin, IndexViewTestMixin, GenericDocumentViewTestCase
):
def _request_indexes_rebuild_get_view(self): def _request_indexes_rebuild_get_view(self):
return self.get( return self.get(
viewname='indexing:rebuild_index_instances' viewname='indexing:rebuild_index_instances'
@@ -159,11 +159,6 @@ class IndexToolsViewTestMixin(object):
} }
) )
class IndexToolsViewTestCase(
IndexTestMixin, IndexViewTestMixin, IndexToolsViewTestMixin,
GenericDocumentViewTestCase
):
def test_indexes_rebuild_no_permission(self): def test_indexes_rebuild_no_permission(self):
self._create_test_index(rebuild=False) self._create_test_index(rebuild=False)

View File

@@ -23,32 +23,84 @@ TEST_UNSIGNED_DOCUMENT_COUNT = 4
TEST_SIGNED_DOCUMENT_COUNT = 2 TEST_SIGNED_DOCUMENT_COUNT = 2
class SignaturesViewTestMixin(object): class SignaturesViewTestCase(SignaturesTestMixin, GenericDocumentViewTestCase):
def _request_test_document_version_signature_delete_view(self): auto_upload_document = False
return self.post(
viewname='signatures:document_version_signature_delete',
kwargs={'pk': self.test_signature.pk}
)
def _request_test_document_version_signature_details_view(self): def _request_document_version_signature_list_view(self, document):
return self.get(
viewname='signatures:document_version_signature_details',
kwargs={'pk': self.test_signature.pk}
)
def _request_test_document_version_signature_download_view(self):
return self.get(
viewname='signatures:document_version_signature_download',
kwargs={'pk': self.test_signature.pk}
)
def _request_test_document_version_signature_list_view(self, document):
return self.get( return self.get(
viewname='signatures:document_version_signature_list', viewname='signatures:document_version_signature_list',
kwargs={'pk': self.test_document.latest_version.pk} kwargs={'pk': self.test_document.latest_version.pk}
) )
def _request_test_document_version_signature_upload_view(self): def test_signature_list_view_no_permission(self):
self._create_test_key()
self.test_document_path = TEST_DOCUMENT_PATH
self.upload_document()
self._create_test_detached_signature()
response = self._request_document_version_signature_list_view(
document=self.test_document
)
self.assertEqual(response.status_code, 403)
def test_signature_list_view_with_access(self):
self._create_test_key()
self.test_document_path = TEST_DOCUMENT_PATH
self.upload_document()
self._create_test_detached_signature()
self.grant_access(
obj=self.test_document,
permission=permission_document_version_signature_view
)
response = self._request_document_version_signature_list_view(
document=self.test_document
)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.context['object_list'].count(), 1)
def _request_document_version_signature_details_view(self):
return self.get(
viewname='signatures:document_version_signature_details',
kwargs={'pk': self.test_signature.pk}
)
def test_signature_detail_view_no_permission(self):
self._create_test_key()
self.test_document_path = TEST_DOCUMENT_PATH
self.upload_document()
self._create_test_detached_signature()
response = self._request_document_version_signature_details_view()
self.assertEqual(response.status_code, 404)
def test_signature_detail_view_with_access(self):
self._create_test_key()
self.test_document_path = TEST_DOCUMENT_PATH
self.upload_document()
self._create_test_detached_signature()
self.grant_access(
obj=self.test_document,
permission=permission_document_version_signature_view
)
response = self._request_document_version_signature_details_view()
self.assertContains(
response=response, text=self.test_signature.signature_id,
status_code=200
)
def _request_document_version_signature_upload_view(self):
with open(TEST_SIGNATURE_FILE_PATH, mode='rb') as file_object: with open(TEST_SIGNATURE_FILE_PATH, mode='rb') as file_object:
return self.post( return self.post(
viewname='signatures:document_version_signature_upload', viewname='signatures:document_version_signature_upload',
@@ -56,16 +108,69 @@ class SignaturesViewTestMixin(object):
data={'signature_file': file_object} data={'signature_file': file_object}
) )
def _request_all_test_document_version_signature_verify_view(self): def test_signature_upload_view_no_permission(self):
return self.post( self.test_document_path = TEST_DOCUMENT_PATH
viewname='signatures:all_document_version_signature_verify' self.upload_document()
response = self._request_document_version_signature_upload_view()
self.assertEqual(response.status_code, 403)
self.assertEqual(DetachedSignature.objects.count(), 0)
def test_signature_upload_view_with_access(self):
self.test_document_path = TEST_DOCUMENT_PATH
self.upload_document()
self.grant_access(
obj=self.test_document,
permission=permission_document_version_signature_upload
) )
response = self._request_document_version_signature_upload_view()
self.assertEqual(response.status_code, 302)
class SignaturesViewTestCase( self.assertEqual(DetachedSignature.objects.count(), 1)
SignaturesTestMixin, SignaturesViewTestMixin, GenericDocumentViewTestCase
): def _request_document_version_signature_download_view(self):
auto_upload_document = False return self.get(
viewname='signatures:document_version_signature_download',
kwargs={'pk': self.test_signature.pk}
)
def test_signature_download_view_no_permission(self):
self.test_document_path = TEST_DOCUMENT_PATH
self.upload_document()
self._create_test_detached_signature()
response = self._request_document_version_signature_download_view()
self.assertEqual(response.status_code, 403)
def test_signature_download_view_with_access(self):
self.test_document_path = TEST_DOCUMENT_PATH
self.upload_document()
self._create_test_detached_signature()
self.grant_access(
obj=self.test_document,
permission=permission_document_version_signature_download
)
self.expected_content_type = 'application/octet-stream; charset=utf-8'
response = self._request_document_version_signature_download_view()
with self.test_signature.signature_file as file_object:
assert_download_response(
self, response=response, content=file_object.read(),
)
def _request_document_version_signature_delete_view(self):
return self.post(
viewname='signatures:document_version_signature_delete',
kwargs={'pk': self.test_signature.pk}
)
def test_signature_delete_view_no_permission(self): def test_signature_delete_view_no_permission(self):
self._create_test_key() self._create_test_key()
@@ -80,7 +185,7 @@ class SignaturesViewTestCase(
permission=permission_document_version_signature_view permission=permission_document_version_signature_view
) )
response = self._request_test_document_version_signature_delete_view() response = self._request_document_version_signature_delete_view()
self.assertEqual(response.status_code, 404) self.assertEqual(response.status_code, 404)
self.assertEqual(DetachedSignature.objects.count(), 1) self.assertEqual(DetachedSignature.objects.count(), 1)
@@ -101,124 +206,15 @@ class SignaturesViewTestCase(
permission=permission_document_version_signature_view permission=permission_document_version_signature_view
) )
response = self._request_test_document_version_signature_delete_view() response = self._request_document_version_signature_delete_view()
self.assertEqual(response.status_code, 302) self.assertEqual(response.status_code, 302)
self.assertEqual(DetachedSignature.objects.count(), 0) self.assertEqual(DetachedSignature.objects.count(), 0)
def test_signature_detail_view_no_permission(self): def _request_all_document_version_signature_verify_view(self):
self._create_test_key() return self.post(
viewname='signatures:all_document_version_signature_verify'
self.test_document_path = TEST_DOCUMENT_PATH
self.upload_document()
self._create_test_detached_signature()
response = self._request_test_document_version_signature_details_view()
self.assertEqual(response.status_code, 404)
def test_signature_detail_view_with_access(self):
self._create_test_key()
self.test_document_path = TEST_DOCUMENT_PATH
self.upload_document()
self._create_test_detached_signature()
self.grant_access(
obj=self.test_document,
permission=permission_document_version_signature_view
) )
response = self._request_test_document_version_signature_details_view()
self.assertContains(
response=response, text=self.test_signature.signature_id,
status_code=200
)
def test_signature_download_view_no_permission(self):
self.test_document_path = TEST_DOCUMENT_PATH
self.upload_document()
self._create_test_detached_signature()
response = self._request_test_document_version_signature_download_view()
self.assertEqual(response.status_code, 403)
def test_signature_download_view_with_access(self):
self.test_document_path = TEST_DOCUMENT_PATH
self.upload_document()
self._create_test_detached_signature()
self.grant_access(
obj=self.test_document,
permission=permission_document_version_signature_download
)
self.expected_content_type = 'application/octet-stream; charset=utf-8'
response = self._request_test_document_version_signature_download_view()
with self.test_signature.signature_file as file_object:
assert_download_response(
self, response=response, content=file_object.read(),
)
def test_signature_list_view_no_permission(self):
self._create_test_key()
self.test_document_path = TEST_DOCUMENT_PATH
self.upload_document()
self._create_test_detached_signature()
response = self._request_test_document_version_signature_list_view(
document=self.test_document
)
self.assertEqual(response.status_code, 403)
def test_signature_list_view_with_access(self):
self._create_test_key()
self.test_document_path = TEST_DOCUMENT_PATH
self.upload_document()
self._create_test_detached_signature()
self.grant_access(
obj=self.test_document,
permission=permission_document_version_signature_view
)
response = self._request_test_document_version_signature_list_view(
document=self.test_document
)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.context['object_list'].count(), 1)
def test_signature_upload_view_no_permission(self):
self.test_document_path = TEST_DOCUMENT_PATH
self.upload_document()
response = self._request_test_document_version_signature_upload_view()
self.assertEqual(response.status_code, 403)
self.assertEqual(DetachedSignature.objects.count(), 0)
def test_signature_upload_view_with_access(self):
self.test_document_path = TEST_DOCUMENT_PATH
self.upload_document()
self.grant_access(
obj=self.test_document,
permission=permission_document_version_signature_upload
)
response = self._request_test_document_version_signature_upload_view()
self.assertEqual(response.status_code, 302)
self.assertEqual(DetachedSignature.objects.count(), 1)
def test_missing_signature_verify_view_no_permission(self): def test_missing_signature_verify_view_no_permission(self):
# Silence converter logging # Silence converter logging
self._silence_logger(name='mayan.apps.converter.backends') self._silence_logger(name='mayan.apps.converter.backends')
@@ -244,7 +240,7 @@ class SignaturesViewTestCase(
DocumentVersion._post_save_hooks = old_hooks DocumentVersion._post_save_hooks = old_hooks
response = self._request_all_test_document_version_signature_verify_view() response = self._request_all_document_version_signature_verify_view()
self.assertEqual(response.status_code, 403) self.assertEqual(response.status_code, 403)
self.assertEqual( self.assertEqual(
@@ -281,7 +277,7 @@ class SignaturesViewTestCase(
permission=permission_document_version_signature_verify permission=permission_document_version_signature_verify
) )
response = self._request_all_test_document_version_signature_verify_view() response = self._request_all_document_version_signature_verify_view()
self.assertEqual(response.status_code, 302) self.assertEqual(response.status_code, 302)
self.assertEqual( self.assertEqual(

View File

@@ -3,7 +3,6 @@ from __future__ import unicode_literals
from django import forms from django import forms
from django.urls import reverse from django.urls import reverse
from django.utils.html import format_html_join, mark_safe from django.utils.html import format_html_join, mark_safe
from django.utils.translation import ugettext_lazy as _
def widget_transition_events(transition): def widget_transition_events(transition):

View File

@@ -0,0 +1,39 @@
from __future__ import absolute_import, unicode_literals
import uuid
from django.utils.translation import ugettext_lazy as _
class BaseDocumentFilenameGenerator(object):
_registry = {}
@classmethod
def get(cls, name):
return cls._registry[name]
@classmethod
def get_choices(cls):
return sorted(
[
(name, klass.label) for name, klass in cls._registry.items()
]
)
@classmethod
def register(cls, klass):
cls._registry[klass.name] = klass
def upload_to(self, instance, filename):
raise NotImplementedError
class UUIDDocumentFilenameGenerator(BaseDocumentFilenameGenerator):
name = 'uuid'
label = _('UUID')
def upload_to(self, instance, filename):
return force_text(uuid.uuid4())
BaseDocumentFilenameGenerator.register(klass=UUIDDocumentFilenameGenerator)

View File

@@ -5,11 +5,20 @@ from django.utils.translation import ugettext_lazy as _
from mayan.apps.acls.models import AccessControlList from mayan.apps.acls.models import AccessControlList
from ..classes import BaseDocumentFilenameGenerator
from ..models import DocumentType, DocumentTypeFilename from ..models import DocumentType, DocumentTypeFilename
__all__ = ('DocumentTypeFilteredSelectForm', 'DocumentTypeFilenameForm_create') __all__ = ('DocumentTypeFilteredSelectForm', 'DocumentTypeFilenameForm_create')
class DocumentTypeForm(forms.ModelForm):
#filename_generator = forms.
class Meta:
fields = ('label', 'filename_generator')
model = DocumentType
class DocumentTypeFilteredSelectForm(forms.Form): class DocumentTypeFilteredSelectForm(forms.Form):
""" """
Form to select the document type of a document to be created. This form Form to select the document type of a document to be created. This form

View File

@@ -11,6 +11,7 @@ from django.utils.translation import ugettext_lazy as _
from mayan.apps.acls.models import AccessControlList from mayan.apps.acls.models import AccessControlList
from mayan.apps.common.literals import TIME_DELTA_UNIT_CHOICES from mayan.apps.common.literals import TIME_DELTA_UNIT_CHOICES
from ..classes import BaseDocumentFilenameGenerator
from ..events import event_document_type_created, event_document_type_edited from ..events import event_document_type_created, event_document_type_edited
from ..literals import DEFAULT_DELETE_PERIOD, DEFAULT_DELETE_TIME_UNIT from ..literals import DEFAULT_DELETE_PERIOD, DEFAULT_DELETE_TIME_UNIT
from ..managers import DocumentTypeManager from ..managers import DocumentTypeManager
@@ -52,6 +53,12 @@ class DocumentType(models.Model):
default=DEFAULT_DELETE_TIME_UNIT, max_length=8, null=True, default=DEFAULT_DELETE_TIME_UNIT, max_length=8, null=True,
verbose_name=_('Delete time unit') verbose_name=_('Delete time unit')
) )
filename_generator = models.CharField(
help_text=_(
'The class responsible for producing the actual filename used '
'to store the uploaded documents.'
), max_length=128, verbose_name=_('Filename generator')
)
objects = DocumentTypeManager() objects = DocumentTypeManager()
@@ -94,6 +101,10 @@ class DocumentType(models.Model):
return queryset.count() return queryset.count()
def get_upload_filename(self, instance, filename):
klass = BaseDocumentFilenameGenerator.get(name=self.filename_generator)
return klass.upload_to(instance=instance, filename=filename)
def natural_key(self): def natural_key(self):
return (self.label,) return (self.label,)

View File

@@ -4,7 +4,6 @@ import hashlib
import logging import logging
import os import os
import shutil import shutil
import uuid
from django.apps import apps from django.apps import apps
from django.core.files.base import ContentFile from django.core.files.base import ContentFile
@@ -37,8 +36,10 @@ def hash_function():
return hashlib.sha256() return hashlib.sha256()
def UUID_FUNCTION(*args, **kwargs): def upload_to(instance, filename):
return force_text(uuid.uuid4()) return instance.document.document_type.get_upload_filename(
instance=instance, filename=filename
)
@python_2_unicode_compatible @python_2_unicode_compatible
@@ -86,7 +87,7 @@ class DocumentVersion(models.Model):
# File related fields # File related fields
file = models.FileField( file = models.FileField(
storage=storage_documentversion, upload_to=UUID_FUNCTION, storage=storage_documentversion, upload_to=upload_to,
verbose_name=_('File') verbose_name=_('File')
) )
mimetype = models.CharField( mimetype = models.CharField(

View File

@@ -82,7 +82,9 @@ class DocumentTypeListView(SingleObjectListView):
class DocumentTypeCreateView(SingleObjectCreateView): class DocumentTypeCreateView(SingleObjectCreateView):
fields = ('label',) fields = ('label',)
model = DocumentType model = DocumentType
post_action_redirect = reverse_lazy(viewname='documents:document_type_list') post_action_redirect = reverse_lazy(
viewname='documents:document_type_list'
)
view_permission = permission_document_type_create view_permission = permission_document_type_create
def get_extra_context(self): def get_extra_context(self):

View File

@@ -10,7 +10,7 @@ from mayan.apps.rest_api.tests import BaseAPITestCase
from ..classes import SearchModel from ..classes import SearchModel
class SearchModelAPIViewTestCase(BaseAPITestCase): class SearchModelAPITestCase(BaseAPITestCase):
def test_search_models_view(self): def test_search_models_view(self):
response = self.get( response = self.get(
viewname='rest_api:searchmodel-list' viewname='rest_api:searchmodel-list'
@@ -23,7 +23,7 @@ class SearchModelAPIViewTestCase(BaseAPITestCase):
) )
class SearchAPIViewTestMixin(object): class SearchAPITestCase(DocumentTestMixin, BaseAPITestCase):
def _request_search_view(self): def _request_search_view(self):
query = {'q': self.test_document.label} query = {'q': self.test_document.label}
return self.get( return self.get(
@@ -32,19 +32,6 @@ class SearchAPIViewTestMixin(object):
}, query=query }, query=query
) )
def _request_advanced_search_view(self):
query = {'document_type__label': self.test_document.document_type.label}
return self.get(
viewname='rest_api:advanced-search-view', kwargs={
'search_model': document_search.get_full_name()
}, query=query
)
class SearchAPIViewTestCase(
SearchAPIViewTestMixin, DocumentTestMixin, BaseAPITestCase
):
def test_search_no_permission(self): def test_search_no_permission(self):
response = self._request_search_view() response = self._request_search_view()
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)
@@ -62,6 +49,15 @@ class SearchAPIViewTestCase(
) )
self.assertEqual(response.data['count'], 1) self.assertEqual(response.data['count'], 1)
def _request_advanced_search_view(self):
query = {'document_type__label': self.test_document.document_type.label}
return self.get(
viewname='rest_api:advanced-search-view', kwargs={
'search_model': document_search.get_full_name()
}, query=query
)
def test_advanced_search_api_view_no_permission(self): def test_advanced_search_api_view_no_permission(self):
response = self._request_advanced_search_view() response = self._request_advanced_search_view()
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)

View File

@@ -10,14 +10,6 @@ from .literals import (
) )
class SmartLinkDocumentViewTestMixin(object):
def _request_test_smart_link_document_instances_view(self):
return self.get(
viewname='linking:smart_link_instances_for_document',
kwargs={'pk': self.test_document.pk}
)
class SmartLinkTestMixin(object): class SmartLinkTestMixin(object):
def _create_test_smart_link(self, add_test_document_type=False): def _create_test_smart_link(self, add_test_document_type=False):
self.test_smart_link = SmartLink.objects.create( self.test_smart_link = SmartLink.objects.create(

File diff suppressed because it is too large Load Diff

View File

@@ -14,15 +14,10 @@ from .literals import (
TEST_SMART_LINK_DYNAMIC_LABEL, TEST_SMART_LINK_LABEL_EDITED, TEST_SMART_LINK_DYNAMIC_LABEL, TEST_SMART_LINK_LABEL_EDITED,
TEST_SMART_LINK_LABEL TEST_SMART_LINK_LABEL
) )
from .mixins import ( from .mixins import SmartLinkTestMixin, SmartLinkViewTestMixin
SmartLinkDocumentViewTestMixin, SmartLinkTestMixin,
SmartLinkViewTestMixin
)
class SmartLinkViewTestCase( class SmartLinkViewTestCase(SmartLinkTestMixin, SmartLinkViewTestMixin, GenericViewTestCase):
SmartLinkTestMixin, SmartLinkViewTestMixin, GenericViewTestCase
):
def test_smart_link_create_view_no_permission(self): def test_smart_link_create_view_no_permission(self):
response = self._request_test_smart_link_create_view() response = self._request_test_smart_link_create_view()
self.assertEqual(response.status_code, 403) self.assertEqual(response.status_code, 403)
@@ -79,15 +74,10 @@ class SmartLinkViewTestCase(
self.assertEqual(response.status_code, 302) self.assertEqual(response.status_code, 302)
self.test_smart_link.refresh_from_db() self.test_smart_link.refresh_from_db()
self.assertEqual( self.assertEqual(self.test_smart_link.label, TEST_SMART_LINK_LABEL_EDITED)
self.test_smart_link.label, TEST_SMART_LINK_LABEL_EDITED
)
class SmartLinkDocumentViewTestCase( class SmartLinkDocumentViewTestCase(SmartLinkTestMixin, GenericDocumentViewTestCase):
SmartLinkTestMixin, SmartLinkDocumentViewTestMixin,
GenericDocumentViewTestCase
):
def setUp(self): def setUp(self):
super(SmartLinkDocumentViewTestCase, self).setUp() super(SmartLinkDocumentViewTestCase, self).setUp()
self._create_test_smart_link() self._create_test_smart_link()
@@ -99,6 +89,12 @@ class SmartLinkDocumentViewTestCase(
) )
self.test_smart_link_2.document_types.add(self.test_document_type) self.test_smart_link_2.document_types.add(self.test_document_type)
def _request_test_smart_link_document_instances_view(self):
return self.get(
viewname='linking:smart_link_instances_for_document',
kwargs={'pk': self.test_document.pk}
)
def test_document_smart_link_list_view_no_permission(self): def test_document_smart_link_list_view_no_permission(self):
self.grant_access( self.grant_access(
obj=self.test_document, permission=permission_document_view obj=self.test_document, permission=permission_document_view

View File

@@ -1,34 +0,0 @@
from __future__ import unicode_literals
from ..literals import SOURCE_CHOICE_WEB_FORM
from ..models import WebFormSource
from .literals import TEST_SOURCE_LABEL, TEST_SOURCE_UNCOMPRESS_N
class SourceTestMixin(object):
def _create_test_source(self):
self.test_source = WebFormSource.objects.create(
enabled=True, label=TEST_SOURCE_LABEL,
uncompress=TEST_SOURCE_UNCOMPRESS_N
)
class SourceViewTestMixin(object):
def _request_setup_source_list_view(self):
return self.get(viewname='sources:setup_source_list')
def _request_setup_source_create_view(self):
return self.post(
kwargs={'source_type': SOURCE_CHOICE_WEB_FORM},
viewname='sources:setup_source_create', data={
'enabled': True, 'label': TEST_SOURCE_LABEL,
'uncompress': TEST_SOURCE_UNCOMPRESS_N
}
)
def _request_setup_source_delete_view(self):
return self.post(
viewname='sources:setup_source_delete',
kwargs={'pk': self.test_source.pk}
)

View File

@@ -28,6 +28,7 @@ from mayan.apps.storage.utils import mkdtemp
from ..literals import SOURCE_UNCOMPRESS_CHOICE_Y from ..literals import SOURCE_UNCOMPRESS_CHOICE_Y
from ..models.email_sources import EmailBaseModel, IMAPEmail, POP3Email from ..models.email_sources import EmailBaseModel, IMAPEmail, POP3Email
from ..models.watch_folder_sources import WatchFolderSource from ..models.watch_folder_sources import WatchFolderSource
from ..models.webform_sources import WebFormSource
from .literals import ( from .literals import (
TEST_EMAIL_ATTACHMENT_AND_INLINE, TEST_EMAIL_BASE64_FILENAME, TEST_EMAIL_ATTACHMENT_AND_INLINE, TEST_EMAIL_BASE64_FILENAME,
@@ -36,24 +37,21 @@ from .literals import (
TEST_EMAIL_NO_CONTENT_TYPE_STRING, TEST_EMAIL_ZERO_LENGTH_ATTACHMENT, TEST_EMAIL_NO_CONTENT_TYPE_STRING, TEST_EMAIL_ZERO_LENGTH_ATTACHMENT,
TEST_WATCHFOLDER_SUBFOLDER TEST_WATCHFOLDER_SUBFOLDER
) )
from .mixins import SourceTestMixin
class CompressedUploadsTestCase(SourceTestMixin, GenericDocumentTestCase): class CompressedUploadsTestCase(GenericDocumentTestCase):
auto_upload_document = False auto_upload_document = False
def test_upload_compressed_file(self): def test_upload_compressed_file(self):
self._create_test_source() source = WebFormSource(
self.test_source.uncompress = SOURCE_UNCOMPRESS_CHOICE_Y label='test source', uncompress=SOURCE_UNCOMPRESS_CHOICE_Y
self.test_source.save() )
with open(TEST_COMPRESSED_DOCUMENT_PATH, mode='rb') as file_object: with open(TEST_COMPRESSED_DOCUMENT_PATH, mode='rb') as file_object:
self.test_source.handle_upload( source.handle_upload(
document_type=self.test_document_type, document_type=self.test_document_type,
file_object=file_object, file_object=file_object,
expand=( expand=(source.uncompress == SOURCE_UNCOMPRESS_CHOICE_Y)
self.test_source.uncompress == SOURCE_UNCOMPRESS_CHOICE_Y
)
) )
self.assertEqual(Document.objects.count(), 2) self.assertEqual(Document.objects.count(), 2)

View File

@@ -25,42 +25,32 @@ from ..permissions import (
from .literals import ( from .literals import (
TEST_SOURCE_LABEL, TEST_SOURCE_UNCOMPRESS_N, TEST_STAGING_PREVIEW_WIDTH TEST_SOURCE_LABEL, TEST_SOURCE_UNCOMPRESS_N, TEST_STAGING_PREVIEW_WIDTH
) )
from .mixins import SourceTestMixin, SourceViewTestMixin
class DocumentUploadWizardViewTestMixin(object): class DocumentUploadTestCase(GenericDocumentViewTestCase):
auto_upload_document = False
def setUp(self):
super(DocumentUploadTestCase, self).setUp()
self.source = WebFormSource.objects.create(
enabled=True, label=TEST_SOURCE_LABEL,
uncompress=TEST_SOURCE_UNCOMPRESS_N
)
def _request_upload_wizard_view(self, document_path=TEST_SMALL_DOCUMENT_PATH): def _request_upload_wizard_view(self, document_path=TEST_SMALL_DOCUMENT_PATH):
with open(document_path, mode='rb') as file_object: with open(document_path, mode='rb') as file_object:
return self.post( return self.post(
viewname='sources:upload_interactive', kwargs={ viewname='sources:upload_interactive', kwargs={
'source_id': self.test_source.pk 'source_id': self.source.pk
}, data={ }, data={
'source-file': file_object, 'source-file': file_object,
'document_type_id': self.test_document_type.pk, 'document_type_id': self.test_document_type.pk,
} }
) )
def _request_upload_interactive_view(self):
return self.get(
viewname='sources:upload_interactive', data={
'document_type_id': self.test_document_type.pk,
}
)
class DocumentUploadWizardViewTestCase(
SourceTestMixin, DocumentUploadWizardViewTestMixin,
GenericDocumentViewTestCase
):
auto_upload_document = False
def setUp(self):
super(DocumentUploadWizardViewTestCase, self).setUp()
self._create_test_source()
def test_upload_compressed_file(self): def test_upload_compressed_file(self):
self.test_source.uncompress = SOURCE_UNCOMPRESS_CHOICE_Y self.source.uncompress = SOURCE_UNCOMPRESS_CHOICE_Y
self.test_source.save() self.source.save()
self.grant_access( self.grant_access(
obj=self.test_document_type, permission=permission_document_create obj=self.test_document_type, permission=permission_document_create
@@ -114,7 +104,7 @@ class DocumentUploadWizardViewTestCase(
with open(TEST_SMALL_DOCUMENT_PATH, mode='rb') as file_object: with open(TEST_SMALL_DOCUMENT_PATH, mode='rb') as file_object:
response = self.post( response = self.post(
viewname='sources:upload_interactive', kwargs={ viewname='sources:upload_interactive', kwargs={
'source_id': self.test_source.pk 'source_id': self.source.pk
}, data={ }, data={
'source-file': file_object, 'source-file': file_object,
'document_type_id': self.test_document_type.pk, 'document_type_id': self.test_document_type.pk,
@@ -124,6 +114,13 @@ class DocumentUploadWizardViewTestCase(
self.assertEqual(Document.objects.count(), 1) self.assertEqual(Document.objects.count(), 1)
def _request_upload_interactive_view(self):
return self.get(
viewname='sources:upload_interactive', data={
'document_type_id': self.test_document_type.pk,
}
)
def test_upload_interactive_view_no_permission(self): def test_upload_interactive_view_no_permission(self):
response = self._request_upload_interactive_view() response = self._request_upload_interactive_view()
self.assertEqual(response.status_code, 403) self.assertEqual(response.status_code, 403)
@@ -134,7 +131,7 @@ class DocumentUploadWizardViewTestCase(
) )
response = self._request_upload_interactive_view() response = self._request_upload_interactive_view()
self.assertContains( self.assertContains(
response=response, text=self.test_source.label, status_code=200 response=response, text=self.source.label, status_code=200
) )
@@ -232,19 +229,7 @@ class NewDocumentVersionViewTestCase(GenericDocumentViewTestCase):
self.assertEqual(resolved_link, None) self.assertEqual(resolved_link, None)
class StagingFolderViewTestMixin(object): class StagingFolderViewTestCase(GenericViewTestCase):
def _request_staging_file_delete_view(self, staging_folder, staging_file):
return self.post(
viewname='sources:staging_file_delete', kwargs={
'pk': staging_folder.pk,
'encoded_filename': staging_file.encoded_filename
}
)
class StagingFolderViewTestCase(
StagingFolderViewTestMixin, GenericViewTestCase
):
def setUp(self): def setUp(self):
super(StagingFolderViewTestCase, self).setUp() super(StagingFolderViewTestCase, self).setUp()
self.temporary_directory = mkdtemp() self.temporary_directory = mkdtemp()
@@ -256,6 +241,14 @@ class StagingFolderViewTestCase(
fs_cleanup(self.temporary_directory) fs_cleanup(self.temporary_directory)
super(StagingFolderViewTestCase, self).tearDown() super(StagingFolderViewTestCase, self).tearDown()
def _request_staging_file_delete_view(self, staging_folder, staging_file):
return self.post(
viewname='sources:staging_file_delete', kwargs={
'pk': staging_folder.pk,
'encoded_filename': staging_file.encoded_filename
}
)
def test_staging_file_delete_no_permission(self): def test_staging_file_delete_no_permission(self):
staging_folder = StagingFolderSource.objects.create( staging_folder = StagingFolderSource.objects.create(
label=TEST_SOURCE_LABEL, label=TEST_SOURCE_LABEL,
@@ -297,10 +290,44 @@ class StagingFolderViewTestCase(
self.assertEqual(len(list(staging_folder.get_files())), 0) self.assertEqual(len(list(staging_folder.get_files())), 0)
class SourcesViewTestCase( class SourcesTestCase(GenericDocumentViewTestCase):
SourceTestMixin, SourceViewTestMixin, GenericViewTestCase def _create_web_source(self):
): self.source = WebFormSource.objects.create(
enabled=True, label=TEST_SOURCE_LABEL,
uncompress=TEST_SOURCE_UNCOMPRESS_N
)
def _request_setup_source_list_view(self):
return self.get(viewname='sources:setup_source_list')
def test_source_list_view_no_permission(self):
self._create_web_source()
response = self._request_setup_source_list_view()
self.assertEqual(response.status_code, 403)
def test_source_list_view_with_permission(self):
self._create_web_source()
self.grant_permission(permission=permission_sources_setup_view)
response = self._request_setup_source_list_view()
self.assertContains(
response=response, text=self.source.label, status_code=200
)
def _request_setup_source_create_view(self):
return self.post(
kwargs={'source_type': SOURCE_CHOICE_WEB_FORM},
viewname='sources:setup_source_create', data={
'enabled': True, 'label': TEST_SOURCE_LABEL,
'uncompress': TEST_SOURCE_UNCOMPRESS_N
}
)
def test_source_create_view_no_permission(self): def test_source_create_view_no_permission(self):
self.grant_permission(permission=permission_sources_setup_view)
response = self._request_setup_source_create_view() response = self._request_setup_source_create_view()
self.assertEqual(response.status_code, 403) self.assertEqual(response.status_code, 403)
@@ -308,6 +335,7 @@ class SourcesViewTestCase(
def test_source_create_view_with_permission(self): def test_source_create_view_with_permission(self):
self.grant_permission(permission=permission_sources_setup_create) self.grant_permission(permission=permission_sources_setup_create)
self.grant_permission(permission=permission_sources_setup_view)
response = self._request_setup_source_create_view() response = self._request_setup_source_create_view()
self.assertEqual(response.status_code, 302) self.assertEqual(response.status_code, 302)
@@ -316,10 +344,17 @@ class SourcesViewTestCase(
self.assertEqual(webform_source.label, TEST_SOURCE_LABEL) self.assertEqual(webform_source.label, TEST_SOURCE_LABEL)
self.assertEqual(webform_source.uncompress, TEST_SOURCE_UNCOMPRESS_N) self.assertEqual(webform_source.uncompress, TEST_SOURCE_UNCOMPRESS_N)
def _request_setup_source_delete_view(self):
return self.post(
viewname='sources:setup_source_delete',
kwargs={'pk': self.source.pk}
)
def test_source_delete_view_with_permission(self): def test_source_delete_view_with_permission(self):
self._create_test_source() self._create_web_source()
self.grant_permission(permission=permission_sources_setup_delete) self.grant_permission(permission=permission_sources_setup_delete)
self.grant_permission(permission=permission_sources_setup_view)
response = self._request_setup_source_delete_view() response = self._request_setup_source_delete_view()
self.assertEqual(response.status_code, 302) self.assertEqual(response.status_code, 302)
@@ -327,25 +362,11 @@ class SourcesViewTestCase(
self.assertEqual(WebFormSource.objects.count(), 0) self.assertEqual(WebFormSource.objects.count(), 0)
def test_source_delete_view_no_permission(self): def test_source_delete_view_no_permission(self):
self._create_test_source() self._create_web_source()
self.grant_permission(permission=permission_sources_setup_view)
response = self._request_setup_source_delete_view() response = self._request_setup_source_delete_view()
self.assertEqual(response.status_code, 403) self.assertEqual(response.status_code, 403)
self.assertEqual(WebFormSource.objects.count(), 1) self.assertEqual(WebFormSource.objects.count(), 1)
def test_source_list_view_no_permission(self):
self._create_test_source()
response = self._request_setup_source_list_view()
self.assertEqual(response.status_code, 403)
def test_source_list_view_with_permission(self):
self._create_test_source()
self.grant_permission(permission=permission_sources_setup_view)
response = self._request_setup_source_list_view()
self.assertContains(
response=response, text=self.test_source.label, status_code=200
)

View File

@@ -215,7 +215,6 @@ class UploadInteractiveView(UploadBaseView):
UploadInteractiveView, self UploadInteractiveView, self
).dispatch(request, *args, **kwargs) ).dispatch(request, *args, **kwargs)
except Exception as exception: except Exception as exception:
raise
if request.is_ajax(): if request.is_ajax():
return JsonResponse( return JsonResponse(
data={'error': force_text(exception)}, status=500 data={'error': force_text(exception)}, status=500

View File

@@ -20,7 +20,7 @@ class TagActionTestCase(TagTestMixin, ActionTestCase):
action.execute(context={'document': self.test_document}) action.execute(context={'document': self.test_document})
self.assertEqual(self.test_tag.documents.count(), 1) self.assertEqual(self.test_tag.documents.count(), 1)
self.assertTrue(self.test_document in self.test_tag.documents.all()) self.assertEqual(self.test_document in self.test_tag.documents.all())
def test_tag_remove_action(self): def test_tag_remove_action(self):
self.test_tag.attach_to(document=self.test_document) self.test_tag.attach_to(document=self.test_document)

View File

@@ -56,7 +56,7 @@ def find_packages(directory):
return packages return packages
install_requires = """ install_requires = """
django==1.11.24 django==1.11.22
Pillow==6.0.0 Pillow==6.0.0
PyPDF2==1.26.0 PyPDF2==1.26.0
PyYAML==5.1.1 PyYAML==5.1.1