Merge pull request #2314 from FinnStutzenstein/Issue2137
new change password view (fixes #2137)
This commit is contained in:
commit
29f9203377
@ -124,7 +124,7 @@ def users_passwords_to_pdf(pdf):
|
|||||||
stylesheet['formfield']))
|
stylesheet['formfield']))
|
||||||
cell2.append(Paragraph(escape(user.username),
|
cell2.append(Paragraph(escape(user.username),
|
||||||
stylesheet['formfield_value']))
|
stylesheet['formfield_value']))
|
||||||
cell2.append(Paragraph("%s:" % _("Password"),
|
cell2.append(Paragraph("%s:" % _("Initial password"),
|
||||||
stylesheet['formfield']))
|
stylesheet['formfield']))
|
||||||
cell2.append(Paragraph(escape(user.default_password),
|
cell2.append(Paragraph(escape(user.default_password),
|
||||||
stylesheet['formfield_value']))
|
stylesheet['formfield_value']))
|
||||||
|
@ -92,6 +92,16 @@ angular.module('OpenSlidesApp.users.site', ['OpenSlidesApp.users'])
|
|||||||
url: '/password',
|
url: '/password',
|
||||||
controller: 'UserPasswordCtrl',
|
controller: 'UserPasswordCtrl',
|
||||||
})
|
})
|
||||||
|
.state('users.user.change-password', {
|
||||||
|
url: '/change-password/{id}',
|
||||||
|
controller: 'UserChangePasswordCtrl',
|
||||||
|
templateUrl: 'static/templates/users/user-change-password.html',
|
||||||
|
resolve: {
|
||||||
|
user: function(User, $stateParams) {
|
||||||
|
return User.find($stateParams.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
.state('users.user.import', {
|
.state('users.user.import', {
|
||||||
url: '/import',
|
url: '/import',
|
||||||
controller: 'UserImportCtrl',
|
controller: 'UserImportCtrl',
|
||||||
@ -229,6 +239,24 @@ angular.module('OpenSlidesApp.users.site', ['OpenSlidesApp.users'])
|
|||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
|
.factory('PasswordGenerator', [
|
||||||
|
function () {
|
||||||
|
return {
|
||||||
|
generate: function (length) {
|
||||||
|
if (!length) {
|
||||||
|
length = 8;
|
||||||
|
}
|
||||||
|
var chars = 'abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789',
|
||||||
|
pw = '';
|
||||||
|
for (var i = 0; i < length; ++i) {
|
||||||
|
pw += chars.charAt(Math.floor(Math.random() * chars.length));
|
||||||
|
}
|
||||||
|
return pw;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
// Service for generic assignment form (create and update)
|
// Service for generic assignment form (create and update)
|
||||||
.factory('UserForm', [
|
.factory('UserForm', [
|
||||||
'$http',
|
'$http',
|
||||||
@ -236,7 +264,8 @@ angular.module('OpenSlidesApp.users.site', ['OpenSlidesApp.users'])
|
|||||||
'Editor',
|
'Editor',
|
||||||
'Group',
|
'Group',
|
||||||
'Mediafile',
|
'Mediafile',
|
||||||
function ($http, gettextCatalog, Editor, Group, Mediafile) {
|
'PasswordGenerator',
|
||||||
|
function ($http, gettextCatalog, Editor, Group, Mediafile, PasswordGenerator) {
|
||||||
return {
|
return {
|
||||||
// ngDialog for user form
|
// ngDialog for user form
|
||||||
getDialog: function (user) {
|
getDialog: function (user) {
|
||||||
@ -318,22 +347,18 @@ angular.module('OpenSlidesApp.users.site', ['OpenSlidesApp.users'])
|
|||||||
key: 'default_password',
|
key: 'default_password',
|
||||||
type: 'input',
|
type: 'input',
|
||||||
templateOptions: {
|
templateOptions: {
|
||||||
label: gettextCatalog.getString('Default password'),
|
label: gettextCatalog.getString('Initial password'),
|
||||||
description: '',
|
description: gettextCatalog.getString('Initial password can not be changed.'),
|
||||||
addonRight: { text: 'Reset', class: 'fa fa-undo', onClick:
|
addonRight: {
|
||||||
function (options, scope) {
|
text: gettextCatalog.getString('Generate'),
|
||||||
$http.post(
|
class: 'fa fa-magic',
|
||||||
'/rest/users/user/' + scope.model.id + '/reset_password/',
|
onClick:function (options, scope) {
|
||||||
{'password': scope.model.default_password})
|
scope.$parent.model.default_password = PasswordGenerator.generate();
|
||||||
.then(function() {
|
|
||||||
options.templateOptions.description =
|
|
||||||
gettextCatalog.getString('Password successfully resetted to:') +
|
|
||||||
' ' + scope.model.default_password;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
hide: !hideOnCreateForm
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: 'comment',
|
key: 'comment',
|
||||||
type: 'input',
|
type: 'input',
|
||||||
@ -616,6 +641,39 @@ angular.module('OpenSlidesApp.users.site', ['OpenSlidesApp.users'])
|
|||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
|
.controller('UserChangePasswordCtrl', [
|
||||||
|
'$scope',
|
||||||
|
'$state',
|
||||||
|
'$http',
|
||||||
|
'User',
|
||||||
|
'user',
|
||||||
|
'gettextCatalog',
|
||||||
|
'PasswordGenerator',
|
||||||
|
function($scope, $state, $http, User, user, gettextCatalog, PasswordGenerator) {
|
||||||
|
User.bindOne(user.id, $scope, 'user');
|
||||||
|
$scope.alert={};
|
||||||
|
$scope.generatePassword = function () {
|
||||||
|
$scope.new_password = PasswordGenerator.generate();
|
||||||
|
};
|
||||||
|
$scope.save = function (user) {
|
||||||
|
if ($scope.new_password !== '') {
|
||||||
|
$http.post(
|
||||||
|
'/rest/users/user/' + user.id + '/reset_password/',
|
||||||
|
{'password': $scope.new_password}
|
||||||
|
).then(
|
||||||
|
function (success) {
|
||||||
|
$scope.alert = {type: 'success', msg: success.data.detail, show: true};
|
||||||
|
$scope.new_password = '';
|
||||||
|
},
|
||||||
|
function (error) {
|
||||||
|
$scope.alert = {type: 'danger', msg: error.data.detail, show: true};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
.controller('UserPasswordCtrl', [
|
.controller('UserPasswordCtrl', [
|
||||||
'$scope',
|
'$scope',
|
||||||
'$state',
|
'$state',
|
||||||
|
@ -0,0 +1,50 @@
|
|||||||
|
<div class="header">
|
||||||
|
<div class="title">
|
||||||
|
<div class="submenu">
|
||||||
|
<a ui-sref="users.user.list" class="btn btn-sm btn-default">
|
||||||
|
<i class="fa fa-angle-double-left fa-lg"></i>
|
||||||
|
<translate>Back to overview</translate>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<h1 translate>Change password for {{ user.get_short_name() }}</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="details">
|
||||||
|
<form name="userForm">
|
||||||
|
<h3 class="text-danger" style="margin-top: 0;">
|
||||||
|
<i class="fa fa-exclamation-triangle"></i>
|
||||||
|
<translate>You override the personally set password of</translate> {{ user.get_short_name() }}!
|
||||||
|
</h3>
|
||||||
|
<uib-alert ng-show="alert.show" type="{{ alert.type }}" ng-click="alert={}" close="alert={}">
|
||||||
|
{{ alert.msg }}
|
||||||
|
</uib-alert>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="inputOldPassword" translate>New password</label>
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="text"
|
||||||
|
ng-model="new_password"
|
||||||
|
class="form-control"
|
||||||
|
name="inputNewPassword"
|
||||||
|
required>
|
||||||
|
</input>
|
||||||
|
<div class="input-group-addon pointer" ng-click="generatePassword()">
|
||||||
|
<i class="fa fa-magic"></i>
|
||||||
|
<translate>Generate</translate>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="spacer-top">
|
||||||
|
<span uib-tooltip="{{ 'Initial password can not be changed.' | translate }}">
|
||||||
|
<i class="fa fa-info-circle"></i>
|
||||||
|
<translate>Initial password</translate>: {{ user.default_password }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button type="submit" ng-click="save(user)" class="btn btn-primary" translate>
|
||||||
|
Change password
|
||||||
|
</button>
|
||||||
|
<button ui-sref="users.user.list" class="btn btn-default" translate>
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
@ -199,6 +199,7 @@
|
|||||||
<div ng-if="user.number"> {{ user.number }} </div>
|
<div ng-if="user.number"> {{ user.number }} </div>
|
||||||
<div os-perms="users.can_manage" class="hoverActions" ng-class="{'hiddenDiv': !user.hover}">
|
<div os-perms="users.can_manage" class="hoverActions" ng-class="{'hiddenDiv': !user.hover}">
|
||||||
<a href="" ng-click="openDialog(user)" translate>Edit</a> |
|
<a href="" ng-click="openDialog(user)" translate>Edit</a> |
|
||||||
|
<a ui-sref="users.user.change-password({id: user.id})" translate>Change password</a> |
|
||||||
<a href="" class="text-danger"
|
<a href="" class="text-danger"
|
||||||
ng-bootbox-confirm="{{ 'Are you sure you want to delete this entry?' | translate }}<br>
|
ng-bootbox-confirm="{{ 'Are you sure you want to delete this entry?' | translate }}<br>
|
||||||
<b>{{ user.get_short_name() }}</b>"
|
<b>{{ user.get_short_name() }}</b>"
|
||||||
|
@ -161,11 +161,12 @@ class UserViewSet(ModelViewSet):
|
|||||||
View to reset the password using the requested password.
|
View to reset the password using the requested password.
|
||||||
"""
|
"""
|
||||||
user = self.get_object()
|
user = self.get_object()
|
||||||
if request.data.get('password'):
|
if isinstance(request.data.get('password'), str):
|
||||||
user.default_password = request.data['password']
|
user.set_password(request.data.get('password'))
|
||||||
user.set_password(user.default_password)
|
|
||||||
user.save()
|
user.save()
|
||||||
return Response({'detail': _('Password successfully reset.')})
|
return Response({'detail': _('Password successfully reset.')})
|
||||||
|
else:
|
||||||
|
raise ValidationError({'detail': 'Password has to be a string.'})
|
||||||
|
|
||||||
|
|
||||||
class GroupViewSetMetadata(SimpleMetadata):
|
class GroupViewSetMetadata(SimpleMetadata):
|
||||||
|
@ -4,6 +4,7 @@ from rest_framework.test import APIClient
|
|||||||
|
|
||||||
from openslides.core.config import config
|
from openslides.core.config import config
|
||||||
from openslides.users.models import Group, User
|
from openslides.users.models import Group, User
|
||||||
|
from openslides.users.serializers import UserFullSerializer
|
||||||
from openslides.utils.test import TestCase
|
from openslides.utils.test import TestCase
|
||||||
|
|
||||||
|
|
||||||
@ -172,17 +173,22 @@ class UserResetPassword(TestCase):
|
|||||||
self.assertTrue(User.objects.get(pk=user.pk).check_password(
|
self.assertTrue(User.objects.get(pk=user.pk).check_password(
|
||||||
'new_password_Yuuh8OoQueePahngohy3_new'))
|
'new_password_Yuuh8OoQueePahngohy3_new'))
|
||||||
|
|
||||||
def test_reset_to_default(self):
|
"""
|
||||||
|
Tests whether a random password is set as default and actual password
|
||||||
|
if no default password is provided.
|
||||||
|
"""
|
||||||
|
def test_set_random_initial_password(self):
|
||||||
admin_client = APIClient()
|
admin_client = APIClient()
|
||||||
admin_client.login(username='admin', password='admin')
|
admin_client.login(username='admin', password='admin')
|
||||||
user = User.objects.create(username='Test name ooMoa4ou4mohn2eo1ree')
|
|
||||||
user.default_password = 'new_password_Yuuh8OoQueePahngohy3'
|
serializer = UserFullSerializer()
|
||||||
|
user = serializer.create({'username': 'Test name 9gt043qwvnj2d0cr'})
|
||||||
user.save()
|
user.save()
|
||||||
response = admin_client.post(
|
|
||||||
reverse('user-reset-password', args=[user.pk]), {})
|
default_password = User.objects.get(pk=user.pk).default_password
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
self.assertIsNotNone(default_password)
|
||||||
self.assertTrue(User.objects.get(pk=user.pk).check_password(
|
self.assertEqual(len(default_password), 8)
|
||||||
'new_password_Yuuh8OoQueePahngohy3'))
|
self.assertTrue(User.objects.get(pk=user.pk).check_password(default_password))
|
||||||
|
|
||||||
|
|
||||||
class GroupMetadata(TestCase):
|
class GroupMetadata(TestCase):
|
||||||
|
Loading…
Reference in New Issue
Block a user