1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-08-09 15:55:23 +02:00

feat(extensions): introduce RBAC extension (#2900)

This commit is contained in:
Anthony Lapenna 2019-05-24 18:04:58 +12:00 committed by GitHub
parent 27a0188949
commit 8057aa45c4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
196 changed files with 3321 additions and 1316 deletions

View file

@ -77,7 +77,7 @@ class CreateConfigController {
async create() {
let accessControlData = this.formValues.AccessControlData;
let userDetails = this.Authentication.getUserDetails();
let isAdmin = userDetails.role === 1;
let isAdmin = this.Authentication.isAdmin();
if (this.formValues.ConfigContent === "") {
this.state.formValidationError = "Config content must not be empty";

View file

@ -24,8 +24,8 @@
<td>ID</td>
<td>
{{ config.Id }}
<button class="btn btn-xs btn-danger" ng-click="removeConfig(config.Id)"><i class="fa fa-trash-alt space-right" aria-hidden="true"></i>Delete this config</button>
<button class="btn btn-xs btn-primary" ui-sref="docker.configs.new({id: config.Id})"><i class="fa fa-copy space-right" aria-hidden="true"></i>Clone config</button>
<button authorization="DockerConfigDelete" class="btn btn-xs btn-danger" ng-click="removeConfig(config.Id)"><i class="fa fa-trash-alt space-right" aria-hidden="true"></i>Delete this config</button>
<button authorization="DockerConfigCreate"class="btn btn-xs btn-primary" ui-sref="docker.configs.new({id: config.Id})"><i class="fa fa-copy space-right" aria-hidden="true"></i>Clone config</button>
</td>
</tr>
<tr>

View file

@ -633,8 +633,7 @@ function ($q, $scope, $state, $timeout, $transition$, $filter, Container, Contai
$scope.availableLoggingDrivers = loggingDrivers;
});
var userDetails = Authentication.getUserDetails();
$scope.isAdmin = userDetails.role === 1;
$scope.isAdmin = Authentication.isAdmin();
}
function validateForm(accessControlData, isAdmin) {
@ -845,10 +844,7 @@ function ($q, $scope, $state, $timeout, $transition$, $filter, Container, Contai
function validateAccessControl() {
var accessControlData = $scope.formValues.AccessControlData;
var userDetails = Authentication.getUserDetails();
var isAdmin = userDetails.role === 1;
return validateForm(accessControlData, isAdmin);
return validateForm(accessControlData, $scope.isAdmin);
}
function onSuccess() {

View file

@ -6,21 +6,21 @@
</rd-header-content>
</rd-header>
<div class="row">
<div class="row" authorization="DockerContainerStart, DockerContainerStop, DockerContainerKill, DockerContainerRestart, DockerContainerPause, DockerContainerUnpause, DockerContainerDelete, DockerContainerCreate">
<div class="col-lg-12 col-md-12 col-xs-12">
<rd-widget>
<rd-widget-header icon="fa-cogs" title-text="Actions"></rd-widget-header>
<rd-widget-body classes="padding">
<div class="btn-group" role="group" aria-label="...">
<button class="btn btn-success btn-sm" ng-click="start()" ng-disabled="container.State.Running"><i class="fa fa-play space-right" aria-hidden="true"></i>Start</button>
<button class="btn btn-danger btn-sm" ng-click="stop()" ng-disabled="!container.State.Running"><i class="fa fa-stop space-right" aria-hidden="true"></i>Stop</button>
<button class="btn btn-danger btn-sm" ng-click="kill()" ng-disabled="!container.State.Running"><i class="fa fa-bomb space-right" aria-hidden="true"></i>Kill</button>
<button class="btn btn-primary btn-sm" ng-click="restart()" ng-disabled="!container.State.Running"><i class="fa fa-sync space-right" aria-hidden="true"></i>Restart</button>
<button class="btn btn-primary btn-sm" ng-click="pause()" ng-disabled="!container.State.Running || container.State.Paused"><i class="fa fa-pause space-right" aria-hidden="true"></i>Pause</button>
<button class="btn btn-primary btn-sm" ng-click="unpause()" ng-disabled="!container.State.Paused"><i class="fa fa-play space-right" aria-hidden="true"></i>Resume</button>
<button class="btn btn-danger btn-sm" ng-click="confirmRemove()"><i class="fa fa-trash-alt space-right" aria-hidden="true"></i>Remove</button>
<button authorization="DockerContainerStart" class="btn btn-success btn-sm" ng-click="start()" ng-disabled="container.State.Running"><i class="fa fa-play space-right" aria-hidden="true"></i>Start</button>
<button authorization="DockerContainerStop" class="btn btn-danger btn-sm" ng-click="stop()" ng-disabled="!container.State.Running"><i class="fa fa-stop space-right" aria-hidden="true"></i>Stop</button>
<button authorization=DockerContainerKill" class="btn btn-danger btn-sm" ng-click="kill()" ng-disabled="!container.State.Running"><i class="fa fa-bomb space-right" aria-hidden="true"></i>Kill</button>
<button authorization="DockerContainerRestart" class="btn btn-primary btn-sm" ng-click="restart()" ng-disabled="!container.State.Running"><i class="fa fa-sync space-right" aria-hidden="true"></i>Restart</button>
<button authorization="DockerContainerPause" class="btn btn-primary btn-sm" ng-click="pause()" ng-disabled="!container.State.Running || container.State.Paused"><i class="fa fa-pause space-right" aria-hidden="true"></i>Pause</button>
<button authorization="DockerContainerUnpause" class="btn btn-primary btn-sm" ng-click="unpause()" ng-disabled="!container.State.Paused"><i class="fa fa-play space-right" aria-hidden="true"></i>Resume</button>
<button authorization="DockerContainerDelete" class="btn btn-danger btn-sm" ng-click="confirmRemove()"><i class="fa fa-trash-alt space-right" aria-hidden="true"></i>Remove</button>
</div>
<div class="btn-group" role="group" aria-label="..." ng-if="!container.Config.Labels['com.docker.swarm.service.id']">
<div class="btn-group" role="group" aria-label="..." ng-if="!container.Config.Labels['com.docker.swarm.service.id']" authorization="DockerContainerCreate">
<button type="button" class="btn btn-danger btn-sm" ng-disabled="state.recreateContainerInProgress" ng-click="recreate()" button-spinner="state.recreateContainerInProgress">
<span ng-hide="state.recreateContainerInProgress"><i class="fa fa-sync space-right" aria-hidden="true"></i>Recreate</span>
<span ng-show="state.recreateContainerInProgress">Recreation in progress...</span>
@ -47,7 +47,7 @@
<td>Name</td>
<td ng-if="!container.edit">
{{ container.Name|trimcontainername }}
<a href="" data-toggle="tooltip" title="Edit container name" ng-click="container.edit = true;"><i class="fa fa-edit"></i></a>
<a authorization="DockerContainerRename" href="" data-toggle="tooltip" title="Edit container name" ng-click="container.edit = true;"><i class="fa fa-edit"></i></a>
</td>
<td ng-if="container.edit">
<form ng-submit="renameContainer()">
@ -81,14 +81,14 @@
<td>Finished</td>
<td>{{ container.State.FinishedAt|getisodate }}</td>
</tr>
<tr>
<tr authorization="DockerContainerLogs, DockerContainerInspect, DockerContainerStats, DockerExecStart">
<td colspan="2">
<div class="btn-group" role="group" aria-label="...">
<a class="btn" type="button" ui-sref="docker.containers.container.logs({ id: container.Id })"><i class="fa fa-file-alt space-right" aria-hidden="true"></i>Logs</a>
<a class="btn" type="button" ui-sref="docker.containers.container.inspect({ id: container.Id })"><i class="fa fa-info-circle space-right" aria-hidden="true"></i>Inspect</a>
<a class="btn" type="button" ui-sref="docker.containers.container.stats({ id: container.Id })"><i class="fa fa-chart-area space-right" aria-hidden="true"></i>Stats</a>
<a class="btn" type="button" ui-sref="docker.containers.container.exec({ id: container.Id })"><i class="fa fa-terminal space-right" aria-hidden="true"></i>Exec</a>
<a class="btn" type="button" ui-sref="docker.containers.container.attach({ id: container.Id })"><i class="fa fa-plug space-right" aria-hidden="true"></i>Attach</a>
<a authorization="DockerContainerLogs" class="btn" type="button" ui-sref="docker.containers.container.logs({ id: container.Id })"><i class="fa fa-file-alt space-right" aria-hidden="true"></i>Logs</a>
<a authorization="DockerContainerInspect" class="btn" type="button" ui-sref="docker.containers.container.inspect({ id: container.Id })"><i class="fa fa-info-circle space-right" aria-hidden="true"></i>Inspect</a>
<a authorization="DockerContainerStats" class="btn" type="button" ui-sref="docker.containers.container.stats({ id: container.Id })"><i class="fa fa-chart-area space-right" aria-hidden="true"></i>Stats</a>
<a authorization="DockerExecStart" class="btn" type="button" ui-sref="docker.containers.container.exec({ id: container.Id })"><i class="fa fa-terminal space-right" aria-hidden="true"></i>Console</a>
<a authorization="DockerContainerAttach" class="btn" type="button" ui-sref="docker.containers.container.attach({ id: container.Id })"><i class="fa fa-plug space-right" aria-hidden="true"></i>Attach</a>
</div>
</td>
</tr>
@ -137,7 +137,7 @@
</div>
</div>
<div class="row">
<div class="row" authorization="DockerImageCreate">
<div class="col-lg-12 col-md-12 col-xs-12">
<rd-widget>
<rd-widget-header icon="fa-clone" title-text="Create image"></rd-widget-header>

View file

@ -19,7 +19,7 @@ angular.module('portainer.docker').controller('HostViewController', [
function initView() {
var applicationState = StateManager.getState();
ctrl.state.isAgent = applicationState.endpoint.mode.agentProxy;
ctrl.state.isAdmin = Authentication.getUserDetails().role === 1;
ctrl.state.isAdmin = Authentication.isAdmin();
var agentApiVersion = applicationState.endpoint.agentApiVersion;
ctrl.state.agentApiVersion = agentApiVersion;
ctrl.state.enableHostManagementFeatures = applicationState.application.enableHostManagementFeatures;

View file

@ -16,14 +16,14 @@
<div class="pull-left" ng-repeat="tag in image.RepoTags" style="display:table">
<div class="input-group col-md-1" style="padding:0 15px">
<span class="input-group-addon">{{ tag }}</span>
<span class="input-group-btn">
<a data-toggle="tooltip" class="btn btn-primary interactive" title="Push to registry" ng-click="pushTag(tag)">
<span class="input-group-btn" authorization="DockerImagePush, DockerImageCreate, DockerImageDelete">
<a data-toggle="tooltip" class="btn btn-primary interactive" title="Push to registry" ng-click="pushTag(tag)" authorization="DockerImagePush">
<span class="fa fa-upload white-icon" aria-hidden="true"></span>
</a>
<a data-toggle="tooltip" class="btn btn-primary interactive" title="Pull from registry" ng-click="pullTag(tag)">
<a data-toggle="tooltip" class="btn btn-primary interactive" title="Pull from registry" ng-click="pullTag(tag)" authorization="DockerImageCreate">
<span class="fa fa-download white-icon" aria-hidden="true"></span>
</a>
<a data-toggle="tooltip" class="btn btn-primary interactive" title="Remove tag" ng-click="removeTag(tag)">
<a data-toggle="tooltip" class="btn btn-primary interactive" title="Remove tag" ng-click="removeTag(tag)" authorization="DockerImageDelete">
<span class="fa fa-trash-alt white-icon" aria-hidden="true"></span>
</a>
</span>
@ -56,7 +56,7 @@
</div>
</div>
<div class="row">
<div class="row" authorization="DockerImageCreate">
<div class="col-lg-12 col-md-12 col-xs-12">
<rd-widget>
<rd-widget-header icon="fa-tag" title-text="Tag the image"></rd-widget-header>
@ -98,8 +98,8 @@
<td>ID</td>
<td>
{{ image.Id }}
<button class="btn btn-xs btn-danger" ng-click="removeImage(image.Id)"><i class="fa fa-trash-alt space-right" aria-hidden="true"></i>Delete this image</button>
<button class="btn btn-xs btn-primary" ng-click="exportImage(image)" button-spinner="$ctrl.exportInProgress" ng-disabled="state.exportInProgress">
<button authorization="DockerImageDelete" class="btn btn-xs btn-danger" ng-click="removeImage(image.Id)"><i class="fa fa-trash-alt space-right" aria-hidden="true"></i>Delete this image</button>
<button authorization="DockerImageGet" class="btn btn-xs btn-primary" ng-click="exportImage(image)" button-spinner="$ctrl.exportInProgress" ng-disabled="state.exportInProgress">
<i class="fa fa-download space-right" aria-hidden="true"></i>
<span ng-hide="state.exportInProgress">Export this image</span>
<span ng-show="state.exportInProgress">Export in progress...</span>

View file

@ -7,7 +7,7 @@
<rd-header-content>Images</rd-header-content>
</rd-header>
<div class="row" ng-if="!offlineMode">
<div class="row" ng-if="!offlineMode" authorization="DockerImageCreate">
<div class="col-lg-12 col-md-12 col-xs-12">
<rd-widget>
<rd-widget-header icon="fa-download" title-text="Pull image ">

View file

@ -158,7 +158,7 @@ angular.module('portainer.docker')
var networkConfiguration = prepareConfiguration();
var accessControlData = $scope.formValues.AccessControlData;
var userDetails = Authentication.getUserDetails();
var isAdmin = userDetails.role === 1;
var isAdmin = Authentication.isAdmin();
if (!validateForm(accessControlData, isAdmin)) {
return;

View file

@ -20,7 +20,7 @@
<td>ID</td>
<td>
{{ network.Id }}
<button ng-if="allowRemove(network)" class="btn btn-xs btn-danger" ng-click="removeNetwork(network.Id)"><i class="fa fa-trash-alt space-right" aria-hidden="true"></i>Delete this network</button>
<button authorization="DockerNetworkDelete" ng-if="allowRemove(network)" class="btn btn-xs btn-danger" ng-click="removeNetwork(network.Id)"><i class="fa fa-trash-alt space-right" aria-hidden="true"></i>Delete this network</button>
</td>
</tr>
<tr>
@ -89,7 +89,7 @@
<th>IPv4 Address</th>
<th>IPv6 Address</th>
<th>MacAddress</th>
<th>Actions</th>
<th authorization="DockerNetworkDisconnect">Actions</th>
</thead>
<tbody>
<tr ng-repeat="container in containersInNetwork">
@ -97,7 +97,7 @@
<td>{{ container.IPv4Address || '-' }}</td>
<td>{{ container.IPv6Address || '-' }}</td>
<td>{{ container.MacAddress || '-' }}</td>
<td>
<td authorization="DockerNetworkDisconnect">
<button type="button" class="btn btn-xs btn-danger" ng-click="containerLeaveNetwork(network, container)"><i class="fa fa-trash-alt space-right" aria-hidden="true"></i>Leave Network</button>
</td>
</tr>

View file

@ -13,7 +13,7 @@ angular.module('portainer.docker').controller('NodeDetailsViewController', [
function initView() {
var applicationState = StateManager.getState();
ctrl.state.isAgent = applicationState.endpoint.mode.agentProxy;
ctrl.state.isAdmin = Authentication.getUserDetails().role === 1;
ctrl.state.isAdmin = Authentication.isAdmin();
ctrl.state.enableHostManagementFeatures = applicationState.application.enableHostManagementFeatures;
var fetchJobs = ctrl.state.isAdmin && ctrl.state.isAgent;

View file

@ -61,7 +61,7 @@ function ($scope, $state, Notifications, SecretService, LabelHelper, Authenticat
var accessControlData = $scope.formValues.AccessControlData;
var userDetails = Authentication.getUserDetails();
var isAdmin = userDetails.role === 1;
var isAdmin = Authentication.isAdmin();
if (!validateForm(accessControlData, isAdmin)) {
return;

View file

@ -24,7 +24,7 @@
<td>ID</td>
<td>
{{ secret.Id }}
<button class="btn btn-xs btn-danger" ng-click="removeSecret(secret.Id)"><i class="fa fa-trash-alt space-right" aria-hidden="true"></i>Delete this secret</button>
<button authorization="DockerSecretDelete" class="btn btn-xs btn-danger" ng-click="removeSecret(secret.Id)"><i class="fa fa-trash-alt space-right" aria-hidden="true"></i>Delete this secret</button>
</td>
</tr>
<tr>

View file

@ -467,12 +467,9 @@ function ($q, $scope, $state, $timeout, Service, ServiceHelper, ConfigService, C
}
$scope.create = function createService() {
var accessControlData = $scope.formValues.AccessControlData;
var userDetails = Authentication.getUserDetails();
var isAdmin = userDetails.role === 1;
if (!validateForm(accessControlData, isAdmin)) {
if (!validateForm(accessControlData, $scope.isAdmin)) {
return;
}
@ -524,8 +521,7 @@ function ($q, $scope, $state, $timeout, Service, ServiceHelper, ConfigService, C
$scope.availableLoggingDrivers = data.availableLoggingDrivers;
initSlidersMaxValuesBasedOnNodeData(data.nodes);
$scope.allowBindMounts = data.settings.AllowBindMountsForRegularUsers;
var userDetails = Authentication.getUserDetails();
$scope.isAdmin = userDetails.role === 1;
$scope.isAdmin = Authentication.isAdmin();
})
.catch(function error(err) {
Notifications.error('Failure', err, 'Unable to initialize view');

View file

@ -3,7 +3,7 @@
<rd-widget-header icon="fa-tasks" title-text="Configs">
</rd-widget-header>
<rd-widget-body classes="no-padding">
<div class="form-inline" style="padding: 10px;">
<div class="form-inline" style="padding: 10px;" authorization="DockerServiceUpdate">
Add a config:
<select class="form-control" ng-options="config.Name for config in configs | orderBy: 'Name'" ng-model="newConfig">
<option selected disabled hidden value="">Select a config</option>
@ -32,7 +32,7 @@
<td>{{ config.Uid }}</td>
<td>{{ config.Gid }}</td>
<td>{{ config.Mode }}</td>
<td>
<td authorization="DockerServiceUpdate">
<button class="btn btn-xs btn-danger pull-right" type="button" ng-click="removeConfig(service, $index)" ng-disabled="isUpdating">
<i class="fa fa-trash" aria-hidden="true"></i> Remove config
</button>
@ -44,7 +44,7 @@
</tbody>
</table>
</rd-widget-body>
<rd-widget-footer>
<rd-widget-footer authorization="DockerServiceUpdate">
<div class="btn-toolbar" role="toolbar">
<div class="btn-group" role="group">
<button type="submit" class="btn btn-primary btn-sm" ng-disabled="!hasChanges(service, ['ServiceConfigs'])">Apply changes</button>

View file

@ -1,7 +1,7 @@
<div ng-if="service.ServiceConstraints" id="service-placement-constraints">
<rd-widget>
<rd-widget-header icon="fa-tasks" title-text="Placement constraints">
<div class="nopadding">
<div class="nopadding" authorization="DockerServiceUpdate">
<a class="btn btn-default btn-sm pull-right" ng-click="isUpdating || addPlacementConstraint(service)" ng-disabled="isUpdating">
<i class="fa fa-plus-circle" aria-hidden="true"></i> placement constraint
</a>
@ -37,7 +37,7 @@
<td>
<div class="input-group input-group-sm">
<input type="text" class="form-control" ng-model="constraint.value" placeholder="e.g. manager" ng-change="updatePlacementConstraint(service, constraint)" ng-disabled="isUpdating">
<span class="input-group-btn">
<span class="input-group-btn" authorization="DockerServiceUpdate">
<button class="btn btn-sm btn-danger" type="button" ng-click="removePlacementConstraint(service, $index)" ng-disabled="isUpdating">
<i class="fa fa-trash" aria-hidden="true"></i>
</button>
@ -48,7 +48,7 @@
</tbody>
</table>
</rd-widget-body>
<rd-widget-footer>
<rd-widget-footer authorization="DockerServiceUpdate">
<div class="btn-toolbar" role="toolbar">
<div class="btn-group" role="group">
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!hasChanges(service, ['ServiceConstraints'])" ng-click="updateService(service)">Apply changes</button>

View file

@ -1,7 +1,7 @@
<div id="service-container-labels">
<rd-widget>
<rd-widget-header icon="fa-tasks" title-text="Container labels">
<div class="nopadding">
<div class="nopadding" authorization="DockerServiceUpdate">
<a class="btn btn-default btn-sm pull-right" ng-click="isUpdating ||addContainerLabel(service)" ng-disabled="isUpdating">
<i class="fa fa-plus-circle" aria-hidden="true"></i> container label
</a>
@ -30,7 +30,7 @@
<div class="input-group input-group-sm">
<span class="input-group-addon fit-text-size">value</span>
<input type="text" class="form-control" ng-model="label.value" placeholder="e.g. bar" ng-change="updateContainerLabel(service, label)" ng-disabled="isUpdating">
<span class="input-group-btn">
<span class="input-group-btn" authorization="DockerServiceUpdate">
<button class="btn btn-sm btn-danger" type="button" ng-click="removeContainerLabel(service, $index)" ng-disabled="isUpdating">
<i class="fa fa-trash" aria-hidden="true"></i>
</button>
@ -41,7 +41,7 @@
</tbody>
</table>
</rd-widget-body>
<rd-widget-footer>
<rd-widget-footer authorization="DockerServiceUpdate">
<div class="btn-toolbar" role="toolbar">
<div class="btn-group" role="group">
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!hasChanges(service, ['ServiceContainerLabels'])" ng-click="updateService(service)">Apply changes</button>

View file

@ -1,7 +1,7 @@
<div ng-if="service.EnvironmentVariables" id="service-env-variables">
<rd-widget>
<rd-widget-header icon="fa-tasks" title-text="Environment variables">
<div class="nopadding">
<div class="nopadding" authorization="DockerServiceUpdate">
<a class="btn btn-default btn-sm pull-right" ng-click="isUpdating ||addEnvironmentVariable(service)" ng-disabled="isUpdating">
<i class="fa fa-plus-circle" aria-hidden="true"></i> environment variable
</a>
@ -30,7 +30,7 @@
<div class="input-group input-group-sm">
<span class="input-group-addon fit-text-size">value</span>
<input type="text" class="form-control" ng-model="var.value" ng-change="updateEnvironmentVariable(service, var)" placeholder="e.g. bar" ng-disabled="isUpdating">
<span class="input-group-btn">
<span class="input-group-btn" authorization="DockerServiceUpdate">
<button class="btn btn-sm btn-danger" type="button" ng-click="removeEnvironmentVariable(service, $index)" ng-disabled="isUpdating">
<i class="fa fa-trash" aria-hidden="true"></i>
</button>
@ -41,7 +41,7 @@
</tbody>
</table>
</rd-widget-body>
<rd-widget-footer>
<rd-widget-footer authorization="DockerServiceUpdate">
<div class="btn-toolbar" role="toolbar">
<div class="btn-group" role="group">
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!hasChanges(service, ['EnvironmentVariables'])" ng-click="updateService(service)">Apply changes</button>

View file

@ -1,7 +1,7 @@
<div>
<rd-widget>
<rd-widget-header icon="fa-tasks" title-text="Hosts file entries">
<div class="nopadding">
<div class="nopadding" authorization="DockerServiceUpdate">
<a class="btn btn-default btn-sm pull-right" ng-click="isUpdating ||addHostsEntry(service)" ng-disabled="isUpdating">
<i class="fa fa-plus-circle" aria-hidden="true"></i> add host entry
</a>
@ -9,7 +9,7 @@
</rd-widget-header>
<rd-widget-body ng-if="!service.Hosts || service.Hosts.length === 0">
<p>The Hosts file has no extra entries.</p>
</rd-widget-body>
</rd-widget-body>
<rd-widget-body ng-if="service.Hosts.length > 0" classes="no-padding">
<table class="table" >
<thead>
@ -28,7 +28,7 @@
<td>
<div class="input-group input-group-sm">
<input type="text" class="form-control" ng-model="entry.ip" placeholder="e.g. 10.0.1.1" ng-change="updateHostsEntry(service, entry)" ng-disabled="isUpdating">
<span class="input-group-btn">
<span class="input-group-btn" authorization="DockerServiceUpdate">
<button class="btn btn-sm btn-danger" type="button" ng-click="removeHostsEntry(service, $index)" ng-disabled="isUpdating">
<i class="fa fa-trash" aria-hidden="true"></i>
</button>
@ -39,7 +39,7 @@
</tbody>
</table>
</rd-widget-body>
<rd-widget-footer>
<rd-widget-footer authorization="DockerServiceUpdate">
<div class="btn-toolbar" role="toolbar">
<div class="btn-group" role="group">
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!hasChanges(service, ['Hosts'])" ng-click="updateService(service)">Apply changes</button>

View file

@ -1,13 +1,13 @@
<div id="service-logging-driver">
<rd-widget>
<rd-widget-header icon="fa-tasks" title-text="Logging driver">
</rd-widget-header>
<rd-widget-header icon="fa-tasks" title-text="Logging driver">
</rd-widget-header>
<rd-widget-body classes="no-padding">
<div class="form-inline" style="padding: 10px;">
<div class="form-inline" style="padding: 10px;" authorization="DockerServiceUpdate">
Driver:
<select class="form-control" ng-model="service.LogDriverName" ng-change="updateLogDriverName(service)" ng-disabled="isUpdating">
<option selected value="">Default logging driver</option>
<option ng-repeat="driver in availableLoggingDrivers" ng-value="driver">{{ driver }}</option>
<option selected value="">Default logging driver</option>
<option ng-repeat="driver in availableLoggingDrivers" ng-value="driver">{{ driver }}</option>
<option value="none">none</option>
</select>
<a class="btn btn-default btn-sm" ng-click="!service.LogDriverName || service.LogDriverName === 'none' || addLogDriverOpt(service)">
@ -33,7 +33,7 @@
<div class="input-group input-group-sm">
<span class="input-group-addon fit-text-size">value</span>
<input type="text" class="form-control" ng-model="option.value" ng-change="updateLogDriverOpt(service, option)" placeholder="e.g. bar" ng-disabled="isUpdating">
<span class="input-group-btn">
<span class="input-group-btn" authorization="DockerServiceUpdate">
<button class="btn btn-sm btn-danger" type="button" ng-click="removeLogDriverOpt(service, $index)" ng-disabled="isUpdating">
<i class="fa fa-trash" aria-hidden="true"></i>
</button>
@ -47,7 +47,7 @@
</tbody>
</table>
</rd-widget-body>
<rd-widget-footer>
<rd-widget-footer authorization="DockerServiceUpdate">
<div class="btn-toolbar" role="toolbar">
<div class="btn-group" role="group">
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!hasChanges(service, ['LogDriverName', 'LogDriverOpts'])" ng-click="updateService(service)">Apply changes</button>
@ -62,4 +62,4 @@
</div>
</rd-widget-footer>
</rd-widget>
</div>
</div>

View file

@ -1,7 +1,7 @@
<div ng-if="service.ServiceMounts" id="service-mounts">
<rd-widget>
<rd-widget-header icon="fa-tasks" title-text="Mounts">
<div class="nopadding">
<div class="nopadding" authorization="DockerServiceUpdate">
<a class="btn btn-default btn-sm pull-right" ng-click="isUpdating ||addMount(service)" ng-disabled="isUpdating">
<i class="fa fa-plus-circle" aria-hidden="true"></i> mount
</a>
@ -41,7 +41,7 @@
<td>
<input type="checkbox" class="form-control" ng-model="mount.ReadOnly" ng-change="updateMount(service, mount)" ng-disabled="isUpdating">
</td>
<td>
<td authorization="DockerServiceUpdate">
<span class="input-group-btn">
<button class="btn btn-sm btn-danger" type="button" ng-click="removeMount(service, $index)" ng-disabled="isUpdating">
<i class="fa fa-trash" aria-hidden="true"></i>
@ -52,7 +52,7 @@
</tbody>
</table>
</rd-widget-body>
<rd-widget-footer>
<rd-widget-footer authorization="DockerServiceUpdate">
<div class="btn-toolbar" role="toolbar">
<div class="btn-group" role="group">
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!hasChanges(service, ['ServiceMounts'])" ng-click="updateService(service)">Apply changes</button>

View file

@ -1,7 +1,7 @@
<div ng-if="service.ServicePreferences" id="service-placement-preferences">
<rd-widget>
<rd-widget-header icon="fa-tasks" title-text="Placement preferences">
<div class="nopadding">
<div class="nopadding" authorization="DockerServiceUpdate">
<a class="btn btn-default btn-sm pull-right" ng-click="isUpdating || addPlacementPreference(service)" ng-disabled="isUpdating">
<i class="fa fa-plus-circle" aria-hidden="true"></i> placement preference
</a>
@ -28,7 +28,7 @@
<td>
<div class="input-group input-group-sm">
<input type="text" class="form-control" ng-model="preference.value" placeholder="e.g. manager" ng-change="updatePlacementPreference(service, preference)" ng-disabled="isUpdating">
<span class="input-group-btn">
<span class="input-group-btn" authorization="DockerServiceUpdate">
<button class="btn btn-sm btn-danger" type="button" ng-click="removePlacementPreference(service, $index)" ng-disabled="isUpdating">
<i class="fa fa-trash" aria-hidden="true"></i>
</button>
@ -39,7 +39,7 @@
</tbody>
</table>
</rd-widget-body>
<rd-widget-footer>
<rd-widget-footer authorization="DockerServiceUpdate">
<div class="btn-toolbar" role="toolbar">
<div class="btn-group" role="group">
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!hasChanges(service, ['ServicePreferences'])" ng-click="updateService(service)">Apply changes</button>

View file

@ -1,7 +1,7 @@
<div>
<rd-widget>
<rd-widget-header icon="fa-tasks" title-text="Published ports">
<div class="nopadding">
<div class="nopadding" authorization="DockerServiceUpdate">
<a class="btn btn-default btn-sm pull-right" ng-click="isUpdating ||addPublishedPort(service)" ng-disabled="isUpdating">
<i class="fa fa-plus-circle" aria-hidden="true"></i> port mapping
</a>
@ -51,7 +51,7 @@
</select>
</div>
</td>
<td>
<td authorization="DockerServiceUpdate">
<span class="input-group-btn">
<button class="btn btn-sm btn-danger" type="button" ng-click="removePortPublishedBinding(service, $index)" ng-disabled="isUpdating">
<i class="fa fa-trash" aria-hidden="true"></i>
@ -62,7 +62,7 @@
</tbody>
</table>
</rd-widget-body>
<rd-widget-footer>
<rd-widget-footer authorization="DockerServiceUpdate">
<div class="btn-toolbar" role="toolbar">
<div class="btn-group" role="group">
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!hasChanges(service, ['Ports'])" ng-click="updateService(service)">Apply changes</button>

View file

@ -10,7 +10,7 @@
Memory reservation (MB)
</td>
<td>
<input class="input-sm" type="number" step="0.125" min="0" ng-model="service.ReservationMemoryBytes" ng-change="updateServiceAttribute(service, 'ReservationMemoryBytes')" ng-disabled="isUpdating"/>
<input class="input-sm" type="number" step="0.125" min="0" ng-model="service.ReservationMemoryBytes" ng-change="updateServiceAttribute(service, 'ReservationMemoryBytes')" disable-authorization="DockerServiceUpdate"/>
</td>
<td style="vertical-align : middle;">
<p class="small text-muted">
@ -23,7 +23,7 @@
Memory limit (MB)
</td>
<td>
<input class="input-sm" type="number" step="0.125" min="0" ng-model="service.LimitMemoryBytes" ng-change="updateServiceAttribute(service, 'LimitMemoryBytes')" ng-disabled="isUpdating"/>
<input class="input-sm" type="number" step="0.125" min="0" ng-model="service.LimitMemoryBytes" ng-change="updateServiceAttribute(service, 'LimitMemoryBytes')" disable-authorization="DockerServiceUpdate"/>
</td>
<td style="vertical-align : middle;">
<p class="small text-muted">
@ -64,7 +64,7 @@
</tbody>
</table>
</rd-widget-body>
<rd-widget-footer>
<rd-widget-footer authorization="DockerServiceUpdate">
<div class="btn-toolbar" role="toolbar">
<div class="btn-group" role="group">
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!hasChanges(service, ['LimitNanoCPUs', 'LimitMemoryBytes', 'ReservationNanoCPUs', 'ReservationMemoryBytes'])" ng-click="updateService(service)">Apply changes</button>

View file

@ -9,7 +9,7 @@
<td>Restart condition</td>
<td>
<div class="input-group input-group-sm">
<select class="selectpicker form-control" ng-model="service.RestartCondition" ng-change="updateServiceAttribute(service, 'RestartCondition')" ng-disabled="isUpdating">
<select class="selectpicker form-control" ng-model="service.RestartCondition" ng-change="updateServiceAttribute(service, 'RestartCondition')" disable-authorization="DockerServiceUpdate">
<option value="none">None</option>
<option value="on-failure">On failure</option>
<option value="any">Any</option>
@ -25,7 +25,7 @@
<tr>
<td>Restart delay</td>
<td>
<input class="input-sm" type="text" ng-model="service.RestartDelay" ng-change="updateServiceAttribute(service, 'RestartDelay')" ng-pattern="/^([0-9]+)(h|m|s|ms|us|ns)$/i" ng-disabled="isUpdating"/>
<input class="input-sm" type="text" ng-model="service.RestartDelay" ng-change="updateServiceAttribute(service, 'RestartDelay')" ng-pattern="/^([0-9]+)(h|m|s|ms|us|ns)$/i" disable-authorization="DockerServiceUpdate"/>
</td>
<td>
<p class="small text-muted" style="margin-top: 10px;">
@ -36,7 +36,7 @@
<tr>
<td>Restart max attempts</td>
<td>
<input class="input-sm" type="number" ng-model="service.RestartMaxAttempts" ng-change="updateServiceAttribute(service, 'RestartMaxAttempts')" ng-disabled="isUpdating"/>
<input class="input-sm" type="number" ng-model="service.RestartMaxAttempts" ng-change="updateServiceAttribute(service, 'RestartMaxAttempts')" disable-authorization="DockerServiceUpdate"/>
</td>
<td>
<p class="small text-muted" style="margin-top: 10px;">
@ -47,7 +47,7 @@
<tr>
<td>Restart window</td>
<td>
<input class="input-sm" type="text" ng-model="service.RestartWindow" ng-change="updateServiceAttribute(service, 'RestartWindow')" ng-pattern="/^([0-9]+)(h|m|s|ms|us|ns)$/i" ng-disabled="isUpdating"/>
<input class="input-sm" type="text" ng-model="service.RestartWindow" ng-change="updateServiceAttribute(service, 'RestartWindow')" ng-pattern="/^([0-9]+)(h|m|s|ms|us|ns)$/i" disable-authorization="DockerServiceUpdate"/>
</td>
<td>
<p class="small text-muted" style="margin-top: 10px;">
@ -58,7 +58,7 @@
</tbody>
</table>
</rd-widget-body>
<rd-widget-footer>
<rd-widget-footer authorization="DockerServiceUpdate">
<div class="btn-toolbar" role="toolbar">
<div class="btn-group" role="group">
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!hasChanges(service, ['RestartCondition', 'RestartDelay', 'RestartMaxAttempts', 'RestartWindow'])" ng-click="updateService(service)">Apply changes</button>

View file

@ -3,7 +3,7 @@
<rd-widget-header icon="fa-tasks" title-text="Secrets">
</rd-widget-header>
<rd-widget-body classes="no-padding">
<div class="form-inline" style="padding: 10px;">
<div class="form-inline" style="padding: 10px;" authorization="DockerServiceUpdate">
Add a secret:
<select class="form-control" ng-options="secret.Name for secret in secrets | orderBy: 'Name'" ng-model="state.addSecret.secret">
<option selected disabled hidden value="">Select a secret</option>
@ -38,7 +38,7 @@
<td>{{ secret.Uid }}</td>
<td>{{ secret.Gid }}</td>
<td>{{ secret.Mode }}</td>
<td>
<td authorization="DockerServiceUpdate">
<button class="btn btn-xs btn-danger pull-right" type="button" ng-click="removeSecret(service, $index)" ng-disabled="isUpdating">
<i class="fa fa-trash" aria-hidden="true"></i> Remove secret
</button>
@ -50,7 +50,7 @@
</tbody>
</table>
</rd-widget-body>
<rd-widget-footer>
<rd-widget-footer authorization="DockerServiceUpdate">
<div class="btn-toolbar" role="toolbar">
<div class="btn-group" role="group">
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!hasChanges(service, ['ServiceSecrets'])" ng-click="updateService(service)">Apply changes</button>

View file

@ -1,7 +1,7 @@
<div id="service-labels">
<rd-widget>
<rd-widget-header icon="fa-tasks" title-text="Service labels">
<div class="nopadding">
<div class="nopadding" authorization="DockerServiceUpdate">
<a class="btn btn-default btn-sm pull-right" ng-click="isUpdating || addLabel(service)" ng-disabled="isUpdating">
<i class="fa fa-plus-circle" aria-hidden="true"></i> label
</a>
@ -34,7 +34,7 @@
<div class="input-group input-group-sm">
<span class="input-group-addon fit-text-size">value</span>
<input type="text" class="form-control" ng-model="label.value" placeholder="e.g. bar" ng-change="updateLabel(service, label)" ng-disabled="isUpdating">
<span class="input-group-btn">
<span class="input-group-btn" authorization="DockerServiceUpdate">
<button class="btn btn-sm btn-danger" type="button" ng-click="removeLabel(service, $index)" ng-disabled="isUpdating">
<i class="fa fa-trash" aria-hidden="true"></i>
</button>
@ -45,7 +45,7 @@
</tbody>
</table>
</rd-widget-body>
<rd-widget-footer>
<rd-widget-footer authorization="DockerServiceUpdate">
<div class="btn-toolbar" role="toolbar">
<div class="btn-group" role="group">
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!hasChanges(service, ['ServiceLabels'])" ng-click="updateService(service)">Apply changes</button>

View file

@ -8,7 +8,7 @@
<tr>
<td>Update Parallelism</td>
<td>
<input class="input-sm" type="number" ng-model="service.UpdateParallelism" ng-change="updateServiceAttribute(service, 'UpdateParallelism')" ng-disabled="isUpdating"/>
<input class="input-sm" type="number" ng-model="service.UpdateParallelism" ng-change="updateServiceAttribute(service, 'UpdateParallelism')" disable-authorization="DockerServiceUpdate"/>
</td>
<td>
<p class="small text-muted" style="margin-top: 10px;">
@ -19,7 +19,7 @@
<tr>
<td>Update Delay</td>
<td>
<input class="input-sm" type="text" ng-model="service.UpdateDelay" ng-change="updateServiceAttribute(service, 'UpdateDelay')" ng-pattern="/^([0-9]+)(h|m|s|ms|us|ns)$/i" ng-disabled="isUpdating"/>
<input class="input-sm" type="text" ng-model="service.UpdateDelay" ng-change="updateServiceAttribute(service, 'UpdateDelay')" ng-pattern="/^([0-9]+)(h|m|s|ms|us|ns)$/i" disable-authorization="DockerServiceUpdate"/>
</td>
<td>
<p class="small text-muted" style="margin-top: 10px;">
@ -32,11 +32,11 @@
<td>
<div class="form-group">
<label class="radio-inline">
<input type="radio" name="failure_action" ng-model="service.UpdateFailureAction" value="continue" ng-change="updateServiceAttribute(service, 'UpdateFailureAction')" ng-disabled="isUpdating">
<input type="radio" name="failure_action" ng-model="service.UpdateFailureAction" value="continue" ng-change="updateServiceAttribute(service, 'UpdateFailureAction')" disable-authorization="DockerServiceUpdate">
Continue
</label>
<label class="radio-inline">
<input type="radio" name="failure_action" ng-model="service.UpdateFailureAction" value="pause" ng-change="updateServiceAttribute(service, 'UpdateFailureAction')" ng-disabled="isUpdating">
<input type="radio" name="failure_action" ng-model="service.UpdateFailureAction" value="pause" ng-change="updateServiceAttribute(service, 'UpdateFailureAction')" disable-authorization="DockerServiceUpdate">
Pause
</label>
</div>
@ -52,11 +52,11 @@
<td>
<div class="form-group">
<label class="radio-inline">
<input type="radio" name="updateconfig_order" ng-model="service.UpdateOrder" value="start-first" ng-change="updateServiceAttribute(service, 'UpdateOrder')" ng-disabled="isUpdating">
<input type="radio" name="updateconfig_order" ng-model="service.UpdateOrder" value="start-first" ng-change="updateServiceAttribute(service, 'UpdateOrder')" disable-authorization="DockerServiceUpdate">
start-first
</label>
<label class="radio-inline">
<input type="radio" name="updateconfig_order" ng-model="service.UpdateOrder" value="stop-first" ng-change="updateServiceAttribute(service, 'UpdateOrder')" ng-disabled="isUpdating">
<input type="radio" name="updateconfig_order" ng-model="service.UpdateOrder" value="stop-first" ng-change="updateServiceAttribute(service, 'UpdateOrder')" disable-authorization="DockerServiceUpdate">
stop-first
</label>
</div>
@ -70,7 +70,7 @@
</tbody>
</table>
</rd-widget-body>
<rd-widget-footer>
<rd-widget-footer authorization="DockerServiceUpdate">
<div class="btn-toolbar" role="toolbar">
<div class="btn-group" role="group">
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!hasChanges(service, ['UpdateFailureAction', 'UpdateDelay', 'UpdateParallelism', 'UpdateOrder'])" ng-click="updateService(service)">Apply changes</button>

View file

@ -60,7 +60,7 @@
<td>Replicas</td>
<td>
<span ng-if="service.Mode === 'replicated'">
<input class="input-sm" type="number" ng-model="service.Replicas" ng-change="updateServiceAttribute(service, 'Replicas')" ng-disabled="isUpdating" />
<input class="input-sm" type="number" ng-model="service.Replicas" ng-change="updateServiceAttribute(service, 'Replicas')" disable-authorization="DockerServiceUpdate" />
</span>
</td>
</tr>
@ -68,7 +68,7 @@
<td>Image</td>
<td>
<input type="text" class="form-control" uib-typeahead="image for image in availableImages | filter:$viewValue | limitTo:5"
ng-model="service.Image" ng-change="updateServiceAttribute(service, 'Image')" id="image_name" ng-disabled="isUpdating">
ng-model="service.Image" ng-change="updateServiceAttribute(service, 'Image')" id="image_name" disable-authorization="DockerServiceUpdate">
</td>
</tr>
<tr>
@ -76,7 +76,7 @@
Service webhook
<portainer-tooltip position="top" message="Webhook (or callback URI) used to automate the update of this service. Sending a POST request to this callback URI (without requiring any authentication) will pull the most up-to-date version of the associated image and re-deploy this service."></portainer-tooltip>
<label class="switch" style="margin-left: 20px;">
<input type="checkbox" ng-model="WebhookExists" ng-click="updateWebhook(service)"><i></i>
<input disable-authorization="DockerServiceUpdate" type="checkbox" ng-model="WebhookExists" ng-click="updateWebhook(service)"><i></i>
</label>
</td>
<td ng-if="webhookURL">
@ -89,14 +89,14 @@
</span>
</td>
</tr>
<tr>
<tr authorization="DockerServiceLogs, DockerServiceUpdate, DockerServiceDelete">
<td colspan="2">
<a ng-if="applicationState.endpoint.apiVersion >= 1.30" class="btn btn-primary btn-sm" type="button" ui-sref="docker.services.service.logs({id: service.Id})"><i class="fa fa-file-alt space-right" aria-hidden="true"></i>Service logs</a>
<button type="button" class="btn btn-primary btn-sm" ng-disabled="state.updateInProgress || isUpdating" ng-click="forceUpdateService(service)" button-spinner="state.updateInProgress" ng-if="applicationState.endpoint.apiVersion >= 1.25">
<a authorization="DockerServiceLogs" ng-if="applicationState.endpoint.apiVersion >= 1.30" class="btn btn-primary btn-sm" type="button" ui-sref="docker.services.service.logs({id: service.Id})"><i class="fa fa-file-alt space-right" aria-hidden="true"></i>Service logs</a>
<button authorization="DockerServiceUpdate" type="button" class="btn btn-primary btn-sm" ng-disabled="state.updateInProgress || isUpdating" ng-click="forceUpdateService(service)" button-spinner="state.updateInProgress" ng-if="applicationState.endpoint.apiVersion >= 1.25">
<span ng-hide="state.updateInProgress"><i class="fa fa-sync space-right" aria-hidden="true"></i>Update the service</span>
<span ng-show="state.updateInProgress">Update in progress...</span>
</button>
<button type="button" class="btn btn-danger btn-sm" ng-disabled="state.deletionInProgress || isUpdating" ng-click="removeService()" button-spinner="state.deletionInProgress">
<button authorization="DockerServiceDelete" type="button" class="btn btn-danger btn-sm" ng-disabled="state.deletionInProgress || isUpdating" ng-click="removeService()" button-spinner="state.deletionInProgress">
<span ng-hide="state.deletionInProgress"><i class="fa fa-trash-alt space-right" aria-hidden="true"></i>Delete the service</span>
<span ng-show="state.deletionInProgress">Deletion in progress...</span>
</button>
@ -105,7 +105,7 @@
</tbody>
</table>
</rd-widget-body>
<rd-widget-footer>
<rd-widget-footer authorization="DockerServiceUpdate">
<p class="small text-muted">
Do you need help? View the Docker Service documentation <a href="https://docs.docker.com/engine/reference/commandline/service_update/" target="self">here</a>.
</p>

View file

@ -508,8 +508,7 @@ function ($q, $scope, $transition$, $state, $location, $timeout, $anchorScroll,
$scope.availableLoggingDrivers = data.availableLoggingDrivers;
$scope.availableVolumes = data.volumes;
$scope.allowBindMounts = data.settings.AllowBindMountsForRegularUsers;
var userDetails = Authentication.getUserDetails();
$scope.isAdmin = userDetails.role === 1;
$scope.isAdmin = Authentication.isAdmin();
if (data.webhooks.length > 0) {
var webhook = data.webhooks[0];

View file

@ -60,9 +60,7 @@ function ($q, $scope, SystemService, NodeService, Notifications, StateManager, A
function initView() {
if (StateManager.getState().application.authentication) {
var userDetails = Authentication.getUserDetails();
var isAdmin = userDetails.role === 1 ? true: false;
$scope.isAdmin = isAdmin;
$scope.isAdmin = Authentication.isAdmin();
}
var provider = $scope.applicationState.endpoint.mode.provider;

View file

@ -69,7 +69,7 @@ function ($q, $scope, $state, VolumeService, PluginService, ResourceControlServi
var volumeConfiguration = VolumeService.createVolumeConfiguration(name, driver, driverOptions);
var accessControlData = $scope.formValues.AccessControlData;
var userDetails = Authentication.getUserDetails();
var isAdmin = userDetails.role === 1;
var isAdmin = Authentication.isAdmin();
if (!validateForm(accessControlData, isAdmin)) {
return;

View file

@ -16,7 +16,7 @@
<td>ID</td>
<td>
{{ volume.Id }}
<button class="btn btn-xs btn-danger" ng-click="removeVolume()"><i class="fa fa-trash-alt space-right" aria-hidden="true"></i>Remove this volume</button>
<button authorization="DockerVolumeDelete" class="btn btn-xs btn-danger" ng-click="removeVolume()"><i class="fa fa-trash-alt space-right" aria-hidden="true"></i>Remove this volume</button>
</td>
</tr>
<tr>