Commit 2257c1f8 by Torkel Ödegaard

dashboard acl work

parent aab6c98e
...@@ -250,7 +250,7 @@ func (hs *HttpServer) registerRoutes() { ...@@ -250,7 +250,7 @@ func (hs *HttpServer) registerRoutes() {
r.Group("/acl", func() { r.Group("/acl", func() {
r.Get("/", wrap(GetDashboardAclList)) r.Get("/", wrap(GetDashboardAclList))
r.Post("/", bind(m.SetDashboardAclCommand{}), wrap(PostDashboardAcl)) r.Post("/", bind(dtos.UpdateDashboardAclCommand{}), wrap(UpdateDashboardAcl))
r.Delete("/:aclId", wrap(DeleteDashboardAcl)) r.Delete("/:aclId", wrap(DeleteDashboardAcl))
}) })
}, reqSignedIn) }, reqSignedIn)
......
package api package api
import ( import (
"time"
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/metrics" "github.com/grafana/grafana/pkg/metrics"
"github.com/grafana/grafana/pkg/middleware" "github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models" m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/util"
) )
func GetDashboardAclList(c *middleware.Context) Response { func GetDashboardAclList(c *middleware.Context) Response {
...@@ -27,7 +29,7 @@ func GetDashboardAclList(c *middleware.Context) Response { ...@@ -27,7 +29,7 @@ func GetDashboardAclList(c *middleware.Context) Response {
return Json(200, list) return Json(200, list)
} }
func PostDashboardAcl(c *middleware.Context, cmd m.SetDashboardAclCommand) Response { func UpdateDashboardAcl(c *middleware.Context, apiCmd dtos.UpdateDashboardAclCommand) Response {
dashId := c.ParamsInt64(":dashboardId") dashId := c.ParamsInt64(":dashboardId")
guardian := guardian.NewDashboardGuardian(dashId, c.OrgId, c.SignedInUser) guardian := guardian.NewDashboardGuardian(dashId, c.OrgId, c.SignedInUser)
...@@ -35,9 +37,22 @@ func PostDashboardAcl(c *middleware.Context, cmd m.SetDashboardAclCommand) Respo ...@@ -35,9 +37,22 @@ func PostDashboardAcl(c *middleware.Context, cmd m.SetDashboardAclCommand) Respo
return dashboardGuardianResponse(err) return dashboardGuardianResponse(err)
} }
cmd.OrgId = c.OrgId cmd := m.UpdateDashboardAclCommand{}
cmd.DashboardId = dashId cmd.DashboardId = dashId
for _, item := range apiCmd.Items {
cmd.Items = append(cmd.Items, &m.DashboardAcl{
OrgId: c.OrgId,
DashboardId: dashId,
UserId: item.UserId,
UserGroupId: item.UserGroupId,
Role: item.Role,
Permission: item.Permission,
Created: time.Now(),
Updated: time.Now(),
})
}
if err := bus.Dispatch(&cmd); err != nil { if err := bus.Dispatch(&cmd); err != nil {
if err == m.ErrDashboardAclInfoMissing || err == m.ErrDashboardPermissionDashboardEmpty { if err == m.ErrDashboardAclInfoMissing || err == m.ErrDashboardPermissionDashboardEmpty {
return ApiError(409, err.Error(), err) return ApiError(409, err.Error(), err)
...@@ -45,12 +60,8 @@ func PostDashboardAcl(c *middleware.Context, cmd m.SetDashboardAclCommand) Respo ...@@ -45,12 +60,8 @@ func PostDashboardAcl(c *middleware.Context, cmd m.SetDashboardAclCommand) Respo
return ApiError(500, "Failed to create permission", err) return ApiError(500, "Failed to create permission", err)
} }
metrics.M_Api_Dashboard_Acl_Create.Inc(1) metrics.M_Api_Dashboard_Acl_Update.Inc(1)
return ApiSuccess("Dashboard acl updated")
return Json(200, &util.DynMap{
"permissionId": cmd.Result.Id,
"message": "Permission created",
})
} }
func DeleteDashboardAcl(c *middleware.Context) Response { func DeleteDashboardAcl(c *middleware.Context) Response {
......
package dtos
import (
m "github.com/grafana/grafana/pkg/models"
)
type UpdateDashboardAclCommand struct {
Items []DashboardAclUpdateItem `json:"items"`
}
type DashboardAclUpdateItem struct {
UserId int64 `json:"userId"`
UserGroupId int64 `json:"userGroupId"`
Role m.RoleType `json:"role"`
Permission m.PermissionType `json:"permission"`
}
...@@ -36,7 +36,7 @@ var ( ...@@ -36,7 +36,7 @@ var (
M_Api_Dashboard_Snapshot_External Counter M_Api_Dashboard_Snapshot_External Counter
M_Api_Dashboard_Snapshot_Get Counter M_Api_Dashboard_Snapshot_Get Counter
M_Api_UserGroup_Create Counter M_Api_UserGroup_Create Counter
M_Api_Dashboard_Acl_Create Counter M_Api_Dashboard_Acl_Update Counter
M_Models_Dashboard_Insert Counter M_Models_Dashboard_Insert Counter
M_Alerting_Result_State_Alerting Counter M_Alerting_Result_State_Alerting Counter
M_Alerting_Result_State_Ok Counter M_Alerting_Result_State_Ok Counter
...@@ -95,7 +95,7 @@ func initMetricVars(settings *MetricSettings) { ...@@ -95,7 +95,7 @@ func initMetricVars(settings *MetricSettings) {
M_Api_User_SignUpInvite = RegCounter("api.user.signup_invite") M_Api_User_SignUpInvite = RegCounter("api.user.signup_invite")
M_Api_UserGroup_Create = RegCounter("api.usergroup.create") M_Api_UserGroup_Create = RegCounter("api.usergroup.create")
M_Api_Dashboard_Acl_Create = RegCounter("api.dashboard.acl.create") M_Api_Dashboard_Acl_Update = RegCounter("api.dashboard.acl.update")
M_Api_Dashboard_Save = RegTimer("api.dashboard.save") M_Api_Dashboard_Save = RegTimer("api.dashboard.save")
M_Api_Dashboard_Get = RegTimer("api.dashboard.get") M_Api_Dashboard_Get = RegTimer("api.dashboard.get")
......
...@@ -36,6 +36,7 @@ type DashboardAcl struct { ...@@ -36,6 +36,7 @@ type DashboardAcl struct {
UserId int64 UserId int64
UserGroupId int64 UserGroupId int64
Role RoleType
Permission PermissionType Permission PermissionType
Created time.Time Created time.Time
...@@ -64,14 +65,19 @@ type DashboardAclInfoDTO struct { ...@@ -64,14 +65,19 @@ type DashboardAclInfoDTO struct {
// COMMANDS // COMMANDS
// //
type UpdateDashboardAclCommand struct {
DashboardId int64
Items []*DashboardAcl
}
type SetDashboardAclCommand struct { type SetDashboardAclCommand struct {
DashboardId int64 `json:"-"` DashboardId int64
OrgId int64 `json:"-"` OrgId int64
UserId int64 `json:"userId"` UserId int64
UserGroupId int64 `json:"userGroupId"` UserGroupId int64
Permission PermissionType `json:"permission" binding:"Required"` Permission PermissionType
Result DashboardAcl `json:"-"` Result DashboardAcl
} }
type RemoveDashboardAclCommand struct { type RemoveDashboardAclCommand struct {
......
...@@ -9,11 +9,44 @@ import ( ...@@ -9,11 +9,44 @@ import (
func init() { func init() {
bus.AddHandler("sql", SetDashboardAcl) bus.AddHandler("sql", SetDashboardAcl)
bus.AddHandler("sql", UpdateDashboardAcl)
bus.AddHandler("sql", RemoveDashboardAcl) bus.AddHandler("sql", RemoveDashboardAcl)
bus.AddHandler("sql", GetDashboardAclInfoList) bus.AddHandler("sql", GetDashboardAclInfoList)
bus.AddHandler("sql", GetInheritedDashboardAcl) bus.AddHandler("sql", GetInheritedDashboardAcl)
} }
func UpdateDashboardAcl(cmd *m.UpdateDashboardAclCommand) error {
return inTransaction(func(sess *DBSession) error {
// delete existing items
_, err := sess.Exec("DELETE FROM dashboard_acl WHERE dashboard_id=?", cmd.DashboardId)
if err != nil {
return err
}
for _, item := range cmd.Items {
if item.UserId == 0 && item.UserGroupId == 0 && !item.Role.IsValid() {
return m.ErrDashboardAclInfoMissing
}
if item.DashboardId == 0 {
return m.ErrDashboardPermissionDashboardEmpty
}
sess.Nullable("user_id", "user_group_id")
if _, err := sess.Insert(item); err != nil {
return err
}
}
// Update dashboard HasAcl flag
dashboard := m.Dashboard{HasAcl: true}
if _, err := sess.Cols("has_acl").Where("id=? OR parent_id=?", cmd.DashboardId, cmd.DashboardId).Update(&dashboard); err != nil {
return err
}
return nil
})
}
func SetDashboardAcl(cmd *m.SetDashboardAclCommand) error { func SetDashboardAcl(cmd *m.SetDashboardAclCommand) error {
return inTransaction(func(sess *DBSession) error { return inTransaction(func(sess *DBSession) error {
if cmd.UserId == 0 && cmd.UserGroupId == 0 { if cmd.UserId == 0 && cmd.UserGroupId == 0 {
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
<div class="modal-content"> <div class="modal-content">
<table class="filter-table gf-form-group"> <table class="filter-table gf-form-group">
<tr ng-repeat="acl in ctrl.aclItems"> <tr ng-repeat="acl in ctrl.items">
<td style="width: 100%;"> <td style="width: 100%;">
<i class="{{acl.icon}}"></i> <i class="{{acl.icon}}"></i>
<span ng-bind-html="acl.nameHtml"></span> <span ng-bind-html="acl.nameHtml"></span>
......
...@@ -6,7 +6,7 @@ import _ from 'lodash'; ...@@ -6,7 +6,7 @@ import _ from 'lodash';
export class AclCtrl { export class AclCtrl {
dashboard: any; dashboard: any;
aclItems: DashboardAcl[]; items: DashboardAcl[];
permissionOptions = [ permissionOptions = [
{value: 1, text: 'View'}, {value: 1, text: 'View'},
{value: 2, text: 'Edit'}, {value: 2, text: 'Edit'},
...@@ -19,12 +19,13 @@ export class AclCtrl { ...@@ -19,12 +19,13 @@ export class AclCtrl {
{value: 'Editor', text: 'Everyone With Editor Role'} {value: 'Editor', text: 'Everyone With Editor Role'}
]; ];
dismiss: () => void;
newType: string; newType: string;
canUpdate: boolean; canUpdate: boolean;
/** @ngInject */ /** @ngInject */
constructor(private backendSrv, private dashboardSrv, private $sce, private $scope) { constructor(private backendSrv, private dashboardSrv, private $sce, private $scope) {
this.aclItems = []; this.items = [];
this.resetNewType(); this.resetNewType();
this.dashboard = dashboardSrv.getCurrent(); this.dashboard = dashboardSrv.getCurrent();
this.get(this.dashboard.id); this.get(this.dashboard.id);
...@@ -37,7 +38,7 @@ export class AclCtrl { ...@@ -37,7 +38,7 @@ export class AclCtrl {
get(dashboardId: number) { get(dashboardId: number) {
return this.backendSrv.get(`/api/dashboards/id/${dashboardId}/acl`) return this.backendSrv.get(`/api/dashboards/id/${dashboardId}/acl`)
.then(result => { .then(result => {
this.aclItems = _.map(result, this.prepareViewModel.bind(this)); this.items = _.map(result, this.prepareViewModel.bind(this));
}); });
} }
...@@ -58,7 +59,7 @@ export class AclCtrl { ...@@ -58,7 +59,7 @@ export class AclCtrl {
update() { update() {
return this.backendSrv.post(`/api/dashboards/id/${this.dashboard.id}/acl`, { return this.backendSrv.post(`/api/dashboards/id/${this.dashboard.id}/acl`, {
acl: this.aclItems.map(item => { items: this.items.map(item => {
return { return {
id: item.id, id: item.id,
userId: item.userId, userId: item.userId,
...@@ -67,12 +68,14 @@ export class AclCtrl { ...@@ -67,12 +68,14 @@ export class AclCtrl {
permission: item.permission, permission: item.permission,
}; };
}) })
}).then(() => {
this.dismiss();
}); });
} }
typeChanged() { typeChanged() {
if (this.newType === 'Viewer' || this.newType === 'Editor') { if (this.newType === 'Viewer' || this.newType === 'Editor') {
this.aclItems.push(this.prepareViewModel({ this.items.push(this.prepareViewModel({
permission: 1, permission: 1,
role: this.newType role: this.newType
})); }));
...@@ -87,7 +90,7 @@ export class AclCtrl { ...@@ -87,7 +90,7 @@ export class AclCtrl {
} }
userPicked(user) { userPicked(user) {
this.aclItems.push(this.prepareViewModel({ this.items.push(this.prepareViewModel({
userId: user.id, userId: user.id,
userLogin: user.login, userLogin: user.login,
permission: 1, permission: 1,
...@@ -99,7 +102,7 @@ export class AclCtrl { ...@@ -99,7 +102,7 @@ export class AclCtrl {
groupPicked(group) { groupPicked(group) {
console.log(group); console.log(group);
this.aclItems.push(this.prepareViewModel({ this.items.push(this.prepareViewModel({
userGroupId: group.id, userGroupId: group.id,
userGroup: group.name, userGroup: group.name,
permission: 1, permission: 1,
...@@ -110,7 +113,7 @@ export class AclCtrl { ...@@ -110,7 +113,7 @@ export class AclCtrl {
} }
removeItem(index) { removeItem(index) {
this.aclItems.splice(index, 1); this.items.splice(index, 1);
this.canUpdate = true; this.canUpdate = true;
} }
} }
......
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