Rename Event -> DueDate
This commit is contained in:
parent
f43a2c94e8
commit
f05d7b2279
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
@ -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:
|
||||||
|
|
@ -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()
|
||||||
|
|
@ -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()
|
||||||
|
|
@ -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')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -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'),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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))
|
||||||
|
|
@ -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"]
|
|
||||||
|
|
@ -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()
|
|
||||||
|
|
@ -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))
|
|
||||||
Loading…
Reference in New Issue