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),
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)
+ )
diff --git a/gestioncof/templates/gestioncof/calendar_subscription.html b/gestioncof/templates/gestioncof/calendar_subscription.html
index 345312e3..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 8c26ecd8..733c96c4 100644
--- a/gestioncof/tests/test_views.py
+++ b/gestioncof/tests/test_views.py
@@ -1,12 +1,156 @@
+import uuid
+from datetime import timedelta
+
from django.contrib import messages
-from django.contrib.messages import get_messages
+from django.contrib.messages.api import get_messages
from django.contrib.messages.storage.base import Message
from django.test import TestCase
-from gestioncof.models import Event, Survey, SurveyAnswer
+from bda.models import Salle, Tirage
+from gestioncof.models import CalendarSubscription, Event, Survey, SurveyAnswer
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 = '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),
+ },
+ ])
+
+
class EventViewTests(ViewTestCaseMixin, TestCase):
url_name = 'event.details'
http_methods = ['GET', 'POST']
diff --git a/gestioncof/urls.py b/gestioncof/urls.py
index 1a66dd57..dde543a5 100644
--- a/gestioncof/urls.py
+++ b/gestioncof/urls.py
@@ -52,9 +52,8 @@ events_patterns = [
calendar_patterns = [
url(r'^subscription$', views.calendar,
name='calendar'),
- url(r'^(?P[a-z0-9-]+)/calendar.ics$',
- views.calendar_ics,
- name="calendar_ics")
+ url(r'^(?P[a-z0-9-]+)/calendar.ics$', views.calendar_ics,
+ name='calendar.ics'),
]
clubs_patterns = [
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):
"""