Project

General

Profile

0003-manager-add-a-change-email-action-on-users-fixes-197.patch

Benjamin Dauvergne, 04 December 2017 03:13 PM

Download (9.49 KB)

View differences:

Subject: [PATCH 3/3] manager: add a change email action on users (fixes
 #19716)

It's only visible for OU with the validate_emails flag.
 src/authentic2/a2_rbac/models.py     |  1 +
 src/authentic2/manager/forms.py      | 10 ++++++++-
 src/authentic2/manager/urls.py       |  6 ++++++
 src/authentic2/manager/user_views.py | 42 ++++++++++++++++++++++++++++++++----
 src/authentic2/settings.py           |  3 ++-
 tests/test_user_manager.py           | 30 ++++++++++++++++++++++++++
 6 files changed, 86 insertions(+), 6 deletions(-)
 create mode 100644 tests/test_user_manager.py
src/authentic2/a2_rbac/models.py
247 247
CHANGE_PASSWORD_OP = Operation(name=_('Change password'), slug='change_password')
248 248
RESET_PASSWORD_OP = Operation(name=_('Reset password'), slug='reset_password')
249 249
ACTIVATE_OP = Operation(name=_('Activate'), slug='activate')
250
CHANGE_EMAIL_OP = Operation(name=_('Change email'), slug='change_email')
src/authentic2/manager/forms.py
622 622

  
623 623
    class Meta:
624 624
        model = get_ou_model()
625
        fields = ('name', 'default', 'username_is_unique', 'email_is_unique')
625
        fields = ('name', 'default', 'username_is_unique', 'email_is_unique', 'validate_emails')
626 626

  
627 627

  
628 628
def get_role_form_class():
629 629
    if app_settings.ROLE_FORM_CLASS:
630 630
        return import_module_or_class(app_settings.ROLE_FORM_CLASS)
631 631
    return RoleEditForm
632

  
633

  
634
class UserChangeEmailForm(CssClass, forms.ModelForm):
635
    def save(self, *args, **kwargs):
636
        return self.instance
637

  
638
    class Meta:
639
        fields = ('email',)
src/authentic2/manager/urls.py
36 36
        url(r'^users/(?P<pk>\d+)/change-password/$',
37 37
            user_views.user_change_password,
38 38
            name='a2-manager-user-change-password'),
39
        url(r'^users/(?P<pk>\d+)/change-email/$',
40
            user_views.user_change_email,
41
            name='a2-manager-user-change-email'),
39 42
        # by uuid
40 43
        url(r'^users/uuid:(?P<slug>[a-z0-9]+)/$', user_views.user_detail,
41 44
            name='a2-manager-user-by-uuid-detail'),
......
47 50
        url(r'^users/uuid:(?P<slug>[a-z0-9]+)/change-password/$',
48 51
            user_views.user_change_password,
49 52
            name='a2-manager-user-by-uuid-change-password'),
53
        url(r'^users/uuid:(?P<slug>[a-z0-9]+)/change-email/$',
54
            user_views.user_change_email,
55
            name='a2-manager-user-by-uuid-change-email'),
50 56

  
51 57
        # Authentic2 roles
52 58
        url(r'^roles/$', role_views.listing,
src/authentic2/manager/user_views.py
16 16

  
17 17
from authentic2.constants import SWITCH_USER_SESSION_KEY
18 18
from authentic2.models import Attribute, PasswordReset
19
from authentic2.utils import switch_user, send_password_reset_mail, redirect
19
from authentic2.utils import switch_user, send_password_reset_mail, redirect, send_email_change_mail
20 20
from authentic2.a2_rbac.utils import get_default_ou
21 21
from authentic2 import hooks
22 22
from django_rbac.utils import get_role_model, get_role_parenting_model, get_ou_model
......
26 26
    BaseEditView, ActionMixin, OtherActionsMixin, Action, ExportMixin, \
27 27
    BaseSubTableView, HideOUColumnMixin, BaseDeleteView, BaseDetailView
28 28
from .tables import UserTable, UserRolesTable, OuUserRolesTable
29
from .forms import UserSearchForm, UserAddForm, UserEditForm, \
30
    UserChangePasswordForm, ChooseUserRoleForm, UserRoleSearchForm
29
from .forms import (UserSearchForm, UserAddForm, UserEditForm,
30
    UserChangePasswordForm, ChooseUserRoleForm, UserRoleSearchForm, UserChangeEmailForm)
31 31
from .resources import UserResource
32 32
from . import app_settings
33 33

  
......
164 164
                     permission='custom_user.change_password_user')
165 165
        if self.request.user.is_superuser:
166 166
            yield Action('switch_user', _('Impersonate this user'))
167
        if self.object.ou and self.object.ou.validate_emails:
168
            yield Action('change_email', _('Change user email'),
169
                         url_name='a2-manager-user-change-email',
170
                         permission='custom_user.change_email_user')
167 171

  
168 172
    def action_force_password_change(self, request, *args, **kwargs):
169 173
        PasswordReset.objects.get_or_create(user=self.object)
......
256 260
    template_name = 'authentic2/manager/user_edit.html'
257 261
    form_class = UserEditForm
258 262
    permissions = ['custom_user.change_user']
259
    fields = ['username', 'ou', 'first_name', 'last_name', 'email']
263
    fields = ['username', 'ou', 'first_name', 'last_name']
260 264
    success_url = '..'
261 265
    slug_field = 'uuid'
262 266
    action = _('Change')
......
264 268

  
265 269
    def get_fields(self):
266 270
        fields = list(self.fields)
271
        if not self.object.ou or not self.object.ou.validate_emails:
272
            fields.append('email')
267 273
        for attribute in Attribute.objects.all():
268 274
            fields.append(attribute.name)
269 275
        if self.request.user.is_superuser and \
......
325 331
user_change_password = UserChangePasswordView.as_view()
326 332

  
327 333

  
334
class UserChangeEmailView(BaseEditView):
335
    template_name = 'authentic2/manager/form.html'
336
    model = get_user_model()
337
    form_class = UserChangeEmailForm
338
    permissions = ['custom_user.change_email_user']
339
    success_url = '..'
340
    slug_field = 'uuid'
341
    title = _('Change user email')
342

  
343
    def get_success_message(self, cleaned_data):
344
        return ugettext('A mail was sent to %s to verify it.') % cleaned_data['email']
345

  
346
    def get_form_kwargs(self):
347
        kwargs = super(UserChangeEmailView, self).get_form_kwargs()
348
        kwargs.setdefault('initial', {})['email'] = self.object.email
349
        return kwargs
350

  
351
    def form_valid(self, form):
352
        response = super(UserChangeEmailView, self).form_valid(form)
353
        email = form.cleaned_data['email']
354
        hooks.call_hooks('event', name='manager-change-email-request', user=self.request.user,
355
                         instance=form.instance, form=form, email=email)
356
        send_email_change_mail(self.object, email, request=self.request)
357
        return response
358

  
359
user_change_email = UserChangeEmailView.as_view()
360

  
361

  
328 362
class UserRolesView(HideOUColumnMixin, BaseSubTableView):
329 363
    model = get_user_model()
330 364
    form_class = ChooseUserRoleForm
src/authentic2/settings.py
299 299
DJANGO_RBAC_PERMISSIONS_HIERARCHY = {
300 300
    'view': ['search'],
301 301
    'change_password': ['view', 'search'],
302
    'change_email': ['view', 'search'],
302 303
    'reset_password': ['view', 'search'],
303 304
    'activate': ['view', 'search'],
304 305
    'admin': ['change', 'delete', 'add', 'view', 'change_password', 'reset_password', 'activate',
305
              'search'],
306
              'search', 'change_email'],
306 307
    'change': ['view', 'search'],
307 308
    'delete': ['view', 'search'],
308 309
    'add': ['view', 'search'],
tests/test_user_manager.py
1
from django.core.urlresolvers import reverse
2

  
3
from utils import login, get_link_from_mail
4

  
5

  
6
def test_manager_user_change_email(app, superuser_or_admin, simple_user, mailoutbox):
7
    response = login(app, superuser_or_admin,
8
                     reverse('a2-manager-user-by-uuid-detail',
9
                             kwargs={'slug': unicode(simple_user.uuid)}))
10
    assert 'Change user email' in response.content
11
    # cannot click it's a submit button :/
12
    response = app.get(reverse('a2-manager-user-by-uuid-change-email',
13
                               kwargs={'slug': unicode(simple_user.uuid)}))
14
    response.form.set('email', 'john.doe@example.com')
15
    assert len(mailoutbox) == 0
16
    response = response.form.submit().follow()
17
    assert 'A mail was sent to john.doe@example.com to verify it.' in response.content
18
    assert 'Change user email' in response.content
19
    # cannot click it's a submit button :/
20
    assert len(mailoutbox) == 1
21
    # logout
22
    app.session.flush()
23

  
24
    link = get_link_from_mail(mailoutbox[0])
25
    response = app.get(link).maybe_follow()
26
    assert (
27
        'your request for changing your email for john.doe@example.com is successful'
28
        in response.content)
29
    simple_user.refresh_from_db()
30
    assert simple_user.email == 'john.doe@example.com'
0
-