import re import sys from collections import OrderedDict from django.conf import settings from django.core.exceptions import ValidationError, AppRegistryNotReady from django.core.validators import validate_email from django.db.models import get_model from django.utils.functional import Promise from django.utils.translation import ugettext_lazy as _ from orchestra.utils.python import import_class, format_exception from .core import validators class Setting(object): """ Keeps track of the defined settings and provides extra batteries like value validation. """ conf_settings = settings settings = OrderedDict() def __str__(self): return self.name def __repr__(self): value = str(self.value) value = ("'%s'" if isinstance(value, str) else '%s') % value return '<%s: %s>' % (self.name, value) def __new__(cls, name, default, help_text="", choices=None, editable=True, serializable=True, multiple=False, validators=[], types=[], call_init=False): if call_init: return super(Setting, cls).__new__(cls) cls.settings[name] = cls(name, default, help_text=help_text, choices=choices, editable=editable, serializable=serializable, multiple=multiple, validators=validators, types=types, call_init=True) return cls.get_value(name, default) def __init__(self, *args, **kwargs): self.name, self.default = args for name, value in kwargs.items(): setattr(self, name, value) self.value = self.get_value(self.name, self.default) try: self.validate_value(self.value) except ValidationError as exc: # Init time warning sys.stderr.write("Error validating setting %s with value %s\n" % (self.name, self.value)) sys.stderr.write(format_exception(exc)) raise exc except AppRegistryNotReady: # lazy bastards pass self.settings[name] = self @classmethod def validate_choices(cls, value): if not isinstance(value, (list, tuple)): raise ValidationError("%s is not a valid choices." % str(value)) for choice in value: if not isinstance(choice, (list, tuple)) or len(choice) != 2: raise ValidationError("%s is not a valid choice." % str(choice)) value, verbose = choice if not isinstance(verbose, (str, Promise)): raise ValidationError("%s is not a valid verbose name." % value) @classmethod def validate_import_class(cls, value): try: import_class(value) except ImportError as exc: if "cannot import name 'settings'" in str(exc): # circular dependency on init time pass except Exception as exc: raise ValidationError(format_exception(exc)) @classmethod def validate_model_label(cls, value): try: get_model(*value.split('.')) except AppRegistryNotReady: # circular dependency on init time pass except Exception as exc: raise ValidationError(format_exception(exc)) @classmethod def string_format_validator(cls, names, modulo=True): def validate_string_format(value, names=names, modulo=modulo): errors = [] regex = r'%\(([^\)]+)\)' if modulo else r'{([^}]+)}' for n in re.findall(regex, value): if n not in names: errors.append( ValidationError('%s is not a valid format name.' % n) ) if errors: raise ValidationError(errors) return validate_string_format def validate_value(self, value): if value: validators.all_valid(value, self.validators) valid_types = list(self.types) if isinstance(self.default, (list, tuple)): valid_types.extend([list, tuple]) valid_types.append(type(self.default)) if not isinstance(value, tuple(valid_types)): raise ValidationError("%s is not a valid type (%s)." % (type(value).__name__, ', '.join(t.__name__ for t in valid_types)) ) @classmethod def get_value(cls, name, default): return getattr(cls.conf_settings, name, default) ORCHESTRA_BASE_DOMAIN = Setting('ORCHESTRA_BASE_DOMAIN', 'orchestra.lan', help_text=("Base domain name used for other settings.
" "If you're editing the settings via the admin interface it is advisable to " "commit this change before changing any other variables which could be affected.") ) ORCHESTRA_SITE_URL = Setting('ORCHESTRA_SITE_URL', 'https://orchestra.%s' % ORCHESTRA_BASE_DOMAIN, help_text=_("Domain name used when it will not be possible to infere the domain from a request." "For example in periodic tasks.
" "Uses ORCHESTRA_BASE_DOMAIN by default.") ) ORCHESTRA_SITE_NAME = Setting('ORCHESTRA_SITE_NAME', 'orchestra', ) ORCHESTRA_SITE_VERBOSE_NAME = Setting('ORCHESTRA_SITE_VERBOSE_NAME', "%s Hosting Management" % ORCHESTRA_SITE_NAME.capitalize(), help_text="Uses ORCHESTRA_SITE_NAME by default." ) # Service management commands ORCHESTRA_START_SERVICES = Setting('ORCHESTRA_START_SERVICES', default=( 'postgresql', 'celeryevcam', 'celeryd', 'celerybeat', ('uwsgi', 'nginx'), ), ) ORCHESTRA_RESTART_SERVICES = Setting('ORCHESTRA_RESTART_SERVICES', default=( 'celeryd', 'celerybeat', 'uwsgi' ), ) ORCHESTRA_STOP_SERVICES = Setting('ORCHESTRA_STOP_SERVICES', default=( ('uwsgi', 'nginx'), 'celerybeat', 'celeryd', 'celeryevcam', 'postgresql' ), ) ORCHESTRA_API_ROOT_VIEW = Setting('ORCHESTRA_API_ROOT_VIEW', 'orchestra.api.root.APIRoot' ) ORCHESTRA_DEFAULT_SUPPORT_FROM_EMAIL = Setting('ORCHESTRA_DEFAULT_SUPPORT_FROM_EMAIL', 'support@{}'.format(ORCHESTRA_BASE_DOMAIN), validators=[validate_email], help_text="Uses ORCHESTRA_BASE_DOMAIN by default." ) ORCHESTRA_EDIT_SETTINGS = Setting('ORCHESTRA_EDIT_SETTINGS', True )