import datetime from django.db import models from django.utils import timezone from wagtail.models import Page from vbv_lernwelt.core.models import User from vbv_lernwelt.course.models import CourseSession class DueDate(models.Model): start = models.DateTimeField( null=True, db_index=True, help_text="Startdatum ist Pflicht" ) end = models.DateTimeField( null=True, blank=True, db_index=True, help_text="Enddatum ist optional" ) manual_override_fields = models.BooleanField( default=False, help_text="Nur aktivieren, wenn man die Felder manuell überschreiben will", ) title = models.CharField( default="", max_length=1024, help_text="Title wird standarmässig vom LearningContent übernommen", ) assignment_type_translation_key = models.CharField( default="", blank=True, max_length=1024, help_text="Translation Key aus dem Frontend", ) date_type_translation_key = models.CharField( default="", blank=True, max_length=1024, help_text="Translation Key aus dem Frontend", ) subtitle = models.TextField( default="", blank=True, help_text="Überschreibt den Untertitel bei `assignment_type_translation_key` und `date_type_translation_key`", ) url = models.CharField( default="", blank=True, max_length=1024, help_text="URL wird vom LearningContent übernommen (sichtbar für Member/Teilnehmer)", ) url_expert = models.CharField( default="", blank=True, max_length=1024, help_text="URL wird aus dem LearningContent generiert (sichtbar für den Experten/Trainer)", ) course_session = models.ForeignKey( "course.CourseSession", on_delete=models.CASCADE, blank=True, ) page = models.ForeignKey(Page, on_delete=models.SET_NULL, null=True, blank=True) circle_data = models.JSONField(default=dict, blank=True) class Meta: ordering = ["start", "end"] def __str__(self): if self.is_undefined: return f"{self.title} undefined" # Convert the UTC datetime to local time local_start = timezone.localtime(self.start) if self.start else None start_str = local_start.strftime("%Y-%m-%d %H:%M") if local_start else "-" result = f"{self.title} {start_str}" if self.end: local_end = timezone.localtime(self.end) if self.end else None end_str = local_end.strftime("%Y-%m-%d %H:%M") if local_end else "-" result += f" - {end_str}" return result def save(self, *args, **kwargs): try: circle = self.get_circle() # prefetch circle data, because loading it dynamically is too slow if circle: self.circle_data = { "id": str(circle.id), "title": circle.title, "slug": circle.slug, } except Exception: # noop pass super().save(*args, **kwargs) @property def display_subtitle(self): result = "" if self.subtitle and self.manual_override_fields: result = self.subtitle result = self.assignment_type_translation_key if self.date_type_translation_key: result += ": " + self.date_type_translation_key return result @property def is_undefined(self): return self.start is None @property def duration(self): if self.end is None: return datetime.timedelta(0) return self.end - self.start def get_circle(self): try: return self.page.specific.get_circle() except Exception: # noop return None @classmethod def get_users_next_events_qs( cls, user: User, course_session: CourseSession = None, limit=10 ): """ Returns a queryset of all due dates that are relevant for the given user. If course_session is given, only due dates for that course_session are returned. The user is determined by via a course session user of a course_assignment. """ qs = cls.get_next_due_dates_qs() if course_session: qs = qs.filter( course_session=course_session, course_session__course_assignment__user=user, ) else: qs = qs.filter(course_session__course_assignment__user=user) qs = qs.order_by("start")[:limit] return qs @classmethod def get_next_due_dates_qs(cls): now = timezone.now() qs = cls.objects.filter(start__gte=now) return qs