-
Jonathan Weth authoredJonathan Weth authored
views.py 9.75 KiB
from collections import OrderedDict
from datetime import date, datetime, timedelta, time
from typing import Optional, Union
from django.contrib.auth.decorators import login_required
from django.db.models import Count, Max, Min
from django.http import HttpRequest, HttpResponse, HttpResponseNotFound
from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse
from django.utils import timezone
from django.utils.translation import ugettext as _
from django_tables2 import RequestConfig
from aleksis.core.decorators import admin_required
from aleksis.core.models import Person, Group
from aleksis.core.util import messages
from .forms import LessonSubstitutionForm
from .models import LessonPeriod, LessonSubstitution, TimePeriod, Room
from .tables import LessonsTable, SubstitutionsTable
from .util import CalendarWeek, get_weeks_for_year
# Determine overall first and last day and period
min_max = TimePeriod.objects.aggregate(
Min("period"), Max("period"), Min("weekday"), Max("weekday"), Min("time_start"), Max("time_end")
)
period_min = min_max.get("period__min", 1)
period_max = min_max.get("period__max", 7)
time_min = min_max.get("time_start__min", None)
time_max = min_max.get("time_end__max", None)
weekday_min_ = min_max.get("weekday__min", 0)
weekday_max = min_max.get("weekday__max", 6)
def get_next_relevant_day(day: Union[date, None] = None, time: Union[time, None] = None):
if day is None:
day = timezone.now().date()
if time is not None:
if time > time_max:
day += timedelta(days=1)
cw = CalendarWeek.from_date(day)
# Remap to Sunday first
weekday = 0 if day.weekday() == 6 else day.weekday() + 1
if weekday > weekday_max or (weekday < weekday_min_):
if weekday > weekday_max or weekday == 0:
cw += 1
# Remap to Monday first
weekday_min = weekday_min_ - 1
# TODO: Probably causes problems
day = cw[weekday_min]
return day
@login_required
def all(request: HttpRequest) -> HttpResponse:
context = {}
teachers = Person.objects.annotate(lessons_count=Count("lessons_as_teacher")).filter(lessons_count__gt=0)
classes = Group.objects.annotate(lessons_count=Count("lessons")).filter(lessons_count__gt=0, parent_groups=None)
rooms = Room.objects.annotate(lessons_count=Count("lesson_periods")).filter(lessons_count__gt=0)
context['teachers'] = teachers
context['classes'] = classes
context['rooms'] = rooms
return render(request, 'chronos/quicklaunch.html', context)
@login_required
def timetable(
request: HttpRequest, _type: str, pk: int, year: Optional[int] = None, week: Optional[int] = None
) -> HttpResponse:
context = {}
if _type == "group":
el = get_object_or_404(Group, pk=pk)
elif _type == "teacher":
el = get_object_or_404(Person, pk=pk)
elif _type == "room":
el = get_object_or_404(Room, pk=pk)
else:
return HttpResponseNotFound()
if year and week:
wanted_week = CalendarWeek(year=year, week=week)
else:
# TODO: On not used days show next week
wanted_week = CalendarWeek()
lesson_periods = LessonPeriod.objects.in_week(wanted_week)
lesson_periods = lesson_periods.filter_from_type(_type, pk)
# else:
# # Redirect to a selected view if no filter provided
# if request.user.person:
# if request.user.person.primary_group:
# return redirect(
# reverse("timetable") + "?group=%d" % request.user.person.primary_group.pk
# )
# elif lesson_periods.filter(lesson__teachers=request.user.person).exists():
# return redirect(reverse("timetable") + "?teacher=%d" % request.user.person.pk)
# Regroup lesson periods per weekday
per_period = {}
for lesson_period in lesson_periods:
print(lesson_period.period)
added = False
if lesson_period.period.period in per_period :
if lesson_period.period.weekday in per_period[lesson_period.period.period]:
print("HEY HEY")
print(per_period[lesson_period.period.period][lesson_period.period.weekday])
per_period[lesson_period.period.period][lesson_period.period.weekday].append(lesson_period)
added =True
if not added:
per_period.setdefault(lesson_period.period.period, {})[
lesson_period.period.weekday
] = [lesson_period]
print(per_period)
# Fill in empty lessons
for period_num in range(period_min, period_max + 1):
print(period_num)
# Fill in empty weekdays
if period_num not in per_period.keys():
per_period[period_num] = {}
# Fill in empty lessons on this workday
for weekday_num in range(weekday_min_, weekday_max + 1):
if weekday_num not in per_period[period_num].keys():
per_period[period_num][weekday_num] = []
# Order this weekday by periods
per_period[period_num] = OrderedDict(sorted(per_period[period_num].items()))
print(lesson_periods)
context["lesson_periods"] = OrderedDict(sorted(per_period.items()))
context["periods"] = TimePeriod.get_times_dict()
context["weekdays"] = dict(TimePeriod.WEEKDAY_CHOICES[weekday_min_:weekday_max + 1])
context["weekdays_short"] = dict(TimePeriod.WEEKDAY_CHOICES_SHORT[weekday_min_:weekday_max + 1])
context["weeks"] = get_weeks_for_year(year=wanted_week.year)
context["week"] = wanted_week
context["type"] = _type
context["pk"] = pk
context["el"] = el
context["smart"] = True
week_prev = wanted_week - 1
week_next = wanted_week + 1
context["url_prev"] = reverse("timetable_by_week", args=[_type, pk, week_prev.year, week_prev.week])
context["url_next"] = reverse("timetable_by_week", args=[_type, pk, week_next.year, week_next.week])
return render(request, "chronos/plan.html", context)
@login_required
def lessons_day(request: HttpRequest, when: Optional[str] = None) -> HttpResponse:
context = {}
if when:
day = datetime.strptime(when, "%Y-%m-%d").date()
else:
day = date.today()
# Get lessons
lesson_periods = LessonPeriod.objects.on_day(day)
# Build table
lessons_table = LessonsTable(lesson_periods.all())
RequestConfig(request).configure(lessons_table)
context["lessons_table"] = lessons_table
context["day"] = day
context["lesson_periods"] = lesson_periods
day_prev = day - timedelta(days=1)
day_next = day + timedelta(days=1)
context["url_prev"] = reverse("lessons_day_by_date", args=[day_prev.strftime("%Y-%m-%d")])
context["url_next"] = reverse("lessons_day_by_date", args=[day_next.strftime("%Y-%m-%d")])
return render(request, "chronos/lessons_day.html", context)
@admin_required
def edit_substitution(request: HttpRequest, id_: int, week: int) -> HttpResponse:
context = {}
lesson_period = get_object_or_404(LessonPeriod, pk=id_)
wanted_week = lesson_period.lesson.get_calendar_week(week)
lesson_substitution = LessonSubstitution.objects.filter(
week=wanted_week.week, lesson_period=lesson_period
).first()
if lesson_substitution:
edit_substitution_form = LessonSubstitutionForm(
request.POST or None, instance=lesson_substitution
)
else:
edit_substitution_form = LessonSubstitutionForm(
request.POST or None,
initial={"week": wanted_week.week, "lesson_period": lesson_period},
)
context["substitution"] = lesson_substitution
if request.method == "POST":
if edit_substitution_form.is_valid():
edit_substitution_form.save(commit=True)
messages.success(request, _("The substitution has been saved."))
return redirect(
"lessons_day_by_date",
when=wanted_week[lesson_period.period.weekday - 1].strftime("%Y-%m-%d"),
)
context["edit_substitution_form"] = edit_substitution_form
return render(request, "chronos/edit_substitution.html", context)
@admin_required
def delete_substitution(request: HttpRequest, id_: int, week: int) -> HttpResponse:
context = {}
lesson_period = get_object_or_404(LessonPeriod, pk=id_)
wanted_week = lesson_period.lesson.get_calendar_week(week)
LessonSubstitution.objects.filter(week=wanted_week.week, lesson_period=lesson_period).delete()
messages.success(request, _("The substitution has been deleted."))
return redirect(
"lessons_day_by_date",
when=wanted_week[lesson_period.period.weekday - 1].strftime("%Y-%m-%d"),
)
def substitutions(
request: HttpRequest, year: Optional[int] = None, month: Optional[int] = None, day: Optional[int] = None
) -> HttpResponse:
context = {}
if day:
wanted_day = timezone.datetime(year=year, month=month, day=day).date()
wanted_day = get_next_relevant_day(wanted_day)
else:
wanted_day = get_next_relevant_day(timezone.now().date(), datetime.now().time())
substitutions = LessonSubstitution.objects.on_day(wanted_day)
# Prepare table
substitutions_table = SubstitutionsTable(substitutions)
RequestConfig(request).configure(substitutions_table)
context["current_head"] = str(wanted_day)
context["substitutions_table"] = substitutions_table
context["substitutions"] = substitutions
context["day"] = wanted_day
day_prev = wanted_day - timedelta(days=1)
day_next = wanted_day + timedelta(days=1)
context["url_prev"] = "%s" % (
reverse("substitutions_by_day", args=[day_prev.year, day_prev.month, day_prev.day])
)
context["url_next"] = "%s" % (
reverse("substitutions_by_day", args=[day_next.year, day_next.month, day_next.day])
)
return render(request, "chronos/substitution.html", context)