Commit 2d1bd270 by Daniel Lee Committed by Torkel Ödegaard

Stale permissions (#10768)

* dashfolders: hide permissions in settings if folder has changed

and the dashboard has not been saved yet. Otherwise the use will
see stale permissions from the original folder.

* dashfolders: return folder url for inherited permissions
parent 04a94ce3
...@@ -24,6 +24,12 @@ func GetDashboardAclList(c *middleware.Context) Response { ...@@ -24,6 +24,12 @@ func GetDashboardAclList(c *middleware.Context) Response {
return ApiError(500, "Failed to get dashboard acl", err) return ApiError(500, "Failed to get dashboard acl", err)
} }
for _, perm := range acl {
if perm.Slug != "" {
perm.Url = m.GetDashboardFolderUrl(perm.IsFolder, perm.Uid, perm.Slug)
}
}
return Json(200, acl) return Json(200, acl)
} }
......
...@@ -59,6 +59,11 @@ type DashboardAclInfoDTO struct { ...@@ -59,6 +59,11 @@ type DashboardAclInfoDTO struct {
Role *RoleType `json:"role,omitempty"` Role *RoleType `json:"role,omitempty"`
Permission PermissionType `json:"permission"` Permission PermissionType `json:"permission"`
PermissionName string `json:"permissionName"` PermissionName string `json:"permissionName"`
Uid string `json:"uid"`
Title string `json:"title"`
Slug string `json:"slug"`
IsFolder bool `json:"isFolder"`
Url string `json:"url"`
} }
// //
......
...@@ -113,6 +113,7 @@ func SetDashboardAcl(cmd *m.SetDashboardAclCommand) error { ...@@ -113,6 +113,7 @@ func SetDashboardAcl(cmd *m.SetDashboardAclCommand) error {
}) })
} }
// RemoveDashboardAcl removes a specified permission from the dashboard acl
func RemoveDashboardAcl(cmd *m.RemoveDashboardAclCommand) error { func RemoveDashboardAcl(cmd *m.RemoveDashboardAclCommand) error {
return inTransaction(func(sess *DBSession) error { return inTransaction(func(sess *DBSession) error {
var rawSQL = "DELETE FROM " + dialect.Quote("dashboard_acl") + " WHERE org_id =? and id=?" var rawSQL = "DELETE FROM " + dialect.Quote("dashboard_acl") + " WHERE org_id =? and id=?"
...@@ -125,6 +126,11 @@ func RemoveDashboardAcl(cmd *m.RemoveDashboardAclCommand) error { ...@@ -125,6 +126,11 @@ func RemoveDashboardAcl(cmd *m.RemoveDashboardAclCommand) error {
}) })
} }
// GetDashboardAclInfoList returns a list of permissions for a dashboard. They can be fetched from three
// different places.
// 1) Permissions for the dashboard
// 2) permissions for its parent folder
// 3) if no specific permissions have been set for the dashboard or its parent folder then get the default permissions
func GetDashboardAclInfoList(query *m.GetDashboardAclInfoListQuery) error { func GetDashboardAclInfoList(query *m.GetDashboardAclInfoListQuery) error {
var err error var err error
...@@ -141,7 +147,11 @@ func GetDashboardAclInfoList(query *m.GetDashboardAclInfoListQuery) error { ...@@ -141,7 +147,11 @@ func GetDashboardAclInfoList(query *m.GetDashboardAclInfoListQuery) error {
da.updated, da.updated,
'' as user_login, '' as user_login,
'' as user_email, '' as user_email,
'' as team '' as team,
'' as title,
'' as slug,
'' as uid,` +
dialect.BooleanStr(false) + ` AS is_folder
FROM dashboard_acl as da FROM dashboard_acl as da
WHERE da.dashboard_id = -1` WHERE da.dashboard_id = -1`
query.Result = make([]*m.DashboardAclInfoDTO, 0) query.Result = make([]*m.DashboardAclInfoDTO, 0)
...@@ -155,6 +165,7 @@ func GetDashboardAclInfoList(query *m.GetDashboardAclInfoListQuery) error { ...@@ -155,6 +165,7 @@ func GetDashboardAclInfoList(query *m.GetDashboardAclInfoListQuery) error {
)`, query.DashboardId, query.DashboardId) )`, query.DashboardId, query.DashboardId)
rawSQL := ` rawSQL := `
-- get permissions for the dashboard and its parent folder
SELECT SELECT
da.id, da.id,
da.org_id, da.org_id,
...@@ -167,13 +178,18 @@ func GetDashboardAclInfoList(query *m.GetDashboardAclInfoListQuery) error { ...@@ -167,13 +178,18 @@ func GetDashboardAclInfoList(query *m.GetDashboardAclInfoListQuery) error {
da.updated, da.updated,
u.login AS user_login, u.login AS user_login,
u.email AS user_email, u.email AS user_email,
ug.name AS team ug.name AS team,
d.title,
d.slug,
d.uid,
d.is_folder
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 team ug on ug.id = da.team_id LEFT OUTER JOIN team ug on ug.id = da.team_id
LEFT OUTER JOIN dashboard d on da.dashboard_id = d.id
WHERE dashboard_id ` + dashboardFilter + ` AND da.org_id = ? WHERE dashboard_id ` + dashboardFilter + ` AND da.org_id = ?
-- Also include default permission if has_acl = 0 -- Also include default permissions if folder or dashboard field "has_acl" is false
UNION UNION
SELECT SELECT
...@@ -188,10 +204,14 @@ func GetDashboardAclInfoList(query *m.GetDashboardAclInfoListQuery) error { ...@@ -188,10 +204,14 @@ func GetDashboardAclInfoList(query *m.GetDashboardAclInfoListQuery) error {
da.updated, da.updated,
'' as user_login, '' as user_login,
'' as user_email, '' as user_email,
'' as team '' as team,
FROM dashboard_acl as da, folder.title,
folder.slug,
folder.uid,
folder.is_folder
FROM dashboard_acl as da,
dashboard as dash dashboard as dash
LEFT JOIN dashboard folder on dash.folder_id = folder.id LEFT OUTER JOIN dashboard folder on dash.folder_id = folder.id
WHERE WHERE
dash.id = ? AND ( dash.id = ? AND (
dash.has_acl = ` + dialect.BooleanStr(false) + ` or dash.has_acl = ` + dialect.BooleanStr(false) + ` or
......
...@@ -63,7 +63,7 @@ export class FolderPermissions extends Component<IContainerProps, any> { ...@@ -63,7 +63,7 @@ export class FolderPermissions extends Component<IContainerProps, any> {
</button> </button>
</div> </div>
<SlideDown in={permissions.isAddPermissionsVisible}> <SlideDown in={permissions.isAddPermissionsVisible}>
<AddPermissions permissions={permissions} backendSrv={backendSrv} dashboardId={dashboardId} /> <AddPermissions permissions={permissions} backendSrv={backendSrv} />
</SlideDown> </SlideDown>
<Permissions permissions={permissions} isFolder={true} dashboardId={dashboardId} backendSrv={backendSrv} /> <Permissions permissions={permissions} isFolder={true} dashboardId={dashboardId} backendSrv={backendSrv} />
</div> </div>
......
...@@ -26,7 +26,7 @@ describe('AddPermissions', () => { ...@@ -26,7 +26,7 @@ describe('AddPermissions', () => {
} }
); );
wrapper = shallow(<AddPermissions permissions={store.permissions} backendSrv={backendSrv} dashboardId={1} />); wrapper = shallow(<AddPermissions permissions={store.permissions} backendSrv={backendSrv} />);
instance = wrapper.instance(); instance = wrapper.instance();
return store.permissions.load(1, true, false); return store.permissions.load(1, true, false);
}); });
......
...@@ -9,7 +9,6 @@ import { permissionOptions } from 'app/stores/PermissionsStore/PermissionsStore' ...@@ -9,7 +9,6 @@ import { permissionOptions } from 'app/stores/PermissionsStore/PermissionsStore'
export interface IProps { export interface IProps {
permissions: any; permissions: any;
backendSrv: any; backendSrv: any;
dashboardId: any;
} }
@observer @observer
class AddPermissions extends Component<IProps, any> { class AddPermissions extends Component<IProps, any> {
...@@ -31,12 +30,6 @@ class AddPermissions extends Component<IProps, any> { ...@@ -31,12 +30,6 @@ class AddPermissions extends Component<IProps, any> {
const { value } = evt.target; const { value } = evt.target;
const { permissions } = this.props; const { permissions } = this.props;
// if (value === 'Viewer' || value === 'Editor') {
// // permissions.addStoreItem({ permission: 1, role: value, dashboardId: dashboardId }, dashboardId);
// // this.resetNewType();
// return;
// }
permissions.setNewType(value); permissions.setNewType(value);
} }
......
...@@ -53,7 +53,7 @@ class DashboardPermissions extends Component<IProps, any> { ...@@ -53,7 +53,7 @@ class DashboardPermissions extends Component<IProps, any> {
</div> </div>
</div> </div>
<SlideDown in={this.permissions.isAddPermissionsVisible}> <SlideDown in={this.permissions.isAddPermissionsVisible}>
<AddPermissions permissions={this.permissions} backendSrv={backendSrv} dashboardId={dashboardId} /> <AddPermissions permissions={this.permissions} backendSrv={backendSrv} />
</SlideDown> </SlideDown>
<Permissions <Permissions
permissions={this.permissions} permissions={this.permissions}
......
...@@ -96,11 +96,14 @@ ...@@ -96,11 +96,14 @@
</div> </div>
<div class="dashboard-settings__content" ng-if="ctrl.viewId === 'permissions'" > <div class="dashboard-settings__content" ng-if="ctrl.viewId === 'permissions'" >
<dashboard-permissions ng-if="ctrl.dashboard" <dashboard-permissions ng-if="ctrl.dashboard && !ctrl.hasUnsavedFolderChange"
dashboardId="ctrl.dashboard.id" dashboardId="ctrl.dashboard.id"
backendSrv="ctrl.backendSrv" backendSrv="ctrl.backendSrv"
folder="ctrl.getFolder()" folder="ctrl.getFolder()"
/> />
<div ng-if="ctrl.hasUnsavedFolderChange">
<h5>You have changed folder, please save to view permissions.</h5>
</div>
</div> </div>
<div class="dashboard-settings__content" ng-if="ctrl.viewId === '404'"> <div class="dashboard-settings__content" ng-if="ctrl.viewId === '404'">
......
...@@ -14,6 +14,7 @@ export class SettingsCtrl { ...@@ -14,6 +14,7 @@ export class SettingsCtrl {
canSave: boolean; canSave: boolean;
canDelete: boolean; canDelete: boolean;
sections: any[]; sections: any[];
hasUnsavedFolderChange: boolean;
/** @ngInject */ /** @ngInject */
constructor(private $scope, private $location, private $rootScope, private backendSrv, private dashboardSrv) { constructor(private $scope, private $location, private $rootScope, private backendSrv, private dashboardSrv) {
...@@ -38,6 +39,7 @@ export class SettingsCtrl { ...@@ -38,6 +39,7 @@ export class SettingsCtrl {
this.$rootScope.onAppEvent('$routeUpdate', this.onRouteUpdated.bind(this), $scope); this.$rootScope.onAppEvent('$routeUpdate', this.onRouteUpdated.bind(this), $scope);
this.$rootScope.appEvent('dash-scroll', { animate: false, pos: 0 }); this.$rootScope.appEvent('dash-scroll', { animate: false, pos: 0 });
this.$rootScope.onAppEvent('dashboard-saved', this.onPostSave.bind(this), $scope);
} }
buildSectionList() { buildSectionList() {
...@@ -135,6 +137,10 @@ export class SettingsCtrl { ...@@ -135,6 +137,10 @@ export class SettingsCtrl {
this.dashboardSrv.saveDashboard(); this.dashboardSrv.saveDashboard();
} }
onPostSave() {
this.hasUnsavedFolderChange = false;
}
hideSettings() { hideSettings() {
var urlParams = this.$location.search(); var urlParams = this.$location.search();
delete urlParams.editview; delete urlParams.editview;
...@@ -195,7 +201,7 @@ export class SettingsCtrl { ...@@ -195,7 +201,7 @@ export class SettingsCtrl {
onFolderChange(folder) { onFolderChange(folder) {
this.dashboard.meta.folderId = folder.id; this.dashboard.meta.folderId = folder.id;
this.dashboard.meta.folderTitle = folder.title; this.dashboard.meta.folderTitle = folder.title;
this.dashboard.meta.folderSlug = folder.slug; this.hasUnsavedFolderChange = true;
} }
getFolder() { getFolder() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment