From 41ce00e708dd4db5980946900c8488935bcef05a 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 | 20 +++++++++++++++++++
 src/authentic2/a2_rbac/models.py              | 19 ++++++++++++++++++
 src/authentic2/manager/user_views.py          | 16 +++++++++++++++
 tests/test_manager.py                         | 17 ++++++++++++++++
 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..b3c7afb8
--- /dev/null
+++ b/src/authentic2/a2_rbac/migrations/0018_organizationalunit_user_add_password_policy.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.18 on 2019-02-27 14:28
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+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.CharField(choices=[(b'0', 'Send reset link'), (b'1', 'Manual password definition')], default=b'0', max_length=2, verbose_name='User creation password policy'),
+        ),
+    ]
diff --git a/src/authentic2/a2_rbac/models.py b/src/authentic2/a2_rbac/models.py
index d6614b98..d028ab74 100644
--- a/src/authentic2/a2_rbac/models.py
+++ b/src/authentic2/a2_rbac/models.py
@@ -23,6 +23,19 @@ from authentic2.decorators import GlobalCache
 from . import managers, fields
 
 
+USER_ADD_PASSWD_POLICY_CHOICES = (
+        ('0', _('Send reset link')),
+        ('1', _('Manual password definition')),
+)
+
+
+# Order: gen passwd, reset passwd at next login, send mail, send passwd reset
+USER_ADD_PASSWD_POLICY_VALUES = (
+        (False, False, False, True), # Send reset link
+        (False, False, True, False), # Manual password definition
+)
+
+
 class OrganizationalUnit(OrganizationalUnitAbstractBase):
     username_is_unique = models.BooleanField(
         blank=True,
@@ -47,6 +60,12 @@ class OrganizationalUnit(OrganizationalUnitAbstractBase):
     user_can_reset_password = models.NullBooleanField(
         verbose_name=_('Users can reset password'))
 
+    user_add_password_policy = models.CharField(
+        verbose_name=_('User creation password policy'),
+        choices=USER_ADD_PASSWD_POLICY_CHOICES,
+        default='0',
+        max_length=2)
+
     objects = managers.OrganizationalUnitManager()
 
     class Meta:
diff --git a/src/authentic2/manager/user_views.py b/src/authentic2/manager/user_views.py
index c94b46d0..7d5db569 100644
--- a/src/authentic2/manager/user_views.py
+++ b/src/authentic2/manager/user_views.py
@@ -150,6 +150,22 @@ 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):
+        from authentic2.a2_rbac.models import USER_ADD_PASSWD_POLICY_VALUES
+        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 = int(ou.user_add_password_policy)
+
+        return dict(zip(options, 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..4e2cabfb 100644
--- a/tests/test_manager.py
+++ b/tests/test_manager.py
@@ -836,3 +836,20 @@ 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):
+    from authentic2.a2_rbac.models import (USER_ADD_PASSWD_POLICY_VALUES,
+            USER_ADD_PASSWD_POLICY_CHOICES)
+    passwd_options = ('generate_password', 'reset_password_at_next_login',
+            'send_mail', 'send_password_reset')
+
+    for policy in [choice[0] for choice in 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(USER_ADD_PASSWD_POLICY_VALUES[int(policy)][i])
+        app.get('/logout/').form.submit()
-- 
2.20.1

