375 lines
15 KiB
Python
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',)
|