API: Restrict anonymous user information access (#18422)

Existing /api/alert-notifications now requires at least editor access.
Existing /api/alert-notifiers now requires at least editor access.
New /api/alert-notifications/lookup returns less information than
/api/alert-notifications and can be access by any authenticated user.
Existing /api/org/users now requires org admin role.
New /api/org/users/lookup returns less information than
/api/org/users and can be access by users that are org admins,
admin in any folder or admin of any team.
UserPicker component now uses /api/org/users/lookup instead
of /api/org/users.

Fixes #17318
This commit is contained in:
Marcus Efraimsson
2019-08-12 20:03:48 +02:00
committed by GitHub
parent ab17015794
commit 8fd153edb7
18 changed files with 621 additions and 326 deletions

View File

@@ -6,15 +6,15 @@ import (
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/bus"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/services/search"
)
func ValidateOrgAlert(c *m.ReqContext) {
func ValidateOrgAlert(c *models.ReqContext) {
id := c.ParamsInt64(":alertId")
query := m.GetAlertByIdQuery{Id: id}
query := models.GetAlertByIdQuery{Id: id}
if err := bus.Dispatch(&query); err != nil {
c.JsonApiErr(404, "Alert not found", nil)
@@ -27,14 +27,14 @@ func ValidateOrgAlert(c *m.ReqContext) {
}
}
func GetAlertStatesForDashboard(c *m.ReqContext) Response {
func GetAlertStatesForDashboard(c *models.ReqContext) Response {
dashboardID := c.QueryInt64("dashboardId")
if dashboardID == 0 {
return Error(400, "Missing query parameter dashboardId", nil)
}
query := m.GetAlertStatesForDashboardQuery{
query := models.GetAlertStatesForDashboardQuery{
OrgId: c.OrgId,
DashboardId: c.QueryInt64("dashboardId"),
}
@@ -47,7 +47,7 @@ func GetAlertStatesForDashboard(c *m.ReqContext) Response {
}
// GET /api/alerts
func GetAlerts(c *m.ReqContext) Response {
func GetAlerts(c *models.ReqContext) Response {
dashboardQuery := c.Query("dashboardQuery")
dashboardTags := c.QueryStrings("dashboardTag")
stringDashboardIDs := c.QueryStrings("dashboardId")
@@ -79,7 +79,7 @@ func GetAlerts(c *m.ReqContext) Response {
DashboardIds: dashboardIDs,
Type: string(search.DashHitDB),
FolderIds: folderIDs,
Permission: m.PERMISSION_VIEW,
Permission: models.PERMISSION_VIEW,
}
err := bus.Dispatch(&searchQuery)
@@ -95,11 +95,11 @@ func GetAlerts(c *m.ReqContext) Response {
// if we didn't find any dashboards, return empty result
if len(dashboardIDs) == 0 {
return JSON(200, []*m.AlertListItemDTO{})
return JSON(200, []*models.AlertListItemDTO{})
}
}
query := m.GetAlertsQuery{
query := models.GetAlertsQuery{
OrgId: c.OrgId,
DashboardIDs: dashboardIDs,
PanelId: c.QueryInt64("panelId"),
@@ -118,14 +118,14 @@ func GetAlerts(c *m.ReqContext) Response {
}
for _, alert := range query.Result {
alert.Url = m.GetDashboardUrl(alert.DashboardUid, alert.DashboardSlug)
alert.Url = models.GetDashboardUrl(alert.DashboardUid, alert.DashboardSlug)
}
return JSON(200, query.Result)
}
// POST /api/alerts/test
func AlertTest(c *m.ReqContext, dto dtos.AlertTestCommand) Response {
func AlertTest(c *models.ReqContext, dto dtos.AlertTestCommand) Response {
if _, idErr := dto.Dashboard.Get("id").Int64(); idErr != nil {
return Error(400, "The dashboard needs to be saved at least once before you can test an alert rule", nil)
}
@@ -141,7 +141,7 @@ func AlertTest(c *m.ReqContext, dto dtos.AlertTestCommand) Response {
if validationErr, ok := err.(alerting.ValidationError); ok {
return Error(422, validationErr.Error(), nil)
}
if err == m.ErrDataSourceAccessDenied {
if err == models.ErrDataSourceAccessDenied {
return Error(403, "Access denied to datasource", err)
}
return Error(500, "Failed to test rule", err)
@@ -171,9 +171,9 @@ func AlertTest(c *m.ReqContext, dto dtos.AlertTestCommand) Response {
}
// GET /api/alerts/:id
func GetAlert(c *m.ReqContext) Response {
func GetAlert(c *models.ReqContext) Response {
id := c.ParamsInt64(":alertId")
query := m.GetAlertByIdQuery{Id: id}
query := models.GetAlertByIdQuery{Id: id}
if err := bus.Dispatch(&query); err != nil {
return Error(500, "List alerts failed", err)
@@ -182,28 +182,52 @@ func GetAlert(c *m.ReqContext) Response {
return JSON(200, &query.Result)
}
func GetAlertNotifiers(c *m.ReqContext) Response {
func GetAlertNotifiers(c *models.ReqContext) Response {
return JSON(200, alerting.GetNotifiers())
}
func GetAlertNotifications(c *m.ReqContext) Response {
query := &m.GetAllAlertNotificationsQuery{OrgId: c.OrgId}
func GetAlertNotificationLookup(c *models.ReqContext) Response {
alertNotifications, err := getAlertNotificationsInternal(c)
if err != nil {
return Error(500, "Failed to get alert notifications", err)
}
if err := bus.Dispatch(query); err != nil {
result := make([]*dtos.AlertNotificationLookup, 0)
for _, notification := range alertNotifications {
result = append(result, dtos.NewAlertNotificationLookup(notification))
}
return JSON(200, result)
}
func GetAlertNotifications(c *models.ReqContext) Response {
alertNotifications, err := getAlertNotificationsInternal(c)
if err != nil {
return Error(500, "Failed to get alert notifications", err)
}
result := make([]*dtos.AlertNotification, 0)
for _, notification := range query.Result {
for _, notification := range alertNotifications {
result = append(result, dtos.NewAlertNotification(notification))
}
return JSON(200, result)
}
func GetAlertNotificationByID(c *m.ReqContext) Response {
query := &m.GetAlertNotificationsQuery{
func getAlertNotificationsInternal(c *models.ReqContext) ([]*models.AlertNotification, error) {
query := &models.GetAllAlertNotificationsQuery{OrgId: c.OrgId}
if err := bus.Dispatch(query); err != nil {
return nil, err
}
return query.Result, nil
}
func GetAlertNotificationByID(c *models.ReqContext) Response {
query := &models.GetAlertNotificationsQuery{
OrgId: c.OrgId,
Id: c.ParamsInt64("notificationId"),
}
@@ -223,8 +247,8 @@ func GetAlertNotificationByID(c *m.ReqContext) Response {
return JSON(200, dtos.NewAlertNotification(query.Result))
}
func GetAlertNotificationByUID(c *m.ReqContext) Response {
query := &m.GetAlertNotificationsWithUidQuery{
func GetAlertNotificationByUID(c *models.ReqContext) Response {
query := &models.GetAlertNotificationsWithUidQuery{
OrgId: c.OrgId,
Uid: c.Params("uid"),
}
@@ -244,7 +268,7 @@ func GetAlertNotificationByUID(c *m.ReqContext) Response {
return JSON(200, dtos.NewAlertNotification(query.Result))
}
func CreateAlertNotification(c *m.ReqContext, cmd m.CreateAlertNotificationCommand) Response {
func CreateAlertNotification(c *models.ReqContext, cmd models.CreateAlertNotificationCommand) Response {
cmd.OrgId = c.OrgId
if err := bus.Dispatch(&cmd); err != nil {
@@ -254,7 +278,7 @@ func CreateAlertNotification(c *m.ReqContext, cmd m.CreateAlertNotificationComma
return JSON(200, dtos.NewAlertNotification(cmd.Result))
}
func UpdateAlertNotification(c *m.ReqContext, cmd m.UpdateAlertNotificationCommand) Response {
func UpdateAlertNotification(c *models.ReqContext, cmd models.UpdateAlertNotificationCommand) Response {
cmd.OrgId = c.OrgId
if err := bus.Dispatch(&cmd); err != nil {
@@ -268,7 +292,7 @@ func UpdateAlertNotification(c *m.ReqContext, cmd m.UpdateAlertNotificationComma
return JSON(200, dtos.NewAlertNotification(cmd.Result))
}
func UpdateAlertNotificationByUID(c *m.ReqContext, cmd m.UpdateAlertNotificationWithUidCommand) Response {
func UpdateAlertNotificationByUID(c *models.ReqContext, cmd models.UpdateAlertNotificationWithUidCommand) Response {
cmd.OrgId = c.OrgId
cmd.Uid = c.Params("uid")
@@ -283,8 +307,8 @@ func UpdateAlertNotificationByUID(c *m.ReqContext, cmd m.UpdateAlertNotification
return JSON(200, dtos.NewAlertNotification(cmd.Result))
}
func DeleteAlertNotification(c *m.ReqContext) Response {
cmd := m.DeleteAlertNotificationCommand{
func DeleteAlertNotification(c *models.ReqContext) Response {
cmd := models.DeleteAlertNotificationCommand{
OrgId: c.OrgId,
Id: c.ParamsInt64("notificationId"),
}
@@ -296,8 +320,8 @@ func DeleteAlertNotification(c *m.ReqContext) Response {
return Success("Notification deleted")
}
func DeleteAlertNotificationByUID(c *m.ReqContext) Response {
cmd := m.DeleteAlertNotificationWithUidCommand{
func DeleteAlertNotificationByUID(c *models.ReqContext) Response {
cmd := models.DeleteAlertNotificationWithUidCommand{
OrgId: c.OrgId,
Uid: c.Params("uid"),
}
@@ -310,7 +334,7 @@ func DeleteAlertNotificationByUID(c *m.ReqContext) Response {
}
//POST /api/alert-notifications/test
func NotificationTest(c *m.ReqContext, dto dtos.NotificationTestCommand) Response {
func NotificationTest(c *models.ReqContext, dto dtos.NotificationTestCommand) Response {
cmd := &alerting.NotificationTestCommand{
Name: dto.Name,
Type: dto.Type,
@@ -318,7 +342,7 @@ func NotificationTest(c *m.ReqContext, dto dtos.NotificationTestCommand) Respons
}
if err := bus.Dispatch(cmd); err != nil {
if err == m.ErrSmtpNotEnabled {
if err == models.ErrSmtpNotEnabled {
return Error(412, err.Error(), err)
}
return Error(500, "Failed to send alert notifications", err)
@@ -328,10 +352,10 @@ func NotificationTest(c *m.ReqContext, dto dtos.NotificationTestCommand) Respons
}
//POST /api/alerts/:alertId/pause
func PauseAlert(c *m.ReqContext, dto dtos.PauseAlertCommand) Response {
func PauseAlert(c *models.ReqContext, dto dtos.PauseAlertCommand) Response {
alertID := c.ParamsInt64("alertId")
query := m.GetAlertByIdQuery{Id: alertID}
query := models.GetAlertByIdQuery{Id: alertID}
if err := bus.Dispatch(&query); err != nil {
return Error(500, "Get Alert failed", err)
@@ -346,7 +370,7 @@ func PauseAlert(c *m.ReqContext, dto dtos.PauseAlertCommand) Response {
return Error(403, "Access denied to this dashboard and alert", nil)
}
cmd := m.PauseAlertCommand{
cmd := models.PauseAlertCommand{
OrgId: c.OrgId,
AlertIds: []int64{alertID},
Paused: dto.Paused,
@@ -356,10 +380,10 @@ func PauseAlert(c *m.ReqContext, dto dtos.PauseAlertCommand) Response {
return Error(500, "", err)
}
var response m.AlertStateType = m.AlertStateUnknown
var response models.AlertStateType = models.AlertStateUnknown
pausedState := "un-paused"
if cmd.Paused {
response = m.AlertStatePaused
response = models.AlertStatePaused
pausedState = "paused"
}
@@ -373,8 +397,8 @@ func PauseAlert(c *m.ReqContext, dto dtos.PauseAlertCommand) Response {
}
//POST /api/admin/pause-all-alerts
func PauseAllAlerts(c *m.ReqContext, dto dtos.PauseAllAlertsCommand) Response {
updateCmd := m.PauseAllAlertCommand{
func PauseAllAlerts(c *models.ReqContext, dto dtos.PauseAllAlertsCommand) Response {
updateCmd := models.PauseAllAlertCommand{
Paused: dto.Paused,
}
@@ -382,10 +406,10 @@ func PauseAllAlerts(c *m.ReqContext, dto dtos.PauseAllAlertsCommand) Response {
return Error(500, "Failed to pause alerts", err)
}
var response m.AlertStateType = m.AlertStatePending
var response models.AlertStateType = models.AlertStatePending
pausedState := "un paused"
if updateCmd.Paused {
response = m.AlertStatePaused
response = models.AlertStatePaused
pausedState = "paused"
}

View File

@@ -5,7 +5,7 @@ import (
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/bus"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/search"
. "github.com/smartystreets/goconvey/convey"
@@ -14,24 +14,24 @@ import (
func TestAlertingApiEndpoint(t *testing.T) {
Convey("Given an alert in a dashboard with an acl", t, func() {
singleAlert := &m.Alert{Id: 1, DashboardId: 1, Name: "singlealert"}
singleAlert := &models.Alert{Id: 1, DashboardId: 1, Name: "singlealert"}
bus.AddHandler("test", func(query *m.GetAlertByIdQuery) error {
bus.AddHandler("test", func(query *models.GetAlertByIdQuery) error {
query.Result = singleAlert
return nil
})
viewerRole := m.ROLE_VIEWER
editorRole := m.ROLE_EDITOR
viewerRole := models.ROLE_VIEWER
editorRole := models.ROLE_EDITOR
aclMockResp := []*m.DashboardAclInfoDTO{}
bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error {
aclMockResp := []*models.DashboardAclInfoDTO{}
bus.AddHandler("test", func(query *models.GetDashboardAclInfoListQuery) error {
query.Result = aclMockResp
return nil
})
bus.AddHandler("test", func(query *m.GetTeamsByUserQuery) error {
query.Result = []*m.TeamDTO{}
bus.AddHandler("test", func(query *models.GetTeamsByUserQuery) error {
query.Result = []*models.TeamDTO{}
return nil
})
@@ -41,7 +41,7 @@ func TestAlertingApiEndpoint(t *testing.T) {
AlertId: 1,
Paused: true,
}
postAlertScenario("When calling POST on", "/api/alerts/1/pause", "/api/alerts/:alertId/pause", m.ROLE_EDITOR, cmd, func(sc *scenarioContext) {
postAlertScenario("When calling POST on", "/api/alerts/1/pause", "/api/alerts/:alertId/pause", models.ROLE_EDITOR, cmd, func(sc *scenarioContext) {
CallPauseAlert(sc)
So(sc.resp.Code, ShouldEqual, 403)
})
@@ -49,9 +49,9 @@ func TestAlertingApiEndpoint(t *testing.T) {
})
Convey("When user is editor and dashboard has default ACL", func() {
aclMockResp = []*m.DashboardAclInfoDTO{
{Role: &viewerRole, Permission: m.PERMISSION_VIEW},
{Role: &editorRole, Permission: m.PERMISSION_EDIT},
aclMockResp = []*models.DashboardAclInfoDTO{
{Role: &viewerRole, Permission: models.PERMISSION_VIEW},
{Role: &editorRole, Permission: models.PERMISSION_EDIT},
}
Convey("Should be able to pause the alert", func() {
@@ -59,22 +59,22 @@ func TestAlertingApiEndpoint(t *testing.T) {
AlertId: 1,
Paused: true,
}
postAlertScenario("When calling POST on", "/api/alerts/1/pause", "/api/alerts/:alertId/pause", m.ROLE_EDITOR, cmd, func(sc *scenarioContext) {
postAlertScenario("When calling POST on", "/api/alerts/1/pause", "/api/alerts/:alertId/pause", models.ROLE_EDITOR, cmd, func(sc *scenarioContext) {
CallPauseAlert(sc)
So(sc.resp.Code, ShouldEqual, 200)
})
})
})
loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/alerts?dashboardId=1", "/api/alerts", m.ROLE_EDITOR, func(sc *scenarioContext) {
loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/alerts?dashboardId=1", "/api/alerts", models.ROLE_EDITOR, func(sc *scenarioContext) {
var searchQuery *search.Query
bus.AddHandler("test", func(query *search.Query) error {
searchQuery = query
return nil
})
var getAlertsQuery *m.GetAlertsQuery
bus.AddHandler("test", func(query *m.GetAlertsQuery) error {
var getAlertsQuery *models.GetAlertsQuery
bus.AddHandler("test", func(query *models.GetAlertsQuery) error {
getAlertsQuery = query
return nil
})
@@ -86,7 +86,7 @@ func TestAlertingApiEndpoint(t *testing.T) {
So(getAlertsQuery, ShouldNotBeNil)
})
loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/alerts?dashboardId=1&dashboardId=2&folderId=3&dashboardTag=abc&dashboardQuery=dbQuery&limit=5&query=alertQuery", "/api/alerts", m.ROLE_EDITOR, func(sc *scenarioContext) {
loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/alerts?dashboardId=1&dashboardId=2&folderId=3&dashboardTag=abc&dashboardQuery=dbQuery&limit=5&query=alertQuery", "/api/alerts", models.ROLE_EDITOR, func(sc *scenarioContext) {
var searchQuery *search.Query
bus.AddHandler("test", func(query *search.Query) error {
searchQuery = query
@@ -97,8 +97,8 @@ func TestAlertingApiEndpoint(t *testing.T) {
return nil
})
var getAlertsQuery *m.GetAlertsQuery
bus.AddHandler("test", func(query *m.GetAlertsQuery) error {
var getAlertsQuery *models.GetAlertsQuery
bus.AddHandler("test", func(query *models.GetAlertsQuery) error {
getAlertsQuery = query
return nil
})
@@ -120,7 +120,7 @@ func TestAlertingApiEndpoint(t *testing.T) {
So(getAlertsQuery.Query, ShouldEqual, "alertQuery")
})
loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/alert-notifications/1", "/alert-notifications/:notificationId", m.ROLE_ADMIN, func(sc *scenarioContext) {
loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/alert-notifications/1", "/alert-notifications/:notificationId", models.ROLE_ADMIN, func(sc *scenarioContext) {
sc.handlerFunc = GetAlertNotificationByID
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
So(sc.resp.Code, ShouldEqual, 404)
@@ -129,19 +129,19 @@ func TestAlertingApiEndpoint(t *testing.T) {
}
func CallPauseAlert(sc *scenarioContext) {
bus.AddHandler("test", func(cmd *m.PauseAlertCommand) error {
bus.AddHandler("test", func(cmd *models.PauseAlertCommand) error {
return nil
})
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
}
func postAlertScenario(desc string, url string, routePattern string, role m.RoleType, cmd dtos.PauseAlertCommand, fn scenarioFunc) {
func postAlertScenario(desc string, url string, routePattern string, role models.RoleType, cmd dtos.PauseAlertCommand, fn scenarioFunc) {
Convey(desc+" "+url, func() {
defer bus.ClearBusHandlers()
sc := setupScenarioContext(url)
sc.defaultHandler = Wrap(func(c *m.ReqContext) Response {
sc.defaultHandler = Wrap(func(c *models.ReqContext) Response {
sc.context = c
sc.context.UserId = TestUserID
sc.context.OrgId = TestOrgID

View File

@@ -183,6 +183,7 @@ func (hs *HTTPServer) registerRoutes() {
apiRoute.Group("/org", func(orgRoute routing.RouteRegister) {
orgRoute.Put("/", bind(dtos.UpdateOrgForm{}), Wrap(UpdateOrgCurrent))
orgRoute.Put("/address", bind(dtos.UpdateOrgAddressForm{}), Wrap(UpdateOrgAddressCurrent))
orgRoute.Get("/users", Wrap(GetOrgUsersForCurrentOrg))
orgRoute.Post("/users", quota("user"), bind(models.AddOrgUserCommand{}), Wrap(AddOrgUserToCurrentOrg))
orgRoute.Patch("/users/:userId", bind(models.UpdateOrgUserCommand{}), Wrap(UpdateOrgUserForCurrentOrg))
orgRoute.Delete("/users/:userId", Wrap(RemoveOrgUserForCurrentOrg))
@@ -199,7 +200,7 @@ func (hs *HTTPServer) registerRoutes() {
// current org without requirement of user to be org admin
apiRoute.Group("/org", func(orgRoute routing.RouteRegister) {
orgRoute.Get("/users", Wrap(GetOrgUsersForCurrentOrg))
orgRoute.Get("/users/lookup", Wrap(GetOrgUsersForCurrentOrgLookup))
})
// create new org
@@ -343,10 +344,10 @@ func (hs *HTTPServer) registerRoutes() {
alertsRoute.Get("/states-for-dashboard", Wrap(GetAlertStatesForDashboard))
})
apiRoute.Get("/alert-notifications", Wrap(GetAlertNotifications))
apiRoute.Get("/alert-notifiers", Wrap(GetAlertNotifiers))
apiRoute.Get("/alert-notifiers", reqEditorRole, Wrap(GetAlertNotifiers))
apiRoute.Group("/alert-notifications", func(alertNotifications routing.RouteRegister) {
alertNotifications.Get("/", Wrap(GetAlertNotifications))
alertNotifications.Post("/test", bind(dtos.NotificationTestCommand{}), Wrap(NotificationTest))
alertNotifications.Post("/", bind(models.CreateAlertNotificationCommand{}), Wrap(CreateAlertNotification))
alertNotifications.Put("/:notificationId", bind(models.UpdateAlertNotificationCommand{}), Wrap(UpdateAlertNotification))
@@ -357,6 +358,11 @@ func (hs *HTTPServer) registerRoutes() {
alertNotifications.Delete("/uid/:uid", Wrap(DeleteAlertNotificationByUID))
}, reqEditorRole)
// alert notifications without requirement of user to be org editor
apiRoute.Group("/alert-notifications", func(orgRoute routing.RouteRegister) {
orgRoute.Get("/lookup", Wrap(GetAlertNotificationLookup))
})
apiRoute.Get("/annotations", Wrap(GetAnnotations))
apiRoute.Post("/annotations/mass-delete", reqOrgAdmin, bind(dtos.DeleteAnnotationsCmd{}), Wrap(DeleteAnnotations))

View File

@@ -77,6 +77,24 @@ type AlertNotification struct {
Settings *simplejson.Json `json:"settings"`
}
func NewAlertNotificationLookup(notification *models.AlertNotification) *AlertNotificationLookup {
return &AlertNotificationLookup{
Id: notification.Id,
Uid: notification.Uid,
Name: notification.Name,
Type: notification.Type,
IsDefault: notification.IsDefault,
}
}
type AlertNotificationLookup struct {
Id int64 `json:"id"`
Uid string `json:"uid"`
Name string `json:"name"`
Type string `json:"type"`
IsDefault bool `json:"isDefault"`
}
type AlertTestCommand struct {
Dashboard *simplejson.Json `json:"dashboard" binding:"Required"`
PanelId int64 `json:"panelId" binding:"Required"`

View File

@@ -50,3 +50,9 @@ type ResetUserPasswordForm struct {
NewPassword string `json:"newPassword"`
ConfirmPassword string `json:"confirmPassword"`
}
type UserLookupDTO struct {
UserID int64 `json:"userId"`
Login string `json:"login"`
AvatarURL string `json:"avatarUrl"`
}

View File

@@ -3,27 +3,27 @@ package api
import (
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/bus"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/models"
)
// POST /api/org/users
func AddOrgUserToCurrentOrg(c *m.ReqContext, cmd m.AddOrgUserCommand) Response {
func AddOrgUserToCurrentOrg(c *models.ReqContext, cmd models.AddOrgUserCommand) Response {
cmd.OrgId = c.OrgId
return addOrgUserHelper(cmd)
}
// POST /api/orgs/:orgId/users
func AddOrgUser(c *m.ReqContext, cmd m.AddOrgUserCommand) Response {
func AddOrgUser(c *models.ReqContext, cmd models.AddOrgUserCommand) Response {
cmd.OrgId = c.ParamsInt64(":orgId")
return addOrgUserHelper(cmd)
}
func addOrgUserHelper(cmd m.AddOrgUserCommand) Response {
func addOrgUserHelper(cmd models.AddOrgUserCommand) Response {
if !cmd.Role.IsValid() {
return Error(400, "Invalid role specified", nil)
}
userQuery := m.GetUserByLoginQuery{LoginOrEmail: cmd.LoginOrEmail}
userQuery := models.GetUserByLoginQuery{LoginOrEmail: cmd.LoginOrEmail}
err := bus.Dispatch(&userQuery)
if err != nil {
return Error(404, "User not found", nil)
@@ -34,7 +34,7 @@ func addOrgUserHelper(cmd m.AddOrgUserCommand) Response {
cmd.UserId = userToAdd.Id
if err := bus.Dispatch(&cmd); err != nil {
if err == m.ErrOrgUserAlreadyAdded {
if err == models.ErrOrgUserAlreadyAdded {
return Error(409, "User is already member of this organization", nil)
}
return Error(500, "Could not add user to organization", err)
@@ -44,54 +44,115 @@ func addOrgUserHelper(cmd m.AddOrgUserCommand) Response {
}
// GET /api/org/users
func GetOrgUsersForCurrentOrg(c *m.ReqContext) Response {
return getOrgUsersHelper(c.OrgId, c.Query("query"), c.QueryInt("limit"))
func GetOrgUsersForCurrentOrg(c *models.ReqContext) Response {
result, err := getOrgUsersHelper(c.OrgId, c.Query("query"), c.QueryInt("limit"))
if err != nil {
return Error(500, "Failed to get users for current organization", err)
}
return JSON(200, result)
}
// GET /api/org/users/lookup
func GetOrgUsersForCurrentOrgLookup(c *models.ReqContext) Response {
isAdmin, err := isOrgAdminFolderAdminOrTeamAdmin(c)
if err != nil {
return Error(500, "Failed to get users for current organization", err)
}
if !isAdmin {
return Error(403, "Permission denied", nil)
}
orgUsers, err := getOrgUsersHelper(c.OrgId, c.Query("query"), c.QueryInt("limit"))
if err != nil {
return Error(500, "Failed to get users for current organization", err)
}
result := make([]*dtos.UserLookupDTO, 0)
for _, u := range orgUsers {
result = append(result, &dtos.UserLookupDTO{
UserID: u.UserId,
Login: u.Login,
AvatarURL: u.AvatarUrl,
})
}
return JSON(200, result)
}
func isOrgAdminFolderAdminOrTeamAdmin(c *models.ReqContext) (bool, error) {
if c.OrgRole == models.ROLE_ADMIN {
return true, nil
}
hasAdminPermissionInFoldersQuery := models.HasAdminPermissionInFoldersQuery{SignedInUser: c.SignedInUser}
if err := bus.Dispatch(&hasAdminPermissionInFoldersQuery); err != nil {
return false, err
}
if hasAdminPermissionInFoldersQuery.Result {
return true, nil
}
isAdminOfTeamsQuery := models.IsAdminOfTeamsQuery{SignedInUser: c.SignedInUser}
if err := bus.Dispatch(&isAdminOfTeamsQuery); err != nil {
return false, err
}
return isAdminOfTeamsQuery.Result, nil
}
// GET /api/orgs/:orgId/users
func GetOrgUsers(c *m.ReqContext) Response {
return getOrgUsersHelper(c.ParamsInt64(":orgId"), "", 0)
func GetOrgUsers(c *models.ReqContext) Response {
result, err := getOrgUsersHelper(c.ParamsInt64(":orgId"), "", 0)
if err != nil {
return Error(500, "Failed to get users for organization", err)
}
return JSON(200, result)
}
func getOrgUsersHelper(orgID int64, query string, limit int) Response {
q := m.GetOrgUsersQuery{
func getOrgUsersHelper(orgID int64, query string, limit int) ([]*models.OrgUserDTO, error) {
q := models.GetOrgUsersQuery{
OrgId: orgID,
Query: query,
Limit: limit,
}
if err := bus.Dispatch(&q); err != nil {
return Error(500, "Failed to get account user", err)
return nil, err
}
for _, user := range q.Result {
user.AvatarUrl = dtos.GetGravatarUrl(user.Email)
}
return JSON(200, q.Result)
return q.Result, nil
}
// PATCH /api/org/users/:userId
func UpdateOrgUserForCurrentOrg(c *m.ReqContext, cmd m.UpdateOrgUserCommand) Response {
func UpdateOrgUserForCurrentOrg(c *models.ReqContext, cmd models.UpdateOrgUserCommand) Response {
cmd.OrgId = c.OrgId
cmd.UserId = c.ParamsInt64(":userId")
return updateOrgUserHelper(cmd)
}
// PATCH /api/orgs/:orgId/users/:userId
func UpdateOrgUser(c *m.ReqContext, cmd m.UpdateOrgUserCommand) Response {
func UpdateOrgUser(c *models.ReqContext, cmd models.UpdateOrgUserCommand) Response {
cmd.OrgId = c.ParamsInt64(":orgId")
cmd.UserId = c.ParamsInt64(":userId")
return updateOrgUserHelper(cmd)
}
func updateOrgUserHelper(cmd m.UpdateOrgUserCommand) Response {
func updateOrgUserHelper(cmd models.UpdateOrgUserCommand) Response {
if !cmd.Role.IsValid() {
return Error(400, "Invalid role specified", nil)
}
if err := bus.Dispatch(&cmd); err != nil {
if err == m.ErrLastOrgAdmin {
if err == models.ErrLastOrgAdmin {
return Error(400, "Cannot change role so that there is no organization admin left", nil)
}
return Error(500, "Failed update org user", err)
@@ -101,8 +162,8 @@ func updateOrgUserHelper(cmd m.UpdateOrgUserCommand) Response {
}
// DELETE /api/org/users/:userId
func RemoveOrgUserForCurrentOrg(c *m.ReqContext) Response {
return removeOrgUserHelper(&m.RemoveOrgUserCommand{
func RemoveOrgUserForCurrentOrg(c *models.ReqContext) Response {
return removeOrgUserHelper(&models.RemoveOrgUserCommand{
UserId: c.ParamsInt64(":userId"),
OrgId: c.OrgId,
ShouldDeleteOrphanedUser: true,
@@ -110,16 +171,16 @@ func RemoveOrgUserForCurrentOrg(c *m.ReqContext) Response {
}
// DELETE /api/orgs/:orgId/users/:userId
func RemoveOrgUser(c *m.ReqContext) Response {
return removeOrgUserHelper(&m.RemoveOrgUserCommand{
func RemoveOrgUser(c *models.ReqContext) Response {
return removeOrgUserHelper(&models.RemoveOrgUserCommand{
UserId: c.ParamsInt64(":userId"),
OrgId: c.ParamsInt64(":orgId"),
})
}
func removeOrgUserHelper(cmd *m.RemoveOrgUserCommand) Response {
func removeOrgUserHelper(cmd *models.RemoveOrgUserCommand) Response {
if err := bus.Dispatch(cmd); err != nil {
if err == m.ErrLastOrgAdmin {
if err == models.ErrLastOrgAdmin {
return Error(400, "Cannot remove last organization admin", nil)
}
return Error(500, "Failed to remove user from organization", err)

View File

@@ -98,3 +98,8 @@ type HasEditPermissionInFoldersQuery struct {
SignedInUser *SignedInUser
Result bool
}
type HasAdminPermissionInFoldersQuery struct {
SignedInUser *SignedInUser
Result bool
}

View File

@@ -88,3 +88,8 @@ type SearchTeamQueryResult struct {
Page int `json:"page"`
PerPage int `json:"perPage"`
}
type IsAdminOfTeamsQuery struct {
SignedInUser *SignedInUser
Result bool
}

View File

@@ -6,7 +6,7 @@ import (
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/infra/metrics"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/search"
"github.com/grafana/grafana/pkg/util"
)
@@ -25,17 +25,18 @@ func init() {
bus.AddHandler("sql", GetDashboardsBySlug)
bus.AddHandler("sql", ValidateDashboardBeforeSave)
bus.AddHandler("sql", HasEditPermissionInFolders)
bus.AddHandler("sql", HasAdminPermissionInFolders)
}
var generateNewUid func() string = util.GenerateShortUID
func SaveDashboard(cmd *m.SaveDashboardCommand) error {
func SaveDashboard(cmd *models.SaveDashboardCommand) error {
return inTransaction(func(sess *DBSession) error {
return saveDashboard(sess, cmd)
})
}
func saveDashboard(sess *DBSession, cmd *m.SaveDashboardCommand) error {
func saveDashboard(sess *DBSession, cmd *models.SaveDashboardCommand) error {
dash := cmd.GetDashboardModel()
userId := cmd.UserId
@@ -45,13 +46,13 @@ func saveDashboard(sess *DBSession, cmd *m.SaveDashboardCommand) error {
}
if dash.Id > 0 {
var existing m.Dashboard
var existing models.Dashboard
dashWithIdExists, err := sess.Where("id=? AND org_id=?", dash.Id, dash.OrgId).Get(&existing)
if err != nil {
return err
}
if !dashWithIdExists {
return m.ErrDashboardNotFound
return models.ErrDashboardNotFound
}
// check for is someone else has written in between
@@ -59,13 +60,13 @@ func saveDashboard(sess *DBSession, cmd *m.SaveDashboardCommand) error {
if cmd.Overwrite {
dash.SetVersion(existing.Version)
} else {
return m.ErrDashboardVersionMismatch
return models.ErrDashboardVersionMismatch
}
}
// do not allow plugin dashboard updates without overwrite flag
if existing.PluginId != "" && !cmd.Overwrite {
return m.UpdatePluginDashboardError{PluginId: existing.PluginId}
return models.UpdatePluginDashboardError{PluginId: existing.PluginId}
}
}
@@ -108,10 +109,10 @@ func saveDashboard(sess *DBSession, cmd *m.SaveDashboardCommand) error {
}
if affectedRows == 0 {
return m.ErrDashboardNotFound
return models.ErrDashboardNotFound
}
dashVersion := &m.DashboardVersion{
dashVersion := &models.DashboardVersion{
DashboardId: dash.Id,
ParentVersion: parentVersion,
RestoredFrom: cmd.RestoredFrom,
@@ -126,7 +127,7 @@ func saveDashboard(sess *DBSession, cmd *m.SaveDashboardCommand) error {
if affectedRows, err = sess.Insert(dashVersion); err != nil {
return err
} else if affectedRows == 0 {
return m.ErrDashboardNotFound
return models.ErrDashboardNotFound
}
// delete existing tags
@@ -154,7 +155,7 @@ func generateNewDashboardUid(sess *DBSession, orgId int64) (string, error) {
for i := 0; i < 3; i++ {
uid := generateNewUid()
exists, err := sess.Where("org_id=? AND uid=?", orgId, uid).Get(&m.Dashboard{})
exists, err := sess.Where("org_id=? AND uid=?", orgId, uid).Get(&models.Dashboard{})
if err != nil {
return "", err
}
@@ -164,17 +165,17 @@ func generateNewDashboardUid(sess *DBSession, orgId int64) (string, error) {
}
}
return "", m.ErrDashboardFailedGenerateUniqueUid
return "", models.ErrDashboardFailedGenerateUniqueUid
}
func GetDashboard(query *m.GetDashboardQuery) error {
dashboard := m.Dashboard{Slug: query.Slug, OrgId: query.OrgId, Id: query.Id, Uid: query.Uid}
func GetDashboard(query *models.GetDashboardQuery) error {
dashboard := models.Dashboard{Slug: query.Slug, OrgId: query.OrgId, Id: query.Id, Uid: query.Uid}
has, err := x.Get(&dashboard)
if err != nil {
return err
} else if !has {
return m.ErrDashboardNotFound
return models.ErrDashboardNotFound
}
dashboard.SetId(dashboard.Id)
@@ -262,7 +263,7 @@ func makeQueryResult(query *search.FindPersistedDashboardsQuery, res []Dashboard
Uid: item.Uid,
Title: item.Title,
Uri: "db/" + item.Slug,
Url: m.GetDashboardFolderUrl(item.IsFolder, item.Uid, item.Slug),
Url: models.GetDashboardFolderUrl(item.IsFolder, item.Uid, item.Slug),
Type: getHitType(item),
FolderId: item.FolderId,
FolderUid: item.FolderUid,
@@ -271,7 +272,7 @@ func makeQueryResult(query *search.FindPersistedDashboardsQuery, res []Dashboard
}
if item.FolderId > 0 {
hit.FolderUrl = m.GetFolderUrl(item.FolderUid, item.FolderSlug)
hit.FolderUrl = models.GetFolderUrl(item.FolderUid, item.FolderSlug)
}
query.Result = append(query.Result, hit)
@@ -283,7 +284,7 @@ func makeQueryResult(query *search.FindPersistedDashboardsQuery, res []Dashboard
}
}
func GetDashboardTags(query *m.GetDashboardTagsQuery) error {
func GetDashboardTags(query *models.GetDashboardTagsQuery) error {
sql := `SELECT
COUNT(*) as count,
term
@@ -293,20 +294,20 @@ func GetDashboardTags(query *m.GetDashboardTagsQuery) error {
GROUP BY term
ORDER BY term`
query.Result = make([]*m.DashboardTagCloudItem, 0)
query.Result = make([]*models.DashboardTagCloudItem, 0)
sess := x.SQL(sql, query.OrgId)
err := sess.Find(&query.Result)
return err
}
func DeleteDashboard(cmd *m.DeleteDashboardCommand) error {
func DeleteDashboard(cmd *models.DeleteDashboardCommand) error {
return inTransaction(func(sess *DBSession) error {
dashboard := m.Dashboard{Id: cmd.Id, OrgId: cmd.OrgId}
dashboard := models.Dashboard{Id: cmd.Id, OrgId: cmd.OrgId}
has, err := sess.Get(&dashboard)
if err != nil {
return err
} else if !has {
return m.ErrDashboardNotFound
return models.ErrDashboardNotFound
}
deletes := []string{
@@ -354,12 +355,12 @@ func DeleteDashboard(cmd *m.DeleteDashboardCommand) error {
})
}
func GetDashboards(query *m.GetDashboardsQuery) error {
func GetDashboards(query *models.GetDashboardsQuery) error {
if len(query.DashboardIds) == 0 {
return m.ErrCommandValidationFailed
return models.ErrCommandValidationFailed
}
var dashboards = make([]*m.Dashboard, 0)
var dashboards = make([]*models.Dashboard, 0)
err := x.In("id", query.DashboardIds).Find(&dashboards)
query.Result = dashboards
@@ -368,18 +369,18 @@ func GetDashboards(query *m.GetDashboardsQuery) error {
// GetDashboardPermissionsForUser returns the maximum permission the specified user has for a dashboard(s)
// The function takes in a list of dashboard ids and the user id and role
func GetDashboardPermissionsForUser(query *m.GetDashboardPermissionsForUserQuery) error {
func GetDashboardPermissionsForUser(query *models.GetDashboardPermissionsForUserQuery) error {
if len(query.DashboardIds) == 0 {
return m.ErrCommandValidationFailed
return models.ErrCommandValidationFailed
}
if query.OrgRole == m.ROLE_ADMIN {
var permissions = make([]*m.DashboardPermissionForUser, 0)
if query.OrgRole == models.ROLE_ADMIN {
var permissions = make([]*models.DashboardPermissionForUser, 0)
for _, d := range query.DashboardIds {
permissions = append(permissions, &m.DashboardPermissionForUser{
permissions = append(permissions, &models.DashboardPermissionForUser{
DashboardId: d,
Permission: m.PERMISSION_ADMIN,
PermissionName: m.PERMISSION_ADMIN.String(),
Permission: models.PERMISSION_ADMIN,
PermissionName: models.PERMISSION_ADMIN.String(),
})
}
query.Result = permissions
@@ -436,8 +437,8 @@ func GetDashboardPermissionsForUser(query *m.GetDashboardPermissionsForUserQuery
return err
}
func GetDashboardsByPluginId(query *m.GetDashboardsByPluginIdQuery) error {
var dashboards = make([]*m.Dashboard, 0)
func GetDashboardsByPluginId(query *models.GetDashboardsByPluginIdQuery) error {
var dashboards = make([]*models.Dashboard, 0)
whereExpr := "org_id=? AND plugin_id=? AND is_folder=" + dialect.BooleanStr(false)
err := x.Where(whereExpr, query.OrgId, query.PluginId).Find(&dashboards)
@@ -449,7 +450,7 @@ type DashboardSlugDTO struct {
Slug string
}
func GetDashboardSlugById(query *m.GetDashboardSlugByIdQuery) error {
func GetDashboardSlugById(query *models.GetDashboardSlugByIdQuery) error {
var rawSql = `SELECT slug from dashboard WHERE Id=?`
var slug = DashboardSlugDTO{}
@@ -458,15 +459,15 @@ func GetDashboardSlugById(query *m.GetDashboardSlugByIdQuery) error {
if err != nil {
return err
} else if !exists {
return m.ErrDashboardNotFound
return models.ErrDashboardNotFound
}
query.Result = slug.Slug
return nil
}
func GetDashboardsBySlug(query *m.GetDashboardsBySlugQuery) error {
var dashboards []*m.Dashboard
func GetDashboardsBySlug(query *models.GetDashboardsBySlugQuery) error {
var dashboards []*models.Dashboard
if err := x.Where("org_id=? AND slug=?", query.OrgId, query.Slug).Find(&dashboards); err != nil {
return err
@@ -476,28 +477,28 @@ func GetDashboardsBySlug(query *m.GetDashboardsBySlugQuery) error {
return nil
}
func GetDashboardUIDById(query *m.GetDashboardRefByIdQuery) error {
func GetDashboardUIDById(query *models.GetDashboardRefByIdQuery) error {
var rawSql = `SELECT uid, slug from dashboard WHERE Id=?`
us := &m.DashboardRef{}
us := &models.DashboardRef{}
exists, err := x.SQL(rawSql, query.Id).Get(us)
if err != nil {
return err
} else if !exists {
return m.ErrDashboardNotFound
return models.ErrDashboardNotFound
}
query.Result = us
return nil
}
func getExistingDashboardByIdOrUidForUpdate(sess *DBSession, cmd *m.ValidateDashboardBeforeSaveCommand) (err error) {
func getExistingDashboardByIdOrUidForUpdate(sess *DBSession, cmd *models.ValidateDashboardBeforeSaveCommand) (err error) {
dash := cmd.Dashboard
dashWithIdExists := false
var existingById m.Dashboard
var existingById models.Dashboard
if dash.Id > 0 {
dashWithIdExists, err = sess.Where("id=? AND org_id=?", dash.Id, dash.OrgId).Get(&existingById)
@@ -506,7 +507,7 @@ func getExistingDashboardByIdOrUidForUpdate(sess *DBSession, cmd *m.ValidateDash
}
if !dashWithIdExists {
return m.ErrDashboardNotFound
return models.ErrDashboardNotFound
}
if dash.Uid == "" {
@@ -515,7 +516,7 @@ func getExistingDashboardByIdOrUidForUpdate(sess *DBSession, cmd *m.ValidateDash
}
dashWithUidExists := false
var existingByUid m.Dashboard
var existingByUid models.Dashboard
if dash.Uid != "" {
dashWithUidExists, err = sess.Where("org_id=? AND uid=?", dash.OrgId, dash.Uid).Get(&existingByUid)
@@ -525,14 +526,14 @@ func getExistingDashboardByIdOrUidForUpdate(sess *DBSession, cmd *m.ValidateDash
}
if dash.FolderId > 0 {
var existingFolder m.Dashboard
var existingFolder models.Dashboard
folderExists, folderErr := sess.Where("org_id=? AND id=? AND is_folder=?", dash.OrgId, dash.FolderId, dialect.BooleanStr(true)).Get(&existingFolder)
if folderErr != nil {
return folderErr
}
if !folderExists {
return m.ErrDashboardFolderNotFound
return models.ErrDashboardFolderNotFound
}
}
@@ -541,7 +542,7 @@ func getExistingDashboardByIdOrUidForUpdate(sess *DBSession, cmd *m.ValidateDash
}
if dashWithIdExists && dashWithUidExists && existingById.Id != existingByUid.Id {
return m.ErrDashboardWithSameUIDExists
return models.ErrDashboardWithSameUIDExists
}
existing := existingById
@@ -558,7 +559,7 @@ func getExistingDashboardByIdOrUidForUpdate(sess *DBSession, cmd *m.ValidateDash
if (existing.IsFolder && !dash.IsFolder) ||
(!existing.IsFolder && dash.IsFolder) {
return m.ErrDashboardTypeMismatch
return models.ErrDashboardTypeMismatch
}
if !dash.IsFolder && dash.FolderId != existing.FolderId {
@@ -570,21 +571,21 @@ func getExistingDashboardByIdOrUidForUpdate(sess *DBSession, cmd *m.ValidateDash
if cmd.Overwrite {
dash.SetVersion(existing.Version)
} else {
return m.ErrDashboardVersionMismatch
return models.ErrDashboardVersionMismatch
}
}
// do not allow plugin dashboard updates without overwrite flag
if existing.PluginId != "" && !cmd.Overwrite {
return m.UpdatePluginDashboardError{PluginId: existing.PluginId}
return models.UpdatePluginDashboardError{PluginId: existing.PluginId}
}
return nil
}
func getExistingDashboardByTitleAndFolder(sess *DBSession, cmd *m.ValidateDashboardBeforeSaveCommand) error {
func getExistingDashboardByTitleAndFolder(sess *DBSession, cmd *models.ValidateDashboardBeforeSaveCommand) error {
dash := cmd.Dashboard
var existing m.Dashboard
var existing models.Dashboard
exists, err := sess.Where("org_id=? AND slug=? AND (is_folder=? OR folder_id=?)", dash.OrgId, dash.Slug, dialect.BooleanStr(true), dash.FolderId).Get(&existing)
if err != nil {
@@ -593,11 +594,11 @@ func getExistingDashboardByTitleAndFolder(sess *DBSession, cmd *m.ValidateDashbo
if exists && dash.Id != existing.Id {
if existing.IsFolder && !dash.IsFolder {
return m.ErrDashboardWithSameNameAsFolder
return models.ErrDashboardWithSameNameAsFolder
}
if !existing.IsFolder && dash.IsFolder {
return m.ErrDashboardFolderWithSameNameAsDashboard
return models.ErrDashboardFolderWithSameNameAsDashboard
}
if !dash.IsFolder && (dash.FolderId != existing.FolderId || dash.Id == 0) {
@@ -609,15 +610,15 @@ func getExistingDashboardByTitleAndFolder(sess *DBSession, cmd *m.ValidateDashbo
dash.SetUid(existing.Uid)
dash.SetVersion(existing.Version)
} else {
return m.ErrDashboardWithSameNameInFolderExists
return models.ErrDashboardWithSameNameInFolderExists
}
}
return nil
}
func ValidateDashboardBeforeSave(cmd *m.ValidateDashboardBeforeSaveCommand) (err error) {
cmd.Result = &m.ValidateDashboardBeforeSaveResult{}
func ValidateDashboardBeforeSave(cmd *models.ValidateDashboardBeforeSaveCommand) (err error) {
cmd.Result = &models.ValidateDashboardBeforeSaveResult{}
return inTransaction(func(sess *DBSession) error {
if err = getExistingDashboardByIdOrUidForUpdate(sess, cmd); err != nil {
return err
@@ -631,15 +632,39 @@ func ValidateDashboardBeforeSave(cmd *m.ValidateDashboardBeforeSaveCommand) (err
})
}
func HasEditPermissionInFolders(query *m.HasEditPermissionInFoldersQuery) error {
if query.SignedInUser.HasRole(m.ROLE_EDITOR) {
func HasEditPermissionInFolders(query *models.HasEditPermissionInFoldersQuery) error {
if query.SignedInUser.HasRole(models.ROLE_EDITOR) {
query.Result = true
return nil
}
builder := &SqlBuilder{}
builder.Write("SELECT COUNT(dashboard.id) AS count FROM dashboard WHERE dashboard.org_id = ? AND dashboard.is_folder = ?", query.SignedInUser.OrgId, dialect.BooleanStr(true))
builder.writeDashboardPermissionFilter(query.SignedInUser, m.PERMISSION_EDIT)
builder.writeDashboardPermissionFilter(query.SignedInUser, models.PERMISSION_EDIT)
type folderCount struct {
Count int64
}
resp := make([]*folderCount, 0)
if err := x.SQL(builder.GetSqlString(), builder.params...).Find(&resp); err != nil {
return err
}
query.Result = len(resp) > 0 && resp[0].Count > 0
return nil
}
func HasAdminPermissionInFolders(query *models.HasAdminPermissionInFoldersQuery) error {
if query.SignedInUser.HasRole(models.ROLE_ADMIN) {
query.Result = true
return nil
}
builder := &SqlBuilder{}
builder.Write("SELECT COUNT(dashboard.id) AS count FROM dashboard WHERE dashboard.org_id = ? AND dashboard.is_folder = ?", query.SignedInUser.OrgId, dialect.BooleanStr(true))
builder.writeDashboardPermissionFilter(query.SignedInUser, models.PERMISSION_ADMIN)
type folderCount struct {
Count int64

View File

@@ -5,7 +5,7 @@ import (
. "github.com/smartystreets/goconvey/convey"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/search"
)
@@ -24,7 +24,7 @@ func TestDashboardFolderDataAccess(t *testing.T) {
Convey("and no acls are set", func() {
Convey("should return all dashboards", func() {
query := &search.FindPersistedDashboardsQuery{
SignedInUser: &m.SignedInUser{UserId: currentUser.Id, OrgId: 1, OrgRole: m.ROLE_VIEWER},
SignedInUser: &models.SignedInUser{UserId: currentUser.Id, OrgId: 1, OrgRole: models.ROLE_VIEWER},
OrgId: 1,
DashboardIds: []int64{folder.Id, dashInRoot.Id},
}
@@ -38,11 +38,11 @@ func TestDashboardFolderDataAccess(t *testing.T) {
Convey("and acl is set for dashboard folder", func() {
var otherUser int64 = 999
testHelperUpdateDashboardAcl(folder.Id, m.DashboardAcl{DashboardId: folder.Id, OrgId: 1, UserId: otherUser, Permission: m.PERMISSION_EDIT})
testHelperUpdateDashboardAcl(folder.Id, models.DashboardAcl{DashboardId: folder.Id, OrgId: 1, UserId: otherUser, Permission: models.PERMISSION_EDIT})
Convey("should not return folder", func() {
query := &search.FindPersistedDashboardsQuery{
SignedInUser: &m.SignedInUser{UserId: currentUser.Id, OrgId: 1, OrgRole: m.ROLE_VIEWER},
SignedInUser: &models.SignedInUser{UserId: currentUser.Id, OrgId: 1, OrgRole: models.ROLE_VIEWER},
OrgId: 1, DashboardIds: []int64{folder.Id, dashInRoot.Id},
}
err := SearchDashboards(query)
@@ -53,11 +53,11 @@ func TestDashboardFolderDataAccess(t *testing.T) {
})
Convey("when the user is given permission", func() {
testHelperUpdateDashboardAcl(folder.Id, m.DashboardAcl{DashboardId: folder.Id, OrgId: 1, UserId: currentUser.Id, Permission: m.PERMISSION_EDIT})
testHelperUpdateDashboardAcl(folder.Id, models.DashboardAcl{DashboardId: folder.Id, OrgId: 1, UserId: currentUser.Id, Permission: models.PERMISSION_EDIT})
Convey("should be able to access folder", func() {
query := &search.FindPersistedDashboardsQuery{
SignedInUser: &m.SignedInUser{UserId: currentUser.Id, OrgId: 1, OrgRole: m.ROLE_VIEWER},
SignedInUser: &models.SignedInUser{UserId: currentUser.Id, OrgId: 1, OrgRole: models.ROLE_VIEWER},
OrgId: 1,
DashboardIds: []int64{folder.Id, dashInRoot.Id},
}
@@ -72,10 +72,10 @@ func TestDashboardFolderDataAccess(t *testing.T) {
Convey("when the user is an admin", func() {
Convey("should be able to access folder", func() {
query := &search.FindPersistedDashboardsQuery{
SignedInUser: &m.SignedInUser{
SignedInUser: &models.SignedInUser{
UserId: currentUser.Id,
OrgId: 1,
OrgRole: m.ROLE_ADMIN,
OrgRole: models.ROLE_ADMIN,
},
OrgId: 1,
DashboardIds: []int64{folder.Id, dashInRoot.Id},
@@ -92,10 +92,10 @@ func TestDashboardFolderDataAccess(t *testing.T) {
Convey("and acl is set for dashboard child and folder has all permissions removed", func() {
var otherUser int64 = 999
testHelperUpdateDashboardAcl(folder.Id)
testHelperUpdateDashboardAcl(childDash.Id, m.DashboardAcl{DashboardId: folder.Id, OrgId: 1, UserId: otherUser, Permission: m.PERMISSION_EDIT})
testHelperUpdateDashboardAcl(childDash.Id, models.DashboardAcl{DashboardId: folder.Id, OrgId: 1, UserId: otherUser, Permission: models.PERMISSION_EDIT})
Convey("should not return folder or child", func() {
query := &search.FindPersistedDashboardsQuery{SignedInUser: &m.SignedInUser{UserId: currentUser.Id, OrgId: 1, OrgRole: m.ROLE_VIEWER}, OrgId: 1, DashboardIds: []int64{folder.Id, childDash.Id, dashInRoot.Id}}
query := &search.FindPersistedDashboardsQuery{SignedInUser: &models.SignedInUser{UserId: currentUser.Id, OrgId: 1, OrgRole: models.ROLE_VIEWER}, OrgId: 1, DashboardIds: []int64{folder.Id, childDash.Id, dashInRoot.Id}}
err := SearchDashboards(query)
So(err, ShouldBeNil)
So(len(query.Result), ShouldEqual, 1)
@@ -103,10 +103,10 @@ func TestDashboardFolderDataAccess(t *testing.T) {
})
Convey("when the user is given permission to child", func() {
testHelperUpdateDashboardAcl(childDash.Id, m.DashboardAcl{DashboardId: childDash.Id, OrgId: 1, UserId: currentUser.Id, Permission: m.PERMISSION_EDIT})
testHelperUpdateDashboardAcl(childDash.Id, models.DashboardAcl{DashboardId: childDash.Id, OrgId: 1, UserId: currentUser.Id, Permission: models.PERMISSION_EDIT})
Convey("should be able to search for child dashboard but not folder", func() {
query := &search.FindPersistedDashboardsQuery{SignedInUser: &m.SignedInUser{UserId: currentUser.Id, OrgId: 1, OrgRole: m.ROLE_VIEWER}, OrgId: 1, DashboardIds: []int64{folder.Id, childDash.Id, dashInRoot.Id}}
query := &search.FindPersistedDashboardsQuery{SignedInUser: &models.SignedInUser{UserId: currentUser.Id, OrgId: 1, OrgRole: models.ROLE_VIEWER}, OrgId: 1, DashboardIds: []int64{folder.Id, childDash.Id, dashInRoot.Id}}
err := SearchDashboards(query)
So(err, ShouldBeNil)
So(len(query.Result), ShouldEqual, 2)
@@ -118,10 +118,10 @@ func TestDashboardFolderDataAccess(t *testing.T) {
Convey("when the user is an admin", func() {
Convey("should be able to search for child dash and folder", func() {
query := &search.FindPersistedDashboardsQuery{
SignedInUser: &m.SignedInUser{
SignedInUser: &models.SignedInUser{
UserId: currentUser.Id,
OrgId: 1,
OrgRole: m.ROLE_ADMIN,
OrgRole: models.ROLE_ADMIN,
},
OrgId: 1,
DashboardIds: []int64{folder.Id, dashInRoot.Id, childDash.Id},
@@ -149,7 +149,7 @@ func TestDashboardFolderDataAccess(t *testing.T) {
Convey("and one folder is expanded, the other collapsed", func() {
Convey("should return dashboards in root and expanded folder", func() {
query := &search.FindPersistedDashboardsQuery{FolderIds: []int64{rootFolderId, folder1.Id}, SignedInUser: &m.SignedInUser{UserId: currentUser.Id, OrgId: 1, OrgRole: m.ROLE_VIEWER}, OrgId: 1}
query := &search.FindPersistedDashboardsQuery{FolderIds: []int64{rootFolderId, folder1.Id}, SignedInUser: &models.SignedInUser{UserId: currentUser.Id, OrgId: 1, OrgRole: models.ROLE_VIEWER}, OrgId: 1}
err := SearchDashboards(query)
So(err, ShouldBeNil)
So(len(query.Result), ShouldEqual, 4)
@@ -162,14 +162,14 @@ func TestDashboardFolderDataAccess(t *testing.T) {
Convey("and acl is set for one dashboard folder", func() {
var otherUser int64 = 999
testHelperUpdateDashboardAcl(folder1.Id, m.DashboardAcl{DashboardId: folder1.Id, OrgId: 1, UserId: otherUser, Permission: m.PERMISSION_EDIT})
testHelperUpdateDashboardAcl(folder1.Id, models.DashboardAcl{DashboardId: folder1.Id, OrgId: 1, UserId: otherUser, Permission: models.PERMISSION_EDIT})
Convey("and a dashboard is moved from folder without acl to the folder with an acl", func() {
moveDashboard(1, childDash2.Data, folder1.Id)
Convey("should not return folder with acl or its children", func() {
query := &search.FindPersistedDashboardsQuery{
SignedInUser: &m.SignedInUser{UserId: currentUser.Id, OrgId: 1, OrgRole: m.ROLE_VIEWER},
SignedInUser: &models.SignedInUser{UserId: currentUser.Id, OrgId: 1, OrgRole: models.ROLE_VIEWER},
OrgId: 1,
DashboardIds: []int64{folder1.Id, childDash1.Id, childDash2.Id, dashInRoot.Id},
}
@@ -184,7 +184,7 @@ func TestDashboardFolderDataAccess(t *testing.T) {
Convey("should return folder without acl and its children", func() {
query := &search.FindPersistedDashboardsQuery{
SignedInUser: &m.SignedInUser{UserId: currentUser.Id, OrgId: 1, OrgRole: m.ROLE_VIEWER},
SignedInUser: &models.SignedInUser{UserId: currentUser.Id, OrgId: 1, OrgRole: models.ROLE_VIEWER},
OrgId: 1,
DashboardIds: []int64{folder2.Id, childDash1.Id, childDash2.Id, dashInRoot.Id},
}
@@ -199,12 +199,12 @@ func TestDashboardFolderDataAccess(t *testing.T) {
})
Convey("and a dashboard with an acl is moved to the folder without an acl", func() {
testHelperUpdateDashboardAcl(childDash1.Id, m.DashboardAcl{DashboardId: childDash1.Id, OrgId: 1, UserId: otherUser, Permission: m.PERMISSION_EDIT})
testHelperUpdateDashboardAcl(childDash1.Id, models.DashboardAcl{DashboardId: childDash1.Id, OrgId: 1, UserId: otherUser, Permission: models.PERMISSION_EDIT})
moveDashboard(1, childDash1.Data, folder2.Id)
Convey("should return folder without acl but not the dashboard with acl", func() {
query := &search.FindPersistedDashboardsQuery{
SignedInUser: &m.SignedInUser{UserId: currentUser.Id, OrgId: 1, OrgRole: m.ROLE_VIEWER},
SignedInUser: &models.SignedInUser{UserId: currentUser.Id, OrgId: 1, OrgRole: models.ROLE_VIEWER},
OrgId: 1,
DashboardIds: []int64{folder2.Id, childDash1.Id, childDash2.Id, dashInRoot.Id},
}
@@ -233,8 +233,8 @@ func TestDashboardFolderDataAccess(t *testing.T) {
Convey("Should have write access to all dashboard folders in their org", func() {
query := search.FindPersistedDashboardsQuery{
OrgId: 1,
SignedInUser: &m.SignedInUser{UserId: adminUser.Id, OrgRole: m.ROLE_ADMIN, OrgId: 1},
Permission: m.PERMISSION_VIEW,
SignedInUser: &models.SignedInUser{UserId: adminUser.Id, OrgRole: models.ROLE_ADMIN, OrgId: 1},
Permission: models.PERMISSION_VIEW,
Type: "dash-folder",
}
@@ -247,11 +247,11 @@ func TestDashboardFolderDataAccess(t *testing.T) {
})
Convey("should have write access to all folders and dashboards", func() {
query := m.GetDashboardPermissionsForUserQuery{
query := models.GetDashboardPermissionsForUserQuery{
DashboardIds: []int64{folder1.Id, folder2.Id},
OrgId: 1,
UserId: adminUser.Id,
OrgRole: m.ROLE_ADMIN,
OrgRole: models.ROLE_ADMIN,
}
err := GetDashboardPermissionsForUser(&query)
@@ -259,26 +259,35 @@ func TestDashboardFolderDataAccess(t *testing.T) {
So(len(query.Result), ShouldEqual, 2)
So(query.Result[0].DashboardId, ShouldEqual, folder1.Id)
So(query.Result[0].Permission, ShouldEqual, m.PERMISSION_ADMIN)
So(query.Result[0].Permission, ShouldEqual, models.PERMISSION_ADMIN)
So(query.Result[1].DashboardId, ShouldEqual, folder2.Id)
So(query.Result[1].Permission, ShouldEqual, m.PERMISSION_ADMIN)
So(query.Result[1].Permission, ShouldEqual, models.PERMISSION_ADMIN)
})
Convey("should have edit permission in folders", func() {
query := &m.HasEditPermissionInFoldersQuery{
SignedInUser: &m.SignedInUser{UserId: adminUser.Id, OrgId: 1, OrgRole: m.ROLE_ADMIN},
query := &models.HasEditPermissionInFoldersQuery{
SignedInUser: &models.SignedInUser{UserId: adminUser.Id, OrgId: 1, OrgRole: models.ROLE_ADMIN},
}
err := HasEditPermissionInFolders(query)
So(err, ShouldBeNil)
So(query.Result, ShouldBeTrue)
})
Convey("should have admin permission in folders", func() {
query := &models.HasAdminPermissionInFoldersQuery{
SignedInUser: &models.SignedInUser{UserId: adminUser.Id, OrgId: 1, OrgRole: models.ROLE_ADMIN},
}
err := HasAdminPermissionInFolders(query)
So(err, ShouldBeNil)
So(query.Result, ShouldBeTrue)
})
})
Convey("Editor users", func() {
query := search.FindPersistedDashboardsQuery{
OrgId: 1,
SignedInUser: &m.SignedInUser{UserId: editorUser.Id, OrgRole: m.ROLE_EDITOR, OrgId: 1},
Permission: m.PERMISSION_EDIT,
SignedInUser: &models.SignedInUser{UserId: editorUser.Id, OrgRole: models.ROLE_EDITOR, OrgId: 1},
Permission: models.PERMISSION_EDIT,
}
Convey("Should have write access to all dashboard folders with default ACL", func() {
@@ -291,11 +300,11 @@ func TestDashboardFolderDataAccess(t *testing.T) {
})
Convey("should have edit access to folders with default ACL", func() {
query := m.GetDashboardPermissionsForUserQuery{
query := models.GetDashboardPermissionsForUserQuery{
DashboardIds: []int64{folder1.Id, folder2.Id},
OrgId: 1,
UserId: editorUser.Id,
OrgRole: m.ROLE_EDITOR,
OrgRole: models.ROLE_EDITOR,
}
err := GetDashboardPermissionsForUser(&query)
@@ -303,13 +312,13 @@ func TestDashboardFolderDataAccess(t *testing.T) {
So(len(query.Result), ShouldEqual, 2)
So(query.Result[0].DashboardId, ShouldEqual, folder1.Id)
So(query.Result[0].Permission, ShouldEqual, m.PERMISSION_EDIT)
So(query.Result[0].Permission, ShouldEqual, models.PERMISSION_EDIT)
So(query.Result[1].DashboardId, ShouldEqual, folder2.Id)
So(query.Result[1].Permission, ShouldEqual, m.PERMISSION_EDIT)
So(query.Result[1].Permission, ShouldEqual, models.PERMISSION_EDIT)
})
Convey("Should have write access to one dashboard folder if default role changed to view for one folder", func() {
testHelperUpdateDashboardAcl(folder1.Id, m.DashboardAcl{DashboardId: folder1.Id, OrgId: 1, UserId: editorUser.Id, Permission: m.PERMISSION_VIEW})
testHelperUpdateDashboardAcl(folder1.Id, models.DashboardAcl{DashboardId: folder1.Id, OrgId: 1, UserId: editorUser.Id, Permission: models.PERMISSION_VIEW})
err := SearchDashboards(&query)
So(err, ShouldBeNil)
@@ -319,20 +328,29 @@ func TestDashboardFolderDataAccess(t *testing.T) {
})
Convey("should have edit permission in folders", func() {
query := &m.HasEditPermissionInFoldersQuery{
SignedInUser: &m.SignedInUser{UserId: editorUser.Id, OrgId: 1, OrgRole: m.ROLE_EDITOR},
query := &models.HasEditPermissionInFoldersQuery{
SignedInUser: &models.SignedInUser{UserId: editorUser.Id, OrgId: 1, OrgRole: models.ROLE_EDITOR},
}
err := HasEditPermissionInFolders(query)
So(err, ShouldBeNil)
So(query.Result, ShouldBeTrue)
})
Convey("should not have admin permission in folders", func() {
query := &models.HasAdminPermissionInFoldersQuery{
SignedInUser: &models.SignedInUser{UserId: adminUser.Id, OrgId: 1, OrgRole: models.ROLE_EDITOR},
}
err := HasAdminPermissionInFolders(query)
So(err, ShouldBeNil)
So(query.Result, ShouldBeFalse)
})
})
Convey("Viewer users", func() {
query := search.FindPersistedDashboardsQuery{
OrgId: 1,
SignedInUser: &m.SignedInUser{UserId: viewerUser.Id, OrgRole: m.ROLE_VIEWER, OrgId: 1},
Permission: m.PERMISSION_EDIT,
SignedInUser: &models.SignedInUser{UserId: viewerUser.Id, OrgRole: models.ROLE_VIEWER, OrgId: 1},
Permission: models.PERMISSION_EDIT,
}
Convey("Should have no write access to any dashboard folders with default ACL", func() {
@@ -343,11 +361,11 @@ func TestDashboardFolderDataAccess(t *testing.T) {
})
Convey("should have view access to folders with default ACL", func() {
query := m.GetDashboardPermissionsForUserQuery{
query := models.GetDashboardPermissionsForUserQuery{
DashboardIds: []int64{folder1.Id, folder2.Id},
OrgId: 1,
UserId: viewerUser.Id,
OrgRole: m.ROLE_VIEWER,
OrgRole: models.ROLE_VIEWER,
}
err := GetDashboardPermissionsForUser(&query)
@@ -355,13 +373,13 @@ func TestDashboardFolderDataAccess(t *testing.T) {
So(len(query.Result), ShouldEqual, 2)
So(query.Result[0].DashboardId, ShouldEqual, folder1.Id)
So(query.Result[0].Permission, ShouldEqual, m.PERMISSION_VIEW)
So(query.Result[0].Permission, ShouldEqual, models.PERMISSION_VIEW)
So(query.Result[1].DashboardId, ShouldEqual, folder2.Id)
So(query.Result[1].Permission, ShouldEqual, m.PERMISSION_VIEW)
So(query.Result[1].Permission, ShouldEqual, models.PERMISSION_VIEW)
})
Convey("Should be able to get one dashboard folder if default role changed to edit for one folder", func() {
testHelperUpdateDashboardAcl(folder1.Id, m.DashboardAcl{DashboardId: folder1.Id, OrgId: 1, UserId: viewerUser.Id, Permission: m.PERMISSION_EDIT})
testHelperUpdateDashboardAcl(folder1.Id, models.DashboardAcl{DashboardId: folder1.Id, OrgId: 1, UserId: viewerUser.Id, Permission: models.PERMISSION_EDIT})
err := SearchDashboards(&query)
So(err, ShouldBeNil)
@@ -371,20 +389,29 @@ func TestDashboardFolderDataAccess(t *testing.T) {
})
Convey("should not have edit permission in folders", func() {
query := &m.HasEditPermissionInFoldersQuery{
SignedInUser: &m.SignedInUser{UserId: viewerUser.Id, OrgId: 1, OrgRole: m.ROLE_VIEWER},
query := &models.HasEditPermissionInFoldersQuery{
SignedInUser: &models.SignedInUser{UserId: viewerUser.Id, OrgId: 1, OrgRole: models.ROLE_VIEWER},
}
err := HasEditPermissionInFolders(query)
So(err, ShouldBeNil)
So(query.Result, ShouldBeFalse)
})
Convey("should not have admin permission in folders", func() {
query := &models.HasAdminPermissionInFoldersQuery{
SignedInUser: &models.SignedInUser{UserId: adminUser.Id, OrgId: 1, OrgRole: models.ROLE_VIEWER},
}
err := HasAdminPermissionInFolders(query)
So(err, ShouldBeNil)
So(query.Result, ShouldBeFalse)
})
Convey("and admin permission is given for user with org role viewer in one dashboard folder", func() {
testHelperUpdateDashboardAcl(folder1.Id, m.DashboardAcl{DashboardId: folder1.Id, OrgId: 1, UserId: viewerUser.Id, Permission: m.PERMISSION_ADMIN})
testHelperUpdateDashboardAcl(folder1.Id, models.DashboardAcl{DashboardId: folder1.Id, OrgId: 1, UserId: viewerUser.Id, Permission: models.PERMISSION_ADMIN})
Convey("should have edit permission in folders", func() {
query := &m.HasEditPermissionInFoldersQuery{
SignedInUser: &m.SignedInUser{UserId: viewerUser.Id, OrgId: 1, OrgRole: m.ROLE_VIEWER},
query := &models.HasEditPermissionInFoldersQuery{
SignedInUser: &models.SignedInUser{UserId: viewerUser.Id, OrgId: 1, OrgRole: models.ROLE_VIEWER},
}
err := HasEditPermissionInFolders(query)
So(err, ShouldBeNil)
@@ -393,11 +420,11 @@ func TestDashboardFolderDataAccess(t *testing.T) {
})
Convey("and edit permission is given for user with org role viewer in one dashboard folder", func() {
testHelperUpdateDashboardAcl(folder1.Id, m.DashboardAcl{DashboardId: folder1.Id, OrgId: 1, UserId: viewerUser.Id, Permission: m.PERMISSION_EDIT})
testHelperUpdateDashboardAcl(folder1.Id, models.DashboardAcl{DashboardId: folder1.Id, OrgId: 1, UserId: viewerUser.Id, Permission: models.PERMISSION_EDIT})
Convey("should have edit permission in folders", func() {
query := &m.HasEditPermissionInFoldersQuery{
SignedInUser: &m.SignedInUser{UserId: viewerUser.Id, OrgId: 1, OrgRole: m.ROLE_VIEWER},
query := &models.HasEditPermissionInFoldersQuery{
SignedInUser: &models.SignedInUser{UserId: viewerUser.Id, OrgId: 1, OrgRole: models.ROLE_VIEWER},
}
err := HasEditPermissionInFolders(query)
So(err, ShouldBeNil)

View File

@@ -5,7 +5,7 @@ import (
. "github.com/smartystreets/goconvey/convey"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/models"
)
type Test struct {
@@ -17,11 +17,11 @@ func TestDataAccess(t *testing.T) {
Convey("Testing DB", t, func() {
InitTestDB(t)
Convey("Can add datasource", func() {
err := AddDataSource(&m.AddDataSourceCommand{
err := AddDataSource(&models.AddDataSourceCommand{
OrgId: 10,
Name: "laban",
Type: m.DS_INFLUXDB,
Access: m.DS_ACCESS_DIRECT,
Type: models.DS_INFLUXDB,
Access: models.DS_ACCESS_DIRECT,
Url: "http://test",
Database: "site",
ReadOnly: true,
@@ -29,7 +29,7 @@ func TestDataAccess(t *testing.T) {
So(err, ShouldBeNil)
query := m.GetDataSourcesQuery{OrgId: 10}
query := models.GetDataSourcesQuery{OrgId: 10}
err = GetDataSources(&query)
So(err, ShouldBeNil)
@@ -43,28 +43,28 @@ func TestDataAccess(t *testing.T) {
})
Convey("Given a datasource", func() {
err := AddDataSource(&m.AddDataSourceCommand{
err := AddDataSource(&models.AddDataSourceCommand{
OrgId: 10,
Name: "nisse",
Type: m.DS_GRAPHITE,
Access: m.DS_ACCESS_DIRECT,
Type: models.DS_GRAPHITE,
Access: models.DS_ACCESS_DIRECT,
Url: "http://test",
})
So(err, ShouldBeNil)
query := m.GetDataSourcesQuery{OrgId: 10}
query := models.GetDataSourcesQuery{OrgId: 10}
err = GetDataSources(&query)
So(err, ShouldBeNil)
ds := query.Result[0]
Convey(" updated ", func() {
cmd := &m.UpdateDataSourceCommand{
cmd := &models.UpdateDataSourceCommand{
Id: ds.Id,
OrgId: 10,
Name: "nisse",
Type: m.DS_GRAPHITE,
Access: m.DS_ACCESS_PROXY,
Type: models.DS_GRAPHITE,
Access: models.DS_ACCESS_PROXY,
Url: "http://test",
Version: ds.Version,
}
@@ -75,27 +75,27 @@ func TestDataAccess(t *testing.T) {
})
Convey("when someone else updated between read and update", func() {
query := m.GetDataSourcesQuery{OrgId: 10}
query := models.GetDataSourcesQuery{OrgId: 10}
err = GetDataSources(&query)
So(err, ShouldBeNil)
ds := query.Result[0]
intendedUpdate := &m.UpdateDataSourceCommand{
intendedUpdate := &models.UpdateDataSourceCommand{
Id: ds.Id,
OrgId: 10,
Name: "nisse",
Type: m.DS_GRAPHITE,
Access: m.DS_ACCESS_PROXY,
Type: models.DS_GRAPHITE,
Access: models.DS_ACCESS_PROXY,
Url: "http://test",
Version: ds.Version,
}
updateFromOtherUser := &m.UpdateDataSourceCommand{
updateFromOtherUser := &models.UpdateDataSourceCommand{
Id: ds.Id,
OrgId: 10,
Name: "nisse",
Type: m.DS_GRAPHITE,
Access: m.DS_ACCESS_PROXY,
Type: models.DS_GRAPHITE,
Access: models.DS_ACCESS_PROXY,
Url: "http://test",
Version: ds.Version,
}
@@ -108,12 +108,12 @@ func TestDataAccess(t *testing.T) {
})
Convey("updating datasource without version", func() {
cmd := &m.UpdateDataSourceCommand{
cmd := &models.UpdateDataSourceCommand{
Id: ds.Id,
OrgId: 10,
Name: "nisse",
Type: m.DS_GRAPHITE,
Access: m.DS_ACCESS_PROXY,
Type: models.DS_GRAPHITE,
Access: models.DS_ACCESS_PROXY,
Url: "http://test",
}
@@ -124,12 +124,12 @@ func TestDataAccess(t *testing.T) {
})
Convey("updating datasource without higher version", func() {
cmd := &m.UpdateDataSourceCommand{
cmd := &models.UpdateDataSourceCommand{
Id: ds.Id,
OrgId: 10,
Name: "nisse",
Type: m.DS_GRAPHITE,
Access: m.DS_ACCESS_PROXY,
Type: models.DS_GRAPHITE,
Access: models.DS_ACCESS_PROXY,
Url: "http://test",
Version: 90000,
}
@@ -142,7 +142,7 @@ func TestDataAccess(t *testing.T) {
})
Convey("Can delete datasource by id", func() {
err := DeleteDataSourceById(&m.DeleteDataSourceByIdCommand{Id: ds.Id, OrgId: ds.OrgId})
err := DeleteDataSourceById(&models.DeleteDataSourceByIdCommand{Id: ds.Id, OrgId: ds.OrgId})
So(err, ShouldBeNil)
GetDataSources(&query)
@@ -150,7 +150,7 @@ func TestDataAccess(t *testing.T) {
})
Convey("Can delete datasource by name", func() {
err := DeleteDataSourceByName(&m.DeleteDataSourceByNameCommand{Name: ds.Name, OrgId: ds.OrgId})
err := DeleteDataSourceByName(&models.DeleteDataSourceByNameCommand{Name: ds.Name, OrgId: ds.OrgId})
So(err, ShouldBeNil)
GetDataSources(&query)
@@ -158,7 +158,7 @@ func TestDataAccess(t *testing.T) {
})
Convey("Can not delete datasource with wrong orgId", func() {
err := DeleteDataSourceById(&m.DeleteDataSourceByIdCommand{Id: ds.Id, OrgId: 123123})
err := DeleteDataSourceById(&models.DeleteDataSourceByIdCommand{Id: ds.Id, OrgId: 123123})
So(err, ShouldBeNil)
GetDataSources(&query)

View File

@@ -6,7 +6,7 @@ import (
"time"
"github.com/grafana/grafana/pkg/bus"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/models"
)
func init() {
@@ -21,6 +21,7 @@ func init() {
bus.AddHandler("sql", UpdateTeamMember)
bus.AddHandler("sql", RemoveTeamMember)
bus.AddHandler("sql", GetTeamMembers)
bus.AddHandler("sql", IsAdminOfTeams)
}
func getTeamSearchSqlBase() string {
@@ -45,16 +46,16 @@ func getTeamSelectSqlBase() string {
FROM team as team `
}
func CreateTeam(cmd *m.CreateTeamCommand) error {
func CreateTeam(cmd *models.CreateTeamCommand) error {
return inTransaction(func(sess *DBSession) error {
if isNameTaken, err := isTeamNameTaken(cmd.OrgId, cmd.Name, 0, sess); err != nil {
return err
} else if isNameTaken {
return m.ErrTeamNameTaken
return models.ErrTeamNameTaken
}
team := m.Team{
team := models.Team{
Name: cmd.Name,
Email: cmd.Email,
OrgId: cmd.OrgId,
@@ -70,16 +71,16 @@ func CreateTeam(cmd *m.CreateTeamCommand) error {
})
}
func UpdateTeam(cmd *m.UpdateTeamCommand) error {
func UpdateTeam(cmd *models.UpdateTeamCommand) error {
return inTransaction(func(sess *DBSession) error {
if isNameTaken, err := isTeamNameTaken(cmd.OrgId, cmd.Name, cmd.Id, sess); err != nil {
return err
} else if isNameTaken {
return m.ErrTeamNameTaken
return models.ErrTeamNameTaken
}
team := m.Team{
team := models.Team{
Name: cmd.Name,
Email: cmd.Email,
Updated: time.Now(),
@@ -94,7 +95,7 @@ func UpdateTeam(cmd *m.UpdateTeamCommand) error {
}
if affectedRows == 0 {
return m.ErrTeamNotFound
return models.ErrTeamNotFound
}
return nil
@@ -102,7 +103,7 @@ func UpdateTeam(cmd *m.UpdateTeamCommand) error {
}
// DeleteTeam will delete a team, its member and any permissions connected to the team
func DeleteTeam(cmd *m.DeleteTeamCommand) error {
func DeleteTeam(cmd *models.DeleteTeamCommand) error {
return inTransaction(func(sess *DBSession) error {
if _, err := teamExists(cmd.OrgId, cmd.Id, sess); err != nil {
return err
@@ -128,14 +129,14 @@ func teamExists(orgId int64, teamId int64, sess *DBSession) (bool, error) {
if res, err := sess.Query("SELECT 1 from team WHERE org_id=? and id=?", orgId, teamId); err != nil {
return false, err
} else if len(res) != 1 {
return false, m.ErrTeamNotFound
return false, models.ErrTeamNotFound
}
return true, nil
}
func isTeamNameTaken(orgId int64, name string, existingId int64, sess *DBSession) (bool, error) {
var team m.Team
var team models.Team
exists, err := sess.Where("org_id=? and name=?", orgId, name).Get(&team)
if err != nil {
@@ -149,9 +150,9 @@ func isTeamNameTaken(orgId int64, name string, existingId int64, sess *DBSession
return false, nil
}
func SearchTeams(query *m.SearchTeamsQuery) error {
query.Result = m.SearchTeamQueryResult{
Teams: make([]*m.TeamDTO, 0),
func SearchTeams(query *models.SearchTeamsQuery) error {
query.Result = models.SearchTeamQueryResult{
Teams: make([]*models.TeamDTO, 0),
}
queryWithWildcards := "%" + query.Query + "%"
@@ -189,7 +190,7 @@ func SearchTeams(query *m.SearchTeamsQuery) error {
return err
}
team := m.Team{}
team := models.Team{}
countSess := x.Table("team")
if query.Query != "" {
countSess.Where(`name `+dialect.LikeStr()+` ?`, queryWithWildcards)
@@ -205,13 +206,13 @@ func SearchTeams(query *m.SearchTeamsQuery) error {
return err
}
func GetTeamById(query *m.GetTeamByIdQuery) error {
func GetTeamById(query *models.GetTeamByIdQuery) error {
var sql bytes.Buffer
sql.WriteString(getTeamSelectSqlBase())
sql.WriteString(` WHERE team.org_id = ? and team.id = ?`)
var team m.TeamDTO
var team models.TeamDTO
exists, err := x.SQL(sql.String(), query.OrgId, query.Id).Get(&team)
if err != nil {
@@ -219,7 +220,7 @@ func GetTeamById(query *m.GetTeamByIdQuery) error {
}
if !exists {
return m.ErrTeamNotFound
return models.ErrTeamNotFound
}
query.Result = &team
@@ -227,8 +228,8 @@ func GetTeamById(query *m.GetTeamByIdQuery) error {
}
// GetTeamsByUser is used by the Guardian when checking a users' permissions
func GetTeamsByUser(query *m.GetTeamsByUserQuery) error {
query.Result = make([]*m.TeamDTO, 0)
func GetTeamsByUser(query *models.GetTeamsByUserQuery) error {
query.Result = make([]*models.TeamDTO, 0)
var sql bytes.Buffer
@@ -241,19 +242,19 @@ func GetTeamsByUser(query *m.GetTeamsByUserQuery) error {
}
// AddTeamMember adds a user to a team
func AddTeamMember(cmd *m.AddTeamMemberCommand) error {
func AddTeamMember(cmd *models.AddTeamMemberCommand) error {
return inTransaction(func(sess *DBSession) error {
if res, err := sess.Query("SELECT 1 from team_member WHERE org_id=? and team_id=? and user_id=?", cmd.OrgId, cmd.TeamId, cmd.UserId); err != nil {
return err
} else if len(res) == 1 {
return m.ErrTeamMemberAlreadyAdded
return models.ErrTeamMemberAlreadyAdded
}
if _, err := teamExists(cmd.OrgId, cmd.TeamId, sess); err != nil {
return err
}
entity := m.TeamMember{
entity := models.TeamMember{
OrgId: cmd.OrgId,
TeamId: cmd.TeamId,
UserId: cmd.UserId,
@@ -268,23 +269,23 @@ func AddTeamMember(cmd *m.AddTeamMemberCommand) error {
})
}
func getTeamMember(sess *DBSession, orgId int64, teamId int64, userId int64) (m.TeamMember, error) {
func getTeamMember(sess *DBSession, orgId int64, teamId int64, userId int64) (models.TeamMember, error) {
rawSql := `SELECT * FROM team_member WHERE org_id=? and team_id=? and user_id=?`
var member m.TeamMember
var member models.TeamMember
exists, err := sess.SQL(rawSql, orgId, teamId, userId).Get(&member)
if err != nil {
return member, err
}
if !exists {
return member, m.ErrTeamMemberNotFound
return member, models.ErrTeamMemberNotFound
}
return member, nil
}
// UpdateTeamMember updates a team member
func UpdateTeamMember(cmd *m.UpdateTeamMemberCommand) error {
func UpdateTeamMember(cmd *models.UpdateTeamMemberCommand) error {
return inTransaction(func(sess *DBSession) error {
member, err := getTeamMember(sess, cmd.OrgId, cmd.TeamId, cmd.UserId)
if err != nil {
@@ -298,7 +299,7 @@ func UpdateTeamMember(cmd *m.UpdateTeamMemberCommand) error {
}
}
if cmd.Permission != m.PERMISSION_ADMIN { // make sure we don't get invalid permission levels in store
if cmd.Permission != models.PERMISSION_ADMIN { // make sure we don't get invalid permission levels in store
cmd.Permission = 0
}
@@ -310,7 +311,7 @@ func UpdateTeamMember(cmd *m.UpdateTeamMemberCommand) error {
}
// RemoveTeamMember removes a member from a team
func RemoveTeamMember(cmd *m.RemoveTeamMemberCommand) error {
func RemoveTeamMember(cmd *models.RemoveTeamMemberCommand) error {
return inTransaction(func(sess *DBSession) error {
if _, err := teamExists(cmd.OrgId, cmd.TeamId, sess); err != nil {
return err
@@ -330,7 +331,7 @@ func RemoveTeamMember(cmd *m.RemoveTeamMemberCommand) error {
}
rows, err := res.RowsAffected()
if rows == 0 {
return m.ErrTeamMemberNotFound
return models.ErrTeamMemberNotFound
}
return err
@@ -340,7 +341,7 @@ func RemoveTeamMember(cmd *m.RemoveTeamMemberCommand) error {
func isLastAdmin(sess *DBSession, orgId int64, teamId int64, userId int64) (bool, error) {
rawSql := "SELECT user_id FROM team_member WHERE org_id=? and team_id=? and permission=?"
userIds := []*int64{}
err := sess.SQL(rawSql, orgId, teamId, m.PERMISSION_ADMIN).Find(&userIds)
err := sess.SQL(rawSql, orgId, teamId, models.PERMISSION_ADMIN).Find(&userIds)
if err != nil {
return false, err
}
@@ -354,15 +355,15 @@ func isLastAdmin(sess *DBSession, orgId int64, teamId int64, userId int64) (bool
}
if isAdmin && len(userIds) == 1 {
return true, m.ErrLastTeamAdmin
return true, models.ErrLastTeamAdmin
}
return false, err
}
// GetTeamMembers return a list of members for the specified team
func GetTeamMembers(query *m.GetTeamMembersQuery) error {
query.Result = make([]*m.TeamMemberDTO, 0)
func GetTeamMembers(query *models.GetTeamMembersQuery) error {
query.Result = make([]*models.TeamMemberDTO, 0)
sess := x.Table("team_member")
sess.Join("INNER", x.Dialect().Quote("user"), fmt.Sprintf("team_member.user_id=%s.id", x.Dialect().Quote("user")))
@@ -392,3 +393,21 @@ func GetTeamMembers(query *m.GetTeamMembersQuery) error {
err := sess.Find(&query.Result)
return err
}
func IsAdminOfTeams(query *models.IsAdminOfTeamsQuery) error {
builder := &SqlBuilder{}
builder.Write("SELECT COUNT(team.id) AS count FROM team INNER JOIN team_member ON team_member.team_id = team.id WHERE team.org_id = ? AND team_member.user_id = ? AND team_member.permission = ?", query.SignedInUser.OrgId, query.SignedInUser.UserId, models.PERMISSION_ADMIN)
type teamCount struct {
Count int64
}
resp := make([]*teamCount, 0)
if err := x.SQL(builder.GetSqlString(), builder.params...).Find(&resp); err != nil {
return err
}
query.Result = len(resp) > 0 && resp[0].Count > 0
return nil
}

View File

@@ -7,7 +7,7 @@ import (
. "github.com/smartystreets/goconvey/convey"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/models"
)
func TestTeamCommandsAndQueries(t *testing.T) {
@@ -18,7 +18,7 @@ func TestTeamCommandsAndQueries(t *testing.T) {
Convey("Given saved users and two teams", func() {
var userIds []int64
for i := 0; i < 5; i++ {
userCmd := &m.CreateUserCommand{
userCmd := &models.CreateUserCommand{
Email: fmt.Sprint("user", i, "@test.com"),
Name: fmt.Sprint("user", i),
Login: fmt.Sprint("loginuser", i),
@@ -29,8 +29,8 @@ func TestTeamCommandsAndQueries(t *testing.T) {
}
var testOrgId int64 = 1
group1 := m.CreateTeamCommand{OrgId: testOrgId, Name: "group1 name", Email: "test1@test.com"}
group2 := m.CreateTeamCommand{OrgId: testOrgId, Name: "group2 name", Email: "test2@test.com"}
group1 := models.CreateTeamCommand{OrgId: testOrgId, Name: "group1 name", Email: "test1@test.com"}
group2 := models.CreateTeamCommand{OrgId: testOrgId, Name: "group2 name", Email: "test2@test.com"}
err := CreateTeam(&group1)
So(err, ShouldBeNil)
@@ -38,7 +38,7 @@ func TestTeamCommandsAndQueries(t *testing.T) {
So(err, ShouldBeNil)
Convey("Should be able to create teams and add users", func() {
query := &m.SearchTeamsQuery{OrgId: testOrgId, Name: "group1 name", Page: 1, Limit: 10}
query := &models.SearchTeamsQuery{OrgId: testOrgId, Name: "group1 name", Page: 1, Limit: 10}
err = SearchTeams(query)
So(err, ShouldBeNil)
So(query.Page, ShouldEqual, 1)
@@ -48,12 +48,12 @@ func TestTeamCommandsAndQueries(t *testing.T) {
So(team1.Email, ShouldEqual, "test1@test.com")
So(team1.OrgId, ShouldEqual, testOrgId)
err = AddTeamMember(&m.AddTeamMemberCommand{OrgId: testOrgId, TeamId: team1.Id, UserId: userIds[0]})
err = AddTeamMember(&models.AddTeamMemberCommand{OrgId: testOrgId, TeamId: team1.Id, UserId: userIds[0]})
So(err, ShouldBeNil)
err = AddTeamMember(&m.AddTeamMemberCommand{OrgId: testOrgId, TeamId: team1.Id, UserId: userIds[1], External: true})
err = AddTeamMember(&models.AddTeamMemberCommand{OrgId: testOrgId, TeamId: team1.Id, UserId: userIds[1], External: true})
So(err, ShouldBeNil)
q1 := &m.GetTeamMembersQuery{OrgId: testOrgId, TeamId: team1.Id}
q1 := &models.GetTeamMembersQuery{OrgId: testOrgId, TeamId: team1.Id}
err = GetTeamMembers(q1)
So(err, ShouldBeNil)
So(q1.Result, ShouldHaveLength, 2)
@@ -65,7 +65,7 @@ func TestTeamCommandsAndQueries(t *testing.T) {
So(q1.Result[1].OrgId, ShouldEqual, testOrgId)
So(q1.Result[1].External, ShouldEqual, true)
q2 := &m.GetTeamMembersQuery{OrgId: testOrgId, TeamId: team1.Id, External: true}
q2 := &models.GetTeamMembersQuery{OrgId: testOrgId, TeamId: team1.Id, External: true}
err = GetTeamMembers(q2)
So(err, ShouldBeNil)
So(q2.Result, ShouldHaveLength, 1)
@@ -77,20 +77,20 @@ func TestTeamCommandsAndQueries(t *testing.T) {
Convey("Should return latest auth module for users when getting team members", func() {
userId := userIds[1]
err := SetAuthInfo(&m.SetAuthInfoCommand{UserId: userId, AuthModule: "oauth_github", AuthId: "1234567"})
err := SetAuthInfo(&models.SetAuthInfoCommand{UserId: userId, AuthModule: "oauth_github", AuthId: "1234567"})
So(err, ShouldBeNil)
teamQuery := &m.SearchTeamsQuery{OrgId: testOrgId, Name: "group1 name", Page: 1, Limit: 10}
teamQuery := &models.SearchTeamsQuery{OrgId: testOrgId, Name: "group1 name", Page: 1, Limit: 10}
err = SearchTeams(teamQuery)
So(err, ShouldBeNil)
So(teamQuery.Page, ShouldEqual, 1)
team1 := teamQuery.Result.Teams[0]
err = AddTeamMember(&m.AddTeamMemberCommand{OrgId: testOrgId, TeamId: team1.Id, UserId: userId, External: true})
err = AddTeamMember(&models.AddTeamMemberCommand{OrgId: testOrgId, TeamId: team1.Id, UserId: userId, External: true})
So(err, ShouldBeNil)
memberQuery := &m.GetTeamMembersQuery{OrgId: testOrgId, TeamId: team1.Id, External: true}
memberQuery := &models.GetTeamMembersQuery{OrgId: testOrgId, TeamId: team1.Id, External: true}
err = GetTeamMembers(memberQuery)
So(err, ShouldBeNil)
So(memberQuery.Result, ShouldHaveLength, 1)
@@ -104,44 +104,44 @@ func TestTeamCommandsAndQueries(t *testing.T) {
Convey("Should be able to update users in a team", func() {
userId := userIds[0]
team := group1.Result
addMemberCmd := m.AddTeamMemberCommand{OrgId: testOrgId, TeamId: team.Id, UserId: userId}
addMemberCmd := models.AddTeamMemberCommand{OrgId: testOrgId, TeamId: team.Id, UserId: userId}
err = AddTeamMember(&addMemberCmd)
So(err, ShouldBeNil)
qBeforeUpdate := &m.GetTeamMembersQuery{OrgId: testOrgId, TeamId: team.Id}
qBeforeUpdate := &models.GetTeamMembersQuery{OrgId: testOrgId, TeamId: team.Id}
err = GetTeamMembers(qBeforeUpdate)
So(err, ShouldBeNil)
So(qBeforeUpdate.Result[0].Permission, ShouldEqual, 0)
err = UpdateTeamMember(&m.UpdateTeamMemberCommand{
err = UpdateTeamMember(&models.UpdateTeamMemberCommand{
UserId: userId,
OrgId: testOrgId,
TeamId: team.Id,
Permission: m.PERMISSION_ADMIN,
Permission: models.PERMISSION_ADMIN,
})
So(err, ShouldBeNil)
qAfterUpdate := &m.GetTeamMembersQuery{OrgId: testOrgId, TeamId: team.Id}
qAfterUpdate := &models.GetTeamMembersQuery{OrgId: testOrgId, TeamId: team.Id}
err = GetTeamMembers(qAfterUpdate)
So(err, ShouldBeNil)
So(qAfterUpdate.Result[0].Permission, ShouldEqual, m.PERMISSION_ADMIN)
So(qAfterUpdate.Result[0].Permission, ShouldEqual, models.PERMISSION_ADMIN)
})
Convey("Should default to member permission level when updating a user with invalid permission level", func() {
userID := userIds[0]
team := group1.Result
addMemberCmd := m.AddTeamMemberCommand{OrgId: testOrgId, TeamId: team.Id, UserId: userID}
addMemberCmd := models.AddTeamMemberCommand{OrgId: testOrgId, TeamId: team.Id, UserId: userID}
err = AddTeamMember(&addMemberCmd)
So(err, ShouldBeNil)
qBeforeUpdate := &m.GetTeamMembersQuery{OrgId: testOrgId, TeamId: team.Id}
qBeforeUpdate := &models.GetTeamMembersQuery{OrgId: testOrgId, TeamId: team.Id}
err = GetTeamMembers(qBeforeUpdate)
So(err, ShouldBeNil)
So(qBeforeUpdate.Result[0].Permission, ShouldEqual, 0)
invalidPermissionLevel := m.PERMISSION_EDIT
err = UpdateTeamMember(&m.UpdateTeamMemberCommand{
invalidPermissionLevel := models.PERMISSION_EDIT
err = UpdateTeamMember(&models.UpdateTeamMemberCommand{
UserId: userID,
OrgId: testOrgId,
TeamId: team.Id,
@@ -150,31 +150,31 @@ func TestTeamCommandsAndQueries(t *testing.T) {
So(err, ShouldBeNil)
qAfterUpdate := &m.GetTeamMembersQuery{OrgId: testOrgId, TeamId: team.Id}
qAfterUpdate := &models.GetTeamMembersQuery{OrgId: testOrgId, TeamId: team.Id}
err = GetTeamMembers(qAfterUpdate)
So(err, ShouldBeNil)
So(qAfterUpdate.Result[0].Permission, ShouldEqual, 0)
})
Convey("Shouldn't be able to update a user not in the team.", func() {
err = UpdateTeamMember(&m.UpdateTeamMemberCommand{
err = UpdateTeamMember(&models.UpdateTeamMemberCommand{
UserId: 1,
OrgId: testOrgId,
TeamId: group1.Result.Id,
Permission: m.PERMISSION_ADMIN,
Permission: models.PERMISSION_ADMIN,
})
So(err, ShouldEqual, m.ErrTeamMemberNotFound)
So(err, ShouldEqual, models.ErrTeamMemberNotFound)
})
Convey("Should be able to search for teams", func() {
query := &m.SearchTeamsQuery{OrgId: testOrgId, Query: "group", Page: 1}
query := &models.SearchTeamsQuery{OrgId: testOrgId, Query: "group", Page: 1}
err = SearchTeams(query)
So(err, ShouldBeNil)
So(len(query.Result.Teams), ShouldEqual, 2)
So(query.Result.TotalCount, ShouldEqual, 2)
query2 := &m.SearchTeamsQuery{OrgId: testOrgId, Query: ""}
query2 := &models.SearchTeamsQuery{OrgId: testOrgId, Query: ""}
err = SearchTeams(query2)
So(err, ShouldBeNil)
So(len(query2.Result.Teams), ShouldEqual, 2)
@@ -182,10 +182,10 @@ func TestTeamCommandsAndQueries(t *testing.T) {
Convey("Should be able to return all teams a user is member of", func() {
groupId := group2.Result.Id
err := AddTeamMember(&m.AddTeamMemberCommand{OrgId: testOrgId, TeamId: groupId, UserId: userIds[0]})
err := AddTeamMember(&models.AddTeamMemberCommand{OrgId: testOrgId, TeamId: groupId, UserId: userIds[0]})
So(err, ShouldBeNil)
query := &m.GetTeamsByUserQuery{OrgId: testOrgId, UserId: userIds[0]}
query := &models.GetTeamsByUserQuery{OrgId: testOrgId, UserId: userIds[0]}
err = GetTeamsByUser(query)
So(err, ShouldBeNil)
So(len(query.Result), ShouldEqual, 1)
@@ -194,66 +194,84 @@ func TestTeamCommandsAndQueries(t *testing.T) {
})
Convey("Should be able to remove users from a group", func() {
err = AddTeamMember(&m.AddTeamMemberCommand{OrgId: testOrgId, TeamId: group1.Result.Id, UserId: userIds[0]})
err = AddTeamMember(&models.AddTeamMemberCommand{OrgId: testOrgId, TeamId: group1.Result.Id, UserId: userIds[0]})
So(err, ShouldBeNil)
err = RemoveTeamMember(&m.RemoveTeamMemberCommand{OrgId: testOrgId, TeamId: group1.Result.Id, UserId: userIds[0]})
err = RemoveTeamMember(&models.RemoveTeamMemberCommand{OrgId: testOrgId, TeamId: group1.Result.Id, UserId: userIds[0]})
So(err, ShouldBeNil)
q2 := &m.GetTeamMembersQuery{OrgId: testOrgId, TeamId: group1.Result.Id}
q2 := &models.GetTeamMembersQuery{OrgId: testOrgId, TeamId: group1.Result.Id}
err = GetTeamMembers(q2)
So(err, ShouldBeNil)
So(len(q2.Result), ShouldEqual, 0)
})
Convey("When ProtectLastAdmin is set to true", func() {
err = AddTeamMember(&m.AddTeamMemberCommand{OrgId: testOrgId, TeamId: group1.Result.Id, UserId: userIds[0], Permission: m.PERMISSION_ADMIN})
err = AddTeamMember(&models.AddTeamMemberCommand{OrgId: testOrgId, TeamId: group1.Result.Id, UserId: userIds[0], Permission: models.PERMISSION_ADMIN})
So(err, ShouldBeNil)
Convey("A user should not be able to remove the last admin", func() {
err = RemoveTeamMember(&m.RemoveTeamMemberCommand{OrgId: testOrgId, TeamId: group1.Result.Id, UserId: userIds[0], ProtectLastAdmin: true})
So(err, ShouldEqual, m.ErrLastTeamAdmin)
err = RemoveTeamMember(&models.RemoveTeamMemberCommand{OrgId: testOrgId, TeamId: group1.Result.Id, UserId: userIds[0], ProtectLastAdmin: true})
So(err, ShouldEqual, models.ErrLastTeamAdmin)
})
Convey("A user should be able to remove an admin if there are other admins", func() {
AddTeamMember(&m.AddTeamMemberCommand{OrgId: testOrgId, TeamId: group1.Result.Id, UserId: userIds[1], Permission: m.PERMISSION_ADMIN})
err = RemoveTeamMember(&m.RemoveTeamMemberCommand{OrgId: testOrgId, TeamId: group1.Result.Id, UserId: userIds[0], ProtectLastAdmin: true})
AddTeamMember(&models.AddTeamMemberCommand{OrgId: testOrgId, TeamId: group1.Result.Id, UserId: userIds[1], Permission: models.PERMISSION_ADMIN})
err = RemoveTeamMember(&models.RemoveTeamMemberCommand{OrgId: testOrgId, TeamId: group1.Result.Id, UserId: userIds[0], ProtectLastAdmin: true})
So(err, ShouldEqual, nil)
})
Convey("A user should not be able to remove the admin permission for the last admin", func() {
err = UpdateTeamMember(&m.UpdateTeamMemberCommand{OrgId: testOrgId, TeamId: group1.Result.Id, UserId: userIds[0], Permission: 0, ProtectLastAdmin: true})
So(err, ShouldEqual, m.ErrLastTeamAdmin)
err = UpdateTeamMember(&models.UpdateTeamMemberCommand{OrgId: testOrgId, TeamId: group1.Result.Id, UserId: userIds[0], Permission: 0, ProtectLastAdmin: true})
So(err, ShouldEqual, models.ErrLastTeamAdmin)
})
Convey("A user should be able to remove the admin permission if there are other admins", func() {
AddTeamMember(&m.AddTeamMemberCommand{OrgId: testOrgId, TeamId: group1.Result.Id, UserId: userIds[1], Permission: m.PERMISSION_ADMIN})
err = UpdateTeamMember(&m.UpdateTeamMemberCommand{OrgId: testOrgId, TeamId: group1.Result.Id, UserId: userIds[0], Permission: 0, ProtectLastAdmin: true})
AddTeamMember(&models.AddTeamMemberCommand{OrgId: testOrgId, TeamId: group1.Result.Id, UserId: userIds[1], Permission: models.PERMISSION_ADMIN})
err = UpdateTeamMember(&models.UpdateTeamMemberCommand{OrgId: testOrgId, TeamId: group1.Result.Id, UserId: userIds[0], Permission: 0, ProtectLastAdmin: true})
So(err, ShouldEqual, nil)
})
})
Convey("Should be able to remove a group with users and permissions", func() {
groupId := group2.Result.Id
err := AddTeamMember(&m.AddTeamMemberCommand{OrgId: testOrgId, TeamId: groupId, UserId: userIds[1]})
err := AddTeamMember(&models.AddTeamMemberCommand{OrgId: testOrgId, TeamId: groupId, UserId: userIds[1]})
So(err, ShouldBeNil)
err = AddTeamMember(&m.AddTeamMemberCommand{OrgId: testOrgId, TeamId: groupId, UserId: userIds[2]})
err = AddTeamMember(&models.AddTeamMemberCommand{OrgId: testOrgId, TeamId: groupId, UserId: userIds[2]})
So(err, ShouldBeNil)
err = testHelperUpdateDashboardAcl(1, m.DashboardAcl{DashboardId: 1, OrgId: testOrgId, Permission: m.PERMISSION_EDIT, TeamId: groupId})
err = testHelperUpdateDashboardAcl(1, models.DashboardAcl{DashboardId: 1, OrgId: testOrgId, Permission: models.PERMISSION_EDIT, TeamId: groupId})
So(err, ShouldBeNil)
err = DeleteTeam(&m.DeleteTeamCommand{OrgId: testOrgId, Id: groupId})
err = DeleteTeam(&models.DeleteTeamCommand{OrgId: testOrgId, Id: groupId})
So(err, ShouldBeNil)
query := &m.GetTeamByIdQuery{OrgId: testOrgId, Id: groupId}
query := &models.GetTeamByIdQuery{OrgId: testOrgId, Id: groupId}
err = GetTeamById(query)
So(err, ShouldEqual, m.ErrTeamNotFound)
So(err, ShouldEqual, models.ErrTeamNotFound)
permQuery := &m.GetDashboardAclInfoListQuery{DashboardId: 1, OrgId: testOrgId}
permQuery := &models.GetDashboardAclInfoListQuery{DashboardId: 1, OrgId: testOrgId}
err = GetDashboardAclInfoList(permQuery)
So(err, ShouldBeNil)
So(len(permQuery.Result), ShouldEqual, 0)
})
Convey("Should be able to return if user is admin of teams or not", func() {
groupId := group2.Result.Id
err := AddTeamMember(&models.AddTeamMemberCommand{OrgId: testOrgId, TeamId: groupId, UserId: userIds[0]})
So(err, ShouldBeNil)
err = AddTeamMember(&models.AddTeamMemberCommand{OrgId: testOrgId, TeamId: groupId, UserId: userIds[1], Permission: models.PERMISSION_ADMIN})
So(err, ShouldBeNil)
query := &models.IsAdminOfTeamsQuery{SignedInUser: &models.SignedInUser{OrgId: testOrgId, UserId: userIds[0]}}
err = IsAdminOfTeams(query)
So(err, ShouldBeNil)
So(query.Result, ShouldBeFalse)
query = &models.IsAdminOfTeamsQuery{SignedInUser: &models.SignedInUser{OrgId: testOrgId, UserId: userIds[1]}}
err = IsAdminOfTeams(query)
So(err, ShouldBeNil)
So(query.Result, ShouldBeTrue)
})
})
})
}