Users administration (client)

This commit is contained in:
jendib 2013-08-09 00:21:11 +02:00
parent 990884137b
commit c48eb7a0fe
14 changed files with 153 additions and 32 deletions

View File

@ -39,5 +39,5 @@ public class Constants {
/**
* Default generic user role.
*/
public static final String DEFAULT_USER_ROLE = "admin";
public static final String DEFAULT_USER_ROLE = "user";
}

View File

@ -1 +1 @@
db.version=2
db.version=3

View File

@ -0,0 +1 @@
insert into T_ROLE(ROL_ID_C, ROL_NAME_C, ROL_CREATEDATE_D) values('user', 'User', NOW());

View File

@ -1 +1 @@
- Users administration (client)
- Users deletion with confirmation (client)

View File

@ -1,3 +1,3 @@
api.current_version=${project.version}
api.min_version=1.0
db.version=2
db.version=3

View File

@ -3,6 +3,7 @@ package com.sismics.docs.rest.resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import javax.servlet.http.Cookie;
import javax.ws.rs.DELETE;
@ -25,6 +26,7 @@ import org.codehaus.jettison.json.JSONObject;
import com.sismics.docs.core.constant.Constants;
import com.sismics.docs.core.dao.jpa.AuthenticationTokenDao;
import com.sismics.docs.core.dao.jpa.RoleBaseFunctionDao;
import com.sismics.docs.core.dao.jpa.UserDao;
import com.sismics.docs.core.dao.jpa.dto.UserDto;
import com.sismics.docs.core.model.jpa.AuthenticationToken;
@ -371,7 +373,9 @@ public class UserResource extends BaseResource {
}
// Ensure that the admin user is not deleted
// TODO Ensure it exists at least one user left
if (hasBaseFunction(BaseFunction.ADMIN)) {
throw new ClientException("ForbiddenError", "The admin user cannot be deleted");
}
// Delete the user
UserDao userDao = new UserDao();
@ -407,7 +411,11 @@ public class UserResource extends BaseResource {
}
// Ensure that the admin user is not deleted
// TODO Ensure it exists at least one user left
RoleBaseFunctionDao userBaseFuction = new RoleBaseFunctionDao();
Set<String> baseFunctionSet = userBaseFuction.findByRoleId(user.getRoleId());
if (baseFunctionSet.contains(BaseFunction.ADMIN.name())) {
throw new ClientException("ForbiddenError", "The admin user cannot be deleted");
}
// Delete the user
userDao.delete(user.getUsername());

View File

@ -85,7 +85,16 @@ var App = angular.module('docs', ['ui.state', 'ui.bootstrap', 'ui.route', 'ui.ke
}
})
.state('settings.user.edit', {
url: '/:username',
url: '/edit/:username',
views: {
'user': {
templateUrl: 'partial/settings.user.edit.html',
controller: 'SettingsUserEdit'
}
}
})
.state('settings.user.add', {
url: '/add',
views: {
'user': {
templateUrl: 'partial/settings.user.edit.html',

View File

@ -4,10 +4,16 @@
* Settings user page controller.
*/
App.controller('SettingsUser', function($scope, $state, Restangular) {
// Load users from server
Restangular.one('user/list').get({ limit: 100 }).then(function(data) {
$scope.users = data.users;
});
/**
* Load users from server.
*/
$scope.loadUsers = function() {
Restangular.one('user/list').get({ limit: 100 }).then(function(data) {
$scope.users = data.users;
});
};
$scope.loadUsers();
/**
* Edit a user.

View File

@ -3,6 +3,39 @@
/**
* Settings user edition page controller.
*/
App.controller('SettingsUserEdit', function($scope, $stateParams, Restangular) {
$scope.user = Restangular.one('user', $stateParams.username).get();
App.controller('SettingsUserEdit', function($scope, $state, $stateParams, Restangular) {
/**
* Returns true if in edit mode (false in add mode).
*/
$scope.isEdit = function() {
return $stateParams.username;
};
/**
* In edit mode, load the current user.
*/
if ($scope.isEdit()) {
Restangular.one('user', $stateParams.username).get().then(function(data) {
$scope.user = data;
});
}
$scope.edit = function() {
var promise = null;
if ($scope.isEdit()) {
promise = Restangular
.one('user', $stateParams.username)
.post('', $scope.user);
} else {
promise = Restangular
.one('user')
.put($scope.user);
}
promise.then(function() {
$scope.loadUsers();
$state.transitionTo('settings.user');
});
};
});

View File

@ -1,13 +1,50 @@
<h2>{{ user.username }}</h2>
<dl class="dl-horizontal">
<dt>E-mail</dt>
<dd>{{ user.email }}</dd>
</dl>
<dl class="dl-horizontal">
<dt>Theme</dt>
<dd>{{ user.theme }}</dd>
</dl>
<dl class="dl-horizontal">
<dt>Locale</dt>
<dd>{{ user.locale }}</dd>
</dl>
<h2 ng-show="isEdit()">Edit <small>"{{ user.username }}"</small></h2>
<h2 ng-show="!isEdit()">Add <small>user</small></h2>
<form class="form-horizontal" name="editUserForm" novalidate>
<div class="control-group" ng-class="{ error: !editUserForm.username.$valid, success: editUserForm.username.$valid }">
<label class="control-label" for="inputUsername">Username</label>
<div class="controls">
<input name="username" type="text" id="inputUsername" required ng-disabled="isEdit()"
ng-minlength="3" ng-maxlength="50" placeholder="Username" ng-model="user.username" />
<span class="help-inline" ng-show="editUserForm.username.$error.required">Required</span>
<span class="help-inline" ng-show="editUserForm.username.$error.minlength">Too short</span>
<span class="help-inline" ng-show="editUserForm.username.$error.maxlength">Too long</span>
</div>
</div>
<div class="control-group" ng-class="{ error: !editUserForm.email.$valid, success: editUserForm.email.$valid }">
<label class="control-label" for="inputEmail">E-mail</label>
<div class="controls">
<input name="email" type="email" id="inputEmail" required
ng-minlength="3" ng-maxlength="50" placeholder="E-mail" ng-model="user.email" />
<span class="help-inline" ng-show="editUserForm.email.$error.required">Required</span>
<span class="help-inline" ng-show="editUserForm.email.$error.email">Must be a valid e-mail</span>
<span class="help-inline" ng-show="editUserForm.email.$error.minlength">Too short</span>
<span class="help-inline" ng-show="editUserForm.email.$error.maxlength">Too long</span>
</div>
</div>
<div class="control-group" ng-class="{ error: !editUserForm.password.$valid, success: editUserForm.password.$valid }">
<label class="control-label" for="inputPassword">Password</label>
<div class="controls">
<input name="password" type="password" id="inputPassword" ng-required="!isEdit()"
ng-minlength="8" ng-maxlength="50" placeholder="Password" ng-model="user.password" />
<span class="help-inline" ng-show="editUserForm.password.$error.required">Required</span>
<span class="help-inline" ng-show="editUserForm.password.$error.minlength">Too short</span>
<span class="help-inline" ng-show="editUserForm.password.$error.maxlength">Too long</span>
</div>
</div>
<div class="control-group" ng-class="{ error: !editUserForm.passwordconfirm.$valid, success: editUserForm.passwordconfirm.$valid }">
<label class="control-label" for="inputPasswordConfirm">Password (confirm)</label>
<div class="controls">
<input name="passwordconfirm" type="password" id="inputPasswordConfirm" ng-required="!isEdit()"
ui-validate="'$value == user.password'" ui-validate-watch="'user.password'"
placeholder="Password (confirm)" ng-model="user.passwordconfirm" />
<span class="help-inline" ng-show="editUserForm.passwordconfirm.$error.validator">Password and password confirmation must match</span>
</div>
</div>
<div class="form-actions">
<button type="submit" class="btn btn-primary" ng-click="edit()" ng-disabled="!editUserForm.$valid">
<span class="icon-pencil icon-white"></span> {{ isEdit() ? 'Edit' : 'Add' }}
</button>
</div>
</form>
<alert ng-repeat="alert in alerts" type="alert.type" close="closeAlert($index)">{{ alert.msg }}</alert>

View File

@ -1,9 +1,9 @@
<h1>Users <small>management</small></h1>
<h1>Users <small>management</small> <a class="btn btn-primary" href="#/settings/user/add">Add</a></h1>
<div class="container-fluid">
<div class="row-fluid">
<div class="span4 well">
<table class="table table-striped table-hover">
<table class="table table-striped table-hover table-users">
<thead>
<tr>
<th>Username</th>
@ -11,7 +11,7 @@
</tr>
</thead>
<tbody>
<tr ng-repeat="user in users" ng-click="editUser(user)">
<tr ng-repeat="user in users | orderBy: 'username'" ng-click="editUser(user)">
<td>{{ user.username }}</td>
<td>{{ user.create_date | date: 'yyyy-MM-dd' }}</td>
</tr>

View File

@ -50,6 +50,13 @@
}
}
// Users list
.table-users {
tbody tr {
cursor: pointer;
}
}
// Logs list
.table-logs {
tbody tr td {

View File

@ -1,3 +1,3 @@
api.current_version=${project.version}
api.min_version=1.0
db.version=2
db.version=3

View File

@ -238,7 +238,7 @@ public class TestUserResource extends BaseJerseyTest {
*/
@Test
public void testUserResourceAdmin() throws JSONException {
// Create admin_user1 user
// Create admin_user1 user
clientUtil.createUser("admin_user1");
// Login admin
@ -275,14 +275,34 @@ public class TestUserResource extends BaseJerseyTest {
userResource = resource().path("/user");
userResource.addFilter(new CookieAuthenticationFilter(adminAuthenticationToken));
postParams = new MultivaluedMapImpl();
postParams.add("email", " alice2@docs.com ");
postParams.add("email", " alice2@reader.com ");
postParams.add("theme", " default.less");
postParams.add("locale", " en ");
postParams.add("display_title_web", true);
postParams.add("display_title_mobile", false);
postParams.add("display_unread_web", false);
postParams.add("display_unread_mobile", false);
response = userResource.post(ClientResponse.class, postParams);
Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus()));
json = response.getEntity(JSONObject.class);
Assert.assertEquals("ok", json.getString("status"));
// User admin deletes himself: forbidden
userResource = resource().path("/user");
userResource.addFilter(new CookieAuthenticationFilter(adminAuthenticationToken));
response = userResource.delete(ClientResponse.class);
Assert.assertEquals(Status.BAD_REQUEST, Status.fromStatusCode(response.getStatus()));
json = response.getEntity(JSONObject.class);
Assert.assertEquals("ForbiddenError", json.getString("type"));
// User admin deletes himself: forbidden
userResource = resource().path("/user/admin");
userResource.addFilter(new CookieAuthenticationFilter(adminAuthenticationToken));
response = userResource.delete(ClientResponse.class);
Assert.assertEquals(Status.BAD_REQUEST, Status.fromStatusCode(response.getStatus()));
json = response.getEntity(JSONObject.class);
Assert.assertEquals("ForbiddenError", json.getString("type"));
// User admin deletes user admin_user1
userResource = resource().path("/user/admin_user1");
userResource.addFilter(new CookieAuthenticationFilter(adminAuthenticationToken));