diff --git a/gestioncof/autocomplete.py b/gestioncof/autocomplete.py
index 968398fd..9263dc50 100644
--- a/gestioncof/autocomplete.py
+++ b/gestioncof/autocomplete.py
@@ -21,6 +21,13 @@ class Clipper(object):
self.clipper = clipper
self.fullname = fullname
+ def __str__(self):
+ return '{} ({})'.format(self.clipper, self.fullname)
+
+ def __eq__(self, other):
+ return (
+ self.clipper == other.clipper and self.fullname == other.fullname)
+
@buro_required
def autocomplete(request):
diff --git a/gestioncof/tests/test_views.py b/gestioncof/tests/test_views.py
new file mode 100644
index 00000000..60f93c9d
--- /dev/null
+++ b/gestioncof/tests/test_views.py
@@ -0,0 +1,339 @@
+from django.contrib import messages
+from django.contrib.auth import get_user_model
+from django.contrib.messages.api import get_messages
+from django.contrib.messages.storage.base import Message
+from django.core import mail
+from django.core.management import call_command
+from django.test import TestCase, override_settings
+
+from gestioncof.autocomplete import Clipper
+from gestioncof.models import Event
+from gestioncof.tests.testcases import ViewTestCaseMixin
+
+from custommail.models import CustomMail
+
+from .utils import create_user, create_member
+
+User = get_user_model()
+
+
+class RegistrationViewTests(ViewTestCaseMixin, TestCase):
+ url_name = 'registration'
+ url_expected = '/registration'
+
+ http_methods = ['GET', 'POST']
+
+ auth_user = 'staff'
+ auth_forbidden = [None, 'user', 'member']
+
+ def requires_mails(self):
+ call_command('syncmails', verbosity=0)
+
+ def test_get(self):
+ r = self.client.get(self.url)
+ self.assertEqual(r.status_code, 200)
+
+ @property
+ def _minimal_data(self):
+ return {
+ 'first_name': '',
+ 'last_name': '',
+ 'email': '',
+
+ # 'is_cof': '1',
+ 'login_clipper': '',
+ 'phone': '',
+ 'occupation': '1A',
+ 'departement': '',
+ 'type_cotiz': 'normalien',
+ 'comments': '',
+
+ # 'user_exists': '1',
+
+ 'events-TOTAL_FORMS': '0',
+ 'events-INITIAL_FORMS': '0',
+ 'events-MIN_NUM_FORMS': '0',
+ 'events-MAX_NUM_FORMS': '1000',
+ }
+
+ def test_post_new(self):
+ self.requires_mails()
+
+ r = self.client.post(self.url, dict(self._minimal_data, **{
+ 'username': 'username',
+ 'first_name': 'first',
+ 'last_name': 'last',
+ 'email': 'username@mail.net',
+ 'is_cof': '1',
+ }))
+
+ self.assertEqual(r.status_code, 200)
+ u = User.objects.get(username='username')
+ expected_message = Message(messages.SUCCESS, (
+ "L'inscription de first last (username@mail.net) a été "
+ "enregistrée avec succès.\n"
+ "Il est désormais membre du COF n°{} !"
+ .format(u.pk)
+ ))
+ self.assertIn(expected_message, get_messages(r.wsgi_request))
+
+ self.assertEqual(u.first_name, 'first')
+ self.assertEqual(u.last_name, 'last')
+ self.assertEqual(u.email, 'username@mail.net')
+
+ def test_post_edit(self):
+ self.requires_mails()
+ u = self.users['user']
+
+ r = self.client.post(self.url, dict(self._minimal_data, **{
+ 'username': 'user',
+ 'first_name': 'first',
+ 'last_name': 'last',
+ 'email': 'user@mail.net',
+ 'is_cof': '1',
+ 'user_exists': '1',
+ }))
+
+ self.assertEqual(r.status_code, 200)
+ u.refresh_from_db()
+ expected_message = Message(messages.SUCCESS, (
+ "L'inscription de first last (user@mail.net) a été "
+ "enregistrée avec succès.\n"
+ "Il est désormais membre du COF n°{} !"
+ .format(u.pk)
+ ))
+ self.assertIn(expected_message, get_messages(r.wsgi_request))
+
+ self.assertEqual(u.first_name, 'first')
+ self.assertEqual(u.last_name, 'last')
+ self.assertEqual(u.email, 'user@mail.net')
+
+ def _test_mail_welcome(self, was_cof, is_cof, expect_mail):
+ self.requires_mails()
+ u = self.users['member'] if was_cof else self.users['user']
+
+ data = dict(self._minimal_data, **{
+ 'username': u.username,
+ 'email': 'user@mail.net',
+ 'user_exists': '1',
+ })
+ if is_cof:
+ data['is_cof'] = '1'
+ self.client.post(self.url, data)
+
+ u.refresh_from_db()
+
+ def _is_sent():
+ cm = CustomMail.objects.get(shortname='welcome')
+ welcome_msg = cm.get_message({'member': u})
+ for m in mail.outbox:
+ if m.subject == welcome_msg.subject:
+ return True
+ return False
+
+ self.assertEqual(_is_sent(), expect_mail)
+
+ def test_mail_welcome_0(self):
+ self._test_mail_welcome(was_cof=False, is_cof=False, expect_mail=False)
+
+ def test_mail_welcome_1(self):
+ self._test_mail_welcome(was_cof=False, is_cof=True, expect_mail=True)
+
+ def test_mail_welcome_2(self):
+ self._test_mail_welcome(was_cof=True, is_cof=False, expect_mail=False)
+
+ def test_mail_welcome_3(self):
+ self._test_mail_welcome(was_cof=True, is_cof=True, expect_mail=False)
+
+ def test_events(self):
+ e = Event.objects.create()
+
+ cf1 = e.commentfields.create(name='Comment Field 1')
+ cf2 = e.commentfields.create(
+ name='Comment Field 2', fieldtype='char',
+ )
+
+ o1 = e.options.create(name='Option 1')
+ o2 = e.options.create(name='Option 2', multi_choices=True)
+
+ oc1 = o1.choices.create(value='O1 - Choice 1')
+ oc2 = o1.choices.create(value='O1 - Choice 2')
+ oc3 = o2.choices.create(value='O2 - Choice 1')
+ oc4 = o2.choices.create(value='O2 - Choice 2')
+
+ self.client.post(self.url, dict(self._minimal_data, **{
+ 'username': 'user',
+ 'user_exists': '1',
+ 'events-TOTAL_FORMS': '1',
+ 'events-INITIAL_FORMS': '0',
+ 'events-MIN_NUM_FORMS': '0',
+ 'events-MAX_NUM_FORMS': '1000',
+ 'events-0-status': 'paid',
+ 'events-0-option_{}'.format(o1.pk): [str(oc1.pk)],
+ 'events-0-option_{}'.format(o2.pk): [str(oc3.pk)],
+ 'events-0-comment_{}'.format(cf1.pk): 'comment 1',
+ 'events-0-comment_{}'.format(cf2.pk): '',
+ }))
+
+ er = e.eventregistration_set.get(user=self.users['user'])
+ self.assertQuerysetEqual(
+ er.options.all(), map(repr, [oc1, oc3]),
+ ordered=False,
+ )
+ self.assertCountEqual(er.comments.values_list('content', flat=True), [
+ 'comment 1',
+ ])
+
+
+class RegistrationFormViewTests(ViewTestCaseMixin, TestCase):
+ urls_conf = [
+ {
+ 'name': 'empty-registration',
+ 'expected': '/registration/empty',
+ },
+ {
+ 'name': 'user-registration',
+ 'kwargs': {'username': 'user'},
+ 'expected': '/registration/user/user',
+ },
+ {
+ 'name': 'clipper-registration',
+ 'kwargs': {
+ 'login_clipper': 'uid',
+ 'fullname': 'First Last1 Last2',
+ },
+ 'expected': '/registration/clipper/uid/First%20Last1%20Last2',
+ },
+ ]
+
+ auth_user = 'staff'
+ auth_forbidden = [None, 'user', 'member']
+
+ def get_initial(self, form, name):
+ return form.get_initial_for_field(form.fields[name], name)
+
+ def test_empty(self):
+ r = self.client.get(self.t_urls[0])
+
+ user_form = r.context['user_form']
+ profile_form = r.context['profile_form']
+ events_form = r.context['event_formset']
+ clubs_form = r.context['clubs_form']
+
+ def test_username(self):
+ u = self.users['user']
+ u.first_name = 'first'
+ u.last_name = 'last'
+ u.save()
+
+ r = self.client.get(self.t_urls[1])
+
+ user_form = r.context['user_form']
+ profile_form = r.context['profile_form']
+ events_form = r.context['event_formset']
+ clubs_form = r.context['clubs_form']
+
+ self.assertEqual(self.get_initial(user_form, 'username'), 'user')
+ self.assertEqual(self.get_initial(user_form, 'first_name'), 'first')
+ self.assertEqual(self.get_initial(user_form, 'last_name'), 'last')
+
+ def test_clipper(self):
+ r = self.client.get(self.t_urls[2])
+
+ user_form = r.context['user_form']
+ profile_form = r.context['profile_form']
+ events_form = r.context['event_formset']
+ clubs_form = r.context['clubs_form']
+
+ self.assertEqual(self.get_initial(user_form, 'first_name'), 'First')
+ self.assertEqual(
+ self.get_initial(user_form, 'last_name'), 'Last1 Last2')
+ self.assertEqual(
+ self.get_initial(user_form, 'email'), 'uid@clipper.ens.fr')
+ self.assertEqual(
+ self.get_initial(profile_form, 'login_clipper'), 'uid')
+
+
+@override_settings(LDAP_SERVER_URL='ldap_url')
+class RegistrationAutocompleteViewTests(ViewTestCaseMixin, TestCase):
+ url_name = 'cof.registration.autocomplete'
+ url_expected = '/autocomplete/registration'
+
+ auth_user = 'staff'
+ auth_forbidden = [None, 'user', 'member']
+
+ def setUp(self):
+ super().setUp()
+
+ self.u1 = create_user('uu_u1', attrs={
+ 'first_name': 'abc', 'last_name': 'xyz',
+ })
+ self.u2 = create_user('uu_u2', attrs={
+ 'first_name': 'wyz', 'last_name': 'abd',
+ })
+ self.m1 = create_member('uu_m1', attrs={
+ 'first_name': 'ebd', 'last_name': 'wyv',
+ })
+
+ self.mockLDAP([])
+
+ def _test(
+ self, query, expected_users, expected_members, expected_clippers,
+ ):
+ r = self.client.get(self.url, {'q': query})
+
+ self.assertEqual(r.status_code, 200)
+
+ self.assertQuerysetEqual(
+ r.context['users'], map(repr, expected_users),
+ ordered=False,
+ )
+ self.assertQuerysetEqual(
+ r.context['members'],
+ map(lambda u: repr(u.profile), expected_members),
+ ordered=False,
+ )
+ self.assertCountEqual(
+ map(str, r.context.get('clippers', [])),
+ map(str, expected_clippers),
+ )
+
+ def test_username(self):
+ self._test('uu', [self.u1, self.u2], [self.m1], [])
+
+ def test_firstname(self):
+ self._test('ab', [self.u1, self.u2], [], [])
+
+ def test_lastname(self):
+ self._test('wy', [self.u2], [self.m1], [])
+
+ def test_multi_query(self):
+ self._test('wy bd', [self.u2], [self.m1], [])
+
+ def test_clipper(self):
+ mock_ldap = self.mockLDAP([('uid', 'first last')])
+
+ self._test('aa bb', [], [], [Clipper('uid', 'first last')])
+
+ mock_ldap.search.assert_called_once_with(
+ 'dc=spi,dc=ens,dc=fr',
+ '(&(|(cn=*aa*)(uid=*aa*))(|(cn=*bb*)(uid=*bb*)))',
+ attributes=['uid', 'cn'],
+ )
+
+ def test_clipper_escaped(self):
+ mock_ldap = self.mockLDAP([])
+
+ self._test('; & | (', [], [], [])
+
+ mock_ldap.search.assert_not_called()
+
+ def test_clipper_no_duplicate(self):
+ self.mockLDAP([('uid', 'uu_u1')])
+
+ self._test('uu u1', [self.u1], [], [Clipper('uid', 'uu_u1')])
+
+ self.u1.profile.login_clipper = 'uid'
+ self.u1.profile.save()
+
+ self._test('uu u1', [self.u1], [], [])
diff --git a/shared/tests/testcases.py b/shared/tests/testcases.py
index 15792383..03e63e6b 100644
--- a/shared/tests/testcases.py
+++ b/shared/tests/testcases.py
@@ -92,6 +92,38 @@ class TestCaseMixin:
else:
self.assertEqual(actual, expected)
+ def mockLDAP(self, results):
+ class Elt:
+ def __init__(self, value):
+ self.value = value
+
+ class Entry:
+ def __init__(self, **kwargs):
+ for k, v in kwargs.items():
+ setattr(self, k, Elt(v))
+
+ results_as_ldap = [
+ Entry(uid=uid, cn=name) for uid, name in results
+ ]
+
+ mock_connection = mock.MagicMock()
+ mock_connection.entries = results_as_ldap
+
+ # Connection is used as a context manager.
+ mock_context_manager = mock.MagicMock()
+ mock_context_manager.return_value.__enter__.return_value = (
+ mock_connection
+ )
+
+ patcher = mock.patch(
+ 'gestioncof.autocomplete.Connection',
+ new=mock_context_manager,
+ )
+ patcher.start()
+ self.addCleanup(patcher.stop)
+
+ return mock_connection
+
class ViewTestCaseMixin(TestCaseMixin):
"""