aboutsummaryrefslogtreecommitdiff
path: root/Documentation/usage
diff options
context:
space:
mode:
Diffstat (limited to 'Documentation/usage')
-rw-r--r--Documentation/usage/commands/printvalues.rst48
-rw-r--r--Documentation/usage/installation.rst39
-rw-r--r--Documentation/usage/rest.rst753
-rw-r--r--Documentation/usage/versions.rst5
4 files changed, 845 insertions, 0 deletions
diff --git a/Documentation/usage/commands/printvalues.rst b/Documentation/usage/commands/printvalues.rst
new file mode 100644
index 0000000..7d53d44
--- /dev/null
+++ b/Documentation/usage/commands/printvalues.rst
@@ -0,0 +1,48 @@
+===============
+``printvalues``
+===============
+
+``printvalues`` affiche le contenu brut d’un ou plusieurs cours, sans
+chercher à interpréter son contenu ou à l’enregistrer dans la base de
+données.
+
+Utilisation
+===========
+.. code:: shell
+
+ $ ./manage.py printvalues --source id [--limit nb]
+
+``--source`` permet de spécifier la source depuis laquelle les cours
+doivent être récupérés. ``id`` correspond à l’ID de la source,
+trouvable à l’aide de la commande :doc:`listtimetables`.
+
+``--limit`` permet de limiter le nombre de cours affichés. ``nb``
+correspond au nombre maximum de cours affichés.
+
+Format de sortie
+================
+::
+
+ {
+ "backColor": "#7D4F72",
+ "clickDisabled": true,
+ "doubleClickDisabled": true,
+ "end": "2019-01-28T09:45:00",
+ "html": "<div style=\"color:White \">(07:45-09:45)<br>COURS/TD<br>ELINF6Q1 - BIOLOGIE<br>L3 INFO s2 CMA<br>U3-307</div>",
+ "id": "76330023",
+ "moveDisabled": true,
+ "resizeDisabled": true,
+ "sort": [],
+ "start": "2019-01-28T07:45:00",
+ "tag": [
+ "celcat",
+ "sat_notvalid",
+ "1",
+ "reg_notmark",
+ "ELINF6Q1",
+ "7491453"
+ ],
+ "text": "(07:45-09:45)<br>COURS/TD<br>ELINF6Q1 - BIOLOGIE<br>L3 INFO s2 CMA<br>U3-307",
+ "toolTip": "(07:45-09:45)<br>COURS/TD<br>ELINF6Q1 - BIOLOGIE<br>L3 INFO s2 CMA<br>U3-307"
+ }
+ Done.
diff --git a/Documentation/usage/installation.rst b/Documentation/usage/installation.rst
index 4dde4f4..92b3c5d 100644
--- a/Documentation/usage/installation.rst
+++ b/Documentation/usage/installation.rst
@@ -12,6 +12,10 @@ suivantes :
- BeautifulSoup4_ et LXML_, pour parser les emplois du temps en XML
- icalendar_, pour générer des fichiers ICS_.
+Une dépendance est optionnelle :
+
+ - `Django REST Framework`_, pour l’:doc:`API REST <rest>`.
+
celcatsanitizer requiert Python 3.4 au minimum, et marche avec les
versions 3.5 et 3.6. Les versions antérieures de Python 3 n’ont pas
étés testées, et les versions supérieures devraient fonctionner sans
@@ -31,6 +35,7 @@ Pour l’instant, l’installation doit passer par git_.
.. _LXML: https://lxml.de/
.. _icalendar: https://icalendar.readthedocs.io/en/latest/
.. _ICS: https://fr.wikipedia.org/wiki/ICalendar
+.. _Django REST Framework: https://www.django-rest-framework.org/
.. _PostgreSQL: https://www.postgresql.org/
.. _psycopg2: http://initd.org/psycopg/docs/install.html
.. _git: https://git-scm.com/
@@ -95,6 +100,13 @@ psycopg2 :
$ pip install psycopg2-binary
+Si vous souhaitez activer l’API REST, vous devez installer le module
+Django Rest Framework :
+
+.. code:: shell
+
+ $ pip install djangorestframework
+
Si vous êtes en production, il est recommandé d’utiliser gunicorn_ si
vous n’utilisez pas le serveur Apache. Installez-le de la même
manière :
@@ -232,6 +244,33 @@ Ce paramètre est **optionnel**.
__ https://docs.djangoproject.com/fr/2.0/topics/i18n/
+Activation de l’API REST et configuration de Django Rest Framework
+``````````````````````````````````````````````````````````````````
+L’API REST permet à des outils tiers d’accéder facilement aux données
+gérées par celcatsanitizer. Elle est optionnelle, et est basée sur
+Django Rest Framework. :doc:`Plus d’informations sur la page de l’API
+REST <rest>`.
+
+Si vous souhaitez l’activer, vous devez d’abord avoir installé Django
+REST Framework, puis mettre la variable ``CS_ENABLE_API`` à ``True``.
+
+.. code:: Python
+
+ CS_ENABLE_API = True
+
+Ajoutez ensuite 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 **optionnelle**.
+
``urls.py``
-----------
Dans le fichier ``celcatsanitizer/urls.py``, importez la fonction
diff --git a/Documentation/usage/rest.rst b/Documentation/usage/rest.rst
new file mode 100644
index 0000000..d18eaa5
--- /dev/null
+++ b/Documentation/usage/rest.rst
@@ -0,0 +1,753 @@
+========
+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.
+
+En fonction de la configuration de celcatsanitizer, l’API ne sera
+peut-être pas disponible.
+
+Années
+======
+
+``api/years/``
+--------------
+Liste les années par ordre alphabétique de nom. :ref:`Le résultat
+peut être paginé <ref-pagination>`.
+
+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/<id>/``
+-------------------
+Retourne seulement une année.
+
+Exemple :
+`````````
+.. code:: json
+
+ {
+ "id": 1,
+ "name": "L3",
+ "slug": "l3"
+ }
+
+``api/years/<id>/timetables/``
+------------------------------
+Liste les emplois du temps associés à une année par ordre alphabétique
+de nom. :ref:`Le résultat peut être paginé <ref-pagination>`.
+
+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é <ref-pagination>`.
+
+Exemple :
+`````````
+.. code:: json
+
+ {
+ "count": 1,
+ "next": null,
+ "previous": null,
+ "results": [
+ {
+ "id": 1,
+ "name": "Info",
+ "slug": "info",
+ "year": 1,
+ "source": 1
+ }
+ ]
+ }
+
+``api/timetables/<id>/``
+------------------------
+Retourne seulement un emploi du temps.
+
+Exemple :
+`````````
+.. code:: json
+
+ {
+ "id": 1,
+ "name": "Info",
+ "slug": "info",
+ "year": 1,
+ "source": 1
+ }
+
+``api/timetables/<id>/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é
+<ref-pagination>`.
+
+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é <ref-pagination>`.
+
+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/<id>/``
+---------------------
+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/<id>/timetables/``
+--------------------------------
+Renvoie la liste des emplois du temps associé à une source triés par
+ordre alphabétique. :ref:`Le résultat peut être paginé
+<ref-pagination>`.
+
+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é <ref-pagination>`.
+
+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/<id>/``
+--------------------
+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/<id>/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é <ref-pagination>`.
+
+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/<id>/courses/days/current/``
+-----------------------------------------
+Retourne la liste des cours du groupe et de ses parents d’un groupe
+pendant le jour courant, par ordre de début. :ref:`Le résultat peut
+être paginé <ref-pagination>`. Le format du résultat est identique à
+celui de :ref:`api/groups/\<id>/courses/ <ref-groups-courses>`.
+
+.. _ref-groups-courses-day-arg:
+
+``api/groups/<id>/courses/days/<year>/<month>/<day>/``
+------------------------------------------------------
+Retourne la liste des cours du groupe et de ses parents pendant le
+jour spécifié, par ordre de début. Si l’année, le mois ou le jour ne
+sont pas des nombres, un code 404 est renvoyé. Si la date est
+invalide, une erreur 400 est renvoyée, et les erreurs rencontrées sont
+renvoyées. :ref:`Le résultat peut être paginé <ref-pagination>`. Le
+format du résultat est identique à celui de
+:ref:`api/groups/\<id>/courses/ <ref-groups-courses>`.
+
+Exemple d’erreur (``api/groups/<id>/courses/days/2018/111/22``) :
+`````````````````````````````````````````````````````````````````
+.. code:: json
+
+ {
+ "month": "Rentrez un mois valide"
+ }
+
+Exemple d’erreur (``api/groups/<id>/courses/days/2018/11/33``) :
+````````````````````````````````````````````````````````````````
+.. code:: json
+
+ {
+ "day": "Numéro de jour invalide pour le mois"
+ }
+
+``api/groups/<id>/courses/weeks/``
+----------------------------------
+Retourne la liste des semaines de cours d’un groupe.
+
+Exemple :
+`````````
+.. code:: json
+
+ [
+ "2018-12-03T00:00:00+01:00"
+ ]
+
+``api/groups/<id>/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é <ref-pagination>`.
+Le format du résultat est identique à celui de
+:ref:`api/groups/\<id>/courses/ <ref-groups-courses>`.
+
+.. _ref-groups-courses-week-arg:
+
+``api/groups/<id>/courses/weeks/<year>/<week>/``
+------------------------------------------------
+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 ou 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é <ref-pagination>`. Le format du résultat est identique à celui
+de :ref:`api/groups/\<id>/courses/ <ref-groups-courses>`.
+
+Exemple d’erreur (``api/groups/<id>/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é <ref-pagination>`.
+
+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/<id>/``
+-------------------
+Renvoie une seule salle.
+
+Exemple :
+`````````
+.. code:: json
+
+ {
+ "id": 26,
+ "name": "1R1-010",
+ "slug": "1r1-010"
+ }
+
+``api/rooms/<id>/courses/``
+---------------------------
+Renvoie la liste des cours se déroulant dans une salle par ordre de
+début. :ref:`Le résultat peut être paginé <ref-pagination>`. Le
+format du résultat est identique à celui de
+:ref:`api/groups/\<id>/courses/ <ref-groups-courses>`.
+
+``api/rooms/<id>/courses/days/current/``
+----------------------------------------
+Retourne la liste des cours se déroulant dans une salle pendant le
+jour courant, par ordre de début. :ref:`Le résultat peut être paginé
+<ref-pagination>`. Le format du résultat est identique à celui de
+:ref:`api/groups/\<id>/courses/ <ref-groups-courses>`.
+
+``api/rooms/<id>/courses/days/<year>/<month>/<day>/``
+-----------------------------------------------------
+Retourne la liste des cours se déroulant dans une salle pendant le
+jour spécifié, par ordre de début. Si l’année, le mois ou le jour ne
+sont pas des nombres, un code 404 est renvoyé. Si la date est
+invalide, une erreur 400 est renvoyée, et les erreurs rencontrées sont
+renvoyées. :ref:`Le résultat peut être paginé <ref-pagination>`. Le
+format du résultat est identique à celui de
+:ref:`api/groups/\<id>/courses/days/\<year>/\<month>/\<day>/
+<ref-groups-courses-day-arg>`.
+
+``api/rooms/<id>/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é <ref-pagination>`. Le
+format du résultat est identique à celui de
+:ref:`api/groups/\<id>/courses/ <ref-groups-courses>`.
+
+``api/rooms/<id>/courses/weeks/<year>/<week>/``
+-----------------------------------------------
+Renvoie la liste des cours se déroulant dans une salle pendant la
+semaine spécifiée. Si l’année ou 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é <ref-pagination>`. Le
+format du résultat est identique à celui de
+:ref:`api/groups/\<id>/courses/weeks/\<year>/\<week>/
+<ref-groups-courses-week-arg>`.
+
+``api/rooms/qsjps/<day>/<begin>/<end>/``
+----------------------------------------
+Fournit un accès à QSJPS. ``<day>`` est une date devant être formatée
+de cette manière : ``YYYY-MM-DD``. ``<begin>`` et ``<end>`` sont des
+heures qui doivent être formatées de cette manière : ``HH:mm``. La
+valeur de ``<begin>`` doit être inférieure à celle de ``<end>``.
+
+Renvoie la liste des salles vides le début du jour ``<day>`` de
+``<begin>`` à ``<end>``.
+
+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é
+<ref-pagination>`.
+
+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/<id>/``
+---------------------
+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.
diff --git a/Documentation/usage/versions.rst b/Documentation/usage/versions.rst
index 71f122d..ed76ce5 100644
--- a/Documentation/usage/versions.rst
+++ b/Documentation/usage/versions.rst
@@ -113,3 +113,8 @@ Version 0.14.3
d’une vérification lors de la récupération des pages ; si une page
est invalide, elle est re-demandée tant qu’elle est incomplète, et
ce trois fois au maximum.
+
+Version 0.14.4
+--------------
+ - Ajout d’une liste de logiciels lisant les calendriers au format ICS
+ et déconseillant l’usage de Google Calendar.