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 @@ ...@@ -11,6 +11,7 @@
<div class="d-flex justify-content-between"> <div class="d-flex justify-content-between">
<div class="btn-group" role="group" aria-label="Day actions"> <div class="btn-group" role="group" aria-label="Day actions">
{% if substitution %} {% if substitution %}
{# FIXME Respect year as well #}
<a href="{% url 'delete_substitution' substitution.lesson_period.id substitution.week %}" class="btn btn-danger"> <a href="{% url 'delete_substitution' substitution.lesson_period.id substitution.week %}" class="btn btn-danger">
{% fa 'trash-o' %} {% fa 'trash-o' %}
</a> </a>
......
from __future__ import annotations
from dataclasses import dataclass
from datetime import date, datetime, timedelta from datetime import date, datetime, timedelta
from typing import Optional, Sequence from typing import Optional, Sequence, Tuple
from django.apps import apps from django.apps import apps
from django.db import models from django.db import models
def current_week() -> int: @dataclass
return int(datetime.now().strftime('%V')) 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]: def __le__(self, other: CalendarWeek) -> bool:
# FIXME Make this aware of the school term concept return self[0] <= other[0]
# cf. BiscuIT-ng#40
year = date.today().year def __gr__(self, other: CalendarWeek) -> bool:
wanted_week = week or current_week() 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: 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 ...@@ -32,9 +75,9 @@ def current_lesson_periods(when: Optional[datetime] = None) -> models.query.Quer
period__time_end__gte=now.time()) period__time_end__gte=now.time())
def week_weekday_from_date(when: date) -> Sequence[int]: def week_weekday_from_date(when: date) -> Tuple[CalendarWeek, int]:
return (int(when.strftime('%V')), int(when.strftime('%u'))) return (CalendarWeek.from_date(when), when.isoweekday())
def week_weekday_to_date(week: int, weekday: int) -> date: def week_weekday_to_date(week: CalendarWeek, weekday: int) -> date:
return week_days(week)[weekday-1] return week[weekday - 1]
...@@ -17,7 +17,7 @@ from biscuit.core.util import messages ...@@ -17,7 +17,7 @@ from biscuit.core.util import messages
from .forms import SelectForm, LessonSubstitutionForm from .forms import SelectForm, LessonSubstitutionForm
from .models import LessonPeriod, TimePeriod, LessonSubstitution 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 from .tables import LessonsTable
...@@ -25,17 +25,20 @@ from .tables import LessonsTable ...@@ -25,17 +25,20 @@ from .tables import LessonsTable
def timetable(request: HttpRequest, week: Optional[int] = None) -> HttpResponse: def timetable(request: HttpRequest, week: Optional[int] = None) -> HttpResponse:
context = {} 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_periods = LessonPeriod.objects.filter(
lesson__date_start__lte=week_days(wanted_week)[0], lesson__date_start__lte=wanted_week[0],
lesson__date_end__gte=week_days(wanted_week)[-1] lesson__date_end__gte=wanted_week[-1]
).select_related( ).select_related(
'lesson', 'lesson__subject', 'period', 'room' 'lesson', 'lesson__subject', 'period', 'room'
).prefetch_related( ).prefetch_related(
'lesson__groups', 'lesson__teachers', 'substitutions' 'lesson__groups', 'lesson__teachers', 'substitutions'
).extra( ).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): 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: ...@@ -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']))) 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']: if 'teacher' in request.GET and request.GET['teacher']:
lesson_periods = lesson_periods.filter( 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']: if 'room' in request.GET and request.GET['room']:
lesson_periods = lesson_periods.filter( lesson_periods = lesson_periods.filter(
room__pk=int(request.GET['room'])) room__pk=int(request.GET['room']))
...@@ -93,10 +96,13 @@ def timetable(request: HttpRequest, week: Optional[int] = None) -> HttpResponse: ...@@ -93,10 +96,13 @@ def timetable(request: HttpRequest, week: Optional[int] = None) -> HttpResponse:
context['periods'] = TimePeriod.get_times_dict() context['periods'] = TimePeriod.get_times_dict()
context['weekdays'] = dict(TimePeriod.WEEKDAY_CHOICES) context['weekdays'] = dict(TimePeriod.WEEKDAY_CHOICES)
context['week'] = wanted_week 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 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) return render(request, 'chronos/tt_week.html', context)
...@@ -118,7 +124,7 @@ def lessons_day(request: HttpRequest, when: Optional[str] = None) -> HttpRespons ...@@ -118,7 +124,7 @@ def lessons_day(request: HttpRequest, when: Optional[str] = None) -> HttpRespons
) )
# Build table # 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) RequestConfig(request).configure(lessons_table)
context['current_head'] = _('Lessons') context['current_head'] = _('Lessons')
...@@ -136,16 +142,18 @@ def lessons_day(request: HttpRequest, when: Optional[str] = None) -> HttpRespons ...@@ -136,16 +142,18 @@ def lessons_day(request: HttpRequest, when: Optional[str] = None) -> HttpRespons
def edit_substitution(request: HttpRequest, id_: int, week: int) -> HttpResponse: def edit_substitution(request: HttpRequest, id_: int, week: int) -> HttpResponse:
context = {} context = {}
wanted_week = CalendarWeek(week=week) # FIXME Respect year as well
lesson_period = get_object_or_404(LessonPeriod, pk=id_) lesson_period = get_object_or_404(LessonPeriod, pk=id_)
lesson_substitution = LessonSubstitution.objects.filter( 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: if lesson_substitution:
edit_substitution_form = LessonSubstitutionForm( edit_substitution_form = LessonSubstitutionForm(
request.POST or None, instance=lesson_substitution) request.POST or None, instance=lesson_substitution)
else: else:
edit_substitution_form = LessonSubstitutionForm( 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 context['substitution'] = lesson_substitution
...@@ -154,7 +162,7 @@ def edit_substitution(request: HttpRequest, id_: int, week: int) -> HttpResponse ...@@ -154,7 +162,7 @@ def edit_substitution(request: HttpRequest, id_: int, week: int) -> HttpResponse
edit_substitution_form.save(commit=True) edit_substitution_form.save(commit=True)
messages.success(request, _('The substitution has been saved.')) 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 context['edit_substitution_form'] = edit_substitution_form
...@@ -165,9 +173,11 @@ def edit_substitution(request: HttpRequest, id_: int, week: int) -> HttpResponse ...@@ -165,9 +173,11 @@ def edit_substitution(request: HttpRequest, id_: int, week: int) -> HttpResponse
def delete_substitution(request: HttpRequest, id_: int, week: int) -> HttpResponse: def delete_substitution(request: HttpRequest, id_: int, week: int) -> HttpResponse:
context = {} context = {}
wanted_week = CalendarWeek(week=week) # FIXME Respect year as well
LessonSubstitution.objects.filter( LessonSubstitution.objects.filter(
week=week, lesson_period__id=id_ week=wanted_week.week, lesson_period__id=id_ # FIXME Respect year as well
).delete() ).delete()
messages.success(request, _('The substitution has been deleted.')) 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