mirror of
https://github.com/portainer/portainer.git
synced 2025-08-08 15:25:22 +02:00
feat(api): rewrite access control management in Docker (#3337)
* feat(api): decorate Docker resource creation response with resource control * fix(api): fix a potential resource control conflict between stacks/volumes * feat(api): generate a default private resource control instead of admin only * fix(api): fix default RC value * fix(api): update RC authorizations check to support admin only flag * refactor(api): relocate access control related methods * fix(api): fix a potential conflict when fetching RC from database * refactor(api): refactor access control logic * refactor(api): remove the concept of DecoratedStack * feat(api): automatically remove RC when removing a Docker resource * refactor(api): update filter resource methods documentation * refactor(api): update proxy package structure * refactor(api): renamed proxy/misc package * feat(api): re-introduce ResourceControlDelete operation as admin restricted * refactor(api): relocate default endpoint authorizations * feat(api): migrate RBAC data * feat(app): ResourceControl management refactor * fix(api): fix access control issue on stack deletion and automatically delete RC * fix(api): fix stack filtering * fix(api): fix UpdateResourceControl operation checks * refactor(api): introduce a NewTransport builder method * refactor(api): inject endpoint in Docker transport * refactor(api): introduce Docker client into Docker transport * refactor(api): refactor http/proxy package * feat(api): inspect a Docker resource labels during access control validation * fix(api): only apply automatic resource control creation on success response * fix(api): fix stack access control check * fix(api): use StatusCreated instead of StatusOK for automatic resource control creation * fix(app): resource control fixes * fix(api): fix an issue preventing administrator to inspect a resource with a RC * refactor(api): remove useless error return * refactor(api): document DecorateStacks function * fix(api): fix invalid resource control type for container deletion * feat(api): support Docker system networks * feat(api): update Swagger docs * refactor(api): rename transport variable * refactor(api): rename transport variable * feat(networks): add system tag for system networks * feat(api): add support for resource control labels * feat(api): upgrade to DBVersion 22 * refactor(api): refactor access control management in Docker proxy * refactor(api): re-implement docker proxy taskListOperation * refactor(api): review parameters declaration * refactor(api): remove extra blank line * refactor(api): review method comments * fix(api): fix invalid ServerAddress property and review method visibility * feat(api): update error message * feat(api): update restrictedVolumeBrowserOperation method * refactor(api): refactor method parameters * refactor(api): minor refactor * refactor(api): change Azure transport visibility * refactor(api): update struct documentation * refactor(api): update struct documentation * feat(api): review restrictedResourceOperation method * refactor(api): remove unused authorization methods * feat(api): apply RBAC when enabled on stack operations * fix(api): fix invalid data migration procedure for DBVersion = 22 * fix(app): RC duplicate on private resource * feat(api): change Docker API version logic for libcompose/client factory * fix(api): update access denied error message to be Docker API compliant * fix(api): update volume browsing authorizations data migration * fix(api): fix an issue with access control in multi-node agent Swarm cluster
This commit is contained in:
parent
198e92c734
commit
19d4db13be
118 changed files with 3600 additions and 3020 deletions
|
@ -71,7 +71,7 @@
|
|||
</div>
|
||||
<!-- restricted-access -->
|
||||
<!-- authorized-teams -->
|
||||
<div class="form-group" ng-if="$ctrl.formData.AccessControlEnabled && $ctrl.formData.Ownership === 'restricted' && ($ctrl.isAdmin || (!$ctrl.isAdmin && $ctrl.availableTeams.length > 1))" >
|
||||
<div class="form-group" ng-if="$ctrl.formData.AccessControlEnabled && $ctrl.formData.Ownership === $ctrl.RCO.RESTRICTED && ($ctrl.isAdmin || (!$ctrl.isAdmin && $ctrl.availableTeams.length > 1))" >
|
||||
<div class="col-sm-12">
|
||||
<label for="group-access" class="control-label text-left">
|
||||
Authorized teams
|
||||
|
@ -97,7 +97,7 @@
|
|||
</div>
|
||||
<!-- !authorized-teams -->
|
||||
<!-- authorized-users -->
|
||||
<div class="form-group" ng-if="$ctrl.formData.AccessControlEnabled && $ctrl.formData.Ownership === 'restricted' && $ctrl.isAdmin">
|
||||
<div class="form-group" ng-if="$ctrl.formData.AccessControlEnabled && $ctrl.formData.Ownership === $ctrl.RCO.RESTRICTED && $ctrl.isAdmin">
|
||||
<div class="col-sm-12">
|
||||
<label for="group-access" class="control-label text-left">
|
||||
Authorized users
|
||||
|
|
|
@ -1,16 +1,19 @@
|
|||
import _ from 'lodash-es';
|
||||
import { ResourceControlOwnership as RCO } from 'Portainer/models/resourceControl/resourceControlOwnership';
|
||||
|
||||
angular.module('portainer.app')
|
||||
.controller('porAccessControlFormController', ['$q', 'UserService', 'TeamService', 'Notifications', 'Authentication', 'ResourceControlService',
|
||||
function ($q, UserService, TeamService, Notifications, Authentication, ResourceControlService) {
|
||||
var ctrl = this;
|
||||
|
||||
ctrl.RCO = RCO;
|
||||
|
||||
ctrl.availableTeams = [];
|
||||
ctrl.availableUsers = [];
|
||||
|
||||
function setOwnership(resourceControl, isAdmin) {
|
||||
if (isAdmin && resourceControl.Ownership === 'private') {
|
||||
ctrl.formData.Ownership = 'restricted';
|
||||
if (isAdmin && resourceControl.Ownership === RCO.PRIVATE) {
|
||||
ctrl.formData.Ownership = RCO.RESTRICTED;
|
||||
} else {
|
||||
ctrl.formData.Ownership = resourceControl.Ownership;
|
||||
}
|
||||
|
@ -37,7 +40,7 @@ function ($q, UserService, TeamService, Notifications, Authentication, ResourceC
|
|||
ctrl.isAdmin = isAdmin;
|
||||
|
||||
if (isAdmin) {
|
||||
ctrl.formData.Ownership = 'administrators';
|
||||
ctrl.formData.Ownership = ctrl.RCO.ADMINISTRATORS;
|
||||
}
|
||||
|
||||
$q.all({
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import { ResourceControlOwnership as RCO } from 'Portainer/models/resourceControl/resourceControlOwnership';
|
||||
|
||||
export function AccessControlFormData() {
|
||||
this.AccessControlEnabled = true;
|
||||
this.Ownership = 'private';
|
||||
this.Ownership = RCO.PRIVATE;
|
||||
this.AuthorizedUsers = [];
|
||||
this.AuthorizedTeams = [];
|
||||
}
|
||||
|
|
|
@ -9,6 +9,8 @@ angular.module('portainer.app').component('porAccessControlPanel', {
|
|||
// This component is usually displayed inside a resource-details view.
|
||||
// This variable specifies the type of the associated resource.
|
||||
// Accepted values: 'container', 'service' or 'volume'.
|
||||
resourceType: '<'
|
||||
resourceType: '<',
|
||||
// Allow to disable the Ownership edition based on non resource control data
|
||||
disableOwnershipChange: '<'
|
||||
}
|
||||
});
|
||||
|
|
|
@ -16,28 +16,28 @@
|
|||
</span>
|
||||
<span ng-if="$ctrl.resourceControl">
|
||||
{{ $ctrl.resourceControl.Ownership }}
|
||||
<portainer-tooltip ng-if="$ctrl.resourceControl.Ownership === 'public'" message="This resource can be managed by any user with access to this endpoint." position="bottom" style="margin-left: -3px;"></portainer-tooltip>
|
||||
<portainer-tooltip ng-if="$ctrl.resourceControl.Ownership === 'private'" message="Management of this resource is restricted to a single user." position="bottom" style="margin-left: -3px;"></portainer-tooltip>
|
||||
<portainer-tooltip ng-if="$ctrl.resourceControl.Ownership === 'restricted'" message="This resource can be managed by a restricted set of users and/or teams." position="bottom" style="margin-left: -3px;"></portainer-tooltip>
|
||||
<portainer-tooltip ng-if="$ctrl.resourceControl.Ownership === $ctrl.RCO.PUBLIC" message="This resource can be managed by any user with access to this endpoint." position="bottom" style="margin-left: -3px;"></portainer-tooltip>
|
||||
<portainer-tooltip ng-if="$ctrl.resourceControl.Ownership === $ctrl.RCO.PRIVATE" message="Management of this resource is restricted to a single user." position="bottom" style="margin-left: -3px;"></portainer-tooltip>
|
||||
<portainer-tooltip ng-if="$ctrl.resourceControl.Ownership === $ctrl.RCO.RESTRICTED" message="This resource can be managed by a restricted set of users and/or teams." position="bottom" style="margin-left: -3px;"></portainer-tooltip>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- !ownership -->
|
||||
<tr ng-if="$ctrl.resourceControl.Type === 2 && $ctrl.resourceType === 'container'">
|
||||
<tr ng-if="$ctrl.resourceControl.Type === $ctrl.RCTI.SERVICE && $ctrl.resourceType === $ctrl.RCTS.CONTAINER">
|
||||
<td colspan="2">
|
||||
<i class="fa fa-info-circle" aria-hidden="true" style="margin-right: 2px;"></i>
|
||||
Access control on this resource is inherited from the following service: <a ui-sref="docker.services.service({ id: $ctrl.resourceControl.ResourceId })">{{ $ctrl.resourceControl.ResourceId | truncate }}</a>
|
||||
<portainer-tooltip message="Access control applied on a service is also applied on each container of that service." position="bottom" style="margin-left: 2px;"></portainer-tooltip>
|
||||
</td>
|
||||
</tr>
|
||||
<tr ng-if="$ctrl.resourceControl.Type === 1 && $ctrl.resourceType === 'volume'">
|
||||
<tr ng-if="$ctrl.resourceControl.Type === $ctrl.RCTI.CONTAINER && $ctrl.resourceType === $ctrl.RCTS.VOLUME">
|
||||
<td colspan="2">
|
||||
<i class="fa fa-info-circle" aria-hidden="true" style="margin-right: 2px;"></i>
|
||||
Access control on this resource is inherited from the following container: <a ui-sref="docker.containers.container({ id: $ctrl.resourceControl.ResourceId })">{{ $ctrl.resourceControl.ResourceId | truncate }}</a>
|
||||
<portainer-tooltip message="Access control applied on a container created using a template is also applied on each volume associated to the container." position="bottom" style="margin-left: 2px;"></portainer-tooltip>
|
||||
</td>
|
||||
</tr>
|
||||
<tr ng-if="$ctrl.resourceControl.Type === 6 && $ctrl.resourceType !== 'stack'">
|
||||
<tr ng-if="$ctrl.resourceControl.Type === $ctrl.RCTI.STACK && $ctrl.resourceType !== $ctrl.RCTS.STACK">
|
||||
<td colspan="2">
|
||||
<i class="fa fa-info-circle" aria-hidden="true" style="margin-right: 2px;"></i>
|
||||
Access control on this resource is inherited from the following stack: {{ $ctrl.resourceControl.ResourceId }}
|
||||
|
@ -61,11 +61,7 @@
|
|||
</tr>
|
||||
<!-- !authorized-teams -->
|
||||
<!-- edit-ownership -->
|
||||
<tr ng-if="!($ctrl.resourceControl.Type === 1 && $ctrl.resourceType === 'volume')
|
||||
&& !($ctrl.resourceControl.Type === 2 && $ctrl.resourceType === 'container')
|
||||
&& !($ctrl.resourceControl.Type === 6 && $ctrl.resourceType !== 'stack')
|
||||
&& !$ctrl.state.editOwnership
|
||||
&& ($ctrl.isAdmin || $ctrl.state.canEditOwnership)">
|
||||
<tr ng-if="$ctrl.canEditOwnership();">
|
||||
<td colspan="2">
|
||||
<a ng-click="$ctrl.state.editOwnership = true"><i class="fa fa-edit space-right" aria-hidden="true"></i>Change ownership</a>
|
||||
</td>
|
||||
|
@ -76,7 +72,7 @@
|
|||
<td colspan="2" style="white-space: inherit;">
|
||||
<div class="boxselector_wrapper">
|
||||
<div ng-if="$ctrl.isAdmin">
|
||||
<input type="radio" id="access_administrators" ng-model="$ctrl.formValues.Ownership" value="administrators">
|
||||
<input type="radio" id="access_administrators" ng-model="$ctrl.formValues.Ownership" ng-value="$ctrl.RCO.ADMINISTRATORS">
|
||||
<label for="access_administrators">
|
||||
<div class="boxselector_header">
|
||||
<i ng-class="'administrators' | ownershipicon" aria-hidden="true" style="margin-right: 2px;"></i>
|
||||
|
@ -86,7 +82,7 @@
|
|||
</label>
|
||||
</div>
|
||||
<div ng-if="$ctrl.isAdmin">
|
||||
<input type="radio" id="access_restricted" ng-model="$ctrl.formValues.Ownership" value="restricted">
|
||||
<input type="radio" id="access_restricted" ng-model="$ctrl.formValues.Ownership" ng-value="$ctrl.RCO.RESTRICTED">
|
||||
<label for="access_restricted">
|
||||
<div class="boxselector_header">
|
||||
<i ng-class="'restricted' | ownershipicon" aria-hidden="true" style="margin-right: 2px;"></i>
|
||||
|
@ -98,7 +94,7 @@
|
|||
</label>
|
||||
</div>
|
||||
<div ng-if="!$ctrl.isAdmin && $ctrl.state.canChangeOwnershipToTeam && $ctrl.availableTeams.length > 0">
|
||||
<input type="radio" id="access_restricted" ng-model="$ctrl.formValues.Ownership" value="restricted">
|
||||
<input type="radio" id="access_restricted" ng-model="$ctrl.formValues.Ownership" ng-value="$ctrl.RCO.RESTRICTED">
|
||||
<label for="access_restricted">
|
||||
<div class="boxselector_header">
|
||||
<i ng-class="'restricted' | ownershipicon" aria-hidden="true" style="margin-right: 2px;"></i>
|
||||
|
@ -113,7 +109,7 @@
|
|||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" id="access_public" ng-model="$ctrl.formValues.Ownership" value="public">
|
||||
<input type="radio" id="access_public" ng-model="$ctrl.formValues.Ownership" ng-value="$ctrl.RCO.PUBLIC">
|
||||
<label for="access_public">
|
||||
<div class="boxselector_header">
|
||||
<i ng-class="'public' | ownershipicon" aria-hidden="true" style="margin-right: 2px;"></i>
|
||||
|
@ -127,7 +123,7 @@
|
|||
</tr>
|
||||
<!-- edit-ownership-choices -->
|
||||
<!-- select-teams -->
|
||||
<tr ng-if="$ctrl.state.editOwnership && $ctrl.formValues.Ownership === 'restricted' && ($ctrl.isAdmin || !$ctrl.isAdmin && $ctrl.availableTeams.length > 1)">
|
||||
<tr ng-if="$ctrl.state.editOwnership && $ctrl.formValues.Ownership === $ctrl.RCO.RESTRICTED && ($ctrl.isAdmin || !$ctrl.isAdmin && $ctrl.availableTeams.length > 1)">
|
||||
<td colspan="2">
|
||||
<span>Teams</span>
|
||||
<span ng-if="$ctrl.isAdmin && $ctrl.availableTeams.length === 0" class="small text-muted" style="margin-left: 10px;">
|
||||
|
@ -149,7 +145,7 @@
|
|||
</tr>
|
||||
<!-- !select-teams -->
|
||||
<!-- select-users -->
|
||||
<tr ng-if="$ctrl.isAdmin && $ctrl.state.editOwnership && $ctrl.formValues.Ownership === 'restricted'">
|
||||
<tr ng-if="$ctrl.isAdmin && $ctrl.state.editOwnership && $ctrl.formValues.Ownership === $ctrl.RCO.RESTRICTED">
|
||||
<td colspan="2">
|
||||
<span>Users</span>
|
||||
<span ng-if="$ctrl.availableUsers.length === 0" class="small text-muted" style="margin-left: 10px;">
|
||||
|
|
|
@ -1,11 +1,17 @@
|
|||
import _ from 'lodash-es';
|
||||
import { AccessControlPanelData } from './porAccessControlPanelModel';
|
||||
import { ResourceControlOwnership as RCO } from 'Portainer/models/resourceControl/resourceControlOwnership';
|
||||
import { ResourceControlTypeString as RCTS, ResourceControlTypeInt as RCTI} from 'Portainer/models/resourceControl/resourceControlTypes';
|
||||
|
||||
angular.module('portainer.app')
|
||||
.controller('porAccessControlPanelController', ['$q', '$state', 'UserService', 'TeamService', 'ResourceControlService', 'Notifications', 'Authentication', 'ModalService', 'FormValidator',
|
||||
function ($q, $state, UserService, TeamService, ResourceControlService, Notifications, Authentication, ModalService, FormValidator) {
|
||||
.controller('porAccessControlPanelController', ['$q', '$state', 'UserService', 'TeamService', 'ResourceControlHelper', 'ResourceControlService', 'Notifications', 'Authentication', 'ModalService', 'FormValidator',
|
||||
function ($q, $state, UserService, TeamService, ResourceControlHelper, ResourceControlService, Notifications, Authentication, ModalService, FormValidator) {
|
||||
|
||||
var ctrl = this;
|
||||
|
||||
ctrl.RCO = RCO;
|
||||
ctrl.RCTS = RCTS;
|
||||
ctrl.RCTI = RCTI;
|
||||
ctrl.state = {
|
||||
displayAccessControlPanel: false,
|
||||
canEditOwnership: false,
|
||||
|
@ -13,17 +19,24 @@ function ($q, $state, UserService, TeamService, ResourceControlService, Notifica
|
|||
formValidationError: ''
|
||||
};
|
||||
|
||||
ctrl.formValues = {
|
||||
Ownership: 'administrators',
|
||||
Ownership_Users: [],
|
||||
Ownership_Teams: []
|
||||
};
|
||||
ctrl.formValues = new AccessControlPanelData();
|
||||
|
||||
ctrl.authorizedUsers = [];
|
||||
ctrl.availableUsers = [];
|
||||
ctrl.authorizedTeams = [];
|
||||
ctrl.availableTeams = [];
|
||||
|
||||
ctrl.canEditOwnership = function() {
|
||||
const hasRC = ctrl.resourceControl;
|
||||
const inheritedVolume = hasRC && ctrl.resourceControl.Type === RCTI.CONTAINER && ctrl.resourceType === RCTS.VOLUME;
|
||||
const inheritedContainer = hasRC && ctrl.resourceControl.Type === RCTI.SERVICE && ctrl.resourceType === RCTS.CONTAINER;
|
||||
const inheritedFromStack = hasRC && ctrl.resourceControl.Type === RCTI.STACK && ctrl.resourceType !== RCTS.STACK;
|
||||
const hasSpecialDisable = ctrl.disableOwnershipChange;
|
||||
|
||||
return !inheritedVolume && !inheritedContainer && !inheritedFromStack && !hasSpecialDisable
|
||||
&& !ctrl.state.editOwnership && (ctrl.isAdmin || ctrl.state.canEditOwnership);
|
||||
}
|
||||
|
||||
ctrl.confirmUpdateOwnership = function () {
|
||||
if (!validateForm()) {
|
||||
return;
|
||||
|
@ -39,7 +52,7 @@ function ($q, $state, UserService, TeamService, ResourceControlService, Notifica
|
|||
var error = '';
|
||||
|
||||
var accessControlData = {
|
||||
AccessControlEnabled: ctrl.formValues.Ownership === 'public' ? false : true,
|
||||
AccessControlEnabled: ctrl.formValues.Ownership === RCO.PUBLIC ? false : true,
|
||||
Ownership: ctrl.formValues.Ownership,
|
||||
AuthorizedUsers: ctrl.formValues.Ownership_Users,
|
||||
AuthorizedTeams: ctrl.formValues.Ownership_Teams
|
||||
|
@ -53,32 +66,8 @@ function ($q, $state, UserService, TeamService, ResourceControlService, Notifica
|
|||
return true;
|
||||
}
|
||||
|
||||
function processOwnershipFormValues() {
|
||||
var userIds = [];
|
||||
angular.forEach(ctrl.formValues.Ownership_Users, function(user) {
|
||||
userIds.push(user.Id);
|
||||
});
|
||||
var teamIds = [];
|
||||
angular.forEach(ctrl.formValues.Ownership_Teams, function(team) {
|
||||
teamIds.push(team.Id);
|
||||
});
|
||||
|
||||
var publicOnly = ctrl.formValues.Ownership === 'public' ? true : false;
|
||||
|
||||
return {
|
||||
ownership: ctrl.formValues.Ownership,
|
||||
authorizedUserIds: publicOnly ? [] : userIds,
|
||||
authorizedTeamIds: publicOnly ? [] : teamIds,
|
||||
publicOnly: publicOnly
|
||||
};
|
||||
}
|
||||
|
||||
function updateOwnership() {
|
||||
var resourceId = ctrl.resourceId;
|
||||
var ownershipParameters = processOwnershipFormValues();
|
||||
|
||||
ResourceControlService.applyResourceControlChange(ctrl.resourceType, resourceId,
|
||||
ctrl.resourceControl, ownershipParameters)
|
||||
ResourceControlService.applyResourceControlChange(ctrl.resourceType, ctrl.resourceId, ctrl.resourceControl, ctrl.formValues)
|
||||
.then(function success() {
|
||||
Notifications.success('Access control successfully updated');
|
||||
$state.reload();
|
||||
|
@ -95,17 +84,12 @@ function ($q, $state, UserService, TeamService, ResourceControlService, Notifica
|
|||
ctrl.isAdmin = isAdmin;
|
||||
var resourceControl = ctrl.resourceControl;
|
||||
|
||||
if (isAdmin) {
|
||||
if (resourceControl) {
|
||||
ctrl.formValues.Ownership = resourceControl.Ownership === 'private' ? 'restricted' : resourceControl.Ownership;
|
||||
} else {
|
||||
ctrl.formValues.Ownership = 'administrators';
|
||||
}
|
||||
if (isAdmin && resourceControl) {
|
||||
ctrl.formValues.Ownership = resourceControl.Ownership === RCO.PRIVATE ? RCO.RESTRICTED : resourceControl.Ownership;
|
||||
} else {
|
||||
ctrl.formValues.Ownership = 'administrators';
|
||||
ctrl.formValues.Ownership = RCO.ADMINISTRATORS;
|
||||
}
|
||||
|
||||
|
||||
ResourceControlService.retrieveOwnershipDetails(resourceControl)
|
||||
.then(function success(data) {
|
||||
ctrl.authorizedUsers = data.authorizedUsers;
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
import { ResourceControlOwnership } from 'Portainer/models/resourceControl/resourceControlOwnership';
|
||||
|
||||
export function AccessControlPanelData() {
|
||||
this.Ownership = ResourceControlOwnership.ADMINISTRATORS;
|
||||
this.Ownership_Users = [];
|
||||
this.Ownership_Teams = [];
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
import _ from 'lodash-es';
|
||||
import './datatable.css';
|
||||
import { ResourceControlOwnership as RCO } from 'Portainer/models/resourceControl/resourceControlOwnership';
|
||||
|
||||
function isBetween(value, a, b) {
|
||||
return (value >= a && value <= b) || (value >= b && value <= a) ;
|
||||
|
@ -9,6 +10,8 @@ angular.module('portainer.app')
|
|||
.controller('GenericDatatableController', ['$interval', 'PaginationService', 'DatatableService', 'PAGINATION_MAX_ITEMS',
|
||||
function ($interval, PaginationService, DatatableService, PAGINATION_MAX_ITEMS) {
|
||||
|
||||
this.RCO = RCO;
|
||||
|
||||
this.state = {
|
||||
selectAll: false,
|
||||
orderBy: this.orderBy,
|
||||
|
|
|
@ -109,7 +109,7 @@
|
|||
<td ng-if="$ctrl.showOwnershipColumn">
|
||||
<span>
|
||||
<i ng-class="item.ResourceControl.Ownership | ownershipicon" aria-hidden="true"></i>
|
||||
{{ item.ResourceControl.Ownership ? item.ResourceControl.Ownership : item.ResourceControl.Ownership = 'administrators' }}
|
||||
{{ item.ResourceControl.Ownership ? item.ResourceControl.Ownership : item.ResourceControl.Ownership = $ctrl.RCO.ADMINISTRATORS }}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
|
|
|
@ -2,6 +2,8 @@ import moment from 'moment';
|
|||
import _ from 'lodash-es';
|
||||
import filesize from 'filesize';
|
||||
|
||||
import { ResourceControlOwnership as RCO } from 'Portainer/models/resourceControl/resourceControlOwnership';
|
||||
|
||||
angular.module('portainer.app')
|
||||
.filter('truncate', function () {
|
||||
'use strict';
|
||||
|
@ -145,11 +147,11 @@ angular.module('portainer.app')
|
|||
'use strict';
|
||||
return function (ownership) {
|
||||
switch (ownership) {
|
||||
case 'private':
|
||||
case RCO.PRIVATE:
|
||||
return 'fa fa-eye-slash';
|
||||
case 'administrators':
|
||||
case RCO.ADMINISTRATORS:
|
||||
return 'fa fa-eye-slash';
|
||||
case 'restricted':
|
||||
case RCO.RESTRICTED:
|
||||
return 'fa fa-users';
|
||||
default:
|
||||
return 'fa fa-eye';
|
||||
|
|
15
app/portainer/helpers/networkHelper.js
Normal file
15
app/portainer/helpers/networkHelper.js
Normal file
|
@ -0,0 +1,15 @@
|
|||
import _ from 'lodash-es';
|
||||
import angular from 'angular';
|
||||
|
||||
class NetworkHelper {
|
||||
constructor(PREDEFINED_NETWORKS) {
|
||||
this.PREDEFINED_NETWORKS = PREDEFINED_NETWORKS;
|
||||
}
|
||||
|
||||
isSystemNetwork(item) {
|
||||
return _.includes(this.PREDEFINED_NETWORKS, item.Name);
|
||||
}
|
||||
}
|
||||
|
||||
export default NetworkHelper;
|
||||
angular.module('portainer.app').service('NetworkHelper', NetworkHelper);
|
|
@ -1,44 +1,121 @@
|
|||
import _ from 'lodash-es';
|
||||
import angular from 'angular';
|
||||
import { ResourceControlOwnership as RCO } from 'Portainer/models/resourceControl/resourceControlOwnership';
|
||||
import { ResourceControlOwnershipParameters } from '../models/resourceControl/resourceControlOwnershipParameters';
|
||||
|
||||
angular.module('portainer.app')
|
||||
.factory('ResourceControlHelper', [function ResourceControlHelperFactory() {
|
||||
'use strict';
|
||||
var helper = {};
|
||||
class ResourceControlHelper {
|
||||
|
||||
helper.retrieveAuthorizedUsers = function(resourceControl, users) {
|
||||
var authorizedUsers = [];
|
||||
angular.forEach(resourceControl.UserAccesses, function(access) {
|
||||
var user = _.find(users, { Id: access.UserId });
|
||||
/**
|
||||
* Transform ResourceControlViewModel to ResourceControlOwnershipParameters
|
||||
* @param {int} userId ID of User performing the action
|
||||
* @param {ResourceControlViewModel} resourceControl ResourceControl view model
|
||||
*/
|
||||
RCViewModelToOwnershipParameters(userId, resourceControl) {
|
||||
if (!resourceControl) {
|
||||
return new ResourceControlOwnershipParameters(true);
|
||||
}
|
||||
let adminOnly = false;
|
||||
let publicOnly = false;
|
||||
let users = [];
|
||||
let teams = [];
|
||||
switch (resourceControl.Ownership) {
|
||||
case RCO.PUBLIC:
|
||||
publicOnly = true;
|
||||
break;
|
||||
case RCO.PRIVATE:
|
||||
users = [userId];
|
||||
break;
|
||||
case RCO.RESTRICTED:
|
||||
users = _.map(resourceControl.UserAccesses, (user) => user.UserId);
|
||||
teams = _.map(resourceControl.TeamAccesses, (team) => team.TeamId);
|
||||
break;
|
||||
default:
|
||||
adminOnly = true;
|
||||
break;
|
||||
}
|
||||
return new ResourceControlOwnershipParameters(adminOnly, publicOnly, users, teams);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform AccessControlFormData to ResourceControlOwnershipParameters
|
||||
* @param {int} userId ID of user performing the operation
|
||||
* @param {AccessControlFormData} formValues Form data (generated by AccessControlForm)
|
||||
* @param {int[]} subResources Sub Resources restricted by the ResourceControl
|
||||
*/
|
||||
RCFormDataToOwnershipParameters(userId, formValues, subResources=[]) {
|
||||
if (!formValues.AccessControlEnabled) {
|
||||
formValues.Ownership = RCO.PUBLIC;
|
||||
}
|
||||
|
||||
let adminOnly = false;
|
||||
let publicOnly = false;
|
||||
let users = [];
|
||||
let teams = [];
|
||||
switch (formValues.Ownership) {
|
||||
case RCO.PUBLIC:
|
||||
publicOnly = true;
|
||||
break;
|
||||
case RCO.PRIVATE:
|
||||
users.push(userId);
|
||||
break;
|
||||
case RCO.RESTRICTED:
|
||||
users = _.map(formValues.AuthorizedUsers, (user) => user.Id);
|
||||
teams = _.map(formValues.AuthorizedTeams, (team) => team.Id);
|
||||
break;
|
||||
default:
|
||||
adminOnly = true;
|
||||
break;
|
||||
}
|
||||
return new ResourceControlOwnershipParameters(adminOnly, publicOnly, users, teams, subResources);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform AccessControlPanelData to ResourceControlOwnershipParameters
|
||||
* @param {AccessControlPanelData} formValues Form data (generated by AccessControlPanel)
|
||||
*/
|
||||
RCPanelDataToOwnershipParameters(formValues) {
|
||||
const adminOnly = formValues.Ownership === RCO.ADMINISTRATORS;
|
||||
const publicOnly = formValues.Ownership === RCO.PUBLIC;
|
||||
const userIds = publicOnly || adminOnly ? [] : _.map(formValues.Ownership_Users, (user) => user.Id);
|
||||
const teamIds = publicOnly || adminOnly ? [] : _.map(formValues.Ownership_Teams, (team) => team.Id);
|
||||
|
||||
return new ResourceControlOwnershipParameters(adminOnly, publicOnly, userIds, teamIds);
|
||||
}
|
||||
|
||||
retrieveAuthorizedUsers(resourceControl, users) {
|
||||
const authorizedUsers = [];
|
||||
_.forEach(resourceControl.UserAccesses, (access) => {
|
||||
const user = _.find(users, { Id: access.UserId });
|
||||
if (user) {
|
||||
authorizedUsers.push(user);
|
||||
}
|
||||
});
|
||||
return authorizedUsers;
|
||||
};
|
||||
}
|
||||
|
||||
helper.retrieveAuthorizedTeams = function(resourceControl, teams) {
|
||||
var authorizedTeams = [];
|
||||
angular.forEach(resourceControl.TeamAccesses, function(access) {
|
||||
var team = _.find(teams, { Id: access.TeamId });
|
||||
retrieveAuthorizedTeams(resourceControl, teams) {
|
||||
const authorizedTeams = [];
|
||||
_.forEach(resourceControl.TeamAccesses, (access) => {
|
||||
const team = _.find(teams, { Id: access.TeamId });
|
||||
if (team) {
|
||||
authorizedTeams.push(team);
|
||||
}
|
||||
});
|
||||
return authorizedTeams;
|
||||
};
|
||||
}
|
||||
|
||||
helper.isLeaderOfAnyRestrictedTeams = function(userMemberships, resourceControl) {
|
||||
var isTeamLeader = false;
|
||||
for (var i = 0; i < userMemberships.length; i++) {
|
||||
var membership = userMemberships[i];
|
||||
var found = _.find(resourceControl.TeamAccesses, { TeamId :membership.TeamId });
|
||||
isLeaderOfAnyRestrictedTeams(userMemberships, resourceControl) {
|
||||
let isTeamLeader = false;
|
||||
_.forEach(userMemberships, (membership) => {
|
||||
const found = _.find(resourceControl.TeamAccesses, { TeamId: membership.TeamId });
|
||||
if (found && membership.Role === 1) {
|
||||
isTeamLeader = true;
|
||||
break;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
return isTeamLeader;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return helper;
|
||||
}]);
|
||||
export default ResourceControlHelper;
|
||||
angular.module('portainer.app').service('ResourceControlHelper', ResourceControlHelper);
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import { ResourceControlOwnership as RCO } from 'Portainer/models/resourceControl/resourceControlOwnership';
|
||||
|
||||
export function ResourceControlViewModel(data) {
|
||||
this.Id = data.Id;
|
||||
this.Type = data.Type;
|
||||
|
@ -5,17 +7,18 @@ export function ResourceControlViewModel(data) {
|
|||
this.UserAccesses = data.UserAccesses;
|
||||
this.TeamAccesses = data.TeamAccesses;
|
||||
this.Public = data.Public;
|
||||
this.System = data.System;
|
||||
this.Ownership = determineOwnership(this);
|
||||
}
|
||||
|
||||
function determineOwnership(resourceControl) {
|
||||
if (resourceControl.Public) {
|
||||
return 'public';
|
||||
return RCO.PUBLIC;
|
||||
} else if (resourceControl.UserAccesses.length === 1 && resourceControl.TeamAccesses.length === 0) {
|
||||
return 'private';
|
||||
return RCO.PRIVATE;
|
||||
} else if (resourceControl.UserAccesses.length > 1 || resourceControl.TeamAccesses.length > 0) {
|
||||
return 'restricted';
|
||||
return RCO.RESTRICTED;
|
||||
} else {
|
||||
return 'administrators';
|
||||
return RCO.ADMINISTRATORS;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
/**
|
||||
* Payload for resourceControleCreate operation
|
||||
* @param {string} resourceId ID of involved Resource
|
||||
* @param {ResourceControlResourceType} resourceType Type of involved Resource
|
||||
* @param {ResourceControlOwnershipParameters} data Transcient type from view data to payload
|
||||
*/
|
||||
export function ResourceControlCreatePayload(resourceId, resourceType, data) {
|
||||
void data;
|
||||
|
||||
this.ResourceID = resourceId;
|
||||
this.Type = resourceType;
|
||||
this.Public = data.Public;
|
||||
this.AdministratorsOnly = data.AdministratorsOnly;
|
||||
this.Users = data.Users;
|
||||
this.Teams = data.Teams;
|
||||
this.SubResourceIDs = data.SubResourceIDs;
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
export const ResourceControlOwnership = Object.freeze({
|
||||
PUBLIC: 'public',
|
||||
PRIVATE: 'private',
|
||||
RESTRICTED: 'restricted',
|
||||
ADMINISTRATORS: 'administrators'
|
||||
});
|
|
@ -0,0 +1,15 @@
|
|||
/**
|
||||
* Transcient type from view data to payload
|
||||
* @param {bool} adminOnly is ResourceControl restricted to admin only
|
||||
* @param {bool} publicOnly is ResourceControl exposed to public
|
||||
* @param {[]int} users Authorized UserIDs array
|
||||
* @param {[]int} teams Authorized TeamIDs array
|
||||
* @param {[]int} subResources subResourceIDs array
|
||||
*/
|
||||
export function ResourceControlOwnershipParameters(adminOnly=false, publicOnly=false, users=[], teams=[], subResources=[]) {
|
||||
this.AdministratorsOnly = adminOnly;
|
||||
this.Public = publicOnly;
|
||||
this.Users = users;
|
||||
this.Teams = teams;
|
||||
this.SubResourceIDs = subResources;
|
||||
}
|
22
app/portainer/models/resourceControl/resourceControlTypes.js
Normal file
22
app/portainer/models/resourceControl/resourceControlTypes.js
Normal file
|
@ -0,0 +1,22 @@
|
|||
export const ResourceControlTypeString = Object.freeze({
|
||||
CONFIG: 'config',
|
||||
CONTAINER: 'container',
|
||||
NETWORK:'network',
|
||||
SECRET:'secret',
|
||||
SERVICE:'service',
|
||||
STACK:'stack',
|
||||
VOLUME:'volume'
|
||||
});
|
||||
|
||||
/**
|
||||
* ResourceType int defined in portainer.go as ResourceControlType
|
||||
*/
|
||||
export const ResourceControlTypeInt = Object.freeze({
|
||||
CONTAINER: 1,
|
||||
SERVICE: 2,
|
||||
VOLUME: 3,
|
||||
NETWORK: 4,
|
||||
SECRET: 5,
|
||||
STACK: 6,
|
||||
CONFIG: 7
|
||||
});
|
|
@ -0,0 +1,10 @@
|
|||
/**
|
||||
* Payload for resourceControlUpdate operation
|
||||
* @param {ResourceControlOwnershipParameters} data
|
||||
*/
|
||||
export function ResourceControlUpdatePayload(data) {
|
||||
this.Public = data.Public;
|
||||
this.AdministratorsOnly = data.AdministratorsOnly;
|
||||
this.Users = data.Users;
|
||||
this.Teams = data.Teams;
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
import { ResourceControlViewModel } from '../../portainer/models/resourceControl';
|
||||
import { ResourceControlViewModel } from 'Portainer/models/resourceControl/resourceControl';
|
||||
|
||||
export function StackViewModel(data) {
|
||||
this.Id = data.Id;
|
||||
|
|
|
@ -1,80 +1,108 @@
|
|||
import _ from 'lodash-es';
|
||||
|
||||
angular.module('portainer.app')
|
||||
.factory('ResourceControlService', ['$q', 'ResourceControl', 'UserService', 'TeamService', 'ResourceControlHelper', function ResourceControlServiceFactory($q, ResourceControl, UserService, TeamService, ResourceControlHelper) {
|
||||
.factory('ResourceControlService', ['$q', 'ResourceControl', 'UserService', 'TeamService', 'ResourceControlHelper',
|
||||
function ResourceControlServiceFactory($q, ResourceControl, UserService, TeamService, ResourceControlHelper) {
|
||||
'use strict';
|
||||
var service = {};
|
||||
const service = {};
|
||||
|
||||
service.createResourceControl = function(publicOnly, userIDs, teamIDs, resourceID, type, subResourceIDs) {
|
||||
service.duplicateResourceControl = duplicateResourceControl;
|
||||
service.applyResourceControlChange = applyResourceControlChange;
|
||||
service.applyResourceControl = applyResourceControl;
|
||||
service.retrieveOwnershipDetails = retrieveOwnershipDetails;
|
||||
service.retrieveUserPermissionsOnResource =retrieveUserPermissionsOnResource;
|
||||
|
||||
/**
|
||||
* PRIVATE SECTION
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a ResourceControl
|
||||
* @param {ResourceControlTypeString} rcType Type of ResourceControl
|
||||
* @param {string} rcID ID of involved resource
|
||||
* @param {ResourceControlOwnershipParameters} ownershipParameters Transcient type from view data to payload
|
||||
*/
|
||||
function createResourceControl(rcType, resourceID, ownershipParameters) {
|
||||
var payload = {
|
||||
Type: type,
|
||||
Public: publicOnly,
|
||||
Type: rcType,
|
||||
Public: ownershipParameters.Public,
|
||||
AdministratorsOnly: ownershipParameters.AdministratorsOnly,
|
||||
ResourceID: resourceID,
|
||||
Users: userIDs,
|
||||
Teams: teamIDs,
|
||||
SubResourceIDs: subResourceIDs
|
||||
Users: ownershipParameters.Users,
|
||||
Teams: ownershipParameters.Teams,
|
||||
SubResourceIds: ownershipParameters.SubResourceIDs
|
||||
};
|
||||
return ResourceControl.create({}, payload).$promise;
|
||||
};
|
||||
}
|
||||
|
||||
service.deleteResourceControl = function(rcID) {
|
||||
return ResourceControl.remove({id: rcID}).$promise;
|
||||
};
|
||||
|
||||
service.updateResourceControl = function(publicOnly, userIDs, teamIDs, resourceControlId) {
|
||||
var payload = {
|
||||
Public: publicOnly,
|
||||
Users: userIDs,
|
||||
Teams: teamIDs
|
||||
/**
|
||||
* Update a ResourceControl
|
||||
* @param {String} rcID ID of involved resource
|
||||
* @param {ResourceControlOwnershipParameters} ownershipParameters Transcient type from view data to payload
|
||||
*/
|
||||
function updateResourceControl(rcID, ownershipParameters) {
|
||||
const payload = {
|
||||
AdministratorsOnly: ownershipParameters.AdministratorsOnly,
|
||||
Public: ownershipParameters.Public,
|
||||
Users: ownershipParameters.Users,
|
||||
Teams: ownershipParameters.Teams
|
||||
};
|
||||
return ResourceControl.update({id: resourceControlId}, payload).$promise;
|
||||
};
|
||||
|
||||
service.applyResourceControl = function(resourceControlType, resourceIdentifier, userId, accessControlData, subResources) {
|
||||
if (!accessControlData.AccessControlEnabled) {
|
||||
accessControlData.Ownership = 'public';
|
||||
}
|
||||
return ResourceControl.update({id: rcID}, payload).$promise;
|
||||
}
|
||||
|
||||
var authorizedUserIds = [];
|
||||
var authorizedTeamIds = [];
|
||||
var publicOnly = false;
|
||||
switch (accessControlData.Ownership) {
|
||||
case 'public':
|
||||
publicOnly = true;
|
||||
break;
|
||||
case 'private':
|
||||
authorizedUserIds.push(userId);
|
||||
break;
|
||||
case 'restricted':
|
||||
angular.forEach(accessControlData.AuthorizedUsers, function(user) {
|
||||
authorizedUserIds.push(user.Id);
|
||||
});
|
||||
angular.forEach(accessControlData.AuthorizedTeams, function(team) {
|
||||
authorizedTeamIds.push(team.Id);
|
||||
});
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
return service.createResourceControl(publicOnly, authorizedUserIds,
|
||||
authorizedTeamIds, resourceIdentifier, resourceControlType, subResources);
|
||||
};
|
||||
/**
|
||||
* END PRIVATE SECTION
|
||||
*/
|
||||
|
||||
service.applyResourceControlChange = function(resourceControlType, resourceId, resourceControl, ownershipParameters) {
|
||||
/**
|
||||
* PUBLIC SECTION
|
||||
*/
|
||||
|
||||
/**
|
||||
* Apply a ResourceControl after Resource creation
|
||||
* @param {int} userId ID of User performing the action
|
||||
* @param {AccessControlFormData} accessControlData ResourceControl to apply
|
||||
* @param {ResourceControlViewModel} resourceControl ResourceControl to update
|
||||
* @param {[]int} subResources SubResources managed by the ResourceControl
|
||||
*/
|
||||
function applyResourceControl(userId, accessControlData, resourceControl, subResources=[]) {
|
||||
const ownershipParameters = ResourceControlHelper.RCFormDataToOwnershipParameters(userId, accessControlData, subResources);
|
||||
return updateResourceControl(resourceControl.Id, ownershipParameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Duplicate an existing ResourceControl (default to AdministratorsOnly if undefined)
|
||||
* @param {int} userId ID of User performing the action
|
||||
* @param {ResourceControlViewModel} oldResourceControl ResourceControl to duplicate
|
||||
* @param {ResourceControlViewModel} newResourceControl ResourceControl to apply duplication to
|
||||
*/
|
||||
function duplicateResourceControl(userId, oldResourceControl, newResourceControl) {
|
||||
const ownershipParameters = ResourceControlHelper.RCViewModelToOwnershipParameters(userId, oldResourceControl);
|
||||
return updateResourceControl(newResourceControl.Id, ownershipParameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an existing ResourceControl or create a new one on existing resource without RC
|
||||
* @param {ResourceControlTypeString} rcType Type of ResourceControl
|
||||
* @param {String} resourceId ID of involved Resource
|
||||
* @param {ResourceControlViewModel} resourceControl Previous ResourceControl (can be undefined)
|
||||
* @param {AccessControlPanelData} formValues View data generated by AccessControlPanel
|
||||
*/
|
||||
function applyResourceControlChange(rcType, resourceId, resourceControl, formValues) {
|
||||
const ownershipParameters = ResourceControlHelper.RCPanelDataToOwnershipParameters(formValues);
|
||||
if (resourceControl) {
|
||||
if (ownershipParameters.ownership === 'administrators') {
|
||||
return service.deleteResourceControl(resourceControl.Id);
|
||||
} else {
|
||||
return service.updateResourceControl(ownershipParameters.publicOnly, ownershipParameters.authorizedUserIds,
|
||||
ownershipParameters.authorizedTeamIds, resourceControl.Id);
|
||||
}
|
||||
return updateResourceControl(resourceControl.Id, ownershipParameters);
|
||||
} else {
|
||||
return service.createResourceControl(ownershipParameters.publicOnly, ownershipParameters.authorizedUserIds,
|
||||
ownershipParameters.authorizedTeamIds, resourceId, resourceControlType);
|
||||
return createResourceControl(rcType, resourceId, ownershipParameters);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
service.retrieveOwnershipDetails = function(resourceControl) {
|
||||
/**
|
||||
* Retrive users and team details for ResourceControlViewModel
|
||||
* @param {ResourceControlViewModel} resourceControl ResourceControl view model
|
||||
*/
|
||||
function retrieveOwnershipDetails(resourceControl) {
|
||||
var deferred = $q.defer();
|
||||
|
||||
if (!resourceControl) {
|
||||
|
@ -96,9 +124,9 @@ angular.module('portainer.app')
|
|||
});
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
}
|
||||
|
||||
service.retrieveUserPermissionsOnResource = function(userID, isAdministrator, resourceControl) {
|
||||
function retrieveUserPermissionsOnResource(userID, isAdministrator, resourceControl) {
|
||||
var deferred = $q.defer();
|
||||
|
||||
if (!resourceControl || isAdministrator) {
|
||||
|
@ -123,7 +151,11 @@ angular.module('portainer.app')
|
|||
}
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* END PUBLIC SECTION
|
||||
*/
|
||||
|
||||
return service;
|
||||
}]);
|
||||
|
|
|
@ -208,11 +208,6 @@ function StackServiceFactory($q, Stack, ResourceControlService, FileUploadServic
|
|||
var deferred = $q.defer();
|
||||
|
||||
Stack.remove({ id: stack.Id ? stack.Id : stack.Name, external: external, endpointId: endpointId }).$promise
|
||||
.then(function success() {
|
||||
if (stack.ResourceControl && stack.ResourceControl.Id) {
|
||||
return ResourceControlService.deleteResourceControl(stack.ResourceControl.Id);
|
||||
}
|
||||
})
|
||||
.then(function success() {
|
||||
deferred.resolve();
|
||||
})
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import { ResourceControlOwnership as RCO } from 'Portainer/models/resourceControl/resourceControlOwnership';
|
||||
|
||||
angular.module('portainer.app')
|
||||
.factory('FormValidator', [function FormValidatorFactory() {
|
||||
'use strict';
|
||||
|
@ -9,11 +11,11 @@ angular.module('portainer.app')
|
|||
return '';
|
||||
}
|
||||
|
||||
if (isAdmin && accessControlData.Ownership === 'restricted' &&
|
||||
if (isAdmin && accessControlData.Ownership === RCO.RESTRICTED &&
|
||||
accessControlData.AuthorizedUsers.length === 0 &&
|
||||
accessControlData.AuthorizedTeams.length === 0) {
|
||||
return 'You must specify at least one team or user.';
|
||||
} else if (!isAdmin && accessControlData.Ownership === 'restricted' &&
|
||||
} else if (!isAdmin && accessControlData.Ownership === RCO.RESTRICTED &&
|
||||
accessControlData.AuthorizedTeams.length === 0) {
|
||||
return 'You must specify at least a team.';
|
||||
}
|
||||
|
|
|
@ -98,7 +98,6 @@ function ($scope, $state, StackService, Authentication, Notifications, FormValid
|
|||
var accessControlData = $scope.formValues.AccessControlData;
|
||||
var userDetails = Authentication.getUserDetails();
|
||||
var isAdmin = Authentication.isAdmin();
|
||||
var userId = userDetails.ID;
|
||||
|
||||
if (method === 'editor' && $scope.formValues.StackFileContent === '') {
|
||||
$scope.state.formValidationError = 'Stack file content must not be empty';
|
||||
|
@ -116,8 +115,13 @@ function ($scope, $state, StackService, Authentication, Notifications, FormValid
|
|||
}
|
||||
$scope.state.actionInProgress = true;
|
||||
action(name, method)
|
||||
.then(function success() {
|
||||
return ResourceControlService.applyResourceControl('stack', name, userId, accessControlData, []);
|
||||
.then(function success(data) {
|
||||
if (data.data) {
|
||||
data = data.data;
|
||||
}
|
||||
const userId = userDetails.ID;
|
||||
const resourceControl = data.ResourceControl;
|
||||
return ResourceControlService.applyResourceControl(userId, accessControlData, resourceControl);
|
||||
})
|
||||
.then(function success() {
|
||||
Notifications.success('Stack successfully deployed');
|
||||
|
|
|
@ -79,8 +79,8 @@ function ($scope, $q, $state, $transition$, $anchorScroll, ContainerService, Ima
|
|||
return ContainerService.createAndStartContainer(templateConfiguration);
|
||||
})
|
||||
.then(function success(data) {
|
||||
var containerIdentifier = data.Id;
|
||||
return ResourceControlService.applyResourceControl('container', containerIdentifier, userId, accessControlData, generatedVolumeIds);
|
||||
const resourceControl = data.Portainer.ResourceControl;
|
||||
return ResourceControlService.applyResourceControl(userId, accessControlData, resourceControl, generatedVolumeIds);
|
||||
})
|
||||
.then(function success() {
|
||||
Notifications.success('Container successfully created');
|
||||
|
@ -111,8 +111,9 @@ function ($scope, $q, $state, $transition$, $anchorScroll, ContainerService, Ima
|
|||
|
||||
var endpointId = EndpointProvider.endpointID();
|
||||
StackService.createComposeStackFromGitRepository(stackName, repositoryOptions, template.Env, endpointId)
|
||||
.then(function success() {
|
||||
return ResourceControlService.applyResourceControl('stack', stackName, userId, accessControlData, []);
|
||||
.then(function success(data) {
|
||||
const resourceControl = data.Portainer.ResourceControl;
|
||||
return ResourceControlService.applyResourceControl(userId, accessControlData, resourceControl);
|
||||
})
|
||||
.then(function success() {
|
||||
Notifications.success('Stack successfully deployed');
|
||||
|
@ -148,8 +149,9 @@ function ($scope, $q, $state, $transition$, $anchorScroll, ContainerService, Ima
|
|||
|
||||
var endpointId = EndpointProvider.endpointID();
|
||||
StackService.createSwarmStackFromGitRepository(stackName, repositoryOptions, env, endpointId)
|
||||
.then(function success() {
|
||||
return ResourceControlService.applyResourceControl('stack', stackName, userId, accessControlData, []);
|
||||
.then(function success(data) {
|
||||
const resourceControl = data.Portainer.ResourceControl;
|
||||
return ResourceControlService.applyResourceControl(userId, accessControlData, resourceControl);
|
||||
})
|
||||
.then(function success() {
|
||||
Notifications.success('Stack successfully deployed');
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue