From 9080e05e4d2625d713271352b6b3632877164964 Mon Sep 17 00:00:00 2001
From: Paul Marillonnet <pmarillonnet@entrouvert.com>
Date: Tue, 26 Feb 2019 15:56:06 +0100
Subject: [PATCH] manager: add settings for password section options on user
 add (#25666)

---
 src/authentic2/a2_rbac/admin.py               |  3 ++-
 ...nizationalunit_user_add_password_policy.py | 19 +++++++++++++++
 src/authentic2/a2_rbac/models.py              | 24 +++++++++++++++++++
 src/authentic2/manager/user_views.py          | 15 ++++++++++++
 tests/test_manager.py                         | 14 +++++++++++
 5 files changed, 74 insertions(+), 1 deletion(-)
 create mode 100644 src/authentic2/a2_rbac/migrations/0018_organizationalunit_user_add_password_policy.py

diff --git a/src/authentic2/a2_rbac/admin.py b/src/authentic2/a2_rbac/admin.py
index fbabc73c..723d44a3 100644
--- a/src/authentic2/a2_rbac/admin.py
+++ b/src/authentic2/a2_rbac/admin.py
@@ -43,7 +43,8 @@ class RoleAdmin(admin.ModelAdmin):
 
 class OrganizationalUnitAdmin(admin.ModelAdmin):
     fields = ('uuid', 'name', 'slug', 'description', 'username_is_unique',
-              'email_is_unique', 'default', 'validate_emails')
+              'email_is_unique', 'default', 'validate_emails',
+              'user_add_password_policy')
     readonly_fields = ('uuid',)
     prepopulated_fields = {"slug": ("name",)}
     list_display = ('name', 'slug')
diff --git a/src/authentic2/a2_rbac/migrations/0018_organizationalunit_user_add_password_policy.py b/src/authentic2/a2_rbac/migrations/0018_organizationalunit_user_add_password_policy.py
new file mode 100644
index 00000000..72285beb
--- /dev/null
+++ b/src/authentic2/a2_rbac/migrations/0018_organizationalunit_user_add_password_policy.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('a2_rbac', '0017_organizationalunit_user_can_reset_password'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='organizationalunit',
+            name='user_add_password_policy',
+            field=models.IntegerField(default=0, verbose_name='User creation password policy', choices=[(0, 'Send reset link'), (1, 'Manual password definition')]),
+        ),
+    ]
diff --git a/src/authentic2/a2_rbac/models.py b/src/authentic2/a2_rbac/models.py
index d6614b98..d8761928 100644
--- a/src/authentic2/a2_rbac/models.py
+++ b/src/authentic2/a2_rbac/models.py
@@ -1,3 +1,4 @@
+from collections import namedtuple
 from django.core.exceptions import ValidationError
 from django.utils.translation import ugettext_lazy as _
 from django.utils.text import slugify
@@ -24,6 +25,24 @@ from . import managers, fields
 
 
 class OrganizationalUnit(OrganizationalUnitAbstractBase):
+
+    RESET_LINK_POLICY = 0
+    MANUAL_PASSWORD_POLICY = 1
+
+    USER_ADD_PASSWD_POLICY_CHOICES = (
+            (RESET_LINK_POLICY, _('Send reset link')),
+            (MANUAL_PASSWORD_POLICY, _('Manual password definition')),
+    )
+
+    PolicyValue = namedtuple('PolicyValue', [
+            'generate_password', 'reset_password_at_next_login',
+            'send_mal', 'send_password_reset'])
+
+    USER_ADD_PASSWD_POLICY_VALUES = {
+            RESET_LINK_POLICY: PolicyValue(False, False, False, True),
+            MANUAL_PASSWORD_POLICY: PolicyValue(False, False, True, False),
+    }
+
     username_is_unique = models.BooleanField(
         blank=True,
         default=False,
@@ -47,6 +66,11 @@ class OrganizationalUnit(OrganizationalUnitAbstractBase):
     user_can_reset_password = models.NullBooleanField(
         verbose_name=_('Users can reset password'))
 
+    user_add_password_policy = models.IntegerField(
+        verbose_name=_('User creation password policy'),
+        choices=USER_ADD_PASSWD_POLICY_CHOICES,
+        default=0)
+
     objects = managers.OrganizationalUnitManager()
 
     class Meta:
diff --git a/src/authentic2/manager/user_views.py b/src/authentic2/manager/user_views.py
index c94b46d0..bd8c12d9 100644
--- a/src/authentic2/manager/user_views.py
+++ b/src/authentic2/manager/user_views.py
@@ -150,6 +150,21 @@ class UserAddView(BaseAddView):
                          instance=form.instance, form=form)
         return response
 
+    def get_initial(self, *args, **kwargs):
+        initial = super(UserAddView, self).get_initial(*args, **kwargs)
+        initial.update(self.get_user_add_policies())
+        return initial
+
+    def get_user_add_policies(self, *args, **kwargs):
+        options = ('generate_password', 'reset_password_at_next_login',
+            'send_mail', 'send_password_reset',)
+        ou_id = self.request.get_full_path().rsplit('/', 3)[1]
+        ou = get_ou_model().objects.get(id=ou_id)
+        value = ou.user_add_password_policy
+
+        return dict(zip(options, get_ou_model().USER_ADD_PASSWD_POLICY_VALUES[value]))
+
+
 user_add = UserAddView.as_view()
 
 
diff --git a/tests/test_manager.py b/tests/test_manager.py
index 9bcdc8ea..0fcac72c 100644
--- a/tests/test_manager.py
+++ b/tests/test_manager.py
@@ -836,3 +836,17 @@ def test_roles_widget(admin, app, db):
     response = app.get(url, params={'field_id': field_id, 'term': 'Admin édou'})
     assert len(response.json['results']) == 1
     assert response.json['results'][0]['text'] == u'La Bédoule - Administrateur'
+
+
+def test_user_add_settings(settings, admin, app, db):
+    passwd_options = ('generate_password', 'reset_password_at_next_login',
+            'send_mail', 'send_password_reset')
+    for policy in [choice[0] for choice in get_ou_model().USER_ADD_PASSWD_POLICY_CHOICES]:
+        ou = get_default_ou()
+        ou.user_add_password_policy = policy
+        ou.save()
+        user_add = login(app, admin, '/manage/users/add/').follow()
+        for option, i in zip(passwd_options, range(4)):
+            assert user_add.form.get(option).value == {False:None, True:'on'}. \
+                    get(get_ou_model().USER_ADD_PASSWD_POLICY_VALUES[policy][i])
+        app.get('/logout/').form.submit()
-- 
2.20.1

