Skip to content
Snippets Groups Projects
models.py 5.58 KiB
Newer Older
Nik | Klampfradler's avatar
Nik | Klampfradler committed
from django.db import models
from django.utils.translation import gettext_lazy as _
from calendarweek import CalendarWeek

from aleksis.apps.chronos.models import LessonPeriod
Tom Teichler's avatar
Tom Teichler committed
from aleksis.core.mixins import ExtensibleModel
from aleksis.core.util.core_helpers import get_site_preferences
def isidentifier(value: str) -> bool:
    return value.isidentifier()


class ExcuseType(ExtensibleModel):
    """An type of excuse.

    Can be used to count different types of absences separately.
    """

Jonathan Weth's avatar
Jonathan Weth committed
    short_name = models.CharField(
        max_length=255, unique=True, verbose_name=_("Short name")
    )
    name = models.CharField(max_length=255, unique=True, verbose_name=_("Name"))

    def __str__(self):
        return f"{self.name} ({self.short_name})"

    @property
    def count_label(self):
        return f"{self.short_name}_count"

    class Meta:
        ordering = ["name"]
        verbose_name = _("Excuse type")
        verbose_name_plural = _("Excuse types")


Tom Teichler's avatar
Tom Teichler committed
class PersonalNote(ExtensibleModel):
    """A personal note about a single person.

    Used in the class register to note absences, excuses
    and remarks about a student in a single lesson period.
    person = models.ForeignKey(
        "core.Person", models.CASCADE, related_name="personal_notes"
    )
    groups_of_person = models.ManyToManyField("core.Group", related_name="+")

    week = models.IntegerField()
    lesson_period = models.ForeignKey(
        "chronos.LessonPeriod", models.CASCADE, related_name="personal_notes"
    )

    absent = models.BooleanField(default=False)
    late = models.IntegerField(default=0)
    excused = models.BooleanField(default=False)
Jonathan Weth's avatar
Jonathan Weth committed
    excuse_type = models.ForeignKey(
        ExcuseType,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        verbose_name=_("Excuse type"),
    )

    remarks = models.CharField(max_length=200, blank=True)

Jonathan Weth's avatar
Jonathan Weth committed
    extra_marks = models.ManyToManyField(
        "ExtraMark", null=True, blank=True, verbose_name=_("Extra marks")
    )

    def save(self, *args, **kwargs):
        if self.excuse_type:
            self.excused = True
        super().save(*args, **kwargs)

        verbose_name = _("Personal note")
        verbose_name_plural = _("Personal notes")
        unique_together = [["lesson_period", "week", "person"]]
        ordering = [
            "lesson_period__lesson__validity__date_start",
            "week",
            "lesson_period__period__weekday",
            "lesson_period__period__period",
            "person__last_name",
            "person__first_name",
        ]
Tom Teichler's avatar
Tom Teichler committed
class LessonDocumentation(ExtensibleModel):
    """A documentation on a single lesson period.

    Non-personal, includes the topic and homework of the lesson.
    week = models.IntegerField()
    lesson_period = models.ForeignKey(
        "chronos.LessonPeriod", models.CASCADE, related_name="documentations"
    )
    topic = models.CharField(verbose_name=_("Lesson topic"), max_length=200, blank=True)
    homework = models.CharField(verbose_name=_("Homework"), max_length=200, blank=True)
Jonathan Weth's avatar
Jonathan Weth committed
    group_note = models.CharField(
        verbose_name=_("Group note"), max_length=200, blank=True
    )
Jonathan Weth's avatar
Jonathan Weth committed
    def _carry_over_data(self):
        """Carry over data to directly adjacent periods in this lesson if data is not already set.
Jonathan Weth's avatar
Jonathan Weth committed
        Can be deactivated using site preference ``alsijil__carry_over``.
        following_periods = LessonPeriod.objects.filter(
            lesson=self.lesson_period.lesson,
            period__weekday=self.lesson_period.period.weekday,
            period__period__gt=self.lesson_period.period.period,
        )
        for period in following_periods:
            lesson_documentation = period.get_or_create_lesson_documentation(
                CalendarWeek(
                    week=self.week, year=self.lesson_period.lesson.get_year(self.week),
            if not lesson_documentation.topic:
                lesson_documentation.topic = self.topic
                changed = True
            if not lesson_documentation.homework:
                lesson_documentation.homework = self.homework
                changed = True
            if not lesson_documentation.group_note:
                lesson_documentation.group_note = self.group_note
                changed = True
            if changed:
                lesson_documentation.save()
        if get_site_preferences()["alsijil__carry_over"] and (
            self.topic or self.homework or self.group_note
        ):
            self._carry_over_data()
        verbose_name = _("Lesson documentation")
        verbose_name_plural = _("Lesson documentations")
        unique_together = [["lesson_period", "week"]]
        ordering = [
            "lesson_period__lesson__validity__date_start",
            "week",
            "lesson_period__period__weekday",
            "lesson_period__period__period",
        ]
Jonathan Weth's avatar
Jonathan Weth committed
class ExtraMark(ExtensibleModel):
    """A model for extra marks.

    Can be used for lesson-based counting of things (like forgotten homework).
    """

    short_name = models.CharField(
        max_length=255, unique=True, verbose_name=_("Short name")
    )
    name = models.CharField(max_length=255, unique=True, verbose_name=_("Name"))

    def __str__(self):
Jonathan Weth's avatar
Jonathan Weth committed

    @property
    def count_label(self):
        return f"{self.short_name}_count"

    class Meta:
        ordering = ["short_name"]
        verbose_name = _("Extra mark")
        verbose_name_plural = _("Extra marks")