1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-08-02 20:35:25 +02:00

feat(global): introduce user teams and new UAC system (#868)

This commit is contained in:
Anthony Lapenna 2017-05-23 20:56:10 +02:00 committed by GitHub
parent a380fd9adc
commit 5523fc9023
160 changed files with 7112 additions and 3166 deletions

View file

@ -29,8 +29,8 @@
<tr>
<td colspan="2">
<span class="small text-muted">
You can select which user can access this endpoint by moving them to the authorized users table. Simply click
on a user entry to move it from one table to the other.
You can select which user or team can access this endpoint by moving them to the authorized accesses table. Simply click
on a user or team entry to move it from one table to the other.
</span>
</td>
</tr>
@ -44,10 +44,10 @@
<div class="row" ng-if="endpoint">
<div class="col-sm-6">
<rd-widget>
<rd-widget-header classes="col-sm-12 col-md-6 nopadding" icon="fa-users" title="Users">
<rd-widget-header classes="col-sm-12 col-md-6 nopadding" icon="fa-users" title="Users and groups">
<div class="pull-md-right pull-lg-right">
Items per page:
<select ng-model="state.pagination_count_users" ng-change="changePaginationCountUsers()">
<select ng-model="state.pagination_count_accesses" ng-change="changePaginationCountAccesses()">
<option value="0">All</option>
<option value="10">10</option>
<option value="25">25</option>
@ -58,7 +58,7 @@
</rd-widget-header>
<rd-widget-taskbar classes="col-sm-12 nopadding">
<div class="col-sm-12 col-md-6 nopadding">
<button class="btn btn-primary btn-sm" ng-click="authorizeAllUsers()" ng-disabled="users.length === 0 || filteredUsers.length === 0"><i class="fa fa-user-plus space-right" aria-hidden="true"></i>Authorize all users</button>
<button class="btn btn-primary btn-sm" ng-click="authorizeAllAccesses()" ng-disabled="accesses.length === 0 || filteredUsers.length === 0"><i class="fa fa-user-plus space-right" aria-hidden="true"></i>Authorize all</button>
</div>
<div class="col-sm-12 col-md-6 nopadding">
<input type="text" id="filter" ng-model="state.filterUsers" placeholder="Filter..." class="form-control input-sm" />
@ -70,38 +70,38 @@
<thead>
<tr>
<th>
<a ui-sref="endpoint.access({id: endpoint.Id})" ng-click="orderUsers('Username')">
<a ui-sref="endpoint.access({id: endpoint.Id})" ng-click="orderAccesses('Name')">
Name
<span ng-show="sortTypeUsers == 'Username' && !sortReverseUsers" class="glyphicon glyphicon-chevron-down"></span>
<span ng-show="sortTypeUsers == 'Username' && sortReverseUsers" class="glyphicon glyphicon-chevron-up"></span>
<span ng-show="sortTypeAccesses == 'Name' && !sortReverseAccesses" class="glyphicon glyphicon-chevron-down"></span>
<span ng-show="sortTypeAccesses == 'Name' && sortReverseAccesses" class="glyphicon glyphicon-chevron-up"></span>
</a>
</th>
<th>
<a ui-sref="endpoint.access({id: endpoint.Id})" ng-click="orderUsers('Role')">
Role
<span ng-show="sortTypeUsers == 'Role' && !sortReverseUsers" class="glyphicon glyphicon-chevron-down"></span>
<span ng-show="sortTypeUsers == 'Role' && sortReverseUsers" class="glyphicon glyphicon-chevron-up"></span>
<a ui-sref="endpoint.access({id: endpoint.Id})" ng-click="orderAccesses('Type')">
Type
<span ng-show="sortTypeAccesses == 'Type' && !sortReverseAccesses" class="glyphicon glyphicon-chevron-down"></span>
<span ng-show="sortTypeAccesses == 'Type' && sortReverseAccesses" class="glyphicon glyphicon-chevron-up"></span>
</a>
</th>
</tr>
</thead>
<tbody>
<tr ng-click="authorizeUser(user)" class="interactive" dir-paginate="user in (state.filteredUsers = (users | filter:state.filterUsers | orderBy:sortTypeUsers:sortReverseUsers | itemsPerPage: state.pagination_count_users))">
<td>{{ user.Username }}</td>
<tr ng-click="authorizeAccess(user)" class="interactive" dir-paginate="user in accesses | filter:state.filterUsers | orderBy:sortTypeAccesses:sortReverseAccesses | itemsPerPage: state.pagination_count_accesses">
<td>{{ user.Name }}</td>
<td>
{{ user.RoleName }}
<i class="fa" ng-class="user.RoleId === 1 ? 'fa-user-circle-o' : 'fa-user'" aria-hidden="true" style="margin-left: 2px;"></i>
<i class="fa" ng-class="user.Type === 'user' ? 'fa-user' : 'fa-users'" aria-hidden="true" style="margin-right: 2px;"></i>
{{ user.Type }}
</td>
</tr>
<tr ng-if="!users">
<tr ng-if="!accesses">
<td colspan="2" class="text-center text-muted">Loading...</td>
</tr>
<tr ng-if="users.length === 0 || state.filteredUsers.length === 0">
<td colspan="2" class="text-center text-muted">No users.</td>
<tr ng-if="accesses.length === 0 || (accesses | filter:state.filterUsers | orderBy:sortTypeAccesses:sortReverseAccesses | itemsPerPage: state.pagination_count_accesses).length === 0">
<td colspan="2" class="text-center text-muted">No user or team available.</td>
</tr>
</tbody>
</table>
<div ng-if="users" class="pull-left pagination-controls">
<div ng-if="accesses" class="pull-left pagination-controls">
<dir-pagination-controls></dir-pagination-controls>
</div>
</div>
@ -110,10 +110,10 @@
</div>
<div class="col-sm-6">
<rd-widget>
<rd-widget-header classes="col-sm-12 col-md-6 nopadding" icon="fa-users" title="Authorized users">
<rd-widget-header classes="col-sm-12 col-md-6 nopadding" icon="fa-users" title="Authorized users and groups">
<div class="pull-md-right pull-lg-right">
Items per page:
<select ng-model="state.pagination_count_authorizedUsers" ng-change="changePaginationCountAuthorizedUsers()">
<select ng-model="state.pagination_count_authorizedAccesses" ng-change="changePaginationCountAuthorizedAccesses()">
<option value="0">All</option>
<option value="10">10</option>
<option value="25">25</option>
@ -124,7 +124,7 @@
</rd-widget-header>
<rd-widget-taskbar classes="col-sm-12 nopadding">
<div class="col-sm-12 col-md-6 nopadding">
<button class="btn btn-primary btn-sm" ng-click="unauthorizeAllUsers()" ng-disabled="authorizedUsers.length === 0 || filteredAuthorizedUsers.length === 0"><i class="fa fa-user-times space-right" aria-hidden="true"></i>Deny all users</button>
<button class="btn btn-primary btn-sm" ng-click="unauthorizeAllAccesses()" ng-disabled="authorizedAccesses.length === 0 || filteredAuthorizedUsers.length === 0"><i class="fa fa-user-times space-right" aria-hidden="true"></i>Deny all</button>
</div>
<div class="col-sm-12 col-md-6 nopadding">
<input type="text" id="filter" ng-model="state.filterAuthorizedUsers" placeholder="Filter..." class="form-control input-sm" />
@ -136,39 +136,39 @@
<thead>
<tr>
<th>
<a ui-sref="endpoint.access({id: endpoint.Id})" ng-click="orderAuthorizedUsers('Username')">
<a ui-sref="endpoint.access({id: endpoint.Id})" ng-click="orderAuthorizedAccesses('Name')">
Name
<span ng-show="sortTypeAuthorizedUsers == 'Username' && !sortReverseAuthorizedUsers" class="glyphicon glyphicon-chevron-down"></span>
<span ng-show="sortTypeAuthorizedUsers == 'Username' && sortReverseAuthorizedUsers" class="glyphicon glyphicon-chevron-up"></span>
<span ng-show="sortTypeAuthorizedAccesses == 'Name' && !sortReverseAuthorizedAccesses" class="glyphicon glyphicon-chevron-down"></span>
<span ng-show="sortTypeAuthorizedAccesses == 'Name' && sortReverseAuthorizedAccesses" class="glyphicon glyphicon-chevron-up"></span>
</a>
</th>
<th>
<a ui-sref="endpoint.access({id: endpoint.Id})" ng-click="orderAuthorizedUsers('Role')">
Role
<span ng-show="sortTypeAuthorizedUsers == 'Role' && !sortReverseAuthorizedUsers" class="glyphicon glyphicon-chevron-down"></span>
<span ng-show="sortTypeAuthorizedUsers == 'Role' && sortReverseAuthorizedUsers" class="glyphicon glyphicon-chevron-up"></span>
<a ui-sref="endpoint.access({id: endpoint.Id})" ng-click="orderAuthorizedAccesses('Type')">
Type
<span ng-show="sortTypeAuthorizedAccesses == 'Type' && !sortReverseAuthorizedAccesses" class="glyphicon glyphicon-chevron-down"></span>
<span ng-show="sortTypeAuthorizedAccesses == 'Type' && sortReverseAuthorizedAccesses" class="glyphicon glyphicon-chevron-up"></span>
</a>
</th>
</tr>
</thead>
<tbody>
<tr ng-click="unauthorizeUser(user)" class="interactive" dir-paginate="user in (state.filteredAuthorizedUsers = (authorizedUsers | filter:state.filterAuthorizedUsers | orderBy:sortTypeAuthorizedUsers:sortReverseAuthorizedUsers | itemsPerPage: state.pagination_count_authorizedUsers))">
<td>{{ user.Username }}</td>
<tr ng-click="unauthorizeAccess(user)" class="interactive" pagination-id="table_authaccess" dir-paginate="user in authorizedAccesses | filter:state.filterAuthorizedUsers | orderBy:sortTypeAuthorizedAccesses:sortReverseAuthorizedAccesses | itemsPerPage: state.pagination_count_authorizedAccesses">
<td>{{ user.Name }}</td>
<td>
{{ user.RoleName }}
<i class="fa" ng-class="user.RoleId === 1 ? 'fa-user-circle-o' : 'fa-user'" aria-hidden="true" style="margin-left: 2px;"></i>
<i class="fa" ng-class="user.Type === 'user' ? 'fa-user' : 'fa-users'" aria-hidden="true" style="margin-right: 2px;"></i>
{{ user.Type }}
</td>
</tr>
<tr ng-if="!authorizedUsers">
<tr ng-if="!authorizedAccesses">
<td colspan="2" class="text-center text-muted">Loading...</td>
</tr>
<tr ng-if="authorizedUsers.length === 0 || state.filteredAuthorizedUsers.length === 0">
<td colspan="2" class="text-center text-muted">No authorized users.</td>
<tr ng-if="authorizedAccesses.length === 0 || (authorizedAccesses | filter:state.filterAuthorizedUsers | orderBy:sortTypeAuthorizedAccesses:sortReverseAuthorizedAccesses | itemsPerPage: state.pagination_count_authorizedAccesses).length === 0">
<td colspan="2" class="text-center text-muted">No authorized user or team.</td>
</tr>
</tbody>
</table>
<div ng-if="authorizedUsers" class="pull-left pagination-controls">
<dir-pagination-controls></dir-pagination-controls>
<div ng-if="authorizedAccesses" class="pull-left pagination-controls">
<dir-pagination-controls pagination-id="table_authaccess"></dir-pagination-controls>
</div>
</div>
</rd-widget-body>

View file

@ -1,148 +1,192 @@
angular.module('endpointAccess', [])
.controller('EndpointAccessController', ['$q', '$scope', '$state', '$stateParams', '$filter', 'EndpointService', 'UserService', 'Pagination', 'Notifications',
function ($q, $scope, $state, $stateParams, $filter, EndpointService, UserService, Pagination, Notifications) {
.controller('EndpointAccessController', ['$q', '$scope', '$state', '$stateParams', '$filter', 'EndpointService', 'UserService', 'TeamService', 'Pagination', 'Notifications',
function ($q, $scope, $state, $stateParams, $filter, EndpointService, UserService, TeamService, Pagination, Notifications) {
$scope.state = {
pagination_count_users: Pagination.getPaginationCount('endpoint_access_users'),
pagination_count_authorizedUsers: Pagination.getPaginationCount('endpoint_access_authorizedUsers')
pagination_count_accesses: Pagination.getPaginationCount('endpoint_access_accesses'),
pagination_count_authorizedAccesses: Pagination.getPaginationCount('endpoint_access_authorizedAccesses')
};
$scope.sortTypeUsers = 'Username';
$scope.sortReverseUsers = true;
$scope.sortTypeAccesses = 'Type';
$scope.sortReverseAccesses = false;
$scope.orderUsers = function(sortType) {
$scope.sortReverseUsers = ($scope.sortTypeUsers === sortType) ? !$scope.sortReverseUsers : false;
$scope.sortTypeUsers = sortType;
$scope.orderAccesses = function(sortType) {
$scope.sortReverseAccesses = ($scope.sortTypeAccesses === sortType) ? !$scope.sortReverseAccesses : false;
$scope.sortTypeAccesses = sortType;
};
$scope.changePaginationCountUsers = function() {
Pagination.setPaginationCount('endpoint_access_users', $scope.state.pagination_count_users);
$scope.changePaginationCountAccesses = function() {
Pagination.setPaginationCount('endpoint_access_accesses', $scope.state.pagination_count_accesses);
};
$scope.sortTypeAuthorizedUsers = 'Username';
$scope.sortReverseAuthorizedUsers = true;
$scope.sortTypeAuthorizedAccesses = 'Type';
$scope.sortReverseAuthorizedAccesses = false;
$scope.orderAuthorizedUsers = function(sortType) {
$scope.sortReverseAuthorizedUsers = ($scope.sortTypeAuthorizedUsers === sortType) ? !$scope.sortReverseAuthorizedUsers : false;
$scope.sortTypeAuthorizedUsers = sortType;
$scope.orderAuthorizedAccesses = function(sortType) {
$scope.sortReverseAuthorizedAccesses = ($scope.sortTypeAuthorizedAccesses === sortType) ? !$scope.sortReverseAuthorizedAccesses : false;
$scope.sortTypeAuthorizedAccesses = sortType;
};
$scope.changePaginationCountAuthorizedUsers = function() {
Pagination.setPaginationCount('endpoint_access_authorizedUsers', $scope.state.pagination_count_authorizedUsers);
$scope.changePaginationCountAuthorizedAccesses = function() {
Pagination.setPaginationCount('endpoint_access_authorizedAccesses', $scope.state.pagination_count_authorizedAccesses);
};
$scope.authorizeAllUsers = function() {
var authorizedUserIDs = [];
angular.forEach($scope.authorizedUsers, function (user) {
authorizedUserIDs.push(user.Id);
});
angular.forEach($scope.users, function (user) {
authorizedUserIDs.push(user.Id);
});
EndpointService.updateAuthorizedUsers($stateParams.id, authorizedUserIDs)
.then(function success(data) {
$scope.authorizedUsers = $scope.authorizedUsers.concat($scope.users);
$scope.users = [];
Notifications.success('Access granted for all users');
})
.catch(function error(err) {
Notifications.error("Failure", err, "Unable to update endpoint permissions");
});
};
$scope.unauthorizeAllUsers = function() {
EndpointService.updateAuthorizedUsers($stateParams.id, [])
.then(function success(data) {
$scope.users = $scope.users.concat($scope.authorizedUsers);
$scope.authorizedUsers = [];
Notifications.success('Access removed for all users');
})
.catch(function error(err) {
Notifications.error("Failure", err, "Unable to update endpoint permissions");
});
};
$scope.authorizeUser = function(user) {
var authorizedUserIDs = [];
angular.forEach($scope.authorizedUsers, function (u) {
authorizedUserIDs.push(u.Id);
});
authorizedUserIDs.push(user.Id);
EndpointService.updateAuthorizedUsers($stateParams.id, authorizedUserIDs)
.then(function success(data) {
removeUserFromArray(user.Id, $scope.users);
$scope.authorizedUsers.push(user);
Notifications.success('Access granted for user', user.Username);
})
.catch(function error(err) {
Notifications.error("Failure", err, "Unable to update endpoint permissions");
});
};
$scope.unauthorizeUser = function(user) {
var authorizedUserIDs = $scope.authorizedUsers.filter(function (u) {
if (u.Id !== user.Id) {
return u;
$scope.authorizeAllAccesses = function() {
var authorizedUsers = [];
var authorizedTeams = [];
angular.forEach($scope.authorizedAccesses, function (a) {
if (a.Type === 'user') {
authorizedUsers.push(a.Id);
} else if (a.Type === 'team') {
authorizedTeams.push(a.Id);
}
}).map(function (u) {
return u.Id;
});
EndpointService.updateAuthorizedUsers($stateParams.id, authorizedUserIDs)
angular.forEach($scope.accesses, function (a) {
if (a.Type === 'user') {
authorizedUsers.push(a.Id);
} else if (a.Type === 'team') {
authorizedTeams.push(a.Id);
}
});
EndpointService.updateAccess($stateParams.id, authorizedUsers, authorizedTeams)
.then(function success(data) {
removeUserFromArray(user.Id, $scope.authorizedUsers);
$scope.users.push(user);
Notifications.success('Access removed for user', user.Username);
$scope.authorizedAccesses = $scope.authorizedAccesses.concat($scope.accesses);
$scope.accesses = [];
Notifications.success('Endpoint accesses successfully updated');
})
.catch(function error(err) {
Notifications.error("Failure", err, "Unable to update endpoint permissions");
Notifications.error('Failure', err, 'Unable to update endpoint accesses');
});
};
function getEndpointAndUsers(endpointID) {
$scope.unauthorizeAllAccesses = function() {
EndpointService.updateAccess($stateParams.id, [], [])
.then(function success(data) {
$scope.accesses = $scope.accesses.concat($scope.authorizedAccesses);
$scope.authorizedAccesses = [];
Notifications.success('Endpoint accesses successfully updated');
})
.catch(function error(err) {
Notifications.error('Failure', err, 'Unable to update endpoint accesses');
});
};
$scope.authorizeAccess = function(access) {
var authorizedUsers = [];
var authorizedTeams = [];
angular.forEach($scope.authorizedAccesses, function (a) {
if (a.Type === 'user') {
authorizedUsers.push(a.Id);
} else if (a.Type === 'team') {
authorizedTeams.push(a.Id);
}
});
if (access.Type === 'user') {
authorizedUsers.push(access.Id);
} else if (access.Type === 'team') {
authorizedTeams.push(access.Id);
}
EndpointService.updateAccess($stateParams.id, authorizedUsers, authorizedTeams)
.then(function success(data) {
removeAccessFromArray(access, $scope.accesses);
$scope.authorizedAccesses.push(access);
Notifications.success('Endpoint accesses successfully updated', access.Name);
})
.catch(function error(err) {
Notifications.error('Failure', err, 'Unable to update endpoint accesses');
});
};
$scope.unauthorizeAccess = function(access) {
var authorizedUsers = [];
var authorizedTeams = [];
angular.forEach($scope.authorizedAccesses, function (a) {
if (a.Type === 'user') {
authorizedUsers.push(a.Id);
} else if (a.Type === 'team') {
authorizedTeams.push(a.Id);
}
});
if (access.Type === 'user') {
_.remove(authorizedUsers, function(n) {
return n === access.Id;
});
} else if (access.Type === 'team') {
_.remove(authorizedTeams, function(n) {
return n === access.Id;
});
}
EndpointService.updateAccess($stateParams.id, authorizedUsers, authorizedTeams)
.then(function success(data) {
removeAccessFromArray(access, $scope.authorizedAccesses);
$scope.accesses.push(access);
Notifications.success('Endpoint accesses successfully updated', access.Name);
})
.catch(function error(err) {
Notifications.error('Failure', err, 'Unable to update endpoint accesses');
});
};
function initView() {
$('#loadingViewSpinner').show();
$q.all({
endpoint: EndpointService.endpoint($stateParams.id),
users: UserService.users(),
users: UserService.users(false),
teams: TeamService.teams()
})
.then(function success(data) {
$scope.endpoint = data.endpoint;
$scope.users = data.users.filter(function (user) {
if (user.Role !== 1) {
return user;
}
}).map(function (user) {
return new UserViewModel(user);
$scope.accesses = [];
var users = data.users.map(function (user) {
return new EndpointAccessUserViewModel(user);
});
$scope.authorizedUsers = [];
var teams = data.teams.map(function (team) {
return new EndpointAccessTeamViewModel(team);
});
$scope.accesses = $scope.accesses.concat(users, teams);
$scope.authorizedAccesses = [];
angular.forEach($scope.endpoint.AuthorizedUsers, function(userID) {
for (var i = 0, l = $scope.users.length; i < l; i++) {
if ($scope.users[i].Id === userID) {
$scope.authorizedUsers.push($scope.users[i]);
$scope.users.splice(i, 1);
for (var i = 0, l = $scope.accesses.length; i < l; i++) {
if ($scope.accesses[i].Type === 'user' && $scope.accesses[i].Id === userID) {
$scope.authorizedAccesses.push($scope.accesses[i]);
$scope.accesses.splice(i, 1);
return;
}
}
});
angular.forEach($scope.endpoint.AuthorizedTeams, function(teamID) {
for (var i = 0, l = $scope.accesses.length; i < l; i++) {
if ($scope.accesses[i].Type === 'team' && $scope.accesses[i].Id === teamID) {
$scope.authorizedAccesses.push($scope.accesses[i]);
$scope.accesses.splice(i, 1);
return;
}
}
});
})
.catch(function error(err) {
$scope.templates = [];
$scope.users = [];
$scope.authorizedUsers = [];
Notifications.error("Failure", err, "Unable to retrieve endpoint details");
$scope.accesses = [];
$scope.authorizedAccesses = [];
Notifications.error('Failure', err, 'Unable to retrieve endpoint details');
})
.finally(function final(){
$('#loadingViewSpinner').hide();
});
}
function removeUserFromArray(id, users) {
for (var i = 0, l = users.length; i < l; i++) {
if (users[i].Id === id) {
users.splice(i, 1);
function removeAccessFromArray(access, accesses) {
for (var i = 0, l = accesses.length; i < l; i++) {
if (access.Type === accesses[i].Type && access.Id === accesses[i].Id) {
accesses.splice(i, 1);
return;
}
}
}
getEndpointAndUsers($stateParams.id);
initView();
}]);