From 3363152e79991c9a6d86da819b758dacab33b16a Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Tue, 5 Sep 2017 19:17:53 +0200 Subject: Squelette de syndication au format ICS --- feeds.py | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 feeds.py (limited to 'feeds.py') diff --git a/feeds.py b/feeds.py new file mode 100644 index 0000000..913e337 --- /dev/null +++ b/feeds.py @@ -0,0 +1,42 @@ +# Copyright (C) 2017 Alban Gruin +# +# celcatsanitizer is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with celcatsanitizer; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +from django.contrib.syndication.views import Feed +from django.utils.feedgenerator import SyndicationFeed + +from icalendar import Calendar, Event + + +class IcalFeed(SyndicationFeed): + content_type = "text/calendar; charset=utf-8" + __ical_names = {"name": "summary", + "notes": "description", + "rooms": "location", + "begin": "dtbegin", + "end": "dtend"} + + def write(self, outfile, encoding): + calendar = Calendar() + calendar.add("version", "2.0") + + write_events(calendar) + outfile.write(calendar.to_ical()) + + def write_events(self, calendar): + for item in items: + event = Event() + for key, value in item.items(): + event.add(__ical_names[key], value) -- cgit v1.2.1 From e1899a300bca73bce70591ccd9a5386bb5152aa9 Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Tue, 5 Sep 2017 19:30:32 +0200 Subject: Ne plante pas si jamais une variable n’a pas d’équivalent icalendar --- feeds.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'feeds.py') diff --git a/feeds.py b/feeds.py index 913e337..f3ccaf3 100644 --- a/feeds.py +++ b/feeds.py @@ -39,4 +39,5 @@ class IcalFeed(SyndicationFeed): for item in items: event = Event() for key, value in item.items(): - event.add(__ical_names[key], value) + if key in __ical_names: + event.add(__ical_names[key], value) -- cgit v1.2.1 From 492da9dc027a42384b286593c61e6951089bc013 Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Tue, 5 Sep 2017 21:40:08 +0200 Subject: Correction de détails --- feeds.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'feeds.py') diff --git a/feeds.py b/feeds.py index f3ccaf3..4b42c47 100644 --- a/feeds.py +++ b/feeds.py @@ -20,7 +20,7 @@ from django.utils.feedgenerator import SyndicationFeed from icalendar import Calendar, Event -class IcalFeed(SyndicationFeed): +class IcalFeedGenerator(SyndicationFeed): content_type = "text/calendar; charset=utf-8" __ical_names = {"name": "summary", "notes": "description", @@ -32,12 +32,14 @@ class IcalFeed(SyndicationFeed): calendar = Calendar() calendar.add("version", "2.0") - write_events(calendar) + self.write_events(calendar) outfile.write(calendar.to_ical()) def write_events(self, calendar): - for item in items: + print(self.items) + for item in self.items: event = Event() - for key, value in item.items(): - if key in __ical_names: - event.add(__ical_names[key], value) + for key, value in self.__ical_names.items(): + if item.get(key) is not None: + event.add(value, item[key]) + calendar.add_component(event) -- cgit v1.2.1 From eea68427e8a84ceae7f41409bd07615af4490d2e Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Tue, 5 Sep 2017 22:48:25 +0200 Subject: Implémentation d’un flux ICS (icalendar) par groupe. Non testé avec un client ICS pour l’instant. --- feeds.py | 45 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 7 deletions(-) (limited to 'feeds.py') diff --git a/feeds.py b/feeds.py index 4b42c47..609d422 100644 --- a/feeds.py +++ b/feeds.py @@ -14,19 +14,24 @@ # with celcatsanitizer; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +from django.core.exceptions import ObjectDoesNotExist from django.contrib.syndication.views import Feed from django.utils.feedgenerator import SyndicationFeed from icalendar import Calendar, Event +from .models import Course, Group, Timetable +from .templatetags.rooms import format_rooms + +ICAL_NAMES = {"name": "summary", + "notes": "description", + "rooms": "location", + "begin": "dtbegin", + "end": "dtend"} + class IcalFeedGenerator(SyndicationFeed): content_type = "text/calendar; charset=utf-8" - __ical_names = {"name": "summary", - "notes": "description", - "rooms": "location", - "begin": "dtbegin", - "end": "dtend"} def write(self, outfile, encoding): calendar = Calendar() @@ -36,10 +41,36 @@ class IcalFeedGenerator(SyndicationFeed): outfile.write(calendar.to_ical()) def write_events(self, calendar): - print(self.items) for item in self.items: event = Event() - for key, value in self.__ical_names.items(): + for key, value in ICAL_NAMES.items(): if item.get(key) is not None: event.add(value, item[key]) calendar.add_component(event) + + +class IcalFeed(Feed): + feed_type = IcalFeedGenerator + link = "" + + def get_object(self, request, timetable_slug, group_slug): + try: + timetable = Timetable.objects.get(slug=timetable_slug) + group = Group.objects.get(timetable=timetable, slug=group_slug) + except: + raise ObjectDoesNotExist + else: + return group + + def item_link(self, item): + return "" + + def items(self, obj): + return Course.objects.get_courses_for_group(obj).order_by("begin") + + def item_extra_kwargs(self, item): + return {"begin": item.begin, + "end": item.end, + "name": item.name, + "notes": item.notes, + "rooms": format_rooms(item.rooms.all())} -- cgit v1.2.1 From 493bbe8ac06a530ca02452da719258e2ad306c82 Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Tue, 5 Sep 2017 22:54:57 +0200 Subject: dtstart, pas dtbegin. Fonctionnalitée testée avec succès sur Lightning. --- feeds.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'feeds.py') diff --git a/feeds.py b/feeds.py index 609d422..e97c29a 100644 --- a/feeds.py +++ b/feeds.py @@ -26,7 +26,7 @@ from .templatetags.rooms import format_rooms ICAL_NAMES = {"name": "summary", "notes": "description", "rooms": "location", - "begin": "dtbegin", + "begin": "dtstart", "end": "dtend"} -- cgit v1.2.1 From 36757e937abd7d5aa3434f4c815dfb040e1e3a71 Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Wed, 6 Sep 2017 11:46:37 +0200 Subject: Simplification du code icalendar --- feeds.py | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'feeds.py') diff --git a/feeds.py b/feeds.py index e97c29a..72d7873 100644 --- a/feeds.py +++ b/feeds.py @@ -23,11 +23,7 @@ from icalendar import Calendar, Event from .models import Course, Group, Timetable from .templatetags.rooms import format_rooms -ICAL_NAMES = {"name": "summary", - "notes": "description", - "rooms": "location", - "begin": "dtstart", - "end": "dtend"} +ICAL_NAMES = ["summary", "description", "location", "start", "dtstart", "dtend"] class IcalFeedGenerator(SyndicationFeed): @@ -43,9 +39,9 @@ class IcalFeedGenerator(SyndicationFeed): def write_events(self, calendar): for item in self.items: event = Event() - for key, value in ICAL_NAMES.items(): + for key in ICAL_NAMES: if item.get(key) is not None: - event.add(value, item[key]) + event.add(key, item[key]) calendar.add_component(event) @@ -62,6 +58,9 @@ class IcalFeed(Feed): else: return group + def item_description(self, item): + return item.notes + def item_link(self, item): return "" @@ -69,8 +68,7 @@ class IcalFeed(Feed): return Course.objects.get_courses_for_group(obj).order_by("begin") def item_extra_kwargs(self, item): - return {"begin": item.begin, - "end": item.end, - "name": item.name, - "notes": item.notes, - "rooms": format_rooms(item.rooms.all())} + return {"dtstart": item.begin, + "dtend": item.end, + "summary": item.name, + "location": format_rooms(item.rooms.all())} -- cgit v1.2.1 From 49e56d97e5a126f66d1d52b5de45befe603893b2 Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Thu, 7 Sep 2017 23:31:54 +0200 Subject: Remplacement de la licence GPL 2 par la licence AGPL 3 --- feeds.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'feeds.py') diff --git a/feeds.py b/feeds.py index 72d7873..ca1c843 100644 --- a/feeds.py +++ b/feeds.py @@ -1,18 +1,17 @@ # Copyright (C) 2017 Alban Gruin # -# celcatsanitizer is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or +# 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 General Public License for more details. +# GNU Affero General Public License for more details. # -# You should have received a copy of the GNU General Public License along -# with celcatsanitizer; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# You should have received a copy of the GNU Affero General Public License +# along with celcatsanitizer. If not, see . from django.core.exceptions import ObjectDoesNotExist from django.contrib.syndication.views import Feed -- cgit v1.2.1 From 57ffdbf0658042069abcf0b1f9184ff69a3139e2 Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Fri, 8 Sep 2017 11:53:49 +0200 Subject: Ajout de l’année dans les urls --- feeds.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'feeds.py') diff --git a/feeds.py b/feeds.py index ca1c843..e2b0b3f 100644 --- a/feeds.py +++ b/feeds.py @@ -19,7 +19,7 @@ from django.utils.feedgenerator import SyndicationFeed from icalendar import Calendar, Event -from .models import Course, Group, Timetable +from .models import Course, Group, Timetable, Year from .templatetags.rooms import format_rooms ICAL_NAMES = ["summary", "description", "location", "start", "dtstart", "dtend"] @@ -48,9 +48,10 @@ class IcalFeed(Feed): feed_type = IcalFeedGenerator link = "" - def get_object(self, request, timetable_slug, group_slug): + def get_object(self, request, year_slug, timetable_slug, group_slug): try: - timetable = Timetable.objects.get(slug=timetable_slug) + year = Year.objects.get(slug=year_slug) + timetable = Timetable.objects.get(year=year, slug=timetable_slug) group = Group.objects.get(timetable=timetable, slug=group_slug) except: raise ObjectDoesNotExist -- cgit v1.2.1 From 62e7f87c1f867e3ac4f2750e9d422c67788e65a9 Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Fri, 8 Sep 2017 20:53:53 +0200 Subject: Regroupement des requêtes --- feeds.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'feeds.py') diff --git a/feeds.py b/feeds.py index e2b0b3f..8191cbb 100644 --- a/feeds.py +++ b/feeds.py @@ -50,9 +50,7 @@ class IcalFeed(Feed): def get_object(self, request, year_slug, timetable_slug, group_slug): try: - year = Year.objects.get(slug=year_slug) - timetable = Timetable.objects.get(year=year, slug=timetable_slug) - group = Group.objects.get(timetable=timetable, slug=group_slug) + group = Group.objects.get(timetable__year__slug=year_slug, timetable__slug=timetable_slug, slug=group_slug) except: raise ObjectDoesNotExist else: -- cgit v1.2.1 From 74a51992dc6c91d939e8d89eb35a8646b1a67f27 Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Fri, 8 Sep 2017 21:30:21 +0200 Subject: Récupération des mises à jours à afficher dans le flux Atom. Il s’agit des 5 dernières mises à jour d’un emploi du temps --- feeds.py | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) (limited to 'feeds.py') diff --git a/feeds.py b/feeds.py index 8191cbb..37d6f8d 100644 --- a/feeds.py +++ b/feeds.py @@ -15,12 +15,14 @@ from django.core.exceptions import ObjectDoesNotExist from django.contrib.syndication.views import Feed -from django.utils.feedgenerator import SyndicationFeed +from django.db.models import Q +from django.utils.feedgenerator import Atom1Feed, SyndicationFeed from icalendar import Calendar, Event -from .models import Course, Group, Timetable, Year +from .models import Course, Group, LastUpdate, Timetable, Year from .templatetags.rooms import format_rooms +from .utils import get_current_or_next_week ICAL_NAMES = ["summary", "description", "location", "start", "dtstart", "dtend"] @@ -70,3 +72,20 @@ class IcalFeed(Feed): "dtend": item.end, "summary": item.name, "location": format_rooms(item.rooms.all())} + + +class AtomFeed(Feed): + feed_type = Atom1Feed + + def get_object(self, request, year_slug, timetable_slug, group_slug): + year, week = get_current_or_next_week() + try: + group = Group.objects.get(timetable__year__slug=year_slug, timetable__slug=timetable_slug, slug=group_slug) + updates = LastUpdate.objects.filter(Q(year=year, week__lte=week) | Q(year__lt=year), timetable__year__slug=year_slug, timetable__slug=timetable_slug).order_by("-year", "-week")[:5] + except: + raise ObjectDoesNotExist + else: + return group, updates + + def items(self, obj): + pass -- cgit v1.2.1 From 5eae1571d2e2a446958c9576b6dbe4a59c488e60 Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Fri, 8 Sep 2017 21:48:47 +0200 Subject: Génération du lien alternatif pour le flux atom. Ajout d’un URL pour le flux atom --- feeds.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'feeds.py') diff --git a/feeds.py b/feeds.py index 37d6f8d..aa68934 100644 --- a/feeds.py +++ b/feeds.py @@ -16,6 +16,7 @@ from django.core.exceptions import ObjectDoesNotExist from django.contrib.syndication.views import Feed from django.db.models import Q +from django.urls import reverse from django.utils.feedgenerator import Atom1Feed, SyndicationFeed from icalendar import Calendar, Event @@ -87,5 +88,10 @@ class AtomFeed(Feed): else: return group, updates + def link(self, obj): + group = obj[0] + link = reverse("timetable", kwargs={"year_slug": group.timetable.year.slug, "timetable_slug": group.timetable.slug, "group_slug": group.slug}) + return link + def items(self, obj): - pass + return [] -- cgit v1.2.1 From eb050fb7d00351bcac8048f75abd703e68783831 Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Sat, 9 Sep 2017 11:19:02 +0200 Subject: Rendu du contenu du flux atom. Il est loin d’être parfait par contre. --- feeds.py | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) (limited to 'feeds.py') diff --git a/feeds.py b/feeds.py index aa68934..1f6ff66 100644 --- a/feeds.py +++ b/feeds.py @@ -16,6 +16,7 @@ from django.core.exceptions import ObjectDoesNotExist from django.contrib.syndication.views import Feed from django.db.models import Q +from django.template import Context, loader from django.urls import reverse from django.utils.feedgenerator import Atom1Feed, SyndicationFeed @@ -23,7 +24,7 @@ from icalendar import Calendar, Event from .models import Course, Group, LastUpdate, Timetable, Year from .templatetags.rooms import format_rooms -from .utils import get_current_or_next_week +from .utils import get_current_or_next_week, get_week, group_courses ICAL_NAMES = ["summary", "description", "location", "start", "dtstart", "dtend"] @@ -93,5 +94,24 @@ class AtomFeed(Feed): link = reverse("timetable", kwargs={"year_slug": group.timetable.year.slug, "timetable_slug": group.timetable.slug, "group_slug": group.slug}) return link + def title(self, obj): + return "Emploi du temps du groupe {0}".format(obj[0]) + + def item_link(self, item): + group = item.group + return reverse("timetable", kwargs={"year_slug": group.timetable.year.slug, "timetable_slug": group.timetable.slug, "group_slug": group.slug, "year": item.year, "week": item.week}) + + def item_description(self, item): + template = loader.get_template("timetable.html") + context = {"group": item.group, "courses": item.courses, "last_update": item, "year": item.year, "week": item.week} + return template.render(context) + def items(self, obj): - return [] + for update in obj[1]: + start, end = get_week(update.year, update.week) + courses = Course.objects.get_courses_for_group(obj[0], begin__gte=start, begin__lt=end) + + update.group = obj[0] + update.courses = group_courses(courses) + + return obj[1] -- cgit v1.2.1 From 0ae8406761f07b9e17229e6723ceb8223d227a8e Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Sat, 9 Sep 2017 11:26:41 +0200 Subject: On ne charge la template qu’une fois, ça accélère peut-être le rendu ? --- feeds.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'feeds.py') diff --git a/feeds.py b/feeds.py index 1f6ff66..68b3a84 100644 --- a/feeds.py +++ b/feeds.py @@ -102,16 +102,18 @@ class AtomFeed(Feed): return reverse("timetable", kwargs={"year_slug": group.timetable.year.slug, "timetable_slug": group.timetable.slug, "group_slug": group.slug, "year": item.year, "week": item.week}) def item_description(self, item): - template = loader.get_template("timetable.html") - context = {"group": item.group, "courses": item.courses, "last_update": item, "year": item.year, "week": item.week} - return template.render(context) + return item.description def items(self, obj): + template = loader.get_template("timetable.html") + group = obj[0] + for update in obj[1]: start, end = get_week(update.year, update.week) - courses = Course.objects.get_courses_for_group(obj[0], begin__gte=start, begin__lt=end) + courses = Course.objects.get_courses_for_group(group, begin__gte=start, begin__lt=end) + context = {"group": group, "courses": group_courses(courses), "last_update": update, "year": update.year, "week": update.week} - update.group = obj[0] - update.courses = group_courses(courses) + update.group = group + update.description = template.render(context) return obj[1] -- cgit v1.2.1 From 4d47946f07bc315db716dbddd1687817e3cae6ff Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Sat, 9 Sep 2017 11:35:16 +0200 Subject: Séparation de la template timetable en deux : une commune, qui ne contient que l’emploi du temps et utilisée par Atom, l’autre qui génère une page html complète. --- feeds.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'feeds.py') diff --git a/feeds.py b/feeds.py index 68b3a84..015a835 100644 --- a/feeds.py +++ b/feeds.py @@ -105,7 +105,7 @@ class AtomFeed(Feed): return item.description def items(self, obj): - template = loader.get_template("timetable.html") + template = loader.get_template("timetable_common.html") group = obj[0] for update in obj[1]: -- cgit v1.2.1 From 14058b4e9b7524cab4241b6188c13e6b97269370 Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Sat, 9 Sep 2017 11:36:49 +0200 Subject: Flux atom valide --- feeds.py | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'feeds.py') diff --git a/feeds.py b/feeds.py index 015a835..dffefc9 100644 --- a/feeds.py +++ b/feeds.py @@ -77,6 +77,7 @@ class IcalFeed(Feed): class AtomFeed(Feed): + author_name = "CelcatSanitizer" feed_type = Atom1Feed def get_object(self, request, year_slug, timetable_slug, group_slug): @@ -104,6 +105,9 @@ class AtomFeed(Feed): def item_description(self, item): return item.description + def item_updateddate(self, item): + return item.date + def items(self, obj): template = loader.get_template("timetable_common.html") group = obj[0] -- cgit v1.2.1 From 9aaa19a62b36e1b0981233785e150f50449c78e3 Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Sat, 9 Sep 2017 12:00:58 +0200 Subject: Suppression des imports inutilisés --- feeds.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'feeds.py') diff --git a/feeds.py b/feeds.py index dffefc9..722f20c 100644 --- a/feeds.py +++ b/feeds.py @@ -16,13 +16,13 @@ from django.core.exceptions import ObjectDoesNotExist from django.contrib.syndication.views import Feed from django.db.models import Q -from django.template import Context, loader +from django.template import loader from django.urls import reverse from django.utils.feedgenerator import Atom1Feed, SyndicationFeed from icalendar import Calendar, Event -from .models import Course, Group, LastUpdate, Timetable, Year +from .models import Course, Group, LastUpdate from .templatetags.rooms import format_rooms from .utils import get_current_or_next_week, get_week, group_courses -- cgit v1.2.1 From 98242cad296b36423daf77e572d7735478d33f1d Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Sat, 9 Sep 2017 15:19:42 +0200 Subject: Ajout d’un flux RSS --- feeds.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'feeds.py') diff --git a/feeds.py b/feeds.py index 722f20c..2dd2479 100644 --- a/feeds.py +++ b/feeds.py @@ -14,6 +14,7 @@ # along with celcatsanitizer. If not, see . from django.core.exceptions import ObjectDoesNotExist +from django.conf import settings from django.contrib.syndication.views import Feed from django.db.models import Q from django.template import loader @@ -76,10 +77,7 @@ class IcalFeed(Feed): "location": format_rooms(item.rooms.all())} -class AtomFeed(Feed): - author_name = "CelcatSanitizer" - feed_type = Atom1Feed - +class RSSFeed(Feed): def get_object(self, request, year_slug, timetable_slug, group_slug): year, week = get_current_or_next_week() try: @@ -121,3 +119,9 @@ class AtomFeed(Feed): update.description = template.render(context) return obj[1] + + +class AtomFeed(RSSFeed): + author_name = settings.ADMINS[0][0] + author_email = settings.ADMINS[0][1] + feed_type = Atom1Feed -- cgit v1.2.1