# Copyright (C) 2019 Alban Gruin
#
# celcatsanitizer is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# celcatsanitizer is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with celcatsanitizer. If not, see .
import datetime
from django.db.models import Count
from django.db.models.functions import ExtractWeek, ExtractYear
from django.utils import timezone
from rest_framework import viewsets
from rest_framework.decorators import action, detail_route
from rest_framework.response import Response
from ..forms import QSJPSForm
from ..models import Course, Group, Room, Source, Timetable, Year
from ..utils import get_current_or_next_week, get_week
from .serializers import CourseSerializer, GroupSerializer, RoomSerializer, \
SourceSerializer, TimetableSerializer, YearSerializer
class YearViewSet(viewsets.ReadOnlyModelViewSet):
queryset = Year.objects.all().order_by("name")
serializer_class = YearSerializer
@detail_route(methods=["get"], url_path="timetables")
def timetable_list(self, request, pk):
year = self.get_object()
timetables = Timetable.objects.filter(year=year).distinct() \
.order_by("name")
timetables_json = TimetableSerializer(
self.paginate_queryset(timetables), many=True)
return self.get_paginated_response(timetables_json.data)
class SourceViewSet(viewsets.ReadOnlyModelViewSet):
queryset = Source.objects.all().order_by("pk")
serializer_class = SourceSerializer
@detail_route(methods=["get"], url_path="timetables")
def timetable_list(self, request, pk):
source = self.get_object()
timetables = Timetable.objects.filter(source=source).distinct() \
.order_by("name")
timetables_json = TimetableSerializer(
self.paginate_queryset(timetables), many=True)
return self.get_paginated_response(timetables_json.data)
class TimetableViewSet(viewsets.ReadOnlyModelViewSet):
queryset = Timetable.objects.all().select_related("source") \
.order_by("year", "name")
serializer_class = TimetableSerializer
@detail_route(methods=["get"], url_path="groups")
def group_list(self, request, pk):
timetable = self.get_object()
groups = Group.objects.filter(source=timetable.source).distinct() \
.order_by("name")
groups_json = GroupSerializer(self.paginate_queryset(groups),
many=True)
return self.get_paginated_response(groups_json.data)
class CourseListGroupSet(viewsets.ReadOnlyModelViewSet):
@detail_route(methods=["get"], url_path="courses")
def course_list(self, request, pk):
obj = self.get_object()
courses = Course.objects.get_courses(obj).prefetch_related("groups")
courses_json = CourseSerializer(self.paginate_queryset(courses),
many=True)
return self.get_paginated_response(courses_json.data)
def __get_courses(self, obj, start, end):
courses = Course.objects.get_courses(obj,
begin__gte=start, end__lt=end) \
.prefetch_related("groups")
courses_json = CourseSerializer(self.paginate_queryset(courses),
many=True)
return self.get_paginated_response(courses_json.data)
@detail_route(methods=["get"], url_path="courses/days/current")
def current_day(self, request, pk):
obj = self.get_object()
start = datetime.date.today()
end = start + datetime.timedelta(days=1)
return self.__get_courses(obj, start, end)
@detail_route(methods=["get"], url_path="courses/days/(?P\d+)/(?P\d+)/(?P\d+)")
def other_day(self, request, pk, year, month, day):
obj = self.get_object()
try:
start = datetime.date(int(year), int(month), int(day))
except ValueError as v:
errors = {}
message = v.args[0]
if message.split(" ")[0] == "month":
errors["month"] = "Rentrez un mois invalide"
else:
errors["day"] = "Numéro de jour invalide pour le mois"
return Response(errors, status=400)
end = start + datetime.timedelta(days=1)
return self.__get_courses(obj, start, end)
@detail_route(methods=["get"], url_path="courses/weeks/current")
def current_week(self, request, pk):
obj = self.get_object()
start, end = get_week(*get_current_or_next_week())
return self.__get_courses(obj, start, end)
@detail_route(methods=["get"],
url_path="courses/weeks/(?P\d+)/(?P\d+)")
def other_week(self, request, pk, year, week):
obj = self.get_object()
errors = {}
if not year.isdigit():
errors["year"] = "Rentrez une année valide"
if not week.isdigit() or not 0 < int(week) <= 53:
errors["week"] = "Rentrez une semaine valide"
if errors:
return Response(errors, status=400)
return self.__get_courses(obj, *get_week(int(year), int(week)))
class GroupViewSet(CourseListGroupSet):
queryset = Group.objects.all().order_by("name")
serializer_class = GroupSerializer
@detail_route(methods=["get"], url_path="courses/weeks")
def weeks(self, request, pk):
group = self.get_object()
groups = Group.objects.get_parents(group)
courses = Course.objects.filter(groups__in=groups) \
.order_by("year", "week") \
.annotate(year=ExtractYear("begin"),
week=ExtractWeek("begin")) \
.values("year", "week") \
.annotate(c=Count("*"))
weeks = [get_week(course["year"], course["week"])[0]
for course in courses]
return Response(weeks)
class RoomViewSet(CourseListGroupSet):
queryset = Room.objects.all().order_by("name")
serializer_class = RoomSerializer
@action(
methods=["get"],
detail=False,
url_path="qsjps/(?P[0-9\-]+)/(?P[0-9:]+)/(?P[0-9:]+)")
def qsjps(self, request, day, begin, end):
form = QSJPSForm({"day": day, "begin": begin, "end": end})
if not form.is_valid():
return Response(form.errors, status=400)
day = form.cleaned_data["day"]
begin_hour = form.cleaned_data["begin"]
end_hour = form.cleaned_data["end"]
begin = timezone.make_aware(datetime.datetime.combine(day, begin_hour))
end = timezone.make_aware(datetime.datetime.combine(day, end_hour))
rooms = Room.objects.qsjps(begin, end)
rooms_json = RoomSerializer(rooms, many=True)
return Response(rooms_json.data)
class CourseViewSet(viewsets.ReadOnlyModelViewSet):
queryset = Course.objects.all().prefetch_related("groups", "rooms")
serializer_class = CourseSerializer