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 {
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)
}
......
......@@ -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"`
}
//
......
......@@ -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
......
......@@ -63,7 +63,7 @@ export class FolderPermissions extends Component<IContainerProps, any> {
</button>
</div>
<SlideDown in={permissions.isAddPermissionsVisible}>
<AddPermissions permissions={permissions} backendSrv={backendSrv} dashboardId={dashboardId} />
<AddPermissions permissions={permissions} backendSrv={backendSrv} />
</SlideDown>
<Permissions permissions={permissions} isFolder={true} dashboardId={dashboardId} backendSrv={backendSrv} />
</div>
......
......@@ -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();
return store.permissions.load(1, true, false);
});
......
......@@ -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<IProps, any> {
......@@ -31,12 +30,6 @@ class AddPermissions extends Component<IProps, any> {
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);
}
......
......@@ -53,7 +53,7 @@ class DashboardPermissions extends Component<IProps, any> {
</div>
</div>
<SlideDown in={this.permissions.isAddPermissionsVisible}>
<AddPermissions permissions={this.permissions} backendSrv={backendSrv} dashboardId={dashboardId} />
<AddPermissions permissions={this.permissions} backendSrv={backendSrv} />
</SlideDown>
<Permissions
permissions={this.permissions}
......
......@@ -96,11 +96,14 @@
</div>
<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"
backendSrv="ctrl.backendSrv"
folder="ctrl.getFolder()"
/>
<div ng-if="ctrl.hasUnsavedFolderChange">
<h5>You have changed folder, please save to view permissions.</h5>
</div>
</div>
<div class="dashboard-settings__content" ng-if="ctrl.viewId === '404'">
......
......@@ -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() {
......
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