Rename Event -> DueDate

This commit is contained in:
Lorenz Padberg 2023-06-14 11:33:39 +02:00
parent f43a2c94e8
commit f05d7b2279
19 changed files with 164 additions and 89 deletions

View File

@ -120,7 +120,7 @@ LOCAL_APPS = [
"vbv_lernwelt.files", "vbv_lernwelt.files",
"vbv_lernwelt.notify", "vbv_lernwelt.notify",
"vbv_lernwelt.assignment", "vbv_lernwelt.assignment",
"vbv_lernwelt.events", "vbv_lernwelt.duedate",
] ]
# https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps # https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps
INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS

View File

@ -29,4 +29,4 @@ def command():
call_command("migrate") call_command("migrate")
call_command("create_default_users") call_command("create_default_users")
call_command("create_default_courses") call_command("create_default_courses")
call_command("create_default_events") call_command("create_default_duedates")

View File

@ -0,0 +1,34 @@
from django.contrib import admin
from wagtail.models import Page
from vbv_lernwelt.duedate.models import DueDate
from vbv_lernwelt.learnpath.models import (
LearningContentAttendanceCourse,
LearningContentTest,
)
# Register your models here.
@admin.register(DueDate)
class DueDateAdmin(admin.ModelAdmin):
date_hierarchy = "end"
list_display = [
"title",
"course_session",
"start",
"end",
"unset"
]
list_filter = ["course_session"]
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == "page":
if request.resolver_match.kwargs.get("object_id"):
object_id = int(request.resolver_match.kwargs.get("object_id"))
csd = DueDate.objects.get(id=object_id)
kwargs["queryset"] = Page.objects.descendant_of(
csd.course_session.course.coursepage
).exact_type(LearningContentAttendanceCourse, LearningContentTest)
else:
kwargs["queryset"] = Page.objects.none()
return super().formfield_for_foreignkey(db_field, request, **kwargs)

View File

@ -3,7 +3,7 @@ from django.apps import AppConfig
class EventsConfig(AppConfig): class EventsConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField" default_auto_field = "django.db.models.BigAutoField"
name = "vbv_lernwelt.events" name = "vbv_lernwelt.duedate"
def ready(self): def ready(self):
try: try:

View File

@ -4,7 +4,7 @@ import structlog
from django.utils import timezone from django.utils import timezone
from factory.django import DjangoModelFactory from factory.django import DjangoModelFactory
from .models import Event from .models import DueDate
from ..assignment.models import Assignment from ..assignment.models import Assignment
from ..course.models import CourseSession from ..course.models import CourseSession
from ..learnpath.models import LearningContentAttendanceCourse from ..learnpath.models import LearningContentAttendanceCourse
@ -16,9 +16,9 @@ def get_date(date_string):
return datetime.datetime.strptime(date_string, '%b %d %Y', ).astimezone(timezone.get_current_timezone()) return datetime.datetime.strptime(date_string, '%b %d %Y', ).astimezone(timezone.get_current_timezone())
class EventFactory(DjangoModelFactory): class DueDateFactory(DjangoModelFactory):
class Meta: class Meta:
model = Event model = DueDate
title = "Prüfung Versicherungsvermittler/-in" title = "Prüfung Versicherungsvermittler/-in"
end = get_date("Jan 01 2021") end = get_date("Jan 01 2021")
@ -26,8 +26,8 @@ class EventFactory(DjangoModelFactory):
def generate_events(start=timezone.now()): def generate_events(start=timezone.now()):
for i in range(20): for i in range(20):
EventFactory(title=f"{i}", start=start + datetime.timedelta(days=i), DueDateFactory(title=f"{i}", start=start + datetime.timedelta(days=i),
end=start + datetime.timedelta(days=i, hours=1)) end=start + datetime.timedelta(days=i, hours=1))
def hour_rounder(t): def hour_rounder(t):
@ -36,14 +36,14 @@ def hour_rounder(t):
+ datetime.timedelta(hours=t.minute // 30)) + datetime.timedelta(hours=t.minute // 30))
def create_events_for_all_course_sessions(): def create_duedates_for_all_course_sessions():
all_course_sessions: list[CourseSession] = CourseSession.objects.all() all_course_sessions: list[CourseSession] = CourseSession.objects.all()
for course_session in all_course_sessions: for course_session in all_course_sessions:
create_events_for_course_session(course_session) create_duedates_for_course_session(course_session)
def create_events_for_course_session(course_session: CourseSession): def create_duedates_for_course_session(course_session: CourseSession):
course = course_session.course course = course_session.course
attendance_courses = list(LearningContentAttendanceCourse.objects.descendant_of(course.get_learning_path())) attendance_courses = list(LearningContentAttendanceCourse.objects.descendant_of(course.get_learning_path()))
assignments = list(Assignment.objects.descendant_of(course.get_learning_path())) assignments = list(Assignment.objects.descendant_of(course.get_learning_path()))
@ -53,17 +53,20 @@ def create_events_for_course_session(course_session: CourseSession):
if callable(getattr(content, 'get_frontend_url', None)): if callable(getattr(content, 'get_frontend_url', None)):
url = content.get_frontend_url() url = content.get_frontend_url()
event, created = Event.objects.get_or_create(course_session=course_session, title=content.title, url=url) duedate, created = DueDate.objects.get_or_create(course_session=course_session,
title=content.title,
url=url,
page=content.specific)
if created: if created:
logger.info(f"Created event {event} for course session {course_session} and content {content}") pass
logger.info("Created duedate ", duedate=duedate, course_session=course_session, content=content)
# def set_default_times_for_duedates():
def set_default_times_for_events():
now = hour_rounder(timezone.now()) now = hour_rounder(timezone.now())
for i, event in enumerate(Event.objects.filter(end__isnull=True)): for i, event in enumerate(DueDate.objects.filter(end__isnull=True)):
event.start = now + datetime.timedelta(days=i) event.start = now + datetime.timedelta(days=i)
event.end = event.start + datetime.timedelta(hours=3) event.end = event.start + datetime.timedelta(hours=3)
event.save() event.save()

View File

@ -0,0 +1,9 @@
import djclick as click
from vbv_lernwelt.duedate.factories import create_duedates_for_all_course_sessions, set_default_times_for_duedates
@click.command()
def command():
create_duedates_for_all_course_sessions()
set_default_times_for_duedates()

View File

@ -0,0 +1,28 @@
# Generated by Django 3.2.13 on 2023-06-14 09:29
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
('course', '0004_import_fields'),
]
operations = [
migrations.CreateModel(
name='DueDate',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('start', models.DateTimeField(db_index=True, null=True)),
('end', models.DateTimeField(db_index=True, null=True)),
('title', models.CharField(default='Termin', max_length=1024)),
('url', models.URLField(blank=True, max_length=1024, null=True)),
('learning_content_id', models.CharField(blank=True, max_length=255, null=True)),
('course_session', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='events', to='course.coursesession')),
],
),
]

View File

@ -0,0 +1,24 @@
# Generated by Django 3.2.13 on 2023-06-14 13:00
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('wagtailcore', '0083_workflowcontenttype'),
('duedate', '0001_initial'),
]
operations = [
migrations.RemoveField(
model_name='duedate',
name='learning_content_id',
),
migrations.AddField(
model_name='duedate',
name='page',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='wagtailcore.page'),
),
]

View File

@ -3,12 +3,13 @@ import datetime
from django.db import models from django.db import models
from django.utils import timezone from django.utils import timezone
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from wagtail.models import Page
from vbv_lernwelt.core.models import User from vbv_lernwelt.core.models import User
from vbv_lernwelt.course.models import CourseSession from vbv_lernwelt.course.models import CourseSession
class Event(models.Model): class DueDate(models.Model):
start = models.DateTimeField(null=True, db_index=True) start = models.DateTimeField(null=True, db_index=True)
end = models.DateTimeField(db_index=True, null=True) end = models.DateTimeField(db_index=True, null=True)
title = models.CharField(default=_('Termin'), max_length=1024) title = models.CharField(default=_('Termin'), max_length=1024)
@ -21,14 +22,16 @@ class Event(models.Model):
blank=True, blank=True,
) )
learning_content_id = models.CharField(blank=True, null=True, max_length=255) page = models.ForeignKey(Page, on_delete=models.SET_NULL, null=True, blank=True)
def Meta(self): def Meta(self):
ordering = ['start', 'end'] ordering = ['start', 'end']
verbose_name = _("Termin") verbose_name = _("Termin")
def __str__(self): def __str__(self):
return f"Event: {self.title} {self.start} to {self.end}" start_str = self.start.strftime('%Y-%m-%d %H:%M') if self.start else ''
end_str = self.end.strftime('%Y-%m-%d %H:%M') if self.end else ''
return f"DueDate: {self.title} {start_str} to {end_str}"
@property @property
def unset(self): def unset(self):
@ -43,12 +46,12 @@ class Event(models.Model):
@classmethod @classmethod
def get_users_next_events_qs(cls, user: User, course_session: CourseSession = None, limit=10): 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. Returns a queryset of all duedates 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. If course_session is given, only duedates for that course_session are returned.
The user is determined by via a course session user of an course_assignment. The user is determined by via a course session user of a course_assignment.
""" """
qs = cls.get_next_events_qs() qs = cls.get_next_duedates_qs()
if course_session: if course_session:
qs = qs.filter(course_session=course_session, course_session__course_assignment__user=user) qs = qs.filter(course_session=course_session, course_session__course_assignment__user=user)
@ -60,7 +63,7 @@ class Event(models.Model):
return qs return qs
@classmethod @classmethod
def get_next_events_qs(cls): def get_next_duedates_qs(cls):
now = timezone.now() now = timezone.now()
qs = cls.objects.filter(end__gte=now) qs = cls.objects.filter(end__gte=now)
return qs return qs

View File

@ -0,0 +1,38 @@
import datetime
from django.test import TestCase
from django.utils import timezone
from vbv_lernwelt.duedate.factories import DueDateFactory
from vbv_lernwelt.duedate.models import DueDate
class TesDueDatetModel(TestCase):
def test_duedate_model_factory(self):
DueDateFactory()
assert DueDate.objects.count() == 1
def test_get_next_duedate_qs_is_really_next(self):
start = timezone.now() - datetime.timedelta(days=18)
generate_duedates(start=start)
self.assertEqual(DueDate.objects.count(), 20)
self.assertEqual(DueDate.get_next_duedates_qs().count(), 2)
# def test_event_model_factory_validation(self):
# e = DueDateFactory()
# 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 = DueDateFactory()
# e.start = get_date("Jan 04 2021")
# e.end = get_date("Jan 02 2021")
# self.assertRaises(ValueError, e.validate)
def generate_duedates(start=timezone.now()):
for i in range(20):
DueDateFactory(title=f"{i}", start=start + datetime.timedelta(days=i),
end=start + datetime.timedelta(days=i, hours=1))

View File

@ -1,17 +0,0 @@
from django.contrib import admin
from vbv_lernwelt.events.models import Event
# Register your models here.
@admin.register(Event)
class EventAdmin(admin.ModelAdmin):
date_hierarchy = "end"
list_display = [
"title",
"course_session",
"start",
"end",
"unset"
]
list_filter = ["course_session"]

View File

@ -1,9 +0,0 @@
import djclick as click
from vbv_lernwelt.events.factories import create_events_for_all_course_sessions, set_default_times_for_events
@click.command()
def command():
create_events_for_all_course_sessions()
set_default_times_for_events()

View File

@ -1,38 +0,0 @@
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))