Explorar o código

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

Torkel Ödegaard %!s(int64=8) %!d(string=hai) anos
pai
achega
876bb08b05

+ 2 - 0
pkg/api/dashboard.go

@@ -57,6 +57,7 @@ func GetDashboard(c *middleware.Context) Response {
 
 	canEdit, _ := guardian.CanEdit()
 	canSave, _ := guardian.CanSave()
+	canAdmin, _ := guardian.CanAdmin()
 
 	isStarred, err := isDashboardStarredByUser(c, dash.Id)
 	if err != nil {
@@ -79,6 +80,7 @@ func GetDashboard(c *middleware.Context) Response {
 		CanStar:     c.IsSignedIn,
 		CanSave:     canSave,
 		CanEdit:     canEdit,
+		CanAdmin:    canAdmin,
 		Created:     dash.Created,
 		Updated:     dash.Updated,
 		UpdatedBy:   updater,

+ 47 - 0
pkg/api/dashboard_test.go

@@ -65,6 +65,7 @@ func TestDashboardApiEndpoint(t *testing.T) {
 				Convey("Should not be able to edit or save dashboard", func() {
 					So(dash.Meta.CanEdit, ShouldBeFalse)
 					So(dash.Meta.CanSave, ShouldBeFalse)
+					So(dash.Meta.CanAdmin, ShouldBeFalse)
 				})
 			})
 
@@ -97,6 +98,7 @@ func TestDashboardApiEndpoint(t *testing.T) {
 				Convey("Should be able to view but not save the dashboard", func() {
 					So(dash.Meta.CanEdit, ShouldBeFalse)
 					So(dash.Meta.CanSave, ShouldBeFalse)
+					So(dash.Meta.CanAdmin, ShouldBeFalse)
 				})
 			})
 
@@ -130,6 +132,7 @@ func TestDashboardApiEndpoint(t *testing.T) {
 				Convey("Should be able to edit or save dashboard", func() {
 					So(dash.Meta.CanEdit, ShouldBeTrue)
 					So(dash.Meta.CanSave, ShouldBeTrue)
+					So(dash.Meta.CanAdmin, ShouldBeFalse)
 				})
 			})
 
@@ -299,6 +302,50 @@ func TestDashboardApiEndpoint(t *testing.T) {
 				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, 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)
 				})
 			})
 

+ 1 - 0
pkg/api/dtos/dashboard.go

@@ -13,6 +13,7 @@ type DashboardMeta struct {
 	Type        string    `json:"type,omitempty"`
 	CanSave     bool      `json:"canSave"`
 	CanEdit     bool      `json:"canEdit"`
+	CanAdmin    bool      `json:"canAdmin"`
 	CanStar     bool      `json:"canStar"`
 	Slug        string    `json:"slug"`
 	Expires     time.Time `json:"expires"`

+ 7 - 5
public/app/core/nav_model_srv.ts

@@ -168,11 +168,13 @@ export class NavModelSrv {
         clickHandler: () => dashNavCtrl.openEditView('annotations')
       });
 
-      menu.push({
-        title: 'Permissions...',
-        icon: 'fa fa-fw fa-lock',
-        clickHandler: () => dashNavCtrl.openEditView('permissions')
-      });
+      if (dashboard.meta.canAdmin) {
+        menu.push({
+          title: 'Permissions...',
+          icon: 'fa fa-fw fa-lock',
+          clickHandler: () => dashNavCtrl.openEditView('permissions')
+        });
+      }
 
       if (!dashboard.meta.isHome) {
         menu.push({

+ 1 - 7
public/app/features/dashboard/acl/acl.ts

@@ -45,9 +45,6 @@ export class AclCtrl {
 
   sortItems() {
     this.items = _.orderBy(this.items, ['sortRank', 'sortName'], ['desc', 'asc']);
-    for (let i of this.items) {
-      console.log(i.sortRank);
-    }
   }
 
   prepareViewModel(item: DashboardAcl): DashboardAcl {
@@ -69,9 +66,6 @@ export class AclCtrl {
       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;
       }
@@ -100,7 +94,7 @@ export class AclCtrl {
     }
 
     return this.backendSrv.post(`/api/dashboards/id/${this.dashboard.id}/acl`, { items: updated }).then(() => {
-      this.dismiss();
+      return this.dismiss();
     });
   }
 

+ 42 - 43
public/app/features/dashboard/acl/specs/acl_specs.ts

@@ -2,12 +2,16 @@ import {describe, beforeEach, it, expect, sinon, angularMocks} from 'test/lib/co
 import {AclCtrl} from '../acl';
 
 describe('AclCtrl', () => {
-  var ctx: any = {};
-  var backendSrv = {
+  const ctx: any = {};
+  const backendSrv = {
     get: 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.controllers'));
 
@@ -18,64 +22,59 @@ describe('AclCtrl', () => {
     ctx.ctrl = $controller(AclCtrl, {
       $scope: ctx.scope,
       backendSrv: backendSrv,
+      dashboardSrv: dashboardSrv
     }, {
-      dashboard: {id: 1}
+      dismiss: () => { return; }
     });
   }));
 
-  describe('when user permission is to be added', () => {
-    beforeEach(done => {
+  describe('when permissions are added', () => {
+    beforeEach(() => {
       backendSrv.get.reset();
       backendSrv.post.reset();
-      ctx.ctrl.type = 'User';
-      ctx.ctrl.userId = 2;
-      ctx.ctrl.permission = 1;
 
-      ctx.ctrl.addPermission().then(() => {
-        done();
-      });
-    });
+      const userItem = {
+        id: 2,
+        login: 'user2',
+      };
 
-    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[1].userId).to.eql(2);
-      expect(backendSrv.post.getCall(0).args[1].permissions).to.eql(1);
-    });
+      ctx.ctrl.userPicked(userItem);
 
-    it('should refresh the list after saving.', () => {
-      expect(backendSrv.get.getCall(0).args[0]).to.eql('/api/dashboards/id/1/acl');
-    });
+      const userGroupItem = {
+        id: 2,
+        name: 'ug1',
+      };
+
+      ctx.ctrl.groupPicked(userGroupItem);
+
+      ctx.ctrl.newType = 'Editor';
+      ctx.ctrl.typeChanged();
 
-     it('should reset userId', () => {
-      expect(ctx.ctrl.userId).to.eql(null);
+      ctx.ctrl.newType = 'Viewer';
+      ctx.ctrl.typeChanged();
     });
-  });
 
-  describe('when user group permission is to be added', () => {
-    beforeEach(done => {
-      backendSrv.get.reset();
-      backendSrv.post.reset();
-      ctx.ctrl.type = 'User Group';
-      ctx.ctrl.userGroupId = 2;
-      ctx.ctrl.permission = 1;
+     it('should sort the result by role, user group and user', () => {
+        expect(ctx.ctrl.items[0].role).to.eql('Viewer');
+        expect(ctx.ctrl.items[1].role).to.eql('Editor');
+        expect(ctx.ctrl.items[2].userGroupId).to.eql(2);
+        expect(ctx.ctrl.items[3].userId).to.eql(2);
+      });
 
-      ctx.ctrl.addPermission().then(() => {
+    it('should save permissions to db', (done) => {
+      ctx.ctrl.update().then(() => {
         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[1].userGroupId).to.eql(2);
-      expect(backendSrv.post.getCall(0).args[1].permissions).to.eql(1);
-    });
-
-    it('should refresh the list after saving.', () => {
-      expect(backendSrv.get.getCall(0).args[0]).to.eql('/api/dashboards/id/1/acl');
-    });
-
-     it('should reset userGroupId', () => {
-      expect(ctx.ctrl.userGroupId).to.eql(null);
+      expect(backendSrv.post.getCall(0).args[1].items[0].role).to.eql('Viewer');
+      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);
+      expect(backendSrv.post.getCall(0).args[1].items[2].userGroupId).to.eql(2);
+      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);
     });
   });
 });

+ 1 - 1
public/app/features/dashboard/partials/settings.html

@@ -4,7 +4,7 @@
 	</h2>
 
 	<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}">
 				{{::tab}}
 			</a>