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
16 changed files with 69 additions and 95 deletions

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,31 +0,0 @@
'use strict';
QUnit.test('partialNavigation.filterLocation', function (assert) {
var testPartialNavigation = new PartialNavigation({
initialURL: '/testInitialURL',
});
/*
* For an empty newLocation we expect the fragment of the URL minus the
* query
*/
var expected = new URI(new URI(location).fragment()).path().toString();
assert.strictEqual(
testPartialNavigation.filterLocation(''), expected, 'newLocation === ""');
/*
* For an empty root value we expect initialURL passed to the
* partialNavigation instance when initialized.
*/
assert.strictEqual(
testPartialNavigation.filterLocation('/'), testPartialNavigation.initialURL, 'newLocation === "/"'
);
/*
* For an empty root value we expect initialURL passed to the
* partialNavigation instance when initialized.
*/
assert.strictEqual(
testPartialNavigation.filterLocation('random'), 'random', 'newLocation === "random"'
);
});

View File

@@ -38,7 +38,6 @@
<script src="{% static 'appearance/node_modules/jquery/dist/jquery.min.js' %}" type="text/javascript"></script> <script src="{% static 'appearance/node_modules/jquery/dist/jquery.min.js' %}" type="text/javascript"></script>
<script src="{% static 'appearance/node_modules/bootstrap/dist/js/bootstrap.min.js' %}" type="text/javascript"></script> <script src="{% static 'appearance/node_modules/bootstrap/dist/js/bootstrap.min.js' %}" type="text/javascript"></script>
<script src="{% static 'appearance/node_modules/@fortawesome/fontawesome-free/js/all.min.js' %}" data-auto-replace-svg="nest" type="text/javascript"></script> <script src="{% static 'appearance/node_modules/@fortawesome/fontawesome-free/js/all.min.js' %}" data-auto-replace-svg="nest" type="text/javascript"></script>
{% block javascript %}{% endblock %}
</body> </body>
</html> </html>
{% endspaceless %} {% endspaceless %}

View File

@@ -4,12 +4,7 @@ from django.utils.translation import ugettext_lazy as _
from mayan.apps.dependencies.classes import ( from mayan.apps.dependencies.classes import (
environment_build, environment_development, environment_testing, environment_build, environment_development, environment_testing,
JavaScriptDependency, PythonDependency PythonDependency
)
JavaScriptDependency(
environment=environment_testing, label=_('QUnit'), module=__name__,
name='qunit', version_string='=2.9.2'
) )
PythonDependency( PythonDependency(

View File

@@ -1,22 +0,0 @@
{% extends 'appearance/base.html' %}
{% load i18n %}
{% load static %}
{% block base_title %}{% trans 'Qunit' %}{% endblock %}
{% block project_name %}{% endblock %}
{% block stylesheets %}
<link href="{% static 'common/node_modules/qunit/qunit/qunit.css' %}" media="screen" rel="stylesheet" type="text/css" />
{% endblock %}
{% block content %}
<div id="qunit"></div>
<div id="qunit-fixture"></div>
{% endblock %}
{% block javascript %}
<script src="{% static 'common/node_modules/qunit/qunit/qunit.js' %}" type="text/javascript"></script>
<script src="{% static 'appearance/js/test/unit/partial_navigation.js' %}" type="text/javascript"></script>
{% endblock %}

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
@@ -73,5 +67,3 @@ class TarGzArchiveClassTestCase(TarArchiveClassTestCase):
class TarBz2ArchiveClassTestCase(TarArchiveClassTestCase): class TarBz2ArchiveClassTestCase(TarArchiveClassTestCase):
archive_path = TEST_TAR_BZ2_FILE_PATH archive_path = TEST_TAR_BZ2_FILE_PATH
cls = TarArchive cls = TarArchive

View File

@@ -10,8 +10,7 @@ from .views import (
AboutView, CurrentUserLocaleProfileDetailsView, AboutView, CurrentUserLocaleProfileDetailsView,
CurrentUserLocaleProfileEditView, FaviconRedirectView, HomeView, CurrentUserLocaleProfileEditView, FaviconRedirectView, HomeView,
LicenseView, ObjectErrorLogEntryListClearView, ObjectErrorLogEntryListView, LicenseView, ObjectErrorLogEntryListClearView, ObjectErrorLogEntryListView,
RootView, SetupListView, ToolsListView, QUnitView, RootView, SetupListView, ToolsListView, multi_object_action_view
multi_object_action_view
) )
urlpatterns = [ urlpatterns = [
@@ -44,9 +43,6 @@ urlpatterns = [
view=ObjectErrorLogEntryListClearView.as_view(), view=ObjectErrorLogEntryListClearView.as_view(),
name='object_error_list_clear' name='object_error_list_clear'
), ),
url(
regex=r'^qunit/', view=QUnitView.as_view(), name='qunit'
)
] ]
urlpatterns += [ urlpatterns += [

View File

@@ -276,8 +276,3 @@ def multi_object_action_view(request):
action, urlencode({'id_list': id_list, 'next': next}) action, urlencode({'id_list': id_list, 'next': next})
) )
) )
class QUnitView(SimpleView):
extra_context = {'title': _('QUnit tests')}
template_name = 'common/qunit.html'

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):