diff --git a/env_secrets/local_lorenz.env b/env_secrets/local_lorenz.env index 22665c98..2c971824 100644 Binary files a/env_secrets/local_lorenz.env and b/env_secrets/local_lorenz.env differ diff --git a/server/config/settings/base.py b/server/config/settings/base.py index bae81804..cb1c3daf 100644 --- a/server/config/settings/base.py +++ b/server/config/settings/base.py @@ -120,6 +120,7 @@ LOCAL_APPS = [ "vbv_lernwelt.files", "vbv_lernwelt.notify", "vbv_lernwelt.assignment", + "vbv_lernwelt.events", ] # https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS @@ -468,9 +469,9 @@ else: structlog.configure( processors=shared_processors - + [ - structlog.stdlib.ProcessorFormatter.wrap_for_formatter, - ], + + [ + structlog.stdlib.ProcessorFormatter.wrap_for_formatter, + ], context_class=dict, logger_factory=structlog.stdlib.LoggerFactory(), wrapper_class=structlog.stdlib.BoundLogger, diff --git a/server/vbv_lernwelt/events/__init__.py b/server/vbv_lernwelt/events/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/server/vbv_lernwelt/events/admin.py b/server/vbv_lernwelt/events/admin.py new file mode 100644 index 00000000..8c38f3f3 --- /dev/null +++ b/server/vbv_lernwelt/events/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/server/vbv_lernwelt/events/apps.py b/server/vbv_lernwelt/events/apps.py new file mode 100644 index 00000000..f0629a22 --- /dev/null +++ b/server/vbv_lernwelt/events/apps.py @@ -0,0 +1,13 @@ +from django.apps import AppConfig + + +class EventsConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "vbv_lernwelt.events" + + def ready(self): + try: + # pylint: disable=unused-import,import-outside-toplevel + import vbv_lernwelt.course.signals # noqa F401 + except ImportError: + pass diff --git a/server/vbv_lernwelt/events/factories.py b/server/vbv_lernwelt/events/factories.py new file mode 100644 index 00000000..c6bfa7c6 --- /dev/null +++ b/server/vbv_lernwelt/events/factories.py @@ -0,0 +1,18 @@ +from datetime import datetime + +from django.utils import timezone +from factory.django import DjangoModelFactory + +from .models import Event + + +def get_date(date_string): + return datetime.strptime(date_string, '%b %d %Y', ).astimezone(timezone.get_current_timezone()) + + +class EventFactory(DjangoModelFactory): + class Meta: + model = Event + + title = "Prüfung Versicherungsvermittler/-in" + end = get_date("Jan 01 2021") diff --git a/server/vbv_lernwelt/events/migrations/__init__.py b/server/vbv_lernwelt/events/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/server/vbv_lernwelt/events/models.py b/server/vbv_lernwelt/events/models.py new file mode 100644 index 00000000..e93284c3 --- /dev/null +++ b/server/vbv_lernwelt/events/models.py @@ -0,0 +1,67 @@ +import datetime + +from django.db import models +from django.utils import timezone +from django.utils.translation import gettext_lazy as _ + +from vbv_lernwelt.core.models import User +from vbv_lernwelt.course.models import CourseSession + + +class Event(models.Model): + start = models.DateTimeField(null=True, db_index=True) + end = models.DateTimeField(db_index=True) + title = models.CharField(default=_('Termin'), max_length=255) + course_session = models.ForeignKey( + 'course.CourseSession', + on_delete=models.CASCADE, + related_name='events', + null=True, + blank=True, + ) + + learning_content = models.ForeignKey( + 'learnpath.LearningContentAttendanceCourse', + on_delete=models.CASCADE, + related_name='events', + null=True, + blank=True, + ) + + def Meta(self): + ordering = ['start', 'end'] + verbose_name = _("Termin") + + def __str__(self): + return f"{self.title} {self.start}" + + @property + def duration(self): + if self.start is None: + return datetime.timedelta(0) + return self.end - self.start + + @classmethod + def get_users_next_events_qs(cls, user: User, course_session: CourseSession = None, limit=10): + """ + Returns a queryset of all events that are relevant for the given user. Ordered nearest start date first. + If course_session is given, only events for that course_session are returned. + The user is determined by via a course session user of an course_assignment. + + """ + qs = cls.get_next_events_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_events_qs(cls): + now = timezone.now() + qs = cls.objects.filter(end__gte=now) + return qs diff --git a/server/vbv_lernwelt/events/tests/__init__.py b/server/vbv_lernwelt/events/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/server/vbv_lernwelt/events/tests/test_event_model.py b/server/vbv_lernwelt/events/tests/test_event_model.py new file mode 100644 index 00000000..412e2190 --- /dev/null +++ b/server/vbv_lernwelt/events/tests/test_event_model.py @@ -0,0 +1,38 @@ +import datetime + +from django.test import TestCase +from django.utils import timezone + +from vbv_lernwelt.events.factories import EventFactory +from vbv_lernwelt.events.models import Event + + +class TestEventModel(TestCase): + def test_event_model_factory(self): + EventFactory() + assert Event.objects.count() == 1 + + def test_get_next_events_qs_is_really_next(self): + start = timezone.now() - datetime.timedelta(days=18) + generate_events(start=start) + self.assertEqual(Event.objects.count(), 20) + self.assertEqual(Event.get_next_events_qs().count(), 2) + + # def test_event_model_factory_validation(self): + # e = EventFactory() + # e.start = get_date("Jan 01 2021") + # e.end = get_date("Jan 02 2021") + # e.validate() + # self.assertTrue(True) + # + # def test_event_model_factory_validation_invalid(self): + # e = EventFactory() + # e.start = get_date("Jan 04 2021") + # e.end = get_date("Jan 02 2021") + # self.assertRaises(ValueError, e.validate) + + +def generate_events(start=timezone.now()): + for i in range(20): + EventFactory(title=f"{i}", start=start + datetime.timedelta(days=i), + end=start + datetime.timedelta(days=i, hours=1)) diff --git a/server/vbv_lernwelt/events/views.py b/server/vbv_lernwelt/events/views.py new file mode 100644 index 00000000..91ea44a2 --- /dev/null +++ b/server/vbv_lernwelt/events/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here.