from django.conf import settings
from django.contrib.auth.models import User
from django.core.exceptions import ImproperlyConfigured, ValidationError
from django.db import models
from django.dispatch import Signal
from django.utils.translation import get_language, get_language_from_request
from django.utils.translation import gettext_lazy as _
from mptt.models import MPTTModel, TreeForeignKey
from oioioi.base.utils.validators import validate_db_string_id, validate_whitespaces
if (
'oioioi.portals.processors.portal_processor'
not in settings.TEMPLATES[0]['OPTIONS']['context_processors']
):
raise ImproperlyConfigured(
"When using portals module "
"you have to add oioioi.portals.processors.portal_processor "
"to TEMPLATES[0]['OPTIONS']['context_processors'] in settings.py"
)
[docs]class Node(MPTTModel):
[docs] short_name = models.CharField(
max_length=32,
verbose_name=_("short name"),
help_text=_("Shown in the URL."),
validators=[validate_db_string_id],
)
[docs] parent = TreeForeignKey(
'self',
null=True,
blank=False,
related_name='children',
verbose_name=_("parent"),
on_delete=models.CASCADE,
)
[docs] problems_in_content = models.ManyToManyField(
'problems.problem', related_name='portal_pages', blank=True
)
[docs] def __str__(self):
return str(self.get_lang_version().full_name)
[docs] def get_lang_version(self, request=None):
"""Tries to get a default language version for a current context (from
a given request, then a current thread and then from the settings). If
none matching version could be found, just return any.
"""
languages = [get_language_from_request(request)] if request is not None else []
languages += [get_language(), settings.LANGUAGE_CODE]
for lang in languages:
try:
return self.language_versions.get(language=lang)
except NodeLanguageVersion.DoesNotExist:
pass
return self.language_versions.first()
[docs] def get_siblings(self, include_self=False):
"""Wrapper around mptt get_siblings method.
Does not consider two root nodes to be siblings.
"""
if self.is_root_node():
if include_self:
return Node.objects.filter(pk=self.pk)
else:
return Node.objects.none()
else:
return super(Node, self).get_siblings(include_self)
[docs] def get_path(self):
return '/'.join(
node.short_name for node in self.get_ancestors(include_self=True)
).lstrip('/')
[docs]class NodeLanguageVersion(models.Model):
[docs] node = models.ForeignKey(
Node, related_name='language_versions', on_delete=models.CASCADE
)
[docs] language = models.CharField(max_length=6, verbose_name=_("language code"))
[docs] full_name = models.CharField(
max_length=32,
verbose_name=_("full name"),
help_text=_("Shown in the navigation menu."),
validators=[validate_whitespaces],
)
[docs] panel_code = models.TextField(null=False, blank=True, verbose_name=_("panel code"))
[docs]class Portal(models.Model):
[docs] owner = models.OneToOneField(User, null=True, unique=True, on_delete=models.CASCADE)
[docs] root = models.OneToOneField(Node, unique=True, on_delete=models.CASCADE)
[docs] short_description = models.CharField(
max_length=256,
null=True,
default=_("My portal."),
verbose_name=_("short description"),
)
[docs] is_public = models.BooleanField(default=False, verbose_name=_("is public"))
[docs] link_name = models.CharField(
max_length=40,
null=True,
unique=True,
help_text=_("Shown in the URL."),
validators=[validate_db_string_id],
)
[docs] def clean(self):
super(Portal, self).clean()
if (self.owner is None) == (self.link_name is None): # !xor
raise ValidationError(
_("Exactly one from the following should be chosen: owner, link_name")
)