From c239f28f171fc899ca9b6824e003e24833bf482f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Delobelle?= Date: Sat, 20 Jan 2018 17:02:23 +0100 Subject: [PATCH 1/5] syncmails should be able to be silent --- gestioncof/management/commands/syncmails.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/gestioncof/management/commands/syncmails.py b/gestioncof/management/commands/syncmails.py index 1d3dddb8..74ad152d 100644 --- a/gestioncof/management/commands/syncmails.py +++ b/gestioncof/management/commands/syncmails.py @@ -63,8 +63,9 @@ class Command(BaseCommand): except CustomMail.DoesNotExist: mail = CustomMail.objects.create(**fields) status['synced'] += 1 - self.stdout.write( - 'SYNCED {:s}'.format(fields['shortname'])) + if options['verbosity']: + self.stdout.write( + 'SYNCED {:s}'.format(fields['shortname'])) assoc['mails'][obj['pk']] = mail # Variables @@ -79,8 +80,9 @@ class Command(BaseCommand): except Variable.DoesNotExist: Variable.objects.create(**fields) - # C'est agréable d'avoir le résultat affiché - self.stdout.write( - '{synced:d} mails synchronized {unchanged:d} unchanged' - .format(**status) - ) + if options['verbosity']: + # C'est agréable d'avoir le résultat affiché + self.stdout.write( + '{synced:d} mails synchronized {unchanged:d} unchanged' + .format(**status) + ) From 7e0ecd8e0f707f912b66cb438778048b877e203e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Delobelle?= Date: Sun, 21 Jan 2018 17:51:23 +0100 Subject: [PATCH 2/5] Add assertion to check ical data is as expected --- shared/tests/testcases.py | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/shared/tests/testcases.py b/shared/tests/testcases.py index 15792383..14a5fbfe 100644 --- a/shared/tests/testcases.py +++ b/shared/tests/testcases.py @@ -8,6 +8,8 @@ from django.test import Client from django.utils import timezone from django.utils.functional import cached_property +import icalendar + User = get_user_model() @@ -92,6 +94,40 @@ class TestCaseMixin: else: self.assertEqual(actual, expected) + def _test_event_equal(self, event, exp): + for k, v_desc in exp.items(): + if isinstance(v_desc, tuple): + v_getter = v_desc[0] + v = v_desc[1] + else: + v_getter = lambda v: v + v = v_desc + if v_getter(event[k.upper()]) != v: + return False + return True + + def _find_event(self, ev, l): + for i, elt in enumerate(l): + if self._test_event_equal(ev, elt): + return elt, i + return False, -1 + + def assertCalEqual(self, ical_content, expected): + remaining = expected.copy() + unexpected = [] + + cal = icalendar.Calendar.from_ical(ical_content) + + for ev in cal.walk('vevent'): + found, i_found = self._find_event(ev, remaining) + if found: + remaining.pop(i_found) + else: + unexpected.append(ev) + + self.assertListEqual(unexpected, []) + self.assertListEqual(remaining, []) + class ViewTestCaseMixin(TestCaseMixin): """ From 2e6a54c7dbb8cff5077d35230e063712aa90b3d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Delobelle?= Date: Sun, 21 Jan 2018 17:52:53 +0100 Subject: [PATCH 3/5] cof -- Add tests for calendar views --- gestioncof/tests/test_views.py | 151 +++++++++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 gestioncof/tests/test_views.py diff --git a/gestioncof/tests/test_views.py b/gestioncof/tests/test_views.py new file mode 100644 index 00000000..e33fe2f2 --- /dev/null +++ b/gestioncof/tests/test_views.py @@ -0,0 +1,151 @@ +import uuid +from datetime import timedelta + +from django.contrib import messages +from django.contrib.messages.api import get_messages +from django.contrib.messages.storage.base import Message +from django.test import TestCase + +from bda.models import Salle, Tirage +from gestioncof.models import CalendarSubscription +from gestioncof.tests.testcases import ViewTestCaseMixin + + +class CalendarViewTests(ViewTestCaseMixin, TestCase): + url_name = 'calendar' + url_expected = '/calendar/subscription' + + auth_user = 'member' + auth_forbidden = [None, 'user'] + + post_expected_message = Message( + messages.SUCCESS, "Calendrier mis à jour avec succès.") + + def test_get(self): + r = self.client.get(self.url) + self.assertEqual(r.status_code, 200) + + def test_post_new(self): + r = self.client.post(self.url, { + 'subscribe_to_events': True, + 'subscribe_to_my_shows': True, + 'other_shows': [], + }) + + self.assertEqual(r.status_code, 200) + self.assertIn(self.post_expected_message, get_messages(r.wsgi_request)) + cs = self.users['member'].calendarsubscription + self.assertTrue(cs.subscribe_to_events) + self.assertTrue(cs.subscribe_to_my_shows) + + def test_post_edit(self): + u = self.users['member'] + token = uuid.uuid4() + cs = CalendarSubscription.objects.create(token=token, user=u) + + r = self.client.post(self.url, { + 'other_shows': [], + }) + + self.assertEqual(r.status_code, 200) + self.assertIn(self.post_expected_message, get_messages(r.wsgi_request)) + cs.refresh_from_db() + self.assertEqual(cs.token, token) + self.assertFalse(cs.subscribe_to_events) + self.assertFalse(cs.subscribe_to_my_shows) + + def test_post_other_shows(self): + t = Tirage.objects.create( + ouverture=self.now, + fermeture=self.now, + active=True, + ) + l = Salle.objects.create() + s = t.spectacle_set.create( + date=self.now, price=3.5, slots=20, location=l, listing=True) + + r = self.client.post(self.url, {'other_shows': [str(s.pk)]}) + + self.assertEqual(r.status_code, 200) + + +class CalendarICSViewTests(ViewTestCaseMixin, TestCase): + url_name = 'gestioncof.views.calendar_ics' + + auth_user = None + auth_forbidden = [] + + @property + def url_kwargs(self): + return {'token': self.token} + + @property + def url_expected(self): + return '/calendar/{}/calendar.ics'.format(self.token) + + def setUp(self): + super().setUp() + + self.token = uuid.uuid4() + + self.t = Tirage.objects.create( + ouverture=self.now, + fermeture=self.now, + active=True, + ) + l = Salle.objects.create(name='Location') + self.s1 = self.t.spectacle_set.create( + price=1, slots=10, location=l, listing=True, + title='Spectacle 1', date=self.now + timedelta(days=1), + ) + self.s2 = self.t.spectacle_set.create( + price=2, slots=20, location=l, listing=True, + title='Spectacle 2', date=self.now + timedelta(days=2), + ) + self.s3 = self.t.spectacle_set.create( + price=3, slots=30, location=l, listing=True, + title='Spectacle 3', date=self.now + timedelta(days=3), + ) + + def test(self): + u = self.users['user'] + p = u.participant_set.create(tirage=self.t) + p.attribution_set.create(spectacle=self.s1) + + self.cs = CalendarSubscription.objects.create( + user=u, token=self.token, + subscribe_to_my_shows=True, subscribe_to_events=True, + ) + self.cs.other_shows.add(self.s2) + + r = self.client.get(self.url) + + def get_dt_from_ical(v): + return v.dt + + self.assertCalEqual(r.content.decode('utf-8'), [ + { + 'summary': 'Spectacle 1', + 'dtstart': (get_dt_from_ical, ( + (self.now + timedelta(days=1)).replace(microsecond=0) + )), + 'dtend': (get_dt_from_ical, ( + (self.now + timedelta(days=1, hours=2)).replace( + microsecond=0) + )), + 'location': 'Location', + 'uid': 'show-{}-{}@example.com'.format(self.s1.pk, self.t.pk), + }, + { + 'summary': 'Spectacle 2', + 'dtstart': (get_dt_from_ical, ( + (self.now + timedelta(days=2)).replace(microsecond=0) + )), + 'dtend': (get_dt_from_ical, ( + (self.now + timedelta(days=2, hours=2)).replace( + microsecond=0) + )), + 'location': 'Location', + 'uid': 'show-{}-{}@example.com'.format(self.s2.pk, self.t.pk), + }, + ]) From acf284862a57f1857a2049067d4bb081a797fffc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Delobelle?= Date: Sun, 21 Jan 2018 18:00:56 +0100 Subject: [PATCH 4/5] Users should be able to refuse to subscribe to shows and events --- gestioncof/forms.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/gestioncof/forms.py b/gestioncof/forms.py index 2124b7c8..5a25b815 100644 --- a/gestioncof/forms.py +++ b/gestioncof/forms.py @@ -351,10 +351,12 @@ EventFormset = formset_factory(AdminEventForm, BaseEventRegistrationFormset) class CalendarForm(forms.ModelForm): subscribe_to_events = forms.BooleanField( initial=True, - label="Événements du COF") + label="Événements du COF", + required=False) subscribe_to_my_shows = forms.BooleanField( initial=True, - label="Les spectacles pour lesquels j'ai obtenu une place") + label="Les spectacles pour lesquels j'ai obtenu une place", + required=False) other_shows = forms.ModelMultipleChoiceField( label="Spectacles supplémentaires", queryset=Spectacle.objects.filter(tirage__active=True), From 38539a9d53607efd417bee8d4d1d930999e39d78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Delobelle?= Date: Sun, 21 Jan 2018 18:03:01 +0100 Subject: [PATCH 5/5] Name url to export calendar to ical --- gestioncof/templates/gestioncof/calendar_subscription.html | 2 +- gestioncof/tests/test_views.py | 2 +- gestioncof/urls.py | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/gestioncof/templates/gestioncof/calendar_subscription.html b/gestioncof/templates/gestioncof/calendar_subscription.html index b13cb7f2..4b9e3cbb 100644 --- a/gestioncof/templates/gestioncof/calendar_subscription.html +++ b/gestioncof/templates/gestioncof/calendar_subscription.html @@ -12,7 +12,7 @@ souscrire aux événements du COF et/ou aux spectacles BdA. {% if token %}

Votre calendrier (compatible avec toutes les applications d'agenda) se trouve à -cette adresse.

+cette adresse.

  • Pour l'ajouter à Thunderbird (lightning), il faut copier ce lien et aller diff --git a/gestioncof/tests/test_views.py b/gestioncof/tests/test_views.py index e33fe2f2..06d6be4a 100644 --- a/gestioncof/tests/test_views.py +++ b/gestioncof/tests/test_views.py @@ -70,7 +70,7 @@ class CalendarViewTests(ViewTestCaseMixin, TestCase): class CalendarICSViewTests(ViewTestCaseMixin, TestCase): - url_name = 'gestioncof.views.calendar_ics' + url_name = 'calendar.ics' auth_user = None auth_forbidden = [] diff --git a/gestioncof/urls.py b/gestioncof/urls.py index 2be609b3..dde543a5 100644 --- a/gestioncof/urls.py +++ b/gestioncof/urls.py @@ -52,7 +52,8 @@ events_patterns = [ calendar_patterns = [ url(r'^subscription$', views.calendar, name='calendar'), - url(r'^(?P[a-z0-9-]+)/calendar.ics$', views.calendar_ics) + url(r'^(?P[a-z0-9-]+)/calendar.ics$', views.calendar_ics, + name='calendar.ics'), ] clubs_patterns = [