mirror of
https://github.com/sismics/docs.git
synced 2024-11-22 05:57:57 +01:00
Users administration (client)
This commit is contained in:
parent
990884137b
commit
c48eb7a0fe
@ -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";
|
||||
}
|
||||
|
@ -1 +1 @@
|
||||
db.version=2
|
||||
db.version=3
|
@ -0,0 +1 @@
|
||||
insert into T_ROLE(ROL_ID_C, ROL_NAME_C, ROL_CREATEDATE_D) values('user', 'User', NOW());
|
@ -1 +1 @@
|
||||
- Users administration (client)
|
||||
- Users deletion with confirmation (client)
|
||||
|
@ -1,3 +1,3 @@
|
||||
api.current_version=${project.version}
|
||||
api.min_version=1.0
|
||||
db.version=2
|
||||
db.version=3
|
@ -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());
|
||||
|
@ -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',
|
||||
|
@ -4,10 +4,16 @@
|
||||
* Settings user page controller.
|
||||
*/
|
||||
App.controller('SettingsUser', function($scope, $state, Restangular) {
|
||||
// Load users from server
|
||||
/**
|
||||
* 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.
|
||||
|
@ -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');
|
||||
});
|
||||
};
|
||||
});
|
@ -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>
|
@ -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>
|
||||
|
@ -50,6 +50,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Users list
|
||||
.table-users {
|
||||
tbody tr {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
// Logs list
|
||||
.table-logs {
|
||||
tbody tr td {
|
||||
|
@ -1,3 +1,3 @@
|
||||
api.current_version=${project.version}
|
||||
api.min_version=1.0
|
||||
db.version=2
|
||||
db.version=3
|
@ -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));
|
||||
|
Loading…
Reference in New Issue
Block a user