Skip to content
Snippets Groups Projects
Verified Commit eeb6b95c authored by Nik | Klampfradler's avatar Nik | Klampfradler
Browse files

Implement ClaendarWeek data class for correct week calculations.

Advances #27.

We still need to do stuff to respect the year as well, but this is
tied to BiscuIT-ng#40.
parent 7ad70480
No related branches found
No related tags found
No related merge requests found
......@@ -11,6 +11,7 @@
<div class="d-flex justify-content-between">
<div class="btn-group" role="group" aria-label="Day actions">
{% if substitution %}
{# FIXME Respect year as well #}
<a href="{% url 'delete_substitution' substitution.lesson_period.id substitution.week %}" class="btn btn-danger">
{% fa 'trash-o' %}
</a>
......
from __future__ import annotations
from dataclasses import dataclass
from datetime import date, datetime, timedelta
from typing import Optional, Sequence
from typing import Optional, Sequence, Tuple
from django.apps import apps
from django.db import models
def current_week() -> int:
return int(datetime.now().strftime('%V'))
@dataclass
class CalendarWeek:
""" A calendar week defined by year and ISO week number. """
year: Optional[int] = None
week: Optional[int] = None
@classmethod
def from_date(cls, when: date):
return cls(year=when.strftime('%Y'), week=when.strftime('%V'))
def __post_init__(self) -> None:
today = date.today()
if not self.year:
self.year = today.year
if not self.week:
self.week = today.isoweekday()
def __len__(self) -> int:
return 7
def __getitem__(self, n: int) -> date:
if n < -7 or n > 6:
raise IndexError('Week day %d is out of range.' % n)
if n < 0:
n += 7
return datetime.strptime('%d-%d-%d' % (self.year, self.week, n + 1), '%G-%V-%u').date()
def __contains__(self, day: date) -> bool:
return self.__class__.form_date(day) == self
def __eq__(self, other: CalendarWeek) -> bool:
return self.year == other.year and self.week == other.week
def __lt__(self, other: CalendarWeek) -> bool:
return self[0] < other[0]
def __gt__(self, other: CalendarWeek) -> bool:
return self[0] > other[0]
def week_days(week: Optional[int]) -> Sequence[date]:
# FIXME Make this aware of the school term concept
# cf. BiscuIT-ng#40
def __le__(self, other: CalendarWeek) -> bool:
return self[0] <= other[0]
year = date.today().year
wanted_week = week or current_week()
def __gr__(self, other: CalendarWeek) -> bool:
return self[0] >= other[0]
first_day = datetime.strptime('%d-%d-1' % (year, wanted_week), '%G-%V-%u')
def __add__(self, weeks: int) -> CalendarWeek:
return self.__class__.from_date(self[0] + timedelta(days=weeks * 7))
return [(first_day + timedelta(days=offset)).date() for offset in range(0, 7)]
def __sub__(self, weeks: int) -> CalendarWeek:
return self.__class__.from_date(self[0] - timedelta(days=weeks * 7))
def current_lesson_periods(when: Optional[datetime] = None) -> models.query.QuerySet:
......@@ -32,9 +75,9 @@ def current_lesson_periods(when: Optional[datetime] = None) -> models.query.Quer
period__time_end__gte=now.time())
def week_weekday_from_date(when: date) -> Sequence[int]:
return (int(when.strftime('%V')), int(when.strftime('%u')))
def week_weekday_from_date(when: date) -> Tuple[CalendarWeek, int]:
return (CalendarWeek.from_date(when), when.isoweekday())
def week_weekday_to_date(week: int, weekday: int) -> date:
return week_days(week)[weekday-1]
def week_weekday_to_date(week: CalendarWeek, weekday: int) -> date:
return week[weekday - 1]
......@@ -17,7 +17,7 @@ from biscuit.core.util import messages
from .forms import SelectForm, LessonSubstitutionForm
from .models import LessonPeriod, TimePeriod, LessonSubstitution
from .util import current_week, week_weekday_from_date, week_days
from .util import CalendarWeek, week_weekday_from_date
from .tables import LessonsTable
......@@ -25,17 +25,20 @@ from .tables import LessonsTable
def timetable(request: HttpRequest, week: Optional[int] = None) -> HttpResponse:
context = {}
wanted_week = week or current_week()
if week:
wanted_week = CalendarWeek(week) # FIXME Respect year as well
else:
wanted_week = CalendarWeek()
lesson_periods = LessonPeriod.objects.filter(
lesson__date_start__lte=week_days(wanted_week)[0],
lesson__date_end__gte=week_days(wanted_week)[-1]
lesson__date_start__lte=wanted_week[0],
lesson__date_end__gte=wanted_week[-1]
).select_related(
'lesson', 'lesson__subject', 'period', 'room'
).prefetch_related(
'lesson__groups', 'lesson__teachers', 'substitutions'
).extra(
select={'_week': wanted_week}
select={'_week': wanted_week.week} # FIXME respect year as well
)
if request.GET.get('group', None) or request.GET.get('teacher', None) or request.GET.get('room', None):
......@@ -45,7 +48,7 @@ def timetable(request: HttpRequest, week: Optional[int] = None) -> HttpResponse:
Q(lesson__groups__pk=int(request.GET['group'])) | Q(lesson__groups__parent_groups__pk=int(request.GET['group'])))
if 'teacher' in request.GET and request.GET['teacher']:
lesson_periods = lesson_periods.filter(
Q(substitutions__teachers__pk=int(request.GET['teacher']), substitutions__week=wanted_week) | Q(lesson__teachers__pk=int(request.GET['teacher'])))
Q(substitutions__teachers__pk=int(request.GET['teacher']), substitutions__week=wanted_week.week) | Q(lesson__teachers__pk=int(request.GET['teacher']))) # FIXME Respect year as well
if 'room' in request.GET and request.GET['room']:
lesson_periods = lesson_periods.filter(
room__pk=int(request.GET['room']))
......@@ -93,10 +96,13 @@ def timetable(request: HttpRequest, week: Optional[int] = None) -> HttpResponse:
context['periods'] = TimePeriod.get_times_dict()
context['weekdays'] = dict(TimePeriod.WEEKDAY_CHOICES)
context['week'] = wanted_week
context['url_prev'] = '%s?%s' % (reverse('timetable_by_week', week=wanted_week - 1), request.GET.urlencode())
context['url_next'] = '%s?%s' % (reverse('timetable_by_week', week=wanted_week + 1), request.GET.urlencode())
context['select_form'] = select_form
week_prev = wanted_week - 1
week_next = wanted_week + 1
context['url_prev'] = '%s?%s' % (reverse('timetable_by_week', year=week_prev.year, week=week_prev.week), request.GET.urlencode())
context['url_next'] = '%s?%s' % (reverse('timetable_by_week', year=week_next.year, week=week_next.week), request.GET.urlencode())
return render(request, 'chronos/tt_week.html', context)
......@@ -118,7 +124,7 @@ def lessons_day(request: HttpRequest, when: Optional[str] = None) -> HttpRespons
)
# Build table
lessons_table = LessonsTable(lesson_periods.extra(select={'_week': week}).all())
lessons_table = LessonsTable(lesson_periods.extra(select={'_week': week.week}).all()) # FIXME Respect year as well
RequestConfig(request).configure(lessons_table)
context['current_head'] = _('Lessons')
......@@ -136,16 +142,18 @@ def lessons_day(request: HttpRequest, when: Optional[str] = None) -> HttpRespons
def edit_substitution(request: HttpRequest, id_: int, week: int) -> HttpResponse:
context = {}
wanted_week = CalendarWeek(week=week) # FIXME Respect year as well
lesson_period = get_object_or_404(LessonPeriod, pk=id_)
lesson_substitution = LessonSubstitution.objects.filter(
week=week, lesson_period=lesson_period).first()
week=wanted_week.week, lesson_period=lesson_period).first() # FIXME Respect year as well
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': week, 'lesson_period': lesson_period})
request.POST or None, initial={'week': wanted_week.week, 'lesson_period': lesson_period}) # FIXME Respect year as well
context['substitution'] = lesson_substitution
......@@ -154,7 +162,7 @@ def edit_substitution(request: HttpRequest, id_: int, week: int) -> HttpResponse
edit_substitution_form.save(commit=True)
messages.success(request, _('The substitution has been saved.'))
return redirect('lessons_day_by_date', when=week_days(week)[lesson_period.period.weekday - 1].strftime('%Y-%m-%d'))
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
......@@ -165,9 +173,11 @@ def edit_substitution(request: HttpRequest, id_: int, week: int) -> HttpResponse
def delete_substitution(request: HttpRequest, id_: int, week: int) -> HttpResponse:
context = {}
wanted_week = CalendarWeek(week=week) # FIXME Respect year as well
LessonSubstitution.objects.filter(
week=week, lesson_period__id=id_
week=wanted_week.week, lesson_period__id=id_ # FIXME Respect year as well
).delete()
messages.success(request, _('The substitution has been deleted.'))
return redirect('lessons_day_by_date', when=week_days(week)[lesson_period.period.weekday - 1].strftime('%Y-%m-%d'))
return redirect('lessons_day_by_date', when=wanted_week[lesson_period.period.weekday - 1].strftime('%Y-%m-%d'))
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment