From 2d1bd270fbe3965afab589fec897a84237c537ec Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Mon, 5 Feb 2018 13:28:24 +0000 Subject: [PATCH] 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 --- pkg/api/dashboard_acl.go | 6 ++++ pkg/models/dashboard_acl.go | 5 +++ pkg/services/sqlstore/dashboard_acl.go | 32 +++++++++++++++---- .../ManageDashboards/FolderPermissions.tsx | 2 +- .../Permissions/AddPermissions.jest.tsx | 2 +- .../components/Permissions/AddPermissions.tsx | 7 ---- .../Permissions/DashboardPermissions.tsx | 2 +- .../features/dashboard/settings/settings.html | 5 ++- .../features/dashboard/settings/settings.ts | 8 ++++- 9 files changed, 51 insertions(+), 18 deletions(-) diff --git a/pkg/api/dashboard_acl.go b/pkg/api/dashboard_acl.go index 6eb11047723..b5d912d25f1 100644 --- a/pkg/api/dashboard_acl.go +++ b/pkg/api/dashboard_acl.go @@ -24,6 +24,12 @@ func GetDashboardAclList(c *middleware.Context) Response { 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) } diff --git a/pkg/models/dashboard_acl.go b/pkg/models/dashboard_acl.go index fa7ad00de7f..933487650e3 100644 --- a/pkg/models/dashboard_acl.go +++ b/pkg/models/dashboard_acl.go @@ -59,6 +59,11 @@ type DashboardAclInfoDTO struct { Role *RoleType `json:"role,omitempty"` Permission PermissionType `json:"permission"` PermissionName string `json:"permissionName"` + Uid string `json:"uid"` + Title string `json:"title"` + Slug string `json:"slug"` + IsFolder bool `json:"isFolder"` + Url string `json:"url"` } // diff --git a/pkg/services/sqlstore/dashboard_acl.go b/pkg/services/sqlstore/dashboard_acl.go index 9027f74f33a..829182a8195 100644 --- a/pkg/services/sqlstore/dashboard_acl.go +++ b/pkg/services/sqlstore/dashboard_acl.go @@ -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 { return inTransaction(func(sess *DBSession) error { var rawSQL = "DELETE FROM " + dialect.Quote("dashboard_acl") + " WHERE org_id =? and id=?" @@ -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 { var err error @@ -141,7 +147,11 @@ func GetDashboardAclInfoList(query *m.GetDashboardAclInfoListQuery) error { da.updated, '' as user_login, '' as user_email, - '' as team + '' as team, + '' as title, + '' as slug, + '' as uid,` + + dialect.BooleanStr(false) + ` AS is_folder FROM dashboard_acl as da WHERE da.dashboard_id = -1` query.Result = make([]*m.DashboardAclInfoDTO, 0) @@ -155,6 +165,7 @@ func GetDashboardAclInfoList(query *m.GetDashboardAclInfoListQuery) error { )`, query.DashboardId, query.DashboardId) rawSQL := ` + -- get permissions for the dashboard and its parent folder SELECT da.id, da.org_id, @@ -167,13 +178,18 @@ func GetDashboardAclInfoList(query *m.GetDashboardAclInfoListQuery) error { da.updated, u.login AS user_login, 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 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 dashboard d on da.dashboard_id = d.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 SELECT @@ -188,10 +204,14 @@ func GetDashboardAclInfoList(query *m.GetDashboardAclInfoListQuery) error { da.updated, '' as user_login, '' as user_email, - '' as team - FROM dashboard_acl as da, + '' as team, + folder.title, + folder.slug, + folder.uid, + folder.is_folder + FROM dashboard_acl as da, 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 dash.id = ? AND ( dash.has_acl = ` + dialect.BooleanStr(false) + ` or diff --git a/public/app/containers/ManageDashboards/FolderPermissions.tsx b/public/app/containers/ManageDashboards/FolderPermissions.tsx index a62165d7194..500072c1da0 100644 --- a/public/app/containers/ManageDashboards/FolderPermissions.tsx +++ b/public/app/containers/ManageDashboards/FolderPermissions.tsx @@ -63,7 +63,7 @@ export class FolderPermissions extends Component { - + diff --git a/public/app/core/components/Permissions/AddPermissions.jest.tsx b/public/app/core/components/Permissions/AddPermissions.jest.tsx index 98a00a8bd7b..48ff20a16aa 100644 --- a/public/app/core/components/Permissions/AddPermissions.jest.tsx +++ b/public/app/core/components/Permissions/AddPermissions.jest.tsx @@ -26,7 +26,7 @@ describe('AddPermissions', () => { } ); - wrapper = shallow(); + wrapper = shallow(); instance = wrapper.instance(); return store.permissions.load(1, true, false); }); diff --git a/public/app/core/components/Permissions/AddPermissions.tsx b/public/app/core/components/Permissions/AddPermissions.tsx index 3ce4360ff86..94afa7c1180 100644 --- a/public/app/core/components/Permissions/AddPermissions.tsx +++ b/public/app/core/components/Permissions/AddPermissions.tsx @@ -9,7 +9,6 @@ import { permissionOptions } from 'app/stores/PermissionsStore/PermissionsStore' export interface IProps { permissions: any; backendSrv: any; - dashboardId: any; } @observer class AddPermissions extends Component { @@ -31,12 +30,6 @@ class AddPermissions extends Component { const { value } = evt.target; const { permissions } = this.props; - // if (value === 'Viewer' || value === 'Editor') { - // // permissions.addStoreItem({ permission: 1, role: value, dashboardId: dashboardId }, dashboardId); - // // this.resetNewType(); - // return; - // } - permissions.setNewType(value); } diff --git a/public/app/core/components/Permissions/DashboardPermissions.tsx b/public/app/core/components/Permissions/DashboardPermissions.tsx index d6b293da4bb..12339cc7c34 100644 --- a/public/app/core/components/Permissions/DashboardPermissions.tsx +++ b/public/app/core/components/Permissions/DashboardPermissions.tsx @@ -53,7 +53,7 @@ class DashboardPermissions extends Component { - +
- +
+
You have changed folder, please save to view permissions.
+
diff --git a/public/app/features/dashboard/settings/settings.ts b/public/app/features/dashboard/settings/settings.ts index 09aa96e42ae..e9d5c6180be 100755 --- a/public/app/features/dashboard/settings/settings.ts +++ b/public/app/features/dashboard/settings/settings.ts @@ -14,6 +14,7 @@ export class SettingsCtrl { canSave: boolean; canDelete: boolean; sections: any[]; + hasUnsavedFolderChange: boolean; /** @ngInject */ constructor(private $scope, private $location, private $rootScope, private backendSrv, private dashboardSrv) { @@ -38,6 +39,7 @@ export class SettingsCtrl { this.$rootScope.onAppEvent('$routeUpdate', this.onRouteUpdated.bind(this), $scope); this.$rootScope.appEvent('dash-scroll', { animate: false, pos: 0 }); + this.$rootScope.onAppEvent('dashboard-saved', this.onPostSave.bind(this), $scope); } buildSectionList() { @@ -135,6 +137,10 @@ export class SettingsCtrl { this.dashboardSrv.saveDashboard(); } + onPostSave() { + this.hasUnsavedFolderChange = false; + } + hideSettings() { var urlParams = this.$location.search(); delete urlParams.editview; @@ -195,7 +201,7 @@ export class SettingsCtrl { onFolderChange(folder) { this.dashboard.meta.folderId = folder.id; this.dashboard.meta.folderTitle = folder.title; - this.dashboard.meta.folderSlug = folder.slug; + this.hasUnsavedFolderChange = true; } getFolder() {