acl: more acl work
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
package sqlstore
|
package sqlstore
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/bus"
|
"github.com/grafana/grafana/pkg/bus"
|
||||||
@@ -148,6 +149,12 @@ func GetInheritedDashboardAcl(query *m.GetInheritedDashboardAclQuery) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetDashboardAclInfoList(query *m.GetDashboardAclInfoListQuery) error {
|
func GetDashboardAclInfoList(query *m.GetDashboardAclInfoListQuery) error {
|
||||||
|
dashboardFilter := fmt.Sprintf(`IN (
|
||||||
|
SELECT id FROM dashboard where id = %d
|
||||||
|
UNION
|
||||||
|
SELECT parent_id from dashboard where id = %d
|
||||||
|
)`, query.DashboardId, query.DashboardId)
|
||||||
|
|
||||||
rawSQL := `
|
rawSQL := `
|
||||||
SELECT
|
SELECT
|
||||||
da.id,
|
da.id,
|
||||||
@@ -165,7 +172,7 @@ func GetDashboardAclInfoList(query *m.GetDashboardAclInfoListQuery) error {
|
|||||||
FROM` + dialect.Quote("dashboard_acl") + ` as da
|
FROM` + dialect.Quote("dashboard_acl") + ` as da
|
||||||
LEFT OUTER JOIN ` + dialect.Quote("user") + ` AS u ON u.id = da.user_id
|
LEFT OUTER JOIN ` + dialect.Quote("user") + ` AS u ON u.id = da.user_id
|
||||||
LEFT OUTER JOIN user_group ug on ug.id = da.user_group_id
|
LEFT OUTER JOIN user_group ug on ug.id = da.user_group_id
|
||||||
WHERE dashboard_id = ?
|
WHERE dashboard_id ` + dashboardFilter + `
|
||||||
|
|
||||||
-- Also include default permission if has_acl = 0
|
-- Also include default permission if has_acl = 0
|
||||||
|
|
||||||
@@ -188,8 +195,7 @@ func GetDashboardAclInfoList(query *m.GetDashboardAclInfoListQuery) error {
|
|||||||
`
|
`
|
||||||
|
|
||||||
query.Result = make([]*m.DashboardAclInfoDTO, 0)
|
query.Result = make([]*m.DashboardAclInfoDTO, 0)
|
||||||
|
err := x.SQL(rawSQL, query.DashboardId).Find(&query.Result)
|
||||||
err := x.SQL(rawSQL, query.DashboardId, query.DashboardId).Find(&query.Result)
|
|
||||||
|
|
||||||
for _, p := range query.Result {
|
for _, p := range query.Result {
|
||||||
p.PermissionName = p.Permission.String()
|
p.PermissionName = p.Permission.String()
|
||||||
|
|||||||
@@ -12,19 +12,22 @@
|
|||||||
|
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<table class="filter-table gf-form-group">
|
<table class="filter-table gf-form-group">
|
||||||
<tr ng-repeat="acl in ctrl.items">
|
<tr ng-repeat="acl in ctrl.items" ng-class="{'gf-form-disabled': acl.inherited}">
|
||||||
<td style="width: 100%;">
|
<td style="width: 100%;">
|
||||||
<i class="{{acl.icon}}"></i>
|
<i class="{{acl.icon}}"></i>
|
||||||
<span ng-bind-html="acl.nameHtml"></span>
|
<span ng-bind-html="acl.nameHtml"></span>
|
||||||
</td>
|
</td>
|
||||||
|
<td>
|
||||||
|
<em class="muted no-wrap" ng-show="acl.inherited">Inherited from folder</em>
|
||||||
|
</td>
|
||||||
<td class="query-keyword">Can</td>
|
<td class="query-keyword">Can</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="gf-form-select-wrapper">
|
<div class="gf-form-select-wrapper">
|
||||||
<select class="gf-form-input gf-size-auto" ng-model="acl.permission" ng-options="p.value as p.text for p in ctrl.permissionOptions" ng-change="ctrl.permissionChanged(acl)"></select>
|
<select class="gf-form-input gf-size-auto" ng-model="acl.permission" ng-options="p.value as p.text for p in ctrl.permissionOptions" ng-change="ctrl.permissionChanged(acl)" ng-disabled="acl.inherited"></select>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a class="btn btn-inverse btn-small" ng-click="ctrl.removeItem($index)">
|
<a class="btn btn-inverse btn-small" ng-click="ctrl.removeItem($index)" ng-hide="acl.inherited">
|
||||||
<i class="fa fa-remove"></i>
|
<i class="fa fa-remove"></i>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@@ -39,36 +39,67 @@ export class AclCtrl {
|
|||||||
return this.backendSrv.get(`/api/dashboards/id/${dashboardId}/acl`)
|
return this.backendSrv.get(`/api/dashboards/id/${dashboardId}/acl`)
|
||||||
.then(result => {
|
.then(result => {
|
||||||
this.items = _.map(result, this.prepareViewModel.bind(this));
|
this.items = _.map(result, this.prepareViewModel.bind(this));
|
||||||
|
this.sortItems();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sortItems() {
|
||||||
|
this.items = _.orderBy(this.items, ['sortRank', 'sortName'], ['desc', 'asc']);
|
||||||
|
for (let i of this.items) {
|
||||||
|
console.log(i.sortRank);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
prepareViewModel(item: DashboardAcl): DashboardAcl {
|
prepareViewModel(item: DashboardAcl): DashboardAcl {
|
||||||
|
item.inherited = this.dashboard.id !== item.dashboardId;
|
||||||
|
item.sortRank = 0;
|
||||||
|
|
||||||
if (item.userId > 0) {
|
if (item.userId > 0) {
|
||||||
item.icon = "fa fa-fw fa-user";
|
item.icon = "fa fa-fw fa-user";
|
||||||
item.nameHtml = this.$sce.trustAsHtml(item.userLogin);
|
item.nameHtml = this.$sce.trustAsHtml(item.userLogin);
|
||||||
|
item.sortName = item.userLogin;
|
||||||
|
item.sortRank = 10;
|
||||||
} else if (item.userGroupId > 0) {
|
} else if (item.userGroupId > 0) {
|
||||||
item.icon = "fa fa-fw fa-users";
|
item.icon = "fa fa-fw fa-users";
|
||||||
item.nameHtml = this.$sce.trustAsHtml(item.userGroup);
|
item.nameHtml = this.$sce.trustAsHtml(item.userGroup);
|
||||||
|
item.sortName = item.userGroup;
|
||||||
|
item.sortRank = 20;
|
||||||
} else if (item.role) {
|
} else if (item.role) {
|
||||||
item.icon = "fa fa-fw fa-street-view";
|
item.icon = "fa fa-fw fa-street-view";
|
||||||
item.nameHtml = this.$sce.trustAsHtml(`Everyone with <span class="query-keyword">${item.role}</span> Role`);
|
item.nameHtml = this.$sce.trustAsHtml(`Everyone with <span class="query-keyword">${item.role}</span> Role`);
|
||||||
|
item.sortName = item.role;
|
||||||
|
item.sortRank = 30;
|
||||||
|
if (item.role === 'Viewer') {
|
||||||
|
item.sortRank += 2;
|
||||||
|
}
|
||||||
|
if (item.role === 'Viewer') {
|
||||||
|
item.sortRank += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.inherited) {
|
||||||
|
item.sortRank += 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
update() {
|
update() {
|
||||||
return this.backendSrv.post(`/api/dashboards/id/${this.dashboard.id}/acl`, {
|
var updated = [];
|
||||||
items: this.items.map(item => {
|
for (let item of this.items) {
|
||||||
return {
|
if (item.inherited) {
|
||||||
id: item.id,
|
continue;
|
||||||
userId: item.userId,
|
}
|
||||||
userGroupId: item.userGroupId,
|
updated.push({
|
||||||
role: item.role,
|
id: item.id,
|
||||||
permission: item.permission,
|
userId: item.userId,
|
||||||
};
|
userGroupId: item.userGroupId,
|
||||||
})
|
role: item.role,
|
||||||
}).then(() => {
|
permission: item.permission,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.backendSrv.post(`/api/dashboards/id/${this.dashboard.id}/acl`, { items: updated }).then(() => {
|
||||||
this.dismiss();
|
this.dismiss();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -89,26 +120,22 @@ export class AclCtrl {
|
|||||||
this.canUpdate = true;
|
this.canUpdate = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
userPicked(user) {
|
addNewItem(item) {
|
||||||
this.items.push(this.prepareViewModel({
|
item.dashboardId = this.dashboard.id;
|
||||||
userId: user.id,
|
|
||||||
userLogin: user.login,
|
this.items.push(this.prepareViewModel(item));
|
||||||
permission: 1,
|
this.sortItems();
|
||||||
}));
|
|
||||||
|
|
||||||
this.canUpdate = true;
|
this.canUpdate = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
userPicked(user) {
|
||||||
|
this.addNewItem({userId: user.id, userLogin: user.login, permission: 1,});
|
||||||
this.$scope.$broadcast('user-picker-reset');
|
this.$scope.$broadcast('user-picker-reset');
|
||||||
}
|
}
|
||||||
|
|
||||||
groupPicked(group) {
|
groupPicked(group) {
|
||||||
console.log(group);
|
this.addNewItem({userGroupId: group.id, userGroup: group.name, permission: 1});
|
||||||
this.items.push(this.prepareViewModel({
|
|
||||||
userGroupId: group.id,
|
|
||||||
userGroup: group.name,
|
|
||||||
permission: 1,
|
|
||||||
}));
|
|
||||||
|
|
||||||
this.canUpdate = true;
|
|
||||||
this.$scope.$broadcast('user-group-picker-reset');
|
this.$scope.$broadcast('user-group-picker-reset');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,7 +169,7 @@ export interface DashboardAcl {
|
|||||||
id?: number;
|
id?: number;
|
||||||
dashboardId?: number;
|
dashboardId?: number;
|
||||||
userId?: number;
|
userId?: number;
|
||||||
userLogin?: number;
|
userLogin?: string;
|
||||||
userEmail?: string;
|
userEmail?: string;
|
||||||
userGroupId?: number;
|
userGroupId?: number;
|
||||||
userGroup?: string;
|
userGroup?: string;
|
||||||
@@ -151,6 +178,9 @@ export interface DashboardAcl {
|
|||||||
role?: string;
|
role?: string;
|
||||||
icon?: string;
|
icon?: string;
|
||||||
nameHtml?: string;
|
nameHtml?: string;
|
||||||
|
inherited?: boolean;
|
||||||
|
sortName?: string;
|
||||||
|
sortRank?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
coreModule.directive('dashAclModal', dashAclModal);
|
coreModule.directive('dashAclModal', dashAclModal);
|
||||||
|
|||||||
@@ -333,3 +333,7 @@ a.external-link {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.no-wrap {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ $gf-form-margin: 0.25rem;
|
|||||||
.gf-form-disabled {
|
.gf-form-disabled {
|
||||||
color: $text-color-weak;
|
color: $text-color-weak;
|
||||||
|
|
||||||
.query-keyword,
|
|
||||||
a,
|
a,
|
||||||
.gf-form-input {
|
.gf-form-input {
|
||||||
color: $text-color-weak;
|
color: $text-color-weak;
|
||||||
@@ -101,7 +100,6 @@ $gf-form-margin: 0.25rem;
|
|||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: $input-padding-y $input-padding-x;
|
padding: $input-padding-y $input-padding-x;
|
||||||
margin-right: $gf-form-margin;
|
|
||||||
font-size: $font-size-base;
|
font-size: $font-size-base;
|
||||||
margin-right: $gf-form-margin;
|
margin-right: $gf-form-margin;
|
||||||
line-height: $input-line-height;
|
line-height: $input-line-height;
|
||||||
@@ -153,10 +151,11 @@ $gf-form-margin: 0.25rem;
|
|||||||
|
|
||||||
&::after {
|
&::after {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 35%;
|
top: 36%;
|
||||||
right: $input-padding-x;
|
right: 11px;
|
||||||
|
font-size: 11px;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
color: $input-color;
|
color: $text-color;
|
||||||
font: normal normal normal $font-size-sm/1 FontAwesome;
|
font: normal normal normal $font-size-sm/1 FontAwesome;
|
||||||
content: '\f0d7';
|
content: '\f0d7';
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
@@ -177,7 +176,6 @@ $gf-form-margin: 0.25rem;
|
|||||||
.gf-form-select-wrapper {
|
.gf-form-select-wrapper {
|
||||||
margin-right: $gf-form-margin;
|
margin-right: $gf-form-margin;
|
||||||
position: relative;
|
position: relative;
|
||||||
background-color: $input-bg;
|
|
||||||
|
|
||||||
select.gf-form-input {
|
select.gf-form-input {
|
||||||
text-indent: .01px;
|
text-indent: .01px;
|
||||||
@@ -200,13 +198,14 @@ $gf-form-margin: 0.25rem;
|
|||||||
|
|
||||||
&::after {
|
&::after {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 35%;
|
top: 36%;
|
||||||
right: $input-padding-x/2;
|
right: 11px;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
color: $input-color;
|
color: $text-color;
|
||||||
font: normal normal normal $font-size-sm/1 FontAwesome;
|
font: normal normal normal $font-size-sm/1 FontAwesome;
|
||||||
content: '\f0d7';
|
content: '\f0d7';
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
font-size: 11px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&--has-help-icon {
|
&--has-help-icon {
|
||||||
|
|||||||
@@ -3,6 +3,12 @@
|
|||||||
color: $blue;
|
color: $blue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.gf-form-disabled {
|
||||||
|
.query-keyword {
|
||||||
|
color: darken($blue, 20%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.query-segment-key {
|
.query-segment-key {
|
||||||
//border-right: none;
|
//border-right: none;
|
||||||
//padding-right: 1px;
|
//padding-right: 1px;
|
||||||
|
|||||||
Reference in New Issue
Block a user