diff options
| -rw-r--r-- | Documentation/index.rst | 1 | ||||
| -rw-r--r-- | Documentation/usage/commands/printvalues.rst | 48 | ||||
| -rw-r--r-- | admin.py | 14 | ||||
| -rw-r--r-- | management/commands/__parsercommand.py | 26 | ||||
| -rw-r--r-- | management/commands/printvalues.py | 45 | ||||
| -rw-r--r-- | management/commands/timetables.py | 16 | ||||
| -rw-r--r-- | management/parsers/ups2018.py | 14 | ||||
| -rw-r--r-- | models.py | 17 | ||||
| -rw-r--r-- | templates/index.html | 2 | ||||
| -rw-r--r-- | templates/mention_list.html | 2 | ||||
| -rw-r--r-- | tests.py | 341 | ||||
| -rw-r--r-- | tests/data/2018/empty.html | 50 | ||||
| -rw-r--r-- | tests/data/2018/october.html | 50 | ||||
| -rw-r--r-- | tests/data/2018/september.html | 51 | 
14 files changed, 642 insertions, 35 deletions
diff --git a/Documentation/index.rst b/Documentation/index.rst index e8dd4f2..7073b0d 100644 --- a/Documentation/index.rst +++ b/Documentation/index.rst @@ -61,6 +61,7 @@ Utilisation de celcatsanitizer     usage/installation     usage/commands/cleancourses     usage/commands/listtimetables +   usage/commands/printvalues     usage/commands/reparse     usage/commands/timetables     usage/rest 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. @@ -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,7 +14,7 @@  #    along with celcatsanitizer.  If not, see <http://www.gnu.org/licenses/>.  from django.contrib import admin -from .models import Course, Group, Room, Source, Timetable, Year +from .models import Course, Group, Module, Room, Source, Timetable, Year  def make_hidden(modeladmin, request, queryset): @@ -62,7 +62,7 @@ class GroupAdmin(admin.ModelAdmin):      actions = (make_hidden, make_visible,) -@admin.register(Room) +@admin.register(Room, Module)  class RoomAdmin(admin.ModelAdmin):      prepopulated_fields = {"slug": ("name",)}      list_display = ("name",) @@ -72,10 +72,12 @@ class RoomAdmin(admin.ModelAdmin):  @admin.register(Course)  class CourseAdmin(admin.ModelAdmin):      fieldsets = ( -        (None, {"fields": ("name", "type", "source", "groups", "rooms", -                           "last_update",)}), +        (None, {"fields": ("name", "type", "source", "groups", "rooms",)}),          ("Horaires", {"fields": ("begin", "end",)}), -        ("Remarques", {"fields": ("notes",)}),) +        ("Remarques", {"fields": ("notes",)}), +        ("Avancé", {"fields": ("celcat_id", "last_update",), +                    "classes": ("collapse",)}),)      list_display = ("name", "type", "source", "begin", "end",)      list_filter = ("type", "source__timetables", "groups",)      ordering = ("begin",) +    readonly_fields = ("celcat_id", "last_update",) diff --git a/management/commands/__parsercommand.py b/management/commands/__parsercommand.py new file mode 100644 index 0000000..99480cc --- /dev/null +++ b/management/commands/__parsercommand.py @@ -0,0 +1,26 @@ +#    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 <http://www.gnu.org/licenses/>. + +from importlib import import_module + +from django.conf import settings + +DEFAULT_PARSER = "edt.management.parsers.ups2017" + + +class ParserCommand: +    def get_parser(self): +        parser_module = getattr(settings, "CS_PARSER", DEFAULT_PARSER) +        return getattr(import_module(parser_module), "Parser") diff --git a/management/commands/printvalues.py b/management/commands/printvalues.py new file mode 100644 index 0000000..91dd18b --- /dev/null +++ b/management/commands/printvalues.py @@ -0,0 +1,45 @@ +#    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 <http://www.gnu.org/licenses/>. + +from django.core.management.base import BaseCommand + +from ...models import Source +from .__parsercommand import ParserCommand + +import json + + +class Command(BaseCommand, ParserCommand): +    help = "List values from courses from a source" + +    def add_arguments(self, parser): +        parser.add_argument("--source", type=int, nargs=1, required=True) +        parser.add_argument("--limit", type=int, nargs=1) + +    def handle(self, *args, **options): +        source = Source.objects.get(pk=options["source"][0]) +        parser = self.get_parser()(source) +        events = [event for month in parser.get_source() for event in month] + +        i = 0 +        limit = len(events) +        if options["limit"] is not None: +            limit = min(options["limit"][0], limit) + +        while i < limit: +            self.stdout.write(json.dumps(events[i], indent=4, sort_keys=True)) +            i += 1 + +        self.stdout.write(self.style.SUCCESS("Done.")) diff --git a/management/commands/timetables.py b/management/commands/timetables.py index ee33f7e..f71accf 100644 --- a/management/commands/timetables.py +++ b/management/commands/timetables.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 @@ -13,20 +13,16 @@  #    You should have received a copy of the GNU Affero General Public License  #    along with celcatsanitizer.  If not, see <http://www.gnu.org/licenses/>. -from importlib import import_module -  import datetime  import traceback -from django.conf import settings  from django.core.management.base import BaseCommand  from django.db import transaction  from django.db.models import Min  from ...models import Course, Source  from ...utils import get_week, tz_now - -DEFAULT_PARSER = "edt.management.parsers.ups2017" +from .__parsercommand import ParserCommand  def delete_courses_in_week(source, year, week, today): @@ -122,7 +118,7 @@ def process_timetable(source, force, parser_cls, year=None, weeks=None):          process_timetable_week(source, force, parser) -class Command(BaseCommand): +class Command(BaseCommand, ParserCommand):      help = "Fetches registered celcat timetables"      def add_arguments(self, parser): @@ -134,14 +130,10 @@ class Command(BaseCommand):                              nargs="+")          parser.add_argument("--year", type=int, nargs=1) -    def __get_parser(self): -        parser_module = getattr(settings, "CS_PARSER", DEFAULT_PARSER) -        return getattr(import_module(parser_module), "Parser") -      def handle(self, *args, **options):          year = None          errcount = 0 -        parser = self.__get_parser() +        parser = self.get_parser()          if options["all"]:              weeks = None diff --git a/management/parsers/ups2018.py b/management/parsers/ups2018.py index f1da5bf..afbfc4b 100644 --- a/management/parsers/ups2018.py +++ b/management/parsers/ups2018.py @@ -1,4 +1,4 @@ -#    Copyright (C) 2018  Alban Gruin +#    Copyright (C) 2018-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 @@ -26,7 +26,7 @@ from django.utils import timezone  import lxml.html  import requests -from ...models import Course, Group, Room +from ...models import Course, Group, Module, Room  from ...utils import get_current_week, get_week  from .abstractparser import AbstractParser, ParserError @@ -114,7 +114,8 @@ class Parser(AbstractParser):              return          course = Course.objects.create( -            source=self.source, begin=begin, end=end +            source=self.source, begin=begin, end=end, +            celcat_id=int(event["id"])          )          min_i = 0 @@ -136,6 +137,13 @@ class Parser(AbstractParser):              # par un dictionnaire classique.              names = OrderedDict.fromkeys(data[i - 1].split(';'))              course.name = ", ".join(names.keys()) + +            module_names = [t for t in event["tag"] +                            if len(t) > 0 and +                            any(n.startswith(t) for n in names.keys())] +            if len(module_names) > 0: +                module, _ = Module.objects.get_or_create(name=module_names[0]) +                course.module = module          else:              course.name = "Sans nom"          if i - 2 >= min_i: @@ -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 @@ -200,6 +200,18 @@ class Room(SlugModel):          verbose_name_plural = "salles" +class Module(SlugModel): +    name = models.CharField(max_length=255, unique=True, verbose_name="nom") +    slug = models.SlugField(max_length=64, default="", unique=True) + +    def __str__(self): +        return self.name + +    class Meta: +        verbose_name = "module" +        verbose_name_plural = "modules" + +  class CourseManager(Manager):      def get_courses(self, obj, **criteria):          qs = self.get_queryset() @@ -246,6 +258,9 @@ class Course(models.Model):      last_update = models.DateTimeField(verbose_name="dernière mise à jour",                                         default=timezone.now) +    celcat_id = models.IntegerField(verbose_name="ID Celcat", null=True) +    module = models.ForeignKey(Module, on_delete=models.SET_NULL, null=True) +      def __str__(self):          return self.name diff --git a/templates/index.html b/templates/index.html index e86038e..53cefd5 100644 --- a/templates/index.html +++ b/templates/index.html @@ -25,7 +25,7 @@        {% endblock %}      </div>      <footer> -      <p>(c) 2018 – Alban Gruin – <a href="{% url "django.contrib.flatpages.views.flatpage" url="contact/" %}">contacter</a> – celcatsanitizer {{ celcatsanitizer_version }} – <a href="{% url "django.contrib.flatpages.views.flatpage" url="a-propos/" %}">à propos</a><br /> +      <p>(c) 2019 – Alban Gruin – <a href="{% url "django.contrib.flatpages.views.flatpage" url="contact/" %}">contacter</a> – celcatsanitizer {{ celcatsanitizer_version }} – <a href="{% url "django.contrib.flatpages.views.flatpage" url="a-propos/" %}">à propos</a><br />        Design inspiré par <a href="https://bestmotherfucking.website/">https://bestmotherfucking.website/</a></p>      </footer>    </body> diff --git a/templates/mention_list.html b/templates/mention_list.html index 3b9d8e8..08d3d4a 100644 --- a/templates/mention_list.html +++ b/templates/mention_list.html @@ -1,6 +1,6 @@  {% extends "index.html" %}  {% block title %}{{ year }} – {% endblock %} -{% block pagetitle %}{{ year }} – Choississez votre mention{% endblock %} +{% block pagetitle %}{{ year }} – Choisissez votre mention{% endblock %}  {% block url %}{% url "groups" year.slug element.slug %}{% endblock %}  {% block navigation %}<a href="{% url "index" %}">Retour à la liste des années</a>{% endblock %} @@ -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 @@ -13,13 +13,46 @@  #    You should have received a copy of the GNU Affero General Public License  #    along with celcatsanitizer.  If not, see <http://www.gnu.org/licenses/>. +from unittest import mock +  from django.test import TestCase  from django.utils import timezone -from .models import Course, Group, Room, Source, Timetable, Year +from .management.parsers.abstractparser import ParserError +from .management.parsers.ups2018 import Parser as UPS2018Parser +from .models import Course, Group, Module, Room, Source, Timetable, Year +from .templatetags.rooms import format_rooms  from .utils import tz_now  import datetime +import os + + +def mock_requests_get(*args, **kwargs): +    class MockedResponse: +        def __init__(self, content=""): +            self.encoding = "utf-8" +            self.content = content +            self.status = 200 + +        def raise_for_status(self): +            return + +    def mocked_response_from_file(filename): +        module_dir = os.path.dirname(__file__) +        filepath = os.path.join(module_dir, filename) +        with open(filepath, "r") as response: +            return MockedResponse(response.read()) + +    if args[0] == "https://example.org/2018": +        if "params" not in kwargs or not kwargs["params"]: +            return mocked_response_from_file("tests/data/2018/september.html") +        elif kwargs["params"].get("Date") == "20181001": +            return mocked_response_from_file("tests/data/2018/october.html") +        else: +            return mocked_response_from_file("tests/data/2018/empty.html") + +    return MockedResponse("<html></html>")  class CourseTestCase(TestCase): @@ -51,7 +84,7 @@ class CourseTestCase(TestCase):          for group in (cma, tda2, self.tpa21, cmb, tdb2, self.tpb21,):              course = Course.objects.create(                  name="{0} course".format(group.name), type="cours", -                source=source, begin=dt, end=dt) +                source=source, begin=dt, end=dt, celcat_id=0)              course.groups.add(group)      def test_get_courses_for_group(self): @@ -300,13 +333,13 @@ class RoomTestCase(TestCase):          group = Group.objects.create(celcat_name="L1 info s2 CMA",                                       source=self.source) -        self.rooms = [Room.objects.create(name="0"), -                      Room.objects.create(name="1"), -                      Room.objects.create(name="2"), -                      Room.objects.create(name="3"), -                      Room.objects.create(name="4"), -                      Room.objects.create(name="5"), -                      Room.objects.create(name="6")] +        self.rooms = [ +            Room.objects.create(name=str(i)) +            for i in range(5) +        ] + [ +            Room.objects.create(name="Amphi {}".format(i)) +            for i in range(5, 7) +        ]          hours = [({"begin": datetime.time(hour=14, minute=0)},),                   ({"begin": datetime.time(hour=16, minute=0)},), @@ -326,10 +359,28 @@ class RoomTestCase(TestCase):                  end = begin + datetime.timedelta(hours=rn.get("duration", 2))                  course = Course.objects.create(source=self.source, -                                               begin=begin, end=end) +                                               begin=begin, end=end, +                                               celcat_id=0)                  course.groups.add(group)                  course.rooms.add(room) +    def test_format(self): +        amphis = self.rooms[-2:] + +        self.assertEqual(format_rooms([]), "") +        self.assertEqual(format_rooms(self.rooms[:1]), "Salle 0") +        self.assertEqual(format_rooms(self.rooms[:2]), "Salles 0, 1") +        self.assertEqual(format_rooms([amphis[0]]), "Amphi 5") +        self.assertEqual(format_rooms(amphis), "Amphi 5, Amphi 6") +        self.assertEqual(format_rooms([amphis[0]] + self.rooms[:1]), +                         "Amphi 5, salle 0") +        self.assertEqual(format_rooms([amphis[0]] + self.rooms[:2]), +                         "Amphi 5, salles 0, 1") +        self.assertEqual(format_rooms(amphis + self.rooms[:1]), +                         "Amphi 5, Amphi 6, salle 0") +        self.assertEqual(format_rooms(amphis + self.rooms[:2]), +                         "Amphi 5, Amphi 6, salles 0, 1") +      def test_qsjps(self):          begin = timezone.make_aware(datetime.datetime.combine(              self.day, datetime.time(hour=15, minute=0))) @@ -345,3 +396,271 @@ class RoomTestCase(TestCase):          self.assertNotIn(self.rooms[4], rooms)          self.assertIn(self.rooms[5], rooms)          self.assertIn(self.rooms[6], rooms) + + +class UPS2018ParserTestCase(TestCase): +    @mock.patch("requests.get", side_effect=mock_requests_get) +    def setUp(self, *args, **kwargs): +        source = Source.objects.create(url="https://example.org/2018") +        self.room = Room.objects.create(name="Salle quelconque") +        self.room2 = Room.objects.create(name="Salle quelconque 2") + +        self.group = Group(celcat_name="L3 Info s1 CMA") +        self.group.source = source +        self.group.save() + +        self.parser = UPS2018Parser(source) + +    def test_get_event(self): +        get_event = self.parser._Parser__get_event +        count = Course.objects.count() +        module_count = Module.objects.count() + +        event = get_event( +            {"start": "2018-09-21T10:00:00", "end": "2018-09-21T12:00:00", +             "text": "(10:00-12:00)<br>COURS/TD<br>Cours quelconque;AAA" +             "<br>L3 Info s1 CMA;L3 Info s1 TDA2<br>" +             "Salle quelconque;Salle quelconque 2<br>Commentaire", "id": "0", +             "tag": ["abc", "def", "AAA"]}, +            timezone.make_aware(datetime.datetime(2018, 9, 21)), +            timezone.make_aware(datetime.datetime(2018, 9, 1)), +            timezone.make_aware(datetime.datetime(2018, 10, 1)), +            2018, 38) + +        ngroup = Group.objects.filter(name="L3 Info s1 TDA2").first() +        self.assertIsNotNone(ngroup) + +        self.assertEqual(event.name, "Cours quelconque, AAA") +        self.assertEqual(event.type, "COURS/TD") +        self.assertIn(self.group, event.groups.all()) +        self.assertIn(ngroup, event.groups.all()) +        self.assertEqual(event.groups.count(), 2) +        self.assertIn(self.room, event.rooms.all()) +        self.assertIn(self.room2, event.rooms.all()) +        self.assertEqual(event.rooms.count(), 2) +        self.assertEqual(event.notes, "Commentaire") +        self.assertEqual(event.celcat_id, 0) +        self.assertEqual(event.begin, timezone.make_aware( +            datetime.datetime(2018, 9, 21, 10, 0, 0))) +        self.assertEqual(event.end, timezone.make_aware( +            datetime.datetime(2018, 9, 21, 12, 0, 0))) +        self.assertEqual(event.module.name, "AAA") + +        count += 1 +        module_count += 1 + +        self.assertEqual(count, Course.objects.count()) +        self.assertEqual(module_count, Module.objects.count()) + +        events = [ +            { +                "text": "(10:00-12:00)<br>COURS/TD<br>Cours quelconque" +                "<br>L3 Info s1 CMA<br>Salle quelconque", +                "name": "Cours quelconque", "type": "COURS/TD", +                "group": self.group, +                "room": self.room, +                "id": "1", +                "tag": ["aaa", "Cours"], +                "meta": 1 +            }, +            { +                "text": "(10:00-12:00)<br>COURS/TD<br>Cours quelconque" +                "<br>L3 Info s1 TDA2<br>Salle quelconque 3", +                "name": "Cours quelconque", +                "type": "COURS/TD", +                "group": ngroup, +                "notes": "Salle quelconque 3", +                "id": "2" +            }, +            { +                "text": "(10:00-12:00)<br>COURS/TD<br>Cours quelconque" +                "<br>L3 Info s1 CMA<br>Salle quelconque 3<br>Commentaire", +                "name": "Cours quelconque", +                "type": "COURS/TD", +                "group": self.group, +                "notes": "Salle quelconque 3\nCommentaire", +                "id": "3" +            }, +            { +                "text": "(10:00-12:00)<br>COURS/TD" +                "<br>L3 Info s1 CMA<br>Salle quelconque 3", +                "name": "COURS/TD", +                "group": self.group, +                "notes": "Salle quelconque 3", +                "id": "4" +            }, +            { +                "text": "COURS/TD<br>L3 Info s1 CMA<br>Salle quelconque 3", +                "name": "COURS/TD", +                "group": self.group, +                "notes": "Salle quelconque 3", +                "id": "5" +            }, +            { +                "text": "L3 Info s1 CMA<br>Salle quelconque", +                "name": "Sans nom", +                "group": self.group, +                "room": self.room, +                "id": "6" +            }, +            { +                "text": "L3 Info s1 CMA<br>Salle quelconque 3", +                "name": "Sans nom", +                "group": self.group, +                "notes": "Salle quelconque 3", +                "id": "7" +            }, +            { +                "text": "(10:00-12:00)<br>L3 Info s1 CMA<br>Salle quelconque", +                "name": "Sans nom", +                "group": self.group, +                "room": self.room, +                "id": "8" +            } +        ] + +        for e in events: +            event = get_event( +                {"start": "2018-09-21T10:00:00", "end": "2018-09-21T12:00:00", +                 "text": e["text"], "id": e["id"], "tag": e.get("tag", [])}, +                timezone.make_aware(datetime.datetime(2018, 9, 21)), +                timezone.make_aware(datetime.datetime(2018, 9, 1)), +                timezone.make_aware(datetime.datetime(2018, 10, 1)), +                2018, 38) + +            self.assertEqual(event.name, e["name"]) +            self.assertIn(e["group"], event.groups.all()) +            self.assertEqual(event.groups.count(), 1) +            self.assertEqual(str(event.celcat_id), e["id"]) + +            if "type" in e: +                self.assertEqual(event.type, e["type"]) +            else: +                self.assertIsNone(event.type) + +            if "room" in e: +                self.assertIn(e["room"], event.rooms.all()) +                self.assertEqual(event.rooms.count(), 1) +            else: +                self.assertEqual(event.rooms.count(), 0) + +            if "notes" in e: +                self.assertEqual(event.notes, e["notes"]) +            else: +                self.assertIsNone(event.notes) + +            if "tag" in e: +                self.assertEqual(event.module.name, e["tag"][e["meta"]]) +                module_count += 1 +            else: +                self.assertIsNone(event.module) + +            count += 1 + +            self.assertEqual(count, Course.objects.count()) +            self.assertEqual(module_count, Module.objects.count()) + +        event = get_event( +            {"start": "2018-09-21T10:00:00", "end": "2018-09-21T12:00:00", +             "text": "Global Event"}, +            timezone.make_aware(datetime.datetime(2018, 9, 21)), +            timezone.make_aware(datetime.datetime(2018, 9, 1)), +            timezone.make_aware(datetime.datetime(2018, 10, 1)), +            2018, 38) +        self.assertIsNone(event) +        self.assertEqual(count, Course.objects.count()) + +        event = get_event( +            {"start": "2018-09-21T10:00:00", "end": "2018-09-21T12:00:00", +             "text": "L3 Info s1 CMA<br>Salle quelconque 2"}, +            timezone.make_aware(datetime.datetime(2018, 9, 21)), +            timezone.make_aware(datetime.datetime(2018, 9, 1)), +            timezone.make_aware(datetime.datetime(2018, 10, 1)), +            2018, 39) +        self.assertIsNone(event) +        self.assertEqual(count, Course.objects.count()) + +    @mock.patch("requests.get", side_effect=mock_requests_get) +    def test_get_events(self, *args, **kwargs): +        self.parser.get_source() +        courses = [ +            {"begin": +             timezone.make_aware(datetime.datetime(2018, 9, 21, 10, 00, 00)), +             "end": +             timezone.make_aware(datetime.datetime(2018, 9, 21, 12, 00, 00)), +             "id": 0}, +            {"begin": +             timezone.make_aware(datetime.datetime(2018, 10, 22, 10, 00, 00)), +             "end": +             timezone.make_aware(datetime.datetime(2018, 10, 22, 12, 00, 00)), +             "id": 2} +        ] + +        for i, course in enumerate(self.parser.get_events( +                timezone.make_aware(datetime.datetime(2018, 9, 21)))): +            self.assertEqual(course.name, "Cours quelconque") +            self.assertEqual(course.type, "COURS/TD") +            self.assertIn(self.group, course.groups.all()) +            self.assertEqual(course.groups.count(), 1) +            self.assertIn(self.room, course.rooms.all()) +            self.assertEqual(course.rooms.count(), 1) +            self.assertIsNone(course.notes) +            self.assertEqual(course.begin, courses[i]["begin"]) +            self.assertEqual(course.end, courses[i]["end"]) +            self.assertEqual(course.celcat_id, courses[i]["id"]) +            self.assertEqual(course.module, None) + +        self.assertEqual(i, len(courses) - 1) + +    @mock.patch("requests.get", side_effect=mock_requests_get) +    def test_get_source(self, *args, **kwargs): +        events = self.parser.get_source() +        self.assertEquals(events, [ +            [{ +                "start": "2018-09-21T10:00:00", "end": "2018-09-21T12:00:00", +                "text": "(10:00-12:00)<br>COURS/TD<br>Cours quelconque" +                "<br>L3 Info s1 CMA<br>Salle quelconque", +                "id": "0", +                "tag": [], +            }], [{ +                "start": "2018-09-21T10:00:00", "end": "2018-09-21T12:00:00", +                "text": "(10:00-12:00)<br>COURS/TD<br>Cours quelconque" +                "<br>L3 Info s1 CMA<br>Salle quelconque", +                "id": "1", +                "tag": [], +            }, { +                "start": "2018-10-22T10:00:00", "end": "2018-10-22T12:00:00", +                "text": "(10:00-12:00)<br>COURS/TD<br>Cours quelconque" +                "<br>L3 Info s1 CMA<br>Salle quelconque", +                "id": "2", +                "tag": [], +            }], [], [], [], [], [], [], [], [], []]) + +    def test_get_update_date(self): +        # Pas de date de mise à jour dans ce format +        self.assertIsNone(self.parser.get_update_date()) + + +class UPS2018BrokenSourceTestCase(TestCase): +    @mock.patch("requests.get") +    def test_broken_source(self, mock_get): +        mock_get.return_value = mock_requests_get("") + +        source = Source.objects.create(url="https://example.org/2018") +        with self.assertRaises(ParserError): +            UPS2018Parser(source) + +    @mock.patch("requests.get") +    def test_half_broken_source(self, mock_get): +        source = Source.objects.create(url="https://example.org/2018") +        mock_get.side_effect = [ +            mock_requests_get(""), +            mock_requests_get(source.url) +        ] + +        parser = UPS2018Parser(source) +        self.assertEqual(parser.months, [ +            "September, 2018", "October, 2018", "November, 2018", +            "December, 2018", "January, 2019", "February, 2019", "March, 2019", +            "April, 2019", "May, 2019", "June, 2019", "July, 2019" +        ]) diff --git a/tests/data/2018/empty.html b/tests/data/2018/empty.html new file mode 100644 index 0000000..dde78b6 --- /dev/null +++ b/tests/data/2018/empty.html @@ -0,0 +1,50 @@ +<script> +function do_something() { +alert("something"); +} +</script> + +			<option value="August, 2017">August, 2017</option> +			<option value="September, 2017">September, 2017</option> +			<option value="October, 2017">October, 2017</option> +			<option value="November, 2017">November, 2017</option> +			<option value="December, 2017">December, 2017</option> +			<option value="January, 2018">January, 2018</option> +			<option value="February, 2018">February, 2018</option> +			<option value="March, 2018">March, 2018</option> +			<option value="April, 2018">April, 2018</option> +			<option value="May, 2018">May, 2018</option> +			<option value="June, 2018">June, 2018</option> +			<option value="July, 2018">July, 2018</option> +			<option value="August, 2018">August, 2018</option> +			<option value="September, 2018">September, 2018</option> +			<option value="October, 2018">October, 2018</option> +			<option value="November, 2018">November, 2018</option> +			<option value="December, 2018">December, 2018</option> +			<option value="January, 2019">January, 2019</option> +			<option value="February, 2019">February, 2019</option> +			<option value="March, 2019">March, 2019</option> +			<option value="April, 2019">April, 2019</option> +			<option value="May, 2019">May, 2019</option> +			<option value="June, 2019">June, 2019</option> +			<option value="July, 2019">July, 2019</option> + +<script> +function do_something_else() { +var v = "a variable"; +var vv = "another_variable"; +do_something(); +} +</script> + +<script> +function courses() { +var v = {}; +v.events.list = [];; +} +</script> + +<script> +courses(); +do_something_else(); +</script> diff --git a/tests/data/2018/october.html b/tests/data/2018/october.html new file mode 100644 index 0000000..ab3da0b --- /dev/null +++ b/tests/data/2018/october.html @@ -0,0 +1,50 @@ +<script> +function do_something() { +alert("something"); +} +</script> + +			<option value="August, 2017">August, 2017</option> +			<option value="September, 2017">September, 2017</option> +			<option value="October, 2017">October, 2017</option> +			<option value="November, 2017">November, 2017</option> +			<option value="December, 2017">December, 2017</option> +			<option value="January, 2018">January, 2018</option> +			<option value="February, 2018">February, 2018</option> +			<option value="March, 2018">March, 2018</option> +			<option value="April, 2018">April, 2018</option> +			<option value="May, 2018">May, 2018</option> +			<option value="June, 2018">June, 2018</option> +			<option value="July, 2018">July, 2018</option> +			<option value="August, 2018">August, 2018</option> +			<option value="September, 2018">September, 2018</option> +			<option selected="selected" value="October, 2018">October, 2018</option> +			<option value="November, 2018">November, 2018</option> +			<option value="December, 2018">December, 2018</option> +			<option value="January, 2019">January, 2019</option> +			<option value="February, 2019">February, 2019</option> +			<option value="March, 2019">March, 2019</option> +			<option value="April, 2019">April, 2019</option> +			<option value="May, 2019">May, 2019</option> +			<option value="June, 2019">June, 2019</option> +			<option value="July, 2019">July, 2019</option> + +<script> +function do_something_else() { +var v = "a variable"; +var vv = "another_variable"; +do_something(); +} +</script> + +<script> +function courses() { +var v = {}; +v.events.list = [{"start": "2018-09-21T10:00:00", "end": "2018-09-21T12:00:00", "text": "(10:00-12:00)<br>COURS/TD<br>Cours quelconque<br>L3 Info s1 CMA<br>Salle quelconque", "id": "1", "tag": []}, {"start": "2018-10-22T10:00:00", "end": "2018-10-22T12:00:00", "text": "(10:00-12:00)<br>COURS/TD<br>Cours quelconque<br>L3 Info s1 CMA<br>Salle quelconque", "id": "2", "tag": []}];; +} +</script> + +<script> +courses(); +do_something_else(); +</script> diff --git a/tests/data/2018/september.html b/tests/data/2018/september.html new file mode 100644 index 0000000..c81fc3b --- /dev/null +++ b/tests/data/2018/september.html @@ -0,0 +1,51 @@ +<script> +function do_something() { +alert("something"); +} +</script> + +			<option value="August, 2017">August, 2017</option> +			<option value="September, 2017">September, 2017</option> +			<option value="October, 2017">October, 2017</option> +			<option value="November, 2017">November, 2017</option> +			<option value="December, 2017">December, 2017</option> +			<option value="January, 2018">January, 2018</option> +			<option value="February, 2018">February, 2018</option> +			<option value="March, 2018">March, 2018</option> +			<option value="April, 2018">April, 2018</option> +			<option value="May, 2018">May, 2018</option> +			<option value="June, 2018">June, 2018</option> +			<option value="July, 2018">July, 2018</option> +			<option value="August, 2018">August, 2018</option> +			<option selected="selected" value="September, 2018">September, 2018</option> +			<option value="October, 2018">October, 2018</option> +			<option value="November, 2018">November, 2018</option> +			<option value="December, 2018">December, 2018</option> +			<option value="January, 2019">January, 2019</option> +			<option value="February, 2019">February, 2019</option> +			<option value="March, 2019">March, 2019</option> +			<option value="April, 2019">April, 2019</option> +			<option value="May, 2019">May, 2019</option> +			<option value="June, 2019">June, 2019</option> +			<option value="July, 2019">July, 2019</option> + +<script> +  function do_something_else() { +      var v = "a variable"; +      var vv = "another_variable"; + +      do_something(); +  } +</script> + +<script> +function courses() { +var v = {}; +v.events.list = [{"start": "2018-09-21T10:00:00", "end": "2018-09-21T12:00:00", "text": "(10:00-12:00)<br>COURS/TD<br>Cours quelconque<br>L3 Info s1 CMA<br>Salle quelconque", "id": "0", "tag": []}];; +} +</script> + +<script> +courses(); +do_something_else(); +</script>  | 
