django-orchestra/orchestra/contrib/websites/directives.py

209 lines
6.4 KiB
Python
Raw Permalink Normal View History

2015-03-10 21:51:10 +00:00
import re
2015-05-18 15:21:42 +00:00
from collections import defaultdict
from functools import lru_cache
2015-03-10 21:51:10 +00:00
from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _
2024-05-23 19:46:45 +00:00
from django.utils.encoding import force_str
2016-02-09 12:17:42 +00:00
from orchestra import plugins
from orchestra.utils.python import import_class
from . import settings
2015-05-19 13:27:04 +00:00
from .utils import normurlpath
2016-02-09 12:17:42 +00:00
class SiteDirective(plugins.Plugin, metaclass=plugins.PluginMount):
HTTPD = 'HTTPD'
SEC = 'ModSecurity'
SSL = 'SSL'
2015-03-23 15:36:51 +00:00
SAAS = 'SaaS'
help_text = ""
unique_name = False
unique_value = False
2016-03-11 12:19:34 +00:00
is_location = False
@classmethod
@lru_cache()
2016-02-09 12:17:42 +00:00
def get_plugins(cls, all=False):
if all:
plugins = super().get_plugins()
else:
plugins = []
for cls in settings.WEBSITES_ENABLED_DIRECTIVES:
plugins.append(import_class(cls))
return plugins
@classmethod
@lru_cache()
def get_option_groups(cls):
groups = {}
for opt in cls.get_plugins():
try:
groups[opt.group].append(opt)
except KeyError:
groups[opt.group] = [opt]
return groups
@classmethod
def get_choices(cls):
""" Generates grouped choices ready to use in Field.choices """
# generators can not be @lru_cache()
yield (None, '-------')
options = cls.get_option_groups()
for option in options.pop(None, ()):
yield (option.name, option.verbose_name)
2015-04-02 16:14:55 +00:00
for group, options in options.items():
yield (group, [(op.name, op.verbose_name) for op in options])
2015-05-18 15:21:42 +00:00
def validate_uniqueness(self, directive, values, locations):
""" Validates uniqueness location, name and value """
errors = defaultdict(list)
2015-05-27 14:05:25 +00:00
value = directive.get('value', None)
2015-05-18 15:21:42 +00:00
# location uniqueness
location = None
2016-03-11 12:19:34 +00:00
if self.is_location and value is not None:
if not value and self.is_location:
value = '/'
location = normurlpath(value.split()[0])
2015-05-18 15:21:42 +00:00
if location is not None and location in locations:
errors['value'].append(ValidationError(
"Location '%s' already in use by other content/directive." % location
))
else:
locations.add(location)
# name uniqueness
if self.unique_name and self.name in values:
errors[None].append(ValidationError(
_("Only one %s can be defined.") % self.get_verbose_name()
))
# value uniqueness
if value is not None:
if self.unique_value and value in values.get(self.name, []):
errors['value'].append(ValidationError(
_("This value is already used by other %s.") % force_str(self.get_verbose_name())
2015-05-18 15:21:42 +00:00
))
values[self.name].append(value)
if errors:
raise ValidationError(errors)
2015-07-29 09:05:07 +00:00
def validate(self, directive):
directive.value = directive.value.strip()
2016-03-11 12:19:34 +00:00
if not directive.value and self.is_location:
directive.value = '/'
2015-07-29 09:05:07 +00:00
if self.regex and not re.match(self.regex, directive.value):
raise ValidationError({
'value': ValidationError(_("'%(value)s' does not match %(regex)s."),
params={
2015-07-29 09:05:07 +00:00
'value': directive.value,
'regex': self.regex
}),
})
class Redirect(SiteDirective):
name = 'redirect'
2015-03-10 21:51:10 +00:00
verbose_name = _("Redirection")
help_text = _("<tt>&lt;website path&gt; &lt;destination URL&gt;</tt>")
2015-07-29 09:05:07 +00:00
regex = r'^[^ ]*\s[^ ]+$'
group = SiteDirective.HTTPD
unique_value = True
2016-03-11 12:19:34 +00:00
is_location = True
2015-07-29 09:05:07 +00:00
def validate(self, directive):
2015-09-28 10:51:03 +00:00
""" inserts default url-path if not provided """
2015-07-29 09:05:07 +00:00
values = directive.value.strip().split()
if len(values) == 1:
values.insert(0, '/')
directive.value = ' '.join(values)
super(Redirect, self).validate(directive)
2015-07-29 09:05:07 +00:00
class Proxy(Redirect):
name = 'proxy'
2015-03-10 21:51:10 +00:00
verbose_name = _("Proxy")
help_text = _("<tt>&lt;website path&gt; &lt;target URL&gt;</tt>")
regex = r'^[^ ]+\shttp[^ ]+(timeout=[0-9]{1,3}|retry=[0-9]|\s)*$'
class ErrorDocument(SiteDirective):
2015-04-07 15:14:49 +00:00
name = 'error-document'
2015-03-10 21:51:10 +00:00
verbose_name = _("ErrorDocumentRoot")
help_text = _("&lt;error code&gt; &lt;URL/path/message&gt;<br>"
"<tt>&nbsp;500 http://foo.example.com/cgi-bin/tester</tt><br>"
"<tt>&nbsp;404 /cgi-bin/bad_urls.pl</tt><br>"
"<tt>&nbsp;401 /subscription_info.html</tt><br>"
"<tt>&nbsp;403 \"Sorry can't allow you access today\"</tt>")
regex = r'[45]0[0-9]\s.*'
group = SiteDirective.HTTPD
unique_value = True
class SSLCA(SiteDirective):
2015-04-07 15:14:49 +00:00
name = 'ssl-ca'
2015-03-10 21:51:10 +00:00
verbose_name = _("SSL CA")
help_text = _("Filesystem path of the CA certificate file.")
2015-07-29 09:05:07 +00:00
regex = r'^/[^ ]+$'
group = SiteDirective.SSL
unique_name = True
2015-07-29 09:05:07 +00:00
class SSLCert(SSLCA):
2015-04-07 15:14:49 +00:00
name = 'ssl-cert'
2015-03-10 21:51:10 +00:00
verbose_name = _("SSL cert")
help_text = _("Filesystem path of the certificate file.")
2015-07-29 09:05:07 +00:00
class SSLKey(SSLCA):
2015-04-07 15:14:49 +00:00
name = 'ssl-key'
2015-03-10 21:51:10 +00:00
verbose_name = _("SSL key")
help_text = _("Filesystem path of the key file.")
class SecRuleRemove(SiteDirective):
2015-04-07 15:14:49 +00:00
name = 'sec-rule-remove'
2015-03-10 21:51:10 +00:00
verbose_name = _("SecRuleRemoveById")
help_text = _("Space separated ModSecurity rule IDs.")
regex = r'^[0-9\s]+$'
group = SiteDirective.SEC
2016-03-11 12:19:34 +00:00
is_location = True
2015-07-29 09:05:07 +00:00
class SecEngine(SecRuleRemove):
2015-04-07 15:14:49 +00:00
name = 'sec-engine'
verbose_name = _("SecRuleEngine Off")
2015-09-28 10:51:03 +00:00
help_text = _("URL-path with disabled modsecurity engine.")
2015-03-12 14:05:23 +00:00
regex = r'^/[^ ]*$'
2016-03-11 12:19:34 +00:00
is_location = False
2015-03-23 15:36:51 +00:00
class WordPressSaaS(SiteDirective):
name = 'wordpress-saas'
verbose_name = "WordPress SaaS"
help_text = _("URL-path for mounting WordPress multisite.")
2015-03-23 15:36:51 +00:00
group = SiteDirective.SAAS
regex = r'^/[^ ]*$'
unique_value = True
2016-03-11 12:19:34 +00:00
is_location = True
2015-03-23 15:36:51 +00:00
2015-07-29 09:05:07 +00:00
class DokuWikiSaaS(WordPressSaaS):
2015-03-23 15:36:51 +00:00
name = 'dokuwiki-saas'
verbose_name = "DokuWiki SaaS"
help_text = _("URL-path for mounting DokuWiki multisite.")
2015-03-23 15:36:51 +00:00
2015-07-29 09:05:07 +00:00
class DrupalSaaS(WordPressSaaS):
2015-03-23 15:36:51 +00:00
name = 'drupal-saas'
verbose_name = "Drupdal SaaS"
help_text = _("URL-path for mounting Drupal multisite.")
class MoodleSaaS(WordPressSaaS):
name = 'moodle-saas'
verbose_name = "Moodle SaaS"
help_text = _("URL-path for mounting Moodle multisite.")