Skip to content
Snippets Groups Projects
views.py 11.1 KiB
Newer Older
from collections import OrderedDict
from datetime import date, datetime, timedelta
from typing import Optional, Tuple
Nik | Klampfradler's avatar
Nik | Klampfradler committed
from django.contrib.auth.decorators import login_required
from django.db.models import Count
from django.http import HttpRequest, HttpResponse, HttpResponseNotFound
Tom Teichler's avatar
Tom Teichler committed
from django.shortcuts import get_object_or_404, redirect, render
Nik | Klampfradler's avatar
Nik | Klampfradler committed
from django.urls import reverse
from django.utils import timezone
from django.utils.translation import ugettext as _
Tom Teichler's avatar
Tom Teichler committed
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
Jonathan Weth's avatar
Jonathan Weth committed
from .models import LessonPeriod, LessonSubstitution, TimePeriod, Room
from .tables import LessonsTable
from .util.js import date_unix
from .util.min_max import period_min, period_max, weekday_min_, weekday_max
from .util.prev_next import get_next_relevant_day, get_prev_next_by_day
Jonathan Weth's avatar
Jonathan Weth committed
from .util.weeks import CalendarWeek, get_weeks_for_year
from aleksis.core.util.core_helpers import has_person
Nik | Klampfradler's avatar
Nik | Klampfradler committed

@login_required
def all_timetables(request: HttpRequest) -> HttpResponse:
    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/all.html", context)
@login_required
def my_timetable(
    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())

    if has_person(request.user):
        if person.is_teacher:
            # Teacher

            type_ = "teacher"
            super_el = person
            lesson_periods_person = person.lesson_periods_as_teacher

        elif person.primary_group:
            # Student

            type_ = "group"
            super_el = person.primary_group
            lesson_periods_person = person.lesson_periods_as_participant

        else:
            # If no student or teacher, redirect to all timetables
            return redirect("all_timetables")

    lesson_periods = lesson_periods_person.on_day(wanted_day)

    # Build dictionary with lessons
    per_period = {}
    for lesson_period in lesson_periods:
        if lesson_period.period.period in per_period:
            per_period[lesson_period.period.period].append(lesson_period)
        else:
            per_period[lesson_period.period.period] = [lesson_period]

    context["lesson_periods"] = OrderedDict(sorted(per_period.items()))
    context["super"] = {"type": type_, "el": super_el}
    context["type"] = type_
    context["day"] = wanted_day
    context["periods"] = TimePeriod.get_times_dict()
    context["smart"] = True
    context["url_prev"], context["url_next"] = get_prev_next_by_day(
Jonathan Weth's avatar
Jonathan Weth committed
        wanted_day, "my_timetable_by_date"
    return render(request, "chronos/my_timetable.html", context)
Nik | Klampfradler's avatar
Nik | Klampfradler committed
@login_required
def timetable(
    request: HttpRequest,
    type_: str,
    pk: int,
    year: Optional[int] = None,
    week: Optional[int] = None,
    regular: Optional[str] = None,
) -> HttpResponse:
Tom Teichler's avatar
Tom Teichler committed
    context = {}

Jonathan Weth's avatar
Jonathan Weth committed
    is_smart = regular != "regular"

Jonathan Weth's avatar
Jonathan Weth committed
    if type_ == "group":
Jonathan Weth's avatar
Jonathan Weth committed
    elif type_ == "teacher":
        el = get_object_or_404(Person, pk=pk)
Jonathan Weth's avatar
Jonathan Weth committed
    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)
        # TODO: On not used days show next week
    lesson_periods = LessonPeriod.objects.in_week(wanted_week)
Jonathan Weth's avatar
Jonathan Weth committed
    lesson_periods = lesson_periods.filter_from_type(type_, pk)
    # Regroup lesson periods per weekday
    for lesson_period in lesson_periods:
        if lesson_period.period.period in per_period:
            if lesson_period.period.weekday in per_period[lesson_period.period.period]:
                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]
    # Fill in empty lessons
    for period_num in range(period_min, period_max + 1):
        # 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()))
    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
Jonathan Weth's avatar
Jonathan Weth committed
    context["type"] = type_
Jonathan Weth's avatar
Jonathan Weth committed
    context["smart"] = is_smart
    context["week_select"] = {
        "year": wanted_week.year,
        "dest": reverse("timetable", args=[type_, pk]),
    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/timetable.html", context)
def lessons_day(
    request: HttpRequest,
    year: Optional[int] = None,
    month: Optional[int] = None,
    day: Optional[int] = None,
) -> HttpResponse:
    if day:
        wanted_day = timezone.datetime(year=year, month=month, day=day).date()
        wanted_day = get_next_relevant_day(wanted_day)
        wanted_day = get_next_relevant_day(timezone.now().date(), datetime.now().time())
    # Get lessons
    lesson_periods = LessonPeriod.objects.on_day(wanted_day)
    # Build table
    lessons_table = LessonsTable(lesson_periods.all())
Tom Teichler's avatar
Tom Teichler committed
    RequestConfig(request).configure(lessons_table)
    context["lessons_table"] = lessons_table
    context["lesson_periods"] = lesson_periods
    context["datepicker"] = {
        "date": date_unix(wanted_day),
        "dest": reverse("lessons_day"),
    context["url_prev"], context["url_next"] = get_prev_next_by_day(
        wanted_day, "lessons_day_by_date"
    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()
        edit_substitution_form = LessonSubstitutionForm(
            request.POST or None, instance=lesson_substitution
        )
        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."))

            date = wanted_week[lesson_period.period.weekday]
            return redirect(
                "lessons_day_by_date", year=date.year, month=date.month, day=date.day
    context["edit_substitution_form"] = edit_substitution_form
    return render(request, "chronos/edit_substitution.html", context)
Nik | Klampfradler's avatar
Nik | Klampfradler committed
def delete_substitution(request: HttpRequest, id_: int, week: int) -> HttpResponse:
    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."))

    date = wanted_week[lesson_period.period.weekday]
    return redirect(
        "lessons_day_by_date", year=date.year, month=date.month, day=date.day
@login_required
def substitutions(
    request: HttpRequest,
    year: Optional[int] = None,
    month: Optional[int] = None,
    day: Optional[int] = None,
    is_print: Optional[str] = None,
) -> HttpResponse:
Tom Teichler's avatar
Tom Teichler committed
    context = {}

    is_print = is_print == "print"
    print(is_print)

    if day:
        wanted_day = timezone.datetime(year=year, month=month, day=day).date()
        wanted_day = get_next_relevant_day(wanted_day)
Tom Teichler's avatar
Tom Teichler committed
    else:
        wanted_day = get_next_relevant_day(timezone.now().date(), datetime.now().time())
        next_day = wanted_day
        for i in range(DAY_COUNT):
            print(i, next_day)
            day_contexts[next_day] = {"day": next_day}
            next_day = get_next_relevant_day(next_day + timedelta(days=1))
            print(day_contexts)
        print(day_contexts)

    else:
        day_contexts = {wanted_day: {"day": wanted_day}}

    print(day_contexts)

    for day in day_contexts:
        day_contexts[day]["substitutions"] = LessonSubstitution.objects.on_day(
            day
        ).order_by("lesson_period__lesson__groups", "lesson_period__period")
        print(day_contexts[day]["substitutions"].count(), day)
    print(day_contexts)

    if not is_print:
        context = day_contexts[wanted_day]
        context["datepicker"] = {
            "date": date_unix(wanted_day),
            "dest": reverse("substitutions"),
        }

        context["url_prev"], context["url_next"] = get_prev_next_by_day(
            wanted_day, "substitutions_by_date"
        )

        template_name = "chronos/substitutions.html"
    else:
        context["days"] = day_contexts
        template_name = "chronos/substitutions_print.html"

    print(context)
    return render(request, template_name, context)