-
Tomáš Valenta authoredTomáš Valenta authored
models.py 6.85 KiB
import mimetypes
import uuid
from datetime import datetime, timedelta
from django.contrib.auth.models import Group
from django.core.exceptions import ValidationError
from django.db import models
from django.db.models.fields.files import FieldFile
from django.urls import reverse
from django.utils import timezone
from django.utils.safestring import mark_safe
from markdownx.models import MarkdownxField
from shared.models import NameStrMixin
from . import settings as app_settings
# Create your models here.
class LectureGroup(NameStrMixin, models.Model):
name = models.CharField(
max_length=128,
verbose_name="Jméno",
)
description = MarkdownxField(
null=True,
blank=True,
verbose_name="Popis",
help_text="Můžeš použít Markdown.",
)
priority = models.IntegerField(
verbose_name="Priorita",
help_text="Čím nižší číslo, tím výš se skupina zobrazí."
)
user_groups = models.ManyToManyField(
Group,
blank=True,
verbose_name="Uživatelské skupiny",
help_text="Pokud žádné nedefinuješ, školení ve skupině jsou dostupná všem.",
)
class Meta:
verbose_name = "Výuková skupina"
verbose_name_plural = "Výukové skupiny"
ordering = ("priority", "name")
class Lecture(NameStrMixin, models.Model):
is_current_starting_treshold = timedelta(hours=8)
is_current_ending_treshold = timedelta(days=60)
timestamp = models.DateTimeField(
verbose_name="Datum a čas konání",
blank=True,
null=True,
) # If undefined, assume this event was in the past
class TypeChoices(models.TextChoices):
RECOMMENDED = "recommended", "Doporučené školení"
OPTIONAL = "optional", "Volitelné školení"
groups = models.ManyToManyField(
LectureGroup,
blank=True,
related_name="lectures",
verbose_name="Výukové skupiny",
help_text="Pokud nevybereš žádné skupiny, školení je dostupné všem.",
)
type = models.CharField(
choices=TypeChoices.choices,
max_length=11,
verbose_name="Typ",
)
name = models.CharField(
max_length=128,
verbose_name="Název",
)
description = MarkdownxField(
blank=True,
null=True,
verbose_name="Popis",
help_text="Můžeš použít Markdown.",
)
# Settings
settings = app_settings.LectureSettings("Nastavení")
class Meta:
verbose_name = "Školení"
verbose_name_plural = verbose_name
ordering = ("-timestamp", "-name")
class LectureLector(NameStrMixin, models.Model):
lecture = models.ForeignKey(
"Lecture",
on_delete=models.CASCADE,
related_name="lectors",
verbose_name="Školení",
)
name = models.CharField(
max_length=128,
verbose_name="Jméno",
)
url = models.URLField(
max_length=256,
blank=True,
null=True,
verbose_name="Odkaz",
help_text=mark_safe("Běžně na <a href=\"https://lide.pirati.cz\">aplikaci Lidé</a>.")
)
username = models.CharField(
max_length=128,
blank=True,
null=True,
verbose_name="Uživatelské jméno",
help_text=(
"Např. na fóru, nebo v Chobotnici. Užívá se "
"k synchronizaci profilového obrázku."
),
)
class Meta:
verbose_name = "Lektor"
verbose_name_plural = "Lektoři"
class LectureRecording(NameStrMixin, models.Model):
lecture = models.ForeignKey(
"Lecture",
on_delete=models.CASCADE,
related_name="recordings",
verbose_name="Školení",
)
name = models.CharField(
max_length=128,
verbose_name="Název",
)
link = models.URLField(
max_length=256,
blank=True,
null=True,
verbose_name="Odkaz",
help_text=mark_safe("Běžně na <a href=\"https://tv.pirati.cz\">Pirátskou TV</a>.")
)
class Meta:
verbose_name = "Nahrávka"
verbose_name_plural = "Nahrávky"
def get_lecture_material_file_location(instance, filename):
mimetypes_instance = mimetypes.MimeTypes()
current_time = datetime.today()
guessed_type = mimetypes_instance.guess_type(filename, strict=False)[0]
extension = ""
if guessed_type is not None:
for mapper in mimetypes_instance.types_map_inv:
if guessed_type not in mapper:
continue
extension = mapper[guessed_type]
if isinstance(extension, list):
extension = extension[0]
break
return (
"_private/"
f"{current_time.year}/{current_time.month}/{current_time.day}/"
f"{uuid.uuid4()}{extension}"
)
class LectureMaterialFileProxy(FieldFile):
@property
def url(self) -> str:
return reverse(
"lectures:download_material_file",
args=(str(self.instance.id),)
)
class LectureMaterialFileField(models.FileField):
attr_class = LectureMaterialFileProxy
class LectureMaterial(NameStrMixin, models.Model):
lecture = models.ForeignKey(
"Lecture",
on_delete=models.CASCADE,
related_name="materials",
verbose_name="Školení",
)
name = models.CharField(
max_length=128,
verbose_name="Název",
)
link = models.URLField(
max_length=256,
blank=True,
null=True,
verbose_name="Odkaz",
help_text="Pokud máš zadaný odkaz, nemůžeš definovat soubor.",
)
file = LectureMaterialFileField(
blank=True,
null=True,
upload_to=get_lecture_material_file_location,
verbose_name="Soubor",
help_text="Pokud máš vložený soubor, nemůžeš definovat odkaz.",
)
@property
def protected_file_url(self) -> str:
return reverse(
"lectures:download_material_file",
args=(self.id,),
)
def clean(self) -> None:
BOTH_FILE_AND_LINK_DEFINED = (
"Definuj prosím pouze odkaz, nebo soubor. Nemůžeš mít oboje najednou."
)
NEITHER_FILE_NOR_LINK_DEFINED = (
"Definuj prosím odkaz, nebo soubor. Aspoň jedna hodnota musí být vyplněna."
)
if not self.file and not self.link:
raise ValidationError(
{
"link": NEITHER_FILE_NOR_LINK_DEFINED,
"file": NEITHER_FILE_NOR_LINK_DEFINED,
}
)
if self.file and self.link:
raise ValidationError(
{
"link": BOTH_FILE_AND_LINK_DEFINED,
"file": BOTH_FILE_AND_LINK_DEFINED,
}
)
class Meta:
verbose_name = "Materiál"
verbose_name_plural = "Materiály"