202 lines
6.0 KiB
Python
202 lines
6.0 KiB
Python
"""Utils app models."""
|
|
from os.path import exists
|
|
from django.contrib.auth.tokens import PasswordResetTokenGenerator
|
|
from django.contrib.gis.db import models
|
|
from django.contrib.postgres.fields import JSONField
|
|
from django.contrib.postgres.fields.jsonb import KeyTextTransform
|
|
from django.utils import timezone
|
|
from django.utils.html import mark_safe
|
|
from django.utils.translation import ugettext_lazy as _, get_language
|
|
from easy_thumbnails.fields import ThumbnailerImageField
|
|
from utils.methods import image_path, svg_image_path
|
|
from utils.validators import svg_image_validator
|
|
|
|
|
|
class ProjectBaseMixin(models.Model):
|
|
"""Base mixin model."""
|
|
|
|
created = models.DateTimeField(default=timezone.now, editable=False,
|
|
verbose_name=_('Date created'))
|
|
modified = models.DateTimeField(auto_now=True,
|
|
verbose_name=_('Date updated'))
|
|
|
|
class Meta:
|
|
"""Meta class."""
|
|
|
|
abstract = True
|
|
|
|
|
|
class TJSONField(JSONField):
|
|
"""Overrided JsonField."""
|
|
|
|
|
|
def to_locale(language):
|
|
"""Turn a language name (en-us) into a locale name (en_US)."""
|
|
language, _, country = language.lower().partition('-')
|
|
if not country:
|
|
return language
|
|
# A language with > 2 characters after the dash only has its first
|
|
# character after the dash capitalized; e.g. sr-latn becomes sr_Latn.
|
|
# A language with 2 characters after the dash has both characters
|
|
# capitalized; e.g. en-us becomes en_US.
|
|
country, _, tail = country.partition('-')
|
|
country = country.title() if len(country) > 2 else country.upper()
|
|
if tail:
|
|
country += '-' + tail
|
|
return language + '-' + country
|
|
|
|
|
|
def translate_field(self, field_name):
|
|
def translate(self):
|
|
field = getattr(self, field_name)
|
|
if isinstance(field, dict):
|
|
return field.get(to_locale(get_language()))
|
|
return None
|
|
return translate
|
|
|
|
|
|
class TraslatedFieldsMixin:
|
|
def __init__(self, *args, **kwargs):
|
|
super(TraslatedFieldsMixin, self).__init__(*args, **kwargs)
|
|
cls = self.__class__
|
|
for field in cls._meta.fields:
|
|
field_name = field.name
|
|
if isinstance(field, TJSONField):
|
|
setattr(cls, f'{field.name}_translated',
|
|
property(translate_field(self, field_name)))
|
|
|
|
|
|
class OAuthProjectMixin:
|
|
"""OAuth2 mixin for project GM"""
|
|
|
|
def get_source(self):
|
|
"""Method to get of platform"""
|
|
return NotImplemented
|
|
|
|
|
|
basemixin_fields = ['created', 'modified']
|
|
|
|
|
|
class BaseAttributes(ProjectBaseMixin):
|
|
created_by = models.ForeignKey(
|
|
'account.User', on_delete=models.SET_NULL, verbose_name=_('created by'),
|
|
null=True, related_name='%(class)s_records_created'
|
|
)
|
|
modified_by = models.ForeignKey(
|
|
'account.User', on_delete=models.SET_NULL, verbose_name=_('modified by'),
|
|
null=True, related_name='%(class)s_records_modified'
|
|
)
|
|
|
|
class Meta:
|
|
"""Meta class."""
|
|
|
|
abstract = True
|
|
|
|
|
|
class ImageMixin(models.Model):
|
|
"""Avatar model."""
|
|
|
|
THUMBNAIL_KEY = 'default'
|
|
|
|
image = ThumbnailerImageField(upload_to=image_path,
|
|
blank=True, null=True, default=None,
|
|
verbose_name=_('Image'))
|
|
|
|
class Meta:
|
|
"""Meta class."""
|
|
|
|
abstract = True
|
|
|
|
def get_image(self, key=None):
|
|
"""Get thumbnailed image file."""
|
|
return self.image[key or self.THUMBNAIL_KEY] if self.image else None
|
|
|
|
def get_image_url(self, key=None):
|
|
"""Get image thumbnail url."""
|
|
return self.get_image(key).url if self.image else None
|
|
|
|
def image_tag(self):
|
|
"""Admin preview tag."""
|
|
if self.image:
|
|
return mark_safe('<img src="%s" />' % self.get_image_url())
|
|
else:
|
|
return None
|
|
|
|
def get_full_image_url(self, request, thumbnail_key=None):
|
|
"""Get full image url"""
|
|
if self.image and exists(self.image.path):
|
|
return request.build_absolute_uri(self.get_image(thumbnail_key).url)
|
|
else:
|
|
return None
|
|
|
|
image_tag.short_description = _('Image')
|
|
image_tag.allow_tags = True
|
|
|
|
|
|
class SVGImageMixin(models.Model):
|
|
"""SVG image model."""
|
|
|
|
svg_image = models.FileField(upload_to=svg_image_path,
|
|
blank=True, null=True, default=None,
|
|
validators=[svg_image_validator, ],
|
|
verbose_name=_('SVG image'))
|
|
|
|
class Meta:
|
|
abstract = True
|
|
|
|
|
|
class PlatformMixin(models.Model):
|
|
"""Platforms"""
|
|
|
|
MOBILE = 0
|
|
WEB = 1
|
|
|
|
SOURCES = (
|
|
(MOBILE, _('Mobile')),
|
|
(WEB, _('Web')),
|
|
)
|
|
source = models.PositiveSmallIntegerField(choices=SOURCES, default=MOBILE,
|
|
verbose_name=_('Source'))
|
|
|
|
class Meta:
|
|
"""Meta class"""
|
|
abstract = True
|
|
|
|
|
|
class LocaleManagerMixin(models.Manager):
|
|
"""Manager for locale"""
|
|
|
|
def annotate_localized_fields(self, locale):
|
|
"""Return queryset by locale"""
|
|
prefix = 'trans'
|
|
|
|
# Prepare fields to localization (only JSONField can be localized)
|
|
fields = [field.name for field in self.model._meta.fields if isinstance(field, JSONField)]
|
|
|
|
# Check filters to check if field has localization
|
|
filters = {f'{field}__has_key': locale for field in fields}
|
|
# Filter QuerySet by prepared filters
|
|
queryset = self.filter(**filters)
|
|
|
|
# Prepare field for annotator
|
|
localized_fields = {f'{field}_{prefix}': KeyTextTransform(f'{locale}', field) for field in fields}
|
|
|
|
# Annotate them
|
|
for _ in fields:
|
|
queryset = queryset.annotate(**localized_fields)
|
|
return queryset
|
|
|
|
|
|
class GMTokenGenerator(PasswordResetTokenGenerator):
|
|
|
|
def _make_hash_value(self, user, timestamp):
|
|
return (
|
|
str(user.pk) +
|
|
str(user.email_confirmed) +
|
|
str(timestamp) +
|
|
str(user.is_active)
|
|
)
|
|
|
|
|
|
gm_token_generator = GMTokenGenerator()
|