Files
mayan-edms/mayan/apps/smart_settings/classes.py
Roberto Rosario d5224d93a7 Settings: Remove support for quoted settings
Instead of passing strings as arguments to backends, all settings must
be formatted according to YAML specifications. This is to remove the
need to add separate YAML parsing to each backend argument in each
app that needs it. Argument passing to backends is not fully
uniform.

Users need to update their config files.
  Example:

    DOCUMENTS_STORAGE_BACKEND_ARGUMENTS: '{location: /home/rosarior/development/mayan-edms/mayan/media/document_storage}'

  must be changed to:

    DOCUMENTS_STORAGE_BACKEND_ARGUMENTS:
      location: /home/rosarior/development/mayan-edms/mayan/media/document_storage

  Example 2:

    CONVERTER_GRAPHICS_BACKEND_CONFIG: '        {            libreoffice_path: /usr/bin/libreoffice,            pdftoppm_dpi:
    300,            pdftoppm_format: jpeg,            pdftoppm_path: /usr/bin/pdftoppm,            pdfinfo_path:
    /usr/bin/pdfinfo,            pillow_format: JPEG        }    '

  must be changed to:

    CONVERTER_GRAPHICS_BACKEND_CONFIG:
      libreoffice_path: /usr/bin/libreoffice
      pdftoppm_dpi: 300
      pdftoppm_format: jpeg
      pdftoppm_path: /usr/bin/pdftoppm
      pdfinfo_path: /usr/bin/pdfinfo
      pillow_format: JPEG

  Example 3:

    OCR_BACKEND_ARGUMENTS: ''

  must be changed to:

    OCR_BACKEND_ARGUMENTS: {}

  Settings that need to be updated are:

  - COMMON_SHARED_STORAGE_ARGUMENTS
  - CONVERTER_GRAPHICS_BACKEND_CONFIG
  - DOCUMENTS_CACHE_STORAGE_BACKEND_ARGUMENTS
  - DOCUMENTS_STORAGE_BACKEND_ARGUMENTS
  - OCR_BACKEND_ARGUMENTS
  - SIGNATURES_STORAGE_BACKEND_ARGUMENTS
  - SOURCES_STAGING_FILE_CACHE_STORAGE_BACKEND_ARGUMENTS

  The following error will appear in the console if a setting is not yet
  updated to this new format::

      TypeError: type object argument after ** must be a mapping, not str

Signed-off-by: Roberto Rosario <roberto.rosario.gonzalez@gmail.com>
2018-11-26 17:27:57 -04:00

194 lines
5.8 KiB
Python

from __future__ import unicode_literals
import errno
from importlib import import_module
import logging
import os
import sys
import yaml
from django.apps import apps
from django.conf import settings
from django.utils.functional import Promise
from django.utils.encoding import force_text, python_2_unicode_compatible
logger = logging.getLogger(__name__)
@python_2_unicode_compatible
class Namespace(object):
_registry = {}
@staticmethod
def initialize():
for app in apps.get_app_configs():
try:
import_module('{}.settings'.format(app.name))
except ImportError as exception:
if force_text(exception) not in ('No module named settings', 'No module named \'{}.settings\''.format(app.name)):
logger.error(
'Error importing %s settings.py file; %s', app.name,
exception
)
@classmethod
def get_all(cls):
return sorted(cls._registry.values(), key=lambda x: x.label)
@classmethod
def get(cls, name):
return cls._registry[name]
@classmethod
def invalidate_cache_all(cls):
for namespace in cls.get_all():
namespace.invalidate_cache()
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 __str__(self):
return force_text(self.label)
def add_setting(self, **kwargs):
return Setting(namespace=self, **kwargs)
def invalidate_cache(self):
for setting in self._settings:
setting.invalidate_cache()
@property
def settings(self):
return sorted(self._settings, key=lambda x: x.global_name)
@python_2_unicode_compatible
class Setting(object):
_registry = {}
@staticmethod
def deserialize_value(value):
return yaml.safe_load(value)
@staticmethod
def serialize_value(value):
if isinstance(value, Promise):
value = force_text(value)
result = yaml.safe_dump(value, allow_unicode=True)
# safe_dump returns bytestrings
# Disregard the last 3 dots that mark the end of the YAML document
if force_text(result).endswith('...\n'):
result = result[:-4]
return result
@classmethod
def dump_data(cls, filter_term=None, namespace=None):
dictionary = {}
for setting in cls.get_all():
if (namespace and setting.namespace.name == namespace) or not namespace:
if (filter_term and filter_term.lower() in setting.global_name.lower()) or not filter_term:
if isinstance(setting.value, Promise):
dictionary[setting.global_name] = force_text(setting.value)
else:
dictionary[setting.global_name] = setting.value
return yaml.safe_dump(dictionary, default_flow_style=False)
@classmethod
def get(cls, global_name):
return cls._registry[global_name]
@classmethod
def get_all(cls):
return sorted(cls._registry.values(), key=lambda x: x.global_name)
@classmethod
def save_configuration(cls, path=settings.CONFIGURATION_FILEPATH):
try:
with open(path, 'w') as file_object:
file_object.write(cls.dump_data())
except IOError as exception:
if exception.errno == errno.ENOENT:
logger.warning(
'The path to the configuration file doesn\'t '
'exist. It is not possible to save the backup file.'
)
@classmethod
def save_last_known_good(cls):
# Don't write over the last good configuration if we are trying
# to restore the last good configuration
if 'revertsettings' not in sys.argv:
cls.save_configuration(
path=settings.CONFIGURATION_LAST_GOOD_FILEPATH
)
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.loaded = False
self.namespace = namespace
self.environment_variable = False
namespace._settings.append(self)
self.__class__._registry[global_name] = self
def __str__(self):
return force_text(self.global_name)
def cache_value(self):
environment_value = os.environ.get('MAYAN_{}'.format(self.global_name))
if environment_value:
self.environment_variable = True
try:
self.raw_value = environment_value
except yaml.YAMLError as exception:
raise type(exception)(
'Error interpreting environment variable: {} with '
'value: {}; {}'.format(
self.global_name, environment_value, exception
)
)
else:
self.raw_value = getattr(settings, self.global_name, self.default)
self.yaml = Setting.serialize_value(self.raw_value)
self.loaded = True
def invalidate_cache(self):
self.loaded = False
@property
def serialized_value(self):
"""
YAML serialize value of the setting.
Used for UI display.
"""
if not self.loaded:
self.cache_value()
return self.yaml
@property
def value(self):
if not self.loaded:
self.cache_value()
return self.raw_value
@value.setter
def value(self, value):
# value is in YAML format
self.yaml = value
self.raw_value = Setting.deserialize_value(value)