Smart settings refactor
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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\
|
||||
|
||||
@@ -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'))
|
||||
|
||||
@@ -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/')
|
||||
|
||||
|
||||
@@ -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'),
|
||||
|
||||
@@ -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():
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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)()
|
||||
|
||||
@@ -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.'))
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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'
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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': ''},
|
||||
# ]
|
||||
#)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)()
|
||||
|
||||
@@ -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.'))
|
||||
|
||||
@@ -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<document_id>\d+)/acls/$', 'document_acl_list', name='document_acl_list'),
|
||||
|
||||
url(r'^(?P<document_id>\d+)/display/$', 'get_document_image', {'size': DISPLAY_SIZE}, 'document_display'),
|
||||
url(r'^(?P<document_id>\d+)/display/print/$', 'get_document_image', {'size': PRINT_SIZE}, 'document_display_print'),
|
||||
url(r'^(?P<document_id>\d+)/display/$', 'get_document_image', {'size': setting_display_size.value}, 'document_display'),
|
||||
url(r'^(?P<document_id>\d+)/display/print/$', 'get_document_image', {'size': setting_print_size.value}, 'document_display_print'),
|
||||
|
||||
url(r'^(?P<document_id>\d+)/download/$', 'document_download', name='document_download'),
|
||||
url(r'^multiple/download/$', 'document_multiple_download', name='document_multiple_download'),
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -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('<div class="full-height scrollable mayan-page-wrapper-interactive" data-height-difference=230>')
|
||||
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('</div>')
|
||||
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('<a href="%s">%s</a>' % (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')
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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.'))
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
48
mayan/apps/metadata/parsers.py
Normal file
48
mayan/apps/metadata/parsers.py
Normal file
@@ -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)
|
||||
@@ -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())
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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__)
|
||||
|
||||
|
||||
@@ -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__)
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.'))
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
from .classes import Namespace, Setting # NOQA
|
||||
|
||||
@@ -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'))
|
||||
},
|
||||
])
|
||||
|
||||
46
mayan/apps/smart_settings/classes.py
Normal file
46
mayan/apps/smart_settings/classes.py
Normal file
@@ -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)))
|
||||
@@ -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')
|
||||
|
||||
@@ -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<namespace_name>\w+)/$', NamespaceDetailView.as_view(), name='namespace_detail'),
|
||||
)
|
||||
|
||||
@@ -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():
|
||||
|
||||
12
mayan/apps/smart_settings/widgets.py
Normal file
12
mayan/apps/smart_settings/widgets.py
Normal file
@@ -0,0 +1,12 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.utils.safestring import mark_safe
|
||||
|
||||
|
||||
def setting_widget(instance):
|
||||
return mark_safe(
|
||||
'''
|
||||
<strong>{}</strong>
|
||||
<p class="small">{}</p>
|
||||
'''.format(instance, instance.help_text or '')
|
||||
)
|
||||
@@ -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({
|
||||
|
||||
@@ -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('<a %s class="%s" href="%s" %s>' % (gallery_template, fancybox_class, '%s?%s' % (reverse(click_view, args=[staging_file.staging_folder.pk, staging_file.encoded_filename]), query_string), title_template))
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
Django==1.7.8
|
||||
|
||||
Pillow==2.8.2
|
||||
PyYAML==3.11
|
||||
|
||||
celery==3.1.18
|
||||
cssmin==0.2.0
|
||||
|
||||
Reference in New Issue
Block a user