mirror of
https://github.com/portainer/portainer.git
synced 2025-07-22 23:09:41 +02:00
feat(settings): add a setting to disable bind mounts for non-admins (#1237)
* feat(settings): add a setting to disable bind mounts for non-admins * refactor(gruntfile): remove temporary setting
This commit is contained in:
parent
6cfffb38f9
commit
ca9d9b9a77
14 changed files with 105 additions and 35 deletions
16
api/bolt/migrate_dbversion4.go
Normal file
16
api/bolt/migrate_dbversion4.go
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
package bolt
|
||||||
|
|
||||||
|
func (m *Migrator) updateSettingsToVersion5() error {
|
||||||
|
legacySettings, err := m.SettingsService.Settings()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
legacySettings.AllowBindMountsForRegularUsers = true
|
||||||
|
|
||||||
|
err = m.SettingsService.StoreSettings(legacySettings)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -65,6 +65,14 @@ func (m *Migrator) Migrate() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://github.com/portainer/portainer/issues/1235
|
||||||
|
if m.CurrentDBVersion < 5 {
|
||||||
|
err := m.updateSettingsToVersion5()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err := m.VersionService.StoreDBVersion(portainer.DBVersion)
|
err := m.VersionService.StoreDBVersion(portainer.DBVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -125,6 +125,7 @@ func initSettings(settingsService portainer.SettingsService, flags *portainer.CL
|
||||||
portainer.LDAPSearchSettings{},
|
portainer.LDAPSearchSettings{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
AllowBindMountsForRegularUsers: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
if *flags.Templates != "" {
|
if *flags.Templates != "" {
|
||||||
|
|
|
@ -45,18 +45,20 @@ func NewSettingsHandler(bouncer *security.RequestBouncer) *SettingsHandler {
|
||||||
|
|
||||||
type (
|
type (
|
||||||
publicSettingsResponse struct {
|
publicSettingsResponse struct {
|
||||||
LogoURL string `json:"LogoURL"`
|
LogoURL string `json:"LogoURL"`
|
||||||
DisplayExternalContributors bool `json:"DisplayExternalContributors"`
|
DisplayExternalContributors bool `json:"DisplayExternalContributors"`
|
||||||
AuthenticationMethod portainer.AuthenticationMethod `json:"AuthenticationMethod"`
|
AuthenticationMethod portainer.AuthenticationMethod `json:"AuthenticationMethod"`
|
||||||
|
AllowBindMountsForRegularUsers bool `json:"AllowBindMountsForRegularUsers"`
|
||||||
}
|
}
|
||||||
|
|
||||||
putSettingsRequest struct {
|
putSettingsRequest struct {
|
||||||
TemplatesURL string `valid:"required"`
|
TemplatesURL string `valid:"required"`
|
||||||
LogoURL string `valid:""`
|
LogoURL string `valid:""`
|
||||||
BlackListedLabels []portainer.Pair `valid:""`
|
BlackListedLabels []portainer.Pair `valid:""`
|
||||||
DisplayExternalContributors bool `valid:""`
|
DisplayExternalContributors bool `valid:""`
|
||||||
AuthenticationMethod int `valid:"required"`
|
AuthenticationMethod int `valid:"required"`
|
||||||
LDAPSettings portainer.LDAPSettings `valid:""`
|
LDAPSettings portainer.LDAPSettings `valid:""`
|
||||||
|
AllowBindMountsForRegularUsers bool `valid:""`
|
||||||
}
|
}
|
||||||
|
|
||||||
putSettingsLDAPCheckRequest struct {
|
putSettingsLDAPCheckRequest struct {
|
||||||
|
@ -85,9 +87,10 @@ func (handler *SettingsHandler) handleGetPublicSettings(w http.ResponseWriter, r
|
||||||
}
|
}
|
||||||
|
|
||||||
publicSettings := &publicSettingsResponse{
|
publicSettings := &publicSettingsResponse{
|
||||||
LogoURL: settings.LogoURL,
|
LogoURL: settings.LogoURL,
|
||||||
DisplayExternalContributors: settings.DisplayExternalContributors,
|
DisplayExternalContributors: settings.DisplayExternalContributors,
|
||||||
AuthenticationMethod: settings.AuthenticationMethod,
|
AuthenticationMethod: settings.AuthenticationMethod,
|
||||||
|
AllowBindMountsForRegularUsers: settings.AllowBindMountsForRegularUsers,
|
||||||
}
|
}
|
||||||
|
|
||||||
encodeJSON(w, publicSettings, handler.Logger)
|
encodeJSON(w, publicSettings, handler.Logger)
|
||||||
|
@ -109,11 +112,12 @@ func (handler *SettingsHandler) handlePutSettings(w http.ResponseWriter, r *http
|
||||||
}
|
}
|
||||||
|
|
||||||
settings := &portainer.Settings{
|
settings := &portainer.Settings{
|
||||||
TemplatesURL: req.TemplatesURL,
|
TemplatesURL: req.TemplatesURL,
|
||||||
LogoURL: req.LogoURL,
|
LogoURL: req.LogoURL,
|
||||||
BlackListedLabels: req.BlackListedLabels,
|
BlackListedLabels: req.BlackListedLabels,
|
||||||
DisplayExternalContributors: req.DisplayExternalContributors,
|
DisplayExternalContributors: req.DisplayExternalContributors,
|
||||||
LDAPSettings: req.LDAPSettings,
|
LDAPSettings: req.LDAPSettings,
|
||||||
|
AllowBindMountsForRegularUsers: req.AllowBindMountsForRegularUsers,
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.AuthenticationMethod == 1 {
|
if req.AuthenticationMethod == 1 {
|
||||||
|
|
|
@ -70,12 +70,13 @@ type (
|
||||||
|
|
||||||
// Settings represents the application settings.
|
// Settings represents the application settings.
|
||||||
Settings struct {
|
Settings struct {
|
||||||
TemplatesURL string `json:"TemplatesURL"`
|
TemplatesURL string `json:"TemplatesURL"`
|
||||||
LogoURL string `json:"LogoURL"`
|
LogoURL string `json:"LogoURL"`
|
||||||
BlackListedLabels []Pair `json:"BlackListedLabels"`
|
BlackListedLabels []Pair `json:"BlackListedLabels"`
|
||||||
DisplayExternalContributors bool `json:"DisplayExternalContributors"`
|
DisplayExternalContributors bool `json:"DisplayExternalContributors"`
|
||||||
AuthenticationMethod AuthenticationMethod `json:"AuthenticationMethod"`
|
AuthenticationMethod AuthenticationMethod `json:"AuthenticationMethod"`
|
||||||
LDAPSettings LDAPSettings `json:"LDAPSettings"`
|
LDAPSettings LDAPSettings `json:"LDAPSettings"`
|
||||||
|
AllowBindMountsForRegularUsers bool `json:"AllowBindMountsForRegularUsers"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// User represents a user account.
|
// User represents a user account.
|
||||||
|
@ -348,7 +349,7 @@ const (
|
||||||
// APIVersion is the version number of the Portainer API.
|
// APIVersion is the version number of the Portainer API.
|
||||||
APIVersion = "1.14.2"
|
APIVersion = "1.14.2"
|
||||||
// DBVersion is the version number of the Portainer database.
|
// DBVersion is the version number of the Portainer database.
|
||||||
DBVersion = 4
|
DBVersion = 5
|
||||||
// DefaultTemplatesURL represents the default URL for the templates definitions.
|
// DefaultTemplatesURL represents the default URL for the templates definitions.
|
||||||
DefaultTemplatesURL = "https://raw.githubusercontent.com/portainer/templates/master/templates.json"
|
DefaultTemplatesURL = "https://raw.githubusercontent.com/portainer/templates/master/templates.json"
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
// @@OLD_SERVICE_CONTROLLER: this service should be rewritten to use services.
|
// @@OLD_SERVICE_CONTROLLER: this service should be rewritten to use services.
|
||||||
// See app/components/templates/templatesController.js as a reference.
|
// See app/components/templates/templatesController.js as a reference.
|
||||||
angular.module('createContainer', [])
|
angular.module('createContainer', [])
|
||||||
.controller('CreateContainerController', ['$q', '$scope', '$state', '$transition$', '$filter', 'Container', 'ContainerHelper', 'Image', 'ImageHelper', 'Volume', 'NetworkService', 'ResourceControlService', 'Authentication', 'Notifications', 'ContainerService', 'ImageService', 'FormValidator', 'ModalService', 'RegistryService',
|
.controller('CreateContainerController', ['$q', '$scope', '$state', '$transition$', '$filter', 'Container', 'ContainerHelper', 'Image', 'ImageHelper', 'Volume', 'NetworkService', 'ResourceControlService', 'Authentication', 'Notifications', 'ContainerService', 'ImageService', 'FormValidator', 'ModalService', 'RegistryService', 'SettingsService',
|
||||||
function ($q, $scope, $state, $transition$, $filter, Container, ContainerHelper, Image, ImageHelper, Volume, NetworkService, ResourceControlService, Authentication, Notifications, ContainerService, ImageService, FormValidator, ModalService, RegistryService) {
|
function ($q, $scope, $state, $transition$, $filter, Container, ContainerHelper, Image, ImageHelper, Volume, NetworkService, ResourceControlService, Authentication, Notifications, ContainerService, ImageService, FormValidator, ModalService, RegistryService, SettingsService) {
|
||||||
|
|
||||||
$scope.formValues = {
|
$scope.formValues = {
|
||||||
alwaysPull: true,
|
alwaysPull: true,
|
||||||
|
@ -482,6 +482,16 @@ function ($q, $scope, $state, $transition$, $filter, Container, ContainerHelper,
|
||||||
Notifications.error('Failure', e, 'Unable to retrieve running containers');
|
Notifications.error('Failure', e, 'Unable to retrieve running containers');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
SettingsService.publicSettings()
|
||||||
|
.then(function success(data) {
|
||||||
|
$scope.allowBindMounts = data.AllowBindMountsForRegularUsers;
|
||||||
|
})
|
||||||
|
.catch(function error(err) {
|
||||||
|
Notifications.error('Failure', err, 'Unable to retrieve application settings');
|
||||||
|
});
|
||||||
|
|
||||||
|
var userDetails = Authentication.getUserDetails();
|
||||||
|
$scope.isAdmin = userDetails.role === 1 ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateForm(accessControlData, isAdmin) {
|
function validateForm(accessControlData, isAdmin) {
|
||||||
|
|
|
@ -235,7 +235,7 @@
|
||||||
</div>
|
</div>
|
||||||
<!-- !container-path -->
|
<!-- !container-path -->
|
||||||
<!-- volume-type -->
|
<!-- volume-type -->
|
||||||
<div class="input-group col-sm-5" style="margin-left: 5px;">
|
<div class="input-group col-sm-5" style="margin-left: 5px;" ng-if="isAdmin || allowBindMounts">
|
||||||
<div class="btn-group btn-group-sm">
|
<div class="btn-group btn-group-sm">
|
||||||
<label class="btn btn-primary" ng-model="volume.type" uib-btn-radio="'volume'" ng-click="volume.name = ''">Volume</label>
|
<label class="btn btn-primary" ng-model="volume.type" uib-btn-radio="'volume'" ng-click="volume.name = ''">Volume</label>
|
||||||
<label class="btn btn-primary" ng-model="volume.type" uib-btn-radio="'bind'" ng-click="volume.name = ''">Bind</label>
|
<label class="btn btn-primary" ng-model="volume.type" uib-btn-radio="'bind'" ng-click="volume.name = ''">Bind</label>
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
// @@OLD_SERVICE_CONTROLLER: this service should be rewritten to use services.
|
// @@OLD_SERVICE_CONTROLLER: this service should be rewritten to use services.
|
||||||
// See app/components/templates/templatesController.js as a reference.
|
// See app/components/templates/templatesController.js as a reference.
|
||||||
angular.module('createService', [])
|
angular.module('createService', [])
|
||||||
.controller('CreateServiceController', ['$q', '$scope', '$state', '$timeout', 'Service', 'ServiceHelper', 'SecretHelper', 'SecretService', 'VolumeService', 'NetworkService', 'ImageHelper', 'LabelHelper', 'Authentication', 'ResourceControlService', 'Notifications', 'FormValidator', 'RegistryService', 'HttpRequestHelper', 'NodeService',
|
.controller('CreateServiceController', ['$q', '$scope', '$state', '$timeout', 'Service', 'ServiceHelper', 'SecretHelper', 'SecretService', 'VolumeService', 'NetworkService', 'ImageHelper', 'LabelHelper', 'Authentication', 'ResourceControlService', 'Notifications', 'FormValidator', 'RegistryService', 'HttpRequestHelper', 'NodeService', 'SettingsService',
|
||||||
function ($q, $scope, $state, $timeout, Service, ServiceHelper, SecretHelper, SecretService, VolumeService, NetworkService, ImageHelper, LabelHelper, Authentication, ResourceControlService, Notifications, FormValidator, RegistryService, HttpRequestHelper, NodeService) {
|
function ($q, $scope, $state, $timeout, Service, ServiceHelper, SecretHelper, SecretService, VolumeService, NetworkService, ImageHelper, LabelHelper, Authentication, ResourceControlService, Notifications, FormValidator, RegistryService, HttpRequestHelper, NodeService, SettingsService) {
|
||||||
|
|
||||||
$scope.formValues = {
|
$scope.formValues = {
|
||||||
Name: '',
|
Name: '',
|
||||||
|
@ -361,7 +361,8 @@ function ($q, $scope, $state, $timeout, Service, ServiceHelper, SecretHelper, Se
|
||||||
volumes: VolumeService.volumes(),
|
volumes: VolumeService.volumes(),
|
||||||
secrets: apiVersion >= 1.25 ? SecretService.secrets() : [],
|
secrets: apiVersion >= 1.25 ? SecretService.secrets() : [],
|
||||||
networks: NetworkService.networks(true, true, false, false),
|
networks: NetworkService.networks(true, true, false, false),
|
||||||
nodes: NodeService.nodes()
|
nodes: NodeService.nodes(),
|
||||||
|
settings: SettingsService.publicSettings()
|
||||||
})
|
})
|
||||||
.then(function success(data) {
|
.then(function success(data) {
|
||||||
$scope.availableVolumes = data.volumes;
|
$scope.availableVolumes = data.volumes;
|
||||||
|
@ -379,6 +380,10 @@ function ($q, $scope, $state, $timeout, Service, ServiceHelper, SecretHelper, Se
|
||||||
} else {
|
} else {
|
||||||
$scope.state.sliderMaxCpu = 32;
|
$scope.state.sliderMaxCpu = 32;
|
||||||
}
|
}
|
||||||
|
var settings = data.settings;
|
||||||
|
$scope.allowBindMounts = settings.AllowBindMountsForRegularUsers;
|
||||||
|
var userDetails = Authentication.getUserDetails();
|
||||||
|
$scope.isAdmin = userDetails.role === 1 ? true : false;
|
||||||
})
|
})
|
||||||
.catch(function error(err) {
|
.catch(function error(err) {
|
||||||
Notifications.error('Failure', err, 'Unable to initialize view');
|
Notifications.error('Failure', err, 'Unable to initialize view');
|
||||||
|
|
|
@ -223,7 +223,7 @@
|
||||||
<!-- !container-path -->
|
<!-- !container-path -->
|
||||||
<!-- volume-type -->
|
<!-- volume-type -->
|
||||||
<div class="input-group col-sm-5" style="margin-left: 5px;">
|
<div class="input-group col-sm-5" style="margin-left: 5px;">
|
||||||
<div class="btn-group btn-group-sm">
|
<div class="btn-group btn-group-sm" ng-if="isAdmin || allowBindMounts">
|
||||||
<label class="btn btn-primary" ng-model="volume.Type" uib-btn-radio="'volume'" ng-click="volume.name = ''">Volume</label>
|
<label class="btn btn-primary" ng-model="volume.Type" uib-btn-radio="'volume'" ng-click="volume.name = ''">Volume</label>
|
||||||
<label class="btn btn-primary" ng-model="volume.Type" uib-btn-radio="'bind'" ng-click="volume.Id = ''">Bind</label>
|
<label class="btn btn-primary" ng-model="volume.Type" uib-btn-radio="'bind'" ng-click="volume.Id = ''">Bind</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -11,6 +11,22 @@
|
||||||
<rd-widget-header icon="fa-cogs" title="Application settings"></rd-widget-header>
|
<rd-widget-header icon="fa-cogs" title="Application settings"></rd-widget-header>
|
||||||
<rd-widget-body>
|
<rd-widget-body>
|
||||||
<form class="form-horizontal">
|
<form class="form-horizontal">
|
||||||
|
<!-- security -->
|
||||||
|
<div class="col-sm-12 form-section-title">
|
||||||
|
Security
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<label for="toggle_allowbindmounts" class="control-label text-left">
|
||||||
|
Disable bind mounts for non-administrators
|
||||||
|
<portainer-tooltip position="bottom" message="When enabled, regular users will not be able to use bind mounts when creating containers."></portainer-tooltip>
|
||||||
|
</label>
|
||||||
|
<label class="switch" style="margin-left: 20px;">
|
||||||
|
<input type="checkbox" name="toggle_allowbindmounts" ng-model="formValues.restrictBindMounts"><i></i>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- security -->
|
||||||
<!-- logo -->
|
<!-- logo -->
|
||||||
<div class="col-sm-12 form-section-title">
|
<div class="col-sm-12 form-section-title">
|
||||||
Logo
|
Logo
|
||||||
|
|
|
@ -6,6 +6,7 @@ function ($scope, $state, Notifications, SettingsService, StateManager, DEFAULT_
|
||||||
customLogo: false,
|
customLogo: false,
|
||||||
customTemplates: false,
|
customTemplates: false,
|
||||||
externalContributions: false,
|
externalContributions: false,
|
||||||
|
restrictBindMounts: false,
|
||||||
labelName: '',
|
labelName: '',
|
||||||
labelValue: ''
|
labelValue: ''
|
||||||
};
|
};
|
||||||
|
@ -39,6 +40,7 @@ function ($scope, $state, Notifications, SettingsService, StateManager, DEFAULT_
|
||||||
settings.TemplatesURL = DEFAULT_TEMPLATES_URL;
|
settings.TemplatesURL = DEFAULT_TEMPLATES_URL;
|
||||||
}
|
}
|
||||||
settings.DisplayExternalContributors = !$scope.formValues.externalContributions;
|
settings.DisplayExternalContributors = !$scope.formValues.externalContributions;
|
||||||
|
settings.AllowBindMountsForRegularUsers = !$scope.formValues.restrictBindMounts;
|
||||||
|
|
||||||
updateSettings(settings, false);
|
updateSettings(settings, false);
|
||||||
};
|
};
|
||||||
|
@ -81,6 +83,7 @@ function ($scope, $state, Notifications, SettingsService, StateManager, DEFAULT_
|
||||||
$scope.formValues.customTemplates = true;
|
$scope.formValues.customTemplates = true;
|
||||||
}
|
}
|
||||||
$scope.formValues.externalContributions = !settings.DisplayExternalContributors;
|
$scope.formValues.externalContributions = !settings.DisplayExternalContributors;
|
||||||
|
$scope.formValues.restrictBindMounts = !settings.AllowBindMountsForRegularUsers;
|
||||||
})
|
})
|
||||||
.catch(function error(err) {
|
.catch(function error(err) {
|
||||||
Notifications.error('Failure', err, 'Unable to retrieve application settings');
|
Notifications.error('Failure', err, 'Unable to retrieve application settings');
|
||||||
|
|
|
@ -154,7 +154,7 @@
|
||||||
<div class="btn-group btn-group-sm">
|
<div class="btn-group btn-group-sm">
|
||||||
<label class="btn btn-primary" ng-model="volume.type" uib-btn-radio="'auto'" ng-click="volume.name = ''">Auto</label>
|
<label class="btn btn-primary" ng-model="volume.type" uib-btn-radio="'auto'" ng-click="volume.name = ''">Auto</label>
|
||||||
<label class="btn btn-primary" ng-model="volume.type" uib-btn-radio="'volume'" ng-click="volume.name = ''">Volume</label>
|
<label class="btn btn-primary" ng-model="volume.type" uib-btn-radio="'volume'" ng-click="volume.name = ''">Volume</label>
|
||||||
<label class="btn btn-primary" ng-model="volume.type" uib-btn-radio="'bind'" ng-click="volume.name = ''">Bind</label>
|
<label class="btn btn-primary" ng-model="volume.type" uib-btn-radio="'bind'" ng-click="volume.name = ''" ng-if="isAdmin || allowBindMounts">Bind</label>
|
||||||
</div>
|
</div>
|
||||||
<button class="btn btn-sm btn-danger" type="button" ng-click="removeVolume($index)">
|
<button class="btn btn-sm btn-danger" type="button" ng-click="removeVolume($index)">
|
||||||
<i class="fa fa-trash" aria-hidden="true"></i>
|
<i class="fa fa-trash" aria-hidden="true"></i>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
angular.module('templates', [])
|
angular.module('templates', [])
|
||||||
.controller('TemplatesController', ['$scope', '$q', '$state', '$transition$', '$anchorScroll', '$filter', 'ContainerService', 'ContainerHelper', 'ImageService', 'NetworkService', 'TemplateService', 'TemplateHelper', 'VolumeService', 'Notifications', 'Pagination', 'ResourceControlService', 'Authentication', 'FormValidator',
|
.controller('TemplatesController', ['$scope', '$q', '$state', '$transition$', '$anchorScroll', '$filter', 'ContainerService', 'ContainerHelper', 'ImageService', 'NetworkService', 'TemplateService', 'TemplateHelper', 'VolumeService', 'Notifications', 'Pagination', 'ResourceControlService', 'Authentication', 'FormValidator', 'SettingsService',
|
||||||
function ($scope, $q, $state, $transition$, $anchorScroll, $filter, ContainerService, ContainerHelper, ImageService, NetworkService, TemplateService, TemplateHelper, VolumeService, Notifications, Pagination, ResourceControlService, Authentication, FormValidator) {
|
function ($scope, $q, $state, $transition$, $anchorScroll, $filter, ContainerService, ContainerHelper, ImageService, NetworkService, TemplateService, TemplateHelper, VolumeService, Notifications, Pagination, ResourceControlService, Authentication, FormValidator, SettingsService) {
|
||||||
$scope.state = {
|
$scope.state = {
|
||||||
selectedTemplate: null,
|
selectedTemplate: null,
|
||||||
showAdvancedOptions: false,
|
showAdvancedOptions: false,
|
||||||
|
@ -157,7 +157,8 @@ function ($scope, $q, $state, $transition$, $anchorScroll, $filter, ContainerSer
|
||||||
provider === 'DOCKER_STANDALONE' || provider === 'DOCKER_SWARM_MODE',
|
provider === 'DOCKER_STANDALONE' || provider === 'DOCKER_SWARM_MODE',
|
||||||
false,
|
false,
|
||||||
provider === 'DOCKER_SWARM_MODE' && apiVersion >= 1.25,
|
provider === 'DOCKER_SWARM_MODE' && apiVersion >= 1.25,
|
||||||
provider === 'DOCKER_SWARM')
|
provider === 'DOCKER_SWARM'),
|
||||||
|
settings: SettingsService.publicSettings()
|
||||||
})
|
})
|
||||||
.then(function success(data) {
|
.then(function success(data) {
|
||||||
$scope.templates = data.templates;
|
$scope.templates = data.templates;
|
||||||
|
@ -171,6 +172,10 @@ function ($scope, $q, $state, $transition$, $anchorScroll, $filter, ContainerSer
|
||||||
var networks = data.networks;
|
var networks = data.networks;
|
||||||
$scope.availableNetworks = networks;
|
$scope.availableNetworks = networks;
|
||||||
$scope.globalNetworkCount = networks.length;
|
$scope.globalNetworkCount = networks.length;
|
||||||
|
var settings = data.settings;
|
||||||
|
$scope.allowBindMounts = settings.AllowBindMountsForRegularUsers;
|
||||||
|
var userDetails = Authentication.getUserDetails();
|
||||||
|
$scope.isAdmin = userDetails.role === 1 ? true : false;
|
||||||
})
|
})
|
||||||
.catch(function error(err) {
|
.catch(function error(err) {
|
||||||
$scope.templates = [];
|
$scope.templates = [];
|
||||||
|
|
|
@ -5,4 +5,5 @@ function SettingsViewModel(data) {
|
||||||
this.DisplayExternalContributors = data.DisplayExternalContributors;
|
this.DisplayExternalContributors = data.DisplayExternalContributors;
|
||||||
this.AuthenticationMethod = data.AuthenticationMethod;
|
this.AuthenticationMethod = data.AuthenticationMethod;
|
||||||
this.LDAPSettings = data.LDAPSettings;
|
this.LDAPSettings = data.LDAPSettings;
|
||||||
|
this.AllowBindMountsForRegularUsers = data.AllowBindMountsForRegularUsers;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue