From 7084c5238c84f7c232efff91ee60ef86cb23680c Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Sun, 27 Jan 2019 16:22:43 +0100 Subject: requirements: ajout d’une dépendance à Django REST Framework Django REST Framework sera utilisé pour réaliser l’API de celcatsanitizer. Signed-off-by: Alban Gruin --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index f2c309f..6c91f54 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,6 @@ beautifulsoup4==4.6.3 Django==2.0.8 +djangorestframework==3.9.1 gunicorn==19.9.0 icalendar==4.0.2 lxml==4.2.4 -- cgit v1.2.1 From 66853337a5f6bd2b67f1130e3f4db7febe27de1b Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Sun, 27 Jan 2019 19:22:35 +0100 Subject: api: ajout d’un sérialiseur pour chaque modèle Les sérialiseurs permettent de représenter les modèles en JSON. Tous les sérialiseurs exportent tous les champs de leurs modèles respectifs. En plus de cela, le sérialiseur du modèle des cours sérialise en plus les groupes et salles pour ne pas avoir à faire trop d’appels à l’API. Signed-off-by: Alban Gruin --- api/serializers.py | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 api/serializers.py diff --git a/api/serializers.py b/api/serializers.py new file mode 100644 index 0000000..5d81f44 --- /dev/null +++ b/api/serializers.py @@ -0,0 +1,57 @@ +# 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 . + +from rest_framework import serializers + +from ..models import Course, Group, Room, Source, Timetable, Year + + +class YearSerializer(serializers.ModelSerializer): + class Meta: + model = Year + fields = "__all__" + + +class SourceSerializer(serializers.ModelSerializer): + class Meta: + model = Source + fields = "__all__" + + +class TimetableSerializer(serializers.ModelSerializer): + class Meta: + model = Timetable + fields = "__all__" + + +class GroupSerializer(serializers.ModelSerializer): + class Meta: + model = Group + fields = "__all__" + + +class RoomSerializer(serializers.ModelSerializer): + class Meta: + model = Room + fields = "__all__" + + +class CourseSerializer(serializers.ModelSerializer): + groups = GroupSerializer(many=True, read_only=True) + rooms = RoomSerializer(many=True, read_only=True) + + class Meta: + model = Course + fields = "__all__" -- cgit v1.2.1 From 1764d2d8f4ae02a81dd6bea1c9f8a374d9706b63 Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Sun, 27 Jan 2019 19:32:38 +0100 Subject: api: ajout des vues de l’API L’API a besoin de vues pour renvoyer des données. Ces vues utilisent les sérialiseurs écrits précédement. Pour l’instant, les sérialiseurs sont assez rudimentaires (ils ne peuvent afficher qu’une liste d’objets ou un seul objet sans filtres ou fonctionnalités supplémentaires), et ne permettent pas d’effectuer de modifications. Signed-off-by: Alban Gruin --- api/views.py | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 api/views.py diff --git a/api/views.py b/api/views.py new file mode 100644 index 0000000..c58c9c0 --- /dev/null +++ b/api/views.py @@ -0,0 +1,50 @@ +# 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 . + +from rest_framework import viewsets +from ..models import Course, Group, Room, Source, Timetable, Year +from .serializers import CourseSerializer, GroupSerializer, RoomSerializer, \ + SourceSerializer, TimetableSerializer, YearSerializer + + +class YearViewSet(viewsets.ReadOnlyModelViewSet): + queryset = Year.objects.all().order_by("name") + serializer_class = YearSerializer + + +class SourceViewSet(viewsets.ReadOnlyModelViewSet): + queryset = Source.objects.all().order_by("pk") + serializer_class = SourceSerializer + + +class TimetableViewSet(viewsets.ReadOnlyModelViewSet): + queryset = Timetable.objects.all().select_related("source") \ + .order_by("year", "name") + serializer_class = TimetableSerializer + + +class GroupViewSet(viewsets.ReadOnlyModelViewSet): + queryset = Group.objects.all().order_by("name") + serializer_class = GroupSerializer + + +class RoomViewSet(viewsets.ReadOnlyModelViewSet): + queryset = Room.objects.all().order_by("name") + serializer_class = RoomSerializer + + +class CourseViewSet(viewsets.ReadOnlyModelViewSet): + queryset = Course.objects.all().prefetch_related("groups", "rooms") + serializer_class = CourseSerializer -- cgit v1.2.1 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(-) 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 From 1a582c97ecf369ca7ca170aeed845aa05ce72432 Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Sun, 27 Jan 2019 19:32:55 +0100 Subject: api: ajout d’un routeur pour l’API, branchement sur urls.py Signed-off-by: Alban Gruin --- api/urls.py | 25 +++++++++++++++++++++++++ urls.py | 5 ++++- 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 api/urls.py diff --git a/api/urls.py b/api/urls.py new file mode 100644 index 0000000..0164a4f --- /dev/null +++ b/api/urls.py @@ -0,0 +1,25 @@ +# 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 . + +from rest_framework import routers +from . import views + +router = routers.DefaultRouter() +router.register(r"years", views.YearViewSet) +router.register(r"sources", views.SourceViewSet) +router.register(r"timetables", views.TimetableViewSet) +router.register(r"rooms", views.RoomViewSet) +router.register(r"groups", views.GroupViewSet) +router.register(r"courses", views.CourseViewSet) diff --git a/urls.py b/urls.py index 977ac8d..5cd134e 100644 --- a/urls.py +++ b/urls.py @@ -1,4 +1,4 @@ -# Copyright (C) 2017-2018 Alban Gruin +# Copyright (C) 2017-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 @@ -14,10 +14,13 @@ # along with celcatsanitizer. If not, see . from django.urls import include, path + from . import feeds, views +from .api.urls import router urlpatterns = [ path("", views.index, name="index"), + path("api/", include(router.urls)), path("pages/", include("django.contrib.flatpages.urls")), path("salles/", views.rooms, name="rooms"), path("salles/qsjps", views.qsjps, name="qsjps"), -- cgit v1.2.1 From 9987d47ec8c74d649de2a7d09ef62beb885949d9 Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Sun, 27 Jan 2019 21:47:39 +0100 Subject: Documentation: ajout d’une doc sur l’API REST Signed-off-by: Alban Gruin --- Documentation/index.rst | 1 + Documentation/usage/installation.rst | 19 + Documentation/usage/rest.rst | 697 +++++++++++++++++++++++++++++++++++ 3 files changed, 717 insertions(+) create mode 100644 Documentation/usage/rest.rst diff --git a/Documentation/index.rst b/Documentation/index.rst index e793dd2..e8dd4f2 100644 --- a/Documentation/index.rst +++ b/Documentation/index.rst @@ -63,6 +63,7 @@ Utilisation de celcatsanitizer usage/commands/listtimetables usage/commands/reparse usage/commands/timetables + usage/rest usage/versions Développement diff --git a/Documentation/usage/installation.rst b/Documentation/usage/installation.rst index 4dde4f4..75e0be1 100644 --- a/Documentation/usage/installation.rst +++ b/Documentation/usage/installation.rst @@ -8,6 +8,7 @@ celcatsanitizer est écrit en Python 3. Il dépend des bibliothèques suivantes : - `Django 2.0`_ + - `Django REST Framework`_ - requests_, pour récupérer les emplois du temps en HTTP(S) - BeautifulSoup4_ et LXML_, pour parser les emplois du temps en XML - icalendar_, pour générer des fichiers ICS_. @@ -25,6 +26,7 @@ d’installer le module psycopg2_. Pour l’instant, l’installation doit passer par git_. .. _Django 2.0: https://www.djangoproject.com/ +.. _Django REST Framework: https://www.django-rest-framework.org/ .. _requests: http://docs.python-requests.org/en/master/ .. _BeautifulSoup4: https://www.crummy.com/software/BeautifulSoup/bs4/doc/ @@ -155,6 +157,23 @@ Si jamais vous utilisez Django en production, vous **devez impérativement** mettre la valeur de la variable ``DEBUG`` à ``False``. +Configuration de Django REST Framework +`````````````````````````````````````` +Ajoutez la chaîne de caractère ``rest_framework`` à la liste +``INSTALLED_APPS``. + +Libre à vous de configurer DRF de la manière dont vous le souhaitez. +`Les différents paramètres sont accessibles ici`__. Les plus +intéressants sont ``DEFAULT_PERMISSION_CLASSES``, +``DEFAULT_RENDERER_CLASSES``, ``DEFAULT_PAGINATION_CLASS`` et +``PAGE_SIZE``. + +__ https://www.django-rest-framework.org/api-guide/settings/ + +Cette étape est **obligatoire**, mais deviendra optionnelle dans le +futur. Dans le cas ou vous ne souhaiterez pas la faire, l’API REST ne +sera pas activée. + Ajout de celcatsanitizer à la liste des applications Django ``````````````````````````````````````````````````````````` Ajoutez la chaîne de caractère ``edt`` à la liste ``INSTALLED_APPS``. diff --git a/Documentation/usage/rest.rst b/Documentation/usage/rest.rst new file mode 100644 index 0000000..bcaada9 --- /dev/null +++ b/Documentation/usage/rest.rst @@ -0,0 +1,697 @@ +======== +API REST +======== + +celcatsanitizer dispose d’une API REST pour permettre à des outils +tiers d’accéder facilement à ses données, qui sont renvoyées en JSON. +Pour l’instant, il ne permet pas la modification des données. + +Le point d’entrée se trouve à l’adresse ``api/`` de l’instance de +celcatsanitizer. Il retourne la liste des autres points d’accès en +JSON. + +Années +====== + +``api/years/`` +-------------- +Liste les années par ordre alphabétique de nom. :ref:`Le résultat +peut être paginé `. + +Exemple : +````````` +.. code:: json + + { + "count": 4, + "next": null, + "previous": null, + "results": [ + { + "id": 3, + "name": "L1", + "slug": "l1" + }, + { + "id": 4, + "name": "L2", + "slug": "l2" + }, + { + "id": 1, + "name": "L3", + "slug": "l3" + }, + { + "id": 2, + "name": "M1", + "slug": "m1" + } + ] + } + +``api/years//`` +------------------- +Retourne seulement une année. + +Exemple : +````````` +.. code:: json + + { + "id": 1, + "name": "L3", + "slug": "l3" + } + +``api/years//timetables`` +----------------------------- +Liste les emplois du temps associés à une année par ordre alphabétique +de nom. :ref:`Le résultat peut être paginé `. + +Exemple : +````````` +.. code:: json + + { + "count": 2, + "next": null, + "previous": null, + "results": [ + { + "id": 2, + "name": "1ere année SRI", + "slug": "1ere-annee-sri", + "year": 1, + "source": 2 + }, + { + "id": 1, + "name": "Info", + "slug": "info", + "year": 1, + "source": 1 + } + ] + } + +Emplois du temps +================ + +``api/timetables`` +------------------ +Liste les emplois du temps par ordre d’année (ID associé) puis de nom. +:ref:`Le résultat peut être paginé `. + +Exemple : +````````` +.. code:: json + + { + "count": 1, + "next": null, + "previous": null, + "results": [ + { + "id": 1, + "name": "Info", + "slug": "info", + "year": 1, + "source": 1 + } + ] + } + +``api/timetables//`` +------------------------ +Retourne seulement un emploi du temps. + +Exemple : +````````` +.. code:: json + + { + "id": 1, + "name": "Info", + "slug": "info", + "year": 1, + "source": 1 + } + +``api/timetables//groups/`` +------------------------------- +Retourne la liste des groupes associés à un emploi du temps, triés par +ordre alphabétique. :ref:`Le résultat peut être paginé +`. + +Exemple : +````````` +.. code:: json + + { + "count": 2, + "next": null, + "previous": null, + "results": [ + { + "id": 207, + "name": "L2 Info s1 CMA", + "celcat_name": "L2 Info s1 CMA", + "mention": "L2 Info", + "semester": 1, + "subgroup": "A", + "slug": "l2-info-s1-cma", + "hidden": false, + "source": 1 + }, + { + "id": 208, + "name": "L3 INFO (toutes sections et semestres confondus)", + "celcat_name": "L3 INFO (toutes sections et semestres confondus)", + "mention": "L3 INFO", + "semester": null, + "subgroup": "", + "slug": "l3-info-toutes-sections-et-semestres-confondus", + "hidden": false, + "source": 1 + } + ] + } + +Sources +======= + +``api/sources/`` +---------------- +Retourne la liste des sources par ordre d’ID. :ref:`Le résultat peut +être paginé `. + +Exemple : +````````` +.. code:: json + + { + "count": 2, + "next": null, + "previous": null, + "results": [ + { + "id": 1, + "url": "https://edt.univ-tlse3.fr/calendar/default.aspx?View=month&Type=group&ResourceN ame=formation_ELINFE", + "last_update_date": null + }, + { + "id": 2, + "url": "https://edt.univ-tlse3.fr/calendar/default.aspx?View=month&Type=group&ResourceN ame=formation_ELUSR1_s1", + "last_update_date": null + } + ] + } + +``api/sources//`` +--------------------- +Renvoie seulement une source. + +Exemple : +````````` +.. code:: json + + { + "id": 1, + "url": "https://edt.univ-tlse3.fr/calendar/default.aspx?View=month&Type=group&ResourceName=formation_ELINFE", + "last_update_date": null + } + +``api/sources//timetables/`` +-------------------------------- +Renvoie la liste des emplois du temps associé à une source triés par +ordre alphabétique. :ref:`Le résultat peut être paginé +`. + +Exemple : +````````` +.. code:: json + + { + "count": 1, + "next": null, + "previous": null, + "results": [ + { + "id": 1, + "name": "Info", + "slug": "info", + "year": 1, + "source": 1 + } + ] + } + +Groupes +======= + +``api/groups/`` +--------------- +Liste les groupes par ordre alphabétique. :ref:`Le résultat peut être +paginé `. + +Exemple : +````````` +.. code:: json + + { + "count": 2, + "next": null, + "previous": null, + "results": [ + { + "id": 207, + "name": "L2 Info s1 CMA", + "celcat_name": "L2 Info s1 CMA", + "mention": "L2 Info", + "semester": 1, + "subgroup": "A", + "slug": "l2-info-s1-cma", + "hidden": false, + "source": 1 + }, + { + "id": 208, + "name": "L3 INFO (toutes sections et semestres confondus)", + "celcat_name": "L3 INFO (toutes sections et semestres confondus)", + "mention": "L3 INFO", + "semester": null, + "subgroup": "", + "slug": "l3-info-toutes-sections-et-semestres-confondus", + "hidden": false, + "source": 1 + } + ] + } + +``api/groups//`` +-------------------- +Affiche seulement un groupe. + +Exemple : +````````` +.. code:: json + + { + "id": 207, + "name": "L2 Info s1 CMA", + "celcat_name": "L2 Info s1 CMA", + "mention": "L2 Info", + "semester": 1, + "subgroup": "A", + "slug": "l2-info-s1-cma", + "hidden": false, + "source": 1 + } + +.. _ref-groups-courses: + +``api/groups//courses/`` +---------------------------- +Retourne tous les cours d’un groupe et de ses parents triés par ordre +de début. :ref:`Le résultat peut être paginé `. + +Exemple : +````````` +.. code:: json + + { + "count": 2, + "next": null, + "previous": null, + "results": [ + { + "id": 34723, + "groups": [ + { + "id": 98, + "name": "L3 INFO s1 CMA", + "celcat_name": "L3 INFO s1 CMA", + "mention": "L3 INFO", + "semester": 1, + "subgroup": "A", + "slug": "l3-info-s1-cma", + "hidden": false, + "source": 1 + }, + { + "id": 207, + "name": "L2 Info s1 CMA", + "celcat_name": "L2 Info s1 CMA", + "mention": "L2 Info", + "semester": 1, + "subgroup": "A", + "slug": "l2-info-s1-cma", + "hidden": false, + "source": 1 + } + ], + "rooms": [], + "name": "REUNION / RENCONTRE", + "type": null, + "notes": "Nuit de l'info", + "begin": "2018-12-06T13:30:00+01:00", + "end": "2018-12-06T23:45:00+01:00", + "last_update": "2018-12-31T13:26:57.122490+01:00", + "source": 1 + }, + { + "id": 34727, + "groups": [ + { + "id": 98, + "name": "L3 INFO s1 CMA", + "celcat_name": "L3 INFO s1 CMA", + "mention": "L3 INFO", + "semester": 1, + "subgroup": "A", + "slug": "l3-info-s1-cma", + "hidden": false, + "source": 1 + }, + { + "id": 207, + "name": "L2 Info s1 CMA", + "celcat_name": "L2 Info s1 CMA", + "mention": "L2 Info", + "semester": 1, + "subgroup": "A", + "slug": "l2-info-s1-cma", + "hidden": false, + "source": 1 + } + ], + "rooms": [], + "name": "REUNION / RENCONTRE", + "type": null, + "notes": "Nuit de l'info", + "begin": "2018-12-07T07:45:00+01:00", + "end": "2018-12-07T23:45:00+01:00", + "last_update": "2018-12-31T13:26:57.136381+01:00", + "source": 1 + } + ] + } + +``api/groups//courses/weeks/`` +---------------------------------- +Retourne la liste des semaines de cours d’un groupe. + +Exemple : +````````` +.. code:: json + + [ + "2018-12-03T00:00:00+01:00" + ] + +``api/groups//courses/weeks/current/`` +------------------------------------------ +Retourne la liste des cours du groupe et de ses parents pendant la +semaine courante (ou prochaine lors du week-end) d’un groupe, par +ordre de début. :ref:`Le résultat peut être paginé `. +Le format du résultat est identique à celui de +:ref:`api/groups/\/courses/ `. + +.. _ref-groups-courses-week-arg: + +``api/groups//courses/weeks///`` +------------------------------------------------ +Retourne la liste des cours du groupe et de ses parents pendant la +semaine spécifiée, par ordre de début. Si l’année et la semaine ne +sont pas des nombres, un code 404 est renvoyé. Si la semaine n’est +pas comprise entre 1 et 53, une erreur 400 est renvoyée, et les +erreurs rencontrées sont renvoyées. :ref:`Le résultat peut être +paginé `. Le format du résultat est identique à celui +de :ref:`api/groups/\/courses/ `. + +Exemple d’erreur (``api/groups//courses/weeks/2018/111/``) : +```````````````````````````````````````````````````````````````` +.. code:: json + + { + "week": "Rentrez une semaine valide" + } + +Salles +====== + +``api/rooms/`` +-------------- +Liste les salles par ordre alphabétique. :ref:`Le résultat peut être +paginé `. + +Exemple : +````````` +.. code:: json + + { + "count": 3, + "next": null, + "previous": null, + "results": [ + { + "id": 26, + "name": "1R1-010", + "slug": "1r1-010" + }, + { + "id": 11, + "name": "1TP1-B08", + "slug": "1tp1-b08" + }, + { + "id": 5, + "name": "1TP1-B08bis", + "slug": "1tp1-b08bis" + } + ] + } + +``api/rooms/`` +------------------ +Renvoie une seule salle. + +Exemple : +````````` +.. code:: json + + { + "id": 26, + "name": "1R1-010", + "slug": "1r1-010" + } + +``api/rooms//courses/`` +--------------------------- +Renvoie la liste des cours se déroulant dans une salle par ordre de +début. :ref:`Le résultat peut être paginé `. Le +format du résultat est identique à celui de +:ref:`api/groups/\/courses/ `. + +``api/rooms//courses/weeks/current/`` +----------------------------------------- +Renvoie la liste des cours se déroulant dans une salle pendant la +semaine courante (ou la semaine prochaine le week-end) par ordre de +début. :ref:`Le résultat peut être paginé `. Le +format du résultat est identique à celui de +:ref:`api/groups/\/courses/ `. + +``api/rooms//courses/weeks///`` +----------------------------------------------- +Renvoie la liste des cours se déroulant dans une salle pendant la +semaine spécifiée. Si l’année et la semaine ne sont pas des nombres, +un code 404 est renvoyé. Si la semaine n’est pas comprise entre 1 et +53, une erreur 400 est renvoyée, et les erreurs rencontrées sont +renvoyées. :ref:`Le résultat peut être paginé `. Le +format du résultat est identique à celui de +:ref:`api/groups/\/courses/weeks/\/\ +`. + +``api/rooms/qsjps////`` +---------------------------------------- +Fournit un accès à QSJPS. ```` est une date devant être formatée +de cette manière : ``YYYY-MM-DD``. ```` et ```` sont des +heures qui doivent être formatées de cette manière : ``HH:mm``. La +valeur de ```` doit être inférieure à celle de ````. + +Renvoie la liste des salles vides le début du jour ```` de +```` à ````. + +En cas de mauvais formatage, une erreur 400 est renvoyée, et les +erreurs sont détaillées dans le corps de la réponse. Sinon, la liste +des salles libres est renvoyée. + +Exemple : +````````` +.. code:: json + + [ + { + "id": 26, + "name": "1R1-010", + "slug": "1r1-010" + }, + { + "id": 11, + "name": "1TP1-B08", + "slug": "1tp1-b08" + }, + { + "id": 5, + "name": "1TP1-B08bis", + "slug": "1tp1-b08bis" + } + ] + +Exemple d’erreur (``api/rooms/qsjps/2019-01-35/12:00/10:00/``) : +```````````````````````````````````````````````````````````````` +.. code:: json + + { + "day": [ + "Saisissez une date valide." + ], + "end": [ + "L’heure de début doit être supérieure à celle de fin." + ] + } + +Exemple d’erreur (``api/rooms/qsjps/2019-01-35/12:70/10:70/``) : +```````````````````````````````````````````````````````````````` +.. code:: json + + { + "day": [ + "Saisissez une date valide." + ], + "begin": [ + "Saisissez une heure valide." + ], + "end": [ + "Saisissez une heure valide." + ] + } + +Cours +===== + +``api/courses/`` +---------------- +Renvoie la liste des cours. :ref:`Le résultat peut être paginé +`. + +Exemple : +````````` +.. code:: json + + { + "count": 4766, + "next": "http://localhost:8000/api/courses/?page=2", + "previous": null, + "results": [ + { + "id": 22133, + "groups": [ + { + "id": 98, + "name": "L3 INFO s1 CMA", + "celcat_name": "L3 INFO s1 CMA", + "mention": "L3 INFO", + "semester": 1, + "subgroup": "A", + "slug": "l3-info-s1-cma", + "hidden": false, + "source": 1 + } + ], + "rooms": [ + { + "id": 1, + "name": "Amphi AMPERE (3A)", + "slug": "amphi-ampere-3a" + } + ], + "name": "REUNION / RENCONTRE", + "type": null, + "notes": null, + "begin": "2018-09-04T15:45:00+02:00", + "end": "2018-09-04T16:45:00+02:00", + "last_update": "2018-09-26T19:34:12.924533+02:00", + "source": 1 + }, + … + ] + } + +``api/courses/`` +-------------------- +Renvoie un seul cours. + +Exemple : +````````` +.. code:: json + + { + "id": 22133, + "groups": [ + { + "id": 98, + "name": "L3 INFO s1 CMA", + "celcat_name": "L3 INFO s1 CMA", + "mention": "L3 INFO", + "semester": 1, + "subgroup": "A", + "slug": "l3-info-s1-cma", + "hidden": false, + "source": 1 + } + ], + "rooms": [ + { + "id": 1, + "name": "Amphi AMPERE (3A)", + "slug": "amphi-ampere-3a" + } + ], + "name": "REUNION / RENCONTRE", + "type": null, + "notes": null, + "begin": "2018-09-04T15:45:00+02:00", + "end": "2018-09-04T16:45:00+02:00", + "last_update": "2018-09-26T19:34:12.924533+02:00", + "source": 1 + } + +.. _ref-pagination: + +Pagination +========== +Il est possible que les résultats soient paginés. Cela dépend de la +configuration de l’instance de celcatsanitizer. Dans ce cas, tous les +appels à des points d’accès renvoyant des résultats pouvant être +paginés se trouvent dans ce genre de structure : + +.. code:: json + + { + "count": 4766, + "next": "http://localhost:8000/api/courses/?page=2", + "previous": null, + "results": [ + … + ] + } + + - ``count`` représente le nombre d’éléments au total (et non pas sur + la page). + - ``next`` est le lien de la page de résultats suivants, si il y en a + une. + - ``previous`` est le lien de la page de résultats précédents, si il + y en a une. + - ``results`` est la liste des résultats, si il y en a. -- cgit v1.2.1