Chore: Refactor api handlers to use web.Bind (#42199)

* Chore: Refactor api handlers to use web.Bind

* fix comments

* fix comment

* trying to fix most of the tests and force routing.Wrap type check

* fix library panels tests

* fix frontend logging tests

* allow passing nil as a response to skip writing

* return nil instead of the response

* rewrite login handler function types

* remove handlerFuncCtx

* make linter happy

* remove old bindings from the libraryelements

* restore comments
This commit is contained in:
Serge Zaitsev
2021-11-29 10:18:01 +01:00
committed by GitHub
parent 9cbc872f22
commit d9cdcb550e
54 changed files with 739 additions and 299 deletions
+22 -4
View File
@@ -3,6 +3,7 @@ package api
import ( import (
"errors" "errors"
"fmt" "fmt"
"net/http"
"github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/api/response"
@@ -11,9 +12,14 @@ import (
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/util"
"github.com/grafana/grafana/pkg/web"
) )
func (hs *HTTPServer) AdminCreateUser(c *models.ReqContext, form dtos.AdminCreateUserForm) response.Response { func (hs *HTTPServer) AdminCreateUser(c *models.ReqContext) response.Response {
form := dtos.AdminCreateUserForm{}
if err := web.Bind(c.Req, &form); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
cmd := models.CreateUserCommand{ cmd := models.CreateUserCommand{
Login: form.Login, Login: form.Login,
Email: form.Email, Email: form.Email,
@@ -56,7 +62,11 @@ func (hs *HTTPServer) AdminCreateUser(c *models.ReqContext, form dtos.AdminCreat
return response.JSON(200, result) return response.JSON(200, result)
} }
func AdminUpdateUserPassword(c *models.ReqContext, form dtos.AdminUpdateUserPasswordForm) response.Response { func AdminUpdateUserPassword(c *models.ReqContext) response.Response {
form := dtos.AdminUpdateUserPasswordForm{}
if err := web.Bind(c.Req, &form); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
userID := c.ParamsInt64(":id") userID := c.ParamsInt64(":id")
if len(form.Password) < 4 { if len(form.Password) < 4 {
@@ -87,7 +97,11 @@ func AdminUpdateUserPassword(c *models.ReqContext, form dtos.AdminUpdateUserPass
} }
// PUT /api/admin/users/:id/permissions // PUT /api/admin/users/:id/permissions
func (hs *HTTPServer) AdminUpdateUserPermissions(c *models.ReqContext, form dtos.AdminUpdateUserPermissionsForm) response.Response { func (hs *HTTPServer) AdminUpdateUserPermissions(c *models.ReqContext) response.Response {
form := dtos.AdminUpdateUserPermissionsForm{}
if err := web.Bind(c.Req, &form); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
userID := c.ParamsInt64(":id") userID := c.ParamsInt64(":id")
err := updateUserPermissions(hs.SQLStore, userID, form.IsGrafanaAdmin) err := updateUserPermissions(hs.SQLStore, userID, form.IsGrafanaAdmin)
@@ -182,7 +196,11 @@ func (hs *HTTPServer) AdminGetUserAuthTokens(c *models.ReqContext) response.Resp
} }
// POST /api/admin/users/:id/revoke-auth-token // POST /api/admin/users/:id/revoke-auth-token
func (hs *HTTPServer) AdminRevokeUserAuthToken(c *models.ReqContext, cmd models.RevokeAuthTokenCmd) response.Response { func (hs *HTTPServer) AdminRevokeUserAuthToken(c *models.ReqContext) response.Response {
cmd := models.RevokeAuthTokenCmd{}
if err := web.Bind(c.Req, &cmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
userID := c.ParamsInt64(":id") userID := c.ParamsInt64(":id")
return hs.revokeUserAuthTokenInternal(c, userID, cmd) return hs.revokeUserAuthTokenInternal(c, userID, cmd)
} }
+6 -3
View File
@@ -315,12 +315,13 @@ func putAdminScenario(t *testing.T, desc string, url string, routePattern string
sc := setupScenarioContext(t, url) sc := setupScenarioContext(t, url)
sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response {
c.Req.Body = mockRequestBody(cmd)
sc.context = c sc.context = c
sc.context.UserId = testUserID sc.context.UserId = testUserID
sc.context.OrgId = testOrgID sc.context.OrgId = testOrgID
sc.context.OrgRole = role sc.context.OrgRole = role
return hs.AdminUpdateUserPermissions(c, cmd) return hs.AdminUpdateUserPermissions(c)
}) })
sc.m.Put(routePattern, sc.defaultHandler) sc.m.Put(routePattern, sc.defaultHandler)
@@ -370,12 +371,13 @@ func adminRevokeUserAuthTokenScenario(t *testing.T, desc string, url string, rou
sc := setupScenarioContext(t, url) sc := setupScenarioContext(t, url)
sc.userAuthTokenService = fakeAuthTokenService sc.userAuthTokenService = fakeAuthTokenService
sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response {
c.Req.Body = mockRequestBody(cmd)
sc.context = c sc.context = c
sc.context.UserId = testUserID sc.context.UserId = testUserID
sc.context.OrgId = testOrgID sc.context.OrgId = testOrgID
sc.context.OrgRole = models.ROLE_ADMIN sc.context.OrgRole = models.ROLE_ADMIN
return hs.AdminRevokeUserAuthToken(c, cmd) return hs.AdminRevokeUserAuthToken(c)
}) })
sc.m.Post(routePattern, sc.defaultHandler) sc.m.Post(routePattern, sc.defaultHandler)
@@ -470,10 +472,11 @@ func adminCreateUserScenario(t *testing.T, desc string, url string, routePattern
sc := setupScenarioContext(t, url) sc := setupScenarioContext(t, url)
sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response {
c.Req.Body = mockRequestBody(cmd)
sc.context = c sc.context = c
sc.context.UserId = testUserID sc.context.UserId = testUserID
return hs.AdminCreateUser(c, cmd) return hs.AdminCreateUser(c)
}) })
sc.m.Post(routePattern, sc.defaultHandler) sc.m.Post(routePattern, sc.defaultHandler)
+36 -7
View File
@@ -4,6 +4,7 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"net/http"
"strconv" "strconv"
"github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/api/dtos"
@@ -132,7 +133,11 @@ func GetAlerts(c *models.ReqContext) response.Response {
} }
// POST /api/alerts/test // POST /api/alerts/test
func (hs *HTTPServer) AlertTest(c *models.ReqContext, dto dtos.AlertTestCommand) response.Response { func (hs *HTTPServer) AlertTest(c *models.ReqContext) response.Response {
dto := dtos.AlertTestCommand{}
if err := web.Bind(c.Req, &dto); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
if _, idErr := dto.Dashboard.Get("id").Int64(); idErr != nil { if _, idErr := dto.Dashboard.Get("id").Int64(); idErr != nil {
return response.Error(400, "The dashboard needs to be saved at least once before you can test an alert rule", nil) return response.Error(400, "The dashboard needs to be saved at least once before you can test an alert rule", nil)
} }
@@ -276,7 +281,11 @@ func GetAlertNotificationByUID(c *models.ReqContext) response.Response {
return response.JSON(200, dtos.NewAlertNotification(query.Result)) return response.JSON(200, dtos.NewAlertNotification(query.Result))
} }
func CreateAlertNotification(c *models.ReqContext, cmd models.CreateAlertNotificationCommand) response.Response { func CreateAlertNotification(c *models.ReqContext) response.Response {
cmd := models.CreateAlertNotificationCommand{}
if err := web.Bind(c.Req, &cmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
cmd.OrgId = c.OrgId cmd.OrgId = c.OrgId
if err := bus.DispatchCtx(c.Req.Context(), &cmd); err != nil { if err := bus.DispatchCtx(c.Req.Context(), &cmd); err != nil {
@@ -293,7 +302,11 @@ func CreateAlertNotification(c *models.ReqContext, cmd models.CreateAlertNotific
return response.JSON(200, dtos.NewAlertNotification(cmd.Result)) return response.JSON(200, dtos.NewAlertNotification(cmd.Result))
} }
func (hs *HTTPServer) UpdateAlertNotification(c *models.ReqContext, cmd models.UpdateAlertNotificationCommand) response.Response { func (hs *HTTPServer) UpdateAlertNotification(c *models.ReqContext) response.Response {
cmd := models.UpdateAlertNotificationCommand{}
if err := web.Bind(c.Req, &cmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
cmd.OrgId = c.OrgId cmd.OrgId = c.OrgId
err := hs.fillWithSecureSettingsData(c.Req.Context(), &cmd) err := hs.fillWithSecureSettingsData(c.Req.Context(), &cmd)
@@ -324,7 +337,11 @@ func (hs *HTTPServer) UpdateAlertNotification(c *models.ReqContext, cmd models.U
return response.JSON(200, dtos.NewAlertNotification(query.Result)) return response.JSON(200, dtos.NewAlertNotification(query.Result))
} }
func (hs *HTTPServer) UpdateAlertNotificationByUID(c *models.ReqContext, cmd models.UpdateAlertNotificationWithUidCommand) response.Response { func (hs *HTTPServer) UpdateAlertNotificationByUID(c *models.ReqContext) response.Response {
cmd := models.UpdateAlertNotificationWithUidCommand{}
if err := web.Bind(c.Req, &cmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
cmd.OrgId = c.OrgId cmd.OrgId = c.OrgId
cmd.Uid = web.Params(c.Req)[":uid"] cmd.Uid = web.Params(c.Req)[":uid"]
@@ -444,7 +461,11 @@ func DeleteAlertNotificationByUID(c *models.ReqContext) response.Response {
} }
// POST /api/alert-notifications/test // POST /api/alert-notifications/test
func NotificationTest(c *models.ReqContext, dto dtos.NotificationTestCommand) response.Response { func NotificationTest(c *models.ReqContext) response.Response {
dto := dtos.NotificationTestCommand{}
if err := web.Bind(c.Req, &dto); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
cmd := &alerting.NotificationTestCommand{ cmd := &alerting.NotificationTestCommand{
OrgID: c.OrgId, OrgID: c.OrgId,
ID: dto.ID, ID: dto.ID,
@@ -470,7 +491,11 @@ func NotificationTest(c *models.ReqContext, dto dtos.NotificationTestCommand) re
} }
// POST /api/alerts/:alertId/pause // POST /api/alerts/:alertId/pause
func PauseAlert(c *models.ReqContext, dto dtos.PauseAlertCommand) response.Response { func PauseAlert(c *models.ReqContext) response.Response {
dto := dtos.PauseAlertCommand{}
if err := web.Bind(c.Req, &dto); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
alertID := c.ParamsInt64(":alertId") alertID := c.ParamsInt64(":alertId")
result := make(map[string]interface{}) result := make(map[string]interface{})
result["alertId"] = alertID result["alertId"] = alertID
@@ -523,7 +548,11 @@ func PauseAlert(c *models.ReqContext, dto dtos.PauseAlertCommand) response.Respo
} }
// POST /api/admin/pause-all-alerts // POST /api/admin/pause-all-alerts
func PauseAllAlerts(c *models.ReqContext, dto dtos.PauseAllAlertsCommand) response.Response { func PauseAllAlerts(c *models.ReqContext) response.Response {
dto := dtos.PauseAllAlertsCommand{}
if err := web.Bind(c.Req, &dto); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
updateCmd := models.PauseAllAlertCommand{ updateCmd := models.PauseAllAlertCommand{
Paused: dto.Paused, Paused: dto.Paused,
} }
+2 -1
View File
@@ -166,12 +166,13 @@ func postAlertScenario(t *testing.T, desc string, url string, routePattern strin
sc := setupScenarioContext(t, url) sc := setupScenarioContext(t, url)
sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response {
c.Req.Body = mockRequestBody(cmd)
sc.context = c sc.context = c
sc.context.UserId = testUserID sc.context.UserId = testUserID
sc.context.OrgId = testOrgID sc.context.OrgId = testOrgID
sc.context.OrgRole = role sc.context.OrgRole = role
return PauseAlert(c, cmd) return PauseAlert(c)
}) })
sc.m.Post(routePattern, sc.defaultHandler) sc.m.Post(routePattern, sc.defaultHandler)
+27 -5
View File
@@ -2,6 +2,7 @@ package api
import ( import (
"errors" "errors"
"net/http"
"strings" "strings"
"github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/api/dtos"
@@ -10,6 +11,7 @@ import (
"github.com/grafana/grafana/pkg/services/annotations" "github.com/grafana/grafana/pkg/services/annotations"
"github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/util"
"github.com/grafana/grafana/pkg/web"
) )
func GetAnnotations(c *models.ReqContext) response.Response { func GetAnnotations(c *models.ReqContext) response.Response {
@@ -51,7 +53,11 @@ func (e *CreateAnnotationError) Error() string {
return e.message return e.message
} }
func PostAnnotation(c *models.ReqContext, cmd dtos.PostAnnotationsCmd) response.Response { func PostAnnotation(c *models.ReqContext) response.Response {
cmd := dtos.PostAnnotationsCmd{}
if err := web.Bind(c.Req, &cmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
if canSave, err := canSaveByDashboardID(c, cmd.DashboardId); err != nil || !canSave { if canSave, err := canSaveByDashboardID(c, cmd.DashboardId); err != nil || !canSave {
return dashboardGuardianResponse(err) return dashboardGuardianResponse(err)
} }
@@ -98,7 +104,11 @@ func formatGraphiteAnnotation(what string, data string) string {
return text return text
} }
func PostGraphiteAnnotation(c *models.ReqContext, cmd dtos.PostGraphiteAnnotationsCmd) response.Response { func PostGraphiteAnnotation(c *models.ReqContext) response.Response {
cmd := dtos.PostGraphiteAnnotationsCmd{}
if err := web.Bind(c.Req, &cmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
repo := annotations.GetRepository() repo := annotations.GetRepository()
if cmd.What == "" { if cmd.What == "" {
@@ -149,7 +159,11 @@ func PostGraphiteAnnotation(c *models.ReqContext, cmd dtos.PostGraphiteAnnotatio
}) })
} }
func UpdateAnnotation(c *models.ReqContext, cmd dtos.UpdateAnnotationsCmd) response.Response { func UpdateAnnotation(c *models.ReqContext) response.Response {
cmd := dtos.UpdateAnnotationsCmd{}
if err := web.Bind(c.Req, &cmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
annotationID := c.ParamsInt64(":annotationId") annotationID := c.ParamsInt64(":annotationId")
repo := annotations.GetRepository() repo := annotations.GetRepository()
@@ -175,7 +189,11 @@ func UpdateAnnotation(c *models.ReqContext, cmd dtos.UpdateAnnotationsCmd) respo
return response.Success("Annotation updated") return response.Success("Annotation updated")
} }
func PatchAnnotation(c *models.ReqContext, cmd dtos.PatchAnnotationsCmd) response.Response { func PatchAnnotation(c *models.ReqContext) response.Response {
cmd := dtos.PatchAnnotationsCmd{}
if err := web.Bind(c.Req, &cmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
annotationID := c.ParamsInt64(":annotationId") annotationID := c.ParamsInt64(":annotationId")
repo := annotations.GetRepository() repo := annotations.GetRepository()
@@ -223,7 +241,11 @@ func PatchAnnotation(c *models.ReqContext, cmd dtos.PatchAnnotationsCmd) respons
return response.Success("Annotation patched") return response.Success("Annotation patched")
} }
func DeleteAnnotations(c *models.ReqContext, cmd dtos.DeleteAnnotationsCmd) response.Response { func DeleteAnnotations(c *models.ReqContext) response.Response {
cmd := dtos.DeleteAnnotationsCmd{}
if err := web.Bind(c.Req, &cmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
repo := annotations.GetRepository() repo := annotations.GetRepository()
err := repo.Delete(&annotations.DeleteParams{ err := repo.Delete(&annotations.DeleteParams{
+8 -4
View File
@@ -275,12 +275,13 @@ func postAnnotationScenario(t *testing.T, desc string, url string, routePattern
sc := setupScenarioContext(t, url) sc := setupScenarioContext(t, url)
sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response {
c.Req.Body = mockRequestBody(cmd)
sc.context = c sc.context = c
sc.context.UserId = testUserID sc.context.UserId = testUserID
sc.context.OrgId = testOrgID sc.context.OrgId = testOrgID
sc.context.OrgRole = role sc.context.OrgRole = role
return PostAnnotation(c, cmd) return PostAnnotation(c)
}) })
fakeAnnoRepo = &fakeAnnotationsRepo{} fakeAnnoRepo = &fakeAnnotationsRepo{}
@@ -299,12 +300,13 @@ func putAnnotationScenario(t *testing.T, desc string, url string, routePattern s
sc := setupScenarioContext(t, url) sc := setupScenarioContext(t, url)
sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response {
c.Req.Body = mockRequestBody(cmd)
sc.context = c sc.context = c
sc.context.UserId = testUserID sc.context.UserId = testUserID
sc.context.OrgId = testOrgID sc.context.OrgId = testOrgID
sc.context.OrgRole = role sc.context.OrgRole = role
return UpdateAnnotation(c, cmd) return UpdateAnnotation(c)
}) })
fakeAnnoRepo = &fakeAnnotationsRepo{} fakeAnnoRepo = &fakeAnnotationsRepo{}
@@ -322,12 +324,13 @@ func patchAnnotationScenario(t *testing.T, desc string, url string, routePattern
sc := setupScenarioContext(t, url) sc := setupScenarioContext(t, url)
sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response {
c.Req.Body = mockRequestBody(cmd)
sc.context = c sc.context = c
sc.context.UserId = testUserID sc.context.UserId = testUserID
sc.context.OrgId = testOrgID sc.context.OrgId = testOrgID
sc.context.OrgRole = role sc.context.OrgRole = role
return PatchAnnotation(c, cmd) return PatchAnnotation(c)
}) })
fakeAnnoRepo = &fakeAnnotationsRepo{} fakeAnnoRepo = &fakeAnnotationsRepo{}
@@ -346,12 +349,13 @@ func deleteAnnotationsScenario(t *testing.T, desc string, url string, routePatte
sc := setupScenarioContext(t, url) sc := setupScenarioContext(t, url)
sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response {
c.Req.Body = mockRequestBody(cmd)
sc.context = c sc.context = c
sc.context.UserId = testUserID sc.context.UserId = testUserID
sc.context.OrgId = testOrgID sc.context.OrgId = testOrgID
sc.context.OrgRole = role sc.context.OrgRole = role
return DeleteAnnotations(c, cmd) return DeleteAnnotations(c)
}) })
fakeAnnoRepo = &fakeAnnotationsRepo{} fakeAnnoRepo = &fakeAnnotationsRepo{}
+69 -73
View File
@@ -4,13 +4,10 @@ package api
import ( import (
"time" "time"
"github.com/go-macaron/binding"
"github.com/grafana/grafana/pkg/api/avatar" "github.com/grafana/grafana/pkg/api/avatar"
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/api/frontendlogging" "github.com/grafana/grafana/pkg/api/frontendlogging"
"github.com/grafana/grafana/pkg/api/routing" "github.com/grafana/grafana/pkg/api/routing"
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/metrics"
"github.com/grafana/grafana/pkg/middleware" "github.com/grafana/grafana/pkg/middleware"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
ac "github.com/grafana/grafana/pkg/services/accesscontrol" ac "github.com/grafana/grafana/pkg/services/accesscontrol"
@@ -35,7 +32,6 @@ func (hs *HTTPServer) registerRoutes() {
authorize := acmiddleware.Middleware(hs.AccessControl) authorize := acmiddleware.Middleware(hs.AccessControl)
authorizeInOrg := acmiddleware.AuthorizeInOrgMiddleware(hs.AccessControl, hs.SQLStore) authorizeInOrg := acmiddleware.AuthorizeInOrgMiddleware(hs.AccessControl, hs.SQLStore)
quota := middleware.Quota(hs.QuotaService) quota := middleware.Quota(hs.QuotaService)
bind := binding.Bind
r := hs.RouteRegister r := hs.RouteRegister
@@ -116,19 +112,19 @@ func (hs *HTTPServer) registerRoutes() {
r.Get("/verify", hs.Index) r.Get("/verify", hs.Index)
r.Get("/signup", hs.Index) r.Get("/signup", hs.Index)
r.Get("/api/user/signup/options", routing.Wrap(GetSignUpOptions)) r.Get("/api/user/signup/options", routing.Wrap(GetSignUpOptions))
r.Post("/api/user/signup", quota("user"), bind(dtos.SignUpForm{}), routing.Wrap(SignUp)) r.Post("/api/user/signup", quota("user"), routing.Wrap(SignUp))
r.Post("/api/user/signup/step2", bind(dtos.SignUpStep2Form{}), routing.Wrap(hs.SignUpStep2)) r.Post("/api/user/signup/step2", routing.Wrap(hs.SignUpStep2))
// invited // invited
r.Get("/api/user/invite/:code", routing.Wrap(GetInviteInfoByCode)) r.Get("/api/user/invite/:code", routing.Wrap(GetInviteInfoByCode))
r.Post("/api/user/invite/complete", bind(dtos.CompleteInviteForm{}), routing.Wrap(hs.CompleteInvite)) r.Post("/api/user/invite/complete", routing.Wrap(hs.CompleteInvite))
// reset password // reset password
r.Get("/user/password/send-reset-email", reqNotSignedIn, hs.Index) r.Get("/user/password/send-reset-email", reqNotSignedIn, hs.Index)
r.Get("/user/password/reset", hs.Index) r.Get("/user/password/reset", hs.Index)
r.Post("/api/user/password/send-reset-email", bind(dtos.SendResetPasswordEmailForm{}), routing.Wrap(SendResetPasswordEmail)) r.Post("/api/user/password/send-reset-email", routing.Wrap(SendResetPasswordEmail))
r.Post("/api/user/password/reset", bind(dtos.ResetUserPasswordForm{}), routing.Wrap(ResetPassword)) r.Post("/api/user/password/reset", routing.Wrap(ResetPassword))
// dashboard snapshots // dashboard snapshots
r.Get("/dashboard/snapshot/*", reqNoAuth, hs.Index) r.Get("/dashboard/snapshot/*", reqNoAuth, hs.Index)
@@ -145,7 +141,7 @@ func (hs *HTTPServer) registerRoutes() {
// user (signed in) // user (signed in)
apiRoute.Group("/user", func(userRoute routing.RouteRegister) { apiRoute.Group("/user", func(userRoute routing.RouteRegister) {
userRoute.Get("/", routing.Wrap(GetSignedInUser)) userRoute.Get("/", routing.Wrap(GetSignedInUser))
userRoute.Put("/", bind(models.UpdateUserCommand{}), routing.Wrap(UpdateSignedInUser)) userRoute.Put("/", routing.Wrap(UpdateSignedInUser))
userRoute.Post("/using/:id", routing.Wrap(UserSetUsingOrg)) userRoute.Post("/using/:id", routing.Wrap(UserSetUsingOrg))
userRoute.Get("/orgs", routing.Wrap(GetSignedInUserOrgList)) userRoute.Get("/orgs", routing.Wrap(GetSignedInUserOrgList))
userRoute.Get("/teams", routing.Wrap(GetSignedInUserTeamList)) userRoute.Get("/teams", routing.Wrap(GetSignedInUserTeamList))
@@ -153,17 +149,17 @@ func (hs *HTTPServer) registerRoutes() {
userRoute.Post("/stars/dashboard/:id", routing.Wrap(StarDashboard)) userRoute.Post("/stars/dashboard/:id", routing.Wrap(StarDashboard))
userRoute.Delete("/stars/dashboard/:id", routing.Wrap(UnstarDashboard)) userRoute.Delete("/stars/dashboard/:id", routing.Wrap(UnstarDashboard))
userRoute.Put("/password", bind(models.ChangeUserPasswordCommand{}), routing.Wrap(ChangeUserPassword)) userRoute.Put("/password", routing.Wrap(ChangeUserPassword))
userRoute.Get("/quotas", routing.Wrap(GetUserQuotas)) userRoute.Get("/quotas", routing.Wrap(GetUserQuotas))
userRoute.Put("/helpflags/:id", routing.Wrap(SetHelpFlag)) userRoute.Put("/helpflags/:id", routing.Wrap(SetHelpFlag))
// For dev purpose // For dev purpose
userRoute.Get("/helpflags/clear", routing.Wrap(ClearHelpFlags)) userRoute.Get("/helpflags/clear", routing.Wrap(ClearHelpFlags))
userRoute.Get("/preferences", routing.Wrap(hs.GetUserPreferences)) userRoute.Get("/preferences", routing.Wrap(hs.GetUserPreferences))
userRoute.Put("/preferences", bind(dtos.UpdatePrefsCmd{}), routing.Wrap(hs.UpdateUserPreferences)) userRoute.Put("/preferences", routing.Wrap(hs.UpdateUserPreferences))
userRoute.Get("/auth-tokens", routing.Wrap(hs.GetUserAuthTokens)) userRoute.Get("/auth-tokens", routing.Wrap(hs.GetUserAuthTokens))
userRoute.Post("/revoke-auth-token", bind(models.RevokeAuthTokenCmd{}), routing.Wrap(hs.RevokeUserAuthToken)) userRoute.Post("/revoke-auth-token", routing.Wrap(hs.RevokeUserAuthToken))
}, reqSignedInNoAnonymous) }, reqSignedInNoAnonymous)
apiRoute.Group("/users", func(usersRoute routing.RouteRegister) { apiRoute.Group("/users", func(usersRoute routing.RouteRegister) {
@@ -175,21 +171,21 @@ func (hs *HTTPServer) registerRoutes() {
usersRoute.Get("/:id/orgs", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionUsersRead, userIDScope)), routing.Wrap(GetUserOrgList)) usersRoute.Get("/:id/orgs", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionUsersRead, userIDScope)), routing.Wrap(GetUserOrgList))
// query parameters /users/lookup?loginOrEmail=admin@example.com // query parameters /users/lookup?loginOrEmail=admin@example.com
usersRoute.Get("/lookup", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionUsersRead, ac.ScopeGlobalUsersAll)), routing.Wrap(GetUserByLoginOrEmail)) usersRoute.Get("/lookup", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionUsersRead, ac.ScopeGlobalUsersAll)), routing.Wrap(GetUserByLoginOrEmail))
usersRoute.Put("/:id", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionUsersWrite, userIDScope)), bind(models.UpdateUserCommand{}), routing.Wrap(UpdateUser)) usersRoute.Put("/:id", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionUsersWrite, userIDScope)), routing.Wrap(UpdateUser))
usersRoute.Post("/:id/using/:orgId", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionUsersWrite, userIDScope)), routing.Wrap(UpdateUserActiveOrg)) usersRoute.Post("/:id/using/:orgId", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionUsersWrite, userIDScope)), routing.Wrap(UpdateUserActiveOrg))
}) })
// team (admin permission required) // team (admin permission required)
apiRoute.Group("/teams", func(teamsRoute routing.RouteRegister) { apiRoute.Group("/teams", func(teamsRoute routing.RouteRegister) {
teamsRoute.Post("/", bind(models.CreateTeamCommand{}), routing.Wrap(hs.CreateTeam)) teamsRoute.Post("/", routing.Wrap(hs.CreateTeam))
teamsRoute.Put("/:teamId", bind(models.UpdateTeamCommand{}), routing.Wrap(hs.UpdateTeam)) teamsRoute.Put("/:teamId", routing.Wrap(hs.UpdateTeam))
teamsRoute.Delete("/:teamId", routing.Wrap(hs.DeleteTeamByID)) teamsRoute.Delete("/:teamId", routing.Wrap(hs.DeleteTeamByID))
teamsRoute.Get("/:teamId/members", routing.Wrap(hs.GetTeamMembers)) teamsRoute.Get("/:teamId/members", routing.Wrap(hs.GetTeamMembers))
teamsRoute.Post("/:teamId/members", bind(models.AddTeamMemberCommand{}), routing.Wrap(hs.AddTeamMember)) teamsRoute.Post("/:teamId/members", routing.Wrap(hs.AddTeamMember))
teamsRoute.Put("/:teamId/members/:userId", bind(models.UpdateTeamMemberCommand{}), routing.Wrap(hs.UpdateTeamMember)) teamsRoute.Put("/:teamId/members/:userId", routing.Wrap(hs.UpdateTeamMember))
teamsRoute.Delete("/:teamId/members/:userId", routing.Wrap(hs.RemoveTeamMember)) teamsRoute.Delete("/:teamId/members/:userId", routing.Wrap(hs.RemoveTeamMember))
teamsRoute.Get("/:teamId/preferences", routing.Wrap(hs.GetTeamPreferences)) teamsRoute.Get("/:teamId/preferences", routing.Wrap(hs.GetTeamPreferences))
teamsRoute.Put("/:teamId/preferences", bind(dtos.UpdatePrefsCmd{}), routing.Wrap(hs.UpdateTeamPreferences)) teamsRoute.Put("/:teamId/preferences", routing.Wrap(hs.UpdateTeamPreferences))
}, reqCanAccessTeams) }, reqCanAccessTeams)
// team without requirement of user to be org admin // team without requirement of user to be org admin
@@ -207,22 +203,22 @@ func (hs *HTTPServer) registerRoutes() {
// current org // current org
apiRoute.Group("/org", func(orgRoute routing.RouteRegister) { apiRoute.Group("/org", func(orgRoute routing.RouteRegister) {
userIDScope := ac.Scope("users", "id", ac.Parameter(":userId")) userIDScope := ac.Scope("users", "id", ac.Parameter(":userId"))
orgRoute.Put("/", authorize(reqOrgAdmin, ac.EvalPermission(ActionOrgsWrite)), bind(dtos.UpdateOrgForm{}), routing.Wrap(UpdateCurrentOrg)) orgRoute.Put("/", authorize(reqOrgAdmin, ac.EvalPermission(ActionOrgsWrite)), routing.Wrap(UpdateCurrentOrg))
orgRoute.Put("/address", authorize(reqOrgAdmin, ac.EvalPermission(ActionOrgsWrite)), bind(dtos.UpdateOrgAddressForm{}), routing.Wrap(UpdateCurrentOrgAddress)) orgRoute.Put("/address", authorize(reqOrgAdmin, ac.EvalPermission(ActionOrgsWrite)), routing.Wrap(UpdateCurrentOrgAddress))
orgRoute.Get("/users", authorize(reqOrgAdmin, ac.EvalPermission(ac.ActionOrgUsersRead, ac.ScopeUsersAll)), routing.Wrap(hs.GetOrgUsersForCurrentOrg)) orgRoute.Get("/users", authorize(reqOrgAdmin, ac.EvalPermission(ac.ActionOrgUsersRead, ac.ScopeUsersAll)), routing.Wrap(hs.GetOrgUsersForCurrentOrg))
orgRoute.Get("/users/search", authorize(reqOrgAdmin, ac.EvalPermission(ac.ActionOrgUsersRead, ac.ScopeUsersAll)), routing.Wrap(hs.SearchOrgUsersWithPaging)) orgRoute.Get("/users/search", authorize(reqOrgAdmin, ac.EvalPermission(ac.ActionOrgUsersRead, ac.ScopeUsersAll)), routing.Wrap(hs.SearchOrgUsersWithPaging))
orgRoute.Post("/users", authorize(reqOrgAdmin, ac.EvalPermission(ac.ActionOrgUsersAdd, ac.ScopeUsersAll)), quota("user"), bind(models.AddOrgUserCommand{}), routing.Wrap(hs.AddOrgUserToCurrentOrg)) orgRoute.Post("/users", authorize(reqOrgAdmin, ac.EvalPermission(ac.ActionOrgUsersAdd, ac.ScopeUsersAll)), quota("user"), routing.Wrap(hs.AddOrgUserToCurrentOrg))
orgRoute.Patch("/users/:userId", authorize(reqOrgAdmin, ac.EvalPermission(ac.ActionOrgUsersRoleUpdate, userIDScope)), bind(models.UpdateOrgUserCommand{}), routing.Wrap(hs.UpdateOrgUserForCurrentOrg)) orgRoute.Patch("/users/:userId", authorize(reqOrgAdmin, ac.EvalPermission(ac.ActionOrgUsersRoleUpdate, userIDScope)), routing.Wrap(hs.UpdateOrgUserForCurrentOrg))
orgRoute.Delete("/users/:userId", authorize(reqOrgAdmin, ac.EvalPermission(ac.ActionOrgUsersRemove, userIDScope)), routing.Wrap(hs.RemoveOrgUserForCurrentOrg)) orgRoute.Delete("/users/:userId", authorize(reqOrgAdmin, ac.EvalPermission(ac.ActionOrgUsersRemove, userIDScope)), routing.Wrap(hs.RemoveOrgUserForCurrentOrg))
// invites // invites
orgRoute.Get("/invites", authorize(reqOrgAdmin, ac.EvalPermission(ac.ActionUsersCreate)), routing.Wrap(GetPendingOrgInvites)) orgRoute.Get("/invites", authorize(reqOrgAdmin, ac.EvalPermission(ac.ActionUsersCreate)), routing.Wrap(GetPendingOrgInvites))
orgRoute.Post("/invites", authorize(reqOrgAdmin, ac.EvalPermission(ac.ActionUsersCreate)), quota("user"), bind(dtos.AddInviteForm{}), routing.Wrap(AddOrgInvite)) orgRoute.Post("/invites", authorize(reqOrgAdmin, ac.EvalPermission(ac.ActionUsersCreate)), quota("user"), routing.Wrap(AddOrgInvite))
orgRoute.Patch("/invites/:code/revoke", authorize(reqOrgAdmin, ac.EvalPermission(ac.ActionUsersCreate)), routing.Wrap(RevokeInvite)) orgRoute.Patch("/invites/:code/revoke", authorize(reqOrgAdmin, ac.EvalPermission(ac.ActionUsersCreate)), routing.Wrap(RevokeInvite))
// prefs // prefs
orgRoute.Get("/preferences", authorize(reqOrgAdmin, ac.EvalPermission(ActionOrgsPreferencesRead)), routing.Wrap(hs.GetOrgPreferences)) orgRoute.Get("/preferences", authorize(reqOrgAdmin, ac.EvalPermission(ActionOrgsPreferencesRead)), routing.Wrap(hs.GetOrgPreferences))
orgRoute.Put("/preferences", authorize(reqOrgAdmin, ac.EvalPermission(ActionOrgsPreferencesWrite)), bind(dtos.UpdatePrefsCmd{}), routing.Wrap(hs.UpdateOrgPreferences)) orgRoute.Put("/preferences", authorize(reqOrgAdmin, ac.EvalPermission(ActionOrgsPreferencesWrite)), routing.Wrap(hs.UpdateOrgPreferences))
}) })
// current org without requirement of user to be org admin // current org without requirement of user to be org admin
@@ -231,7 +227,7 @@ func (hs *HTTPServer) registerRoutes() {
}) })
// create new org // create new org
apiRoute.Post("/orgs", authorizeInOrg(reqSignedIn, acmiddleware.UseGlobalOrg, ac.EvalPermission(ActionOrgsCreate)), quota("org"), bind(models.CreateOrgCommand{}), routing.Wrap(hs.CreateOrg)) apiRoute.Post("/orgs", authorizeInOrg(reqSignedIn, acmiddleware.UseGlobalOrg, ac.EvalPermission(ActionOrgsCreate)), quota("org"), routing.Wrap(hs.CreateOrg))
// search all orgs // search all orgs
apiRoute.Get("/orgs", authorizeInOrg(reqGrafanaAdmin, acmiddleware.UseGlobalOrg, ac.EvalPermission(ActionOrgsRead)), routing.Wrap(SearchOrgs)) apiRoute.Get("/orgs", authorizeInOrg(reqGrafanaAdmin, acmiddleware.UseGlobalOrg, ac.EvalPermission(ActionOrgsRead)), routing.Wrap(SearchOrgs))
@@ -240,15 +236,15 @@ func (hs *HTTPServer) registerRoutes() {
apiRoute.Group("/orgs/:orgId", func(orgsRoute routing.RouteRegister) { apiRoute.Group("/orgs/:orgId", func(orgsRoute routing.RouteRegister) {
userIDScope := ac.Scope("users", "id", ac.Parameter(":userId")) userIDScope := ac.Scope("users", "id", ac.Parameter(":userId"))
orgsRoute.Get("/", authorizeInOrg(reqGrafanaAdmin, acmiddleware.UseOrgFromContextParams, ac.EvalPermission(ActionOrgsRead)), routing.Wrap(GetOrgByID)) orgsRoute.Get("/", authorizeInOrg(reqGrafanaAdmin, acmiddleware.UseOrgFromContextParams, ac.EvalPermission(ActionOrgsRead)), routing.Wrap(GetOrgByID))
orgsRoute.Put("/", authorizeInOrg(reqGrafanaAdmin, acmiddleware.UseOrgFromContextParams, ac.EvalPermission(ActionOrgsWrite)), bind(dtos.UpdateOrgForm{}), routing.Wrap(UpdateOrg)) orgsRoute.Put("/", authorizeInOrg(reqGrafanaAdmin, acmiddleware.UseOrgFromContextParams, ac.EvalPermission(ActionOrgsWrite)), routing.Wrap(UpdateOrg))
orgsRoute.Put("/address", authorizeInOrg(reqGrafanaAdmin, acmiddleware.UseOrgFromContextParams, ac.EvalPermission(ActionOrgsWrite)), bind(dtos.UpdateOrgAddressForm{}), routing.Wrap(UpdateOrgAddress)) orgsRoute.Put("/address", authorizeInOrg(reqGrafanaAdmin, acmiddleware.UseOrgFromContextParams, ac.EvalPermission(ActionOrgsWrite)), routing.Wrap(UpdateOrgAddress))
orgsRoute.Delete("/", authorizeInOrg(reqGrafanaAdmin, acmiddleware.UseOrgFromContextParams, ac.EvalPermission(ActionOrgsDelete)), routing.Wrap(DeleteOrgByID)) orgsRoute.Delete("/", authorizeInOrg(reqGrafanaAdmin, acmiddleware.UseOrgFromContextParams, ac.EvalPermission(ActionOrgsDelete)), routing.Wrap(DeleteOrgByID))
orgsRoute.Get("/users", authorizeInOrg(reqGrafanaAdmin, acmiddleware.UseOrgFromContextParams, ac.EvalPermission(ac.ActionOrgUsersRead, ac.ScopeUsersAll)), routing.Wrap(hs.GetOrgUsers)) orgsRoute.Get("/users", authorizeInOrg(reqGrafanaAdmin, acmiddleware.UseOrgFromContextParams, ac.EvalPermission(ac.ActionOrgUsersRead, ac.ScopeUsersAll)), routing.Wrap(hs.GetOrgUsers))
orgsRoute.Post("/users", authorizeInOrg(reqGrafanaAdmin, acmiddleware.UseOrgFromContextParams, ac.EvalPermission(ac.ActionOrgUsersAdd, ac.ScopeUsersAll)), bind(models.AddOrgUserCommand{}), routing.Wrap(hs.AddOrgUser)) orgsRoute.Post("/users", authorizeInOrg(reqGrafanaAdmin, acmiddleware.UseOrgFromContextParams, ac.EvalPermission(ac.ActionOrgUsersAdd, ac.ScopeUsersAll)), routing.Wrap(hs.AddOrgUser))
orgsRoute.Patch("/users/:userId", authorizeInOrg(reqGrafanaAdmin, acmiddleware.UseOrgFromContextParams, ac.EvalPermission(ac.ActionOrgUsersRoleUpdate, userIDScope)), bind(models.UpdateOrgUserCommand{}), routing.Wrap(hs.UpdateOrgUser)) orgsRoute.Patch("/users/:userId", authorizeInOrg(reqGrafanaAdmin, acmiddleware.UseOrgFromContextParams, ac.EvalPermission(ac.ActionOrgUsersRoleUpdate, userIDScope)), routing.Wrap(hs.UpdateOrgUser))
orgsRoute.Delete("/users/:userId", authorizeInOrg(reqGrafanaAdmin, acmiddleware.UseOrgFromContextParams, ac.EvalPermission(ac.ActionOrgUsersRemove, userIDScope)), routing.Wrap(hs.RemoveOrgUser)) orgsRoute.Delete("/users/:userId", authorizeInOrg(reqGrafanaAdmin, acmiddleware.UseOrgFromContextParams, ac.EvalPermission(ac.ActionOrgUsersRemove, userIDScope)), routing.Wrap(hs.RemoveOrgUser))
orgsRoute.Get("/quotas", authorizeInOrg(reqGrafanaAdmin, acmiddleware.UseOrgFromContextParams, ac.EvalPermission(ActionOrgsQuotasRead)), routing.Wrap(hs.GetOrgQuotas)) orgsRoute.Get("/quotas", authorizeInOrg(reqGrafanaAdmin, acmiddleware.UseOrgFromContextParams, ac.EvalPermission(ActionOrgsQuotasRead)), routing.Wrap(hs.GetOrgQuotas))
orgsRoute.Put("/quotas/:target", authorizeInOrg(reqGrafanaAdmin, acmiddleware.UseOrgFromContextParams, ac.EvalPermission(ActionOrgsQuotasWrite)), bind(models.UpdateOrgQuotaCmd{}), routing.Wrap(hs.UpdateOrgQuota)) orgsRoute.Put("/quotas/:target", authorizeInOrg(reqGrafanaAdmin, acmiddleware.UseOrgFromContextParams, ac.EvalPermission(ActionOrgsQuotasWrite)), routing.Wrap(hs.UpdateOrgQuota))
}) })
// orgs (admin routes) // orgs (admin routes)
@@ -257,21 +253,21 @@ func (hs *HTTPServer) registerRoutes() {
// auth api keys // auth api keys
apiRoute.Group("/auth/keys", func(keysRoute routing.RouteRegister) { apiRoute.Group("/auth/keys", func(keysRoute routing.RouteRegister) {
keysRoute.Get("/", routing.Wrap(GetAPIKeys)) keysRoute.Get("/", routing.Wrap(GetAPIKeys))
keysRoute.Post("/", quota("api_key"), bind(models.AddApiKeyCommand{}), routing.Wrap(hs.AddAPIKey)) keysRoute.Post("/", quota("api_key"), routing.Wrap(hs.AddAPIKey))
keysRoute.Post("/additional", quota("api_key"), bind(models.AddApiKeyCommand{}), routing.Wrap(hs.AdditionalAPIKey)) keysRoute.Post("/additional", quota("api_key"), routing.Wrap(hs.AdditionalAPIKey))
keysRoute.Delete("/:id", routing.Wrap(DeleteAPIKey)) keysRoute.Delete("/:id", routing.Wrap(DeleteAPIKey))
}, reqOrgAdmin) }, reqOrgAdmin)
// Preferences // Preferences
apiRoute.Group("/preferences", func(prefRoute routing.RouteRegister) { apiRoute.Group("/preferences", func(prefRoute routing.RouteRegister) {
prefRoute.Post("/set-home-dash", bind(models.SavePreferencesCommand{}), routing.Wrap(SetHomeDashboard)) prefRoute.Post("/set-home-dash", routing.Wrap(SetHomeDashboard))
}) })
// Data sources // Data sources
apiRoute.Group("/datasources", func(datasourceRoute routing.RouteRegister) { apiRoute.Group("/datasources", func(datasourceRoute routing.RouteRegister) {
datasourceRoute.Get("/", authorize(reqOrgAdmin, ac.EvalPermission(ActionDatasourcesRead, ScopeDatasourcesAll)), routing.Wrap(hs.GetDataSources)) datasourceRoute.Get("/", authorize(reqOrgAdmin, ac.EvalPermission(ActionDatasourcesRead, ScopeDatasourcesAll)), routing.Wrap(hs.GetDataSources))
datasourceRoute.Post("/", authorize(reqOrgAdmin, ac.EvalPermission(ActionDatasourcesCreate)), quota("data_source"), bind(models.AddDataSourceCommand{}), routing.Wrap(AddDataSource)) datasourceRoute.Post("/", authorize(reqOrgAdmin, ac.EvalPermission(ActionDatasourcesCreate)), quota("data_source"), routing.Wrap(AddDataSource))
datasourceRoute.Put("/:id", authorize(reqOrgAdmin, ac.EvalPermission(ActionDatasourcesWrite, ScopeDatasourceID)), bind(models.UpdateDataSourceCommand{}), routing.Wrap(hs.UpdateDataSource)) datasourceRoute.Put("/:id", authorize(reqOrgAdmin, ac.EvalPermission(ActionDatasourcesWrite, ScopeDatasourceID)), routing.Wrap(hs.UpdateDataSource))
datasourceRoute.Delete("/:id", authorize(reqOrgAdmin, ac.EvalPermission(ActionDatasourcesDelete, ScopeDatasourceID)), routing.Wrap(hs.DeleteDataSourceById)) datasourceRoute.Delete("/:id", authorize(reqOrgAdmin, ac.EvalPermission(ActionDatasourcesDelete, ScopeDatasourceID)), routing.Wrap(hs.DeleteDataSourceById))
datasourceRoute.Delete("/uid/:uid", authorize(reqOrgAdmin, ac.EvalPermission(ActionDatasourcesDelete, ScopeDatasourceUID)), routing.Wrap(hs.DeleteDataSourceByUID)) datasourceRoute.Delete("/uid/:uid", authorize(reqOrgAdmin, ac.EvalPermission(ActionDatasourcesDelete, ScopeDatasourceUID)), routing.Wrap(hs.DeleteDataSourceByUID))
datasourceRoute.Delete("/name/:name", authorize(reqOrgAdmin, ac.EvalPermission(ActionDatasourcesDelete, ScopeDatasourceName)), routing.Wrap(hs.DeleteDataSourceByName)) datasourceRoute.Delete("/name/:name", authorize(reqOrgAdmin, ac.EvalPermission(ActionDatasourcesDelete, ScopeDatasourceName)), routing.Wrap(hs.DeleteDataSourceByName))
@@ -291,13 +287,13 @@ func (hs *HTTPServer) registerRoutes() {
apiRoute.Get("/plugins/errors", routing.Wrap(hs.GetPluginErrorsList)) apiRoute.Get("/plugins/errors", routing.Wrap(hs.GetPluginErrorsList))
apiRoute.Group("/plugins", func(pluginRoute routing.RouteRegister) { apiRoute.Group("/plugins", func(pluginRoute routing.RouteRegister) {
pluginRoute.Post("/:pluginId/install", bind(dtos.InstallPluginCommand{}), routing.Wrap(hs.InstallPlugin)) pluginRoute.Post("/:pluginId/install", routing.Wrap(hs.InstallPlugin))
pluginRoute.Post("/:pluginId/uninstall", routing.Wrap(hs.UninstallPlugin)) pluginRoute.Post("/:pluginId/uninstall", routing.Wrap(hs.UninstallPlugin))
}, reqGrafanaAdmin) }, reqGrafanaAdmin)
apiRoute.Group("/plugins", func(pluginRoute routing.RouteRegister) { apiRoute.Group("/plugins", func(pluginRoute routing.RouteRegister) {
pluginRoute.Get("/:pluginId/dashboards/", routing.Wrap(hs.GetPluginDashboards)) pluginRoute.Get("/:pluginId/dashboards/", routing.Wrap(hs.GetPluginDashboards))
pluginRoute.Post("/:pluginId/settings", bind(models.UpdatePluginSettingCmd{}), routing.Wrap(hs.UpdatePluginSetting)) pluginRoute.Post("/:pluginId/settings", routing.Wrap(hs.UpdatePluginSetting))
pluginRoute.Get("/:pluginId/metrics", routing.Wrap(hs.CollectPluginMetrics)) pluginRoute.Get("/:pluginId/metrics", routing.Wrap(hs.CollectPluginMetrics))
}, reqOrgAdmin) }, reqOrgAdmin)
@@ -312,16 +308,16 @@ func (hs *HTTPServer) registerRoutes() {
apiRoute.Group("/folders", func(folderRoute routing.RouteRegister) { apiRoute.Group("/folders", func(folderRoute routing.RouteRegister) {
folderRoute.Get("/", routing.Wrap(hs.GetFolders)) folderRoute.Get("/", routing.Wrap(hs.GetFolders))
folderRoute.Get("/id/:id", routing.Wrap(hs.GetFolderByID)) folderRoute.Get("/id/:id", routing.Wrap(hs.GetFolderByID))
folderRoute.Post("/", bind(models.CreateFolderCommand{}), routing.Wrap(hs.CreateFolder)) folderRoute.Post("/", routing.Wrap(hs.CreateFolder))
folderRoute.Group("/:uid", func(folderUidRoute routing.RouteRegister) { folderRoute.Group("/:uid", func(folderUidRoute routing.RouteRegister) {
folderUidRoute.Get("/", routing.Wrap(hs.GetFolderByUID)) folderUidRoute.Get("/", routing.Wrap(hs.GetFolderByUID))
folderUidRoute.Put("/", bind(models.UpdateFolderCommand{}), routing.Wrap(hs.UpdateFolder)) folderUidRoute.Put("/", routing.Wrap(hs.UpdateFolder))
folderUidRoute.Delete("/", routing.Wrap(hs.DeleteFolder)) folderUidRoute.Delete("/", routing.Wrap(hs.DeleteFolder))
folderUidRoute.Group("/permissions", func(folderPermissionRoute routing.RouteRegister) { folderUidRoute.Group("/permissions", func(folderPermissionRoute routing.RouteRegister) {
folderPermissionRoute.Get("/", routing.Wrap(hs.GetFolderPermissionList)) folderPermissionRoute.Get("/", routing.Wrap(hs.GetFolderPermissionList))
folderPermissionRoute.Post("/", bind(dtos.UpdateDashboardAclCommand{}), routing.Wrap(hs.UpdateFolderPermissions)) folderPermissionRoute.Post("/", routing.Wrap(hs.UpdateFolderPermissions))
}) })
}) })
}) })
@@ -331,22 +327,22 @@ func (hs *HTTPServer) registerRoutes() {
dashboardRoute.Get("/uid/:uid", routing.Wrap(hs.GetDashboard)) dashboardRoute.Get("/uid/:uid", routing.Wrap(hs.GetDashboard))
dashboardRoute.Delete("/uid/:uid", routing.Wrap(hs.DeleteDashboardByUID)) dashboardRoute.Delete("/uid/:uid", routing.Wrap(hs.DeleteDashboardByUID))
dashboardRoute.Post("/calculate-diff", bind(dtos.CalculateDiffOptions{}), routing.Wrap(CalculateDashboardDiff)) dashboardRoute.Post("/calculate-diff", routing.Wrap(CalculateDashboardDiff))
dashboardRoute.Post("/trim", bind(models.TrimDashboardCommand{}), routing.Wrap(hs.TrimDashboard)) dashboardRoute.Post("/trim", routing.Wrap(hs.TrimDashboard))
dashboardRoute.Post("/db", bind(models.SaveDashboardCommand{}), routing.Wrap(hs.PostDashboard)) dashboardRoute.Post("/db", routing.Wrap(hs.PostDashboard))
dashboardRoute.Get("/home", routing.Wrap(hs.GetHomeDashboard)) dashboardRoute.Get("/home", routing.Wrap(hs.GetHomeDashboard))
dashboardRoute.Get("/tags", GetDashboardTags) dashboardRoute.Get("/tags", GetDashboardTags)
dashboardRoute.Post("/import", bind(dtos.ImportDashboardCommand{}), routing.Wrap(hs.ImportDashboard)) dashboardRoute.Post("/import", routing.Wrap(hs.ImportDashboard))
dashboardRoute.Group("/id/:dashboardId", func(dashIdRoute routing.RouteRegister) { dashboardRoute.Group("/id/:dashboardId", func(dashIdRoute routing.RouteRegister) {
dashIdRoute.Get("/versions", routing.Wrap(GetDashboardVersions)) dashIdRoute.Get("/versions", routing.Wrap(GetDashboardVersions))
dashIdRoute.Get("/versions/:id", routing.Wrap(GetDashboardVersion)) dashIdRoute.Get("/versions/:id", routing.Wrap(GetDashboardVersion))
dashIdRoute.Post("/restore", bind(dtos.RestoreDashboardVersionCommand{}), routing.Wrap(hs.RestoreDashboardVersion)) dashIdRoute.Post("/restore", routing.Wrap(hs.RestoreDashboardVersion))
dashIdRoute.Group("/permissions", func(dashboardPermissionRoute routing.RouteRegister) { dashIdRoute.Group("/permissions", func(dashboardPermissionRoute routing.RouteRegister) {
dashboardPermissionRoute.Get("/", routing.Wrap(hs.GetDashboardPermissionList)) dashboardPermissionRoute.Get("/", routing.Wrap(hs.GetDashboardPermissionList))
dashboardPermissionRoute.Post("/", bind(dtos.UpdateDashboardAclCommand{}), routing.Wrap(hs.UpdateDashboardPermissions)) dashboardPermissionRoute.Post("/", routing.Wrap(hs.UpdateDashboardPermissions))
}) })
}) })
}) })
@@ -363,8 +359,8 @@ func (hs *HTTPServer) registerRoutes() {
playlistRoute.Get("/:id/items", ValidateOrgPlaylist, routing.Wrap(GetPlaylistItems)) playlistRoute.Get("/:id/items", ValidateOrgPlaylist, routing.Wrap(GetPlaylistItems))
playlistRoute.Get("/:id/dashboards", ValidateOrgPlaylist, routing.Wrap(GetPlaylistDashboards)) playlistRoute.Get("/:id/dashboards", ValidateOrgPlaylist, routing.Wrap(GetPlaylistDashboards))
playlistRoute.Delete("/:id", reqEditorRole, ValidateOrgPlaylist, routing.Wrap(DeletePlaylist)) playlistRoute.Delete("/:id", reqEditorRole, ValidateOrgPlaylist, routing.Wrap(DeletePlaylist))
playlistRoute.Put("/:id", reqEditorRole, bind(models.UpdatePlaylistCommand{}), ValidateOrgPlaylist, routing.Wrap(UpdatePlaylist)) playlistRoute.Put("/:id", reqEditorRole, ValidateOrgPlaylist, routing.Wrap(UpdatePlaylist))
playlistRoute.Post("/", reqEditorRole, bind(models.CreatePlaylistCommand{}), routing.Wrap(CreatePlaylist)) playlistRoute.Post("/", reqEditorRole, routing.Wrap(CreatePlaylist))
}) })
// Search // Search
@@ -372,14 +368,14 @@ func (hs *HTTPServer) registerRoutes() {
apiRoute.Get("/search/", routing.Wrap(Search)) apiRoute.Get("/search/", routing.Wrap(Search))
// metrics // metrics
apiRoute.Post("/tsdb/query", authorize(reqSignedIn, ac.EvalPermission(ActionDatasourcesQuery)), bind(dtos.MetricRequest{}), routing.Wrap(hs.QueryMetrics)) apiRoute.Post("/tsdb/query", authorize(reqSignedIn, ac.EvalPermission(ActionDatasourcesQuery)), routing.Wrap(hs.QueryMetrics))
// DataSource w/ expressions // DataSource w/ expressions
apiRoute.Post("/ds/query", authorize(reqSignedIn, ac.EvalPermission(ActionDatasourcesQuery)), bind(dtos.MetricRequest{}), routing.Wrap(hs.QueryMetricsV2)) apiRoute.Post("/ds/query", authorize(reqSignedIn, ac.EvalPermission(ActionDatasourcesQuery)), routing.Wrap(hs.QueryMetricsV2))
apiRoute.Group("/alerts", func(alertsRoute routing.RouteRegister) { apiRoute.Group("/alerts", func(alertsRoute routing.RouteRegister) {
alertsRoute.Post("/test", bind(dtos.AlertTestCommand{}), routing.Wrap(hs.AlertTest)) alertsRoute.Post("/test", routing.Wrap(hs.AlertTest))
alertsRoute.Post("/:alertId/pause", reqEditorRole, bind(dtos.PauseAlertCommand{}), routing.Wrap(PauseAlert)) alertsRoute.Post("/:alertId/pause", reqEditorRole, routing.Wrap(PauseAlert))
alertsRoute.Get("/:alertId", ValidateOrgAlert, routing.Wrap(GetAlert)) alertsRoute.Get("/:alertId", ValidateOrgAlert, routing.Wrap(GetAlert))
alertsRoute.Get("/", routing.Wrap(GetAlerts)) alertsRoute.Get("/", routing.Wrap(GetAlerts))
alertsRoute.Get("/states-for-dashboard", routing.Wrap(GetAlertStatesForDashboard)) alertsRoute.Get("/states-for-dashboard", routing.Wrap(GetAlertStatesForDashboard))
@@ -391,13 +387,13 @@ func (hs *HTTPServer) registerRoutes() {
apiRoute.Group("/alert-notifications", func(alertNotifications routing.RouteRegister) { apiRoute.Group("/alert-notifications", func(alertNotifications routing.RouteRegister) {
alertNotifications.Get("/", routing.Wrap(GetAlertNotifications)) alertNotifications.Get("/", routing.Wrap(GetAlertNotifications))
alertNotifications.Post("/test", bind(dtos.NotificationTestCommand{}), routing.Wrap(NotificationTest)) alertNotifications.Post("/test", routing.Wrap(NotificationTest))
alertNotifications.Post("/", bind(models.CreateAlertNotificationCommand{}), routing.Wrap(CreateAlertNotification)) alertNotifications.Post("/", routing.Wrap(CreateAlertNotification))
alertNotifications.Put("/:notificationId", bind(models.UpdateAlertNotificationCommand{}), routing.Wrap(hs.UpdateAlertNotification)) alertNotifications.Put("/:notificationId", routing.Wrap(hs.UpdateAlertNotification))
alertNotifications.Get("/:notificationId", routing.Wrap(GetAlertNotificationByID)) alertNotifications.Get("/:notificationId", routing.Wrap(GetAlertNotificationByID))
alertNotifications.Delete("/:notificationId", routing.Wrap(DeleteAlertNotification)) alertNotifications.Delete("/:notificationId", routing.Wrap(DeleteAlertNotification))
alertNotifications.Get("/uid/:uid", routing.Wrap(GetAlertNotificationByUID)) alertNotifications.Get("/uid/:uid", routing.Wrap(GetAlertNotificationByUID))
alertNotifications.Put("/uid/:uid", bind(models.UpdateAlertNotificationWithUidCommand{}), routing.Wrap(hs.UpdateAlertNotificationByUID)) alertNotifications.Put("/uid/:uid", routing.Wrap(hs.UpdateAlertNotificationByUID))
alertNotifications.Delete("/uid/:uid", routing.Wrap(DeleteAlertNotificationByUID)) alertNotifications.Delete("/uid/:uid", routing.Wrap(DeleteAlertNotificationByUID))
}, reqEditorRole) }, reqEditorRole)
@@ -407,22 +403,22 @@ func (hs *HTTPServer) registerRoutes() {
}) })
apiRoute.Get("/annotations", routing.Wrap(GetAnnotations)) apiRoute.Get("/annotations", routing.Wrap(GetAnnotations))
apiRoute.Post("/annotations/mass-delete", reqOrgAdmin, bind(dtos.DeleteAnnotationsCmd{}), routing.Wrap(DeleteAnnotations)) apiRoute.Post("/annotations/mass-delete", reqOrgAdmin, routing.Wrap(DeleteAnnotations))
apiRoute.Group("/annotations", func(annotationsRoute routing.RouteRegister) { apiRoute.Group("/annotations", func(annotationsRoute routing.RouteRegister) {
annotationsRoute.Post("/", bind(dtos.PostAnnotationsCmd{}), routing.Wrap(PostAnnotation)) annotationsRoute.Post("/", routing.Wrap(PostAnnotation))
annotationsRoute.Delete("/:annotationId", routing.Wrap(DeleteAnnotationByID)) annotationsRoute.Delete("/:annotationId", routing.Wrap(DeleteAnnotationByID))
annotationsRoute.Put("/:annotationId", bind(dtos.UpdateAnnotationsCmd{}), routing.Wrap(UpdateAnnotation)) annotationsRoute.Put("/:annotationId", routing.Wrap(UpdateAnnotation))
annotationsRoute.Patch("/:annotationId", bind(dtos.PatchAnnotationsCmd{}), routing.Wrap(PatchAnnotation)) annotationsRoute.Patch("/:annotationId", routing.Wrap(PatchAnnotation))
annotationsRoute.Post("/graphite", reqEditorRole, bind(dtos.PostGraphiteAnnotationsCmd{}), routing.Wrap(PostGraphiteAnnotation)) annotationsRoute.Post("/graphite", reqEditorRole, routing.Wrap(PostGraphiteAnnotation))
annotationsRoute.Get("/tags", routing.Wrap(GetAnnotationTags)) annotationsRoute.Get("/tags", routing.Wrap(GetAnnotationTags))
}) })
apiRoute.Post("/frontend-metrics", bind(metrics.PostFrontendMetricsCommand{}), routing.Wrap(hs.PostFrontendMetrics)) apiRoute.Post("/frontend-metrics", routing.Wrap(hs.PostFrontendMetrics))
apiRoute.Group("/live", func(liveRoute routing.RouteRegister) { apiRoute.Group("/live", func(liveRoute routing.RouteRegister) {
// the channel path is in the name // the channel path is in the name
liveRoute.Post("/publish", bind(dtos.LivePublishCmd{}), routing.Wrap(hs.Live.HandleHTTPPublish)) liveRoute.Post("/publish", routing.Wrap(hs.Live.HandleHTTPPublish))
// POST influx line protocol. // POST influx line protocol.
liveRoute.Post("/push/:streamId", hs.LivePushGateway.Handle) liveRoute.Post("/push/:streamId", hs.LivePushGateway.Handle)
@@ -450,14 +446,14 @@ func (hs *HTTPServer) registerRoutes() {
}) })
// short urls // short urls
apiRoute.Post("/short-urls", bind(dtos.CreateShortURLCmd{}), routing.Wrap(hs.createShortURL)) apiRoute.Post("/short-urls", routing.Wrap(hs.createShortURL))
}, reqSignedIn) }, reqSignedIn)
// admin api // admin api
r.Group("/api/admin", func(adminRoute routing.RouteRegister) { r.Group("/api/admin", func(adminRoute routing.RouteRegister) {
adminRoute.Get("/settings", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionSettingsRead)), routing.Wrap(hs.AdminGetSettings)) adminRoute.Get("/settings", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionSettingsRead)), routing.Wrap(hs.AdminGetSettings))
adminRoute.Get("/stats", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionServerStatsRead)), routing.Wrap(AdminGetStats)) adminRoute.Get("/stats", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionServerStatsRead)), routing.Wrap(AdminGetStats))
adminRoute.Post("/pause-all-alerts", reqGrafanaAdmin, bind(dtos.PauseAllAlertsCommand{}), routing.Wrap(PauseAllAlerts)) adminRoute.Post("/pause-all-alerts", reqGrafanaAdmin, routing.Wrap(PauseAllAlerts))
adminRoute.Post("/provisioning/dashboards/reload", authorize(reqGrafanaAdmin, ac.EvalPermission(ActionProvisioningReload, ScopeProvisionersDashboards)), routing.Wrap(hs.AdminProvisioningReloadDashboards)) adminRoute.Post("/provisioning/dashboards/reload", authorize(reqGrafanaAdmin, ac.EvalPermission(ActionProvisioningReload, ScopeProvisionersDashboards)), routing.Wrap(hs.AdminProvisioningReloadDashboards))
adminRoute.Post("/provisioning/plugins/reload", authorize(reqGrafanaAdmin, ac.EvalPermission(ActionProvisioningReload, ScopeProvisionersPlugins)), routing.Wrap(hs.AdminProvisioningReloadPlugins)) adminRoute.Post("/provisioning/plugins/reload", authorize(reqGrafanaAdmin, ac.EvalPermission(ActionProvisioningReload, ScopeProvisionersPlugins)), routing.Wrap(hs.AdminProvisioningReloadPlugins))
@@ -474,18 +470,18 @@ func (hs *HTTPServer) registerRoutes() {
r.Group("/api/admin/users", func(adminUserRoute routing.RouteRegister) { r.Group("/api/admin/users", func(adminUserRoute routing.RouteRegister) {
userIDScope := ac.Scope("global", "users", "id", ac.Parameter(":id")) userIDScope := ac.Scope("global", "users", "id", ac.Parameter(":id"))
adminUserRoute.Post("/", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionUsersCreate)), bind(dtos.AdminCreateUserForm{}), routing.Wrap(hs.AdminCreateUser)) adminUserRoute.Post("/", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionUsersCreate)), routing.Wrap(hs.AdminCreateUser))
adminUserRoute.Put("/:id/password", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionUsersPasswordUpdate, userIDScope)), bind(dtos.AdminUpdateUserPasswordForm{}), routing.Wrap(AdminUpdateUserPassword)) adminUserRoute.Put("/:id/password", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionUsersPasswordUpdate, userIDScope)), routing.Wrap(AdminUpdateUserPassword))
adminUserRoute.Put("/:id/permissions", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionUsersPermissionsUpdate, userIDScope)), bind(dtos.AdminUpdateUserPermissionsForm{}), routing.Wrap(hs.AdminUpdateUserPermissions)) adminUserRoute.Put("/:id/permissions", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionUsersPermissionsUpdate, userIDScope)), routing.Wrap(hs.AdminUpdateUserPermissions))
adminUserRoute.Delete("/:id", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionUsersDelete, userIDScope)), routing.Wrap(AdminDeleteUser)) adminUserRoute.Delete("/:id", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionUsersDelete, userIDScope)), routing.Wrap(AdminDeleteUser))
adminUserRoute.Post("/:id/disable", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionUsersDisable, userIDScope)), routing.Wrap(hs.AdminDisableUser)) adminUserRoute.Post("/:id/disable", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionUsersDisable, userIDScope)), routing.Wrap(hs.AdminDisableUser))
adminUserRoute.Post("/:id/enable", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionUsersEnable, userIDScope)), routing.Wrap(AdminEnableUser)) adminUserRoute.Post("/:id/enable", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionUsersEnable, userIDScope)), routing.Wrap(AdminEnableUser))
adminUserRoute.Get("/:id/quotas", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionUsersQuotasList, userIDScope)), routing.Wrap(GetUserQuotas)) adminUserRoute.Get("/:id/quotas", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionUsersQuotasList, userIDScope)), routing.Wrap(GetUserQuotas))
adminUserRoute.Put("/:id/quotas/:target", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionUsersQuotasUpdate, userIDScope)), bind(models.UpdateUserQuotaCmd{}), routing.Wrap(UpdateUserQuota)) adminUserRoute.Put("/:id/quotas/:target", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionUsersQuotasUpdate, userIDScope)), routing.Wrap(UpdateUserQuota))
adminUserRoute.Post("/:id/logout", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionUsersLogout, userIDScope)), routing.Wrap(hs.AdminLogoutUser)) adminUserRoute.Post("/:id/logout", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionUsersLogout, userIDScope)), routing.Wrap(hs.AdminLogoutUser))
adminUserRoute.Get("/:id/auth-tokens", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionUsersAuthTokenList, userIDScope)), routing.Wrap(hs.AdminGetUserAuthTokens)) adminUserRoute.Get("/:id/auth-tokens", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionUsersAuthTokenList, userIDScope)), routing.Wrap(hs.AdminGetUserAuthTokens))
adminUserRoute.Post("/:id/revoke-auth-token", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionUsersAuthTokenUpdate, userIDScope)), bind(models.RevokeAuthTokenCmd{}), routing.Wrap(hs.AdminRevokeUserAuthToken)) adminUserRoute.Post("/:id/revoke-auth-token", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionUsersAuthTokenUpdate, userIDScope)), routing.Wrap(hs.AdminRevokeUserAuthToken))
}) })
// rendering // rendering
@@ -499,7 +495,7 @@ func (hs *HTTPServer) registerRoutes() {
r.Get("/avatar/:hash", avatarCacheServer.Handler) r.Get("/avatar/:hash", avatarCacheServer.Handler)
// Snapshots // Snapshots
r.Post("/api/snapshots/", reqSnapshotPublicModeOrSignedIn, bind(models.CreateDashboardSnapshotCommand{}), CreateDashboardSnapshot) r.Post("/api/snapshots/", reqSnapshotPublicModeOrSignedIn, CreateDashboardSnapshot)
r.Get("/api/snapshot/shared-options/", reqSignedIn, GetSharingOptions) r.Get("/api/snapshot/shared-options/", reqSignedIn, GetSharingOptions)
r.Get("/api/snapshots/:key", routing.Wrap(GetDashboardSnapshot)) r.Get("/api/snapshots/:key", routing.Wrap(GetDashboardSnapshot))
r.Get("/api/snapshots-delete/:deleteKey", reqSnapshotPublicModeOrSignedIn, routing.Wrap(DeleteDashboardSnapshotByDeleteKey)) r.Get("/api/snapshots-delete/:deleteKey", reqSnapshotPublicModeOrSignedIn, routing.Wrap(DeleteDashboardSnapshotByDeleteKey))
@@ -508,5 +504,5 @@ func (hs *HTTPServer) registerRoutes() {
// Frontend logs // Frontend logs
sourceMapStore := frontendlogging.NewSourceMapStore(hs.Cfg, hs.pluginStaticRouteResolver, frontendlogging.ReadSourceMapFromFS) sourceMapStore := frontendlogging.NewSourceMapStore(hs.Cfg, hs.pluginStaticRouteResolver, frontendlogging.ReadSourceMapFromFS)
r.Post("/log", middleware.RateLimit(hs.Cfg.Sentry.EndpointRPS, hs.Cfg.Sentry.EndpointBurst, time.Now), r.Post("/log", middleware.RateLimit(hs.Cfg.Sentry.EndpointRPS, hs.Cfg.Sentry.EndpointBurst, time.Now),
bind(frontendlogging.FrontendSentryEvent{}), routing.Wrap(NewFrontendLogMessageHandler(sourceMapStore))) routing.Wrap(NewFrontendLogMessageHandler(sourceMapStore)))
} }
+13 -3
View File
@@ -2,6 +2,7 @@ package api
import ( import (
"errors" "errors"
"net/http"
"time" "time"
"github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/api/dtos"
@@ -9,6 +10,7 @@ import (
"github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/apikeygen" "github.com/grafana/grafana/pkg/components/apikeygen"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/web"
) )
// GetAPIKeys returns a list of API keys // GetAPIKeys returns a list of API keys
@@ -58,7 +60,11 @@ func DeleteAPIKey(c *models.ReqContext) response.Response {
} }
// AddAPIKey adds an API key // AddAPIKey adds an API key
func (hs *HTTPServer) AddAPIKey(c *models.ReqContext, cmd models.AddApiKeyCommand) response.Response { func (hs *HTTPServer) AddAPIKey(c *models.ReqContext) response.Response {
cmd := models.AddApiKeyCommand{}
if err := web.Bind(c.Req, &cmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
if !cmd.Role.IsValid() { if !cmd.Role.IsValid() {
return response.Error(400, "Invalid role specified", nil) return response.Error(400, "Invalid role specified", nil)
} }
@@ -129,7 +135,11 @@ func (hs *HTTPServer) AddAPIKey(c *models.ReqContext, cmd models.AddApiKeyComman
} }
// AddAPIKey adds an additional API key to a service account // AddAPIKey adds an additional API key to a service account
func (hs *HTTPServer) AdditionalAPIKey(c *models.ReqContext, cmd models.AddApiKeyCommand) response.Response { func (hs *HTTPServer) AdditionalAPIKey(c *models.ReqContext) response.Response {
cmd := models.AddApiKeyCommand{}
if err := web.Bind(c.Req, &cmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
if !hs.Cfg.FeatureToggles["service-accounts"] { if !hs.Cfg.FeatureToggles["service-accounts"] {
return response.Error(500, "Requires services-accounts feature", errors.New("feature missing")) return response.Error(500, "Requires services-accounts feature", errors.New("feature missing"))
} }
@@ -137,5 +147,5 @@ func (hs *HTTPServer) AdditionalAPIKey(c *models.ReqContext, cmd models.AddApiKe
return response.Error(500, "Can't create service account while adding additional API key", nil) return response.Error(500, "Can't create service account while adding additional API key", nil)
} }
return hs.AddAPIKey(c, cmd) return hs.AddAPIKey(c)
} }
+7 -10
View File
@@ -1,7 +1,9 @@
package api package api
import ( import (
"bytes"
"context" "context"
"encoding/json"
"fmt" "fmt"
"io" "io"
"net/http" "net/http"
@@ -52,10 +54,6 @@ func loggedInUserScenarioWithRole(t *testing.T, desc string, method string, url
return sc.handlerFunc(sc.context) return sc.handlerFunc(sc.context)
} }
if sc.handlerFuncCtx != nil {
return sc.handlerFuncCtx(context.Background(), sc.context)
}
return nil return nil
}) })
@@ -81,10 +79,6 @@ func anonymousUserScenario(t *testing.T, desc string, method string, url string,
return sc.handlerFunc(sc.context) return sc.handlerFunc(sc.context)
} }
if sc.handlerFuncCtx != nil {
return sc.handlerFuncCtx(context.Background(), sc.context)
}
return nil return nil
}) })
@@ -154,7 +148,6 @@ type scenarioContext struct {
context *models.ReqContext context *models.ReqContext
resp *httptest.ResponseRecorder resp *httptest.ResponseRecorder
handlerFunc handlerFunc handlerFunc handlerFunc
handlerFuncCtx handlerFuncCtx
defaultHandler web.Handler defaultHandler web.Handler
req *http.Request req *http.Request
url string url string
@@ -167,7 +160,6 @@ func (sc *scenarioContext) exec() {
type scenarioFunc func(c *scenarioContext) type scenarioFunc func(c *scenarioContext)
type handlerFunc func(c *models.ReqContext) response.Response type handlerFunc func(c *models.ReqContext) response.Response
type handlerFuncCtx func(ctx context.Context, c *models.ReqContext) response.Response
func getContextHandler(t *testing.T, cfg *setting.Cfg) *contexthandler.ContextHandler { func getContextHandler(t *testing.T, cfg *setting.Cfg) *contexthandler.ContextHandler {
t.Helper() t.Helper()
@@ -376,3 +368,8 @@ func callAPI(server *web.Mux, method, path string, body io.Reader, t *testing.T)
server.ServeHTTP(recorder, req) server.ServeHTTP(recorder, req)
return recorder return recorder
} }
func mockRequestBody(v interface{}) io.ReadCloser {
b, _ := json.Marshal(v)
return io.NopCloser(bytes.NewReader(b))
}
+26 -5
View File
@@ -5,6 +5,7 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"net/http"
"os" "os"
"path/filepath" "path/filepath"
"strconv" "strconv"
@@ -49,7 +50,11 @@ func dashboardGuardianResponse(err error) response.Response {
return response.Error(403, "Access denied to this dashboard", nil) return response.Error(403, "Access denied to this dashboard", nil)
} }
func (hs *HTTPServer) TrimDashboard(c *models.ReqContext, cmd models.TrimDashboardCommand) response.Response { func (hs *HTTPServer) TrimDashboard(c *models.ReqContext) response.Response {
cmd := models.TrimDashboardCommand{}
if err := web.Bind(c.Req, &cmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
var err error var err error
dash := cmd.Dashboard dash := cmd.Dashboard
meta := cmd.Meta meta := cmd.Meta
@@ -277,7 +282,15 @@ func (hs *HTTPServer) deleteDashboard(c *models.ReqContext) response.Response {
}) })
} }
func (hs *HTTPServer) PostDashboard(c *models.ReqContext, cmd models.SaveDashboardCommand) response.Response { func (hs *HTTPServer) PostDashboard(c *models.ReqContext) response.Response {
cmd := models.SaveDashboardCommand{}
if err := web.Bind(c.Req, &cmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
return hs.postDashboard(c, cmd)
}
func (hs *HTTPServer) postDashboard(c *models.ReqContext, cmd models.SaveDashboardCommand) response.Response {
ctx := c.Req.Context() ctx := c.Req.Context()
var err error var err error
cmd.OrgId = c.OrgId cmd.OrgId = c.OrgId
@@ -585,7 +598,11 @@ func GetDashboardVersion(c *models.ReqContext) response.Response {
} }
// POST /api/dashboards/calculate-diff performs diffs on two dashboards // POST /api/dashboards/calculate-diff performs diffs on two dashboards
func CalculateDashboardDiff(c *models.ReqContext, apiOptions dtos.CalculateDiffOptions) response.Response { func CalculateDashboardDiff(c *models.ReqContext) response.Response {
apiOptions := dtos.CalculateDiffOptions{}
if err := web.Bind(c.Req, &apiOptions); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
guardianBase := guardian.New(c.Req.Context(), apiOptions.Base.DashboardId, c.OrgId, c.SignedInUser) guardianBase := guardian.New(c.Req.Context(), apiOptions.Base.DashboardId, c.OrgId, c.SignedInUser)
if canSave, err := guardianBase.CanSave(); err != nil || !canSave { if canSave, err := guardianBase.CanSave(); err != nil || !canSave {
return dashboardGuardianResponse(err) return dashboardGuardianResponse(err)
@@ -629,7 +646,11 @@ func CalculateDashboardDiff(c *models.ReqContext, apiOptions dtos.CalculateDiffO
} }
// RestoreDashboardVersion restores a dashboard to the given version. // RestoreDashboardVersion restores a dashboard to the given version.
func (hs *HTTPServer) RestoreDashboardVersion(c *models.ReqContext, apiCmd dtos.RestoreDashboardVersionCommand) response.Response { func (hs *HTTPServer) RestoreDashboardVersion(c *models.ReqContext) response.Response {
apiCmd := dtos.RestoreDashboardVersionCommand{}
if err := web.Bind(c.Req, &apiCmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
dash, rsp := getDashboardHelper(c.Req.Context(), c.OrgId, c.ParamsInt64(":dashboardId"), "") dash, rsp := getDashboardHelper(c.Req.Context(), c.OrgId, c.ParamsInt64(":dashboardId"), "")
if rsp != nil { if rsp != nil {
return rsp return rsp
@@ -657,7 +678,7 @@ func (hs *HTTPServer) RestoreDashboardVersion(c *models.ReqContext, apiCmd dtos.
saveCmd.Message = fmt.Sprintf("Restored from version %d", version.Version) saveCmd.Message = fmt.Sprintf("Restored from version %d", version.Version)
saveCmd.FolderId = dash.FolderId saveCmd.FolderId = dash.FolderId
return hs.PostDashboard(c, saveCmd) return hs.postDashboard(c, saveCmd)
} }
func GetDashboardTags(c *models.ReqContext) { func GetDashboardTags(c *models.ReqContext) {
+7 -1
View File
@@ -2,12 +2,14 @@ package api
import ( import (
"errors" "errors"
"net/http"
"time" "time"
"github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/web"
) )
func (hs *HTTPServer) GetDashboardPermissionList(c *models.ReqContext) response.Response { func (hs *HTTPServer) GetDashboardPermissionList(c *models.ReqContext) response.Response {
@@ -50,7 +52,11 @@ func (hs *HTTPServer) GetDashboardPermissionList(c *models.ReqContext) response.
return response.JSON(200, filteredAcls) return response.JSON(200, filteredAcls)
} }
func (hs *HTTPServer) UpdateDashboardPermissions(c *models.ReqContext, apiCmd dtos.UpdateDashboardAclCommand) response.Response { func (hs *HTTPServer) UpdateDashboardPermissions(c *models.ReqContext) response.Response {
apiCmd := dtos.UpdateDashboardAclCommand{}
if err := web.Bind(c.Req, &apiCmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
if err := validatePermissionsUpdate(apiCmd); err != nil { if err := validatePermissionsUpdate(apiCmd); err != nil {
return response.Error(400, err.Error(), err) return response.Error(400, err.Error(), err)
} }
+2 -1
View File
@@ -433,11 +433,12 @@ func updateDashboardPermissionScenario(t *testing.T, ctx updatePermissionContext
sc := setupScenarioContext(t, ctx.url) sc := setupScenarioContext(t, ctx.url)
sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response {
c.Req.Body = mockRequestBody(ctx.cmd)
sc.context = c sc.context = c
sc.context.OrgId = testOrgID sc.context.OrgId = testOrgID
sc.context.UserId = testUserID sc.context.UserId = testUserID
return hs.UpdateDashboardPermissions(c, ctx.cmd) return hs.UpdateDashboardPermissions(c)
}) })
sc.m.Post(ctx.routePattern, sc.defaultHandler) sc.m.Post(ctx.routePattern, sc.defaultHandler)
+6 -3
View File
@@ -1122,10 +1122,11 @@ func postDashboardScenario(t *testing.T, desc string, url string, routePattern s
sc := setupScenarioContext(t, url) sc := setupScenarioContext(t, url)
sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response {
c.Req.Body = mockRequestBody(cmd)
sc.context = c sc.context = c
sc.context.SignedInUser = &models.SignedInUser{OrgId: cmd.OrgId, UserId: cmd.UserId} sc.context.SignedInUser = &models.SignedInUser{OrgId: cmd.OrgId, UserId: cmd.UserId}
return hs.PostDashboard(c, cmd) return hs.PostDashboard(c)
}) })
origNewDashboardService := dashboards.NewService origNewDashboardService := dashboards.NewService
@@ -1154,6 +1155,7 @@ func postDiffScenario(t *testing.T, desc string, url string, routePattern string
sc := setupScenarioContext(t, url) sc := setupScenarioContext(t, url)
sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response {
c.Req.Body = mockRequestBody(cmd)
sc.context = c sc.context = c
sc.context.SignedInUser = &models.SignedInUser{ sc.context.SignedInUser = &models.SignedInUser{
OrgId: testOrgID, OrgId: testOrgID,
@@ -1161,7 +1163,7 @@ func postDiffScenario(t *testing.T, desc string, url string, routePattern string
} }
sc.context.OrgRole = role sc.context.OrgRole = role
return CalculateDashboardDiff(c, cmd) return CalculateDashboardDiff(c)
}) })
sc.m.Post(routePattern, sc.defaultHandler) sc.m.Post(routePattern, sc.defaultHandler)
@@ -1188,6 +1190,7 @@ func restoreDashboardVersionScenario(t *testing.T, desc string, url string, rout
sc := setupScenarioContext(t, url) sc := setupScenarioContext(t, url)
sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response {
c.Req.Body = mockRequestBody(cmd)
sc.context = c sc.context = c
sc.context.SignedInUser = &models.SignedInUser{ sc.context.SignedInUser = &models.SignedInUser{
OrgId: testOrgID, OrgId: testOrgID,
@@ -1195,7 +1198,7 @@ func restoreDashboardVersionScenario(t *testing.T, desc string, url string, rout
} }
sc.context.OrgRole = models.ROLE_ADMIN sc.context.OrgRole = models.ROLE_ADMIN
return hs.RestoreDashboardVersion(c, cmd) return hs.RestoreDashboardVersion(c)
}) })
origProvisioningService := dashboards.NewProvisioningService origProvisioningService := dashboards.NewProvisioningService
+11 -2
View File
@@ -5,6 +5,7 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"net/http"
"sort" "sort"
"github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend"
@@ -211,7 +212,11 @@ func validateURL(tp string, u string) response.Response {
return nil return nil
} }
func AddDataSource(c *models.ReqContext, cmd models.AddDataSourceCommand) response.Response { func AddDataSource(c *models.ReqContext) response.Response {
cmd := models.AddDataSourceCommand{}
if err := web.Bind(c.Req, &cmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
datasourcesLogger.Debug("Received command to add data source", "url", cmd.Url) datasourcesLogger.Debug("Received command to add data source", "url", cmd.Url)
cmd.OrgId = c.OrgId cmd.OrgId = c.OrgId
if resp := validateURL(cmd.Type, cmd.Url); resp != nil { if resp := validateURL(cmd.Type, cmd.Url); resp != nil {
@@ -235,7 +240,11 @@ func AddDataSource(c *models.ReqContext, cmd models.AddDataSourceCommand) respon
}) })
} }
func (hs *HTTPServer) UpdateDataSource(c *models.ReqContext, cmd models.UpdateDataSourceCommand) response.Response { func (hs *HTTPServer) UpdateDataSource(c *models.ReqContext) response.Response {
cmd := models.UpdateDataSourceCommand{}
if err := web.Bind(c.Req, &cmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
datasourcesLogger.Debug("Received command to update data source", "url", cmd.Url) datasourcesLogger.Debug("Received command to update data source", "url", cmd.Url)
cmd.OrgId = c.OrgId cmd.OrgId = c.OrgId
cmd.Id = c.ParamsInt64(":id") cmd.Id = c.ParamsInt64(":id")
+24 -12
View File
@@ -80,10 +80,13 @@ func TestAddDataSource_InvalidURL(t *testing.T) {
sc := setupScenarioContext(t, "/api/datasources") sc := setupScenarioContext(t, "/api/datasources")
sc.m.Post(sc.url, routing.Wrap(func(c *models.ReqContext) response.Response { sc.m.Post(sc.url, routing.Wrap(func(c *models.ReqContext) response.Response {
return AddDataSource(c, models.AddDataSourceCommand{ c.Req.Body = mockRequestBody(models.AddDataSourceCommand{
Name: "Test", Name: "Test",
Url: "invalid:url", Url: "invalid:url",
Access: "direct",
Type: "test",
}) })
return AddDataSource(c)
})) }))
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec() sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
@@ -110,10 +113,13 @@ func TestAddDataSource_URLWithoutProtocol(t *testing.T) {
sc := setupScenarioContext(t, "/api/datasources") sc := setupScenarioContext(t, "/api/datasources")
sc.m.Post(sc.url, routing.Wrap(func(c *models.ReqContext) response.Response { sc.m.Post(sc.url, routing.Wrap(func(c *models.ReqContext) response.Response {
return AddDataSource(c, models.AddDataSourceCommand{ c.Req.Body = mockRequestBody(models.AddDataSourceCommand{
Name: name, Name: name,
Url: url, Url: url,
Access: "direct",
Type: "test",
}) })
return AddDataSource(c)
})) }))
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec() sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
@@ -128,10 +134,13 @@ func TestUpdateDataSource_InvalidURL(t *testing.T) {
sc := setupScenarioContext(t, "/api/datasources/1234") sc := setupScenarioContext(t, "/api/datasources/1234")
sc.m.Put(sc.url, routing.Wrap(func(c *models.ReqContext) response.Response { sc.m.Put(sc.url, routing.Wrap(func(c *models.ReqContext) response.Response {
return AddDataSource(c, models.AddDataSourceCommand{ c.Req.Body = mockRequestBody(models.AddDataSourceCommand{
Name: "Test", Name: "Test",
Url: "invalid:url", Url: "invalid:url",
Access: "direct",
Type: "test",
}) })
return AddDataSource(c)
})) }))
sc.fakeReqWithParams("PUT", sc.url, map[string]string{}).exec() sc.fakeReqWithParams("PUT", sc.url, map[string]string{}).exec()
@@ -158,10 +167,13 @@ func TestUpdateDataSource_URLWithoutProtocol(t *testing.T) {
sc := setupScenarioContext(t, "/api/datasources/1234") sc := setupScenarioContext(t, "/api/datasources/1234")
sc.m.Put(sc.url, routing.Wrap(func(c *models.ReqContext) response.Response { sc.m.Put(sc.url, routing.Wrap(func(c *models.ReqContext) response.Response {
return AddDataSource(c, models.AddDataSourceCommand{ c.Req.Body = mockRequestBody(models.AddDataSourceCommand{
Name: name, Name: name,
Url: url, Url: url,
Access: "direct",
Type: "test",
}) })
return AddDataSource(c)
})) }))
sc.fakeReqWithParams("PUT", sc.url, map[string]string{}).exec() sc.fakeReqWithParams("PUT", sc.url, map[string]string{}).exec()
+11 -2
View File
@@ -4,6 +4,7 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"net/http"
"github.com/grafana/grafana/pkg/api/apierrors" "github.com/grafana/grafana/pkg/api/apierrors"
"github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/api/dtos"
@@ -59,7 +60,11 @@ func (hs *HTTPServer) GetFolderByID(c *models.ReqContext) response.Response {
return response.JSON(200, toFolderDto(c.Req.Context(), g, folder)) return response.JSON(200, toFolderDto(c.Req.Context(), g, folder))
} }
func (hs *HTTPServer) CreateFolder(c *models.ReqContext, cmd models.CreateFolderCommand) response.Response { func (hs *HTTPServer) CreateFolder(c *models.ReqContext) response.Response {
cmd := models.CreateFolderCommand{}
if err := web.Bind(c.Req, &cmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
s := dashboards.NewFolderService(c.OrgId, c.SignedInUser, hs.SQLStore) s := dashboards.NewFolderService(c.OrgId, c.SignedInUser, hs.SQLStore)
folder, err := s.CreateFolder(c.Req.Context(), cmd.Title, cmd.Uid) folder, err := s.CreateFolder(c.Req.Context(), cmd.Title, cmd.Uid)
if err != nil { if err != nil {
@@ -77,7 +82,11 @@ func (hs *HTTPServer) CreateFolder(c *models.ReqContext, cmd models.CreateFolder
return response.JSON(200, toFolderDto(c.Req.Context(), g, folder)) return response.JSON(200, toFolderDto(c.Req.Context(), g, folder))
} }
func (hs *HTTPServer) UpdateFolder(c *models.ReqContext, cmd models.UpdateFolderCommand) response.Response { func (hs *HTTPServer) UpdateFolder(c *models.ReqContext) response.Response {
cmd := models.UpdateFolderCommand{}
if err := web.Bind(c.Req, &cmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
s := dashboards.NewFolderService(c.OrgId, c.SignedInUser, hs.SQLStore) s := dashboards.NewFolderService(c.OrgId, c.SignedInUser, hs.SQLStore)
err := s.UpdateFolder(c.Req.Context(), web.Params(c.Req)[":uid"], &cmd) err := s.UpdateFolder(c.Req.Context(), web.Params(c.Req)[":uid"], &cmd)
if err != nil { if err != nil {
+6 -1
View File
@@ -2,6 +2,7 @@ package api
import ( import (
"errors" "errors"
"net/http"
"time" "time"
"github.com/grafana/grafana/pkg/api/apierrors" "github.com/grafana/grafana/pkg/api/apierrors"
@@ -58,7 +59,11 @@ func (hs *HTTPServer) GetFolderPermissionList(c *models.ReqContext) response.Res
return response.JSON(200, filteredAcls) return response.JSON(200, filteredAcls)
} }
func (hs *HTTPServer) UpdateFolderPermissions(c *models.ReqContext, apiCmd dtos.UpdateDashboardAclCommand) response.Response { func (hs *HTTPServer) UpdateFolderPermissions(c *models.ReqContext) response.Response {
apiCmd := dtos.UpdateDashboardAclCommand{}
if err := web.Bind(c.Req, &apiCmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
if err := validatePermissionsUpdate(apiCmd); err != nil { if err := validatePermissionsUpdate(apiCmd); err != nil {
return response.Error(400, err.Error(), err) return response.Error(400, err.Error(), err)
} }
+2 -1
View File
@@ -402,11 +402,12 @@ func updateFolderPermissionScenario(t *testing.T, ctx updatePermissionContext, h
sc := setupScenarioContext(t, ctx.url) sc := setupScenarioContext(t, ctx.url)
sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response {
c.Req.Body = mockRequestBody(ctx.cmd)
sc.context = c sc.context = c
sc.context.OrgId = testOrgID sc.context.OrgId = testOrgID
sc.context.UserId = testUserID sc.context.UserId = testUserID
return hs.UpdateFolderPermissions(c, ctx.cmd) return hs.UpdateFolderPermissions(c)
}) })
sc.m.Post(ctx.routePattern, sc.defaultHandler) sc.m.Post(ctx.routePattern, sc.defaultHandler)
+4 -2
View File
@@ -148,10 +148,11 @@ func createFolderScenario(t *testing.T, desc string, url string, routePattern st
sc := setupScenarioContext(t, url) sc := setupScenarioContext(t, url)
sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response {
c.Req.Body = mockRequestBody(cmd)
sc.context = c sc.context = c
sc.context.SignedInUser = &models.SignedInUser{OrgId: testOrgID, UserId: testUserID} sc.context.SignedInUser = &models.SignedInUser{OrgId: testOrgID, UserId: testUserID}
return hs.CreateFolder(c, cmd) return hs.CreateFolder(c)
}) })
origNewFolderService := dashboards.NewFolderService origNewFolderService := dashboards.NewFolderService
@@ -182,10 +183,11 @@ func updateFolderScenario(t *testing.T, desc string, url string, routePattern st
sc := setupScenarioContext(t, url) sc := setupScenarioContext(t, url)
sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response {
c.Req.Body = mockRequestBody(cmd)
sc.context = c sc.context = c
sc.context.SignedInUser = &models.SignedInUser{OrgId: testOrgID, UserId: testUserID} sc.context.SignedInUser = &models.SignedInUser{OrgId: testOrgID, UserId: testUserID}
return hs.UpdateFolder(c, cmd) return hs.UpdateFolder(c)
}) })
origNewFolderService := dashboards.NewFolderService origNewFolderService := dashboards.NewFolderService
+10 -2
View File
@@ -1,19 +1,27 @@
package api package api
import ( import (
"net/http"
"github.com/getsentry/sentry-go" "github.com/getsentry/sentry-go"
"github.com/grafana/grafana/pkg/api/frontendlogging" "github.com/grafana/grafana/pkg/api/frontendlogging"
"github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/web"
) )
var frontendLogger = log.New("frontend") var frontendLogger = log.New("frontend")
type frontendLogMessageHandler func(c *models.ReqContext, event frontendlogging.FrontendSentryEvent) response.Response type frontendLogMessageHandler func(c *models.ReqContext) response.Response
func NewFrontendLogMessageHandler(store *frontendlogging.SourceMapStore) frontendLogMessageHandler { func NewFrontendLogMessageHandler(store *frontendlogging.SourceMapStore) frontendLogMessageHandler {
return func(c *models.ReqContext, event frontendlogging.FrontendSentryEvent) response.Response { return func(c *models.ReqContext) response.Response {
event := frontendlogging.FrontendSentryEvent{}
if err := web.Bind(c.Req, &event); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
var msg = "unknown" var msg = "unknown"
if len(event.Message) > 0 { if len(event.Message) > 0 {
+3 -3
View File
@@ -3,7 +3,6 @@ package api
import ( import (
"errors" "errors"
"io/ioutil" "io/ioutil"
"net/http"
"net/url" "net/url"
"os" "os"
"strings" "strings"
@@ -84,9 +83,10 @@ func logSentryEventScenario(t *testing.T, desc string, event frontendlogging.Fro
loggingHandler := NewFrontendLogMessageHandler(sourceMapStore) loggingHandler := NewFrontendLogMessageHandler(sourceMapStore)
handler := routing.Wrap(func(w http.ResponseWriter, c *models.ReqContext) response.Response { handler := routing.Wrap(func(c *models.ReqContext) response.Response {
sc.context = c sc.context = c
return loggingHandler(c, event) c.Req.Body = mockRequestBody(event)
return loggingHandler(c)
}) })
sc.m.Post(sc.url, handler) sc.m.Post(sc.url, handler)
+7 -1
View File
@@ -1,14 +1,20 @@
package api package api
import ( import (
"net/http"
"strings" "strings"
"github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/infra/metrics" "github.com/grafana/grafana/pkg/infra/metrics"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/web"
) )
func (hs *HTTPServer) PostFrontendMetrics(c *models.ReqContext, cmd metrics.PostFrontendMetricsCommand) response.Response { func (hs *HTTPServer) PostFrontendMetrics(c *models.ReqContext) response.Response {
cmd := metrics.PostFrontendMetricsCommand{}
if err := web.Bind(c.Req, &cmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
for _, event := range cmd.Events { for _, event := range cmd.Events {
name := strings.Replace(event.Name, "-", "_", -1) name := strings.Replace(event.Name, "-", "_", -1)
if recorder, ok := metrics.FrontendMetrics[name]; ok { if recorder, ok := metrics.FrontendMetrics[name]; ok {
+14
View File
@@ -1,6 +1,7 @@
package frontendlogging package frontendlogging
import ( import (
"encoding/json"
"fmt" "fmt"
"strings" "strings"
@@ -93,3 +94,16 @@ func (event *FrontendSentryEvent) ToLogContext(store *SourceMapStore) log15.Ctx
return ctx return ctx
} }
func (event *FrontendSentryEvent) MarshalJSON() ([]byte, error) {
eventJSON, err := json.Marshal(event.Event)
if err != nil {
return nil, err
}
exceptionJSON, err := json.Marshal(map[string]interface{}{"exception": event.Exception})
if err != nil {
return nil, err
}
exceptionJSON[0] = ','
return append(eventJSON[:len(eventJSON)-1], exceptionJSON...), nil
}
+1 -1
View File
@@ -100,7 +100,7 @@ func (user *LDAPUserDTO) FetchOrgs(ctx context.Context) error {
} }
// ReloadLDAPCfg reloads the LDAP configuration // ReloadLDAPCfg reloads the LDAP configuration
func (hs *HTTPServer) ReloadLDAPCfg() response.Response { func (hs *HTTPServer) ReloadLDAPCfg(c *models.ReqContext) response.Response {
if !ldap.IsEnabled() { if !ldap.IsEnabled() {
return response.Error(http.StatusBadRequest, "LDAP is not enabled", nil) return response.Error(http.StatusBadRequest, "LDAP is not enabled", nil)
} }
+18 -16
View File
@@ -11,6 +11,7 @@ import (
"net/http" "net/http"
"net/url" "net/url"
"github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/metrics" "github.com/grafana/grafana/pkg/infra/metrics"
@@ -67,7 +68,7 @@ func genPKCECode() (string, string, error) {
return string(ascii), pkce, nil return string(ascii), pkce, nil
} }
func (hs *HTTPServer) OAuthLogin(ctx *models.ReqContext) { func (hs *HTTPServer) OAuthLogin(ctx *models.ReqContext) response.Response {
loginInfo := models.LoginInfo{ loginInfo := models.LoginInfo{
AuthModule: "oauth", AuthModule: "oauth",
} }
@@ -79,7 +80,7 @@ func (hs *HTTPServer) OAuthLogin(ctx *models.ReqContext) {
HttpStatus: http.StatusNotFound, HttpStatus: http.StatusNotFound,
PublicMessage: "OAuth not enabled", PublicMessage: "OAuth not enabled",
}) })
return return nil
} }
connect, err := hs.SocialService.GetConnector(name) connect, err := hs.SocialService.GetConnector(name)
@@ -88,7 +89,7 @@ func (hs *HTTPServer) OAuthLogin(ctx *models.ReqContext) {
HttpStatus: http.StatusNotFound, HttpStatus: http.StatusNotFound,
PublicMessage: fmt.Sprintf("No OAuth with name %s configured", name), PublicMessage: fmt.Sprintf("No OAuth with name %s configured", name),
}) })
return return nil
} }
errorParam := ctx.Query("error") errorParam := ctx.Query("error")
@@ -96,7 +97,7 @@ func (hs *HTTPServer) OAuthLogin(ctx *models.ReqContext) {
errorDesc := ctx.Query("error_description") errorDesc := ctx.Query("error_description")
oauthLogger.Error("failed to login ", "error", errorParam, "errorDesc", errorDesc) oauthLogger.Error("failed to login ", "error", errorParam, "errorDesc", errorDesc)
hs.handleOAuthLoginErrorWithRedirect(ctx, loginInfo, login.ErrProviderDeniedRequest, "error", errorParam, "errorDesc", errorDesc) hs.handleOAuthLoginErrorWithRedirect(ctx, loginInfo, login.ErrProviderDeniedRequest, "error", errorParam, "errorDesc", errorDesc)
return return nil
} }
code := ctx.Query("code") code := ctx.Query("code")
@@ -128,7 +129,7 @@ func (hs *HTTPServer) OAuthLogin(ctx *models.ReqContext) {
HttpStatus: http.StatusInternalServerError, HttpStatus: http.StatusInternalServerError,
PublicMessage: "An internal error occurred", PublicMessage: "An internal error occurred",
}) })
return return nil
} }
hashedState := hashStatecode(state, provider.ClientSecret) hashedState := hashStatecode(state, provider.ClientSecret)
@@ -138,7 +139,7 @@ func (hs *HTTPServer) OAuthLogin(ctx *models.ReqContext) {
} }
ctx.Redirect(connect.AuthCodeURL(state, opts...)) ctx.Redirect(connect.AuthCodeURL(state, opts...))
return return nil
} }
cookieState := ctx.GetCookie(OauthStateCookieName) cookieState := ctx.GetCookie(OauthStateCookieName)
@@ -151,7 +152,7 @@ func (hs *HTTPServer) OAuthLogin(ctx *models.ReqContext) {
HttpStatus: http.StatusInternalServerError, HttpStatus: http.StatusInternalServerError,
PublicMessage: "login.OAuthLogin(missing saved state)", PublicMessage: "login.OAuthLogin(missing saved state)",
}) })
return return nil
} }
queryState := hashStatecode(ctx.Query("state"), provider.ClientSecret) queryState := hashStatecode(ctx.Query("state"), provider.ClientSecret)
@@ -161,7 +162,7 @@ func (hs *HTTPServer) OAuthLogin(ctx *models.ReqContext) {
HttpStatus: http.StatusInternalServerError, HttpStatus: http.StatusInternalServerError,
PublicMessage: "login.OAuthLogin(state mismatch)", PublicMessage: "login.OAuthLogin(state mismatch)",
}) })
return return nil
} }
oauthClient, err := hs.SocialService.GetOAuthHttpClient(name) oauthClient, err := hs.SocialService.GetOAuthHttpClient(name)
@@ -171,7 +172,7 @@ func (hs *HTTPServer) OAuthLogin(ctx *models.ReqContext) {
HttpStatus: http.StatusInternalServerError, HttpStatus: http.StatusInternalServerError,
PublicMessage: "login.OAuthLogin(" + err.Error() + ")", PublicMessage: "login.OAuthLogin(" + err.Error() + ")",
}) })
return return nil
} }
oauthCtx := context.WithValue(context.Background(), oauth2.HTTPClient, oauthClient) oauthCtx := context.WithValue(context.Background(), oauth2.HTTPClient, oauthClient)
@@ -193,7 +194,7 @@ func (hs *HTTPServer) OAuthLogin(ctx *models.ReqContext) {
PublicMessage: "login.OAuthLogin(NewTransportWithCode)", PublicMessage: "login.OAuthLogin(NewTransportWithCode)",
Err: err, Err: err,
}) })
return return nil
} }
// token.TokenType was defaulting to "bearer", which is out of spec, so we explicitly set to "Bearer" // token.TokenType was defaulting to "bearer", which is out of spec, so we explicitly set to "Bearer"
token.TokenType = "Bearer" token.TokenType = "Bearer"
@@ -216,7 +217,7 @@ func (hs *HTTPServer) OAuthLogin(ctx *models.ReqContext) {
Err: err, Err: err,
}) })
} }
return return nil
} }
oauthLogger.Debug("OAuthLogin got user info", "userInfo", userInfo) oauthLogger.Debug("OAuthLogin got user info", "userInfo", userInfo)
@@ -224,26 +225,26 @@ func (hs *HTTPServer) OAuthLogin(ctx *models.ReqContext) {
// validate that we got at least an email address // validate that we got at least an email address
if userInfo.Email == "" { if userInfo.Email == "" {
hs.handleOAuthLoginErrorWithRedirect(ctx, loginInfo, login.ErrNoEmail) hs.handleOAuthLoginErrorWithRedirect(ctx, loginInfo, login.ErrNoEmail)
return return nil
} }
// validate that the email is allowed to login to grafana // validate that the email is allowed to login to grafana
if !connect.IsEmailAllowed(userInfo.Email) { if !connect.IsEmailAllowed(userInfo.Email) {
hs.handleOAuthLoginErrorWithRedirect(ctx, loginInfo, login.ErrEmailNotAllowed) hs.handleOAuthLoginErrorWithRedirect(ctx, loginInfo, login.ErrEmailNotAllowed)
return return nil
} }
loginInfo.ExternalUser = *buildExternalUserInfo(token, userInfo, name) loginInfo.ExternalUser = *buildExternalUserInfo(token, userInfo, name)
loginInfo.User, err = syncUser(ctx, &loginInfo.ExternalUser, connect) loginInfo.User, err = syncUser(ctx, &loginInfo.ExternalUser, connect)
if err != nil { if err != nil {
hs.handleOAuthLoginErrorWithRedirect(ctx, loginInfo, err) hs.handleOAuthLoginErrorWithRedirect(ctx, loginInfo, err)
return return nil
} }
// login // login
if err := hs.loginUserWithUser(loginInfo.User, ctx); err != nil { if err := hs.loginUserWithUser(loginInfo.User, ctx); err != nil {
hs.handleOAuthLoginErrorWithRedirect(ctx, loginInfo, err) hs.handleOAuthLoginErrorWithRedirect(ctx, loginInfo, err)
return return nil
} }
loginInfo.HTTPStatus = http.StatusOK loginInfo.HTTPStatus = http.StatusOK
@@ -254,12 +255,13 @@ func (hs *HTTPServer) OAuthLogin(ctx *models.ReqContext) {
if err := hs.ValidateRedirectTo(redirectTo); err == nil { if err := hs.ValidateRedirectTo(redirectTo); err == nil {
cookies.DeleteCookie(ctx.Resp, "redirect_to", hs.CookieOptionsFromCfg) cookies.DeleteCookie(ctx.Resp, "redirect_to", hs.CookieOptionsFromCfg)
ctx.Redirect(redirectTo) ctx.Redirect(redirectTo)
return return nil
} }
ctx.Logger.Debug("Ignored invalid redirect_to cookie value", "redirect_to", redirectTo) ctx.Logger.Debug("Ignored invalid redirect_to cookie value", "redirect_to", redirectTo)
} }
ctx.Redirect(setting.AppSubUrl + "/") ctx.Redirect(setting.AppSubUrl + "/")
return nil
} }
// buildExternalUserInfo returns a ExternalUserInfo struct from OAuth user profile // buildExternalUserInfo returns a ExternalUserInfo struct from OAuth user profile
+12 -7
View File
@@ -118,8 +118,9 @@ func TestLoginErrorCookieAPIEndpoint(t *testing.T) {
SecretsService: secretsService, SecretsService: secretsService,
} }
sc.defaultHandler = routing.Wrap(func(w http.ResponseWriter, c *models.ReqContext) { sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response {
hs.LoginView(c) hs.LoginView(c)
return response.Empty(http.StatusOK)
}) })
cfg.LoginCookieName = "grafana_session" cfg.LoginCookieName = "grafana_session"
@@ -166,12 +167,13 @@ func TestLoginViewRedirect(t *testing.T) {
} }
hs.Cfg.CookieSecure = true hs.Cfg.CookieSecure = true
sc.defaultHandler = routing.Wrap(func(w http.ResponseWriter, c *models.ReqContext) { sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response {
c.IsSignedIn = true c.IsSignedIn = true
c.SignedInUser = &models.SignedInUser{ c.SignedInUser = &models.SignedInUser{
UserId: 10, UserId: 10,
} }
hs.LoginView(c) hs.LoginView(c)
return response.Empty(http.StatusOK)
}) })
redirectCases := []redirectCase{ redirectCases := []redirectCase{
@@ -340,7 +342,7 @@ func TestLoginPostRedirect(t *testing.T) {
} }
hs.Cfg.CookieSecure = true hs.Cfg.CookieSecure = true
sc.defaultHandler = routing.Wrap(func(w http.ResponseWriter, c *models.ReqContext) response.Response { sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response {
c.Req.Header.Set("Content-Type", "application/json") c.Req.Header.Set("Content-Type", "application/json")
c.Req.Body = io.NopCloser(bytes.NewBufferString(`{"user":"admin","password":"admin"}`)) c.Req.Body = io.NopCloser(bytes.NewBufferString(`{"user":"admin","password":"admin"}`))
return hs.LoginPost(c) return hs.LoginPost(c)
@@ -504,8 +506,9 @@ func TestLoginOAuthRedirect(t *testing.T) {
SocialService: mock, SocialService: mock,
} }
sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) { sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response {
hs.LoginView(c) hs.LoginView(c)
return response.Empty(http.StatusOK)
}) })
setting.OAuthAutoLogin = true setting.OAuthAutoLogin = true
@@ -529,9 +532,10 @@ func TestLoginInternal(t *testing.T) {
log: log.New("test"), log: log.New("test"),
} }
sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) { sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response {
c.Req.URL.RawQuery = "disableAutoLogin=true" c.Req.URL.RawQuery = "disableAutoLogin=true"
hs.LoginView(c) hs.LoginView(c)
return response.Empty(http.StatusOK)
}) })
setting.OAuthAutoLogin = true setting.OAuthAutoLogin = true
@@ -580,12 +584,13 @@ func setupAuthProxyLoginTest(t *testing.T, enableLoginToken bool) *scenarioConte
SocialService: &mockSocialService{}, SocialService: &mockSocialService{},
} }
sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) { sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response {
c.IsSignedIn = true c.IsSignedIn = true
c.SignedInUser = &models.SignedInUser{ c.SignedInUser = &models.SignedInUser{
UserId: 10, UserId: 10,
} }
hs.LoginView(c) hs.LoginView(c)
return response.Empty(http.StatusOK)
}) })
sc.cfg.AuthProxyEnabled = true sc.cfg.AuthProxyEnabled = true
@@ -616,7 +621,7 @@ func TestLoginPostRunLokingHook(t *testing.T) {
HooksService: hookService, HooksService: hookService,
} }
sc.defaultHandler = routing.Wrap(func(w http.ResponseWriter, c *models.ReqContext) response.Response { sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response {
c.Req.Header.Set("Content-Type", "application/json") c.Req.Header.Set("Content-Type", "application/json")
c.Req.Body = io.NopCloser(bytes.NewBufferString(`{"user":"admin","password":"admin"}`)) c.Req.Body = io.NopCloser(bytes.NewBufferString(`{"user":"admin","password":"admin"}`))
x := hs.LoginPost(c) x := hs.LoginPost(c)
+11 -2
View File
@@ -16,11 +16,16 @@ import (
"github.com/grafana/grafana/pkg/plugins/adapters" "github.com/grafana/grafana/pkg/plugins/adapters"
"github.com/grafana/grafana/pkg/tsdb/grafanads" "github.com/grafana/grafana/pkg/tsdb/grafanads"
"github.com/grafana/grafana/pkg/tsdb/legacydata" "github.com/grafana/grafana/pkg/tsdb/legacydata"
"github.com/grafana/grafana/pkg/web"
) )
// QueryMetricsV2 returns query metrics. // QueryMetricsV2 returns query metrics.
// POST /api/ds/query DataSource query w/ expressions // POST /api/ds/query DataSource query w/ expressions
func (hs *HTTPServer) QueryMetricsV2(c *models.ReqContext, reqDTO dtos.MetricRequest) response.Response { func (hs *HTTPServer) QueryMetricsV2(c *models.ReqContext) response.Response {
reqDTO := dtos.MetricRequest{}
if err := web.Bind(c.Req, &reqDTO); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
if len(reqDTO.Queries) == 0 { if len(reqDTO.Queries) == 0 {
return response.Error(http.StatusBadRequest, "No queries found in query", nil) return response.Error(http.StatusBadRequest, "No queries found in query", nil)
} }
@@ -162,7 +167,11 @@ func (hs *HTTPServer) handleGetDataSourceError(err error, datasourceRef interfac
// QueryMetrics returns query metrics // QueryMetrics returns query metrics
// POST /api/tsdb/query // POST /api/tsdb/query
func (hs *HTTPServer) QueryMetrics(c *models.ReqContext, reqDto dtos.MetricRequest) response.Response { func (hs *HTTPServer) QueryMetrics(c *models.ReqContext) response.Response {
reqDto := dtos.MetricRequest{}
if err := web.Bind(c.Req, &reqDto); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
if len(reqDto.Queries) == 0 { if len(reqDto.Queries) == 0 {
return response.Error(http.StatusBadRequest, "No queries found in query", nil) return response.Error(http.StatusBadRequest, "No queries found in query", nil)
} }
+26 -5
View File
@@ -3,6 +3,7 @@ package api
import ( import (
"context" "context"
"errors" "errors"
"net/http"
"github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/api/response"
@@ -78,7 +79,11 @@ func getOrgHelper(ctx context.Context, orgID int64) response.Response {
} }
// POST /api/orgs // POST /api/orgs
func (hs *HTTPServer) CreateOrg(c *models.ReqContext, cmd models.CreateOrgCommand) response.Response { func (hs *HTTPServer) CreateOrg(c *models.ReqContext) response.Response {
cmd := models.CreateOrgCommand{}
if err := web.Bind(c.Req, &cmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
acEnabled := hs.Cfg.FeatureToggles["accesscontrol"] acEnabled := hs.Cfg.FeatureToggles["accesscontrol"]
if !acEnabled && !(setting.AllowUserOrgCreate || c.IsGrafanaAdmin) { if !acEnabled && !(setting.AllowUserOrgCreate || c.IsGrafanaAdmin) {
return response.Error(403, "Access denied", nil) return response.Error(403, "Access denied", nil)
@@ -101,12 +106,20 @@ func (hs *HTTPServer) CreateOrg(c *models.ReqContext, cmd models.CreateOrgComman
} }
// PUT /api/org // PUT /api/org
func UpdateCurrentOrg(c *models.ReqContext, form dtos.UpdateOrgForm) response.Response { func UpdateCurrentOrg(c *models.ReqContext) response.Response {
form := dtos.UpdateOrgForm{}
if err := web.Bind(c.Req, &form); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
return updateOrgHelper(c.Req.Context(), form, c.OrgId) return updateOrgHelper(c.Req.Context(), form, c.OrgId)
} }
// PUT /api/orgs/:orgId // PUT /api/orgs/:orgId
func UpdateOrg(c *models.ReqContext, form dtos.UpdateOrgForm) response.Response { func UpdateOrg(c *models.ReqContext) response.Response {
form := dtos.UpdateOrgForm{}
if err := web.Bind(c.Req, &form); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
return updateOrgHelper(c.Req.Context(), form, c.ParamsInt64(":orgId")) return updateOrgHelper(c.Req.Context(), form, c.ParamsInt64(":orgId"))
} }
@@ -123,12 +136,20 @@ func updateOrgHelper(ctx context.Context, form dtos.UpdateOrgForm, orgID int64)
} }
// PUT /api/org/address // PUT /api/org/address
func UpdateCurrentOrgAddress(c *models.ReqContext, form dtos.UpdateOrgAddressForm) response.Response { func UpdateCurrentOrgAddress(c *models.ReqContext) response.Response {
form := dtos.UpdateOrgAddressForm{}
if err := web.Bind(c.Req, &form); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
return updateOrgAddressHelper(c.Req.Context(), form, c.OrgId) return updateOrgAddressHelper(c.Req.Context(), form, c.OrgId)
} }
// PUT /api/orgs/:orgId/address // PUT /api/orgs/:orgId/address
func UpdateOrgAddress(c *models.ReqContext, form dtos.UpdateOrgAddressForm) response.Response { func UpdateOrgAddress(c *models.ReqContext) response.Response {
form := dtos.UpdateOrgAddressForm{}
if err := web.Bind(c.Req, &form); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
return updateOrgAddressHelper(c.Req.Context(), form, c.ParamsInt64(":orgId")) return updateOrgAddressHelper(c.Req.Context(), form, c.ParamsInt64(":orgId"))
} }
+11 -2
View File
@@ -4,6 +4,7 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"net/http"
"github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/api/response"
@@ -30,7 +31,11 @@ func GetPendingOrgInvites(c *models.ReqContext) response.Response {
return response.JSON(200, query.Result) return response.JSON(200, query.Result)
} }
func AddOrgInvite(c *models.ReqContext, inviteDto dtos.AddInviteForm) response.Response { func AddOrgInvite(c *models.ReqContext) response.Response {
inviteDto := dtos.AddInviteForm{}
if err := web.Bind(c.Req, &inviteDto); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
if !inviteDto.Role.IsValid() { if !inviteDto.Role.IsValid() {
return response.Error(400, "Invalid role specified", nil) return response.Error(400, "Invalid role specified", nil)
} }
@@ -165,7 +170,11 @@ func GetInviteInfoByCode(c *models.ReqContext) response.Response {
}) })
} }
func (hs *HTTPServer) CompleteInvite(c *models.ReqContext, completeInvite dtos.CompleteInviteForm) response.Response { func (hs *HTTPServer) CompleteInvite(c *models.ReqContext) response.Response {
completeInvite := dtos.CompleteInviteForm{}
if err := web.Bind(c.Req, &completeInvite); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
query := models.GetTempUserByCodeQuery{Code: completeInvite.InviteCode} query := models.GetTempUserByCodeQuery{Code: completeInvite.InviteCode}
if err := bus.DispatchCtx(c.Req.Context(), &query); err != nil { if err := bus.DispatchCtx(c.Req.Context(), &query); err != nil {
+24 -5
View File
@@ -3,21 +3,31 @@ package api
import ( import (
"context" "context"
"errors" "errors"
"net/http"
"github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/util"
"github.com/grafana/grafana/pkg/web"
) )
// POST /api/org/users // POST /api/org/users
func (hs *HTTPServer) AddOrgUserToCurrentOrg(c *models.ReqContext, cmd models.AddOrgUserCommand) response.Response { func (hs *HTTPServer) AddOrgUserToCurrentOrg(c *models.ReqContext) response.Response {
cmd := models.AddOrgUserCommand{}
if err := web.Bind(c.Req, &cmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
cmd.OrgId = c.OrgId cmd.OrgId = c.OrgId
return hs.addOrgUserHelper(c.Req.Context(), cmd) return hs.addOrgUserHelper(c.Req.Context(), cmd)
} }
// POST /api/orgs/:orgId/users // POST /api/orgs/:orgId/users
func (hs *HTTPServer) AddOrgUser(c *models.ReqContext, cmd models.AddOrgUserCommand) response.Response { func (hs *HTTPServer) AddOrgUser(c *models.ReqContext) response.Response {
cmd := models.AddOrgUserCommand{}
if err := web.Bind(c.Req, &cmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
cmd.OrgId = c.ParamsInt64(":orgId") cmd.OrgId = c.ParamsInt64(":orgId")
return hs.addOrgUserHelper(c.Req.Context(), cmd) return hs.addOrgUserHelper(c.Req.Context(), cmd)
} }
@@ -128,7 +138,8 @@ func (hs *HTTPServer) getOrgUsersHelper(ctx context.Context, query *models.GetOr
// SearchOrgUsersWithPaging is an HTTP handler to search for org users with paging. // SearchOrgUsersWithPaging is an HTTP handler to search for org users with paging.
// GET /api/org/users/search // GET /api/org/users/search
func (hs *HTTPServer) SearchOrgUsersWithPaging(ctx context.Context, c *models.ReqContext) response.Response { func (hs *HTTPServer) SearchOrgUsersWithPaging(c *models.ReqContext) response.Response {
ctx := c.Req.Context()
perPage := c.QueryInt("perpage") perPage := c.QueryInt("perpage")
if perPage <= 0 { if perPage <= 0 {
perPage = 1000 perPage = 1000
@@ -168,14 +179,22 @@ func (hs *HTTPServer) SearchOrgUsersWithPaging(ctx context.Context, c *models.Re
} }
// PATCH /api/org/users/:userId // PATCH /api/org/users/:userId
func (hs *HTTPServer) UpdateOrgUserForCurrentOrg(c *models.ReqContext, cmd models.UpdateOrgUserCommand) response.Response { func (hs *HTTPServer) UpdateOrgUserForCurrentOrg(c *models.ReqContext) response.Response {
cmd := models.UpdateOrgUserCommand{}
if err := web.Bind(c.Req, &cmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
cmd.OrgId = c.OrgId cmd.OrgId = c.OrgId
cmd.UserId = c.ParamsInt64(":userId") cmd.UserId = c.ParamsInt64(":userId")
return hs.updateOrgUserHelper(c.Req.Context(), cmd) return hs.updateOrgUserHelper(c.Req.Context(), cmd)
} }
// PATCH /api/orgs/:orgId/users/:userId // PATCH /api/orgs/:orgId/users/:userId
func (hs *HTTPServer) UpdateOrgUser(c *models.ReqContext, cmd models.UpdateOrgUserCommand) response.Response { func (hs *HTTPServer) UpdateOrgUser(c *models.ReqContext) response.Response {
cmd := models.UpdateOrgUserCommand{}
if err := web.Bind(c.Req, &cmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
cmd.OrgId = c.ParamsInt64(":orgId") cmd.OrgId = c.ParamsInt64(":orgId")
cmd.UserId = c.ParamsInt64(":userId") cmd.UserId = c.ParamsInt64(":userId")
return hs.updateOrgUserHelper(c.Req.Context(), cmd) return hs.updateOrgUserHelper(c.Req.Context(), cmd)
+2 -2
View File
@@ -57,7 +57,7 @@ func TestOrgUsersAPIEndpoint_userLoggedIn(t *testing.T) {
loggedInUserScenario(t, "When calling GET on", "api/org/users/search", func(sc *scenarioContext) { loggedInUserScenario(t, "When calling GET on", "api/org/users/search", func(sc *scenarioContext) {
setUpGetOrgUsersDB(t, sqlStore) setUpGetOrgUsersDB(t, sqlStore)
sc.handlerFuncCtx = hs.SearchOrgUsersWithPaging sc.handlerFunc = hs.SearchOrgUsersWithPaging
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec() sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
require.Equal(t, http.StatusOK, sc.resp.Code) require.Equal(t, http.StatusOK, sc.resp.Code)
@@ -75,7 +75,7 @@ func TestOrgUsersAPIEndpoint_userLoggedIn(t *testing.T) {
loggedInUserScenario(t, "When calling GET with page and limit query parameters on", "api/org/users/search", func(sc *scenarioContext) { loggedInUserScenario(t, "When calling GET with page and limit query parameters on", "api/org/users/search", func(sc *scenarioContext) {
setUpGetOrgUsersDB(t, sqlStore) setUpGetOrgUsersDB(t, sqlStore)
sc.handlerFuncCtx = hs.SearchOrgUsersWithPaging sc.handlerFunc = hs.SearchOrgUsersWithPaging
sc.fakeReqWithParams("GET", sc.url, map[string]string{"perpage": "2", "page": "2"}).exec() sc.fakeReqWithParams("GET", sc.url, map[string]string{"perpage": "2", "page": "2"}).exec()
require.Equal(t, http.StatusOK, sc.resp.Code) require.Equal(t, http.StatusOK, sc.resp.Code)
+12 -2
View File
@@ -2,6 +2,7 @@ package api
import ( import (
"errors" "errors"
"net/http"
"github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/api/response"
@@ -9,9 +10,14 @@ import (
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/util"
"github.com/grafana/grafana/pkg/web"
) )
func SendResetPasswordEmail(c *models.ReqContext, form dtos.SendResetPasswordEmailForm) response.Response { func SendResetPasswordEmail(c *models.ReqContext) response.Response {
form := dtos.SendResetPasswordEmailForm{}
if err := web.Bind(c.Req, &form); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
if setting.LDAPEnabled || setting.AuthProxyEnabled { if setting.LDAPEnabled || setting.AuthProxyEnabled {
return response.Error(401, "Not allowed to reset password when LDAP or Auth Proxy is enabled", nil) return response.Error(401, "Not allowed to reset password when LDAP or Auth Proxy is enabled", nil)
} }
@@ -34,7 +40,11 @@ func SendResetPasswordEmail(c *models.ReqContext, form dtos.SendResetPasswordEma
return response.Success("Email sent") return response.Success("Email sent")
} }
func ResetPassword(c *models.ReqContext, form dtos.ResetUserPasswordForm) response.Response { func ResetPassword(c *models.ReqContext) response.Response {
form := dtos.ResetUserPasswordForm{}
if err := web.Bind(c.Req, &form); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
query := models.ValidateResetPasswordCodeQuery{Code: form.Code} query := models.ValidateResetPasswordCodeQuery{Code: form.Code}
if err := bus.Dispatch(&query); err != nil { if err := bus.Dispatch(&query); err != nil {
+12 -2
View File
@@ -2,10 +2,12 @@ package api
import ( import (
"context" "context"
"net/http"
"github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/web"
) )
func ValidateOrgPlaylist(c *models.ReqContext) { func ValidateOrgPlaylist(c *models.ReqContext) {
@@ -138,7 +140,11 @@ func DeletePlaylist(c *models.ReqContext) response.Response {
return response.JSON(200, "") return response.JSON(200, "")
} }
func CreatePlaylist(c *models.ReqContext, cmd models.CreatePlaylistCommand) response.Response { func CreatePlaylist(c *models.ReqContext) response.Response {
cmd := models.CreatePlaylistCommand{}
if err := web.Bind(c.Req, &cmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
cmd.OrgId = c.OrgId cmd.OrgId = c.OrgId
if err := bus.DispatchCtx(c.Req.Context(), &cmd); err != nil { if err := bus.DispatchCtx(c.Req.Context(), &cmd); err != nil {
@@ -148,7 +154,11 @@ func CreatePlaylist(c *models.ReqContext, cmd models.CreatePlaylistCommand) resp
return response.JSON(200, cmd.Result) return response.JSON(200, cmd.Result)
} }
func UpdatePlaylist(c *models.ReqContext, cmd models.UpdatePlaylistCommand) response.Response { func UpdatePlaylist(c *models.ReqContext) response.Response {
cmd := models.UpdatePlaylistCommand{}
if err := web.Bind(c.Req, &cmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
cmd.OrgId = c.OrgId cmd.OrgId = c.OrgId
cmd.Id = c.ParamsInt64(":id") cmd.Id = c.ParamsInt64(":id")
+15 -3
View File
@@ -149,7 +149,11 @@ func (hs *HTTPServer) GetPluginSettingByID(c *models.ReqContext) response.Respon
return response.JSON(200, dto) return response.JSON(200, dto)
} }
func (hs *HTTPServer) UpdatePluginSetting(c *models.ReqContext, cmd models.UpdatePluginSettingCmd) response.Response { func (hs *HTTPServer) UpdatePluginSetting(c *models.ReqContext) response.Response {
cmd := models.UpdatePluginSettingCmd{}
if err := web.Bind(c.Req, &cmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
pluginID := web.Params(c.Req)[":pluginId"] pluginID := web.Params(c.Req)[":pluginId"]
if _, exists := hs.pluginStore.Plugin(c.Req.Context(), pluginID); !exists { if _, exists := hs.pluginStore.Plugin(c.Req.Context(), pluginID); !exists {
@@ -208,7 +212,11 @@ func (hs *HTTPServer) GetPluginMarkdown(c *models.ReqContext) response.Response
return resp return resp
} }
func (hs *HTTPServer) ImportDashboard(c *models.ReqContext, apiCmd dtos.ImportDashboardCommand) response.Response { func (hs *HTTPServer) ImportDashboard(c *models.ReqContext) response.Response {
apiCmd := dtos.ImportDashboardCommand{}
if err := web.Bind(c.Req, &apiCmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
var err error var err error
if apiCmd.PluginId == "" && apiCmd.Dashboard == nil { if apiCmd.PluginId == "" && apiCmd.Dashboard == nil {
return response.Error(422, "Dashboard must be set", nil) return response.Error(422, "Dashboard must be set", nil)
@@ -387,7 +395,11 @@ func (hs *HTTPServer) GetPluginErrorsList(_ *models.ReqContext) response.Respons
return response.JSON(200, hs.pluginErrorResolver.PluginErrors()) return response.JSON(200, hs.pluginErrorResolver.PluginErrors())
} }
func (hs *HTTPServer) InstallPlugin(c *models.ReqContext, dto dtos.InstallPluginCommand) response.Response { func (hs *HTTPServer) InstallPlugin(c *models.ReqContext) response.Response {
dto := dtos.InstallPluginCommand{}
if err := web.Bind(c.Req, &dto); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
pluginID := web.Params(c.Req)[":pluginId"] pluginID := web.Params(c.Req)[":pluginId"]
err := hs.pluginStore.Add(c.Req.Context(), pluginID, dto.Version, plugins.AddOpts{}) err := hs.pluginStore.Add(c.Req.Context(), pluginID, dto.Version, plugins.AddOpts{})
+17 -3
View File
@@ -2,11 +2,13 @@ package api
import ( import (
"context" "context"
"net/http"
"github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/web"
) )
const ( const (
@@ -16,7 +18,11 @@ const (
) )
// POST /api/preferences/set-home-dash // POST /api/preferences/set-home-dash
func SetHomeDashboard(c *models.ReqContext, cmd models.SavePreferencesCommand) response.Response { func SetHomeDashboard(c *models.ReqContext) response.Response {
cmd := models.SavePreferencesCommand{}
if err := web.Bind(c.Req, &cmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
cmd.UserId = c.UserId cmd.UserId = c.UserId
cmd.OrgId = c.OrgId cmd.OrgId = c.OrgId
@@ -50,7 +56,11 @@ func (hs *HTTPServer) getPreferencesFor(ctx context.Context, orgID, userID, team
} }
// PUT /api/user/preferences // PUT /api/user/preferences
func (hs *HTTPServer) UpdateUserPreferences(c *models.ReqContext, dtoCmd dtos.UpdatePrefsCmd) response.Response { func (hs *HTTPServer) UpdateUserPreferences(c *models.ReqContext) response.Response {
dtoCmd := dtos.UpdatePrefsCmd{}
if err := web.Bind(c.Req, &dtoCmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
return hs.updatePreferencesFor(c.Req.Context(), c.OrgId, c.UserId, 0, &dtoCmd) return hs.updatePreferencesFor(c.Req.Context(), c.OrgId, c.UserId, 0, &dtoCmd)
} }
@@ -81,6 +91,10 @@ func (hs *HTTPServer) GetOrgPreferences(c *models.ReqContext) response.Response
} }
// PUT /api/org/preferences // PUT /api/org/preferences
func (hs *HTTPServer) UpdateOrgPreferences(c *models.ReqContext, dtoCmd dtos.UpdatePrefsCmd) response.Response { func (hs *HTTPServer) UpdateOrgPreferences(c *models.ReqContext) response.Response {
dtoCmd := dtos.UpdatePrefsCmd{}
if err := web.Bind(c.Req, &dtoCmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
return hs.updatePreferencesFor(c.Req.Context(), c.OrgId, 0, 0, &dtoCmd) return hs.updatePreferencesFor(c.Req.Context(), c.OrgId, 0, 0, &dtoCmd)
} }
+12 -2
View File
@@ -1,6 +1,8 @@
package api package api
import ( import (
"net/http"
"github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
@@ -29,7 +31,11 @@ func (hs *HTTPServer) getOrgQuotasHelper(c *models.ReqContext, orgID int64) resp
return response.JSON(200, query.Result) return response.JSON(200, query.Result)
} }
func (hs *HTTPServer) UpdateOrgQuota(c *models.ReqContext, cmd models.UpdateOrgQuotaCmd) response.Response { func (hs *HTTPServer) UpdateOrgQuota(c *models.ReqContext) response.Response {
cmd := models.UpdateOrgQuotaCmd{}
if err := web.Bind(c.Req, &cmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
if !hs.Cfg.Quota.Enabled { if !hs.Cfg.Quota.Enabled {
return response.Error(404, "Quotas not enabled", nil) return response.Error(404, "Quotas not enabled", nil)
} }
@@ -59,7 +65,11 @@ func GetUserQuotas(c *models.ReqContext) response.Response {
return response.JSON(200, query.Result) return response.JSON(200, query.Result)
} }
func UpdateUserQuota(c *models.ReqContext, cmd models.UpdateUserQuotaCmd) response.Response { func UpdateUserQuota(c *models.ReqContext) response.Response {
cmd := models.UpdateUserQuotaCmd{}
if err := web.Bind(c.Req, &cmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
if !setting.Quota.Enabled { if !setting.Quota.Enabled {
return response.Error(404, "Quotas not enabled", nil) return response.Error(404, "Quotas not enabled", nil)
} }
+3 -9
View File
@@ -12,16 +12,10 @@ var (
} }
) )
func Wrap(action interface{}) web.Handler { func Wrap(handler func(c *models.ReqContext) response.Response) web.Handler {
return func(c *models.ReqContext) { return func(c *models.ReqContext) {
var res response.Response if res := handler(c); res != nil {
val, err := c.Invoke(action) res.WriteTo(c)
if err == nil && val != nil && len(val) > 0 {
res = val[0].Interface().(response.Response)
} else {
res = ServerError(err)
} }
res.WriteTo(c)
} }
} }
+6 -1
View File
@@ -3,6 +3,7 @@ package api
import ( import (
"errors" "errors"
"fmt" "fmt"
"net/http"
"path" "path"
"strings" "strings"
@@ -15,7 +16,11 @@ import (
) )
// createShortURL handles requests to create short URLs. // createShortURL handles requests to create short URLs.
func (hs *HTTPServer) createShortURL(c *models.ReqContext, cmd dtos.CreateShortURLCmd) response.Response { func (hs *HTTPServer) createShortURL(c *models.ReqContext) response.Response {
cmd := dtos.CreateShortURLCmd{}
if err := web.Bind(c.Req, &cmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
hs.log.Debug("Received request to create short URL", "path", cmd.Path) hs.log.Debug("Received request to create short URL", "path", cmd.Path)
cmd.Path = strings.TrimSpace(cmd.Path) cmd.Path = strings.TrimSpace(cmd.Path)
+2 -1
View File
@@ -64,10 +64,11 @@ func createShortURLScenario(t *testing.T, desc string, url string, routePattern
sc := setupScenarioContext(t, url) sc := setupScenarioContext(t, url)
sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response {
c.Req.Body = mockRequestBody(cmd)
sc.context = c sc.context = c
sc.context.SignedInUser = &models.SignedInUser{OrgId: testOrgID, UserId: testUserID} sc.context.SignedInUser = &models.SignedInUser{OrgId: testOrgID, UserId: testUserID}
return hs.createShortURL(c, cmd) return hs.createShortURL(c)
}) })
sc.m.Post(routePattern, sc.defaultHandler) sc.m.Post(routePattern, sc.defaultHandler)
+12 -2
View File
@@ -3,6 +3,7 @@ package api
import ( import (
"context" "context"
"errors" "errors"
"net/http"
"github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/api/response"
@@ -12,6 +13,7 @@ import (
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/util"
"github.com/grafana/grafana/pkg/web"
) )
// GET /api/user/signup/options // GET /api/user/signup/options
@@ -23,7 +25,11 @@ func GetSignUpOptions(c *models.ReqContext) response.Response {
} }
// POST /api/user/signup // POST /api/user/signup
func SignUp(c *models.ReqContext, form dtos.SignUpForm) response.Response { func SignUp(c *models.ReqContext) response.Response {
form := dtos.SignUpForm{}
if err := web.Bind(c.Req, &form); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
if !setting.AllowUserSignUp { if !setting.AllowUserSignUp {
return response.Error(401, "User signup is disabled", nil) return response.Error(401, "User signup is disabled", nil)
} }
@@ -61,7 +67,11 @@ func SignUp(c *models.ReqContext, form dtos.SignUpForm) response.Response {
return response.JSON(200, util.DynMap{"status": "SignUpCreated"}) return response.JSON(200, util.DynMap{"status": "SignUpCreated"})
} }
func (hs *HTTPServer) SignUpStep2(c *models.ReqContext, form dtos.SignUpStep2Form) response.Response { func (hs *HTTPServer) SignUpStep2(c *models.ReqContext) response.Response {
form := dtos.SignUpStep2Form{}
if err := web.Bind(c.Req, &form); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
if !setting.AllowUserSignUp { if !setting.AllowUserSignUp {
return response.Error(401, "User signup is disabled", nil) return response.Error(401, "User signup is disabled", nil)
} }
+17 -3
View File
@@ -2,6 +2,7 @@ package api
import ( import (
"errors" "errors"
"net/http"
"github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/api/response"
@@ -10,10 +11,15 @@ import (
"github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/teamguardian" "github.com/grafana/grafana/pkg/services/teamguardian"
"github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/util"
"github.com/grafana/grafana/pkg/web"
) )
// POST /api/teams // POST /api/teams
func (hs *HTTPServer) CreateTeam(c *models.ReqContext, cmd models.CreateTeamCommand) response.Response { func (hs *HTTPServer) CreateTeam(c *models.ReqContext) response.Response {
cmd := models.CreateTeamCommand{}
if err := web.Bind(c.Req, &cmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
if c.OrgRole == models.ROLE_VIEWER { if c.OrgRole == models.ROLE_VIEWER {
return response.Error(403, "Not allowed to create team.", nil) return response.Error(403, "Not allowed to create team.", nil)
} }
@@ -47,7 +53,11 @@ func (hs *HTTPServer) CreateTeam(c *models.ReqContext, cmd models.CreateTeamComm
} }
// PUT /api/teams/:teamId // PUT /api/teams/:teamId
func (hs *HTTPServer) UpdateTeam(c *models.ReqContext, cmd models.UpdateTeamCommand) response.Response { func (hs *HTTPServer) UpdateTeam(c *models.ReqContext) response.Response {
cmd := models.UpdateTeamCommand{}
if err := web.Bind(c.Req, &cmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
cmd.OrgId = c.OrgId cmd.OrgId = c.OrgId
cmd.Id = c.ParamsInt64(":teamId") cmd.Id = c.ParamsInt64(":teamId")
@@ -159,7 +169,11 @@ func (hs *HTTPServer) GetTeamPreferences(c *models.ReqContext) response.Response
} }
// PUT /api/teams/:teamId/preferences // PUT /api/teams/:teamId/preferences
func (hs *HTTPServer) UpdateTeamPreferences(c *models.ReqContext, dtoCmd dtos.UpdatePrefsCmd) response.Response { func (hs *HTTPServer) UpdateTeamPreferences(c *models.ReqContext) response.Response {
dtoCmd := dtos.UpdatePrefsCmd{}
if err := web.Bind(c.Req, &dtoCmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
teamId := c.ParamsInt64(":teamId") teamId := c.ParamsInt64(":teamId")
orgId := c.OrgId orgId := c.OrgId
+12 -2
View File
@@ -2,6 +2,7 @@ package api
import ( import (
"errors" "errors"
"net/http"
"github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/api/response"
@@ -10,6 +11,7 @@ import (
"github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/teamguardian" "github.com/grafana/grafana/pkg/services/teamguardian"
"github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/util"
"github.com/grafana/grafana/pkg/web"
) )
// GET /api/teams/:teamId/members // GET /api/teams/:teamId/members
@@ -41,7 +43,11 @@ func (hs *HTTPServer) GetTeamMembers(c *models.ReqContext) response.Response {
} }
// POST /api/teams/:teamId/members // POST /api/teams/:teamId/members
func (hs *HTTPServer) AddTeamMember(c *models.ReqContext, cmd models.AddTeamMemberCommand) response.Response { func (hs *HTTPServer) AddTeamMember(c *models.ReqContext) response.Response {
cmd := models.AddTeamMemberCommand{}
if err := web.Bind(c.Req, &cmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
cmd.OrgId = c.OrgId cmd.OrgId = c.OrgId
cmd.TeamId = c.ParamsInt64(":teamId") cmd.TeamId = c.ParamsInt64(":teamId")
@@ -68,7 +74,11 @@ func (hs *HTTPServer) AddTeamMember(c *models.ReqContext, cmd models.AddTeamMemb
} }
// PUT /:teamId/members/:userId // PUT /:teamId/members/:userId
func (hs *HTTPServer) UpdateTeamMember(c *models.ReqContext, cmd models.UpdateTeamMemberCommand) response.Response { func (hs *HTTPServer) UpdateTeamMember(c *models.ReqContext) response.Response {
cmd := models.UpdateTeamMemberCommand{}
if err := web.Bind(c.Req, &cmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
teamId := c.ParamsInt64(":teamId") teamId := c.ParamsInt64(":teamId")
orgId := c.OrgId orgId := c.OrgId
+4 -4
View File
@@ -130,8 +130,8 @@ func TestTeamAPIEndpoint(t *testing.T) {
Logger: stub, Logger: stub,
} }
c.OrgRole = models.ROLE_EDITOR c.OrgRole = models.ROLE_EDITOR
cmd := models.CreateTeamCommand{Name: teamName} c.Req.Body = mockRequestBody(models.CreateTeamCommand{Name: teamName})
hs.CreateTeam(c, cmd) hs.CreateTeam(c)
assert.Equal(t, createTeamCalled, 1) assert.Equal(t, createTeamCalled, 1)
assert.Equal(t, addTeamMemberCalled, 0) assert.Equal(t, addTeamMemberCalled, 0)
assert.True(t, stub.warnCalled) assert.True(t, stub.warnCalled)
@@ -146,9 +146,9 @@ func TestTeamAPIEndpoint(t *testing.T) {
Logger: stub, Logger: stub,
} }
c.OrgRole = models.ROLE_EDITOR c.OrgRole = models.ROLE_EDITOR
cmd := models.CreateTeamCommand{Name: teamName} c.Req.Body = mockRequestBody(models.CreateTeamCommand{Name: teamName})
createTeamCalled, addTeamMemberCalled = 0, 0 createTeamCalled, addTeamMemberCalled = 0, 0
hs.CreateTeam(c, cmd) hs.CreateTeam(c)
assert.Equal(t, createTeamCalled, 1) assert.Equal(t, createTeamCalled, 1)
assert.Equal(t, addTeamMemberCalled, 1) assert.Equal(t, addTeamMemberCalled, 1)
assert.False(t, stub.warnCalled) assert.False(t, stub.warnCalled)
+17 -3
View File
@@ -3,6 +3,7 @@ package api
import ( import (
"context" "context"
"errors" "errors"
"net/http"
"github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/api/response"
@@ -10,6 +11,7 @@ import (
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/util"
"github.com/grafana/grafana/pkg/web"
) )
// GET /api/user (current authenticated user) // GET /api/user (current authenticated user)
@@ -70,7 +72,11 @@ func GetUserByLoginOrEmail(c *models.ReqContext) response.Response {
} }
// POST /api/user // POST /api/user
func UpdateSignedInUser(c *models.ReqContext, cmd models.UpdateUserCommand) response.Response { func UpdateSignedInUser(c *models.ReqContext) response.Response {
cmd := models.UpdateUserCommand{}
if err := web.Bind(c.Req, &cmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
if setting.AuthProxyEnabled { if setting.AuthProxyEnabled {
if setting.AuthProxyHeaderProperty == "email" && cmd.Email != c.Email { if setting.AuthProxyHeaderProperty == "email" && cmd.Email != c.Email {
return response.Error(400, "Not allowed to change email when auth proxy is using email property", nil) return response.Error(400, "Not allowed to change email when auth proxy is using email property", nil)
@@ -84,7 +90,11 @@ func UpdateSignedInUser(c *models.ReqContext, cmd models.UpdateUserCommand) resp
} }
// POST /api/users/:id // POST /api/users/:id
func UpdateUser(c *models.ReqContext, cmd models.UpdateUserCommand) response.Response { func UpdateUser(c *models.ReqContext) response.Response {
cmd := models.UpdateUserCommand{}
if err := web.Bind(c.Req, &cmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
cmd.UserId = c.ParamsInt64(":id") cmd.UserId = c.ParamsInt64(":id")
return handleUpdateUser(c.Req.Context(), cmd) return handleUpdateUser(c.Req.Context(), cmd)
} }
@@ -217,7 +227,11 @@ func (hs *HTTPServer) ChangeActiveOrgAndRedirectToHome(c *models.ReqContext) {
c.Redirect(hs.Cfg.AppSubURL + "/") c.Redirect(hs.Cfg.AppSubURL + "/")
} }
func ChangeUserPassword(c *models.ReqContext, cmd models.ChangeUserPasswordCommand) response.Response { func ChangeUserPassword(c *models.ReqContext) response.Response {
cmd := models.ChangeUserPasswordCommand{}
if err := web.Bind(c.Req, &cmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
if setting.LDAPEnabled || setting.AuthProxyEnabled { if setting.LDAPEnabled || setting.AuthProxyEnabled {
return response.Error(400, "Not allowed to change password when LDAP or Auth Proxy is enabled", nil) return response.Error(400, "Not allowed to change password when LDAP or Auth Proxy is enabled", nil)
} }
+7 -1
View File
@@ -3,6 +3,7 @@ package api
import ( import (
"context" "context"
"errors" "errors"
"net/http"
"time" "time"
"github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/api/dtos"
@@ -10,6 +11,7 @@ import (
"github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/util"
"github.com/grafana/grafana/pkg/web"
"github.com/ua-parser/uap-go/uaparser" "github.com/ua-parser/uap-go/uaparser"
) )
@@ -19,7 +21,11 @@ func (hs *HTTPServer) GetUserAuthTokens(c *models.ReqContext) response.Response
} }
// POST /api/user/revoke-auth-token // POST /api/user/revoke-auth-token
func (hs *HTTPServer) RevokeUserAuthToken(c *models.ReqContext, cmd models.RevokeAuthTokenCmd) response.Response { func (hs *HTTPServer) RevokeUserAuthToken(c *models.ReqContext) response.Response {
cmd := models.RevokeAuthTokenCmd{}
if err := web.Bind(c.Req, &cmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
return hs.revokeUserAuthTokenInternal(c, c.UserId, cmd) return hs.revokeUserAuthTokenInternal(c, c.UserId, cmd)
} }
+2 -1
View File
@@ -184,12 +184,13 @@ func revokeUserAuthTokenScenario(t *testing.T, desc string, url string, routePat
sc := setupScenarioContext(t, url) sc := setupScenarioContext(t, url)
sc.userAuthTokenService = fakeAuthTokenService sc.userAuthTokenService = fakeAuthTokenService
sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response {
c.Req.Body = mockRequestBody(cmd)
sc.context = c sc.context = c
sc.context.UserId = userId sc.context.UserId = userId
sc.context.OrgId = testOrgID sc.context.OrgId = testOrgID
sc.context.OrgRole = models.ROLE_ADMIN sc.context.OrgRole = models.ROLE_ADMIN
return hs.RevokeUserAuthToken(c, cmd) return hs.RevokeUserAuthToken(c)
}) })
sc.m.Post(routePattern, sc.defaultHandler) sc.m.Post(routePattern, sc.defaultHandler)
+15 -5
View File
@@ -2,8 +2,8 @@ package libraryelements
import ( import (
"errors" "errors"
"net/http"
"github.com/go-macaron/binding"
"github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/api/routing" "github.com/grafana/grafana/pkg/api/routing"
"github.com/grafana/grafana/pkg/middleware" "github.com/grafana/grafana/pkg/middleware"
@@ -13,18 +13,23 @@ import (
func (l *LibraryElementService) registerAPIEndpoints() { func (l *LibraryElementService) registerAPIEndpoints() {
l.RouteRegister.Group("/api/library-elements", func(entities routing.RouteRegister) { l.RouteRegister.Group("/api/library-elements", func(entities routing.RouteRegister) {
entities.Post("/", middleware.ReqSignedIn, binding.Bind(CreateLibraryElementCommand{}), routing.Wrap(l.createHandler)) entities.Post("/", middleware.ReqSignedIn, routing.Wrap(l.createHandler))
entities.Delete("/:uid", middleware.ReqSignedIn, routing.Wrap(l.deleteHandler)) entities.Delete("/:uid", middleware.ReqSignedIn, routing.Wrap(l.deleteHandler))
entities.Get("/", middleware.ReqSignedIn, routing.Wrap(l.getAllHandler)) entities.Get("/", middleware.ReqSignedIn, routing.Wrap(l.getAllHandler))
entities.Get("/:uid", middleware.ReqSignedIn, routing.Wrap(l.getHandler)) entities.Get("/:uid", middleware.ReqSignedIn, routing.Wrap(l.getHandler))
entities.Get("/:uid/connections/", middleware.ReqSignedIn, routing.Wrap(l.getConnectionsHandler)) entities.Get("/:uid/connections/", middleware.ReqSignedIn, routing.Wrap(l.getConnectionsHandler))
entities.Get("/name/:name", middleware.ReqSignedIn, routing.Wrap(l.getByNameHandler)) entities.Get("/name/:name", middleware.ReqSignedIn, routing.Wrap(l.getByNameHandler))
entities.Patch("/:uid", middleware.ReqSignedIn, binding.Bind(patchLibraryElementCommand{}), routing.Wrap(l.patchHandler)) entities.Patch("/:uid", middleware.ReqSignedIn, routing.Wrap(l.patchHandler))
}) })
} }
// createHandler handles POST /api/library-elements. // createHandler handles POST /api/library-elements.
func (l *LibraryElementService) createHandler(c *models.ReqContext, cmd CreateLibraryElementCommand) response.Response { func (l *LibraryElementService) createHandler(c *models.ReqContext) response.Response {
cmd := CreateLibraryElementCommand{}
if err := web.Bind(c.Req, &cmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
element, err := l.createLibraryElement(c.Req.Context(), c.SignedInUser, cmd) element, err := l.createLibraryElement(c.Req.Context(), c.SignedInUser, cmd)
if err != nil { if err != nil {
return toLibraryElementError(err, "Failed to create library element") return toLibraryElementError(err, "Failed to create library element")
@@ -77,7 +82,12 @@ func (l *LibraryElementService) getAllHandler(c *models.ReqContext) response.Res
} }
// patchHandler handles PATCH /api/library-elements/:uid // patchHandler handles PATCH /api/library-elements/:uid
func (l *LibraryElementService) patchHandler(c *models.ReqContext, cmd patchLibraryElementCommand) response.Response { func (l *LibraryElementService) patchHandler(c *models.ReqContext) response.Response {
cmd := patchLibraryElementCommand{}
if err := web.Bind(c.Req, &cmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
element, err := l.patchLibraryElement(c.Req.Context(), c.SignedInUser, cmd, web.Params(c.Req)[":uid"]) element, err := l.patchLibraryElement(c.Req.Context(), c.SignedInUser, cmd, web.Params(c.Req)[":uid"])
if err != nil { if err != nil {
return toLibraryElementError(err, "Failed to update library element") return toLibraryElementError(err, "Failed to update library element")
@@ -14,7 +14,8 @@ func TestCreateLibraryElement(t *testing.T) {
scenarioWithPanel(t, "When an admin tries to create a library panel that already exists, it should fail", scenarioWithPanel(t, "When an admin tries to create a library panel that already exists, it should fail",
func(t *testing.T, sc scenarioContext) { func(t *testing.T, sc scenarioContext) {
command := getCreatePanelCommand(sc.folder.Id, "Text - Library Panel") command := getCreatePanelCommand(sc.folder.Id, "Text - Library Panel")
resp := sc.service.createHandler(sc.reqContext, command) sc.reqContext.Req.Body = mockRequestBody(command)
resp := sc.service.createHandler(sc.reqContext)
require.Equal(t, 400, resp.Status()) require.Equal(t, 400, resp.Status())
}) })
@@ -64,7 +65,8 @@ func TestCreateLibraryElement(t *testing.T) {
func(t *testing.T, sc scenarioContext) { func(t *testing.T, sc scenarioContext) {
command := getCreatePanelCommand(sc.folder.Id, "Nonexistent UID") command := getCreatePanelCommand(sc.folder.Id, "Nonexistent UID")
command.UID = util.GenerateShortUID() command.UID = util.GenerateShortUID()
resp := sc.service.createHandler(sc.reqContext, command) sc.reqContext.Req.Body = mockRequestBody(command)
resp := sc.service.createHandler(sc.reqContext)
var result = validateAndUnMarshalResponse(t, resp) var result = validateAndUnMarshalResponse(t, resp)
var expected = libraryElementResult{ var expected = libraryElementResult{
Result: libraryElement{ Result: libraryElement{
@@ -110,7 +112,8 @@ func TestCreateLibraryElement(t *testing.T) {
func(t *testing.T, sc scenarioContext) { func(t *testing.T, sc scenarioContext) {
command := getCreatePanelCommand(sc.folder.Id, "Existing UID") command := getCreatePanelCommand(sc.folder.Id, "Existing UID")
command.UID = sc.initialResult.Result.UID command.UID = sc.initialResult.Result.UID
resp := sc.service.createHandler(sc.reqContext, command) sc.reqContext.Req.Body = mockRequestBody(command)
resp := sc.service.createHandler(sc.reqContext)
require.Equal(t, 400, resp.Status()) require.Equal(t, 400, resp.Status())
}) })
@@ -118,7 +121,8 @@ func TestCreateLibraryElement(t *testing.T) {
func(t *testing.T, sc scenarioContext) { func(t *testing.T, sc scenarioContext) {
command := getCreatePanelCommand(sc.folder.Id, "Invalid UID") command := getCreatePanelCommand(sc.folder.Id, "Invalid UID")
command.UID = "Testing an invalid UID" command.UID = "Testing an invalid UID"
resp := sc.service.createHandler(sc.reqContext, command) sc.reqContext.Req.Body = mockRequestBody(command)
resp := sc.service.createHandler(sc.reqContext)
require.Equal(t, 400, resp.Status()) require.Equal(t, 400, resp.Status())
}) })
@@ -126,14 +130,16 @@ func TestCreateLibraryElement(t *testing.T) {
func(t *testing.T, sc scenarioContext) { func(t *testing.T, sc scenarioContext) {
command := getCreatePanelCommand(sc.folder.Id, "Invalid UID") command := getCreatePanelCommand(sc.folder.Id, "Invalid UID")
command.UID = "j6T00KRZzj6T00KRZzj6T00KRZzj6T00KRZzj6T00K" command.UID = "j6T00KRZzj6T00KRZzj6T00KRZzj6T00KRZzj6T00K"
resp := sc.service.createHandler(sc.reqContext, command) sc.reqContext.Req.Body = mockRequestBody(command)
resp := sc.service.createHandler(sc.reqContext)
require.Equal(t, 400, resp.Status()) require.Equal(t, 400, resp.Status())
}) })
testScenario(t, "When an admin tries to create a library panel where name and panel title differ, it should not update panel title", testScenario(t, "When an admin tries to create a library panel where name and panel title differ, it should not update panel title",
func(t *testing.T, sc scenarioContext) { func(t *testing.T, sc scenarioContext) {
command := getCreatePanelCommand(1, "Library Panel Name") command := getCreatePanelCommand(1, "Library Panel Name")
resp := sc.service.createHandler(sc.reqContext, command) sc.reqContext.Req.Body = mockRequestBody(command)
resp := sc.service.createHandler(sc.reqContext)
var result = validateAndUnMarshalResponse(t, resp) var result = validateAndUnMarshalResponse(t, resp)
var expected = libraryElementResult{ var expected = libraryElementResult{
Result: libraryElement{ Result: libraryElement{
@@ -37,7 +37,8 @@ func TestGetAllLibraryElements(t *testing.T) {
scenarioWithPanel(t, "When an admin tries to get all panel elements and both panels and variables exist, it should only return panels", scenarioWithPanel(t, "When an admin tries to get all panel elements and both panels and variables exist, it should only return panels",
func(t *testing.T, sc scenarioContext) { func(t *testing.T, sc scenarioContext) {
command := getCreateVariableCommand(sc.folder.Id, "query0") command := getCreateVariableCommand(sc.folder.Id, "query0")
resp := sc.service.createHandler(sc.reqContext, command) sc.reqContext.Req.Body = mockRequestBody(command)
resp := sc.service.createHandler(sc.reqContext)
require.Equal(t, 200, resp.Status()) require.Equal(t, 200, resp.Status())
err := sc.reqContext.Req.ParseForm() err := sc.reqContext.Req.ParseForm()
@@ -102,7 +103,8 @@ func TestGetAllLibraryElements(t *testing.T) {
scenarioWithPanel(t, "When an admin tries to get all variable elements and both panels and variables exist, it should only return panels", scenarioWithPanel(t, "When an admin tries to get all variable elements and both panels and variables exist, it should only return panels",
func(t *testing.T, sc scenarioContext) { func(t *testing.T, sc scenarioContext) {
command := getCreateVariableCommand(sc.folder.Id, "query0") command := getCreateVariableCommand(sc.folder.Id, "query0")
resp := sc.service.createHandler(sc.reqContext, command) sc.reqContext.Req.Body = mockRequestBody(command)
resp := sc.service.createHandler(sc.reqContext)
require.Equal(t, 200, resp.Status()) require.Equal(t, 200, resp.Status())
err := sc.reqContext.Req.ParseForm() err := sc.reqContext.Req.ParseForm()
@@ -166,7 +168,8 @@ func TestGetAllLibraryElements(t *testing.T) {
scenarioWithPanel(t, "When an admin tries to get all library panels and two exist, it should succeed", scenarioWithPanel(t, "When an admin tries to get all library panels and two exist, it should succeed",
func(t *testing.T, sc scenarioContext) { func(t *testing.T, sc scenarioContext) {
command := getCreatePanelCommand(sc.folder.Id, "Text - Library Panel2") command := getCreatePanelCommand(sc.folder.Id, "Text - Library Panel2")
resp := sc.service.createHandler(sc.reqContext, command) sc.reqContext.Req.Body = mockRequestBody(command)
resp := sc.service.createHandler(sc.reqContext)
require.Equal(t, 200, resp.Status()) require.Equal(t, 200, resp.Status())
resp = sc.service.getAllHandler(sc.reqContext) resp = sc.service.getAllHandler(sc.reqContext)
@@ -262,7 +265,8 @@ func TestGetAllLibraryElements(t *testing.T) {
scenarioWithPanel(t, "When an admin tries to get all library panels and two exist and sort desc is set, it should succeed and the result should be correct", scenarioWithPanel(t, "When an admin tries to get all library panels and two exist and sort desc is set, it should succeed and the result should be correct",
func(t *testing.T, sc scenarioContext) { func(t *testing.T, sc scenarioContext) {
command := getCreatePanelCommand(sc.folder.Id, "Text - Library Panel2") command := getCreatePanelCommand(sc.folder.Id, "Text - Library Panel2")
resp := sc.service.createHandler(sc.reqContext, command) sc.reqContext.Req.Body = mockRequestBody(command)
resp := sc.service.createHandler(sc.reqContext)
require.Equal(t, 200, resp.Status()) require.Equal(t, 200, resp.Status())
err := sc.reqContext.Req.ParseForm() err := sc.reqContext.Req.ParseForm()
@@ -369,7 +373,8 @@ func TestGetAllLibraryElements(t *testing.T) {
"description": "Gauge description" "description": "Gauge description"
} }
`)) `))
resp := sc.service.createHandler(sc.reqContext, command) sc.reqContext.Req.Body = mockRequestBody(command)
resp := sc.service.createHandler(sc.reqContext)
require.Equal(t, 200, resp.Status()) require.Equal(t, 200, resp.Status())
command = getCreateCommandWithModel(sc.folder.Id, "BarGauge - Library Panel", models.PanelElement, []byte(` command = getCreateCommandWithModel(sc.folder.Id, "BarGauge - Library Panel", models.PanelElement, []byte(`
@@ -381,7 +386,8 @@ func TestGetAllLibraryElements(t *testing.T) {
"description": "BarGauge description" "description": "BarGauge description"
} }
`)) `))
resp = sc.service.createHandler(sc.reqContext, command) sc.reqContext.Req.Body = mockRequestBody(command)
resp = sc.service.createHandler(sc.reqContext)
require.Equal(t, 200, resp.Status()) require.Equal(t, 200, resp.Status())
err := sc.reqContext.Req.ParseForm() err := sc.reqContext.Req.ParseForm()
@@ -488,7 +494,8 @@ func TestGetAllLibraryElements(t *testing.T) {
"description": "Gauge description" "description": "Gauge description"
} }
`)) `))
resp := sc.service.createHandler(sc.reqContext, command) sc.reqContext.Req.Body = mockRequestBody(command)
resp := sc.service.createHandler(sc.reqContext)
require.Equal(t, 200, resp.Status()) require.Equal(t, 200, resp.Status())
err := sc.reqContext.Req.ParseForm() err := sc.reqContext.Req.ParseForm()
@@ -517,7 +524,8 @@ func TestGetAllLibraryElements(t *testing.T) {
func(t *testing.T, sc scenarioContext) { func(t *testing.T, sc scenarioContext) {
newFolder := createFolderWithACL(t, sc.sqlStore, "NewFolder", sc.user, []folderACLItem{}) newFolder := createFolderWithACL(t, sc.sqlStore, "NewFolder", sc.user, []folderACLItem{})
command := getCreatePanelCommand(newFolder.Id, "Text - Library Panel2") command := getCreatePanelCommand(newFolder.Id, "Text - Library Panel2")
resp := sc.service.createHandler(sc.reqContext, command) sc.reqContext.Req.Body = mockRequestBody(command)
resp := sc.service.createHandler(sc.reqContext)
require.Equal(t, 200, resp.Status()) require.Equal(t, 200, resp.Status())
folderFilter := strconv.FormatInt(newFolder.Id, 10) folderFilter := strconv.FormatInt(newFolder.Id, 10)
@@ -583,7 +591,8 @@ func TestGetAllLibraryElements(t *testing.T) {
func(t *testing.T, sc scenarioContext) { func(t *testing.T, sc scenarioContext) {
newFolder := createFolderWithACL(t, sc.sqlStore, "NewFolder", sc.user, []folderACLItem{}) newFolder := createFolderWithACL(t, sc.sqlStore, "NewFolder", sc.user, []folderACLItem{})
command := getCreatePanelCommand(newFolder.Id, "Text - Library Panel2") command := getCreatePanelCommand(newFolder.Id, "Text - Library Panel2")
resp := sc.service.createHandler(sc.reqContext, command) sc.reqContext.Req.Body = mockRequestBody(command)
resp := sc.service.createHandler(sc.reqContext)
require.Equal(t, 200, resp.Status()) require.Equal(t, 200, resp.Status())
folderFilter := "2020,2021" folderFilter := "2020,2021"
@@ -612,7 +621,8 @@ func TestGetAllLibraryElements(t *testing.T) {
scenarioWithPanel(t, "When an admin tries to get all library panels and two exist and folderFilter is set to General folder, it should succeed and the result should be correct", scenarioWithPanel(t, "When an admin tries to get all library panels and two exist and folderFilter is set to General folder, it should succeed and the result should be correct",
func(t *testing.T, sc scenarioContext) { func(t *testing.T, sc scenarioContext) {
command := getCreatePanelCommand(sc.folder.Id, "Text - Library Panel2") command := getCreatePanelCommand(sc.folder.Id, "Text - Library Panel2")
resp := sc.service.createHandler(sc.reqContext, command) sc.reqContext.Req.Body = mockRequestBody(command)
resp := sc.service.createHandler(sc.reqContext)
require.Equal(t, 200, resp.Status()) require.Equal(t, 200, resp.Status())
folderFilter := "0" folderFilter := "0"
@@ -712,7 +722,8 @@ func TestGetAllLibraryElements(t *testing.T) {
scenarioWithPanel(t, "When an admin tries to get all library panels and two exist and excludeUID is set, it should succeed and the result should be correct", scenarioWithPanel(t, "When an admin tries to get all library panels and two exist and excludeUID is set, it should succeed and the result should be correct",
func(t *testing.T, sc scenarioContext) { func(t *testing.T, sc scenarioContext) {
command := getCreatePanelCommand(sc.folder.Id, "Text - Library Panel2") command := getCreatePanelCommand(sc.folder.Id, "Text - Library Panel2")
resp := sc.service.createHandler(sc.reqContext, command) sc.reqContext.Req.Body = mockRequestBody(command)
resp := sc.service.createHandler(sc.reqContext)
require.Equal(t, 200, resp.Status()) require.Equal(t, 200, resp.Status())
err := sc.reqContext.Req.ParseForm() err := sc.reqContext.Req.ParseForm()
@@ -776,7 +787,8 @@ func TestGetAllLibraryElements(t *testing.T) {
scenarioWithPanel(t, "When an admin tries to get all library panels and two exist and perPage is 1, it should succeed and the result should be correct", scenarioWithPanel(t, "When an admin tries to get all library panels and two exist and perPage is 1, it should succeed and the result should be correct",
func(t *testing.T, sc scenarioContext) { func(t *testing.T, sc scenarioContext) {
command := getCreatePanelCommand(sc.folder.Id, "Text - Library Panel2") command := getCreatePanelCommand(sc.folder.Id, "Text - Library Panel2")
resp := sc.service.createHandler(sc.reqContext, command) sc.reqContext.Req.Body = mockRequestBody(command)
resp := sc.service.createHandler(sc.reqContext)
require.Equal(t, 200, resp.Status()) require.Equal(t, 200, resp.Status())
err := sc.reqContext.Req.ParseForm() err := sc.reqContext.Req.ParseForm()
@@ -840,7 +852,8 @@ func TestGetAllLibraryElements(t *testing.T) {
scenarioWithPanel(t, "When an admin tries to get all library panels and two exist and perPage is 1 and page is 2, it should succeed and the result should be correct", scenarioWithPanel(t, "When an admin tries to get all library panels and two exist and perPage is 1 and page is 2, it should succeed and the result should be correct",
func(t *testing.T, sc scenarioContext) { func(t *testing.T, sc scenarioContext) {
command := getCreatePanelCommand(sc.folder.Id, "Text - Library Panel2") command := getCreatePanelCommand(sc.folder.Id, "Text - Library Panel2")
resp := sc.service.createHandler(sc.reqContext, command) sc.reqContext.Req.Body = mockRequestBody(command)
resp := sc.service.createHandler(sc.reqContext)
require.Equal(t, 200, resp.Status()) require.Equal(t, 200, resp.Status())
err := sc.reqContext.Req.ParseForm() err := sc.reqContext.Req.ParseForm()
@@ -913,7 +926,8 @@ func TestGetAllLibraryElements(t *testing.T) {
"description": "Some other d e s c r i p t i o n" "description": "Some other d e s c r i p t i o n"
} }
`)) `))
resp := sc.service.createHandler(sc.reqContext, command) sc.reqContext.Req.Body = mockRequestBody(command)
resp := sc.service.createHandler(sc.reqContext)
require.Equal(t, 200, resp.Status()) require.Equal(t, 200, resp.Status())
err := sc.reqContext.Req.ParseForm() err := sc.reqContext.Req.ParseForm()
@@ -987,7 +1001,8 @@ func TestGetAllLibraryElements(t *testing.T) {
"description": "A Library Panel" "description": "A Library Panel"
} }
`)) `))
resp := sc.service.createHandler(sc.reqContext, command) sc.reqContext.Req.Body = mockRequestBody(command)
resp := sc.service.createHandler(sc.reqContext)
require.Equal(t, 200, resp.Status()) require.Equal(t, 200, resp.Status())
err := sc.reqContext.Req.ParseForm() err := sc.reqContext.Req.ParseForm()
@@ -1086,7 +1101,8 @@ func TestGetAllLibraryElements(t *testing.T) {
scenarioWithPanel(t, "When an admin tries to get all library panels and two exist and perPage is 1 and page is 1 and searchString is panel2, it should succeed and the result should be correct", scenarioWithPanel(t, "When an admin tries to get all library panels and two exist and perPage is 1 and page is 1 and searchString is panel2, it should succeed and the result should be correct",
func(t *testing.T, sc scenarioContext) { func(t *testing.T, sc scenarioContext) {
command := getCreatePanelCommand(sc.folder.Id, "Text - Library Panel2") command := getCreatePanelCommand(sc.folder.Id, "Text - Library Panel2")
resp := sc.service.createHandler(sc.reqContext, command) sc.reqContext.Req.Body = mockRequestBody(command)
resp := sc.service.createHandler(sc.reqContext)
require.Equal(t, 200, resp.Status()) require.Equal(t, 200, resp.Status())
err := sc.reqContext.Req.ParseForm() err := sc.reqContext.Req.ParseForm()
@@ -1152,7 +1168,8 @@ func TestGetAllLibraryElements(t *testing.T) {
scenarioWithPanel(t, "When an admin tries to get all library panels and two exist and perPage is 1 and page is 3 and searchString is panel, it should succeed and the result should be correct", scenarioWithPanel(t, "When an admin tries to get all library panels and two exist and perPage is 1 and page is 3 and searchString is panel, it should succeed and the result should be correct",
func(t *testing.T, sc scenarioContext) { func(t *testing.T, sc scenarioContext) {
command := getCreatePanelCommand(sc.folder.Id, "Text - Library Panel2") command := getCreatePanelCommand(sc.folder.Id, "Text - Library Panel2")
resp := sc.service.createHandler(sc.reqContext, command) sc.reqContext.Req.Body = mockRequestBody(command)
resp := sc.service.createHandler(sc.reqContext)
require.Equal(t, 200, resp.Status()) require.Equal(t, 200, resp.Status())
err := sc.reqContext.Req.ParseForm() err := sc.reqContext.Req.ParseForm()
@@ -1182,7 +1199,8 @@ func TestGetAllLibraryElements(t *testing.T) {
scenarioWithPanel(t, "When an admin tries to get all library panels and two exist and perPage is 1 and page is 3 and searchString does not exist, it should succeed and the result should be correct", scenarioWithPanel(t, "When an admin tries to get all library panels and two exist and perPage is 1 and page is 3 and searchString does not exist, it should succeed and the result should be correct",
func(t *testing.T, sc scenarioContext) { func(t *testing.T, sc scenarioContext) {
command := getCreatePanelCommand(sc.folder.Id, "Text - Library Panel2") command := getCreatePanelCommand(sc.folder.Id, "Text - Library Panel2")
resp := sc.service.createHandler(sc.reqContext, command) sc.reqContext.Req.Body = mockRequestBody(command)
resp := sc.service.createHandler(sc.reqContext)
require.Equal(t, 200, resp.Status()) require.Equal(t, 200, resp.Status())
err := sc.reqContext.Req.ParseForm() err := sc.reqContext.Req.ParseForm()
@@ -14,9 +14,10 @@ import (
func TestPatchLibraryElement(t *testing.T) { func TestPatchLibraryElement(t *testing.T) {
scenarioWithPanel(t, "When an admin tries to patch a library panel that does not exist, it should fail", scenarioWithPanel(t, "When an admin tries to patch a library panel that does not exist, it should fail",
func(t *testing.T, sc scenarioContext) { func(t *testing.T, sc scenarioContext) {
cmd := patchLibraryElementCommand{Kind: int64(models.PanelElement)} cmd := patchLibraryElementCommand{Kind: int64(models.PanelElement), Version: 1}
sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": "unknown"}) sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": "unknown"})
resp := sc.service.patchHandler(sc.reqContext, cmd) sc.reqContext.Req.Body = mockRequestBody(cmd)
resp := sc.service.patchHandler(sc.reqContext)
require.Equal(t, 404, resp.Status()) require.Equal(t, 404, resp.Status())
}) })
@@ -39,7 +40,8 @@ func TestPatchLibraryElement(t *testing.T) {
Version: 1, Version: 1,
} }
sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID}) sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID})
resp := sc.service.patchHandler(sc.reqContext, cmd) sc.reqContext.Req.Body = mockRequestBody(cmd)
resp := sc.service.patchHandler(sc.reqContext)
require.Equal(t, 200, resp.Status()) require.Equal(t, 200, resp.Status())
var result = validateAndUnMarshalResponse(t, resp) var result = validateAndUnMarshalResponse(t, resp)
var expected = libraryElementResult{ var expected = libraryElementResult{
@@ -91,7 +93,8 @@ func TestPatchLibraryElement(t *testing.T) {
Version: 1, Version: 1,
} }
sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID}) sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID})
resp := sc.service.patchHandler(sc.reqContext, cmd) sc.reqContext.Req.Body = mockRequestBody(cmd)
resp := sc.service.patchHandler(sc.reqContext)
require.Equal(t, 200, resp.Status()) require.Equal(t, 200, resp.Status())
var result = validateAndUnMarshalResponse(t, resp) var result = validateAndUnMarshalResponse(t, resp)
sc.initialResult.Result.FolderID = newFolder.Id sc.initialResult.Result.FolderID = newFolder.Id
@@ -113,7 +116,8 @@ func TestPatchLibraryElement(t *testing.T) {
Version: 1, Version: 1,
} }
sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID}) sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID})
resp := sc.service.patchHandler(sc.reqContext, cmd) sc.ctx.Req.Body = mockRequestBody(cmd)
resp := sc.service.patchHandler(sc.reqContext)
var result = validateAndUnMarshalResponse(t, resp) var result = validateAndUnMarshalResponse(t, resp)
sc.initialResult.Result.Name = "New Name" sc.initialResult.Result.Name = "New Name"
sc.initialResult.Result.Meta.CreatedBy.Name = userInDbName sc.initialResult.Result.Meta.CreatedBy.Name = userInDbName
@@ -135,7 +139,8 @@ func TestPatchLibraryElement(t *testing.T) {
Version: 1, Version: 1,
} }
sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID}) sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID})
resp := sc.service.patchHandler(sc.reqContext, cmd) sc.ctx.Req.Body = mockRequestBody(cmd)
resp := sc.service.patchHandler(sc.reqContext)
var result = validateAndUnMarshalResponse(t, resp) var result = validateAndUnMarshalResponse(t, resp)
sc.initialResult.Result.UID = cmd.UID sc.initialResult.Result.UID = cmd.UID
sc.initialResult.Result.Meta.CreatedBy.Name = userInDbName sc.initialResult.Result.Meta.CreatedBy.Name = userInDbName
@@ -157,7 +162,8 @@ func TestPatchLibraryElement(t *testing.T) {
Version: 1, Version: 1,
} }
sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID}) sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID})
resp := sc.service.patchHandler(sc.reqContext, cmd) sc.ctx.Req.Body = mockRequestBody(cmd)
resp := sc.service.patchHandler(sc.reqContext)
require.Equal(t, 400, resp.Status()) require.Equal(t, 400, resp.Status())
}) })
@@ -170,7 +176,8 @@ func TestPatchLibraryElement(t *testing.T) {
Version: 1, Version: 1,
} }
sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID}) sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID})
resp := sc.service.patchHandler(sc.reqContext, cmd) sc.ctx.Req.Body = mockRequestBody(cmd)
resp := sc.service.patchHandler(sc.reqContext)
require.Equal(t, 400, resp.Status()) require.Equal(t, 400, resp.Status())
}) })
@@ -178,7 +185,8 @@ func TestPatchLibraryElement(t *testing.T) {
func(t *testing.T, sc scenarioContext) { func(t *testing.T, sc scenarioContext) {
command := getCreatePanelCommand(sc.folder.Id, "Existing UID") command := getCreatePanelCommand(sc.folder.Id, "Existing UID")
command.UID = util.GenerateShortUID() command.UID = util.GenerateShortUID()
resp := sc.service.createHandler(sc.reqContext, command) sc.reqContext.Req.Body = mockRequestBody(command)
resp := sc.service.createHandler(sc.reqContext)
require.Equal(t, 200, resp.Status()) require.Equal(t, 200, resp.Status())
cmd := patchLibraryElementCommand{ cmd := patchLibraryElementCommand{
FolderID: -1, FolderID: -1,
@@ -187,7 +195,8 @@ func TestPatchLibraryElement(t *testing.T) {
Version: 1, Version: 1,
} }
sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID}) sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID})
resp = sc.service.patchHandler(sc.reqContext, cmd) sc.ctx.Req.Body = mockRequestBody(cmd)
resp = sc.service.patchHandler(sc.reqContext)
require.Equal(t, 400, resp.Status()) require.Equal(t, 400, resp.Status())
}) })
@@ -200,7 +209,8 @@ func TestPatchLibraryElement(t *testing.T) {
Version: 1, Version: 1,
} }
sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID}) sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID})
resp := sc.service.patchHandler(sc.reqContext, cmd) sc.ctx.Req.Body = mockRequestBody(cmd)
resp := sc.service.patchHandler(sc.reqContext)
var result = validateAndUnMarshalResponse(t, resp) var result = validateAndUnMarshalResponse(t, resp)
sc.initialResult.Result.Type = "graph" sc.initialResult.Result.Type = "graph"
sc.initialResult.Result.Description = "New description" sc.initialResult.Result.Description = "New description"
@@ -228,7 +238,8 @@ func TestPatchLibraryElement(t *testing.T) {
Version: 1, Version: 1,
} }
sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID}) sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID})
resp := sc.service.patchHandler(sc.reqContext, cmd) sc.ctx.Req.Body = mockRequestBody(cmd)
resp := sc.service.patchHandler(sc.reqContext)
var result = validateAndUnMarshalResponse(t, resp) var result = validateAndUnMarshalResponse(t, resp)
sc.initialResult.Result.Type = "text" sc.initialResult.Result.Type = "text"
sc.initialResult.Result.Description = "New description" sc.initialResult.Result.Description = "New description"
@@ -254,7 +265,8 @@ func TestPatchLibraryElement(t *testing.T) {
Version: 1, Version: 1,
} }
sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID}) sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID})
resp := sc.service.patchHandler(sc.reqContext, cmd) sc.ctx.Req.Body = mockRequestBody(cmd)
resp := sc.service.patchHandler(sc.reqContext)
var result = validateAndUnMarshalResponse(t, resp) var result = validateAndUnMarshalResponse(t, resp)
sc.initialResult.Result.Type = "graph" sc.initialResult.Result.Type = "graph"
sc.initialResult.Result.Description = "A description" sc.initialResult.Result.Description = "A description"
@@ -276,7 +288,8 @@ func TestPatchLibraryElement(t *testing.T) {
cmd := patchLibraryElementCommand{FolderID: -1, Version: 1, Kind: int64(models.PanelElement)} cmd := patchLibraryElementCommand{FolderID: -1, Version: 1, Kind: int64(models.PanelElement)}
sc.reqContext.UserId = 2 sc.reqContext.UserId = 2
sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID}) sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID})
resp := sc.service.patchHandler(sc.reqContext, cmd) sc.ctx.Req.Body = mockRequestBody(cmd)
resp := sc.service.patchHandler(sc.reqContext)
var result = validateAndUnMarshalResponse(t, resp) var result = validateAndUnMarshalResponse(t, resp)
sc.initialResult.Result.Meta.UpdatedBy.ID = int64(2) sc.initialResult.Result.Meta.UpdatedBy.ID = int64(2)
sc.initialResult.Result.Meta.CreatedBy.Name = userInDbName sc.initialResult.Result.Meta.CreatedBy.Name = userInDbName
@@ -291,7 +304,8 @@ func TestPatchLibraryElement(t *testing.T) {
scenarioWithPanel(t, "When an admin tries to patch a library panel with a name that already exists, it should fail", scenarioWithPanel(t, "When an admin tries to patch a library panel with a name that already exists, it should fail",
func(t *testing.T, sc scenarioContext) { func(t *testing.T, sc scenarioContext) {
command := getCreatePanelCommand(sc.folder.Id, "Another Panel") command := getCreatePanelCommand(sc.folder.Id, "Another Panel")
resp := sc.service.createHandler(sc.reqContext, command) sc.ctx.Req.Body = mockRequestBody(command)
resp := sc.service.createHandler(sc.reqContext)
var result = validateAndUnMarshalResponse(t, resp) var result = validateAndUnMarshalResponse(t, resp)
cmd := patchLibraryElementCommand{ cmd := patchLibraryElementCommand{
Name: "Text - Library Panel", Name: "Text - Library Panel",
@@ -299,7 +313,8 @@ func TestPatchLibraryElement(t *testing.T) {
Kind: int64(models.PanelElement), Kind: int64(models.PanelElement),
} }
sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": result.Result.UID}) sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": result.Result.UID})
resp = sc.service.patchHandler(sc.reqContext, cmd) sc.ctx.Req.Body = mockRequestBody(cmd)
resp = sc.service.patchHandler(sc.reqContext)
require.Equal(t, 400, resp.Status()) require.Equal(t, 400, resp.Status())
}) })
@@ -307,7 +322,8 @@ func TestPatchLibraryElement(t *testing.T) {
func(t *testing.T, sc scenarioContext) { func(t *testing.T, sc scenarioContext) {
newFolder := createFolderWithACL(t, sc.sqlStore, "NewFolder", sc.user, []folderACLItem{}) newFolder := createFolderWithACL(t, sc.sqlStore, "NewFolder", sc.user, []folderACLItem{})
command := getCreatePanelCommand(newFolder.Id, "Text - Library Panel") command := getCreatePanelCommand(newFolder.Id, "Text - Library Panel")
resp := sc.service.createHandler(sc.reqContext, command) sc.ctx.Req.Body = mockRequestBody(command)
resp := sc.service.createHandler(sc.reqContext)
var result = validateAndUnMarshalResponse(t, resp) var result = validateAndUnMarshalResponse(t, resp)
cmd := patchLibraryElementCommand{ cmd := patchLibraryElementCommand{
FolderID: 1, FolderID: 1,
@@ -315,7 +331,8 @@ func TestPatchLibraryElement(t *testing.T) {
Kind: int64(models.PanelElement), Kind: int64(models.PanelElement),
} }
sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": result.Result.UID}) sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": result.Result.UID})
resp = sc.service.patchHandler(sc.reqContext, cmd) sc.ctx.Req.Body = mockRequestBody(cmd)
resp = sc.service.patchHandler(sc.reqContext)
require.Equal(t, 400, resp.Status()) require.Equal(t, 400, resp.Status())
}) })
@@ -328,7 +345,8 @@ func TestPatchLibraryElement(t *testing.T) {
} }
sc.reqContext.OrgId = 2 sc.reqContext.OrgId = 2
sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID}) sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID})
resp := sc.service.patchHandler(sc.reqContext, cmd) sc.ctx.Req.Body = mockRequestBody(cmd)
resp := sc.service.patchHandler(sc.reqContext)
require.Equal(t, 404, resp.Status()) require.Equal(t, 404, resp.Status())
}) })
@@ -340,9 +358,11 @@ func TestPatchLibraryElement(t *testing.T) {
Kind: int64(models.PanelElement), Kind: int64(models.PanelElement),
} }
sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID}) sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID})
resp := sc.service.patchHandler(sc.reqContext, cmd) sc.ctx.Req.Body = mockRequestBody(cmd)
resp := sc.service.patchHandler(sc.reqContext)
require.Equal(t, 200, resp.Status()) require.Equal(t, 200, resp.Status())
resp = sc.service.patchHandler(sc.reqContext, cmd) sc.ctx.Req.Body = mockRequestBody(cmd)
resp = sc.service.patchHandler(sc.reqContext)
require.Equal(t, 412, resp.Status()) require.Equal(t, 412, resp.Status())
}) })
@@ -354,7 +374,8 @@ func TestPatchLibraryElement(t *testing.T) {
Kind: int64(models.VariableElement), Kind: int64(models.VariableElement),
} }
sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID}) sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID})
resp := sc.service.patchHandler(sc.reqContext, cmd) sc.ctx.Req.Body = mockRequestBody(cmd)
resp := sc.service.patchHandler(sc.reqContext)
require.Equal(t, 200, resp.Status()) require.Equal(t, 200, resp.Status())
var result = validateAndUnMarshalResponse(t, resp) var result = validateAndUnMarshalResponse(t, resp)
sc.initialResult.Result.Type = "text" sc.initialResult.Result.Type = "text"
@@ -71,7 +71,8 @@ func TestLibraryElementPermissions(t *testing.T) {
sc.reqContext.SignedInUser.OrgRole = testCase.role sc.reqContext.SignedInUser.OrgRole = testCase.role
command := getCreatePanelCommand(folder.Id, "Library Panel Name") command := getCreatePanelCommand(folder.Id, "Library Panel Name")
resp := sc.service.createHandler(sc.reqContext, command) sc.reqContext.Req.Body = mockRequestBody(command)
resp := sc.service.createHandler(sc.reqContext)
require.Equal(t, testCase.status, resp.Status()) require.Equal(t, testCase.status, resp.Status())
}) })
@@ -79,14 +80,16 @@ func TestLibraryElementPermissions(t *testing.T) {
func(t *testing.T, sc scenarioContext) { func(t *testing.T, sc scenarioContext) {
fromFolder := createFolderWithACL(t, sc.sqlStore, "Everyone", sc.user, everyonePermissions) fromFolder := createFolderWithACL(t, sc.sqlStore, "Everyone", sc.user, everyonePermissions)
command := getCreatePanelCommand(fromFolder.Id, "Library Panel Name") command := getCreatePanelCommand(fromFolder.Id, "Library Panel Name")
resp := sc.service.createHandler(sc.reqContext, command) sc.reqContext.Req.Body = mockRequestBody(command)
resp := sc.service.createHandler(sc.reqContext)
result := validateAndUnMarshalResponse(t, resp) result := validateAndUnMarshalResponse(t, resp)
toFolder := createFolderWithACL(t, sc.sqlStore, "Folder", sc.user, testCase.items) toFolder := createFolderWithACL(t, sc.sqlStore, "Folder", sc.user, testCase.items)
sc.reqContext.SignedInUser.OrgRole = testCase.role sc.reqContext.SignedInUser.OrgRole = testCase.role
cmd := patchLibraryElementCommand{FolderID: toFolder.Id, Version: 1, Kind: int64(models.PanelElement)} cmd := patchLibraryElementCommand{FolderID: toFolder.Id, Version: 1, Kind: int64(models.PanelElement)}
sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": result.Result.UID}) sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": result.Result.UID})
resp = sc.service.patchHandler(sc.reqContext, cmd) sc.reqContext.Req.Body = mockRequestBody(cmd)
resp = sc.service.patchHandler(sc.reqContext)
require.Equal(t, testCase.status, resp.Status()) require.Equal(t, testCase.status, resp.Status())
}) })
@@ -94,14 +97,16 @@ func TestLibraryElementPermissions(t *testing.T) {
func(t *testing.T, sc scenarioContext) { func(t *testing.T, sc scenarioContext) {
fromFolder := createFolderWithACL(t, sc.sqlStore, "Everyone", sc.user, testCase.items) fromFolder := createFolderWithACL(t, sc.sqlStore, "Everyone", sc.user, testCase.items)
command := getCreatePanelCommand(fromFolder.Id, "Library Panel Name") command := getCreatePanelCommand(fromFolder.Id, "Library Panel Name")
resp := sc.service.createHandler(sc.reqContext, command) sc.reqContext.Req.Body = mockRequestBody(command)
resp := sc.service.createHandler(sc.reqContext)
result := validateAndUnMarshalResponse(t, resp) result := validateAndUnMarshalResponse(t, resp)
toFolder := createFolderWithACL(t, sc.sqlStore, "Folder", sc.user, everyonePermissions) toFolder := createFolderWithACL(t, sc.sqlStore, "Folder", sc.user, everyonePermissions)
sc.reqContext.SignedInUser.OrgRole = testCase.role sc.reqContext.SignedInUser.OrgRole = testCase.role
cmd := patchLibraryElementCommand{FolderID: toFolder.Id, Version: 1, Kind: int64(models.PanelElement)} cmd := patchLibraryElementCommand{FolderID: toFolder.Id, Version: 1, Kind: int64(models.PanelElement)}
sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": result.Result.UID}) sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": result.Result.UID})
resp = sc.service.patchHandler(sc.reqContext, cmd) sc.reqContext.Req.Body = mockRequestBody(cmd)
resp = sc.service.patchHandler(sc.reqContext)
require.Equal(t, testCase.status, resp.Status()) require.Equal(t, testCase.status, resp.Status())
}) })
@@ -109,7 +114,8 @@ func TestLibraryElementPermissions(t *testing.T) {
func(t *testing.T, sc scenarioContext) { func(t *testing.T, sc scenarioContext) {
folder := createFolderWithACL(t, sc.sqlStore, "Folder", sc.user, testCase.items) folder := createFolderWithACL(t, sc.sqlStore, "Folder", sc.user, testCase.items)
cmd := getCreatePanelCommand(folder.Id, "Library Panel Name") cmd := getCreatePanelCommand(folder.Id, "Library Panel Name")
resp := sc.service.createHandler(sc.reqContext, cmd) sc.reqContext.Req.Body = mockRequestBody(cmd)
resp := sc.service.createHandler(sc.reqContext)
result := validateAndUnMarshalResponse(t, resp) result := validateAndUnMarshalResponse(t, resp)
sc.reqContext.SignedInUser.OrgRole = testCase.role sc.reqContext.SignedInUser.OrgRole = testCase.role
@@ -134,7 +140,8 @@ func TestLibraryElementPermissions(t *testing.T) {
sc.reqContext.SignedInUser.OrgRole = testCase.role sc.reqContext.SignedInUser.OrgRole = testCase.role
command := getCreatePanelCommand(0, "Library Panel Name") command := getCreatePanelCommand(0, "Library Panel Name")
resp := sc.service.createHandler(sc.reqContext, command) sc.reqContext.Req.Body = mockRequestBody(command)
resp := sc.service.createHandler(sc.reqContext)
require.Equal(t, testCase.status, resp.Status()) require.Equal(t, testCase.status, resp.Status())
}) })
@@ -142,13 +149,15 @@ func TestLibraryElementPermissions(t *testing.T) {
func(t *testing.T, sc scenarioContext) { func(t *testing.T, sc scenarioContext) {
folder := createFolderWithACL(t, sc.sqlStore, "Folder", sc.user, everyonePermissions) folder := createFolderWithACL(t, sc.sqlStore, "Folder", sc.user, everyonePermissions)
command := getCreatePanelCommand(folder.Id, "Library Panel Name") command := getCreatePanelCommand(folder.Id, "Library Panel Name")
resp := sc.service.createHandler(sc.reqContext, command) sc.reqContext.Req.Body = mockRequestBody(command)
resp := sc.service.createHandler(sc.reqContext)
result := validateAndUnMarshalResponse(t, resp) result := validateAndUnMarshalResponse(t, resp)
sc.reqContext.SignedInUser.OrgRole = testCase.role sc.reqContext.SignedInUser.OrgRole = testCase.role
cmd := patchLibraryElementCommand{FolderID: 0, Version: 1, Kind: int64(models.PanelElement)} cmd := patchLibraryElementCommand{FolderID: 0, Version: 1, Kind: int64(models.PanelElement)}
sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": result.Result.UID}) sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": result.Result.UID})
resp = sc.service.patchHandler(sc.reqContext, cmd) sc.ctx.Req.Body = mockRequestBody(cmd)
resp = sc.service.patchHandler(sc.reqContext)
require.Equal(t, testCase.status, resp.Status()) require.Equal(t, testCase.status, resp.Status())
}) })
@@ -156,20 +165,23 @@ func TestLibraryElementPermissions(t *testing.T) {
func(t *testing.T, sc scenarioContext) { func(t *testing.T, sc scenarioContext) {
folder := createFolderWithACL(t, sc.sqlStore, "Folder", sc.user, everyonePermissions) folder := createFolderWithACL(t, sc.sqlStore, "Folder", sc.user, everyonePermissions)
command := getCreatePanelCommand(0, "Library Panel Name") command := getCreatePanelCommand(0, "Library Panel Name")
resp := sc.service.createHandler(sc.reqContext, command) sc.reqContext.Req.Body = mockRequestBody(command)
resp := sc.service.createHandler(sc.reqContext)
result := validateAndUnMarshalResponse(t, resp) result := validateAndUnMarshalResponse(t, resp)
sc.reqContext.SignedInUser.OrgRole = testCase.role sc.reqContext.SignedInUser.OrgRole = testCase.role
cmd := patchLibraryElementCommand{FolderID: folder.Id, Version: 1, Kind: int64(models.PanelElement)} cmd := patchLibraryElementCommand{FolderID: folder.Id, Version: 1, Kind: int64(models.PanelElement)}
sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": result.Result.UID}) sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": result.Result.UID})
resp = sc.service.patchHandler(sc.reqContext, cmd) sc.ctx.Req.Body = mockRequestBody(cmd)
resp = sc.service.patchHandler(sc.reqContext)
require.Equal(t, testCase.status, resp.Status()) require.Equal(t, testCase.status, resp.Status())
}) })
testScenario(t, fmt.Sprintf("When %s tries to delete a library panel in the General folder, it should return correct status", testCase.role), testScenario(t, fmt.Sprintf("When %s tries to delete a library panel in the General folder, it should return correct status", testCase.role),
func(t *testing.T, sc scenarioContext) { func(t *testing.T, sc scenarioContext) {
cmd := getCreatePanelCommand(0, "Library Panel Name") cmd := getCreatePanelCommand(0, "Library Panel Name")
resp := sc.service.createHandler(sc.reqContext, cmd) sc.reqContext.Req.Body = mockRequestBody(cmd)
resp := sc.service.createHandler(sc.reqContext)
result := validateAndUnMarshalResponse(t, resp) result := validateAndUnMarshalResponse(t, resp)
sc.reqContext.SignedInUser.OrgRole = testCase.role sc.reqContext.SignedInUser.OrgRole = testCase.role
@@ -193,7 +205,8 @@ func TestLibraryElementPermissions(t *testing.T) {
sc.reqContext.SignedInUser.OrgRole = testCase.role sc.reqContext.SignedInUser.OrgRole = testCase.role
command := getCreatePanelCommand(-100, "Library Panel Name") command := getCreatePanelCommand(-100, "Library Panel Name")
resp := sc.service.createHandler(sc.reqContext, command) sc.reqContext.Req.Body = mockRequestBody(command)
resp := sc.service.createHandler(sc.reqContext)
require.Equal(t, 404, resp.Status()) require.Equal(t, 404, resp.Status())
}) })
@@ -201,13 +214,15 @@ func TestLibraryElementPermissions(t *testing.T) {
func(t *testing.T, sc scenarioContext) { func(t *testing.T, sc scenarioContext) {
folder := createFolderWithACL(t, sc.sqlStore, "Folder", sc.user, everyonePermissions) folder := createFolderWithACL(t, sc.sqlStore, "Folder", sc.user, everyonePermissions)
command := getCreatePanelCommand(folder.Id, "Library Panel Name") command := getCreatePanelCommand(folder.Id, "Library Panel Name")
resp := sc.service.createHandler(sc.reqContext, command) sc.reqContext.Req.Body = mockRequestBody(command)
resp := sc.service.createHandler(sc.reqContext)
result := validateAndUnMarshalResponse(t, resp) result := validateAndUnMarshalResponse(t, resp)
sc.reqContext.SignedInUser.OrgRole = testCase.role sc.reqContext.SignedInUser.OrgRole = testCase.role
cmd := patchLibraryElementCommand{FolderID: -100, Version: 1, Kind: int64(models.PanelElement)} cmd := patchLibraryElementCommand{FolderID: -100, Version: 1, Kind: int64(models.PanelElement)}
sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": result.Result.UID}) sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": result.Result.UID})
resp = sc.service.patchHandler(sc.reqContext, cmd) sc.reqContext.Req.Body = mockRequestBody(cmd)
resp = sc.service.patchHandler(sc.reqContext)
require.Equal(t, 404, resp.Status()) require.Equal(t, 404, resp.Status())
}) })
} }
@@ -228,7 +243,8 @@ func TestLibraryElementPermissions(t *testing.T) {
for i, folderCase := range folderCases { for i, folderCase := range folderCases {
folder := createFolderWithACL(t, sc.sqlStore, fmt.Sprintf("Folder%v", i), sc.user, folderCase) folder := createFolderWithACL(t, sc.sqlStore, fmt.Sprintf("Folder%v", i), sc.user, folderCase)
cmd := getCreatePanelCommand(folder.Id, fmt.Sprintf("Library Panel in Folder%v", i)) cmd := getCreatePanelCommand(folder.Id, fmt.Sprintf("Library Panel in Folder%v", i))
resp := sc.service.createHandler(sc.reqContext, cmd) sc.reqContext.Req.Body = mockRequestBody(cmd)
resp := sc.service.createHandler(sc.reqContext)
result := validateAndUnMarshalResponse(t, resp) result := validateAndUnMarshalResponse(t, resp)
result.Result.Meta.CreatedBy.Name = userInDbName result.Result.Meta.CreatedBy.Name = userInDbName
result.Result.Meta.CreatedBy.AvatarURL = userInDbAvatar result.Result.Meta.CreatedBy.AvatarURL = userInDbAvatar
@@ -250,7 +266,8 @@ func TestLibraryElementPermissions(t *testing.T) {
testScenario(t, fmt.Sprintf("When %s tries to get a library panel from General folder, it should return correct response", testCase.role), testScenario(t, fmt.Sprintf("When %s tries to get a library panel from General folder, it should return correct response", testCase.role),
func(t *testing.T, sc scenarioContext) { func(t *testing.T, sc scenarioContext) {
cmd := getCreatePanelCommand(0, "Library Panel in General Folder") cmd := getCreatePanelCommand(0, "Library Panel in General Folder")
resp := sc.service.createHandler(sc.reqContext, cmd) sc.reqContext.Req.Body = mockRequestBody(cmd)
resp := sc.service.createHandler(sc.reqContext)
result := validateAndUnMarshalResponse(t, resp) result := validateAndUnMarshalResponse(t, resp)
result.Result.Meta.CreatedBy.Name = userInDbName result.Result.Meta.CreatedBy.Name = userInDbName
result.Result.Meta.CreatedBy.AvatarURL = userInDbAvatar result.Result.Meta.CreatedBy.AvatarURL = userInDbAvatar
@@ -289,7 +306,8 @@ func TestLibraryElementPermissions(t *testing.T) {
for i, folderCase := range folderCases { for i, folderCase := range folderCases {
folder := createFolderWithACL(t, sc.sqlStore, fmt.Sprintf("Folder%v", i), sc.user, folderCase) folder := createFolderWithACL(t, sc.sqlStore, fmt.Sprintf("Folder%v", i), sc.user, folderCase)
cmd := getCreatePanelCommand(folder.Id, fmt.Sprintf("Library Panel in Folder%v", i)) cmd := getCreatePanelCommand(folder.Id, fmt.Sprintf("Library Panel in Folder%v", i))
resp := sc.service.createHandler(sc.reqContext, cmd) sc.reqContext.Req.Body = mockRequestBody(cmd)
resp := sc.service.createHandler(sc.reqContext)
result := validateAndUnMarshalResponse(t, resp) result := validateAndUnMarshalResponse(t, resp)
result.Result.Meta.CreatedBy.Name = userInDbName result.Result.Meta.CreatedBy.Name = userInDbName
result.Result.Meta.CreatedBy.AvatarURL = userInDbAvatar result.Result.Meta.CreatedBy.AvatarURL = userInDbAvatar
@@ -340,7 +358,8 @@ func TestLibraryElementPermissions(t *testing.T) {
testScenario(t, fmt.Sprintf("When %s tries to get all library panels from General folder, it should return correct response", testCase.role), testScenario(t, fmt.Sprintf("When %s tries to get all library panels from General folder, it should return correct response", testCase.role),
func(t *testing.T, sc scenarioContext) { func(t *testing.T, sc scenarioContext) {
cmd := getCreatePanelCommand(0, "Library Panel in General Folder") cmd := getCreatePanelCommand(0, "Library Panel in General Folder")
resp := sc.service.createHandler(sc.reqContext, cmd) sc.reqContext.Req.Body = mockRequestBody(cmd)
resp := sc.service.createHandler(sc.reqContext)
result := validateAndUnMarshalResponse(t, resp) result := validateAndUnMarshalResponse(t, resp)
result.Result.Meta.CreatedBy.Name = userInDbName result.Result.Meta.CreatedBy.Name = userInDbName
result.Result.Meta.CreatedBy.AvatarURL = userInDbAvatar result.Result.Meta.CreatedBy.AvatarURL = userInDbAvatar
@@ -1,8 +1,10 @@
package libraryelements package libraryelements
import ( import (
"bytes"
"context" "context"
"encoding/json" "encoding/json"
"io"
"net/http" "net/http"
"testing" "testing"
"time" "time"
@@ -68,7 +70,8 @@ func TestDeleteLibraryPanelsInFolder(t *testing.T) {
scenarioWithPanel(t, "When an admin tries to delete a folder that contains disconnected elements, it should delete all disconnected elements too", scenarioWithPanel(t, "When an admin tries to delete a folder that contains disconnected elements, it should delete all disconnected elements too",
func(t *testing.T, sc scenarioContext) { func(t *testing.T, sc scenarioContext) {
command := getCreateVariableCommand(sc.folder.Id, "query0") command := getCreateVariableCommand(sc.folder.Id, "query0")
resp := sc.service.createHandler(sc.reqContext, command) sc.reqContext.Req.Body = mockRequestBody(command)
resp := sc.service.createHandler(sc.reqContext)
require.Equal(t, 200, resp.Status()) require.Equal(t, 200, resp.Status())
resp = sc.service.getAllHandler(sc.reqContext) resp = sc.service.getAllHandler(sc.reqContext)
@@ -266,7 +269,8 @@ func scenarioWithPanel(t *testing.T, desc string, fn func(t *testing.T, sc scena
testScenario(t, desc, func(t *testing.T, sc scenarioContext) { testScenario(t, desc, func(t *testing.T, sc scenarioContext) {
command := getCreatePanelCommand(sc.folder.Id, "Text - Library Panel") command := getCreatePanelCommand(sc.folder.Id, "Text - Library Panel")
resp := sc.service.createHandler(sc.reqContext, command) sc.reqContext.Req.Body = mockRequestBody(command)
resp := sc.service.createHandler(sc.reqContext)
sc.initialResult = validateAndUnMarshalResponse(t, resp) sc.initialResult = validateAndUnMarshalResponse(t, resp)
fn(t, sc) fn(t, sc)
@@ -333,3 +337,8 @@ func getCompareOptions() []cmp.Option {
}), }),
} }
} }
func mockRequestBody(v interface{}) io.ReadCloser {
b, _ := json.Marshal(v)
return io.NopCloser(bytes.NewReader(b))
}
+1 -1
View File
@@ -170,7 +170,7 @@ type CreateLibraryElementCommand struct {
type patchLibraryElementCommand struct { type patchLibraryElementCommand struct {
FolderID int64 `json:"folderId" binding:"Default(-1)"` FolderID int64 `json:"folderId" binding:"Default(-1)"`
Name string `json:"name"` Name string `json:"name"`
Model json.RawMessage `json:"model"` Model json.RawMessage `json:"model,omitempty"`
Kind int64 `json:"kind" binding:"Required"` Kind int64 `json:"kind" binding:"Required"`
Version int64 `json:"version" binding:"Required"` Version int64 `json:"version" binding:"Required"`
UID string `json:"uid"` UID string `json:"uid"`
+5 -1
View File
@@ -893,7 +893,11 @@ func (g *GrafanaLive) ClientCount(orgID int64, channel string) (int, error) {
return len(p.Presence), nil return len(p.Presence), nil
} }
func (g *GrafanaLive) HandleHTTPPublish(ctx *models.ReqContext, cmd dtos.LivePublishCmd) response.Response { func (g *GrafanaLive) HandleHTTPPublish(ctx *models.ReqContext) response.Response {
cmd := dtos.LivePublishCmd{}
if err := web.Bind(ctx.Req, &cmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
addr, err := live.ParseChannel(cmd.Channel) addr, err := live.ParseChannel(cmd.Channel)
if err != nil { if err != nil {
return response.Error(http.StatusBadRequest, "invalid channel ID", nil) return response.Error(http.StatusBadRequest, "invalid channel ID", nil)