From 6059ca067b96f3eb2071f022a39ef2d7d1cc5cf8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Delobelle?=
Date: Mon, 15 Jan 2018 05:26:33 +0100
Subject: [PATCH 01/33] Speed up tests
~20% less using MD5 and force_login in kfet testcase.
~77% less by disabling the debug tollbar.
---
cof/settings/common.py | 3 +++
cof/settings/dev.py | 22 ++++++++++++++--------
kfet/tests/testcases.py | 8 +-------
3 files changed, 18 insertions(+), 15 deletions(-)
diff --git a/cof/settings/common.py b/cof/settings/common.py
index 48242fc3..708e90a0 100644
--- a/cof/settings/common.py
+++ b/cof/settings/common.py
@@ -7,6 +7,7 @@ the local development server should be here.
"""
import os
+import sys
try:
from . import secret
@@ -53,6 +54,8 @@ BASE_DIR = os.path.dirname(
os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
)
+TESTING = sys.argv[1] == 'test'
+
# Application definition
INSTALLED_APPS = [
diff --git a/cof/settings/dev.py b/cof/settings/dev.py
index 6e1f6b11..114f37da 100644
--- a/cof/settings/dev.py
+++ b/cof/settings/dev.py
@@ -4,13 +4,18 @@ The settings that are not listed here are imported from .common
"""
from .common import * # NOQA
-from .common import INSTALLED_APPS, MIDDLEWARE
+from .common import INSTALLED_APPS, MIDDLEWARE, TESTING
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
DEBUG = True
+if TESTING:
+ PASSWORD_HASHERS = [
+ 'django.contrib.auth.hashers.MD5PasswordHasher',
+ ]
+
# ---
# Apache static/media config
@@ -36,12 +41,13 @@ def show_toolbar(request):
"""
return DEBUG
-INSTALLED_APPS += ["debug_toolbar", "debug_panel"]
+if not TESTING:
+ INSTALLED_APPS += ["debug_toolbar", "debug_panel"]
-MIDDLEWARE = [
- "debug_panel.middleware.DebugPanelMiddleware"
-] + MIDDLEWARE
+ MIDDLEWARE = [
+ "debug_panel.middleware.DebugPanelMiddleware"
+ ] + MIDDLEWARE
-DEBUG_TOOLBAR_CONFIG = {
- 'SHOW_TOOLBAR_CALLBACK': show_toolbar,
-}
+ DEBUG_TOOLBAR_CONFIG = {
+ 'SHOW_TOOLBAR_CALLBACK': show_toolbar,
+ }
diff --git a/kfet/tests/testcases.py b/kfet/tests/testcases.py
index 3ea428c3..aa2fb1b6 100644
--- a/kfet/tests/testcases.py
+++ b/kfet/tests/testcases.py
@@ -245,13 +245,7 @@ class ViewTestCaseMixin(TestCaseMixin):
self.register_user(label, user)
if self.auth_user:
- # The wrapper is a sanity check.
- self.assertTrue(
- self.client.login(
- username=self.auth_user,
- password=self.auth_user,
- )
- )
+ self.client.force_login(self.users[self.auth_user])
def tearDown(self):
del self.users_base
From e23e1bdba6c6ddbc4e80e23b2099c7e6e99788f5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Delobelle?=
Date: Mon, 15 Jan 2018 16:52:46 +0100
Subject: [PATCH 02/33] kfet -- Add test to check the choices of checkouts in
K-Psul
Particularly, it adds a regression test for #184.
---
kfet/tests/test_forms.py | 48 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 48 insertions(+)
create mode 100644 kfet/tests/test_forms.py
diff --git a/kfet/tests/test_forms.py b/kfet/tests/test_forms.py
new file mode 100644
index 00000000..e946d39d
--- /dev/null
+++ b/kfet/tests/test_forms.py
@@ -0,0 +1,48 @@
+import datetime
+from unittest import mock
+
+from django.test import TestCase
+from django.utils import timezone
+
+from kfet.forms import KPsulCheckoutForm
+from kfet.models import Checkout
+
+from .utils import create_user
+
+
+class KPsulCheckoutFormTests(TestCase):
+
+ def setUp(self):
+ self.now = timezone.now()
+
+ user = create_user()
+
+ self.c1 = Checkout.objects.create(
+ name='C1', balance=10,
+ created_by=user.profile.account_kfet,
+ valid_from=self.now,
+ valid_to=self.now + datetime.timedelta(days=1),
+ )
+
+ self.form = KPsulCheckoutForm()
+
+ def test_checkout(self):
+ checkout_f = self.form.fields['checkout']
+ self.assertListEqual(list(checkout_f.choices), [
+ ('', '---------'),
+ (self.c1.pk, 'C1'),
+ ])
+
+ @mock.patch('django.utils.timezone.now')
+ def test_checkout_valid(self, mock_now):
+ """
+ Checkout are filtered using the current datetime.
+ Regression test for #184.
+ """
+ self.now += datetime.timedelta(days=2)
+ mock_now.return_value = self.now
+
+ form = KPsulCheckoutForm()
+
+ checkout_f = form.fields['checkout']
+ self.assertListEqual(list(checkout_f.choices), [('', '---------')])
From 525bb4d16dc7057fa746d5e66c9c8ebb336466b5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Delobelle?=
Date: Mon, 15 Jan 2018 16:56:38 +0100
Subject: [PATCH 03/33] kfet -- Fix available checkouts in K-Psul
The checkout validity is checked using the current datetime (when
requesting the kpsul page).
---
kfet/forms.py | 16 ++++++++--------
kfet/models.py | 9 +++++++++
2 files changed, 17 insertions(+), 8 deletions(-)
diff --git a/kfet/forms.py b/kfet/forms.py
index 963e4254..26774b1c 100644
--- a/kfet/forms.py
+++ b/kfet/forms.py
@@ -296,17 +296,17 @@ class KPsulAccountForm(forms.ModelForm):
class KPsulCheckoutForm(forms.Form):
checkout = forms.ModelChoiceField(
- queryset=(
- Checkout.objects
- .filter(
- is_protected=False,
- valid_from__lte=timezone.now(),
- valid_to__gte=timezone.now(),
- )
- ),
+ queryset=None,
widget=forms.Select(attrs={'id': 'id_checkout_select'}),
)
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+
+ # Create the queryset on form instanciation to use the current time.
+ self.fields['checkout'].queryset = (
+ Checkout.objects.is_valid().filter(is_protected=False))
+
class KPsulOperationForm(forms.ModelForm):
article = forms.ModelChoiceField(
diff --git a/kfet/models.py b/kfet/models.py
index deee76eb..c9de48bc 100644
--- a/kfet/models.py
+++ b/kfet/models.py
@@ -341,6 +341,13 @@ class AccountNegative(models.Model):
return self.start + kfet_config.overdraft_duration
+class CheckoutQuerySet(models.QuerySet):
+
+ def is_valid(self):
+ now = timezone.now()
+ return self.filter(valid_from__lte=now, valid_to__gte=now)
+
+
class Checkout(models.Model):
created_by = models.ForeignKey(
Account, on_delete = models.PROTECT,
@@ -353,6 +360,8 @@ class Checkout(models.Model):
default = 0)
is_protected = models.BooleanField(default = False)
+ objects = CheckoutQuerySet.as_manager()
+
def get_absolute_url(self):
return reverse('kfet.checkout.read', kwargs={'pk': self.pk})
From 478f56d94b6db8a185bbd0dd821147c06a2bfafc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Delobelle?=
Date: Tue, 16 Jan 2018 15:59:17 +0100
Subject: [PATCH 04/33] kfet -- Create initial statement on checkout save
- Why? Because it should be the actual behavior.
- To allow using arithmetic operations with values of DecimalField when
object are not retrieved from DB, some strings are replaced by Decimal
or int.
If you wonder why it's not automatically done, see:
https://code.djangoproject.com/ticket/27825
---
kfet/models.py | 16 ++++++++++++++++
kfet/tests/test_models.py | 37 ++++++++++++++++++++++++++++++++++++-
kfet/tests/test_views.py | 19 ++++++++++++-------
kfet/views.py | 10 +---------
4 files changed, 65 insertions(+), 17 deletions(-)
diff --git a/kfet/models.py b/kfet/models.py
index deee76eb..3f38cc44 100644
--- a/kfet/models.py
+++ b/kfet/models.py
@@ -362,6 +362,22 @@ class Checkout(models.Model):
def __str__(self):
return self.name
+ def save(self, *args, **kwargs):
+ created = self.pk is None
+
+ ret = super().save(*args, **kwargs)
+
+ if created:
+ self.statements.create(
+ amount_taken=0,
+ balance_old=self.balance,
+ balance_new=self.balance,
+ by=self.created_by,
+ )
+
+ return ret
+
+
class CheckoutTransfer(models.Model):
from_checkout = models.ForeignKey(
Checkout, on_delete = models.PROTECT,
diff --git a/kfet/tests/test_models.py b/kfet/tests/test_models.py
index ea132acd..727cac4e 100644
--- a/kfet/tests/test_models.py
+++ b/kfet/tests/test_models.py
@@ -1,7 +1,12 @@
+import datetime
+
from django.contrib.auth import get_user_model
from django.test import TestCase
+from django.utils import timezone
-from kfet.models import Account
+from kfet.models import Account, Checkout
+
+from .utils import create_user
User = get_user_model()
@@ -23,3 +28,33 @@ class AccountTests(TestCase):
with self.assertRaises(Account.DoesNotExist):
Account.objects.get_by_password('bernard')
+
+
+class CheckoutTests(TestCase):
+
+ def setUp(self):
+ self.now = timezone.now()
+
+ self.u = create_user()
+ self.u_acc = self.u.profile.account_kfet
+
+ self.c = Checkout(
+ created_by=self.u_acc,
+ valid_from=self.now,
+ valid_to=self.now + datetime.timedelta(days=1),
+ )
+
+ def test_initial_statement(self):
+ """A statement is added with initial balance on creation."""
+ self.c.balance = 10
+ self.c.save()
+
+ st = self.c.statements.get()
+ self.assertEqual(st.balance_new, 10)
+ self.assertEqual(st.amount_taken, 0)
+ self.assertEqual(st.amount_error, 0)
+
+ # Saving again doesn't create a new statement.
+ self.c.save()
+
+ self.assertEqual(self.c.statements.count(), 1)
diff --git a/kfet/tests/test_views.py b/kfet/tests/test_views.py
index 41ed8b5c..40f895a1 100644
--- a/kfet/tests/test_views.py
+++ b/kfet/tests/test_views.py
@@ -746,12 +746,16 @@ class CheckoutReadViewTests(ViewTestCaseMixin, TestCase):
def setUp(self):
super().setUp()
- self.checkout = Checkout.objects.create(
- name='Checkout',
- created_by=self.accounts['team'],
- valid_from=self.now,
- valid_to=self.now + timedelta(days=5),
- )
+
+ with mock.patch('django.utils.timezone.now') as mock_now:
+ mock_now.return_value = self.now
+
+ self.checkout = Checkout.objects.create(
+ name='Checkout', balance=Decimal('10'),
+ created_by=self.accounts['team'],
+ valid_from=self.now,
+ valid_to=self.now + timedelta(days=1),
+ )
def test_ok(self):
r = self.client.get(self.url)
@@ -794,7 +798,7 @@ class CheckoutUpdateViewTests(ViewTestCaseMixin, TestCase):
name='Checkout',
valid_from=self.now,
valid_to=self.now + timedelta(days=5),
- balance='3.14',
+ balance=Decimal('3.14'),
is_protected=False,
created_by=self.accounts['team'],
)
@@ -864,6 +868,7 @@ class CheckoutStatementListViewTests(ViewTestCaseMixin, TestCase):
self.assertQuerysetEqual(
r.context['checkoutstatements'],
map(repr, expected_statements),
+ ordered=False,
)
diff --git a/kfet/views.py b/kfet/views.py
index 1fe9ac22..2b69684d 100644
--- a/kfet/views.py
+++ b/kfet/views.py
@@ -528,15 +528,7 @@ class CheckoutCreate(SuccessMessageMixin, CreateView):
# Creating
form.instance.created_by = self.request.user.profile.account_kfet
- checkout = form.save()
-
- # Création d'un relevé avec balance initiale
- CheckoutStatement.objects.create(
- checkout = checkout,
- by = self.request.user.profile.account_kfet,
- balance_old = checkout.balance,
- balance_new = checkout.balance,
- amount_taken = 0)
+ form.save()
return super(CheckoutCreate, self).form_valid(form)
From 57de31d59a82906b935237f533844397efa5e4e3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Delobelle?=
Date: Fri, 19 Jan 2018 17:57:43 +0100
Subject: [PATCH 05/33] cof -- Add tests for survey views
---
gestioncof/tests/test_views.py | 178 +++++++++++++++++++++++++++++++++
1 file changed, 178 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..b8860811
--- /dev/null
+++ b/gestioncof/tests/test_views.py
@@ -0,0 +1,178 @@
+from django.contrib import messages
+from django.contrib.messages import get_messages
+from django.contrib.messages.storage.base import Message
+from django.test import TestCase
+
+from gestioncof.models import Survey, SurveyAnswer
+from gestioncof.tests.testcases import ViewTestCaseMixin
+
+
+class SurveyViewTests(ViewTestCaseMixin, TestCase):
+ url_name = 'survey.details'
+
+ http_methods = ['GET', 'POST']
+
+ auth_user = 'user'
+ auth_forbidden = [None]
+
+ post_expected_message = Message(messages.SUCCESS, (
+ "Votre réponse a bien été enregistrée ! Vous pouvez cependant la "
+ "modifier jusqu'à la fin du sondage."
+ ))
+
+ @property
+ def url_kwargs(self):
+ return {'survey_id': self.s.pk}
+
+ @property
+ def url_expected(self):
+ return '/survey/{}'.format(self.s.pk)
+
+ def setUp(self):
+ super().setUp()
+
+ self.s = Survey.objects.create(title='Title')
+
+ self.q1 = self.s.questions.create(question='Question 1 ?')
+ self.q2 = self.s.questions.create(
+ question='Question 2 ?',
+ multi_answers=True,
+ )
+
+ self.qa1 = self.q1.answers.create(answer='Q1 - Answer 1')
+ self.qa2 = self.q1.answers.create(answer='Q1 - Answer 2')
+ self.qa3 = self.q2.answers.create(answer='Q2 - Answer 1')
+ self.qa4 = self.q2.answers.create(answer='Q2 - Answer 2')
+
+ 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, {
+ 'question_{}'.format(self.q1.pk): [str(self.qa1.pk)],
+ 'question_{}'.format(self.q2.pk): [
+ str(self.qa3.pk), str(self.qa4.pk),
+ ],
+ })
+
+ self.assertEqual(r.status_code, 200)
+ self.assertIn(self.post_expected_message, get_messages(r.wsgi_request))
+
+ a = self.s.surveyanswer_set.get(user=self.users['user'])
+ self.assertQuerysetEqual(
+ a.answers.all(), map(repr, [self.qa1, self.qa3, self.qa4]),
+ ordered=False,
+ )
+
+ def test_post_edit(self):
+ a = self.s.surveyanswer_set.create(user=self.users['user'])
+ a.answers.add(self.qa1, self.qa1, self.qa4)
+
+ r = self.client.post(self.url, {
+ 'question_{}'.format(self.q1.pk): [],
+ 'question_{}'.format(self.q2.pk): [str(self.qa3.pk)],
+ })
+
+ self.assertEqual(r.status_code, 200)
+ self.assertIn(self.post_expected_message, get_messages(r.wsgi_request))
+
+ a.refresh_from_db()
+ self.assertQuerysetEqual(
+ a.answers.all(), map(repr, [self.qa3]),
+ ordered=False,
+ )
+
+ def test_post_delete(self):
+ a = self.s.surveyanswer_set.create(user=self.users['user'])
+ a.answers.add(self.qa1, self.qa4)
+
+ r = self.client.post(self.url, {'delete': '1'})
+
+ self.assertEqual(r.status_code, 200)
+ expected_message = Message(
+ messages.SUCCESS, "Votre réponse a bien été supprimée")
+ self.assertIn(expected_message, get_messages(r.wsgi_request))
+
+ with self.assertRaises(SurveyAnswer.DoesNotExist):
+ a.refresh_from_db()
+
+ def test_forbidden_closed(self):
+ self.s.survey_open = False
+ self.s.save()
+
+ r = self.client.get(self.url)
+
+ self.assertNotEqual(r.status_code, 200)
+
+ def test_forbidden_old(self):
+ self.s.old = True
+ self.s.save()
+
+ r = self.client.get(self.url)
+
+ self.assertNotEqual(r.status_code, 200)
+
+
+class SurveyStatusViewTests(ViewTestCaseMixin, TestCase):
+ url_name = 'survey.details.status'
+
+ http_methods = ['GET', 'POST']
+
+ auth_user = 'staff'
+ auth_forbidden = [None, 'user', 'member']
+
+ @property
+ def url_kwargs(self):
+ return {'survey_id': self.s.pk}
+
+ @property
+ def url_expected(self):
+ return '/survey/{}/status'.format(self.s.pk)
+
+ def setUp(self):
+ super().setUp()
+
+ self.s = Survey.objects.create(title='Title')
+
+ self.q1 = self.s.questions.create(question='Question 1 ?')
+ self.q2 = self.s.questions.create(
+ question='Question 2 ?',
+ multi_answers=True,
+ )
+
+ self.qa1 = self.q1.answers.create(answer='Q1 - Answer 1')
+ self.qa2 = self.q1.answers.create(answer='Q1 - Answer 2')
+ self.qa3 = self.q2.answers.create(answer='Q2 - Answer 1')
+ self.qa4 = self.q2.answers.create(answer='Q2 - Answer 2')
+
+ self.a1 = self.s.surveyanswer_set.create(user=self.users['user'])
+ self.a1.answers.add(self.qa1)
+ self.a2 = self.s.surveyanswer_set.create(user=self.users['member'])
+
+ def test_get(self):
+ r = self.client.get(self.url)
+ self.assertEqual(r.status_code, 200)
+
+ def _get_qa_filter_name(self, qa):
+ return 'question_{}_answer_{}'.format(qa.survey_question.pk, qa.pk)
+
+ def _test_filters(self, filters, expected):
+ r = self.client.post(self.url, {
+ self._get_qa_filter_name(qa): v for qa, v in filters
+ })
+
+ self.assertEqual(r.status_code, 200)
+ self.assertQuerysetEqual(
+ r.context['user_answers'], map(repr, expected),
+ ordered=False,
+ )
+
+ def test_filter_none(self):
+ self._test_filters([(self.qa1, 'none')], [self.a1, self.a2])
+
+ def test_filter_yes(self):
+ self._test_filters([(self.qa1, 'yes')], [self.a1])
+
+ def test_filter_no(self):
+ self._test_filters([(self.qa1, 'no')], [self.a2])
From 8675948d9e849acc028e79c78f7aed92b68101ac Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Delobelle?=
Date: Fri, 19 Jan 2018 18:01:36 +0100
Subject: [PATCH 06/33] cof -- Fix urls naming in survey templates
---
gestioncof/templates/gestioncof/survey.html | 2 +-
gestioncof/templates/survey_status.html | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/gestioncof/templates/gestioncof/survey.html b/gestioncof/templates/gestioncof/survey.html
index ccf447ef..9d4d67b3 100644
--- a/gestioncof/templates/gestioncof/survey.html
+++ b/gestioncof/templates/gestioncof/survey.html
@@ -8,7 +8,7 @@
{% if survey.details %}
{{ survey.details }}
{% endif %}
-
- 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 = [
From 80ca35a4c0ff1f69916037ffba7713c4a57e5532 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Delobelle?=
Date: Mon, 22 Jan 2018 14:49:02 +0100
Subject: [PATCH 18/33] Add helper to check HttpResponse containing csv
---
shared/tests/testcases.py | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/shared/tests/testcases.py b/shared/tests/testcases.py
index 15792383..cac036af 100644
--- a/shared/tests/testcases.py
+++ b/shared/tests/testcases.py
@@ -1,3 +1,4 @@
+import csv
from unittest import mock
from urllib.parse import parse_qs, urlparse
@@ -92,6 +93,10 @@ class TestCaseMixin:
else:
self.assertEqual(actual, expected)
+ def load_from_csv_response(self, r):
+ decoded = r.content.decode('utf-8')
+ return list(csv.reader(decoded.split('\n')[:-1]))
+
class ViewTestCaseMixin(TestCaseMixin):
"""
From f371606cdbd98298383a038879b6f51d5242b447 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Delobelle?=
Date: Mon, 22 Jan 2018 14:58:38 +0100
Subject: [PATCH 19/33] cof -- Add tests for export views
---
gestioncof/tests/test_views.py | 159 +++++++++++++++++++++++++++++++++
1 file changed, 159 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..8cd323cc
--- /dev/null
+++ b/gestioncof/tests/test_views.py
@@ -0,0 +1,159 @@
+import csv
+
+from django.test import TestCase
+
+from gestioncof.models import Event
+from gestioncof.tests.testcases import ViewTestCaseMixin
+
+from .utils import create_user
+
+
+class ExportMembersViewTests(ViewTestCaseMixin, TestCase):
+ url_name = 'gestioncof.views.export_members'
+ url_expected = '/export/members'
+
+ auth_user = 'staff'
+ auth_forbidden = [None, 'user', 'member']
+
+ def test(self):
+ u1, u2 = self.users['member'], self.users['staff']
+ u1.first_name = 'first'
+ u1.last_name = 'last'
+ u1.email = 'user@mail.net'
+ u1.save()
+ u1.profile.phone = '0123456789'
+ u1.profile.departement = 'Dept'
+ u1.profile.save()
+
+ r = self.client.get(self.url)
+
+ self.assertEqual(r.status_code, 200)
+ data = list(csv.reader(r.content.decode('utf-8').split('\n')[:-1]))
+ self.assertListEqual(data, [
+ [
+ str(u1.pk), 'member', 'first', 'last', 'user@mail.net',
+ '0123456789', '1A', 'Dept', 'normalien',
+ ],
+ [str(u2.pk), 'staff', '', '', '', '', '1A', '', 'normalien'],
+ ])
+
+
+class MegaHelpers:
+
+ def setUp(self):
+ super().setUp()
+
+ u1 = create_user('u1')
+ u1.first_name = 'first'
+ u1.last_name = 'last'
+ u1.email = 'user@mail.net'
+ u1.save()
+ u1.profile.phone = '0123456789'
+ u1.profile.departement = 'Dept'
+ u1.profile.comments = 'profile.comments'
+ u1.profile.save()
+
+ u2 = create_user('u2')
+ u2.profile.save()
+
+ m = Event.objects.create(title='MEGA 2017')
+
+ cf1 = m.commentfields.create(name='Commentaire')
+ cf2 = m.commentfields.create(
+ name='Comment Field 2', fieldtype='char',
+ )
+
+ option_type = m.options.create(name='Conscrit/Orga ?')
+ choice_orga = option_type.choices.create(value='Orga')
+ choice_conscrit = option_type.choices.create(value='Conscrit')
+
+ mr1 = m.eventregistration_set.create(user=u1)
+ mr1.options.add(choice_orga)
+ mr1.comments.create(commentfield=cf1, content='Comment 1')
+ mr1.comments.create(commentfield=cf2, content='Comment 2')
+
+ mr2 = m.eventregistration_set.create(user=u2)
+ mr2.options.add(choice_conscrit)
+
+ self.u1 = u1
+ self.u2 = u2
+ self.m = m
+ self.choice_orga = choice_orga
+ self.choice_conscrit = choice_conscrit
+
+
+class ExportMegaViewTests(MegaHelpers, ViewTestCaseMixin, TestCase):
+ url_name = 'gestioncof.views.export_mega'
+ url_expected = '/export/mega'
+
+ auth_user = 'staff'
+ auth_forbidden = [None, 'user', 'member']
+
+ def test(self):
+ r = self.client.get(self.url)
+
+ self.assertEqual(r.status_code, 200)
+ self.assertListEqual(self.load_from_csv_response(r), [
+ [
+ 'u1', 'first', 'last', 'user@mail.net', '0123456789',
+ str(self.u1.pk), 'profile.comments', 'Comment 1---Comment 2',
+ ],
+ ['u2', '', '', '', '', str(self.u2.pk), '', ''],
+ ])
+
+
+class ExportMegaOrgasViewTests(MegaHelpers, ViewTestCaseMixin, TestCase):
+ url_name = 'gestioncof.views.export_mega_orgas'
+ url_expected = '/export/mega/orgas'
+
+ auth_user = 'staff'
+ auth_forbidden = [None, 'user', 'member']
+
+ def test(self):
+
+ r = self.client.get(self.url)
+
+ self.assertEqual(r.status_code, 200)
+ self.assertListEqual(self.load_from_csv_response(r), [
+ [
+ 'u1', 'first', 'last', 'user@mail.net', '0123456789',
+ str(self.u1.pk), 'profile.comments', 'Comment 1---Comment 2',
+ ],
+ ])
+
+
+class ExportMegaParticipantsViewTests(
+ MegaHelpers, ViewTestCaseMixin, TestCase):
+ url_name = 'gestioncof.views.export_mega_participants'
+ url_expected = '/export/mega/participants'
+
+ auth_user = 'staff'
+ auth_forbidden = [None, 'user', 'member']
+
+ def test(self):
+ r = self.client.get(self.url)
+
+ self.assertEqual(r.status_code, 200)
+ self.assertListEqual(self.load_from_csv_response(r), [
+ ['u2', '', '', '', '', str(self.u2.pk), '', ''],
+ ])
+
+
+class ExportMegaRemarksViewTests(
+ MegaHelpers, ViewTestCaseMixin, TestCase):
+ url_name = 'gestioncof.views.export_mega_remarksonly'
+ url_expected = '/export/mega/avecremarques'
+
+ auth_user = 'staff'
+ auth_forbidden = [None, 'user', 'member']
+
+ def test(self):
+ r = self.client.get(self.url)
+
+ self.assertEqual(r.status_code, 200)
+ self.assertListEqual(self.load_from_csv_response(r), [
+ [
+ 'u1', 'first', 'last', 'user@mail.net', '0123456789',
+ str(self.u1.pk), 'profile.comments', 'Comment 1',
+ ],
+ ])
From a813507ddd6218e51769f8a0b8e17ddc7f04115f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Delobelle?=
Date: Mon, 22 Jan 2018 14:59:57 +0100
Subject: [PATCH 20/33] Name urls of export views (cof members, mega)
---
gestioncof/templates/gestioncof/utile_cof.html | 8 ++++----
gestioncof/tests/test_views.py | 10 +++++-----
gestioncof/urls.py | 15 ++++++++++-----
3 files changed, 19 insertions(+), 14 deletions(-)
diff --git a/gestioncof/templates/gestioncof/utile_cof.html b/gestioncof/templates/gestioncof/utile_cof.html
index ae024949..8cea33df 100644
--- a/gestioncof/templates/gestioncof/utile_cof.html
+++ b/gestioncof/templates/gestioncof/utile_cof.html
@@ -7,15 +7,15 @@
Liens utiles du COF
COF
Mega
Note : pour ouvrir les fichiers .csv avec Excel, il faut
diff --git a/gestioncof/tests/test_views.py b/gestioncof/tests/test_views.py
index 8cd323cc..02288e2b 100644
--- a/gestioncof/tests/test_views.py
+++ b/gestioncof/tests/test_views.py
@@ -9,7 +9,7 @@ from .utils import create_user
class ExportMembersViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'gestioncof.views.export_members'
+ url_name = 'cof.membres_export'
url_expected = '/export/members'
auth_user = 'staff'
@@ -83,7 +83,7 @@ class MegaHelpers:
class ExportMegaViewTests(MegaHelpers, ViewTestCaseMixin, TestCase):
- url_name = 'gestioncof.views.export_mega'
+ url_name = 'cof.mega_export'
url_expected = '/export/mega'
auth_user = 'staff'
@@ -103,7 +103,7 @@ class ExportMegaViewTests(MegaHelpers, ViewTestCaseMixin, TestCase):
class ExportMegaOrgasViewTests(MegaHelpers, ViewTestCaseMixin, TestCase):
- url_name = 'gestioncof.views.export_mega_orgas'
+ url_name = 'cof.mega_export_orgas'
url_expected = '/export/mega/orgas'
auth_user = 'staff'
@@ -124,7 +124,7 @@ class ExportMegaOrgasViewTests(MegaHelpers, ViewTestCaseMixin, TestCase):
class ExportMegaParticipantsViewTests(
MegaHelpers, ViewTestCaseMixin, TestCase):
- url_name = 'gestioncof.views.export_mega_participants'
+ url_name = 'cof.mega_export_participants'
url_expected = '/export/mega/participants'
auth_user = 'staff'
@@ -141,7 +141,7 @@ class ExportMegaParticipantsViewTests(
class ExportMegaRemarksViewTests(
MegaHelpers, ViewTestCaseMixin, TestCase):
- url_name = 'gestioncof.views.export_mega_remarksonly'
+ url_name = 'cof.mega_export_remarks'
url_expected = '/export/mega/avecremarques'
auth_user = 'staff'
diff --git a/gestioncof/urls.py b/gestioncof/urls.py
index 2be609b3..ef3b4190 100644
--- a/gestioncof/urls.py
+++ b/gestioncof/urls.py
@@ -6,12 +6,17 @@ from gestioncof import views, petits_cours_views
from gestioncof.decorators import buro_required
export_patterns = [
- url(r'^members$', views.export_members),
- url(r'^mega/avecremarques$', views.export_mega_remarksonly),
- url(r'^mega/participants$', views.export_mega_participants),
- url(r'^mega/orgas$', views.export_mega_orgas),
+ url(r'^members$', views.export_members,
+ name='cof.membres_export'),
+ url(r'^mega/avecremarques$', views.export_mega_remarksonly,
+ name='cof.mega_export_remarks'),
+ url(r'^mega/participants$', views.export_mega_participants,
+ name='cof.mega_export_participants'),
+ url(r'^mega/orgas$', views.export_mega_orgas,
+ name='cof.mega_export_orgas'),
# url(r'^mega/(?P.+)$', views.export_mega_bytype),
- url(r'^mega$', views.export_mega),
+ url(r'^mega$', views.export_mega,
+ name='cof.mega_export'),
]
petitcours_patterns = [
From bd89dce11d72f6ecf86501cfaf920dac646c6914 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Delobelle?=
Date: Mon, 22 Jan 2018 21:38:01 +0100
Subject: [PATCH 21/33] Add testing helpers to create superuser
---
gestioncof/tests/utils.py | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/gestioncof/tests/utils.py b/gestioncof/tests/utils.py
index 8d55680a..7ba361b7 100644
--- a/gestioncof/tests/utils.py
+++ b/gestioncof/tests/utils.py
@@ -9,7 +9,9 @@ def _create_user(username, is_cof=False, is_staff=False, attrs=None):
password = attrs.pop('password', username)
- user_keys = ['first_name', 'last_name', 'email', 'is_staff']
+ user_keys = [
+ 'first_name', 'last_name', 'email', 'is_staff', 'is_superuser',
+ ]
user_attrs = {k: v for k, v in attrs.items() if k in user_keys}
profile_keys = [
@@ -49,3 +51,11 @@ def create_member(username, attrs=None):
def create_staff(username, attrs=None):
return _create_user(username, is_cof=True, is_staff=True, attrs=attrs)
+
+
+def create_root(username, attrs=None):
+ if attrs is None:
+ attrs = {}
+ attrs.setdefault('is_staff', True)
+ attrs.setdefault('is_superuser', True)
+ return _create_user(username, attrs=attrs)
From 91162addb95fcafbf555288cc7fdeafa6f910b4c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Delobelle?=
Date: Mon, 22 Jan 2018 21:41:02 +0100
Subject: [PATCH 22/33] cof -- Add tests for some views
---
gestioncof/tests/test_views.py | 131 +++++++++++++++++++++++++++++++++
gestioncof/views.py | 1 +
2 files changed, 132 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..9f13fb36
--- /dev/null
+++ b/gestioncof/tests/test_views.py
@@ -0,0 +1,131 @@
+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 django.urls import reverse
+
+from gestioncof.tests.testcases import ViewTestCaseMixin
+
+from .utils import create_member, create_root, create_user
+
+
+class HomeViewTests(ViewTestCaseMixin, TestCase):
+ url_name = 'home'
+ url_expected = '/'
+
+ auth_user = 'user'
+ auth_forbidden = [None]
+
+ def test(self):
+ r = self.client.get(self.url)
+ self.assertEqual(r.status_code, 200)
+
+
+class ProfileViewTests(ViewTestCaseMixin, TestCase):
+ url_name = 'profile'
+ url_expected = '/profile'
+
+ http_methods = ['GET', 'POST']
+
+ auth_user = 'member'
+ auth_forbidden = [None, 'user']
+
+ def test_get(self):
+ r = self.client.get(self.url)
+ self.assertEqual(r.status_code, 200)
+
+ def test_post(self):
+ u = self.users['member']
+
+ r = self.client.post(self.url, {
+ 'first_name': 'First',
+ 'last_name': 'Last',
+ 'phone': '',
+ # 'mailing_cof': '1',
+ # 'mailing_bda': '1',
+ # 'mailing_bda_revente': '1',
+ })
+
+ self.assertEqual(r.status_code, 200)
+ expected_message = Message(messages.SUCCESS, (
+ "Votre profil a été mis à jour avec succès !"
+ ))
+ self.assertIn(expected_message, get_messages(r.wsgi_request))
+ u.refresh_from_db()
+ self.assertEqual(u.first_name, 'First')
+ self.assertEqual(u.last_name, 'Last')
+ self.assertFalse(u.profile.mailing_cof)
+ self.assertFalse(u.profile.mailing_bda)
+ self.assertFalse(u.profile.mailing_bda_revente)
+
+
+class UtilsViewTests(ViewTestCaseMixin, TestCase):
+ url_name = 'utile_cof'
+ url_expected = '/utile_cof'
+
+ auth_user = 'staff'
+ auth_forbidden = [None, 'user', 'member']
+
+ def test(self):
+ r = self.client.get(self.url)
+ self.assertEqual(r.status_code, 200)
+
+
+class MailingListDiffCof(ViewTestCaseMixin, TestCase):
+ url_name = 'gestioncof.views.liste_diffcof'
+ url_expected = '/utile_cof/diff_cof'
+
+ auth_user = 'staff'
+ auth_forbidden = [None, 'user', 'member']
+
+ def setUp(self):
+ super().setUp()
+
+ self.u1 = create_member('u1', attrs={'mailing_cof': True})
+ self.u2 = create_member('u2', attrs={'mailing_cof': False})
+ self.u3 = create_user('u3', attrs={'mailing_cof': True})
+
+ def test(self):
+ r = self.client.get(self.url)
+
+ self.assertEqual(r.status_code, 200)
+ self.assertEqual(r.context['personnes'].get(), self.u1.profile)
+
+
+class ConfigUpdateViewTests(ViewTestCaseMixin, TestCase):
+ url_name = 'config.edit'
+ url_expected = '/config'
+
+ http_methods = ['GET', 'POST']
+
+ auth_user = 'root'
+ auth_forbidden = [None, 'user', 'member', 'staff']
+
+ def get_users_extra(self):
+ return {
+ 'root': create_root('root'),
+ }
+
+ def test_get(self):
+ r = self.client.get(self.url)
+ self.assertEqual(r.status_code, 200)
+
+ def test_post(self):
+ r = self.client.post(self.url, {
+ 'gestion_banner': 'Announcement !',
+ })
+
+ self.assertRedirects(r, reverse('home'))
+
+
+class UserAutocompleteViewTests(ViewTestCaseMixin, TestCase):
+ url_name = 'cof-user-autocomplete'
+ url_expected = '/user/autocomplete'
+
+ auth_user = 'staff'
+ auth_forbidden = [None, 'user', 'member']
+
+ def test(self):
+ r = self.client.get(self.url, {'q': 'user'})
+
+ self.assertEqual(r.status_code, 200)
diff --git a/gestioncof/views.py b/gestioncof/views.py
index 5dfee83f..2039bb65 100644
--- a/gestioncof/views.py
+++ b/gestioncof/views.py
@@ -9,6 +9,7 @@ from django.http import Http404, HttpResponse, HttpResponseForbidden
from django.contrib.auth.decorators import login_required
from django.contrib.auth.views import (
login as django_login_view, logout as django_logout_view,
+ redirect_to_login,
)
from django.contrib.auth.models import User
from django.contrib.sites.models import Site
From 0876a004e55a04cf638903a2aa423e608a3654bf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Delobelle?=
Date: Mon, 22 Jan 2018 14:59:57 +0100
Subject: [PATCH 23/33] Name urls of export views (cof members, mega)
---
gestioncof/templates/gestioncof/utile_cof.html | 8 ++++----
gestioncof/urls.py | 15 ++++++++++-----
2 files changed, 14 insertions(+), 9 deletions(-)
diff --git a/gestioncof/templates/gestioncof/utile_cof.html b/gestioncof/templates/gestioncof/utile_cof.html
index ae024949..8cea33df 100644
--- a/gestioncof/templates/gestioncof/utile_cof.html
+++ b/gestioncof/templates/gestioncof/utile_cof.html
@@ -7,15 +7,15 @@
Liens utiles du COF
COF
Mega
Note : pour ouvrir les fichiers .csv avec Excel, il faut
diff --git a/gestioncof/urls.py b/gestioncof/urls.py
index 2be609b3..ef3b4190 100644
--- a/gestioncof/urls.py
+++ b/gestioncof/urls.py
@@ -6,12 +6,17 @@ from gestioncof import views, petits_cours_views
from gestioncof.decorators import buro_required
export_patterns = [
- url(r'^members$', views.export_members),
- url(r'^mega/avecremarques$', views.export_mega_remarksonly),
- url(r'^mega/participants$', views.export_mega_participants),
- url(r'^mega/orgas$', views.export_mega_orgas),
+ url(r'^members$', views.export_members,
+ name='cof.membres_export'),
+ url(r'^mega/avecremarques$', views.export_mega_remarksonly,
+ name='cof.mega_export_remarks'),
+ url(r'^mega/participants$', views.export_mega_participants,
+ name='cof.mega_export_participants'),
+ url(r'^mega/orgas$', views.export_mega_orgas,
+ name='cof.mega_export_orgas'),
# url(r'^mega/(?P.+)$', views.export_mega_bytype),
- url(r'^mega$', views.export_mega),
+ url(r'^mega$', views.export_mega,
+ name='cof.mega_export'),
]
petitcours_patterns = [
From f8361b9114700facc4ebfcaa79d024be49496193 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Delobelle?=
Date: Mon, 22 Jan 2018 21:53:19 +0100
Subject: [PATCH 24/33] Add & fix urls naming
---
cof/urls.py | 6 ++++--
gestioncof/templates/gestioncof/profile.html | 2 +-
gestioncof/templates/gestioncof/utile_cof.html | 2 +-
gestioncof/tests/test_views.py | 2 +-
4 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/cof/urls.py b/cof/urls.py
index e6e5d313..33d4fbc6 100644
--- a/cof/urls.py
+++ b/cof/urls.py
@@ -86,13 +86,15 @@ urlpatterns = [
url(r'^utile_bda$', gestioncof_views.utile_bda,
name='utile_bda'),
url(r'^utile_bda/bda_diff$', gestioncof_views.liste_bdadiff),
- url(r'^utile_cof/diff_cof$', gestioncof_views.liste_diffcof),
+ url(r'^utile_cof/diff_cof$', gestioncof_views.liste_diffcof,
+ name='ml_diffcof'),
url(r'^utile_bda/bda_revente$', gestioncof_views.liste_bdarevente),
url(r'^k-fet/', include('kfet.urls')),
url(r'^cms/', include(wagtailadmin_urls)),
url(r'^documents/', include(wagtaildocs_urls)),
# djconfig
- url(r"^config", gestioncof_views.ConfigUpdate.as_view()),
+ url(r"^config", gestioncof_views.ConfigUpdate.as_view(),
+ name='config.edit'),
]
if 'debug_toolbar' in settings.INSTALLED_APPS:
diff --git a/gestioncof/templates/gestioncof/profile.html b/gestioncof/templates/gestioncof/profile.html
index 59358239..5decdfb3 100644
--- a/gestioncof/templates/gestioncof/profile.html
+++ b/gestioncof/templates/gestioncof/profile.html
@@ -5,7 +5,7 @@
{% block realcontent %}
Modifier mon profil
-