2023-07-09 07:51:51 +00:00
|
|
|
import os
|
|
|
|
from collections import OrderedDict
|
|
|
|
|
|
|
|
from django.db import models
|
|
|
|
from django.utils.functional import cached_property
|
|
|
|
from django.utils.translation import gettext_lazy as _
|
|
|
|
|
|
|
|
from orchestra.core import validators
|
|
|
|
from orchestra.utils.functional import cached
|
|
|
|
|
|
|
|
from . import settings
|
|
|
|
from .directives import SiteDirective
|
|
|
|
|
|
|
|
|
|
|
|
class Website(models.Model):
|
|
|
|
""" Models a web site, also known as virtual host """
|
|
|
|
HTTP = 'http'
|
|
|
|
HTTPS = 'https'
|
|
|
|
HTTP_AND_HTTPS = 'http/https'
|
|
|
|
HTTPS_ONLY = 'https-only'
|
|
|
|
|
|
|
|
name = models.CharField(_("name"), max_length=128,
|
|
|
|
validators=[validators.validate_name])
|
|
|
|
account = models.ForeignKey('accounts.Account', on_delete=models.CASCADE,
|
|
|
|
verbose_name=_("Account"), related_name='websites')
|
|
|
|
protocol = models.CharField(_("protocol"), max_length=16,
|
|
|
|
choices=settings.WEBSITES_PROTOCOL_CHOICES,
|
|
|
|
default=settings.WEBSITES_DEFAULT_PROTOCOL,
|
|
|
|
help_text=_("Select the protocol(s) for this website<br>"
|
|
|
|
"<tt>HTTPS only</tt> performs a redirection from <tt>http</tt> to <tt>https</tt>."))
|
|
|
|
# port = models.PositiveIntegerField(_("port"),
|
|
|
|
# choices=settings.WEBSITES_PORT_CHOICES,
|
|
|
|
# default=settings.WEBSITES_DEFAULT_PORT)
|
|
|
|
domains = models.ManyToManyField(settings.WEBSITES_DOMAIN_MODEL, blank=True,
|
|
|
|
related_name='websites', verbose_name=_("domains"))
|
|
|
|
contents = models.ManyToManyField('webapps.WebApp', through='websites.Content')
|
|
|
|
target_server = models.ForeignKey('orchestration.Server', on_delete=models.CASCADE,
|
|
|
|
verbose_name=_("Target Server"), related_name='websites')
|
|
|
|
is_active = models.BooleanField(_("active"), default=True)
|
|
|
|
comments = models.TextField(default="", blank=True)
|
|
|
|
|
|
|
|
class Meta:
|
2023-08-20 07:07:45 +00:00
|
|
|
unique_together = ('name', 'account', 'target_server')
|
2023-07-09 07:51:51 +00:00
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
return self.name
|
|
|
|
|
|
|
|
@property
|
|
|
|
def unique_name(self):
|
|
|
|
context = self.get_settings_context()
|
|
|
|
return settings.WEBSITES_UNIQUE_NAME_FORMAT % context
|
|
|
|
|
|
|
|
@cached_property
|
|
|
|
def active(self):
|
|
|
|
return self.is_active and self.account.is_active
|
|
|
|
|
|
|
|
def disable(self):
|
|
|
|
self.is_active = False
|
|
|
|
self.save(update_fields=('is_active',))
|
|
|
|
|
|
|
|
def enable(self):
|
|
|
|
self.is_active = False
|
|
|
|
self.save(update_fields=('is_active',))
|
|
|
|
|
|
|
|
def get_settings_context(self):
|
|
|
|
""" format settings strings """
|
|
|
|
return {
|
|
|
|
'id': self.id,
|
|
|
|
'pk': self.pk,
|
|
|
|
'home': self.get_user().get_home(),
|
|
|
|
'user': self.get_username(),
|
|
|
|
'group': self.get_groupname(),
|
|
|
|
'site_name': self.name,
|
|
|
|
'protocol': self.protocol,
|
|
|
|
}
|
|
|
|
|
|
|
|
def get_protocol(self):
|
|
|
|
if self.protocol in (self.HTTP, self.HTTP_AND_HTTPS):
|
|
|
|
return self.HTTP
|
|
|
|
return self.HTTPS
|
|
|
|
|
|
|
|
@cached
|
|
|
|
def get_directives(self):
|
|
|
|
directives = OrderedDict()
|
|
|
|
for opt in self.directives.all().order_by('name', 'value'):
|
|
|
|
try:
|
|
|
|
directives[opt.name].append(opt.value)
|
|
|
|
except KeyError:
|
|
|
|
directives[opt.name] = [opt.value]
|
|
|
|
return directives
|
|
|
|
|
|
|
|
def get_absolute_url(self):
|
|
|
|
try:
|
|
|
|
domain = self.domains.all()[0]
|
|
|
|
except IndexError:
|
|
|
|
return
|
|
|
|
else:
|
|
|
|
return '%s://%s' % (self.get_protocol(), domain)
|
|
|
|
|
|
|
|
def get_user(self):
|
|
|
|
return self.account.main_systemuser
|
|
|
|
|
|
|
|
def get_username(self):
|
|
|
|
return self.get_user().username
|
|
|
|
|
|
|
|
def get_groupname(self):
|
|
|
|
return self.get_username()
|
|
|
|
|
|
|
|
def get_www_access_log_path(self):
|
|
|
|
context = self.get_settings_context()
|
|
|
|
context['unique_name'] = self.unique_name
|
|
|
|
path = settings.WEBSITES_WEBSITE_WWW_ACCESS_LOG_PATH % context
|
|
|
|
return os.path.normpath(path)
|
|
|
|
|
|
|
|
def get_www_error_log_path(self):
|
|
|
|
context = self.get_settings_context()
|
|
|
|
context['unique_name'] = self.unique_name
|
|
|
|
path = settings.WEBSITES_WEBSITE_WWW_ERROR_LOG_PATH % context
|
|
|
|
return os.path.normpath(path)
|
|
|
|
|
|
|
|
|
|
|
|
class WebsiteDirective(models.Model):
|
|
|
|
website = models.ForeignKey(Website, on_delete=models.CASCADE,
|
|
|
|
verbose_name=_("web site"), related_name='directives')
|
|
|
|
name = models.CharField(_("name"), max_length=128, db_index=True,
|
|
|
|
choices=SiteDirective.get_choices())
|
|
|
|
value = models.CharField(_("value"), max_length=256, blank=True)
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
return self.name
|
|
|
|
|
|
|
|
@cached_property
|
|
|
|
def directive_class(self):
|
|
|
|
return SiteDirective.get(self.name)
|
|
|
|
|
|
|
|
@cached_property
|
|
|
|
def directive_instance(self):
|
|
|
|
""" Per request lived directive instance """
|
|
|
|
return self.directive_class()
|
|
|
|
|
|
|
|
def clean(self):
|
|
|
|
self.directive_instance.validate(self)
|
|
|
|
|
|
|
|
|
|
|
|
class Content(models.Model):
|
|
|
|
# related_name is content_set to differentiate between website.content -> webapp
|
|
|
|
webapp = models.ForeignKey('webapps.WebApp', on_delete=models.CASCADE,
|
|
|
|
verbose_name=_("web application"))
|
|
|
|
website = models.ForeignKey('websites.Website', on_delete=models.CASCADE,
|
|
|
|
verbose_name=_("web site"))
|
|
|
|
path = models.CharField(_("path"), max_length=256, blank=True,
|
|
|
|
validators=[validators.validate_url_path])
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
unique_together = ('website', 'path')
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
try:
|
|
|
|
return self.website.name + self.path
|
|
|
|
except Website.DoesNotExist:
|
|
|
|
return self.path
|
|
|
|
|
|
|
|
def clean_fields(self, *args, **kwargs):
|
|
|
|
self.path = self.path.strip()
|
|
|
|
return super(Content, self).clean_fields(*args, **kwargs)
|
|
|
|
|
|
|
|
def clean(self):
|
|
|
|
if not self.path:
|
|
|
|
self.path = '/'
|
|
|
|
|
|
|
|
def get_absolute_url(self):
|
|
|
|
try:
|
|
|
|
domain = self.website.domains.all()[0]
|
|
|
|
except IndexError:
|
|
|
|
return
|
|
|
|
else:
|
|
|
|
return '%s://%s%s' % (self.website.get_protocol(), domain, self.path)
|