Newer
Older
from django.urls import reverse
from django.utils.formats import date_format
from django.utils.translation import gettext_lazy as _

Jonathan Weth
committed
from calendarweek import CalendarWeek
from aleksis.apps.alsijil.data_checks import (
ExcusesWithoutAbsences,
LessonDocumentationOnHolidaysDataCheck,
NoGroupsOfPersonsSetInPersonalNotesDataCheck,
NoPersonalNotesInCancelledLessonsDataCheck,
PersonalNoteOnHolidaysDataCheck,
)
from aleksis.apps.alsijil.managers import PersonalNoteManager
from aleksis.apps.chronos.mixins import WeekRelatedMixin

Jonathan Weth
committed
from aleksis.apps.chronos.models import LessonPeriod
from aleksis.apps.chronos.util.date import get_current_year

Jonathan Weth
committed
from aleksis.core.util.core_helpers import get_site_preferences
from aleksis.core.util.model_helpers import COLOURS, ICONS
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.
"""
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")
class PersonalNote(ExtensibleModel, WeekRelatedMixin):
"""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.
data_checks = [
NoPersonalNotesInCancelledLessonsDataCheck,
NoGroupsOfPersonsSetInPersonalNotesDataCheck,
PersonalNoteOnHolidaysDataCheck,
ExcusesWithoutAbsences,
]
objects = PersonalNoteManager()
person = models.ForeignKey("core.Person", models.CASCADE, related_name="personal_notes")
groups_of_person = models.ManyToManyField("core.Group", related_name="+")
week = models.IntegerField()
year = models.IntegerField(verbose_name=_("Year"), default=get_current_year)
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)
ExcuseType, on_delete=models.SET_NULL, null=True, blank=True, verbose_name=_("Excuse type"),
remarks = models.CharField(max_length=200, blank=True)
extra_marks = models.ManyToManyField("ExtraMark", blank=True, verbose_name=_("Extra marks"))
def save(self, *args, **kwargs):
if self.excuse_type:
self.excused = True
if not self.absent:
self.excused = False
self.excuse_type = None
def reset_values(self):
"""Reset all saved data to default values.
.. warning ::
This won't save the data, please execute ``save`` extra.
defaults = PersonalNote()
self.absent = defaults.absent
self.late = defaults.late
self.excused = defaults.excused
self.excuse_type = defaults.excuse_type
self.remarks = defaults.remarks
self.extra_marks.clear()
def __str__(self):
return f"{date_format(self.date)}, {self.lesson_period}, {self.person}"
def get_absolute_url(self):
return (
reverse(
"lesson_by_week_and_period", args=[self.year, self.week, self.lesson_period.pk],
)
+ "#personal-notes"
)
verbose_name = _("Personal note")
verbose_name_plural = _("Personal notes")
unique_together = [["lesson_period", "week", "person"]]
ordering = [
"week",
"lesson_period__period__weekday",
"lesson_period__period__period",
"person__last_name",
"person__first_name",
]
class LessonDocumentation(ExtensibleModel, WeekRelatedMixin):
"""A documentation on a single lesson period.
Non-personal, includes the topic and homework of the lesson.
data_checks = [LessonDocumentationOnHolidaysDataCheck]
week = models.IntegerField()
year = models.IntegerField(verbose_name=_("Year"), default=get_current_year)
"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)
group_note = models.CharField(verbose_name=_("Group note"), max_length=200, blank=True)
"""Carry over data to directly adjacent periods in this lesson if data is not already set.

Jonathan Weth
committed
Can be deactivated using site preference ``alsijil__carry_over``.

Jonathan Weth
committed
"""
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.year)

Jonathan Weth
committed

Jonathan Weth
committed
if not lesson_documentation.topic:
lesson_documentation.topic = self.topic
changed = True

Jonathan Weth
committed
if not lesson_documentation.homework:
lesson_documentation.homework = self.homework
changed = True

Jonathan Weth
committed
if not lesson_documentation.group_note:
lesson_documentation.group_note = self.group_note
changed = True

Jonathan Weth
committed
if changed:
lesson_documentation.save()

Jonathan Weth
committed
def __str__(self):
return f"{self.lesson_period}, {date_format(self.date)}"
def get_absolute_url(self):
return reverse(
"lesson_by_week_and_period", args=[self.year, self.week, self.lesson_period.pk],
)

Jonathan Weth
committed
def save(self, *args, **kwargs):
if get_site_preferences()["alsijil__carry_over"] and (
self.topic or self.homework or self.group_note
):
self._carry_over_data()

Jonathan Weth
committed
super().save(*args, **kwargs)
verbose_name = _("Lesson documentation")
verbose_name_plural = _("Lesson documentations")
unique_together = [["lesson_period", "week"]]
ordering = [
"week",
"lesson_period__period__weekday",
"lesson_period__period__period",
]
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):
return f"{self.name}"
@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")
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
class ClassRole(ExtensibleModel):
name = models.CharField(max_length=255, verbose_name=_("Name"))
icon = models.CharField(max_length=50, blank=True, choices=ICONS, verbose_name=_("Icon"))
colour = models.CharField(max_length=50, blank=True, choices=COLOURS, verbose_name=_("Colour"))
def __str__(self):
return self.name
class Meta:
verbose_name = _("Class role")
verbose_name_plural = _("Class roles")
class ClassRoleAssignment(ExtensibleModel):
role = models.ForeignKey(
ClassRole,
on_delete=models.CASCADE,
related_name="assignments",
verbose_name=_("Class role"),
)
person = models.ForeignKey(
"core.Person",
on_delete=models.CASCADE,
related_name="class_roles",
verbose_name=_("Assigned person"),
)
group = models.ForeignKey(
"core.Group",
on_delete=models.CASCADE,
related_name="class_roles",
verbose_name=_("Group"),
blank=True,
null=True,
)
date_start = models.DateField(verbose_name=_("Start date"))
date_end = models.DateField(
blank=True,
null=True,
verbose_name=_("End date"),
help_text=_("Can be left empty if end date is not clear yet"),
)
def __str__(self):
date_end = date_format(self.date_end) if self.date_end else "?"
return f"{self.role}: {self.person}, {date_format(self.date_start)}–{date_end}"
class Meta:
verbose_name = _("Class role assignment")
verbose_name_plural = _("Class role assignments")
class AlsijilGlobalPermissions(ExtensibleModel):
class Meta:
managed = False
permissions = (
("view_week", _("Can view week overview")),
("register_absence", _("Can register absence")),
("list_personal_note_filters", _("Can list all personal note filters")),
)