Move password set views to the authentication app

Signed-off-by: Roberto Rosario <roberto.rosario.gonzalez@gmail.com>
This commit is contained in:
Roberto Rosario
2019-05-07 03:13:14 -04:00
parent 5e4518211f
commit f69fcbcc82
15 changed files with 214 additions and 190 deletions

View File

@@ -2,13 +2,17 @@ from __future__ import absolute_import, unicode_literals
import logging
from django.contrib.auth import get_user_model
from django.utils.translation import ugettext_lazy as _
from mayan.apps.common.apps import MayanAppConfig
from mayan.apps.common.menus import menu_user
from mayan.apps.common.menus import menu_multi_item, menu_object, menu_user
from mayan.apps.navigation.classes import Separator
from .links import link_logout, link_password_change
from .links import (
link_logout, link_password_change, link_user_multiple_set_password,
link_user_set_password
)
logger = logging.getLogger(__name__)
@@ -23,6 +27,17 @@ class AuthenticationApp(MayanAppConfig):
def ready(self):
super(AuthenticationApp, self).ready()
User = get_user_model()
menu_multi_item.bind_links(
links=(link_user_multiple_set_password,),
sources=('user_management:user_list',)
)
menu_object.bind_links(
links=(link_user_set_password,), sources=(User,)
)
menu_user.bind_links(
links=(
Separator(), link_password_change, link_logout

View File

@@ -3,8 +3,7 @@ from __future__ import unicode_literals
from django.utils.translation import ugettext_lazy as _
from mayan.apps.navigation.classes import Link
from .icons import icon_logout, icon_password_change
from mayan.apps.user_management.permissions import permission_user_edit
def has_usable_password_and_can_change_password(context):
@@ -18,11 +17,24 @@ def has_usable_password_and_can_change_password(context):
link_logout = Link(
html_extra_classes='non-ajax', icon_class=icon_logout,
html_extra_classes='non-ajax',
icon_class_path='mayan.apps.authentication.icons.icon_logout',
text=_('Logout'), view='authentication:logout_view'
)
link_password_change = Link(
condition=has_usable_password_and_can_change_password,
icon_class=icon_password_change, text=_('Change password'),
icon_class_path='mayan.apps.authentication.icons.icon_password_change',
text=_('Change password'),
view='authentication:password_change_view'
)
link_user_multiple_set_password = Link(
icon_class_path='mayan.apps.authentication.icons.icon_password_change',
permissions=(permission_user_edit,), text=_('Set password'),
view='authentication:user_multiple_set_password'
)
link_user_set_password = Link(
args='object.id',
icon_class_path='mayan.apps.authentication.icons.icon_password_change',
permissions=(permission_user_edit,),
text=_('Set password'), view='authentication:user_set_password',
)

View File

@@ -0,0 +1,22 @@
from __future__ import unicode_literals
class UserPasswordViewTestMixin(object):
def _request_test_user_password_set_view(self, password):
return self.post(
viewname='authentication:user_set_password',
kwargs={'pk': self.test_user.pk},
data={
'new_password1': password, 'new_password2': password
}
)
def _request_test_user_password_set_multiple_view(self, password):
return self.post(
viewname='authentication:user_multiple_set_password',
data={
'id_list': self.test_user.pk,
'new_password1': password,
'new_password2': password
}
)

View File

@@ -13,10 +13,14 @@ from django.utils.http import urlunquote_plus
from mayan.apps.common.tests import GenericViewTestCase
from mayan.apps.smart_settings.classes import Namespace
from mayan.apps.user_management.permissions import permission_user_edit
from mayan.apps.user_management.tests.mixins import UserTestMixin
from mayan.apps.user_management.tests.literals import TEST_USER_PASSWORD_EDITED
from ..settings import setting_maximum_session_length
from .literals import TEST_EMAIL_AUTHENTICATION_BACKEND
from .mixins import UserPasswordViewTestMixin
class CurrentUserViewTestCase(GenericViewTestCase):
@@ -256,3 +260,58 @@ class UserLoginTestCase(GenericViewTestCase):
)
self.assertEqual(response.redirect_chain, [(TEST_REDIRECT_URL, 302)])
class UserViewTestCase(UserTestMixin, UserPasswordViewTestMixin, GenericViewTestCase):
def test_user_set_password_view_no_access(self):
self._create_test_user()
password_hash = self.test_user.password
response = self._request_test_user_password_set_view(
password=TEST_USER_PASSWORD_EDITED
)
self.assertEqual(response.status_code, 404)
self.test_user.refresh_from_db()
self.assertEqual(self.test_user.password, password_hash)
def test_user_set_password_view_with_access(self):
self._create_test_user()
self.grant_access(obj=self.test_user, permission=permission_user_edit)
password_hash = self.test_user.password
response = self._request_test_user_password_set_view(
password=TEST_USER_PASSWORD_EDITED
)
self.assertEqual(response.status_code, 302)
self.test_user.refresh_from_db()
self.assertNotEqual(self.test_user.password, password_hash)
def test_user_multiple_set_password_view_no_access(self):
self._create_test_user()
password_hash = self.test_user.password
response = self._request_test_user_password_set_multiple_view(
password=TEST_USER_PASSWORD_EDITED
)
self.assertEqual(response.status_code, 404)
self.test_user.refresh_from_db()
self.assertEqual(self.test_user.password, password_hash)
def test_user_multiple_set_password_view_with_access(self):
self._create_test_user()
self.grant_access(obj=self.test_user, permission=permission_user_edit)
password_hash = self.test_user.password
response = self._request_test_user_password_set_multiple_view(
password=TEST_USER_PASSWORD_EDITED
)
self.assertEqual(response.status_code, 302)
self.test_user.refresh_from_db()
self.assertNotEqual(self.test_user.password, password_hash)

View File

@@ -6,7 +6,7 @@ from .views import (
MayanLoginView, MayanLogoutView, MayanPasswordChangeDoneView,
MayanPasswordChangeView, MayanPasswordResetCompleteView,
MayanPasswordResetConfirmView, MayanPasswordResetDoneView,
MayanPasswordResetView
MayanPasswordResetView, UserSetPasswordView
)
@@ -34,11 +34,20 @@ urlpatterns = [
name='password_reset_confirm_view'
),
url(
regex=r'^password/reset/done/$', view=MayanPasswordResetDoneView.as_view(),
regex=r'^password/reset/done/$',
view=MayanPasswordResetDoneView.as_view(),
name='password_reset_done_view'
),
url(
regex=r'^password/reset/$', view=MayanPasswordResetView.as_view(),
name='password_reset_view'
)
),
url(
regex=r'^users/(?P<pk>\d+)/set_password/$',
view=UserSetPasswordView.as_view(), name='user_set_password'
),
url(
regex=r'^users/multiple/set_password/$',
view=UserSetPasswordView.as_view(), name='user_multiple_set_password'
),
]

View File

@@ -1,22 +1,27 @@
from __future__ import absolute_import, unicode_literals
from django.contrib import messages
from django.contrib.auth import get_user_model
from django.contrib.auth.forms import SetPasswordForm
from django.contrib.auth.views import (
LoginView, LogoutView, PasswordChangeDoneView, PasswordChangeView,
PasswordResetCompleteView, PasswordResetConfirmView, PasswordResetDoneView,
PasswordResetView
)
from django.core.exceptions import PermissionDenied
from django.http import HttpResponseRedirect
from django.shortcuts import redirect
from django.urls import reverse, reverse_lazy
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ungettext, ugettext_lazy as _
from stronghold.views import StrongholdPublicMixin
import mayan
from mayan.apps.common.generics import MultipleObjectFormActionView
from mayan.apps.common.settings import (
setting_home_view, setting_project_title, setting_project_url
)
from mayan.apps.user_management.permissions import permission_user_edit
from .forms import EmailAuthenticationForm, UsernameAuthenticationForm
from .settings import setting_login_method, setting_maximum_session_length
@@ -131,3 +136,71 @@ class MayanPasswordResetView(StrongholdPublicMixin, PasswordResetView):
viewname='authentication:password_reset_done_view'
)
template_name = 'authentication/password_reset_form.html'
class UserSetPasswordView(MultipleObjectFormActionView):
form_class = SetPasswordForm
model = get_user_model()
object_permission = permission_user_edit
success_message = _('Password change request performed on %(count)d user')
success_message_plural = _(
'Password change request performed on %(count)d users'
)
def get_extra_context(self):
queryset = self.get_object_list()
result = {
'submit_label': _('Submit'),
'title': ungettext(
singular='Change user password',
plural='Change users passwords',
number=queryset.count()
)
}
if queryset.count() == 1:
result.update(
{
'object': queryset.first(),
'title': _('Change password for user: %s') % queryset.first()
}
)
return result
def get_form_extra_kwargs(self):
queryset = self.get_object_list()
result = {}
if queryset:
result['user'] = queryset.first()
return result
else:
raise PermissionDenied
def object_action(self, form, instance):
try:
if instance.is_superuser or instance.is_staff:
messages.error(
message=_(
'Super user and staff user password '
'reseting is not allowed, use the admin '
'interface for these cases.'
), request=self.request
)
else:
instance.set_password(form.cleaned_data['new_password1'])
instance.save()
messages.success(
message=_(
'Successful password reset for user: %s.'
) % instance, request=self.request
)
except Exception as exception:
messages.error(
message=_(
'Error reseting password for user "%(user)s": %(error)s'
) % {
'user': instance, 'error': exception
}, request=self.request
)