Merge branch 'develop' into panel-title-menu-ux

This commit is contained in:
Torkel Ödegaard
2017-08-02 09:56:08 +02:00
116 changed files with 5196 additions and 1071 deletions

View File

@@ -0,0 +1,95 @@
package models
import (
"errors"
"time"
)
type PermissionType int
const (
PERMISSION_VIEW PermissionType = 1 << iota
PERMISSION_EDIT
PERMISSION_ADMIN
)
func (p PermissionType) String() string {
names := map[int]string{
int(PERMISSION_VIEW): "View",
int(PERMISSION_EDIT): "Edit",
int(PERMISSION_ADMIN): "Admin",
}
return names[int(p)]
}
// Typed errors
var (
ErrDashboardAclInfoMissing = errors.New("User id and user group id cannot both be empty for a dashboard permission.")
ErrDashboardPermissionDashboardEmpty = errors.New("Dashboard Id must be greater than zero for a dashboard permission.")
)
// Dashboard ACL model
type DashboardAcl struct {
Id int64
OrgId int64
DashboardId int64
UserId int64
UserGroupId int64
Role *RoleType // pointer to be nullable
Permission PermissionType
Created time.Time
Updated time.Time
}
type DashboardAclInfoDTO struct {
Id int64 `json:"id"`
OrgId int64 `json:"-"`
DashboardId int64 `json:"dashboardId"`
Created time.Time `json:"created"`
Updated time.Time `json:"updated"`
UserId int64 `json:"userId"`
UserLogin string `json:"userLogin"`
UserEmail string `json:"userEmail"`
UserGroupId int64 `json:"userGroupId"`
UserGroup string `json:"userGroup"`
Role *RoleType `json:"role,omitempty"`
Permission PermissionType `json:"permission"`
PermissionName string `json:"permissionName"`
}
//
// COMMANDS
//
type UpdateDashboardAclCommand struct {
DashboardId int64
Items []*DashboardAcl
}
type SetDashboardAclCommand struct {
DashboardId int64
OrgId int64
UserId int64
UserGroupId int64
Permission PermissionType
Result DashboardAcl
}
type RemoveDashboardAclCommand struct {
AclId int64
OrgId int64
}
//
// QUERIES
//
type GetDashboardAclInfoListQuery struct {
DashboardId int64
OrgId int64
Result []*DashboardAclInfoDTO
}

View File

@@ -0,0 +1,21 @@
package models
import (
"testing"
"fmt"
. "github.com/smartystreets/goconvey/convey"
)
func TestDashboardAclModel(t *testing.T) {
Convey("When printing a PermissionType", t, func() {
view := PERMISSION_VIEW
printed := fmt.Sprint(view)
Convey("Should output a friendly name", func() {
So(printed, ShouldEqual, "View")
})
})
}

View File

@@ -11,11 +11,12 @@ import (
// Typed errors
var (
ErrDashboardNotFound = errors.New("Dashboard not found")
ErrDashboardSnapshotNotFound = errors.New("Dashboard snapshot not found")
ErrDashboardWithSameNameExists = errors.New("A dashboard with the same name already exists")
ErrDashboardVersionMismatch = errors.New("The dashboard has been changed by someone else")
ErrDashboardTitleEmpty = errors.New("Dashboard title cannot be empty")
ErrDashboardNotFound = errors.New("Dashboard not found")
ErrDashboardSnapshotNotFound = errors.New("Dashboard snapshot not found")
ErrDashboardWithSameNameExists = errors.New("A dashboard with the same name already exists")
ErrDashboardVersionMismatch = errors.New("The dashboard has been changed by someone else")
ErrDashboardTitleEmpty = errors.New("Dashboard title cannot be empty")
ErrDashboardFolderCannotHaveParent = errors.New("A Dashboard Folder cannot be added to another folder")
)
type UpdatePluginDashboardError struct {
@@ -47,6 +48,9 @@ type Dashboard struct {
UpdatedBy int64
CreatedBy int64
FolderId int64
IsFolder bool
HasAcl bool
Title string
Data *simplejson.Json
@@ -111,6 +115,8 @@ func (cmd *SaveDashboardCommand) GetDashboardModel() *Dashboard {
dash.UpdatedBy = userId
dash.OrgId = cmd.OrgId
dash.PluginId = cmd.PluginId
dash.IsFolder = cmd.IsFolder
dash.FolderId = cmd.FolderId
dash.UpdateSlug()
return dash
}
@@ -138,12 +144,14 @@ type SaveDashboardCommand struct {
OrgId int64 `json:"-"`
RestoredFrom int `json:"-"`
PluginId string `json:"-"`
FolderId int64 `json:"folderId"`
IsFolder bool `json:"isFolder"`
Result *Dashboard
}
type DeleteDashboardCommand struct {
Slug string
Id int64
OrgId int64
}

View File

@@ -28,4 +28,27 @@ func TestDashboardModel(t *testing.T) {
})
})
Convey("Given a new dashboard folder", t, func() {
json := simplejson.New()
json.Set("title", "test dash")
cmd := &SaveDashboardCommand{Dashboard: json, IsFolder: true}
dash := cmd.GetDashboardModel()
Convey("Should set IsFolder to true", func() {
So(dash.IsFolder, ShouldBeTrue)
})
})
Convey("Given a child dashboard", t, func() {
json := simplejson.New()
json.Set("title", "test dash")
cmd := &SaveDashboardCommand{Dashboard: json, FolderId: 1}
dash := cmd.GetDashboardModel()
Convey("Should set FolderId", func() {
So(dash.FolderId, ShouldEqual, 1)
})
})
}

View File

@@ -32,11 +32,20 @@ func (r RoleType) Includes(other RoleType) bool {
if r == ROLE_ADMIN {
return true
}
if r == ROLE_EDITOR || r == ROLE_READ_ONLY_EDITOR {
return other != ROLE_ADMIN
if other == ROLE_READ_ONLY_EDITOR {
return r == ROLE_EDITOR || r == ROLE_READ_ONLY_EDITOR
}
return r == other
if other == ROLE_EDITOR {
return r == ROLE_EDITOR
}
if other == ROLE_VIEWER {
return r == ROLE_READ_ONLY_EDITOR || r == ROLE_EDITOR || r == ROLE_VIEWER
}
return false
}
func (r *RoleType) UnmarshalJSON(data []byte) error {

View File

@@ -162,6 +162,14 @@ type SignedInUser struct {
HelpFlags1 HelpFlags1
}
func (user *SignedInUser) HasRole(role RoleType) bool {
if user.IsGrafanaAdmin {
return true
}
return user.OrgRole.Includes(role)
}
type UserProfileDTO struct {
Id int64 `json:"id"`
Email string `json:"email"`

68
pkg/models/user_group.go Normal file
View File

@@ -0,0 +1,68 @@
package models
import (
"errors"
"time"
)
// Typed errors
var (
ErrUserGroupNotFound = errors.New("User Group not found")
ErrUserGroupNameTaken = errors.New("User Group name is taken")
)
// UserGroup model
type UserGroup struct {
Id int64 `json:"id"`
OrgId int64 `json:"orgId"`
Name string `json:"name"`
Created time.Time `json:"created"`
Updated time.Time `json:"updated"`
}
// ---------------------
// COMMANDS
type CreateUserGroupCommand struct {
Name string `json:"name" binding:"Required"`
OrgId int64 `json:"-"`
Result UserGroup `json:"-"`
}
type UpdateUserGroupCommand struct {
Id int64
Name string
}
type DeleteUserGroupCommand struct {
Id int64
}
type GetUserGroupByIdQuery struct {
Id int64
Result *UserGroup
}
type GetUserGroupsByUserQuery struct {
UserId int64 `json:"userId"`
Result []*UserGroup `json:"userGroups"`
}
type SearchUserGroupsQuery struct {
Query string
Name string
Limit int
Page int
OrgId int64
Result SearchUserGroupQueryResult
}
type SearchUserGroupQueryResult struct {
TotalCount int64 `json:"totalCount"`
UserGroups []*UserGroup `json:"userGroups"`
Page int `json:"page"`
PerPage int `json:"perPage"`
}

View File

@@ -0,0 +1,55 @@
package models
import (
"errors"
"time"
)
// Typed errors
var (
ErrUserGroupMemberAlreadyAdded = errors.New("User is already added to this user group")
)
// UserGroupMember model
type UserGroupMember struct {
Id int64
OrgId int64
UserGroupId int64
UserId int64
Created time.Time
Updated time.Time
}
// ---------------------
// COMMANDS
type AddUserGroupMemberCommand struct {
UserId int64 `json:"userId" binding:"Required"`
OrgId int64 `json:"-"`
UserGroupId int64 `json:"-"`
}
type RemoveUserGroupMemberCommand struct {
UserId int64
UserGroupId int64
}
// ----------------------
// QUERIES
type GetUserGroupMembersQuery struct {
UserGroupId int64
Result []*UserGroupMemberDTO
}
// ----------------------
// Projections and DTOs
type UserGroupMemberDTO struct {
OrgId int64 `json:"orgId"`
UserGroupId int64 `json:"userGroupId"`
UserId int64 `json:"userId"`
Email string `json:"email"`
Login string `json:"login"`
}