Commit 876bb08b by Torkel Ödegaard

Merge branch 'develop' of github.com:grafana/grafana into develop

parents 5360303a 6d86afd4
...@@ -57,6 +57,7 @@ func GetDashboard(c *middleware.Context) Response { ...@@ -57,6 +57,7 @@ func GetDashboard(c *middleware.Context) Response {
canEdit, _ := guardian.CanEdit() canEdit, _ := guardian.CanEdit()
canSave, _ := guardian.CanSave() canSave, _ := guardian.CanSave()
canAdmin, _ := guardian.CanAdmin()
isStarred, err := isDashboardStarredByUser(c, dash.Id) isStarred, err := isDashboardStarredByUser(c, dash.Id)
if err != nil { if err != nil {
...@@ -79,6 +80,7 @@ func GetDashboard(c *middleware.Context) Response { ...@@ -79,6 +80,7 @@ func GetDashboard(c *middleware.Context) Response {
CanStar: c.IsSignedIn, CanStar: c.IsSignedIn,
CanSave: canSave, CanSave: canSave,
CanEdit: canEdit, CanEdit: canEdit,
CanAdmin: canAdmin,
Created: dash.Created, Created: dash.Created,
Updated: dash.Updated, Updated: dash.Updated,
UpdatedBy: updater, UpdatedBy: updater,
......
...@@ -65,6 +65,7 @@ func TestDashboardApiEndpoint(t *testing.T) { ...@@ -65,6 +65,7 @@ func TestDashboardApiEndpoint(t *testing.T) {
Convey("Should not be able to edit or save dashboard", func() { Convey("Should not be able to edit or save dashboard", func() {
So(dash.Meta.CanEdit, ShouldBeFalse) So(dash.Meta.CanEdit, ShouldBeFalse)
So(dash.Meta.CanSave, ShouldBeFalse) So(dash.Meta.CanSave, ShouldBeFalse)
So(dash.Meta.CanAdmin, ShouldBeFalse)
}) })
}) })
...@@ -97,6 +98,7 @@ func TestDashboardApiEndpoint(t *testing.T) { ...@@ -97,6 +98,7 @@ func TestDashboardApiEndpoint(t *testing.T) {
Convey("Should be able to view but not save the dashboard", func() { Convey("Should be able to view but not save the dashboard", func() {
So(dash.Meta.CanEdit, ShouldBeFalse) So(dash.Meta.CanEdit, ShouldBeFalse)
So(dash.Meta.CanSave, ShouldBeFalse) So(dash.Meta.CanSave, ShouldBeFalse)
So(dash.Meta.CanAdmin, ShouldBeFalse)
}) })
}) })
...@@ -130,6 +132,7 @@ func TestDashboardApiEndpoint(t *testing.T) { ...@@ -130,6 +132,7 @@ func TestDashboardApiEndpoint(t *testing.T) {
Convey("Should be able to edit or save dashboard", func() { Convey("Should be able to edit or save dashboard", func() {
So(dash.Meta.CanEdit, ShouldBeTrue) So(dash.Meta.CanEdit, ShouldBeTrue)
So(dash.Meta.CanSave, ShouldBeTrue) So(dash.Meta.CanSave, ShouldBeTrue)
So(dash.Meta.CanAdmin, ShouldBeFalse)
}) })
}) })
...@@ -299,6 +302,50 @@ func TestDashboardApiEndpoint(t *testing.T) { ...@@ -299,6 +302,50 @@ func TestDashboardApiEndpoint(t *testing.T) {
Convey("Should be able to get dashboard with edit rights", func() { Convey("Should be able to get dashboard with edit rights", func() {
So(dash.Meta.CanEdit, ShouldBeTrue) So(dash.Meta.CanEdit, ShouldBeTrue)
So(dash.Meta.CanSave, ShouldBeTrue) So(dash.Meta.CanSave, ShouldBeTrue)
So(dash.Meta.CanAdmin, ShouldBeFalse)
})
})
loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/2", "/api/dashboards/:id", role, func(sc *scenarioContext) {
CallDeleteDashboard(sc)
So(sc.resp.Code, ShouldEqual, 200)
})
loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/id/2/versions/1", "/api/dashboards/id/:dashboardId/versions/:id", role, func(sc *scenarioContext) {
CallGetDashboardVersion(sc)
So(sc.resp.Code, ShouldEqual, 200)
})
loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/id/2/versions", "/api/dashboards/id/:dashboardId/versions", role, func(sc *scenarioContext) {
CallGetDashboardVersions(sc)
So(sc.resp.Code, ShouldEqual, 200)
})
postDashboardScenario("When calling POST on", "/api/dashboards", "/api/dashboards", role, cmd, func(sc *scenarioContext) {
CallPostDashboard(sc)
So(sc.resp.Code, ShouldEqual, 200)
})
})
Convey("When user is an Org Viewer but has an admin permission", func() {
role := m.ROLE_VIEWER
mockResult := []*m.DashboardAclInfoDTO{
{Id: 1, OrgId: 1, DashboardId: 2, UserId: 1, Permission: m.PERMISSION_ADMIN},
}
bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error {
query.Result = mockResult
return nil
})
loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/2", "/api/dashboards/:id", role, func(sc *scenarioContext) {
dash := GetDashboardShouldReturn200(sc)
Convey("Should be able to get dashboard with edit rights", func() {
So(dash.Meta.CanEdit, ShouldBeTrue)
So(dash.Meta.CanSave, ShouldBeTrue)
So(dash.Meta.CanAdmin, ShouldBeTrue)
}) })
}) })
......
...@@ -13,6 +13,7 @@ type DashboardMeta struct { ...@@ -13,6 +13,7 @@ type DashboardMeta struct {
Type string `json:"type,omitempty"` Type string `json:"type,omitempty"`
CanSave bool `json:"canSave"` CanSave bool `json:"canSave"`
CanEdit bool `json:"canEdit"` CanEdit bool `json:"canEdit"`
CanAdmin bool `json:"canAdmin"`
CanStar bool `json:"canStar"` CanStar bool `json:"canStar"`
Slug string `json:"slug"` Slug string `json:"slug"`
Expires time.Time `json:"expires"` Expires time.Time `json:"expires"`
......
...@@ -168,11 +168,13 @@ export class NavModelSrv { ...@@ -168,11 +168,13 @@ export class NavModelSrv {
clickHandler: () => dashNavCtrl.openEditView('annotations') clickHandler: () => dashNavCtrl.openEditView('annotations')
}); });
menu.push({ if (dashboard.meta.canAdmin) {
title: 'Permissions...', menu.push({
icon: 'fa fa-fw fa-lock', title: 'Permissions...',
clickHandler: () => dashNavCtrl.openEditView('permissions') icon: 'fa fa-fw fa-lock',
}); clickHandler: () => dashNavCtrl.openEditView('permissions')
});
}
if (!dashboard.meta.isHome) { if (!dashboard.meta.isHome) {
menu.push({ menu.push({
......
...@@ -45,9 +45,6 @@ export class AclCtrl { ...@@ -45,9 +45,6 @@ export class AclCtrl {
sortItems() { sortItems() {
this.items = _.orderBy(this.items, ['sortRank', 'sortName'], ['desc', 'asc']); 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 {
...@@ -70,9 +67,6 @@ export class AclCtrl { ...@@ -70,9 +67,6 @@ export class AclCtrl {
item.sortName = item.role; item.sortName = item.role;
item.sortRank = 30; item.sortRank = 30;
if (item.role === 'Viewer') { if (item.role === 'Viewer') {
item.sortRank += 2;
}
if (item.role === 'Viewer') {
item.sortRank += 1; item.sortRank += 1;
} }
} }
...@@ -100,7 +94,7 @@ export class AclCtrl { ...@@ -100,7 +94,7 @@ export class AclCtrl {
} }
return this.backendSrv.post(`/api/dashboards/id/${this.dashboard.id}/acl`, { items: updated }).then(() => { return this.backendSrv.post(`/api/dashboards/id/${this.dashboard.id}/acl`, { items: updated }).then(() => {
this.dismiss(); return this.dismiss();
}); });
} }
......
...@@ -2,12 +2,16 @@ import {describe, beforeEach, it, expect, sinon, angularMocks} from 'test/lib/co ...@@ -2,12 +2,16 @@ import {describe, beforeEach, it, expect, sinon, angularMocks} from 'test/lib/co
import {AclCtrl} from '../acl'; import {AclCtrl} from '../acl';
describe('AclCtrl', () => { describe('AclCtrl', () => {
var ctx: any = {}; const ctx: any = {};
var backendSrv = { const backendSrv = {
get: sinon.stub().returns(Promise.resolve([])), get: sinon.stub().returns(Promise.resolve([])),
post: sinon.stub().returns(Promise.resolve([])) post: sinon.stub().returns(Promise.resolve([]))
}; };
const dashboardSrv = {
getCurrent: sinon.stub().returns({id: 1})
};
beforeEach(angularMocks.module('grafana.core')); beforeEach(angularMocks.module('grafana.core'));
beforeEach(angularMocks.module('grafana.controllers')); beforeEach(angularMocks.module('grafana.controllers'));
...@@ -18,64 +22,59 @@ describe('AclCtrl', () => { ...@@ -18,64 +22,59 @@ describe('AclCtrl', () => {
ctx.ctrl = $controller(AclCtrl, { ctx.ctrl = $controller(AclCtrl, {
$scope: ctx.scope, $scope: ctx.scope,
backendSrv: backendSrv, backendSrv: backendSrv,
dashboardSrv: dashboardSrv
}, { }, {
dashboard: {id: 1} dismiss: () => { return; }
}); });
})); }));
describe('when user permission is to be added', () => { describe('when permissions are added', () => {
beforeEach(done => { beforeEach(() => {
backendSrv.get.reset(); backendSrv.get.reset();
backendSrv.post.reset(); backendSrv.post.reset();
ctx.ctrl.type = 'User';
ctx.ctrl.userId = 2;
ctx.ctrl.permission = 1;
ctx.ctrl.addPermission().then(() => { const userItem = {
done(); id: 2,
}); login: 'user2',
}); };
it('should parse the result and save to db', () => { ctx.ctrl.userPicked(userItem);
expect(backendSrv.post.getCall(0).args[0]).to.eql('/api/dashboards/id/1/acl');
expect(backendSrv.post.getCall(0).args[1].userId).to.eql(2);
expect(backendSrv.post.getCall(0).args[1].permissions).to.eql(1);
});
it('should refresh the list after saving.', () => { const userGroupItem = {
expect(backendSrv.get.getCall(0).args[0]).to.eql('/api/dashboards/id/1/acl'); id: 2,
}); name: 'ug1',
};
ctx.ctrl.groupPicked(userGroupItem);
ctx.ctrl.newType = 'Editor';
ctx.ctrl.typeChanged();
it('should reset userId', () => { ctx.ctrl.newType = 'Viewer';
expect(ctx.ctrl.userId).to.eql(null); ctx.ctrl.typeChanged();
}); });
});
describe('when user group permission is to be added', () => { it('should sort the result by role, user group and user', () => {
beforeEach(done => { expect(ctx.ctrl.items[0].role).to.eql('Viewer');
backendSrv.get.reset(); expect(ctx.ctrl.items[1].role).to.eql('Editor');
backendSrv.post.reset(); expect(ctx.ctrl.items[2].userGroupId).to.eql(2);
ctx.ctrl.type = 'User Group'; expect(ctx.ctrl.items[3].userId).to.eql(2);
ctx.ctrl.userGroupId = 2; });
ctx.ctrl.permission = 1;
ctx.ctrl.addPermission().then(() => { it('should save permissions to db', (done) => {
ctx.ctrl.update().then(() => {
done(); done();
}); });
});
it('should parse the result and save to db', () => {
expect(backendSrv.post.getCall(0).args[0]).to.eql('/api/dashboards/id/1/acl'); expect(backendSrv.post.getCall(0).args[0]).to.eql('/api/dashboards/id/1/acl');
expect(backendSrv.post.getCall(0).args[1].userGroupId).to.eql(2); expect(backendSrv.post.getCall(0).args[1].items[0].role).to.eql('Viewer');
expect(backendSrv.post.getCall(0).args[1].permissions).to.eql(1); expect(backendSrv.post.getCall(0).args[1].items[0].permission).to.eql(1);
}); expect(backendSrv.post.getCall(0).args[1].items[1].role).to.eql('Editor');
expect(backendSrv.post.getCall(0).args[1].items[1].permission).to.eql(1);
it('should refresh the list after saving.', () => { expect(backendSrv.post.getCall(0).args[1].items[2].userGroupId).to.eql(2);
expect(backendSrv.get.getCall(0).args[0]).to.eql('/api/dashboards/id/1/acl'); expect(backendSrv.post.getCall(0).args[1].items[2].permission).to.eql(1);
}); expect(backendSrv.post.getCall(0).args[1].items[3].userId).to.eql(2);
expect(backendSrv.post.getCall(0).args[1].items[3].permission).to.eql(1);
it('should reset userGroupId', () => {
expect(ctx.ctrl.userGroupId).to.eql(null);
}); });
}); });
}); });
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
</h2> </h2>
<ul class="gf-tabs"> <ul class="gf-tabs">
<li class="gf-tabs-item" ng-repeat="tab in ::['General', 'Rows', 'Links', 'Time picker', 'Permissions']"> <li class="gf-tabs-item" ng-repeat="tab in ::['General', 'Rows', 'Links', 'Time picker']">
<a class="gf-tabs-link" ng-click="editor.index = $index" ng-class="{active: editor.index === $index}"> <a class="gf-tabs-link" ng-click="editor.index = $index" ng-class="{active: editor.index === $index}">
{{::tab}} {{::tab}}
</a> </a>
......
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