From 78198f339879a224a4338be7f3301cec1cc5c5f1 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 22 Jun 2015 21:04:06 -0400 Subject: [PATCH] Smart settings refactor --- .travis.yml | 2 +- .../middleware/login_required_middleware.py | 4 +- mayan/apps/authentication/settings.py | 23 ++------- mayan/apps/authentication/tests.py | 18 ++++--- mayan/apps/authentication/urls.py | 1 - mayan/apps/authentication/views.py | 4 +- mayan/apps/common/apps.py | 9 ++-- mayan/apps/common/runtime.py | 4 +- mayan/apps/common/settings.py | 23 ++------- .../common/templatetags/attribute_tags.py | 3 ++ mayan/apps/common/views.py | 4 ++ mayan/apps/converter/backends/python.py | 4 +- mayan/apps/converter/classes.py | 14 +++--- mayan/apps/converter/runtime.py | 4 +- mayan/apps/converter/settings.py | 31 ++++++------ mayan/apps/django_gpg/runtime.py | 4 +- mayan/apps/django_gpg/settings.py | 15 ++---- mayan/apps/documents/api_views.py | 14 +++--- mayan/apps/documents/apps.py | 9 ++-- mayan/apps/documents/links.py | 6 +-- mayan/apps/documents/managers.py | 10 ++-- mayan/apps/documents/models.py | 22 ++++----- mayan/apps/documents/runtime.py | 4 +- mayan/apps/documents/settings.py | 44 ++++++++--------- mayan/apps/documents/urls.py | 6 +-- mayan/apps/documents/views.py | 24 +++++----- mayan/apps/documents/widgets.py | 8 ++-- mayan/apps/dynamic_search/api.py | 2 +- mayan/apps/dynamic_search/classes.py | 2 +- mayan/apps/dynamic_search/managers.py | 2 +- mayan/apps/dynamic_search/settings.py | 16 +++---- mayan/apps/dynamic_search/views.py | 6 +-- mayan/apps/metadata/forms.py | 4 +- mayan/apps/metadata/models.py | 4 +- mayan/apps/metadata/parsers.py | 48 +++++++++++++++++++ mayan/apps/metadata/settings.py | 16 +++---- mayan/apps/ocr/api.py | 4 +- mayan/apps/ocr/apps.py | 8 ++-- mayan/apps/ocr/backends/tesseract.py | 2 +- mayan/apps/ocr/classes.py | 2 - mayan/apps/ocr/parsers/__init__.py | 8 ++-- mayan/apps/ocr/runtime.py | 4 +- mayan/apps/ocr/settings.py | 17 +++---- mayan/apps/smart_settings/__init__.py | 1 + mayan/apps/smart_settings/apps.py | 23 ++++++++- mayan/apps/smart_settings/classes.py | 46 ++++++++++++++++++ mayan/apps/smart_settings/links.py | 1 + mayan/apps/smart_settings/urls.py | 4 ++ mayan/apps/smart_settings/views.py | 38 +++++++++++++++ mayan/apps/smart_settings/widgets.py | 12 +++++ mayan/apps/sources/api_views.py | 6 +-- mayan/apps/sources/widgets.py | 6 +-- .../apps/storage/backends/filebasedstorage.py | 4 +- mayan/apps/storage/settings.py | 12 ++--- requirements/common.txt | 1 + 55 files changed, 370 insertions(+), 243 deletions(-) create mode 100644 mayan/apps/metadata/parsers.py create mode 100644 mayan/apps/smart_settings/classes.py create mode 100644 mayan/apps/smart_settings/widgets.py diff --git a/.travis.yml b/.travis.yml index df957ff4ce..fc26eab04e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,7 @@ python: - 2.7 env: global: - - TEST_APPS="document_indexing documents django_gpg dynamic_search lock_manager document_signatures folders ocr sources tags" + - TEST_APPS="authentication document_indexing documents django_gpg dynamic_search lock_manager document_signatures folders ocr sources tags" matrix: - DB=mysql - DB=postgres diff --git a/mayan/apps/authentication/middleware/login_required_middleware.py b/mayan/apps/authentication/middleware/login_required_middleware.py index ea631fa96e..6522bcce63 100644 --- a/mayan/apps/authentication/middleware/login_required_middleware.py +++ b/mayan/apps/authentication/middleware/login_required_middleware.py @@ -6,7 +6,7 @@ from django.http import HttpResponseRedirect from django.conf import settings from django.core.urlresolvers import reverse -from ..settings import ALLOW_ANONYMOUS_ACCESS +from ..settings import setting_allow_anonymous_access EXEMPT_URLS = [re.compile(reverse(settings.LOGIN_URL).lstrip('/'))] if hasattr(settings, 'LOGIN_EXEMPT_URLS'): @@ -25,7 +25,7 @@ class LoginRequiredMiddleware: """ def process_request(self, request): - if not ALLOW_ANONYMOUS_ACCESS: + if not setting_allow_anonymous_access.value: assert hasattr(request, 'user'), "The Login Required middleware\ requires authentication middleware to be installed. Edit your\ MIDDLEWARE_CLASSES setting to insert\ diff --git a/mayan/apps/authentication/settings.py b/mayan/apps/authentication/settings.py index 30ebe7d9fc..e3d9738426 100644 --- a/mayan/apps/authentication/settings.py +++ b/mayan/apps/authentication/settings.py @@ -1,24 +1,9 @@ from __future__ import unicode_literals -from django.contrib.auth.models import User from django.utils.translation import ugettext_lazy as _ -from smart_settings.api import register_setting +from smart_settings import Namespace -register_setting( - namespace='authentication', - module='authentication.settings', - name='LOGIN_METHOD', - global_name='COMMON_LOGIN_METHOD', - default='username', - description=_('Controls the mechanism used to authenticated user. Options are: username, email'), -) - -register_setting( - namespace='authentication', - module='authentication.settings', - name='ALLOW_ANONYMOUS_ACCESS', - global_name='COMMON_ALLOW_ANONYMOUS_ACCESS', - default=False, - description=_('Allow non authenticated users, access to all views'), -) +namespace = Namespace(name='authentication', label=_('Authentication')) +setting_login_method = namespace.add_setting(global_name='AUTHENTICATION_LOGIN_METHOD', default='username', help_text=_('Controls the mechanism used to authenticated user. Options are: username, email')) +setting_allow_anonymous_access = namespace.add_setting(global_name='AUTHENTICATION_ALLOW_ANONYMOUS_ACCESS', default=False, help_text=_('Allow non authenticated users, access to all views')) diff --git a/mayan/apps/authentication/tests.py b/mayan/apps/authentication/tests.py index 74dd087c15..4818cc7c68 100644 --- a/mayan/apps/authentication/tests.py +++ b/mayan/apps/authentication/tests.py @@ -6,8 +6,7 @@ from django.core.urlresolvers import reverse from django.test import TestCase from django.test.client import Client -from authentication import settings as auth_authentication -import authentication +from .settings import setting_login_method TEST_ADMIN_EMAIL = 'admin@admin.com' TEST_ADMIN_PASSWORD = 'test_admin_password' @@ -24,12 +23,14 @@ class UserLoginTestCase(TestCase): self.client = Client() def test_normal_behaviour(self): - setattr(authentication.settings, 'LOGIN_METHOD', 'username') + # TODO set setting_login_method to 'username' + # setattr(authentication.settings, 'LOGIN_METHOD', 'username') response = self.client.get(reverse('documents:document_list')) self.assertRedirects(response, 'http://testserver/authentication/login/') def test_username_login(self): - setattr(authentication.settings, 'LOGIN_METHOD', 'username') + # TODO set setting_login_method to 'username' + # setattr(authentication.settings, 'LOGIN_METHOD', 'username') logged_in = self.client.login(username=TEST_ADMIN_USERNAME, password=TEST_ADMIN_PASSWORD) self.assertTrue(logged_in) response = self.client.get(reverse('documents:document_list')) @@ -38,7 +39,8 @@ class UserLoginTestCase(TestCase): def test_email_login(self): with self.settings(COMMON_LOGIN_METHOD='email', AUTHENTICATION_BACKENDS=('authentication.auth.email_auth_backend.EmailAuthBackend',)): - setattr(authentication.settings, 'LOGIN_METHOD', 'email') + # TODO set setting_login_method to 'email' + #setattr(authentication.settings, 'LOGIN_METHOD', 'email') logged_in = self.client.login(username=TEST_ADMIN_USERNAME, password=TEST_ADMIN_PASSWORD) self.assertFalse(logged_in) @@ -50,7 +52,8 @@ class UserLoginTestCase(TestCase): self.assertEqual(response.status_code, 200) def test_username_login_via_views(self): - setattr(authentication.settings, 'LOGIN_METHOD', 'username') + # TODO set setting_login_method to 'username' + # setattr(authentication.settings, 'LOGIN_METHOD', 'username') response = self.client.get(reverse('documents:document_list')) self.assertRedirects(response, 'http://testserver/authentication/login/') @@ -61,7 +64,8 @@ class UserLoginTestCase(TestCase): def test_email_login_via_views(self): with self.settings(COMMON_LOGIN_METHOD='email', AUTHENTICATION_BACKENDS=('authentication.auth.email_auth_backend.EmailAuthBackend',)): - setattr(authentication.settings, 'LOGIN_METHOD', 'email') + # TODO set setting_login_method to 'email' + #setattr(authentication.settings, 'LOGIN_METHOD', 'email') response = self.client.get(reverse('documents:document_list')) self.assertRedirects(response, 'http://testserver/authentication/login/') diff --git a/mayan/apps/authentication/urls.py b/mayan/apps/authentication/urls.py index ceacea55b8..9e1643cb06 100644 --- a/mayan/apps/authentication/urls.py +++ b/mayan/apps/authentication/urls.py @@ -3,7 +3,6 @@ from __future__ import unicode_literals from django.conf import settings from django.conf.urls import patterns, url - urlpatterns = patterns('authentication.views', url(r'^login/$', 'login_view', (), name='login_view'), url(r'^password/change/done/$', 'password_change_done', (), name='password_change_done'), diff --git a/mayan/apps/authentication/views.py b/mayan/apps/authentication/views.py index eefa58a592..ecf0b20254 100644 --- a/mayan/apps/authentication/views.py +++ b/mayan/apps/authentication/views.py @@ -22,7 +22,7 @@ from dynamic_search.classes import SearchModel from permissions.models import Permission from .forms import EmailAuthenticationForm -from .settings import LOGIN_METHOD +from .settings import setting_login_method def login_view(request): @@ -32,7 +32,7 @@ def login_view(request): """ kwargs = {'template_name': 'appearance/login.html'} - if LOGIN_METHOD == 'email': + if setting_login_method.value == 'email': kwargs['authentication_form'] = EmailAuthenticationForm if not request.user.is_authenticated(): diff --git a/mayan/apps/common/apps.py b/mayan/apps/common/apps.py index 27f9c836ea..b9646ad3be 100644 --- a/mayan/apps/common/apps.py +++ b/mayan/apps/common/apps.py @@ -10,8 +10,6 @@ from django.contrib.auth.signals import user_logged_in from django.db.models.signals import post_migrate, post_save from django.utils.translation import ugettext_lazy as _ -from common import settings as common_settings - from .handlers import ( user_locale_profile_session_config, user_locale_profile_create ) @@ -25,7 +23,7 @@ from .menus import ( menu_facet, menu_main, menu_secondary, menu_setup, menu_tools ) from .models import AnonymousUserSingleton -from .settings import TEMPORARY_DIRECTORY +from .settings import setting_temporary_directory from .utils import validate_path logger = logging.getLogger(__name__) @@ -80,5 +78,6 @@ class CommonApp(MayanAppConfig): user_logged_in.connect(user_locale_profile_session_config, dispatch_uid='user_locale_profile_session_config', sender=settings.AUTH_USER_MODEL) post_save.connect(user_locale_profile_create, dispatch_uid='user_locale_profile_create', sender=settings.AUTH_USER_MODEL) - if (not validate_path(TEMPORARY_DIRECTORY)) or (not TEMPORARY_DIRECTORY): - setattr(common_settings, 'TEMPORARY_DIRECTORY', tempfile.mkdtemp()) + # TODO: Create temp directory and update setting if /tmp not found/writable or value == None + #if (not validate_path(setting_temporary_directory.value)) or (not setting_temporary_directory.value): + # setattr(common_settings, 'setting_temporary_directory.value', tempfile.mkdtemp()) diff --git a/mayan/apps/common/runtime.py b/mayan/apps/common/runtime.py index 2f338304d4..59621c1341 100644 --- a/mayan/apps/common/runtime.py +++ b/mayan/apps/common/runtime.py @@ -1,5 +1,5 @@ from django.utils.module_loading import import_string -from .settings import SHARED_STORAGE +from .settings import setting_shared_storage -shared_storage_backend = import_string(SHARED_STORAGE)() +shared_storage_backend = import_string(setting_shared_storage.value)() diff --git a/mayan/apps/common/settings.py b/mayan/apps/common/settings.py index 6b962637eb..89c0a5b463 100644 --- a/mayan/apps/common/settings.py +++ b/mayan/apps/common/settings.py @@ -2,23 +2,8 @@ from __future__ import unicode_literals from django.utils.translation import ugettext_lazy as _ -from smart_settings.api import register_setting +from smart_settings import Namespace -TEMPORARY_DIRECTORY = register_setting( - namespace='common', - module='common.settings', - name='TEMPORARY_DIRECTORY', - global_name='COMMON_TEMPORARY_DIRECTORY', - default='/tmp', - description=_('Temporary directory used site wide to store thumbnails, previews and temporary files. If none is specified, one will be created using tempfile.mkdtemp()'), - exists=True -) - -register_setting( - namespace='common', - module='common.settings', - name='SHARED_STORAGE', - global_name='COMMON_SHARED_STORAGE', - default='storage.backends.filebasedstorage.FileBasedStorage', - description=_('A storage backend that all workers can use to share files.'), -) +namespace = Namespace(name='common', label=_('Common')) +setting_temporary_directory = namespace.add_setting(global_name='COMMON_setting_temporary_directory', default='/tmp', help_text=_('Temporary directory used site wide to store thumbnails, previews and temporary files. If none is specified, one will be created using tempfile.mkdtemp()'), is_path=True) # TODO: get os default temp directory +setting_shared_storage = namespace.add_setting(global_name='COMMON_SHARED_STORAGE', default='storage.backends.filebasedstorage.FileBasedStorage', help_text=_('A storage backend that all workers can use to share files.')) diff --git a/mayan/apps/common/templatetags/attribute_tags.py b/mayan/apps/common/templatetags/attribute_tags.py index 2cd00fe82b..b06b6d9b97 100644 --- a/mayan/apps/common/templatetags/attribute_tags.py +++ b/mayan/apps/common/templatetags/attribute_tags.py @@ -27,6 +27,9 @@ def get_model_list_columns(obj): except IndexError: # It a list and it's empty pass + except KeyError: + # It a list and it's empty + pass for key, value in model_list_columns.items(): if key == obj or isinstance(obj, key): diff --git a/mayan/apps/common/views.py b/mayan/apps/common/views.py index d7165420bb..4742b6d162 100644 --- a/mayan/apps/common/views.py +++ b/mayan/apps/common/views.py @@ -465,6 +465,10 @@ class SetupListView(TemplateView): return data +class SimpleView(ViewPermissionCheckMixin, ExtraContextMixin, TemplateView): + pass + + class ToolsListView(TemplateView): template_name = 'appearance/generic_list_horizontal.html' diff --git a/mayan/apps/converter/backends/python.py b/mayan/apps/converter/backends/python.py index 326daac750..fe98db0725 100644 --- a/mayan/apps/converter/backends/python.py +++ b/mayan/apps/converter/backends/python.py @@ -17,10 +17,10 @@ import sh from common.utils import fs_cleanup from ..classes import ConverterBase -from ..settings import PDFTOPPM_PATH +from ..settings import setting_pdftoppm_path try: - pdftoppm = sh.Command(PDFTOPPM_PATH) + pdftoppm = sh.Command(setting_pdftoppm_path.value) except sh.CommandNotFound: pdftoppm = None else: diff --git a/mayan/apps/converter/classes.py b/mayan/apps/converter/classes.py index 9f32629c29..6154a58d42 100644 --- a/mayan/apps/converter/classes.py +++ b/mayan/apps/converter/classes.py @@ -15,13 +15,13 @@ from PIL import Image from django.utils.translation import ugettext_lazy as _ -from common.settings import TEMPORARY_DIRECTORY +from common.settings import setting_temporary_directory from common.utils import fs_cleanup from mimetype.api import get_mimetype from .exceptions import OfficeConversionError, UnknownFileFormat from .literals import DEFAULT_PAGE_NUMBER, DEFAULT_FILE_FORMAT -from .settings import LIBREOFFICE_PATH +from .settings import setting_libreoffice_path CONVERTER_OFFICE_FILE_MIMETYPES = [ 'application/msword', @@ -86,18 +86,18 @@ class ConverterBase(object): new_file_object.close() command = [] - command.append(LIBREOFFICE_PATH) + command.append(setting_libreoffice_path.value) command.append('--headless') command.append('--convert-to') command.append('pdf') command.append(input_filepath) command.append('--outdir') - command.append(TEMPORARY_DIRECTORY) + command.append(setting_temporary_directory.value) logger.debug('command: %s', command) - os.environ['HOME'] = TEMPORARY_DIRECTORY + os.environ['HOME'] = setting_temporary_directory.value proc = subprocess.Popen(command, close_fds=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE) return_code = proc.wait() logger.debug('return_code: %s', return_code) @@ -111,7 +111,7 @@ class ConverterBase(object): logger.debug('filename: %s', filename) logger.debug('extension: %s', extension) - converted_output = os.path.join(TEMPORARY_DIRECTORY, os.path.extsep.join([filename, 'pdf'])) + converted_output = os.path.join(setting_temporary_directory.value, os.path.extsep.join([filename, 'pdf'])) logger.debug('converted_output: %s', converted_output) return converted_output @@ -151,7 +151,7 @@ class ConverterBase(object): self.mime_type = 'application/pdf' if self.mime_type in CONVERTER_OFFICE_FILE_MIMETYPES: - if os.path.exists(LIBREOFFICE_PATH): + if os.path.exists(setting_libreoffice_path.value): if not self.soffice_file_object: converted_output = ConverterBase.soffice(self.file_object) self.file_object.seek(0) diff --git a/mayan/apps/converter/runtime.py b/mayan/apps/converter/runtime.py index 23449d62f4..acfc7d1e7f 100644 --- a/mayan/apps/converter/runtime.py +++ b/mayan/apps/converter/runtime.py @@ -4,7 +4,7 @@ import logging from django.utils.module_loading import import_string -from .settings import GRAPHICS_BACKEND +from .settings import setting_graphics_backend logger = logging.getLogger(__name__) -backend = converter_class = import_string(GRAPHICS_BACKEND) +backend = converter_class = import_string(setting_graphics_backend.value) diff --git a/mayan/apps/converter/settings.py b/mayan/apps/converter/settings.py index d0732fc473..896b8b9bab 100644 --- a/mayan/apps/converter/settings.py +++ b/mayan/apps/converter/settings.py @@ -2,18 +2,21 @@ from __future__ import unicode_literals from django.utils.translation import ugettext_lazy as _ -from smart_settings.api import register_settings +from smart_settings import Namespace -register_settings( - namespace='converter', - module='converter.settings', - settings=[ - {'name': 'IM_CONVERT_PATH', 'global_name': 'CONVERTER_IM_CONVERT_PATH', 'default': '/usr/bin/convert', 'description': _('File path to imagemagick\'s convert program.'), 'exists': True}, - {'name': 'IM_IDENTIFY_PATH', 'global_name': 'CONVERTER_IM_IDENTIFY_PATH', 'default': '/usr/bin/identify', 'description': _('File path to imagemagick\'s identify program.'), 'exists': True}, - {'name': 'GM_PATH', 'global_name': 'CONVERTER_GM_PATH', 'default': '/usr/bin/gm', 'description': _('File path to graphicsmagick\'s program.'), 'exists': True}, - {'name': 'GM_SETTINGS', 'global_name': 'CONVERTER_GM_SETTINGS', 'default': ''}, - {'name': 'GRAPHICS_BACKEND', 'global_name': 'CONVERTER_GRAPHICS_BACKEND', 'default': 'converter.backends.python.Python', 'description': _('Graphics conversion backend to use. Options are: converter.backends.imagemagick.ImageMagick, converter.backends.graphicsmagick.GraphicsMagick and converter.backends.python.Python')}, - {'name': 'LIBREOFFICE_PATH', 'global_name': 'CONVERTER_LIBREOFFICE_PATH', 'default': '/usr/bin/libreoffice', 'exists': True, 'description': _('Path to the libreoffice program.')}, - {'name': 'PDFTOPPM_PATH', 'global_name': 'CONVERTER_PDFTOPPM_PATH', 'default': '/usr/bin/pdftoppm', 'exists': True, 'description': _('Path to the Popple program pdftoppm.')}, - ] -) +namespace = Namespace(name='converter', label=_('Converter')) +setting_graphics_backend = namespace.add_setting(global_name='CONVERTER_GRAPHICS_BACKEND', default='converter.backends.python.Python', help_text=_('Graphics conversion backend to use.')) +setting_libreoffice_path = namespace.add_setting(global_name='CONVERTER_LIBREOFFICE_PATH', default='/usr/bin/libreoffice', help_text=_('Path to the libreoffice program.'), is_path=True) +setting_pdftoppm_path = namespace.add_setting(global_name='CONVERTER_PDFTOPPM_PATH', default='/usr/bin/pdftoppm', help_text=_('Path to the Popple program pdftoppm.'), is_path=True) + +# TODO: remove unconverted backends from repository +#register_settings( +# namespace='converter', +# module='converter.settings', +# settings=[ +# {'name': 'IM_CONVERT_PATH', 'global_name': 'CONVERTER_IM_CONVERT_PATH', 'default': '/usr/bin/convert', 'description': _('File path to imagemagick\'s convert program.'), 'exists': True}, +# {'name': 'IM_IDENTIFY_PATH', 'global_name': 'CONVERTER_IM_IDENTIFY_PATH', 'default': '/usr/bin/identify', 'description': _('File path to imagemagick\'s identify program.'), 'exists': True}, +# {'name': 'GM_PATH', 'global_name': 'CONVERTER_GM_PATH', 'default': '/usr/bin/gm', 'description': _('File path to graphicsmagick\'s program.'), 'exists': True}, +# {'name': 'GM_SETTINGS', 'global_name': 'CONVERTER_GM_SETTINGS', 'default': ''}, +# ] +#) diff --git a/mayan/apps/django_gpg/runtime.py b/mayan/apps/django_gpg/runtime.py index 2a471b09e9..d5e4f2b5e2 100644 --- a/mayan/apps/django_gpg/runtime.py +++ b/mayan/apps/django_gpg/runtime.py @@ -1,4 +1,4 @@ from .api import GPG -from .settings import GPG_HOME, GPG_PATH, KEYSERVERS +from .settings import setting_gpg_home, setting_gpg_path, setting_keyservers -gpg = GPG(binary_path=GPG_PATH, home=GPG_HOME, keyservers=KEYSERVERS) +gpg = GPG(binary_path=setting_gpg_path.value, home=setting_gpg_home.value, keyservers=setting_keyservers.value) diff --git a/mayan/apps/django_gpg/settings.py b/mayan/apps/django_gpg/settings.py index af8c6eae6a..93efbfa4f9 100644 --- a/mayan/apps/django_gpg/settings.py +++ b/mayan/apps/django_gpg/settings.py @@ -5,14 +5,9 @@ import os from django.conf import settings from django.utils.translation import ugettext_lazy as _ -from smart_settings.api import register_settings +from smart_settings import Namespace -register_settings( - namespace='django_gpg', - module='django_gpg.settings', - settings=[ - {'name': 'KEYSERVERS', 'global_name': 'SIGNATURES_KEYSERVERS', 'default': ['pool.sks-keyservers.net'], 'description': _('List of keyservers to be queried for unknown keys.')}, - {'name': 'GPG_HOME', 'global_name': 'SIGNATURES_GPG_HOME', 'default': os.path.join(settings.MEDIA_ROOT, 'gpg_home'), 'description': _('Home directory used to store keys as well as configuration files.')}, - {'name': 'GPG_PATH', 'global_name': 'SIGNATURES_GPG_PATH', 'default': '/usr/bin/gpg', 'exists': True, 'description': _('Path to the GPG binary.')}, - ] -) +namespace = Namespace(name='django_gpg', label=_('Signatures')) +setting_keyservers = namespace.add_setting(global_name='SIGNATURES_KEYSERVERS', default=['pool.sks-keyservers.net'], help_text=_('List of keyservers to be queried for unknown keys.')) +setting_gpg_home = namespace.add_setting(global_name='SIGNATURES_GPG_HOME', default=os.path.join(settings.MEDIA_ROOT, 'gpg_home'), help_text=_('Home directory used to store keys as well as configuration files.'), is_path=True) +setting_gpg_path = namespace.add_setting(global_name='SIGNATURES_GPG_PATH', default='/usr/bin/gpg', help_text=_('Path to the GPG binary.'), is_path=True) diff --git a/mayan/apps/documents/api_views.py b/mayan/apps/documents/api_views.py index d05cdbb1c2..042cd08b1d 100644 --- a/mayan/apps/documents/api_views.py +++ b/mayan/apps/documents/api_views.py @@ -35,7 +35,9 @@ from .serializers import ( DocumentTypeSerializer, DocumentVersionSerializer, NewDocumentSerializer, RecentDocumentSerializer ) -from .settings import DISPLAY_SIZE, ZOOM_MAX_LEVEL, ZOOM_MIN_LEVEL +from .settings import ( + setting_display_size, setting_zoom_max_level, setting_zoom_min_level +) from .tasks import task_get_document_page_image, task_new_document @@ -186,7 +188,7 @@ class APIDocumentImageView(generics.GenericAPIView): except PermissionDenied: AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VIEW, request.user, document) - size = request.GET.get('size', DISPLAY_SIZE) + size = request.GET.get('size', setting_display_size.value) page = int(request.GET.get('page', DEFAULT_PAGE_NUMBER)) @@ -194,11 +196,11 @@ class APIDocumentImageView(generics.GenericAPIView): version = int(request.GET.get('version', document.latest_version.pk)) - if zoom < ZOOM_MIN_LEVEL: - zoom = ZOOM_MIN_LEVEL + if zoom < setting_zoom_min_level.value: + zoom = setting_zoom_min_level.value - if zoom > ZOOM_MAX_LEVEL: - zoom = ZOOM_MAX_LEVEL + if zoom > setting_zoom_max_level.value: + zoom = setting_zoom_max_level.value rotation = int(request.GET.get('rotation', DEFAULT_ROTATION)) % 360 diff --git a/mayan/apps/documents/apps.py b/mayan/apps/documents/apps.py index c393d2739f..ffba982bf3 100644 --- a/mayan/apps/documents/apps.py +++ b/mayan/apps/documents/apps.py @@ -64,7 +64,7 @@ from .permissions import ( PERMISSION_DOCUMENT_PRINT, PERMISSION_DOCUMENT_PROPERTIES_EDIT, PERMISSION_DOCUMENT_VERSION_REVERT, PERMISSION_DOCUMENT_VIEW ) -from .settings import THUMBNAIL_SIZE +from .settings import setting_thumbnail_size from .statistics import DocumentStatistics, DocumentUsageStatistics from .widgets import document_thumbnail @@ -76,8 +76,9 @@ class DocumentsApp(MayanAppConfig): def ready(self): super(DocumentsApp, self).ready() - if (not validate_path(document_settings.CACHE_PATH)) or (not document_settings.CACHE_PATH): - setattr(document_settings, 'CACHE_PATH', tempfile.mkdtemp()) + # TODO: validate cache_path or create new + #if (not validate_path(document_settings.CACHE_PATH)) or (not document_settings.CACHE_PATH): + # setattr(document_settings, 'CACHE_PATH', tempfile.mkdtemp()) APIEndPoint('documents') @@ -155,7 +156,7 @@ class DocumentsApp(MayanAppConfig): register_model_list_columns(Document, [ { 'name': _('Thumbnail'), 'attribute': - encapsulate(lambda x: document_thumbnail(x, gallery_name='documents:document_list', title=getattr(x, 'label', None), size=THUMBNAIL_SIZE)) + encapsulate(lambda x: document_thumbnail(x, gallery_name='documents:document_list', title=getattr(x, 'label', None), size=setting_thumbnail_size.value)) }, { 'name': _('Type'), 'attribute': 'document_type' diff --git a/mayan/apps/documents/links.py b/mayan/apps/documents/links.py index 8729039a47..de1a529cb1 100644 --- a/mayan/apps/documents/links.py +++ b/mayan/apps/documents/links.py @@ -17,7 +17,7 @@ from .permissions import ( PERMISSION_DOCUMENT_TYPE_CREATE, PERMISSION_DOCUMENT_TYPE_DELETE, PERMISSION_DOCUMENT_TYPE_EDIT, PERMISSION_DOCUMENT_TYPE_VIEW ) -from .settings import ZOOM_MAX_LEVEL, ZOOM_MIN_LEVEL +from .settings import setting_zoom_max_level, setting_zoom_min_level def is_not_current_version(context): @@ -33,11 +33,11 @@ def is_last_page(context): def is_max_zoom(context): - return context['zoom'] >= ZOOM_MAX_LEVEL + return context['zoom'] >= setting_zoom_max_level.value def is_min_zoom(context): - return context['zoom'] <= ZOOM_MIN_LEVEL + return context['zoom'] <= setting_zoom_min_level.value # Facet diff --git a/mayan/apps/documents/managers.py b/mayan/apps/documents/managers.py index 01ba4321bd..5bdb31e896 100644 --- a/mayan/apps/documents/managers.py +++ b/mayan/apps/documents/managers.py @@ -6,7 +6,7 @@ from django.db import models, transaction from common.compressed_files import CompressedFile, NotACompressedFile -from .settings import RECENT_COUNT, LANGUAGE +from .settings import setting_recent_count, setting_language logger = logging.getLogger(__name__) @@ -19,7 +19,7 @@ class RecentDocumentManager(models.Manager): # document already in the recent list, just save to force # accessed date and time update new_recent.save() - for recent_to_delete in self.model.objects.filter(user=user)[RECENT_COUNT:]: + for recent_to_delete in self.model.objects.filter(user=user)[setting_recent_count.value:]: recent_to_delete.delete() def get_for_user(self, user): @@ -52,7 +52,7 @@ class DocumentManager(models.Manager): for compressed_file_child in compressed_file.children(): if command_line: print 'Uploading file #%d: %s' % (count, compressed_file_child) - versions_created.append(self.upload_single_document(document_type=document_type, file_object=compressed_file_child, description=description, label=unicode(compressed_file_child), language=language or LANGUAGE, user=user)) + versions_created.append(self.upload_single_document(document_type=document_type, file_object=compressed_file_child, description=description, label=unicode(compressed_file_child), language=language or setting_language.value, user=user)) compressed_file_child.close() count += 1 @@ -60,9 +60,9 @@ class DocumentManager(models.Manager): logging.debug('Exception: NotACompressedFile') if command_line: raise - versions_created.append(self.upload_single_document(document_type=document_type, file_object=file_object, description=description, label=label, language=language or LANGUAGE, user=user)) + versions_created.append(self.upload_single_document(document_type=document_type, file_object=file_object, description=description, label=label, language=language or setting_language.value, user=user)) else: - versions_created.append(self.upload_single_document(document_type=document_type, file_object=file_object, description=description, label=label, language=language or LANGUAGE, user=user)) + versions_created.append(self.upload_single_document(document_type=document_type, file_object=file_object, description=description, label=label, language=language or setting_language.value, user=user)) return versions_created diff --git a/mayan/apps/documents/models.py b/mayan/apps/documents/models.py index 4042d7b158..4246e3e284 100644 --- a/mayan/apps/documents/models.py +++ b/mayan/apps/documents/models.py @@ -16,7 +16,7 @@ from django.utils.encoding import python_2_unicode_compatible from django.utils.translation import ugettext_lazy as _ from acls.utils import apply_default_acls -from common.settings import TEMPORARY_DIRECTORY +from common.settings import setting_temporary_directory from common.utils import fs_cleanup from converter import ( converter_class, TransformationResize, TransformationRotate, TransformationZoom @@ -37,8 +37,8 @@ from .managers import ( ) from .runtime import storage_backend from .settings import ( - CACHE_PATH, DISPLAY_SIZE, LANGUAGE, LANGUAGE_CHOICES, ZOOM_MAX_LEVEL, - ZOOM_MIN_LEVEL + setting_cache_path, setting_display_size, setting_language, + setting_language_choices, setting_zoom_max_level, setting_zoom_min_level ) from .signals import post_version_upload, post_document_type_change @@ -86,7 +86,7 @@ class Document(models.Model): label = models.CharField(max_length=255, default=_('Uninitialized document'), db_index=True, help_text=_('The name of the document'), verbose_name=_('Label')) description = models.TextField(blank=True, null=True, verbose_name=_('Description')) date_added = models.DateTimeField(verbose_name=_('Added'), auto_now_add=True) - language = models.CharField(choices=LANGUAGE_CHOICES, default=LANGUAGE, max_length=8, verbose_name=_('Language')) + language = models.CharField(choices=setting_language_choices.value, default=setting_language.value, max_length=8, verbose_name=_('Language')) objects = DocumentManager() @@ -215,7 +215,7 @@ class Document(models.Model): return self.versions.order_by('timestamp').last() def document_save_to_temp_dir(self, filename, buffer_size=1024 * 1024): - temporary_path = os.path.join(TEMPORARY_DIRECTORY, filename) + temporary_path = os.path.join(setting_temporary_directory.value, filename) return self.save_to_file(temporary_path, buffer_size) @@ -466,20 +466,20 @@ class DocumentPage(models.Model): return 'page-cache-{}-{}-{}'.format(self.document.uuid, self.document_version.pk, self.pk) def get_cache_filename(self): - return os.path.join(CACHE_PATH, self.get_uuid()) + return os.path.join(setting_cache_path.value, self.get_uuid()) def get_image(self, *args, **kwargs): as_base64 = kwargs.pop('as_base64', False) transformations = kwargs.pop('transformations', []) - size = kwargs.pop('size', DISPLAY_SIZE) + size = kwargs.pop('size', setting_display_size.value) rotation = kwargs.pop('rotation', DEFAULT_ROTATION) zoom_level = kwargs.pop('zoom', DEFAULT_ZOOM_LEVEL) - if zoom_level < ZOOM_MIN_LEVEL: - zoom_level = ZOOM_MIN_LEVEL + if zoom_level < setting_zoom_min_level.value: + zoom_level = setting_zoom_min_level.value - if zoom_level > ZOOM_MAX_LEVEL: - zoom_level = ZOOM_MAX_LEVEL + if zoom_level > setting_zoom_max_level.value: + zoom_level = setting_zoom_max_level.value rotation = rotation % 360 diff --git a/mayan/apps/documents/runtime.py b/mayan/apps/documents/runtime.py index 00e8f422de..7d5bdfc4ca 100644 --- a/mayan/apps/documents/runtime.py +++ b/mayan/apps/documents/runtime.py @@ -1,5 +1,5 @@ from django.utils.module_loading import import_string -from .settings import STORAGE_BACKEND +from .settings import setting_storage_backend -storage_backend = import_string(STORAGE_BACKEND)() +storage_backend = import_string(setting_storage_backend.value)() diff --git a/mayan/apps/documents/settings.py b/mayan/apps/documents/settings.py index 9fb43ec1c3..c08242e287 100644 --- a/mayan/apps/documents/settings.py +++ b/mayan/apps/documents/settings.py @@ -6,30 +6,24 @@ import pycountry from django.conf import settings from django.utils.translation import ugettext_lazy as _ -from smart_settings.api import register_settings +from smart_settings import Namespace -LANGUAGE_CHOICES = [(i.bibliographic, _(i.name)) for i in list(pycountry.languages)] +# TODO: Findout method to make languages names' translatable. +# YAML fails to serialize ugettext_lazy and ugettext is not allowed at this level +LANGUAGE_CHOICES = [(i.bibliographic, i.name) for i in list(pycountry.languages)] -register_settings( - namespace='documents', - module='documents.settings', - settings=[ - # Storage - {'name': 'STORAGE_BACKEND', 'global_name': 'DOCUMENTS_STORAGE_BACKEND', 'default': 'storage.backends.filebasedstorage.FileBasedStorage'}, - # Usage - {'name': 'PREVIEW_SIZE', 'global_name': 'DOCUMENTS_PREVIEW_SIZE', 'default': '640x480'}, - {'name': 'PRINT_SIZE', 'global_name': 'DOCUMENTS_PRINT_SIZE', 'default': '3600'}, - {'name': 'MULTIPAGE_PREVIEW_SIZE', 'global_name': 'DOCUMENTS_MULTIPAGE_PREVIEW_SIZE', 'default': '160x120'}, - {'name': 'THUMBNAIL_SIZE', 'global_name': 'DOCUMENTS_THUMBNAIL_SIZE', 'default': '50x50'}, - {'name': 'DISPLAY_SIZE', 'global_name': 'DOCUMENTS_DISPLAY_SIZE', 'default': '3600'}, - {'name': 'RECENT_COUNT', 'global_name': 'DOCUMENTS_RECENT_COUNT', 'default': 40, 'description': _('Maximum number of recent (created, edited, viewed) documents to remember per user.')}, - {'name': 'ZOOM_PERCENT_STEP', 'global_name': 'DOCUMENTS_ZOOM_PERCENT_STEP', 'default': 25, 'description': _('Amount in percent zoom in or out a document page per user interaction.')}, - {'name': 'ZOOM_MAX_LEVEL', 'global_name': 'DOCUMENTS_ZOOM_MAX_LEVEL', 'default': 300, 'description': _('Maximum amount in percent (%) to allow user to zoom in a document page interactively.')}, - {'name': 'ZOOM_MIN_LEVEL', 'global_name': 'DOCUMENTS_ZOOM_MIN_LEVEL', 'default': 25, 'description': _('Minimum amount in percent (%) to allow user to zoom out a document page interactively.')}, - {'name': 'ROTATION_STEP', 'global_name': 'DOCUMENTS_ROTATION_STEP', 'default': 90, 'description': _('Amount in degrees to rotate a document page per user interaction.')}, - # - {'name': 'CACHE_PATH', 'global_name': 'DOCUMENTS_CACHE_PATH', 'default': os.path.join(settings.MEDIA_ROOT, 'image_cache'), 'exists': True}, - {'name': 'LANGUAGE', 'global_name': 'DOCUMENTS_LANGUAGE', 'default': 'eng', 'description': _('Default documents language (in ISO639-2 format).')}, - {'name': 'LANGUAGE_CHOICES', 'global_name': 'DOCUMENTS_LANGUAGE_CHOICES', 'default': LANGUAGE_CHOICES, 'description': _('List of supported document languages.')}, - ] -) +namespace = Namespace(name='documents', label=_('Documents')) +setting_storage_backend = namespace.add_setting(global_name='DOCUMENTS_STORAGE_BACKEND', default='storage.backends.filebasedstorage.FileBasedStorage') +setting_preview_size = namespace.add_setting(global_name='DOCUMENTS_PREVIEW_SIZE', default='640x480') +setting_print_size = namespace.add_setting(global_name='DOCUMENTS_PRINT_SIZE', default='3600') +setting_multipage_preview_size = namespace.add_setting(global_name='DOCUMENTS_MULTIPAGE_PREVIEW_SIZE', default='160x120') +setting_thumbnail_size = namespace.add_setting(global_name='DOCUMENTS_THUMBNAIL_SIZE', default='50x50') +setting_display_size = namespace.add_setting(global_name='DOCUMENTS_DISPLAY_SIZE', default='3600') +setting_recent_count = namespace.add_setting(global_name='DOCUMENTS_RECENT_COUNT', default=40, help_text=_('Maximum number of recent (created, edited, viewed) documents to remember per user.')) +setting_zoom_percent_step = namespace.add_setting(global_name='DOCUMENTS_ZOOM_PERCENT_STEP', default=25, help_text=_('Amount in percent zoom in or out a document page per user interaction.')) +setting_zoom_max_level = namespace.add_setting(global_name='DOCUMENTS_ZOOM_MAX_LEVEL', default=300, help_text=_('Maximum amount in percent (%) to allow user to zoom in a document page interactively.')) +setting_zoom_min_level = namespace.add_setting(global_name='DOCUMENTS_ZOOM_MIN_LEVEL', default=25, help_text=_('Minimum amount in percent (%) to allow user to zoom out a document page interactively.')) +setting_rotation_step = namespace.add_setting(global_name='DOCUMENTS_ROTATION_STEP', default=90, help_text=_('Amount in degrees to rotate a document page per user interaction.')) +setting_cache_path = namespace.add_setting(global_name='DOCUMENTS_CACHE_PATH', default=os.path.join(settings.MEDIA_ROOT, 'image_cache'), is_path=True) +setting_language = namespace.add_setting(global_name='DOCUMENTS_LANGUAGE', default='eng', help_text=_('Default documents language (in ISO639-2 format).')) +setting_language_choices = namespace.add_setting(global_name='DOCUMENTS_LANGUAGE_CHOICES', default=LANGUAGE_CHOICES, help_text=_('List of supported document languages.')) diff --git a/mayan/apps/documents/urls.py b/mayan/apps/documents/urls.py index f91b787f92..132b1eb1c1 100644 --- a/mayan/apps/documents/urls.py +++ b/mayan/apps/documents/urls.py @@ -9,7 +9,7 @@ from .api_views import ( APIDocumentVersionCreateView, APIDocumentVersionView, APIRecentDocumentListView ) -from .settings import PRINT_SIZE, DISPLAY_SIZE +from .settings import setting_print_size, setting_display_size from .views import ( DocumentListView, DocumentPageListView, RecentDocumentListView ) @@ -32,8 +32,8 @@ urlpatterns = patterns( url(r'^(?P\d+)/acls/$', 'document_acl_list', name='document_acl_list'), - url(r'^(?P\d+)/display/$', 'get_document_image', {'size': DISPLAY_SIZE}, 'document_display'), - url(r'^(?P\d+)/display/print/$', 'get_document_image', {'size': PRINT_SIZE}, 'document_display_print'), + url(r'^(?P\d+)/display/$', 'get_document_image', {'size': setting_display_size.value}, 'document_display'), + url(r'^(?P\d+)/display/print/$', 'get_document_image', {'size': setting_print_size.value}, 'document_display_print'), url(r'^(?P\d+)/download/$', 'document_download', name='document_download'), url(r'^multiple/download/$', 'document_multiple_download', name='document_multiple_download'), diff --git a/mayan/apps/documents/views.py b/mayan/apps/documents/views.py index afdf529ee8..9b7998d439 100644 --- a/mayan/apps/documents/views.py +++ b/mayan/apps/documents/views.py @@ -51,8 +51,8 @@ from .permissions import ( PERMISSION_DOCUMENT_VERSION_REVERT, PERMISSION_DOCUMENT_VIEW, ) from .settings import ( - PREVIEW_SIZE, RECENT_COUNT, ROTATION_STEP, ZOOM_PERCENT_STEP, - ZOOM_MAX_LEVEL, ZOOM_MIN_LEVEL + setting_preview_size, setting_recent_count, setting_rotation_step, + setting_zoom_percent_step, setting_zoom_max_level, setting_zoom_min_level ) from .tasks import ( task_clear_image_cache, task_get_document_page_image, @@ -94,7 +94,7 @@ class DocumentPageListView(ParentChildListView): class RecentDocumentListView(DocumentListView): extra_context = { 'hide_links': True, - 'recent_count': RECENT_COUNT, + 'recent_count': setting_recent_count.value, # TODO: used for something? 'title': _('Recent documents'), } @@ -338,7 +338,7 @@ def document_multiple_document_type_edit(request): # TODO: Get rid of this view and convert widget to use API and base64 only images -def get_document_image(request, document_id, size=PREVIEW_SIZE): +def get_document_image(request, document_id, size=setting_preview_size.value): document = get_object_or_404(Document, pk=document_id) try: Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) @@ -351,11 +351,11 @@ def get_document_image(request, document_id, size=PREVIEW_SIZE): version = int(request.GET.get('version', document.latest_version.pk)) - if zoom < ZOOM_MIN_LEVEL: - zoom = ZOOM_MIN_LEVEL + if zoom < setting_zoom_min_level.value: + zoom = setting_zoom_min_level.value - if zoom > ZOOM_MAX_LEVEL: - zoom = ZOOM_MAX_LEVEL + if zoom > setting_zoom_max_level.value: + zoom = setting_zoom_max_level.value rotation = int(request.GET.get('rotation', DEFAULT_ROTATION)) % 360 @@ -713,7 +713,7 @@ def document_page_zoom_in(request, document_page_id): return transform_page( request, document_page_id, - zoom_function=lambda x: ZOOM_MAX_LEVEL if x + ZOOM_PERCENT_STEP > ZOOM_MAX_LEVEL else x + ZOOM_PERCENT_STEP + zoom_function=lambda x: setting_zoom_max_level.value if x + setting_zoom_percent_step.value > setting_zoom_max_level.value else x + setting_zoom_percent_step.value ) @@ -721,7 +721,7 @@ def document_page_zoom_out(request, document_page_id): return transform_page( request, document_page_id, - zoom_function=lambda x: ZOOM_MIN_LEVEL if x - ZOOM_PERCENT_STEP < ZOOM_MIN_LEVEL else x - ZOOM_PERCENT_STEP + zoom_function=lambda x: setting_zoom_min_level.value if x - setting_zoom_percent_step.value < setting_zoom_min_level.value else x - setting_zoom_percent_step.value ) @@ -729,7 +729,7 @@ def document_page_rotate_right(request, document_page_id): return transform_page( request, document_page_id, - rotation_function=lambda x: (x + ROTATION_STEP) % 360 + rotation_function=lambda x: (x + setting_rotation_step.value) % 360 ) @@ -737,7 +737,7 @@ def document_page_rotate_left(request, document_page_id): return transform_page( request, document_page_id, - rotation_function=lambda x: (x - ROTATION_STEP) % 360 + rotation_function=lambda x: (x - setting_rotation_step.value) % 360 ) diff --git a/mayan/apps/documents/widgets.py b/mayan/apps/documents/widgets.py index 24053b3cb1..b022a773ca 100644 --- a/mayan/apps/documents/widgets.py +++ b/mayan/apps/documents/widgets.py @@ -13,7 +13,7 @@ from converter.literals import ( DEFAULT_PAGE_NUMBER, DEFAULT_ROTATION, DEFAULT_ZOOM_LEVEL ) -from .settings import DISPLAY_SIZE, THUMBNAIL_SIZE +from .settings import setting_display_size, setting_thumbnail_size class DocumentPageImageWidget(forms.widgets.Widget): @@ -24,7 +24,7 @@ class DocumentPageImageWidget(forms.widgets.Widget): if value: output = [] output.append('
') - output.append(document_html_widget(value, zoom=zoom, rotation=rotation, image_class='lazy-load', nolazyload=False, size=DISPLAY_SIZE)) + output.append(document_html_widget(value, zoom=zoom, rotation=rotation, image_class='lazy-load', nolazyload=False, size=setting_display_size.value)) output.append('
') return mark_safe(''.join(output)) else: @@ -55,7 +55,7 @@ class DocumentPagesCarouselWidget(forms.widgets.Widget): click_view_arguments=[page.pk], fancybox_class='', image_class='lazy-load-carousel', - size=DISPLAY_SIZE, + size=setting_display_size.value, post_load_class='lazy-load-carousel-loaded', ) ) @@ -75,7 +75,7 @@ def document_link(document): return mark_safe('%s' % (document.get_absolute_url(), document)) -def document_html_widget(document_page, click_view=None, click_view_arguments=None, zoom=DEFAULT_ZOOM_LEVEL, rotation=DEFAULT_ROTATION, gallery_name=None, fancybox_class='fancybox', image_class='lazy-load', title=None, size=THUMBNAIL_SIZE, nolazyload=False, post_load_class=None): +def document_html_widget(document_page, click_view=None, click_view_arguments=None, zoom=DEFAULT_ZOOM_LEVEL, rotation=DEFAULT_ROTATION, gallery_name=None, fancybox_class='fancybox', image_class='lazy-load', title=None, size=setting_thumbnail_size.value, nolazyload=False, post_load_class=None): result = [] alt_text = _('Document page image') diff --git a/mayan/apps/dynamic_search/api.py b/mayan/apps/dynamic_search/api.py index 5af0530142..ddb2203e17 100644 --- a/mayan/apps/dynamic_search/api.py +++ b/mayan/apps/dynamic_search/api.py @@ -120,7 +120,7 @@ def perform_search(query_string, field_list=None): model_result_ids = [] result_count += len(model_result_ids) - results = model.objects.in_bulk(list(model_result_ids)[: LIMIT]).values() + results = model.objects.in_bulk(list(model_result_ids)[: LIMIT.value]).values() shown_result_count += len(results) if results: model_list[title] = results diff --git a/mayan/apps/dynamic_search/classes.py b/mayan/apps/dynamic_search/classes.py index 6735f66359..8ada5b90d7 100644 --- a/mayan/apps/dynamic_search/classes.py +++ b/mayan/apps/dynamic_search/classes.py @@ -163,7 +163,7 @@ class SearchModel(object): elapsed_time = unicode(datetime.datetime.now() - start_time).split(':')[2] - queryset = self.model.objects.in_bulk(list(result_set)[: LIMIT]).values() + queryset = self.model.objects.in_bulk(list(result_set)[: LIMIT.value]).values() if self.permission: try: diff --git a/mayan/apps/dynamic_search/managers.py b/mayan/apps/dynamic_search/managers.py index 6df88790fa..32f09570f5 100644 --- a/mayan/apps/dynamic_search/managers.py +++ b/mayan/apps/dynamic_search/managers.py @@ -31,5 +31,5 @@ class RecentSearchManager(models.Manager): new_recent.hits = hits new_recent.save() - for recent_to_delete in self.model.objects.filter(user=user)[RECENT_COUNT:]: + for recent_to_delete in self.model.objects.filter(user=user)[RECENT_COUNT.value:]: recent_to_delete.delete() diff --git a/mayan/apps/dynamic_search/settings.py b/mayan/apps/dynamic_search/settings.py index 1db80e0705..81c75f409c 100644 --- a/mayan/apps/dynamic_search/settings.py +++ b/mayan/apps/dynamic_search/settings.py @@ -2,14 +2,10 @@ from __future__ import unicode_literals from django.utils.translation import ugettext_lazy as _ -from smart_settings.api import register_settings +from smart_settings import Namespace -register_settings( - namespace='dynamic_search', - module='dynamic_search.settings', - settings=[ - {'name': 'SHOW_OBJECT_TYPE', 'global_name': 'SEARCH_SHOW_OBJECT_TYPE', 'default': True}, - {'name': 'LIMIT', 'global_name': 'SEARCH_LIMIT', 'default': 100, 'description': _('Maximum amount search hits to fetch and display.')}, - {'name': 'RECENT_COUNT', 'global_name': 'SEARCH_RECENT_COUNT', 'default': 5, 'description': _('Maximum number of search queries to remember per user.')}, - ] -) + +namespace = Namespace(name='dynamic_search', label=_('Search')) +SHOW_OBJECT_TYPE = namespace.add_setting(global_name='SEARCH_SHOW_OBJECT_TYPE', default=True) +LIMIT = namespace.add_setting(global_name='SEARCH_LIMIT', default=100, help_text=_('Maximum amount search hits to fetch and display.')) +RECENT_COUNT = namespace.add_setting(global_name='SEARCH_RECENT_COUNT', default=5, help_text=_('Maximum number of search queries to remember per user.')) diff --git a/mayan/apps/dynamic_search/views.py b/mayan/apps/dynamic_search/views.py index 1e3b794a7b..1273ef790d 100644 --- a/mayan/apps/dynamic_search/views.py +++ b/mayan/apps/dynamic_search/views.py @@ -23,7 +23,7 @@ def results(request, extra_context=None): context = { 'query_string': request.GET, 'hide_links': True, - 'search_results_limit': LIMIT, + 'search_results_limit': LIMIT.value, } if request.GET: @@ -42,7 +42,7 @@ def results(request, extra_context=None): if extra_context: context.update(extra_context) - if SHOW_OBJECT_TYPE: + if SHOW_OBJECT_TYPE.value: context.update({ 'extra_columns': [{'name': _('Type'), 'attribute': lambda x: x._meta.verbose_name[0].upper() + x._meta.verbose_name[1:]}] }) @@ -63,7 +63,7 @@ def search(request, advanced=False): 'title': _('Advanced search'), 'form_action': reverse('search:results'), 'submit_method': 'GET', - 'search_results_limit': LIMIT, + 'search_results_limit': LIMIT.value, 'submit_label': _('Search'), 'submit_icon': 'fa fa-search', }, context_instance=RequestContext(request) diff --git a/mayan/apps/metadata/forms.py b/mayan/apps/metadata/forms.py index c835fabc0c..09f51f5db1 100644 --- a/mayan/apps/metadata/forms.py +++ b/mayan/apps/metadata/forms.py @@ -6,7 +6,7 @@ from django.forms.formsets import formset_factory from django.utils.translation import ugettext_lazy as _ from .models import MetadataType -from .settings import AVAILABLE_FUNCTIONS, AVAILABLE_MODELS, AVAILABLE_VALIDATORS +from .settings import AVAILABLE_FUNCTIONS, AVAILABLE_MODELS, setting_available_validators class MetadataForm(forms.Form): @@ -15,7 +15,7 @@ class MetadataForm(forms.Form): metadata_type = MetadataType.objects.get(pk=self.cleaned_data['id']) try: - validation_function = AVAILABLE_VALIDATORS[metadata_type.validation] + validation_function = setting_available_validators.value[metadata_type.validation] except KeyError: # User entered a validation function name, but was not found # Return value entered as is diff --git a/mayan/apps/metadata/models.py b/mayan/apps/metadata/models.py index 0fa2340b6f..17ef079012 100644 --- a/mayan/apps/metadata/models.py +++ b/mayan/apps/metadata/models.py @@ -8,7 +8,7 @@ from django.utils.translation import ugettext_lazy as _ from documents.models import Document, DocumentType from .managers import MetadataTypeManager -from .settings import AVAILABLE_VALIDATORS +from .settings import setting_available_validators @python_2_unicode_compatible @@ -27,7 +27,7 @@ class MetadataType(models.Model): lookup = models.TextField(blank=True, null=True, verbose_name=_('Lookup'), help_text=_('Enter a string to be evaluated that returns an iterable.')) - validation = models.CharField(blank=True, choices=zip(AVAILABLE_VALIDATORS, AVAILABLE_VALIDATORS), max_length=64, verbose_name=_('Validation function name')) + validation = models.CharField(blank=True, choices=zip(setting_available_validators.value, setting_available_validators.value), max_length=64, verbose_name=_('Validation function name')) # TODO: Find a different way to let users know what models and functions are # available now that we removed these from the help_text objects = MetadataTypeManager() diff --git a/mayan/apps/metadata/parsers.py b/mayan/apps/metadata/parsers.py new file mode 100644 index 0000000000..6f5672ca4e --- /dev/null +++ b/mayan/apps/metadata/parsers.py @@ -0,0 +1,48 @@ +from __future__ import unicode_literals + +from dateutil.parser import parse + +from django.utils.translation import ugettext_lazy as _ + + +class MetadataParser(object): + _registry = [] + + @classmethod + def register(cls, parser): + cls._registry.append(parser) + + @classmethod + def get_all(cls): + return cls._registry + + @classmethod + def get_import_path(cls): + return cls.__module__ + '.' + cls.__name__ + + @classmethod + def get_import_paths(cls): + return [parser.get_import_path() for parser in cls.get_all()] + + def parse(self, input_data): + raise NotImplementedError + + +class DateAndTimeParser(MetadataParser): + def parse(self, input_data): + return parse(input_data).isoformat() + + +class DateParser(MetadataParser): + def parse(self, input_data): + return parse(input_data).date().isoformat() + + +class TimeParser(MetadataParser): + def parse(self, input_data): + return parse(input_data).time().isoformat() + + +MetadataParser.register(DateAndTimeParser) +MetadataParser.register(DateParser) +MetadataParser.register(TimeParser) diff --git a/mayan/apps/metadata/settings.py b/mayan/apps/metadata/settings.py index a06bc26eea..135542731a 100644 --- a/mayan/apps/metadata/settings.py +++ b/mayan/apps/metadata/settings.py @@ -1,12 +1,16 @@ from __future__ import unicode_literals -from dateutil.parser import parse +import yaml from django.contrib.auth.models import User from django.utils.timezone import now +from django.utils.translation import ugettext_lazy as _ +from smart_settings import Namespace from smart_settings.api import register_settings +from .parsers import MetadataParser + default_available_functions = { 'current_date': now().date, } @@ -15,12 +19,6 @@ default_available_models = { 'User': User } -default_available_validators = { - 'Parse date and time': lambda input: parse(input).isoformat(), - 'Parse date': lambda input: parse(input).date().isoformat(), - 'Parse time': lambda input: parse(input).time().isoformat() -} - register_settings( namespace='metadata', module='metadata.settings', @@ -28,8 +26,10 @@ register_settings( # Definition {'name': 'AVAILABLE_FUNCTIONS', 'global_name': 'METADATA_AVAILABLE_FUNCTIONS', 'default': default_available_functions}, {'name': 'AVAILABLE_MODELS', 'global_name': 'METADATA_AVAILABLE_MODELS', 'default': default_available_models}, - {'name': 'AVAILABLE_VALIDATORS', 'global_name': 'METADATA_AVAILABLE_VALIDATORS', 'default': default_available_validators}, ] ) # TODO: remove classes, import by string, all settings must be simple serializable types + +namespace = Namespace(name='metadata', label=_('Metadata')) +setting_available_validators = namespace.add_setting(global_name='METADATA_AVAILABLE_VALIDATORS', default=MetadataParser.get_import_paths()) diff --git a/mayan/apps/ocr/api.py b/mayan/apps/ocr/api.py index 6447643ae9..9a1339f938 100644 --- a/mayan/apps/ocr/api.py +++ b/mayan/apps/ocr/api.py @@ -9,7 +9,7 @@ import sh from django.utils.module_loading import import_string from django.utils.translation import ugettext_lazy as _ -from common.settings import TEMPORARY_DIRECTORY +from common.settings import setting_temporary_directory from common.utils import fs_cleanup from converter import converter_class from documents.models import DocumentPage @@ -47,7 +47,7 @@ def execute_unpaper(input_filepath, output_filepath=None): """ if UNPAPER: if not output_filepath: - fd, output_filepath = tempfile.mkstemp(dir=TEMPORARY_DIRECTORY) + fd, output_filepath = tempfile.mkstemp(dir=setting_temporary_directory.value) try: UNPAPER(input_filepath, output_filepath) diff --git a/mayan/apps/ocr/apps.py b/mayan/apps/ocr/apps.py index 7866b15813..f4a5a0a15d 100644 --- a/mayan/apps/ocr/apps.py +++ b/mayan/apps/ocr/apps.py @@ -29,7 +29,7 @@ from .links import ( ) from .models import DocumentVersionOCRError from .permissions import PERMISSION_OCR_DOCUMENT, PERMISSION_OCR_CONTENT_VIEW -from .settings import PDFTOTEXT_PATH, TESSERACT_PATH, UNPAPER_PATH +from .settings import setting_pdftotext_path, setting_tesseract_path, setting_unpaper_path from .tasks import task_do_ocr logger = logging.getLogger(__name__) @@ -74,7 +74,7 @@ class OCRApp(MayanAppConfig): namespace = PropertyNamespace('ocr', _('OCR')) try: - pdftotext = sh.Command(PDFTOTEXT_PATH) + pdftotext = sh.Command(setting_pdftotext_path.value) except sh.CommandNotFound: namespace.add_property('pdftotext', _('pdftotext version'), _('not found'), report=True) except Exception: @@ -83,7 +83,7 @@ class OCRApp(MayanAppConfig): namespace.add_property('pdftotext', _('pdftotext version'), pdftotext('-v').stderr, report=True) try: - tesseract = sh.Command(TESSERACT_PATH) + tesseract = sh.Command(setting_tesseract_path.value) except sh.CommandNotFound: namespace.add_property('tesseract', _('tesseract version'), _('not found'), report=True) except Exception: @@ -92,7 +92,7 @@ class OCRApp(MayanAppConfig): namespace.add_property('tesseract', _('tesseract version'), tesseract('-v').stderr, report=True) try: - unpaper = sh.Command(UNPAPER_PATH) + unpaper = sh.Command(setting_unpaper_path.value) except sh.CommandNotFound: namespace.add_property('unpaper', _('unpaper version'), _('not found'), report=True) except Exception: diff --git a/mayan/apps/ocr/backends/tesseract.py b/mayan/apps/ocr/backends/tesseract.py index ba70de6a91..5e90148822 100644 --- a/mayan/apps/ocr/backends/tesseract.py +++ b/mayan/apps/ocr/backends/tesseract.py @@ -18,7 +18,7 @@ from common.utils import fs_cleanup from ..classes import OCRBackendBase from ..exceptions import OCRError -from ..settings import TESSERACT_PATH +from ..settings import setting_tesseract_path logger = logging.getLogger(__name__) diff --git a/mayan/apps/ocr/classes.py b/mayan/apps/ocr/classes.py index e8a9b0ec7d..67753b33c6 100644 --- a/mayan/apps/ocr/classes.py +++ b/mayan/apps/ocr/classes.py @@ -7,7 +7,6 @@ import tempfile from django.utils.module_loading import import_string from django.utils.translation import ugettext_lazy as _ -from common.settings import TEMPORARY_DIRECTORY from common.utils import fs_cleanup from converter import converter_class from documents.models import DocumentPage @@ -19,7 +18,6 @@ from .literals import ( from .models import DocumentPageContent from .parsers import parse_document_page from .parsers.exceptions import ParserError, ParserUnknownFile -from .settings import UNPAPER_PATH logger = logging.getLogger(__name__) diff --git a/mayan/apps/ocr/parsers/__init__.py b/mayan/apps/ocr/parsers/__init__.py index 98d9028692..149049da62 100644 --- a/mayan/apps/ocr/parsers/__init__.py +++ b/mayan/apps/ocr/parsers/__init__.py @@ -8,14 +8,14 @@ import tempfile from django.utils.translation import ugettext_lazy as _ -from common.settings import TEMPORARY_DIRECTORY +from common.settings import setting_temporary_directory from common.utils import copyfile from converter.exceptions import OfficeConversionError from converter.classes import ( CONVERTER_OFFICE_FILE_MIMETYPES ) -from ..settings import PDFTOTEXT_PATH +from ..settings import setting_pdftotext_path from .exceptions import ParserError, ParserUnknownFile @@ -128,7 +128,7 @@ class PopplerParser(Parser): PDF parser using the pdftotext execute from the poppler package """ def __init__(self): - self.pdftotext_path = PDFTOTEXT_PATH if PDFTOTEXT_PATH else '/usr/bin/pdftotext' + self.pdftotext_path = setting_pdftotext_path.value if setting_pdftotext_path.value else '/usr/bin/pdftotext' if not os.path.exists(self.pdftotext_path): raise ParserError('cannot find pdftotext executable') logger.debug('self.pdftotext_path: %s', self.pdftotext_path) @@ -138,7 +138,7 @@ class PopplerParser(Parser): pagenum = str(document_page.page_number) if descriptor: - destination_descriptor, temp_filepath = tempfile.mkstemp(dir=TEMPORARY_DIRECTORY) + destination_descriptor, temp_filepath = tempfile.mkstemp(dir=setting_temporary_directory.value) copyfile(descriptor, temp_filepath) document_file = temp_filepath else: diff --git a/mayan/apps/ocr/runtime.py b/mayan/apps/ocr/runtime.py index c8a0ac40ec..afe052ad29 100644 --- a/mayan/apps/ocr/runtime.py +++ b/mayan/apps/ocr/runtime.py @@ -1,5 +1,5 @@ from django.utils.module_loading import import_string -from .settings import BACKEND +from .settings import setting_ocr_backend -ocr_backend_class = import_string(BACKEND) +ocr_backend_class = import_string(setting_ocr_backend.value) diff --git a/mayan/apps/ocr/settings.py b/mayan/apps/ocr/settings.py index 7bde2b13bb..fb2aaeac2d 100644 --- a/mayan/apps/ocr/settings.py +++ b/mayan/apps/ocr/settings.py @@ -2,15 +2,10 @@ from __future__ import unicode_literals from django.utils.translation import ugettext_lazy as _ -from smart_settings.api import register_settings +from smart_settings import Namespace -register_settings( - namespace='ocr', - module='ocr.settings', - settings=[ - {'name': 'TESSERACT_PATH', 'global_name': 'OCR_TESSERACT_PATH', 'default': '/usr/bin/tesseract', 'exists': True}, - {'name': 'UNPAPER_PATH', 'global_name': 'OCR_UNPAPER_PATH', 'default': '/usr/bin/unpaper', 'description': _('File path to unpaper program.'), 'exists': True}, - {'name': 'PDFTOTEXT_PATH', 'global_name': 'OCR_PDFTOTEXT_PATH', 'default': '/usr/bin/pdftotext', 'description': _('File path to poppler\'s pdftotext program used to extract text from PDF files.'), 'exists': True}, - {'name': 'BACKEND', 'global_name': 'OCR_BACKEND', 'default': 'ocr.backends.tesseract.Tesseract', 'description': _('Full path to the backend to be used to do OCR.')}, - ] -) +namespace = Namespace(name='ocr', label=_('OCR')) +setting_tesseract_path = namespace.add_setting(global_name='OCR_TESSERACT_PATH', default='/usr/bin/tesseract', help_text=_('File path to tesseract program.'), is_path=True) +setting_unpaper_path = namespace.add_setting(global_name='OCR_UNPAPER_PATH', default='/usr/bin/unpaper', help_text=_('File path to unpaper program.'), is_path=True) +setting_pdftotext_path = namespace.add_setting(global_name='OCR_PDFTOTEXT_PATH', default='/usr/bin/pdftotext', help_text=_('File path to poppler\'s pdftotext program used to extract text from PDF files.'), is_path=True) +setting_ocr_backend = namespace.add_setting(global_name='OCR_BACKEND', default='ocr.backends.tesseract.Tesseract', help_text=_('Full path to the backend to be used to do OCR.')) diff --git a/mayan/apps/smart_settings/__init__.py b/mayan/apps/smart_settings/__init__.py index e69de29bb2..704c918800 100644 --- a/mayan/apps/smart_settings/__init__.py +++ b/mayan/apps/smart_settings/__init__.py @@ -0,0 +1 @@ +from .classes import Namespace, Setting # NOQA diff --git a/mayan/apps/smart_settings/apps.py b/mayan/apps/smart_settings/apps.py index ea7c0a951a..2bfa88165c 100644 --- a/mayan/apps/smart_settings/apps.py +++ b/mayan/apps/smart_settings/apps.py @@ -2,9 +2,14 @@ from __future__ import unicode_literals from django.utils.translation import ugettext_lazy as _ -from common import MayanAppConfig, menu_setup +from common import MayanAppConfig, menu_setup, menu_object +from common.utils import encapsulate +from common.widgets import exists_widget +from navigation.api import register_model_list_columns -from .links import link_check_settings +from .classes import Namespace, Setting +from .links import link_check_settings, link_namespace_detail +from .widgets import setting_widget class SmartSettingsApp(MayanAppConfig): @@ -16,4 +21,18 @@ class SmartSettingsApp(MayanAppConfig): def ready(self): super(SmartSettingsApp, self).ready() + menu_object.bind_links(links=[link_namespace_detail], sources=[Namespace]) menu_setup.bind_links(links=[link_check_settings]) + + register_model_list_columns(Setting, [ + { + 'name': _('Name'), + 'attribute': encapsulate(lambda instance: setting_widget(instance)) + }, + { + 'name': _('Value'), 'attribute': 'value' + }, + { + 'name': _('Found in path'), 'attribute': encapsulate(lambda instance: exists_widget(instance.value) if instance.is_path else _('n/a')) + }, + ]) diff --git a/mayan/apps/smart_settings/classes.py b/mayan/apps/smart_settings/classes.py new file mode 100644 index 0000000000..85a7596168 --- /dev/null +++ b/mayan/apps/smart_settings/classes.py @@ -0,0 +1,46 @@ +from __future__ import unicode_literals + +import yaml + +from django.conf import settings + +class Namespace(object): + _registry = {} + + @classmethod + def get_all(cls): + return cls._registry.values() + + @classmethod + def get(cls, name): + return cls._registry[name] + + def __unicode__(self): + return unicode(self.label) + + def __init__(self, name, label): + if name in self.__class__._registry: + raise Exception('Namespace names must be unique; "%s" already exists.' % name) + self.name = name + self.label = label + self.__class__._registry[name] = self + self.settings = [] + + def add_setting(self, **kwargs): + return Setting(namespace=self, **kwargs) + + +class Setting(object): + def __init__(self, namespace, global_name, default, help_text=None, is_path=False): + self.global_name = global_name + self.default = default + self.help_text = help_text + self.is_path = is_path + namespace.settings.append(self) + + def __unicode__(self): + return unicode(self.global_name) + + @property + def value(self): + return yaml.safe_load(getattr(settings, yaml.safe_dump(self.global_name), yaml.safe_dump(self.default))) diff --git a/mayan/apps/smart_settings/links.py b/mayan/apps/smart_settings/links.py index b918617da5..dcde36368b 100644 --- a/mayan/apps/smart_settings/links.py +++ b/mayan/apps/smart_settings/links.py @@ -10,3 +10,4 @@ def is_superuser(context): link_check_settings = Link(condition=is_superuser, icon='fa fa-sliders', text=_('Settings'), view='settings:setting_list') +link_namespace_detail = Link(condition=is_superuser, text=_('Settings'), view='settings:namespace_detail', args='resolved_object.name') diff --git a/mayan/apps/smart_settings/urls.py b/mayan/apps/smart_settings/urls.py index 6bc2835333..4159bad184 100644 --- a/mayan/apps/smart_settings/urls.py +++ b/mayan/apps/smart_settings/urls.py @@ -2,7 +2,11 @@ from __future__ import unicode_literals from django.conf.urls import patterns, url +from .views import NamespaceDetailView, NamespaceListView + urlpatterns = patterns( 'smart_settings.views', url(r'^list/$', 'setting_list', name='setting_list'), + url(r'^namespace/all/$', NamespaceListView.as_view(), name='namespace_list'), + url(r'^namespace/(?P\w+)/$', NamespaceDetailView.as_view(), name='namespace_detail'), ) diff --git a/mayan/apps/smart_settings/views.py b/mayan/apps/smart_settings/views.py index 3ecf82afe7..d58583ca6e 100644 --- a/mayan/apps/smart_settings/views.py +++ b/mayan/apps/smart_settings/views.py @@ -7,11 +7,49 @@ from django.utils.safestring import mark_safe from common.utils import encapsulate from common.widgets import exists_widget +from common.views import SimpleView from .api import settings +from .classes import Namespace from .utils import return_type # TODO: remove return_type, all settings must be simple types +class NamespaceListView(SimpleView): + template_name = 'appearance/generic_list.html' + + def get_context_data(self, **kwargs): + context = super(NamespaceListView, self).get_context_data(**kwargs) + + context.update( + { + 'hide_link': True, + 'object_list': Namespace.get_all(), + 'title': _('Setting namespaces'), + } + ) + + return context + + +class NamespaceDetailView(SimpleView): + template_name = 'appearance/generic_list.html' + + def get_context_data(self, **kwargs): + context = super(NamespaceDetailView, self).get_context_data(**kwargs) + + namespace = Namespace.get(self.kwargs['namespace_name']) + + context.update( + { + 'hide_object': True, + 'object_list': namespace.settings, + 'title': _('Settings in namespace: %s') % namespace, + } + ) + + return context + + def setting_list(request): new_settings = [] for namespace, sub_settings in settings.items(): diff --git a/mayan/apps/smart_settings/widgets.py b/mayan/apps/smart_settings/widgets.py new file mode 100644 index 0000000000..824ddb4d26 --- /dev/null +++ b/mayan/apps/smart_settings/widgets.py @@ -0,0 +1,12 @@ +from __future__ import unicode_literals + +from django.utils.safestring import mark_safe + + +def setting_widget(instance): + return mark_safe( + ''' + {} +

{}

+ '''.format(instance, instance.help_text or '') + ) diff --git a/mayan/apps/sources/api_views.py b/mayan/apps/sources/api_views.py index 512927e3ab..ab0f929ab9 100644 --- a/mayan/apps/sources/api_views.py +++ b/mayan/apps/sources/api_views.py @@ -10,9 +10,7 @@ from converter.models import Transformation from rest_framework import generics from rest_framework.response import Response -from documents.settings import ( - DISPLAY_SIZE, ZOOM_MAX_LEVEL, ZOOM_MIN_LEVEL -) +from documents.settings import setting_display_size from .models import StagingFolderSource from .serializers import ( @@ -63,7 +61,7 @@ class APIStagingSourceFileImageView(generics.GenericAPIView): staging_folder = get_object_or_404(StagingFolderSource, pk=staging_folder_pk) staging_file = staging_folder.get_file(encoded_filename=encoded_filename) - size = request.GET.get('size', DISPLAY_SIZE) + size = request.GET.get('size', setting_display_size.value) try: return Response({ diff --git a/mayan/apps/sources/widgets.py b/mayan/apps/sources/widgets.py index 2bec8360cb..f83d93ec56 100644 --- a/mayan/apps/sources/widgets.py +++ b/mayan/apps/sources/widgets.py @@ -10,14 +10,14 @@ from django.utils.translation import ugettext_lazy as _ from converter.literals import ( DEFAULT_PAGE_NUMBER, DEFAULT_ROTATION, DEFAULT_ZOOM_LEVEL ) -from documents.settings import PREVIEW_SIZE, THUMBNAIL_SIZE +from documents.settings import setting_preview_size, setting_thumbnail_size def staging_file_thumbnail(staging_file, **kwargs): return staging_file_html_widget(staging_file, click_view='stagingfolderfile-image-view', **kwargs) -def staging_file_html_widget(staging_file, click_view=None, page=DEFAULT_PAGE_NUMBER, zoom=DEFAULT_ZOOM_LEVEL, rotation=DEFAULT_ROTATION, gallery_name=None, fancybox_class='fancybox-staging', image_class='lazy-load', title=None, size=THUMBNAIL_SIZE, nolazyload=False): +def staging_file_html_widget(staging_file, click_view=None, page=DEFAULT_PAGE_NUMBER, zoom=DEFAULT_ZOOM_LEVEL, rotation=DEFAULT_ROTATION, gallery_name=None, fancybox_class='fancybox-staging', image_class='lazy-load', title=None, size=setting_thumbnail_size.value, nolazyload=False): result = [] alt_text = _('Staging file page image') @@ -50,7 +50,7 @@ def staging_file_html_widget(staging_file, click_view=None, page=DEFAULT_PAGE_NU if click_view: # TODO: fix this hack - query_dict['size'] = PREVIEW_SIZE + query_dict['size'] = setting_preview_size.value query_string = urlencode(query_dict) result.append('' % (gallery_template, fancybox_class, '%s?%s' % (reverse(click_view, args=[staging_file.staging_folder.pk, staging_file.encoded_filename]), query_string), title_template)) diff --git a/mayan/apps/storage/backends/filebasedstorage.py b/mayan/apps/storage/backends/filebasedstorage.py index 7c91396899..e446f7401b 100644 --- a/mayan/apps/storage/backends/filebasedstorage.py +++ b/mayan/apps/storage/backends/filebasedstorage.py @@ -4,7 +4,7 @@ import os from django.core.files.storage import FileSystemStorage -from ..settings import FILESTORAGE_LOCATION +from ..settings import setting_filestorage_location class FileBasedStorage(FileSystemStorage): @@ -14,4 +14,4 @@ class FileBasedStorage(FileSystemStorage): def __init__(self, *args, **kwargs): super(FileBasedStorage, self).__init__(*args, **kwargs) - self.location = FILESTORAGE_LOCATION + self.location = setting_filestorage_location.value diff --git a/mayan/apps/storage/settings.py b/mayan/apps/storage/settings.py index 769a07130f..077e84b23e 100644 --- a/mayan/apps/storage/settings.py +++ b/mayan/apps/storage/settings.py @@ -3,13 +3,9 @@ from __future__ import unicode_literals import os from django.conf import settings +from django.utils.translation import ugettext_lazy as _ -from smart_settings.api import register_settings +from smart_settings import Namespace -register_settings( - namespace='storage', - module='storage.settings', - settings=[ - {'name': 'FILESTORAGE_LOCATION', 'global_name': 'STORAGE_FILESTORAGE_LOCATION', 'default': os.path.join(settings.MEDIA_ROOT, 'document_storage'), 'exists': True}, - ] -) +namespace = Namespace(name='storage', label=_('Storage')) +setting_filestorage_location = namespace.add_setting(global_name='STORAGE_FILESTORAGE_LOCATION', default=os.path.join(settings.MEDIA_ROOT, 'document_storage'), is_path=True) diff --git a/requirements/common.txt b/requirements/common.txt index 2cdf48d1c2..50ff222445 100644 --- a/requirements/common.txt +++ b/requirements/common.txt @@ -1,6 +1,7 @@ Django==1.7.8 Pillow==2.8.2 +PyYAML==3.11 celery==3.1.18 cssmin==0.2.0