conventionschedule-android/webstorage/webproj/bff/models.py
2018-12-27 23:20:54 -02:00

375 lines
15 KiB
Python

import uuid
from django.db import models
from colorfield.fields import ColorField
from ckeditor.fields import RichTextField
from django.db.models.signals import post_delete
from .helpers import file_cleanup
from .helpers import RandomFileName
from django.core.validators import MaxValueValidator, MinValueValidator, RegexValidator
class IntListField(models.CharField):
description = "An integer list"
def __init__(self, *args, **kwargs):
if 'max_length' not in kwargs:
kwargs['max_length'] = 255
if 'default' not in kwargs:
kwargs['default'] = ''
super().__init__(*args, **kwargs)
def from_db_value(self, value, expression, connection):
if value is None:
return value
if value.strip() == '':
return list()
return list(map(int, map(str.strip, value.split(','))))
def to_python(self, value):
if isinstance(value, list):
return value
if value is None:
return value
for i in '[](){}':
value = value.replace(i, '')
if value.strip() == '':
return list()
return list(map(int, map(str.strip, value.split(','))))
def get_prep_value(self, value):
return ','.join(list(map(str, value)))
# Create your models here.
class Timestampable(models.Model):
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
resource_uuid = models.UUIDField(default=uuid.uuid4, editable=False, primary_key=False)
class Meta:
abstract = True
class Remindable(Timestampable):
reminder_alias = models.CharField(default='', unique=True, max_length=255, validators=[
RegexValidator(r'^[A-Za-z_][A-Za-z0-9_]*$'),
], help_text='All characters must be alphanumerical or underline, except by the first character, which must not be alphanumerical.')
kind = '???'
@property
def reminder_title(self):
return self.__class__.__name__
def __str__(self):
return f'{self.reminder_title} {self.kind} #{self.pk}: {self.reminder_alias}'
class Meta:
abstract = True
class LanguageString(Remindable):
resource_uuid = models.UUIDField(default=uuid.uuid4, editable=False, unique=True, primary_key=False)
reminder_title = 'Language'
class Meta:
abstract = True
ordering = ('reminder_alias', )
class LanguagePhrase(LanguageString):
kind = 'phrase'
pt = models.CharField(default='', max_length=255)
en = models.CharField(default='', max_length=255)
es = models.CharField(default='', max_length=255)
class LanguageText(LanguageString):
kind = 'text'
pt = models.TextField(default='')
en = models.TextField(default='')
es = models.TextField(default='')
class LanguageRichText(LanguageString):
kind = 'rich text'
pt = RichTextField(default='')
en = RichTextField(default='')
es = RichTextField(default='')
class LanguageInvariantImage(LanguageString):
kind = 'invariant image'
picture = models.ImageField(upload_to=RandomFileName(''))
@property
def pt(self): return self.picture
@property
def en(self): return self.picture
@property
def es(self): return self.picture
post_delete.connect(file_cleanup, sender=LanguageInvariantImage, dispatch_uid="webproj.bff.LanguageInvariantImage.file_cleanup")
class LanguageImage(LanguageString):
kind = 'image'
pt_image = models.ForeignKey(LanguageInvariantImage, on_delete=models.PROTECT, related_name='+')
en_image = models.ForeignKey(LanguageInvariantImage, on_delete=models.PROTECT, related_name='+')
es_image = models.ForeignKey(LanguageInvariantImage, on_delete=models.PROTECT, related_name='+')
@property
def pt(self): return self.pt_image.picture
@property
def en(self): return self.en_image.picture
@property
def es(self): return self.es_image.picture
class Announcement(Timestampable):
convention = models.ForeignKey('ConventionSeries', on_delete=models.PROTECT, related_name='announcements')
title = models.ForeignKey(LanguagePhrase, on_delete=models.PROTECT, related_name='+')
body = models.ForeignKey(LanguageText, on_delete=models.PROTECT, related_name='+')
link = models.ForeignKey(LanguagePhrase, blank=True, null=True, on_delete=models.PROTECT, related_name='+')
def __str__(self):
return f'Announcement #{self.pk}: {self.title}'
class Color(Remindable):
color = ColorField(default='#000000')
opacity = models.IntegerField(default=255, validators=[MinValueValidator(0), MaxValueValidator(255)], help_text="Opacity: 0 is transparent, 255 is opaque.")
kind = ''
class ActivityCategory(Timestampable):
name = models.ForeignKey(LanguagePhrase, on_delete=models.PROTECT, related_name='+')
color = models.ForeignKey(Color, on_delete=models.PROTECT, related_name='+')
ordering = models.IntegerField(default=0, blank=True, null=False)
def __str__(self):
return f'Category #{self.pk}: {self.name.en}'
class Meta:
ordering = ('ordering', '-pk', )
class Place(Timestampable):
name = models.ForeignKey(LanguagePhrase, on_delete=models.PROTECT, related_name='+')
color = models.ForeignKey(Color, on_delete=models.PROTECT, related_name='+')
ordering = models.IntegerField(default=0, blank=True, null=False)
def __str__(self):
return f'Place #{self.pk}: {self.name.en}'
class Meta:
ordering = ('ordering', '-pk', )
class Timezone(Remindable):
kind = ''
hour = models.IntegerField(default=-3, validators=[MinValueValidator(-24), MaxValueValidator(24)])
minute = models.IntegerField(default=0, validators=[MinValueValidator(0), MaxValueValidator(60)])
class RegistrationBenefitDefinition(Timestampable):
description = models.ForeignKey(LanguagePhrase, on_delete=models.PROTECT, related_name='+')
ordering = models.IntegerField(default=0, blank=True, null=False)
def __str__(self):
return f'Registration benefit definition #{self.pk}: {self.description.en}'
class Meta:
ordering = ('ordering', '-pk', )
class RegistrationTierDefinition(Timestampable):
title = models.ForeignKey(LanguagePhrase, on_delete=models.PROTECT, related_name='+')
ordering = models.IntegerField(default=0, blank=True, null=False)
def __str__(self):
return f'Registration tier definition #{self.pk}: {self.title.en}'
class Meta:
ordering = ('ordering', '-pk', )
TRILINGUAL_CHOICES = (
('pt', 'Portuguese'),
('en', 'English'),
('es', 'Spanish')
)
class ConventionRegistrationTier(Timestampable):
level = models.IntegerField(default=0)
tier = models.ForeignKey(RegistrationTierDefinition, on_delete=models.PROTECT, related_name='+')
benefits = models.ManyToManyField(RegistrationBenefitDefinition, blank=True, related_name='+')
convention = models.ForeignKey('ConventionEdition', on_delete=models.PROTECT, related_name='registration_tiers')
is_lowest = models.BooleanField(default=False, blank=True, null=False)
def __str__(self):
return f'Convention registration tier #{self.pk}: {self.convention.name.en} - {self.tier.title.en} ({self.benefits.count()})'
class ConventionActivity(Timestampable):
conbook_key = models.CharField(default='', max_length=255)
conbook_pages = IntListField()
title = models.ForeignKey(LanguagePhrase, on_delete=models.PROTECT, related_name='+')
subtitle = models.ForeignKey(LanguagePhrase, on_delete=models.PROTECT, blank=True, null=True, related_name='+')
description = models.ForeignKey(LanguageText, on_delete=models.PROTECT, related_name='+')
time_start = models.DateTimeField(help_text="fill with the time on the timezone of the event.")
time_end = models.DateTimeField(help_text="fill with the time on the timezone of the event.")
places = models.ManyToManyField(Place, related_name='on_activities')
categories = models.ManyToManyField(ActivityCategory, blank=True, related_name='on_activities')
attendable_by = models.ManyToManyField(ConventionRegistrationTier, related_name='+')
language = models.CharField(
max_length=2,
choices=TRILINGUAL_CHOICES,
default='pt',
)
hidden_from_time_table = models.BooleanField(default=False, blank=True, null=False)
picture = models.ForeignKey(LanguageInvariantImage, blank=True, null=True, related_name='+', on_delete=models.PROTECT)
convention = models.ForeignKey('ConventionEdition', related_name='events', on_delete=models.PROTECT)
class Meta:
ordering = ('-time_start', '-time_end', 'conbook_key')
def __str__(self):
return f'Convention activity #{self.pk}: {self.convention.name.en} - {self.title.en} [{self.conbook_key}] ({self.time_start} - {self.time_end})'
class ConventionSeries(Timestampable):
name = models.ForeignKey(LanguagePhrase, on_delete=models.PROTECT, related_name='+')
url = models.SlugField(default='', unique=True, max_length=255)
featured = models.ForeignKey('ConventionEdition', null=True, blank=True, on_delete=models.PROTECT, related_name='+')
statute = models.ForeignKey(LanguageRichText, on_delete=models.PROTECT, related_name='+')
timezone = models.ForeignKey(Timezone, on_delete=models.PROTECT, related_name='+')
default_banner = models.ForeignKey(LanguageImage, default=None, on_delete=models.PROTECT, related_name='+')
language = models.CharField(
max_length=2,
choices=TRILINGUAL_CHOICES,
default='pt',
)
# banners ← foreign_relation
# social_medias ← foreign_relation
def __str__(self):
return f'Convention series #{self.pk}: {self.name.en} (/{self.url})'
class SocialMedia(Remindable):
ordering = models.IntegerField(default=0)
convention = models.ForeignKey(ConventionSeries, on_delete=models.PROTECT, related_name='social_medias')
name = models.ForeignKey(LanguagePhrase, on_delete=models.PROTECT, related_name='+')
url = models.ForeignKey(LanguagePhrase, on_delete=models.PROTECT, related_name='+')
icon = models.CharField(default=None, blank=True, null=True, max_length=255, choices=[
(None, '-- no icon --'),
('ic_telegram', 'Telegram'),
('ic_twitter', 'Twitter'),
('ic_facebook_official', 'Facebook'),
('ic_youtube_play', 'YouTube'),
('ic_instagram', 'Instagram'),
('ic_web_black_24dp', 'Web browser'),
])
kind = ''
color = models.ForeignKey(Color, on_delete=models.PROTECT, related_name='+')
class Meta:
ordering = ('ordering', 'name__reminder_alias', '-pk', )
class ConventionEdition(Timestampable):
# id ← inherited
# events ← foreign_relation
# registration_tiers ← foreign_relation
# lowestRegistrationTier ← process
# places ← process
# tags ← process
edition_of = models.ForeignKey(ConventionSeries, on_delete=models.PROTECT, related_name='editions')
name = models.ForeignKey(LanguagePhrase, on_delete=models.PROTECT, related_name='+')
theme = models.ForeignKey(LanguagePhrase, on_delete=models.PROTECT, related_name='+')
hashtag_reminder = models.CharField(default='', max_length=255)
timezone = models.ForeignKey(Timezone, on_delete=models.PROTECT, related_name='+')
fire_notifications_n_minutes_before = models.PositiveIntegerField(default=15)
convention_day_start_time = models.TimeField(help_text="fill with the time on the timezone of the event.")
convention_day_end_time = models.TimeField(help_text="fill with the time on the timezone of the event.")
rule_621_checker = models.BooleanField(default=False, blank=True, null=False)
next_edition_date = models.DateField(help_text="fill with the time on the timezone of the event.")
ceremony_opening_time = models.DateTimeField(help_text="fill with the time on the timezone of the event.")
ceremony_closing_time = models.DateTimeField(help_text="fill with the time on the timezone of the event.")
image_default_event = models.ForeignKey(LanguageImage, default=None, null=True, blank=True, on_delete=models.PROTECT, related_name='+')
image_favorites = models.ForeignKey(LanguageImage, default=None, null=True, blank=True, on_delete=models.PROTECT, related_name='+')
split_day_into_n_parts = models.IntegerField(default=24, blank=False, null=False, validators=[MaxValueValidator(1440), MinValueValidator(1)])
language = models.CharField(
max_length=2,
choices=TRILINGUAL_CHOICES,
default='pt',
)
def __str__(self):
return f'Convention #{self.pk}: {self.name.en}'
class Meta:
ordering = ('ceremony_opening_time', '-pk', )
class BannerChange(Remindable):
convention = models.ForeignKey(ConventionSeries, default=None, blank=False, null=False, on_delete=models.PROTECT, related_name="banners")
show_up_after = models.DateTimeField(help_text="fill with the time on the timezone of the event.")
hide_after = models.DateTimeField(help_text="fill with the time on the timezone of the event.")
banner = models.ForeignKey(LanguageImage, default=None, on_delete=models.PROTECT, related_name='+')
reminder_title = 'Banner change'
kind = ''
class Meta:
ordering = ('show_up_after', '-pk', )
class MapImage(Remindable):
ordering = models.IntegerField(default=0)
convention = models.ForeignKey(ConventionEdition, default=None, blank=False, null=False, on_delete=models.PROTECT, related_name="maps")
name = models.ForeignKey(LanguagePhrase, blank=False, null=False, on_delete=models.PROTECT, related_name='+')
image = models.ForeignKey(LanguageImage, blank=False, null=False, on_delete=models.PROTECT, related_name='+')
reminder_title = 'Map'
kind = 'image'
class Meta:
ordering = ('convention__ceremony_opening_time', 'ordering', '-pk', )
class ConventionRegistrationLink(Remindable):
ordering = models.IntegerField(default=0)
convention = models.ForeignKey(ConventionEdition, default=None, blank=False, null=False, on_delete=models.PROTECT, related_name="registration_links")
name = models.ForeignKey(LanguagePhrase, blank=False, null=False, on_delete=models.PROTECT, related_name='+')
url = models.ForeignKey(LanguagePhrase, blank=False, null=False, on_delete=models.PROTECT, related_name='+')
color = models.ForeignKey(Color, on_delete=models.PROTECT, null=True, blank=True, related_name='+')
appears = models.DateTimeField(help_text="fill with the time on the timezone of the event.")
vanishes = models.DateTimeField(help_text="fill with the time on the timezone of the event.")
reminder_title = 'Registration'
kind = 'link'
class Meta:
ordering = ('convention__ceremony_opening_time', 'ordering', '-pk', )
class AdditionalRules(Timestampable):
convention = models.ForeignKey(ConventionEdition, blank=False, null=False, on_delete=models.PROTECT, related_name='additional_rules')
name = models.ForeignKey(LanguagePhrase, blank=False, null=False, on_delete=models.PROTECT, related_name='+')
rules = models.ForeignKey(LanguageRichText, blank=False, null=False, on_delete=models.PROTECT, related_name='+')
ordering = models.IntegerField(default=0, blank=True, null=False)
def __str__(self):
return f'Additional rules #{self.pk} @ {self.convention.name.en}: {self.name.en}'
class Meta:
ordering = ('ordering', '-pk',)