Compare commits

..

13 Commits

Author SHA1 Message Date
Roberto Rosario
d5aab12b8d Update release chapter instructions
Signed-off-by: Roberto Rosario <roberto.rosario@mayan-edms.com>
2019-10-01 13:35:00 -04:00
Roberto Rosario
ebc0a5f449 Update build string
Signed-off-by: Roberto Rosario <roberto.rosario@mayan-edms.com>
2019-10-01 13:32:38 -04:00
Roberto Rosario
415d3bcd2f Bump version to 3.2.8
Signed-off-by: Roberto Rosario <roberto.rosario@mayan-edms.com>
2019-10-01 13:31:40 -04:00
Roberto Rosario
b985f2ef05 Update changelog and release notes
Signed-off-by: Roberto Rosario <roberto.rosario@mayan-edms.com>
2019-10-01 13:30:28 -04:00
Roberto Rosario
15c953815e Improve linking app tests
Signed-off-by: Roberto Rosario <roberto.rosario@mayan-edms.com>
2019-10-01 00:54:10 -04:00
Roberto Rosario
390e552c1f Update test according to new layout
Separate method making request from TestCase
and into separate TestMixins classes.

Signed-off-by: Roberto Rosario <roberto.rosario@mayan-edms.com>
2019-09-30 09:35:52 -04:00
Roberto Rosario
9041f00caa Update release notes
Signed-off-by: Roberto Rosario <roberto.rosario@mayan-edms.com>
2019-09-30 05:02:53 -04:00
Roberto Rosario
b0163319eb Improve source tests layout
Signed-off-by: Roberto Rosario <roberto.rosario@mayan-edms.com>
2019-09-29 23:14:33 -04:00
Roberto Rosario
762cdc5b89 Add Chinese fonts to the Docker image
Signed-off-by: Roberto Rosario <roberto.rosario@mayan-edms.com>
2019-09-28 01:52:23 -04:00
Roberto Rosario
396cbb4b22 Add template comment
Signed-off-by: Roberto Rosario <roberto.rosario@mayan-edms.com>
2019-09-27 05:24:21 -04:00
Roberto Rosario
8b0cd93526 Tweak jstree CSS
Remove border radius and remove the column gutter.

Signed-off-by: Roberto Rosario <roberto.rosario@mayan-edms.com>
2019-09-27 05:23:18 -04:00
Roberto Rosario
f97ccb693b Add test GitLab issue #653
Tests opening zip files containing a non English named member.

Signed-off-by: Roberto Rosario <roberto.rosario@mayan-edms.com>
2019-09-25 23:00:51 -04:00
Roberto Rosario
c3b539ba19 Add MAYAN_GUNICORN_TIMEOUT documentatoin
Signed-off-by: Roberto Rosario <roberto.rosario@mayan-edms.com>
2019-09-25 22:17:50 -04:00
36 changed files with 778 additions and 714 deletions

View File

@@ -1,4 +1,4 @@
3.2.8 (2019-XX-XX) 3.2.8 (2019-10-01)
================== ==================
- Fix error when accessing some API entry points without - Fix error when accessing some API entry points without
being authenticated. being authenticated.
@@ -17,6 +17,7 @@
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,6 +23,8 @@ 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 \
@@ -60,7 +62,6 @@ 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.7 3.2.8

View File

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

View File

@@ -233,6 +233,12 @@ 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,12 +1,21 @@
Version 3.2.8 Version 3.2.8
============= =============
Released: XX, 2019 Released: October 1, 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
^^^^^^^^ ^^^^^^^^
@@ -14,25 +23,43 @@ 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
^^^^^^^^^^^^^
- Fix error when accessing some API entry points without Dependencies
being authenticated. ^^^^^^^^^^^^
- Add cabinet add and remove workflow actions.
- Update Django to version 1.11.24. The Django version used was updated to version 1.11.24. The jQuery version
- Update jQuery to version 3.4.1 used was updated to version 3.4.1. Both as fully backwards compatible with
- Add support for deleting the OCR content of a document their previous versions.
or selection of documents.
- Add OCR content deleted event.
- Add missing recursive option to Docker entrypoint OCR
chown. GitLab issue #668. Thanks to John Wice (@brilthor) ^^^
for the report.
- Add support for deleting the parsed content of a document Support was added to delete the content of document's OCR or parsed content.
of selection of documents. Events for both situations was added allowing content deletion to be used
- Add parsed content deleted event. as workflow transition triggers.
- 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
@@ -126,7 +153,9 @@ 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.7' __version__ = '3.2.8'
__build__ = 0x030207 __build__ = 0x030208
__build_string__ = 'v3.2.7_Wed Aug 28 17:31:08 2019 -0400' __build_string__ = 'v3.2.8_Tue Oct 1 13:31:40 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,5 +418,4 @@ 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"> <div class="col-xs-12 col-sm-12 col-md-12 col-lg-2" style="margin-right: -25px;">{# Remove gutter #}
<h4>{% trans 'Navigation:' %}</h4> <h4>{% trans 'Navigation:' %}</h4>
<div id="jstree"></div> <div id="jstree"></div>
</div> </div>

View File

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

View File

@@ -11,6 +11,7 @@ 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'
@@ -23,6 +24,10 @@ 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,6 +5,7 @@ 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
@@ -58,6 +59,11 @@ 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,19 +13,28 @@ from .literals import TEST_KEY_DATA, TEST_KEY_FINGERPRINT
from .mixins import KeyTestMixin from .mixins import KeyTestMixin
class KeyAPITestCase(KeyTestMixin, BaseAPITestCase): class KeyAPIViewTestMixin(object):
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_key_create_view() response = self._request_test_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)
@@ -33,7 +42,7 @@ class KeyAPITestCase(KeyTestMixin, 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_key_create_view() response = self._request_test_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)
@@ -41,17 +50,10 @@ class KeyAPITestCase(KeyTestMixin, 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_key_delete_view() response = self._request_test_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)
@@ -62,22 +64,15 @@ class KeyAPITestCase(KeyTestMixin, BaseAPITestCase):
obj=self.test_key, permission=permission_key_delete obj=self.test_key, permission=permission_key_delete
) )
response = self._request_key_delete_view() response = self._request_test_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_key_detail_view() response = self._request_test_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):
@@ -86,7 +81,7 @@ class KeyAPITestCase(KeyTestMixin, BaseAPITestCase):
obj=self.test_key, permission=permission_key_view obj=self.test_key, permission=permission_key_view
) )
response = self._request_key_detail_view() response = self._request_test_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,13 +11,23 @@ from .literals import TEST_KEY_DATA, TEST_KEY_FINGERPRINT
from .mixins import KeyTestMixin from .mixins import KeyTestMixin
class KeyViewTestCase(KeyTestMixin, GenericViewTestCase): class KeyViewTestMixin(object):
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.get( response = self._request_test_key_download_view()
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):
@@ -25,20 +35,18 @@ class KeyViewTestCase(KeyTestMixin, GenericViewTestCase):
self._create_test_key() self._create_test_key()
self.grant_access(obj=self.test_key, permission=permission_key_download) self.grant_access(
obj=self.test_key, permission=permission_key_download
response = self.get(
viewname='django_gpg:key_download', kwargs={'pk': self.test_key.pk}
) )
response = self._request_test_key_download_view()
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.post( response = self._request_test_key_upload_view()
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)
@@ -46,12 +54,10 @@ class KeyViewTestCase(KeyTestMixin, 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.post( response = self._request_test_key_upload_view()
viewname='django_gpg:key_upload', data={'key_data': TEST_KEY_DATA}, self.assertEqual(response.status_code, 302)
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(Key.objects.first().fingerprint, TEST_KEY_FINGERPRINT) self.assertEqual(
Key.objects.first().fingerprint, TEST_KEY_FINGERPRINT
)

View File

@@ -15,9 +15,7 @@ from .literals import TEST_COMMENT_TEXT, TEST_COMMENT_TEXT_EDITED
from .mixins import DocumentCommentTestMixin from .mixins import DocumentCommentTestMixin
class CommentAPITestCase( class CommentAPIViewTestMixin(object):
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={
@@ -27,6 +25,42 @@ class CommentAPITestCase(
} }
) )
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)
@@ -45,14 +79,6 @@ class CommentAPITestCase(
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()
@@ -72,19 +98,11 @@ class CommentAPITestCase(
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_comment_edit_patch_api_view() response = self._request_test_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()
@@ -97,24 +115,16 @@ class CommentAPITestCase(
) )
comment_text = self.test_document_comment.comment comment_text = self.test_document_comment.comment
response = self._request_comment_edit_patch_api_view() response = self._request_test_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_api_view() response = self._request_test_comment_detail_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):
@@ -123,18 +133,11 @@ class CommentAPITestCase(
obj=self.test_document, permission=permission_document_comment_view obj=self.test_document, permission=permission_document_comment_view
) )
response = self._request_test_comment_api_view() response = self._request_test_comment_detail_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,7 +13,8 @@ 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
self.test_index.document_types.add(self.test_document_type) if hasattr(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,10 +15,8 @@ from .literals import TEST_INDEX_LABEL, TEST_INDEX_SLUG
from .mixins import IndexTestMixin from .mixins import IndexTestMixin
class DocumentIndexingAPITestCase(IndexTestMixin, DocumentTestMixin, BaseAPITestCase): class DocumentIndexingAPIViewTestMixin(object):
auto_upload_document = False def _request_test_index_create_api_view(self):
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,
@@ -26,8 +24,29 @@ class DocumentIndexingAPITestCase(IndexTestMixin, DocumentTestMixin, BaseAPITest
} }
) )
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_index_create_api_view() response = self._request_test_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)
@@ -35,7 +54,7 @@ class DocumentIndexingAPITestCase(IndexTestMixin, DocumentTestMixin, BaseAPITest
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_index_create_api_view() response = self._request_test_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()
@@ -46,17 +65,10 @@ class DocumentIndexingAPITestCase(IndexTestMixin, DocumentTestMixin, BaseAPITest
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_index_delete_api_view() response = self._request_test_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())
@@ -68,22 +80,15 @@ class DocumentIndexingAPITestCase(IndexTestMixin, DocumentTestMixin, BaseAPITest
obj=self.test_index, permission=permission_document_indexing_delete obj=self.test_index, permission=permission_document_indexing_delete
) )
response = self._request_index_delete_api_view() response = self._request_test_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_index_detail_api_view() response = self._request_test_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)
@@ -95,7 +100,7 @@ class DocumentIndexingAPITestCase(IndexTestMixin, DocumentTestMixin, BaseAPITest
obj=self.test_index, permission=permission_document_indexing_view obj=self.test_index, permission=permission_document_indexing_view
) )
response = self._request_index_detail_api_view() response = self._request_test_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,5 +1,6 @@
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
@@ -18,10 +19,8 @@ from .mixins import IndexTestMixin, IndexViewTestMixin
class IndexViewTestCase( class IndexViewTestCase(
IndexTestMixin, IndexViewTestMixin, GenericDocumentViewTestCase IndexTestMixin, IndexViewTestMixin, GenericViewTestCase
): ):
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)
@@ -80,9 +79,7 @@ class IndexViewTestCase(
self.assertEqual(self.test_index.label, TEST_INDEX_LABEL_EDITED) self.assertEqual(self.test_index.label, TEST_INDEX_LABEL_EDITED)
class IndexInstaceViewTestCase( class IndexInstaceViewTestMixin(object):
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,
@@ -90,6 +87,18 @@ class IndexInstaceViewTestCase(
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()
@@ -115,17 +124,10 @@ 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_index_instance_node_view( response = self._request_test_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)
@@ -138,15 +140,13 @@ class IndexInstaceViewTestCase(
permission=permission_document_indexing_instance_view permission=permission_document_indexing_instance_view
) )
response = self._request_index_instance_node_view( response = self._request_test_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 IndexToolsViewTestCase( class IndexToolsViewTestMixin(object):
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,6 +159,11 @@ class IndexToolsViewTestCase(
} }
) )
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,84 +23,32 @@ TEST_UNSIGNED_DOCUMENT_COUNT = 4
TEST_SIGNED_DOCUMENT_COUNT = 2 TEST_SIGNED_DOCUMENT_COUNT = 2
class SignaturesViewTestCase(SignaturesTestMixin, GenericDocumentViewTestCase): class SignaturesViewTestMixin(object):
auto_upload_document = False def _request_test_document_version_signature_delete_view(self):
return self.post(
def _request_document_version_signature_list_view(self, document): viewname='signatures:document_version_signature_delete',
return self.get( kwargs={'pk': self.test_signature.pk}
viewname='signatures:document_version_signature_list',
kwargs={'pk': self.test_document.latest_version.pk}
) )
def test_signature_list_view_no_permission(self): def _request_test_document_version_signature_details_view(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( return self.get(
viewname='signatures:document_version_signature_details', viewname='signatures:document_version_signature_details',
kwargs={'pk': self.test_signature.pk} kwargs={'pk': self.test_signature.pk}
) )
def test_signature_detail_view_no_permission(self): def _request_test_document_version_signature_download_view(self):
self._create_test_key() return self.get(
viewname='signatures:document_version_signature_download',
self.test_document_path = TEST_DOCUMENT_PATH kwargs={'pk': self.test_signature.pk}
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() def _request_test_document_version_signature_list_view(self, document):
self.assertContains( return self.get(
response=response, text=self.test_signature.signature_id, viewname='signatures:document_version_signature_list',
status_code=200 kwargs={'pk': self.test_document.latest_version.pk}
) )
def _request_document_version_signature_upload_view(self): def _request_test_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',
@@ -108,70 +56,17 @@ class SignaturesViewTestCase(SignaturesTestMixin, GenericDocumentViewTestCase):
data={'signature_file': file_object} data={'signature_file': file_object}
) )
def test_signature_upload_view_no_permission(self): def _request_all_test_document_version_signature_verify_view(self):
self.test_document_path = TEST_DOCUMENT_PATH
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)
self.assertEqual(DetachedSignature.objects.count(), 1)
def _request_document_version_signature_download_view(self):
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( return self.post(
viewname='signatures:document_version_signature_delete', viewname='signatures:all_document_version_signature_verify'
kwargs={'pk': self.test_signature.pk}
) )
class SignaturesViewTestCase(
SignaturesTestMixin, SignaturesViewTestMixin, GenericDocumentViewTestCase
):
auto_upload_document = False
def test_signature_delete_view_no_permission(self): def test_signature_delete_view_no_permission(self):
self._create_test_key() self._create_test_key()
@@ -185,7 +80,7 @@ class SignaturesViewTestCase(SignaturesTestMixin, GenericDocumentViewTestCase):
permission=permission_document_version_signature_view permission=permission_document_version_signature_view
) )
response = self._request_document_version_signature_delete_view() response = self._request_test_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)
@@ -206,15 +101,124 @@ class SignaturesViewTestCase(SignaturesTestMixin, GenericDocumentViewTestCase):
permission=permission_document_version_signature_view permission=permission_document_version_signature_view
) )
response = self._request_document_version_signature_delete_view() response = self._request_test_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 _request_all_document_version_signature_verify_view(self): def test_signature_detail_view_no_permission(self):
return self.post( self._create_test_key()
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')
@@ -240,7 +244,7 @@ class SignaturesViewTestCase(SignaturesTestMixin, GenericDocumentViewTestCase):
DocumentVersion._post_save_hooks = old_hooks DocumentVersion._post_save_hooks = old_hooks
response = self._request_all_document_version_signature_verify_view() response = self._request_all_test_document_version_signature_verify_view()
self.assertEqual(response.status_code, 403) self.assertEqual(response.status_code, 403)
self.assertEqual( self.assertEqual(
@@ -277,7 +281,7 @@ class SignaturesViewTestCase(SignaturesTestMixin, GenericDocumentViewTestCase):
permission=permission_document_version_signature_verify permission=permission_document_version_signature_verify
) )
response = self._request_all_document_version_signature_verify_view() response = self._request_all_test_document_version_signature_verify_view()
self.assertEqual(response.status_code, 302) self.assertEqual(response.status_code, 302)
self.assertEqual( self.assertEqual(

View File

@@ -3,6 +3,7 @@ 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

@@ -1,39 +0,0 @@
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,20 +5,11 @@ 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,7 +11,6 @@ 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
@@ -53,12 +52,6 @@ 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()
@@ -101,10 +94,6 @@ 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,6 +4,7 @@ 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
@@ -36,10 +37,8 @@ def hash_function():
return hashlib.sha256() return hashlib.sha256()
def upload_to(instance, filename): def UUID_FUNCTION(*args, **kwargs):
return instance.document.document_type.get_upload_filename( return force_text(uuid.uuid4())
instance=instance, filename=filename
)
@python_2_unicode_compatible @python_2_unicode_compatible
@@ -87,7 +86,7 @@ class DocumentVersion(models.Model):
# File related fields # File related fields
file = models.FileField( file = models.FileField(
storage=storage_documentversion, upload_to=upload_to, storage=storage_documentversion, upload_to=UUID_FUNCTION,
verbose_name=_('File') verbose_name=_('File')
) )
mimetype = models.CharField( mimetype = models.CharField(

View File

@@ -82,9 +82,7 @@ class DocumentTypeListView(SingleObjectListView):
class DocumentTypeCreateView(SingleObjectCreateView): class DocumentTypeCreateView(SingleObjectCreateView):
fields = ('label',) fields = ('label',)
model = DocumentType model = DocumentType
post_action_redirect = reverse_lazy( post_action_redirect = reverse_lazy(viewname='documents:document_type_list')
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 SearchModelAPITestCase(BaseAPITestCase): class SearchModelAPIViewTestCase(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 SearchModelAPITestCase(BaseAPITestCase):
) )
class SearchAPITestCase(DocumentTestMixin, BaseAPITestCase): class SearchAPIViewTestMixin(object):
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,6 +32,19 @@ class SearchAPITestCase(DocumentTestMixin, BaseAPITestCase):
}, 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)
@@ -49,15 +62,6 @@ class SearchAPITestCase(DocumentTestMixin, BaseAPITestCase):
) )
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,6 +10,14 @@ 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,10 +14,15 @@ 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 SmartLinkTestMixin, SmartLinkViewTestMixin from .mixins import (
SmartLinkDocumentViewTestMixin, SmartLinkTestMixin,
SmartLinkViewTestMixin
)
class SmartLinkViewTestCase(SmartLinkTestMixin, SmartLinkViewTestMixin, GenericViewTestCase): class SmartLinkViewTestCase(
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)
@@ -74,10 +79,15 @@ class SmartLinkViewTestCase(SmartLinkTestMixin, SmartLinkViewTestMixin, GenericV
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.test_smart_link.label, TEST_SMART_LINK_LABEL_EDITED) self.assertEqual(
self.test_smart_link.label, TEST_SMART_LINK_LABEL_EDITED
)
class SmartLinkDocumentViewTestCase(SmartLinkTestMixin, GenericDocumentViewTestCase): class SmartLinkDocumentViewTestCase(
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()
@@ -89,12 +99,6 @@ class SmartLinkDocumentViewTestCase(SmartLinkTestMixin, GenericDocumentViewTestC
) )
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

@@ -0,0 +1,34 @@
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,7 +28,6 @@ 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,
@@ -37,21 +36,24 @@ 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(GenericDocumentTestCase): class CompressedUploadsTestCase(SourceTestMixin, GenericDocumentTestCase):
auto_upload_document = False auto_upload_document = False
def test_upload_compressed_file(self): def test_upload_compressed_file(self):
source = WebFormSource( self._create_test_source()
label='test source', uncompress=SOURCE_UNCOMPRESS_CHOICE_Y self.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:
source.handle_upload( self.test_source.handle_upload(
document_type=self.test_document_type, document_type=self.test_document_type,
file_object=file_object, file_object=file_object,
expand=(source.uncompress == SOURCE_UNCOMPRESS_CHOICE_Y) expand=(
self.test_source.uncompress == SOURCE_UNCOMPRESS_CHOICE_Y
)
) )
self.assertEqual(Document.objects.count(), 2) self.assertEqual(Document.objects.count(), 2)

View File

@@ -25,32 +25,42 @@ 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 DocumentUploadTestCase(GenericDocumentViewTestCase): class DocumentUploadWizardViewTestMixin(object):
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.source.pk 'source_id': self.test_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.source.uncompress = SOURCE_UNCOMPRESS_CHOICE_Y self.test_source.uncompress = SOURCE_UNCOMPRESS_CHOICE_Y
self.source.save() self.test_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
@@ -104,7 +114,7 @@ class DocumentUploadTestCase(GenericDocumentViewTestCase):
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.source.pk 'source_id': self.test_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,
@@ -114,13 +124,6 @@ class DocumentUploadTestCase(GenericDocumentViewTestCase):
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)
@@ -131,7 +134,7 @@ class DocumentUploadTestCase(GenericDocumentViewTestCase):
) )
response = self._request_upload_interactive_view() response = self._request_upload_interactive_view()
self.assertContains( self.assertContains(
response=response, text=self.source.label, status_code=200 response=response, text=self.test_source.label, status_code=200
) )
@@ -229,7 +232,19 @@ class NewDocumentVersionViewTestCase(GenericDocumentViewTestCase):
self.assertEqual(resolved_link, None) self.assertEqual(resolved_link, None)
class StagingFolderViewTestCase(GenericViewTestCase): class StagingFolderViewTestMixin(object):
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()
@@ -241,14 +256,6 @@ class StagingFolderViewTestCase(GenericViewTestCase):
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,
@@ -290,44 +297,10 @@ class StagingFolderViewTestCase(GenericViewTestCase):
self.assertEqual(len(list(staging_folder.get_files())), 0) self.assertEqual(len(list(staging_folder.get_files())), 0)
class SourcesTestCase(GenericDocumentViewTestCase): class SourcesViewTestCase(
def _create_web_source(self): SourceTestMixin, SourceViewTestMixin, GenericViewTestCase
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)
@@ -335,7 +308,6 @@ class SourcesTestCase(GenericDocumentViewTestCase):
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)
@@ -344,17 +316,10 @@ class SourcesTestCase(GenericDocumentViewTestCase):
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_web_source() self._create_test_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)
@@ -362,11 +327,25 @@ class SourcesTestCase(GenericDocumentViewTestCase):
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_web_source() self._create_test_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,6 +215,7 @@ 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.assertEqual(self.test_document in self.test_tag.documents.all()) self.assertTrue(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.22 django==1.11.24
Pillow==6.0.0 Pillow==6.0.0
PyPDF2==1.26.0 PyPDF2==1.26.0
PyYAML==5.1.1 PyYAML==5.1.1