forked from DGNum/gestioCOF
Merge branch 'aureplop/cof-tests_calendar' into 'master'
cof -- Add tests for calendar views See merge request cof-geek/gestioCOF!290
This commit is contained in:
commit
f23d351ddc
6 changed files with 198 additions and 15 deletions
|
@ -351,10 +351,12 @@ EventFormset = formset_factory(AdminEventForm, BaseEventRegistrationFormset)
|
||||||
class CalendarForm(forms.ModelForm):
|
class CalendarForm(forms.ModelForm):
|
||||||
subscribe_to_events = forms.BooleanField(
|
subscribe_to_events = forms.BooleanField(
|
||||||
initial=True,
|
initial=True,
|
||||||
label="Événements du COF")
|
label="Événements du COF",
|
||||||
|
required=False)
|
||||||
subscribe_to_my_shows = forms.BooleanField(
|
subscribe_to_my_shows = forms.BooleanField(
|
||||||
initial=True,
|
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(
|
other_shows = forms.ModelMultipleChoiceField(
|
||||||
label="Spectacles supplémentaires",
|
label="Spectacles supplémentaires",
|
||||||
queryset=Spectacle.objects.filter(tirage__active=True),
|
queryset=Spectacle.objects.filter(tirage__active=True),
|
||||||
|
|
|
@ -63,6 +63,7 @@ class Command(BaseCommand):
|
||||||
except CustomMail.DoesNotExist:
|
except CustomMail.DoesNotExist:
|
||||||
mail = CustomMail.objects.create(**fields)
|
mail = CustomMail.objects.create(**fields)
|
||||||
status['synced'] += 1
|
status['synced'] += 1
|
||||||
|
if options['verbosity']:
|
||||||
self.stdout.write(
|
self.stdout.write(
|
||||||
'SYNCED {:s}'.format(fields['shortname']))
|
'SYNCED {:s}'.format(fields['shortname']))
|
||||||
assoc['mails'][obj['pk']] = mail
|
assoc['mails'][obj['pk']] = mail
|
||||||
|
@ -79,6 +80,7 @@ class Command(BaseCommand):
|
||||||
except Variable.DoesNotExist:
|
except Variable.DoesNotExist:
|
||||||
Variable.objects.create(**fields)
|
Variable.objects.create(**fields)
|
||||||
|
|
||||||
|
if options['verbosity']:
|
||||||
# C'est agréable d'avoir le résultat affiché
|
# C'est agréable d'avoir le résultat affiché
|
||||||
self.stdout.write(
|
self.stdout.write(
|
||||||
'{synced:d} mails synchronized {unchanged:d} unchanged'
|
'{synced:d} mails synchronized {unchanged:d} unchanged'
|
||||||
|
|
|
@ -12,7 +12,7 @@ souscrire aux événements du COF et/ou aux spectacles BdA.
|
||||||
|
|
||||||
{% if token %}
|
{% if token %}
|
||||||
<p>Votre calendrier (compatible avec toutes les applications d'agenda) se trouve à
|
<p>Votre calendrier (compatible avec toutes les applications d'agenda) se trouve à
|
||||||
<a href="{% url 'calendar_ics' token %}">cette adresse</a>.</p>
|
<a href="{% url 'calendar.ics' token %}">cette adresse</a>.</p>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li>Pour l'ajouter à Thunderbird (lightning), il faut copier ce lien et aller
|
<li>Pour l'ajouter à Thunderbird (lightning), il faut copier ce lien et aller
|
||||||
|
|
|
@ -1,12 +1,156 @@
|
||||||
|
import uuid
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
from django.contrib import messages
|
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.contrib.messages.storage.base import Message
|
||||||
from django.test import TestCase
|
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
|
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):
|
class EventViewTests(ViewTestCaseMixin, TestCase):
|
||||||
url_name = 'event.details'
|
url_name = 'event.details'
|
||||||
http_methods = ['GET', 'POST']
|
http_methods = ['GET', 'POST']
|
||||||
|
|
|
@ -52,9 +52,8 @@ events_patterns = [
|
||||||
calendar_patterns = [
|
calendar_patterns = [
|
||||||
url(r'^subscription$', views.calendar,
|
url(r'^subscription$', views.calendar,
|
||||||
name='calendar'),
|
name='calendar'),
|
||||||
url(r'^(?P<token>[a-z0-9-]+)/calendar.ics$',
|
url(r'^(?P<token>[a-z0-9-]+)/calendar.ics$', views.calendar_ics,
|
||||||
views.calendar_ics,
|
name='calendar.ics'),
|
||||||
name="calendar_ics")
|
|
||||||
]
|
]
|
||||||
|
|
||||||
clubs_patterns = [
|
clubs_patterns = [
|
||||||
|
|
|
@ -8,6 +8,8 @@ from django.test import Client
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
|
|
||||||
|
import icalendar
|
||||||
|
|
||||||
User = get_user_model()
|
User = get_user_model()
|
||||||
|
|
||||||
|
|
||||||
|
@ -92,6 +94,40 @@ class TestCaseMixin:
|
||||||
else:
|
else:
|
||||||
self.assertEqual(actual, expected)
|
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):
|
class ViewTestCaseMixin(TestCaseMixin):
|
||||||
"""
|
"""
|
||||||
|
|
Loading…
Reference in a new issue