|
@@ -0,0 +1,343 @@
|
|
|
|
|
+package sqlstore
|
|
|
|
|
+
|
|
|
|
|
+import (
|
|
|
|
|
+ "context"
|
|
|
|
|
+ "math/rand"
|
|
|
|
|
+ "testing"
|
|
|
|
|
+ "time"
|
|
|
|
|
+
|
|
|
|
|
+ "github.com/grafana/grafana/pkg/components/simplejson"
|
|
|
|
|
+ "github.com/grafana/grafana/pkg/models"
|
|
|
|
|
+ "github.com/stretchr/testify/assert"
|
|
|
|
|
+)
|
|
|
|
|
+
|
|
|
|
|
+func TestSqlBuilder(t *testing.T) {
|
|
|
|
|
+ t.Run("writeDashboardPermissionFilter", func(t *testing.T) {
|
|
|
|
|
+ t.Run("user ACL", func(t *testing.T) {
|
|
|
|
|
+ test(t,
|
|
|
|
|
+ DashboardProps{},
|
|
|
|
|
+ &DashboardPermission{User: true, Permission: models.PERMISSION_VIEW},
|
|
|
|
|
+ Search{UserFromACL: true, RequiredPermission: models.PERMISSION_VIEW},
|
|
|
|
|
+ shouldFind,
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ test(t,
|
|
|
|
|
+ DashboardProps{},
|
|
|
|
|
+ &DashboardPermission{User: true, Permission: models.PERMISSION_VIEW},
|
|
|
|
|
+ Search{UserFromACL: true, RequiredPermission: models.PERMISSION_EDIT},
|
|
|
|
|
+ shouldNotFind,
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ test(t,
|
|
|
|
|
+ DashboardProps{},
|
|
|
|
|
+ &DashboardPermission{User: true, Permission: models.PERMISSION_EDIT},
|
|
|
|
|
+ Search{UserFromACL: true, RequiredPermission: models.PERMISSION_EDIT},
|
|
|
|
|
+ shouldFind,
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ test(t,
|
|
|
|
|
+ DashboardProps{},
|
|
|
|
|
+ &DashboardPermission{User: true, Permission: models.PERMISSION_VIEW},
|
|
|
|
|
+ Search{RequiredPermission: models.PERMISSION_VIEW},
|
|
|
|
|
+ shouldNotFind,
|
|
|
|
|
+ )
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ t.Run("role ACL", func(t *testing.T) {
|
|
|
|
|
+ test(t,
|
|
|
|
|
+ DashboardProps{},
|
|
|
|
|
+ &DashboardPermission{Role: models.ROLE_VIEWER, Permission: models.PERMISSION_VIEW},
|
|
|
|
|
+ Search{UsersOrgRole: models.ROLE_VIEWER, RequiredPermission: models.PERMISSION_VIEW},
|
|
|
|
|
+ shouldFind,
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ test(t,
|
|
|
|
|
+ DashboardProps{},
|
|
|
|
|
+ &DashboardPermission{Role: models.ROLE_VIEWER, Permission: models.PERMISSION_VIEW},
|
|
|
|
|
+ Search{UsersOrgRole: models.ROLE_VIEWER, RequiredPermission: models.PERMISSION_EDIT},
|
|
|
|
|
+ shouldNotFind,
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ test(t,
|
|
|
|
|
+ DashboardProps{},
|
|
|
|
|
+ &DashboardPermission{Role: models.ROLE_EDITOR, Permission: models.PERMISSION_VIEW},
|
|
|
|
|
+ Search{UsersOrgRole: models.ROLE_VIEWER, RequiredPermission: models.PERMISSION_VIEW},
|
|
|
|
|
+ shouldNotFind,
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ test(t,
|
|
|
|
|
+ DashboardProps{},
|
|
|
|
|
+ &DashboardPermission{Role: models.ROLE_EDITOR, Permission: models.PERMISSION_VIEW},
|
|
|
|
|
+ Search{UsersOrgRole: models.ROLE_VIEWER, RequiredPermission: models.PERMISSION_VIEW},
|
|
|
|
|
+ shouldNotFind,
|
|
|
|
|
+ )
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ t.Run("team ACL", func(t *testing.T) {
|
|
|
|
|
+ test(t,
|
|
|
|
|
+ DashboardProps{},
|
|
|
|
|
+ &DashboardPermission{Team: true, Permission: models.PERMISSION_VIEW},
|
|
|
|
|
+ Search{UserFromACL: true, RequiredPermission: models.PERMISSION_VIEW},
|
|
|
|
|
+ shouldFind,
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ test(t,
|
|
|
|
|
+ DashboardProps{},
|
|
|
|
|
+ &DashboardPermission{Team: true, Permission: models.PERMISSION_VIEW},
|
|
|
|
|
+ Search{UserFromACL: true, RequiredPermission: models.PERMISSION_EDIT},
|
|
|
|
|
+ shouldNotFind,
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ test(t,
|
|
|
|
|
+ DashboardProps{},
|
|
|
|
|
+ &DashboardPermission{Team: true, Permission: models.PERMISSION_EDIT},
|
|
|
|
|
+ Search{UserFromACL: true, RequiredPermission: models.PERMISSION_EDIT},
|
|
|
|
|
+ shouldFind,
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ test(t,
|
|
|
|
|
+ DashboardProps{},
|
|
|
|
|
+ &DashboardPermission{Team: true, Permission: models.PERMISSION_EDIT},
|
|
|
|
|
+ Search{UserFromACL: false, RequiredPermission: models.PERMISSION_EDIT},
|
|
|
|
|
+ shouldNotFind,
|
|
|
|
|
+ )
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ t.Run("defaults for user ACL", func(t *testing.T) {
|
|
|
|
|
+ test(t,
|
|
|
|
|
+ DashboardProps{},
|
|
|
|
|
+ nil,
|
|
|
|
|
+ Search{OrgId: -1, UsersOrgRole: models.ROLE_VIEWER, RequiredPermission: models.PERMISSION_VIEW},
|
|
|
|
|
+ shouldNotFind,
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ test(t,
|
|
|
|
|
+ DashboardProps{OrgId: -1},
|
|
|
|
|
+ nil,
|
|
|
|
|
+ Search{OrgId: -1, UsersOrgRole: models.ROLE_VIEWER, RequiredPermission: models.PERMISSION_VIEW},
|
|
|
|
|
+ shouldFind,
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ test(t,
|
|
|
|
|
+ DashboardProps{OrgId: -1},
|
|
|
|
|
+ nil,
|
|
|
|
|
+ Search{OrgId: -1, UsersOrgRole: models.ROLE_EDITOR, RequiredPermission: models.PERMISSION_EDIT},
|
|
|
|
|
+ shouldFind,
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ test(t,
|
|
|
|
|
+ DashboardProps{OrgId: -1},
|
|
|
|
|
+ nil,
|
|
|
|
|
+ Search{OrgId: -1, UsersOrgRole: models.ROLE_VIEWER, RequiredPermission: models.PERMISSION_EDIT},
|
|
|
|
|
+ shouldNotFind,
|
|
|
|
|
+ )
|
|
|
|
|
+ })
|
|
|
|
|
+ })
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+var shouldFind = true
|
|
|
|
|
+var shouldNotFind = false
|
|
|
|
|
+
|
|
|
|
|
+type DashboardProps struct {
|
|
|
|
|
+ OrgId int64
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+type DashboardPermission struct {
|
|
|
|
|
+ User bool
|
|
|
|
|
+ Team bool
|
|
|
|
|
+ Role models.RoleType
|
|
|
|
|
+ Permission models.PermissionType
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+type Search struct {
|
|
|
|
|
+ UsersOrgRole models.RoleType
|
|
|
|
|
+ UserFromACL bool
|
|
|
|
|
+ RequiredPermission models.PermissionType
|
|
|
|
|
+ OrgId int64
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+type dashboardResponse struct {
|
|
|
|
|
+ Id int64
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func test(t *testing.T, dashboardProps DashboardProps, dashboardPermission *DashboardPermission, search Search, shouldFind bool) {
|
|
|
|
|
+ // Will also cleanup the db
|
|
|
|
|
+ sqlStore := InitTestDB(t)
|
|
|
|
|
+
|
|
|
|
|
+ dashboard, err := createDummyDashboard(dashboardProps)
|
|
|
|
|
+ if !assert.Equal(t, nil, err) {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ var aclUserId int64
|
|
|
|
|
+ if dashboardPermission != nil {
|
|
|
|
|
+ aclUserId, err = createDummyAcl(dashboardPermission, search, dashboard.Id)
|
|
|
|
|
+ if !assert.Equal(t, nil, err) {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ dashboards, err := getDashboards(sqlStore, search, aclUserId)
|
|
|
|
|
+ if !assert.Equal(t, nil, err) {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if shouldFind {
|
|
|
|
|
+ if assert.Equal(t, 1, len(dashboards), "Should return one dashboard") {
|
|
|
|
|
+ assert.Equal(t, dashboards[0].Id, dashboard.Id, "Should return created dashboard")
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ assert.Equal(t, 0, len(dashboards), "Should node return any dashboard")
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func createDummyUser() (*models.User, error) {
|
|
|
|
|
+ uid := rand.Intn(9999999)
|
|
|
|
|
+ createUserCmd := &models.CreateUserCommand{
|
|
|
|
|
+ Email: string(uid) + "@example.com",
|
|
|
|
|
+ Login: string(uid),
|
|
|
|
|
+ Name: string(uid),
|
|
|
|
|
+ Company: "",
|
|
|
|
|
+ OrgName: "",
|
|
|
|
|
+ Password: string(uid),
|
|
|
|
|
+ EmailVerified: true,
|
|
|
|
|
+ IsAdmin: false,
|
|
|
|
|
+ SkipOrgSetup: false,
|
|
|
|
|
+ DefaultOrgRole: string(models.ROLE_VIEWER),
|
|
|
|
|
+ }
|
|
|
|
|
+ err := CreateUser(context.Background(), createUserCmd)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return &createUserCmd.Result, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func createDummyTeam() (*models.Team, error) {
|
|
|
|
|
+ cmd := &models.CreateTeamCommand{
|
|
|
|
|
+ // Does not matter in this tests actually
|
|
|
|
|
+ OrgId: 1,
|
|
|
|
|
+ Name: "test",
|
|
|
|
|
+ Email: "test@example.com",
|
|
|
|
|
+ }
|
|
|
|
|
+ err := CreateTeam(cmd)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return &cmd.Result, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func createDummyDashboard(dashboardProps DashboardProps) (*models.Dashboard, error) {
|
|
|
|
|
+ json, _ := simplejson.NewJson([]byte(`{"schemaVersion":17,"title":"gdev dashboards","uid":"","version":1}`))
|
|
|
|
|
+
|
|
|
|
|
+ saveDashboardCmd := &models.SaveDashboardCommand{
|
|
|
|
|
+ Dashboard: json,
|
|
|
|
|
+ UserId: 0,
|
|
|
|
|
+ Overwrite: false,
|
|
|
|
|
+ Message: "",
|
|
|
|
|
+ RestoredFrom: 0,
|
|
|
|
|
+ PluginId: "",
|
|
|
|
|
+ FolderId: 0,
|
|
|
|
|
+ IsFolder: false,
|
|
|
|
|
+ UpdatedAt: time.Time{},
|
|
|
|
|
+ }
|
|
|
|
|
+ if dashboardProps.OrgId != 0 {
|
|
|
|
|
+ saveDashboardCmd.OrgId = dashboardProps.OrgId
|
|
|
|
|
+ } else {
|
|
|
|
|
+ saveDashboardCmd.OrgId = 1
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ err := SaveDashboard(saveDashboardCmd)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return saveDashboardCmd.Result, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func createDummyAcl(dashboardPermission *DashboardPermission, search Search, dashboardId int64) (int64, error) {
|
|
|
|
|
+ acl := &models.DashboardAcl{
|
|
|
|
|
+ OrgId: 1,
|
|
|
|
|
+ Created: time.Now(),
|
|
|
|
|
+ Updated: time.Now(),
|
|
|
|
|
+ Permission: dashboardPermission.Permission,
|
|
|
|
|
+ DashboardId: dashboardId,
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ var user *models.User
|
|
|
|
|
+ var err error
|
|
|
|
|
+ if dashboardPermission.User {
|
|
|
|
|
+ user, err = createDummyUser()
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return 0, err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ acl.UserId = user.Id
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if dashboardPermission.Team {
|
|
|
|
|
+ team, err := createDummyTeam()
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return 0, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if search.UserFromACL {
|
|
|
|
|
+ user, err = createDummyUser()
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return 0, err
|
|
|
|
|
+ }
|
|
|
|
|
+ addTeamMemberCmd := &models.AddTeamMemberCommand{
|
|
|
|
|
+ UserId: user.Id,
|
|
|
|
|
+ OrgId: 1,
|
|
|
|
|
+ TeamId: team.Id,
|
|
|
|
|
+ }
|
|
|
|
|
+ err = AddTeamMember(addTeamMemberCmd)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return 0, err
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ acl.TeamId = team.Id
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if len(string(dashboardPermission.Role)) > 0 {
|
|
|
|
|
+ acl.Role = &dashboardPermission.Role
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ updateAclCmd := &models.UpdateDashboardAclCommand{
|
|
|
|
|
+ DashboardId: dashboardId,
|
|
|
|
|
+ Items: []*models.DashboardAcl{acl},
|
|
|
|
|
+ }
|
|
|
|
|
+ err = UpdateDashboardAcl(updateAclCmd)
|
|
|
|
|
+ if user != nil {
|
|
|
|
|
+ return user.Id, err
|
|
|
|
|
+ }
|
|
|
|
|
+ return 0, err
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func getDashboards(sqlStore *SqlStore, search Search, aclUserId int64) ([]*dashboardResponse, error) {
|
|
|
|
|
+ builder := &SqlBuilder{}
|
|
|
|
|
+ signedInUser := &models.SignedInUser{
|
|
|
|
|
+ UserId: 9999999999,
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if search.OrgId == 0 {
|
|
|
|
|
+ signedInUser.OrgId = 1
|
|
|
|
|
+ } else {
|
|
|
|
|
+ signedInUser.OrgId = search.OrgId
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if len(string(search.UsersOrgRole)) > 0 {
|
|
|
|
|
+ signedInUser.OrgRole = search.UsersOrgRole
|
|
|
|
|
+ } else {
|
|
|
|
|
+ signedInUser.OrgRole = models.ROLE_VIEWER
|
|
|
|
|
+ }
|
|
|
|
|
+ if search.UserFromACL {
|
|
|
|
|
+ signedInUser.UserId = aclUserId
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ var res []*dashboardResponse
|
|
|
|
|
+ builder.Write("SELECT * FROM dashboard WHERE true")
|
|
|
|
|
+ builder.writeDashboardPermissionFilter(signedInUser, search.RequiredPermission)
|
|
|
|
|
+ err := sqlStore.engine.SQL(builder.GetSqlString(), builder.params...).Find(&res)
|
|
|
|
|
+ return res, err
|
|
|
|
|
+}
|