From 549e087ac32484d661197745bccc801856bc2d26 Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Sun, 27 Jan 2019 19:29:33 +0100 Subject: api: complétion des vues de l’API Ajout de vues permettant de consulter les emplois du temps associés à une année ou à une source, les groupes associés à un emploi du temps, les cours d’un groupe ou d’une salle (soit tous, soit ceux de la semaine courante, soit ceux d’une semaine précise), de lister les semaines de cours, et d’accéder à QSJPS. Signed-off-by: Alban Gruin --- api/views.py | 124 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 122 insertions(+), 2 deletions(-) (limited to 'api') diff --git a/api/views.py b/api/views.py index c58c9c0..f6aa620 100644 --- a/api/views.py +++ b/api/views.py @@ -13,8 +13,20 @@ # 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 @@ -23,27 +35,135 @@ 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) + + @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()) + + 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/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) -class GroupViewSet(viewsets.ReadOnlyModelViewSet): + start, end = get_week(int(year), int(week)) + + 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) + + +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(viewsets.ReadOnlyModelViewSet): + +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") -- cgit v1.2.1