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/22] 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/22] 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/22] 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/22] 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/22] 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/22] 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 ac1a57d96993466d38a2e87edcbcd1e5501b8c54 Mon Sep 17 00:00:00 2001
From: Basile Clement
Date: Sun, 11 Feb 2018 17:01:26 +0100
Subject: [PATCH 18/22] Make provisioning script stop immediately on errors
By default, bash will ignore any failing commands and happily proceed to
execute the next ones. This is usually not the behavior the we want in
provisioning script (or ever in scripts, actually): if one step of the
provisioning fails, it doesn't make much sense to proceed with the
following ones.
This simple patch uses `set -e` to ask bash to abort the whole script if
any command within it fails, leading to outputs that are easier to parse
since the commands following a failing one will usually fail also,
hiding the root cause.
---
provisioning/bootstrap.sh | 3 +++
provisioning/prepare_django.sh | 3 +++
2 files changed, 6 insertions(+)
diff --git a/provisioning/bootstrap.sh b/provisioning/bootstrap.sh
index 69bbcf4c..cb6917a7 100644
--- a/provisioning/bootstrap.sh
+++ b/provisioning/bootstrap.sh
@@ -1,5 +1,8 @@
#!/bin/sh
+# Stop if an error is encountered
+set -e
+
# Configuration de la base de données. Le mot de passe est constant car c'est
# pour une installation de dév locale qui ne sera accessible que depuis la
# machine virtuelle.
diff --git a/provisioning/prepare_django.sh b/provisioning/prepare_django.sh
index 1818a0cd..891108e8 100644
--- a/provisioning/prepare_django.sh
+++ b/provisioning/prepare_django.sh
@@ -1,5 +1,8 @@
#!/bin/bash
+# Stop if an error is encountered.
+set -e
+
python manage.py migrate
python manage.py loaddata gestion sites articles
python manage.py loaddevdata
From 3314670cab2917f3d57e3340c56a7a5daddd92c8 Mon Sep 17 00:00:00 2001
From: Basile Clement
Date: Sun, 11 Feb 2018 19:09:07 +0100
Subject: [PATCH 19/22] Various fixes for Django 1.11
- The {% cycle %} command was used non-quoted arguments separated by
commas, while it is supposed to use quoted arguments separated by
spaces (I'm actually not sure how that ever worked :)
- django-bootstrap-form was at version 3.2.1 which is not compatible
with Django 1.11 (but also required by GestioCOF). I upgraded it to
version 3.3.
---
bda/templates/bda/inscription-formset.html | 2 +-
gestioncof/templates/inscription-petit-cours-formset.html | 2 +-
requirements.txt | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/bda/templates/bda/inscription-formset.html b/bda/templates/bda/inscription-formset.html
index 65ef389b..88b65600 100644
--- a/bda/templates/bda/inscription-formset.html
+++ b/bda/templates/bda/inscription-formset.html
@@ -14,7 +14,7 @@
{% endif %}
-
+
{% for field in form.visible_fields %}
{% if field.name != "DELETE" and field.name != "priority" %}
diff --git a/gestioncof/templates/inscription-petit-cours-formset.html b/gestioncof/templates/inscription-petit-cours-formset.html
index ec8979f5..40311772 100644
--- a/gestioncof/templates/inscription-petit-cours-formset.html
+++ b/gestioncof/templates/inscription-petit-cours-formset.html
@@ -16,7 +16,7 @@
{% endif %}
-
+
{% for field in form.visible_fields %}
{% if field.name != "DELETE" and field.name != "priority" %}
diff --git a/requirements.txt b/requirements.txt
index d1046042..b30660ee 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -11,7 +11,7 @@ psycopg2
Pillow
six
unicodecsv
-django-bootstrap-form==3.2.1
+django-bootstrap-form==3.3
asgiref==1.1.1
daphne==1.3.0
asgi-redis==1.3.0
From 6ecc9a54b36d153dea502057531dd5b6bb7ea8cc Mon Sep 17 00:00:00 2001
From: Basile Clement
Date: Sun, 11 Feb 2018 19:24:01 +0100
Subject: [PATCH 20/22] Properly propagate the default number of places in
tirage
Fixes #182.
---
bda/templates/bda/inscription-tirage.html | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/bda/templates/bda/inscription-tirage.html b/bda/templates/bda/inscription-tirage.html
index d56b4229..3fd81378 100644
--- a/bda/templates/bda/inscription-tirage.html
+++ b/bda/templates/bda/inscription-tirage.html
@@ -27,6 +27,14 @@ var django = {
var newFor = $(this).attr('for').replace('-' + (total-1) + '-','-' + total + '-');
$(this).attr('for', newFor);
});
+ // Cloning element doesn't properly propagate the default
+ // selected , so we set it manually.
+ newElement.find('select').each(function (index, select) {
+ var defaultValue = $(select).find('option[selected]').val();
+ if (typeof defaultValue !== 'undefined') {
+ $(select).val(defaultValue);
+ }
+ });
total++;
$('#id_' + type + '-TOTAL_FORMS').val(total);
$(selector).after(newElement);
From 35e17a81a6e2e91f22facc5ca9df6a0a56a8f67a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martin=20P=C3=A9pin?=
Date: Thu, 5 Apr 2018 23:48:53 +0200
Subject: [PATCH 21/22] New year -> new promo -> migration in k-fet
---
kfet/migrations/0063_promo.py | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
create mode 100644 kfet/migrations/0063_promo.py
diff --git a/kfet/migrations/0063_promo.py b/kfet/migrations/0063_promo.py
new file mode 100644
index 00000000..3fac5a8a
--- /dev/null
+++ b/kfet/migrations/0063_promo.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.12 on 2018-04-05 21:47
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('kfet', '0062_delete_globalpermissions'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='account',
+ name='promo',
+ field=models.IntegerField(blank=True, choices=[(1980, 1980), (1981, 1981), (1982, 1982), (1983, 1983), (1984, 1984), (1985, 1985), (1986, 1986), (1987, 1987), (1988, 1988), (1989, 1989), (1990, 1990), (1991, 1991), (1992, 1992), (1993, 1993), (1994, 1994), (1995, 1995), (1996, 1996), (1997, 1997), (1998, 1998), (1999, 1999), (2000, 2000), (2001, 2001), (2002, 2002), (2003, 2003), (2004, 2004), (2005, 2005), (2006, 2006), (2007, 2007), (2008, 2008), (2009, 2009), (2010, 2010), (2011, 2011), (2012, 2012), (2013, 2013), (2014, 2014), (2015, 2015), (2016, 2016), (2017, 2017), (2018, 2018)], default=2017, null=True),
+ ),
+ ]
From 623047dca2dabb3e8eec9e5b97ef30f8c64caf85 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martin=20P=C3=A9pin?=
Date: Fri, 6 Apr 2018 11:11:02 +0200
Subject: [PATCH 22/22] Fix old-style reversal of calendar urls
---
bda/templates/bda/resume_places.html | 2 +-
gestioncof/templates/gestioncof/calendar_subscription.html | 2 +-
gestioncof/urls.py | 4 +++-
3 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/bda/templates/bda/resume_places.html b/bda/templates/bda/resume_places.html
index 3785169b..7cbd06ea 100644
--- a/bda/templates/bda/resume_places.html
+++ b/bda/templates/bda/resume_places.html
@@ -16,7 +16,7 @@
Total à payer : {{ total|floatformat }}€
Ne manque pas un spectacle avec le
- calendrier
+ calendrier
automatique !
{% else %}
Vous n'avez aucune place :(
diff --git a/gestioncof/templates/gestioncof/calendar_subscription.html b/gestioncof/templates/gestioncof/calendar_subscription.html
index b13cb7f2..345312e3 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/urls.py b/gestioncof/urls.py
index 2be609b3..1a66dd57 100644
--- a/gestioncof/urls.py
+++ b/gestioncof/urls.py
@@ -52,7 +52,9 @@ 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 = [