From b0211666b3f3437a0496b9c9f03a3613698b9804 Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Sun, 23 Sep 2018 19:34:27 +0200 Subject: ups2018: déduplication avec OrderedDict au lieu de set() set() ne conserve pas nécessairement l’ordre des données, ce qui a plusieurs conséquences. Premièrement, un cours avec plusieurs noms séparés par un point-virgule peut changer de nom dans celcatsanitizer d’une mise à jour à une autre. Deuxièmement, cette fonctionnalité devient intestable de manière certaine. Pour remédier à cela, on utilise la structure OrderedDict à la place. Signed-off-by: Alban Gruin --- management/parsers/ups2018.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/management/parsers/ups2018.py b/management/parsers/ups2018.py index 15c629a..4ae7ef7 100644 --- a/management/parsers/ups2018.py +++ b/management/parsers/ups2018.py @@ -14,6 +14,7 @@ # along with celcatsanitizer. If not, see . from datetime import datetime, timedelta +from collections import OrderedDict import asyncio import calendar @@ -104,7 +105,11 @@ class Parser(AbstractParser): groups = data[i] if i - 1 >= 0: - course.name = ", ".join(set(data[i - 1].split(';'))) + # TODO: le jour où la version minimale supportée sera + # Python 3.7, il sera possible de remplacer OrderedDict + # par un dictionnaire classique. + names = OrderedDict.fromkeys(data[i - 1].split(';')) + course.name = ", ".join(names.keys()) else: course.name = "Sans nom" if i - 2 >= 0: -- cgit v1.2.1 From f9da11d173229ac9dc197fa25163479686b5d0d6 Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Sun, 23 Sep 2018 19:40:17 +0200 Subject: ups2018: détection du premier élément « utile » des données du cours La plupart des cours contiennent un élément correspondant à l’heure de début et de fin du cours. Lorsqu’un cours ne possède pas de nom, il se peut que cet élément soit utilisé comme type, ce qui n’a pas de sens. On va donc détecter la présence de cet élément à la première place à l’aide d’une regex, et, si jamais il est présent, on n’utilise pas le premier élément de la liste. À l’origine, cet élément ne devait pas être utilisé pour cette raison, mais ce comportement a été changé avec le commit ab6ca3c ("parsers: correction de l’index du premier élément à analyser"), après la détection de cours n’ayant pas cet élément. Signed-off-by: Alban Gruin --- management/parsers/ups2018.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/management/parsers/ups2018.py b/management/parsers/ups2018.py index 4ae7ef7..805c761 100644 --- a/management/parsers/ups2018.py +++ b/management/parsers/ups2018.py @@ -19,6 +19,7 @@ from collections import OrderedDict import asyncio import calendar import json +import re from django.utils import timezone @@ -95,7 +96,11 @@ class Parser(AbstractParser): if data[0] == "Global Event": return - i = 0 + min_i = 0 + if len(data) > 0 and re.match("^\(\d+:\d+-\d+:\d+\)$", data[0]): + min_i = 1 + + i = min_i while i < len(data) and not data[i].startswith( ("L1 ", "L2 ", "L3 ", "L3P ", "M1 ", "M2 ", "DEUST ", "MAG1 ", "1ERE ANNEE ", "2EME ANNEE ", "3EME ANNEE ", @@ -104,7 +109,7 @@ class Parser(AbstractParser): i += 1 groups = data[i] - if i - 1 >= 0: + if i - 1 >= min_i: # TODO: le jour où la version minimale supportée sera # Python 3.7, il sera possible de remplacer OrderedDict # par un dictionnaire classique. @@ -112,7 +117,7 @@ class Parser(AbstractParser): course.name = ", ".join(names.keys()) else: course.name = "Sans nom" - if i - 2 >= 0: + if i - 2 >= min_i: course.type = data[i - 2] if len(data) >= i + 2: rooms = data[i + 1] -- cgit v1.2.1 From ecee7054329e55dc861970fc667bb1d3be6627d5 Mon Sep 17 00:00:00 2001 From: Maxime Date: Fri, 28 Sep 2018 21:34:32 +0200 Subject: Changement de "Semaine NN" vers "Semaine Suivante/Précédente" --- templates/timetable.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/timetable.html b/templates/timetable.html index a6dc1ab..9866079 100644 --- a/templates/timetable.html +++ b/templates/timetable.html @@ -29,13 +29,13 @@ {% endif %} – {% if last_week is not None %} - Semaine {{ last_week|dt_week }} + Semaine Précédente – {% endif %} {% if next_week is not None %} - Semaine {{ next_week|dt_week }} + Semaine Suivante – {% endif %} -- cgit v1.2.1 From 2123fbe0311457933785d6715db09f5ecdf63437 Mon Sep 17 00:00:00 2001 From: Maxime Date: Fri, 28 Sep 2018 22:17:31 +0200 Subject: Changement de "Semaine Suivante/Précédente" vers "Semaine suivante/précédente" --- templates/timetable.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/timetable.html b/templates/timetable.html index 9866079..79c5471 100644 --- a/templates/timetable.html +++ b/templates/timetable.html @@ -29,13 +29,13 @@ {% endif %} – {% if last_week is not None %} - Semaine Précédente + Semaine précédente – {% endif %} {% if next_week is not None %} - Semaine Suivante + Semaine suivante – {% endif %} -- cgit v1.2.1 From 0533690d2423214c3cd1c013cab6242c10f9d094 Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Sat, 29 Sep 2018 16:45:53 +0200 Subject: ups2018: pas de création de cours si l’événement est global Pour l’instant, on ne souhaite pas enregistrer les événement globaux. On vérifie donc si l’événement est global, et, si c’est le cas, on ne traite pas l’événement. Or, on insérait un cours dans la base de données avant de faire ce test. Un cours avec aucun attribut était donc laissé dans la base de données. Ce commit déplace donc la création du cours après avoir vérifié si un événement est global. Signed-off-by: Alban Gruin --- management/parsers/ups2018.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/management/parsers/ups2018.py b/management/parsers/ups2018.py index 805c761..522a26a 100644 --- a/management/parsers/ups2018.py +++ b/management/parsers/ups2018.py @@ -87,15 +87,15 @@ class Parser(AbstractParser): if event_year != year or event_week != week: return - course = Course.objects.create( - source=self.source, begin=begin, end=end - ) - data = event["text"].split("
") rooms = None if data[0] == "Global Event": return + course = Course.objects.create( + source=self.source, begin=begin, end=end + ) + min_i = 0 if len(data) > 0 and re.match("^\(\d+:\d+-\d+:\d+\)$", data[0]): min_i = 1 -- cgit v1.2.1 From 82d95e3d9bc7409974496f2d99952a7860d43d08 Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Fri, 28 Sep 2018 22:35:25 +0200 Subject: forms: correction du message d’erreur de QSJPS Lorsque le formulaire de QSJPS est incorrect, il manque un espace au message affiché. Ce commit corrige cela. Signed-off-by: Alban Gruin --- forms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/forms.py b/forms.py index d4ee94d..b1a3052 100644 --- a/forms.py +++ b/forms.py @@ -64,6 +64,6 @@ class QSJPSForm(forms.Form): form_data["begin"] >= form_data["end"]: # Si l’heure de fin est plus petite ou égale, on affiche # une erreur. - self.add_error("end", "L’heure de début doit être" + self.add_error("end", "L’heure de début doit être " "supérieure à celle de fin.") return form_data -- cgit v1.2.1 From 8666eeda04d8c57c9857c98cf357eb7572046a9d Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Fri, 28 Sep 2018 22:36:20 +0200 Subject: views: code d’erreur 400 lorsque le formulaire de QSJPS est invalide Ce commit change le code HTTP renvoyé si le formulaire de QSJPS est invalide. Le code renvoyé était le code 200, signifiant que la requête s’est bien déroulée. Avec ce commit, on renvoye un code 400, qui indique à l’utilisateur que sa requête est invalide. Signed-off-by: Alban Gruin --- views.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/views.py b/views.py index e45ece3..de38f35 100644 --- a/views.py +++ b/views.py @@ -259,6 +259,8 @@ def room_timetable(request, room_slug, year=None, week=None): @csrf_exempt def qsjps(request): + status = 200 + if request.method == "POST": # Si on traite un formulaire, on le valide form = QSJPSForm(request.POST) @@ -278,12 +280,13 @@ def qsjps(request): # Si le formulaire est invalide, on ré-affiche le formulaire # avec les erreurs + status = 400 else: # Si le formulaire n’a pas été soumis, on en instancie un # nouveau form = QSJPSForm() - return render(request, "qsjps_form.html", {"form": form}) + return render(request, "qsjps_form.html", {"form": form}, status=status) def ctx_processor(request): -- cgit v1.2.1 From 7f8a890bc12e64037501c71182a9960513815c6d Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Sat, 29 Sep 2018 16:55:39 +0200 Subject: doc: mise à jour de la documentation Signed-off-by: Alban Gruin --- Documentation/usage/versions.rst | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Documentation/usage/versions.rst b/Documentation/usage/versions.rst index 8812b17..b0a1fb4 100644 --- a/Documentation/usage/versions.rst +++ b/Documentation/usage/versions.rst @@ -88,3 +88,20 @@ Version 0.14.1 l’heure de début est après l’heure de fin. - Correction d’un bogue lorsqu’un cours ne possède ni nom ni type dans le parseur UPS2018, résultant en un échec de mise à jour. + +Version 0.14.2 +-------------- + - Renvoi d’un code d’erreur 400 lorsque le formulaire de QSJPS est + invalide. + - Correction du texte d’erreur du formulaire de QSJPS. + - Changement des textes « semaine N » par « semaine + précédente/suivante » dans les calendriers. + - Correction d’un bogue qui faisait croire au parseur que l’heure de + début et de fin d’un cours était son type. + - Correction d’un bogue qui faisait que le parseur créait un cours + vide quand il traitait un événement global, alors qu’il ne devrait + pas en créer du tout. + - Lorsqu’un cours a plusieurs noms, la technique de déduplication + utilisée jusqu’alors faisait que l’ordre des noms n’était pas + forcément identique d’une mise à jour à une autre. Cette technique + a été changée par une autre permettant de conserver cet ordre. -- cgit v1.2.1 From c95740a4d97fc579f4f12a6abf01eac446fde1cc Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Sat, 29 Sep 2018 16:57:44 +0200 Subject: Version 0.14.2 Signed-off-by: Alban Gruin --- Documentation/conf.py | 2 +- __init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/conf.py b/Documentation/conf.py index 198e67a..ad8660d 100644 --- a/Documentation/conf.py +++ b/Documentation/conf.py @@ -15,7 +15,7 @@ copyright = u'%d, Alban Gruin' % year author = u'Alban Gruin' version = u'0.14' -release = u'0.14.1' +release = u'0.14.2' language = 'fr' diff --git a/__init__.py b/__init__.py index d95a5fd..a67d67f 100644 --- a/__init__.py +++ b/__init__.py @@ -13,7 +13,7 @@ # You should have received a copy of the GNU Affero General Public License # along with celcatsanitizer. If not, see . -VERSION = "0.14.1" +VERSION = "0.14.2" __version__ = VERSION default_app_config = "edt.apps.EdtConfig" -- cgit v1.2.1