From 3d41267fc4fc94c1a4630b4ecf6e0c149d250837 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=A4ggmark?= Date: Fri, 15 Jan 2021 14:43:20 +0100 Subject: [PATCH] Chore: Moves common and response into separate packages (#30298) * Chore: moves common and response into separate packages * Chore: moves common and response into separate packages * Update pkg/api/utils/common.go Co-authored-by: Arve Knudsen * Chore: changes after PR comments * Chore: move wrap to routing package * Chore: move functions in common to response package * Chore: move functions in common to response package * Chore: formats imports Co-authored-by: Arve Knudsen --- pkg/api/admin.go | 11 +- pkg/api/admin_provisioning.go | 25 +- pkg/api/admin_users.go | 73 +++--- pkg/api/admin_users_test.go | 16 +- pkg/api/alerting.go | 163 ++++++------ pkg/api/alerting_test.go | 5 +- pkg/api/annotations.go | 57 ++--- pkg/api/annotations_test.go | 10 +- pkg/api/api.go | 360 +++++++++++++-------------- pkg/api/apikey.go | 31 +-- pkg/api/common.go | 109 -------- pkg/api/common_test.go | 8 +- pkg/api/dashboard.go | 103 ++++---- pkg/api/dashboard_permission.go | 25 +- pkg/api/dashboard_permission_test.go | 4 +- pkg/api/dashboard_snapshot.go | 45 ++-- pkg/api/dashboard_test.go | 12 +- pkg/api/datasources.go | 123 ++++----- pkg/api/datasources_test.go | 10 +- pkg/api/folder.go | 39 +-- pkg/api/folder_permission.go | 25 +- pkg/api/folder_permission_test.go | 4 +- pkg/api/folder_test.go | 6 +- pkg/api/frontend_logging.go | 5 +- pkg/api/frontend_logging_test.go | 4 +- pkg/api/ldap_debug.go | 65 ++--- pkg/api/ldap_debug_test.go | 8 +- pkg/api/login.go | 45 ++-- pkg/api/login_test.go | 16 +- pkg/api/metrics.go | 55 ++-- pkg/api/org.go | 67 ++--- pkg/api/org_invite.go | 81 +++--- pkg/api/org_users.go | 67 ++--- pkg/api/password.go | 27 +- pkg/api/playlist.go | 45 ++-- pkg/api/plugins.go | 85 +++---- pkg/api/preferences.go | 27 +- pkg/api/quota.go | 37 +-- pkg/api/{ => response}/response.go | 122 ++++++++- pkg/api/routing/routing.go | 27 ++ pkg/api/search.go | 13 +- pkg/api/short_url.go | 9 +- pkg/api/signup.go | 43 ++-- pkg/api/stars.go | 19 +- pkg/api/team.go | 53 ++-- pkg/api/team_members.go | 41 +-- pkg/api/user.go | 115 ++++----- pkg/api/user_token.go | 43 ++-- pkg/api/user_token_test.go | 12 +- pkg/services/librarypanels/api.go | 84 +++---- pkg/services/ngalert/api.go | 90 +++---- 51 files changed, 1321 insertions(+), 1248 deletions(-) delete mode 100644 pkg/api/common.go rename pkg/api/{ => response}/response.go (50%) create mode 100644 pkg/api/routing/routing.go diff --git a/pkg/api/admin.go b/pkg/api/admin.go index 003b9981a49..c7f06ecf112 100644 --- a/pkg/api/admin.go +++ b/pkg/api/admin.go @@ -4,12 +4,13 @@ import ( "regexp" "strings" + "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/setting" ) -func AdminGetSettings(c *models.ReqContext) Response { +func AdminGetSettings(c *models.ReqContext) response.Response { settings := make(map[string]interface{}) for _, section := range setting.Raw.Sections() { @@ -35,15 +36,15 @@ func AdminGetSettings(c *models.ReqContext) Response { } } - return JSON(200, settings) + return response.JSON(200, settings) } -func AdminGetStats(c *models.ReqContext) Response { +func AdminGetStats(c *models.ReqContext) response.Response { statsQuery := models.GetAdminStatsQuery{} if err := bus.Dispatch(&statsQuery); err != nil { - return Error(500, "Failed to get admin stats from database", err) + return response.Error(500, "Failed to get admin stats from database", err) } - return JSON(200, statsQuery.Result) + return response.JSON(200, statsQuery.Result) } diff --git a/pkg/api/admin_provisioning.go b/pkg/api/admin_provisioning.go index e902a2b3477..e9cd437217a 100644 --- a/pkg/api/admin_provisioning.go +++ b/pkg/api/admin_provisioning.go @@ -4,37 +4,38 @@ import ( "context" "errors" + "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/models" ) -func (hs *HTTPServer) AdminProvisioningReloadDashboards(c *models.ReqContext) Response { +func (hs *HTTPServer) AdminProvisioningReloadDashboards(c *models.ReqContext) response.Response { err := hs.ProvisioningService.ProvisionDashboards() if err != nil && !errors.Is(err, context.Canceled) { - return Error(500, "", err) + return response.Error(500, "", err) } - return Success("Dashboards config reloaded") + return response.Success("Dashboards config reloaded") } -func (hs *HTTPServer) AdminProvisioningReloadDatasources(c *models.ReqContext) Response { +func (hs *HTTPServer) AdminProvisioningReloadDatasources(c *models.ReqContext) response.Response { err := hs.ProvisioningService.ProvisionDatasources() if err != nil { - return Error(500, "", err) + return response.Error(500, "", err) } - return Success("Datasources config reloaded") + return response.Success("Datasources config reloaded") } -func (hs *HTTPServer) AdminProvisioningReloadPlugins(c *models.ReqContext) Response { +func (hs *HTTPServer) AdminProvisioningReloadPlugins(c *models.ReqContext) response.Response { err := hs.ProvisioningService.ProvisionPlugins() if err != nil { - return Error(500, "Failed to reload plugins config", err) + return response.Error(500, "Failed to reload plugins config", err) } - return Success("Plugins config reloaded") + return response.Success("Plugins config reloaded") } -func (hs *HTTPServer) AdminProvisioningReloadNotifications(c *models.ReqContext) Response { +func (hs *HTTPServer) AdminProvisioningReloadNotifications(c *models.ReqContext) response.Response { err := hs.ProvisioningService.ProvisionNotifications() if err != nil { - return Error(500, "", err) + return response.Error(500, "", err) } - return Success("Notifications config reloaded") + return response.Success("Notifications config reloaded") } diff --git a/pkg/api/admin_users.go b/pkg/api/admin_users.go index 08f36d09010..0da29417751 100644 --- a/pkg/api/admin_users.go +++ b/pkg/api/admin_users.go @@ -5,13 +5,14 @@ import ( "fmt" "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/infra/metrics" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/util" ) -func AdminCreateUser(c *models.ReqContext, form dtos.AdminCreateUserForm) Response { +func AdminCreateUser(c *models.ReqContext, form dtos.AdminCreateUserForm) response.Response { cmd := models.CreateUserCommand{ Login: form.Login, Email: form.Email, @@ -23,24 +24,24 @@ func AdminCreateUser(c *models.ReqContext, form dtos.AdminCreateUserForm) Respon if len(cmd.Login) == 0 { cmd.Login = cmd.Email if len(cmd.Login) == 0 { - return Error(400, "Validation error, need specify either username or email", nil) + return response.Error(400, "Validation error, need specify either username or email", nil) } } if len(cmd.Password) < 4 { - return Error(400, "Password is missing or too short", nil) + return response.Error(400, "Password is missing or too short", nil) } if err := bus.Dispatch(&cmd); err != nil { if errors.Is(err, models.ErrOrgNotFound) { - return Error(400, err.Error(), nil) + return response.Error(400, err.Error(), nil) } if errors.Is(err, models.ErrUserAlreadyExists) { - return Error(412, fmt.Sprintf("User with email '%s' or username '%s' already exists", form.Email, form.Login), err) + return response.Error(412, fmt.Sprintf("User with email '%s' or username '%s' already exists", form.Email, form.Login), err) } - return Error(500, "failed to create user", err) + return response.Error(500, "failed to create user", err) } metrics.MApiAdminUserCreate.Inc() @@ -52,25 +53,25 @@ func AdminCreateUser(c *models.ReqContext, form dtos.AdminCreateUserForm) Respon Id: user.Id, } - return JSON(200, result) + return response.JSON(200, result) } -func AdminUpdateUserPassword(c *models.ReqContext, form dtos.AdminUpdateUserPasswordForm) Response { +func AdminUpdateUserPassword(c *models.ReqContext, form dtos.AdminUpdateUserPasswordForm) response.Response { userID := c.ParamsInt64(":id") if len(form.Password) < 4 { - return Error(400, "New password too short", nil) + return response.Error(400, "New password too short", nil) } userQuery := models.GetUserByIdQuery{Id: userID} if err := bus.Dispatch(&userQuery); err != nil { - return Error(500, "Could not read user from database", err) + return response.Error(500, "Could not read user from database", err) } passwordHashed, err := util.EncodePassword(form.Password, userQuery.Result.Salt) if err != nil { - return Error(500, "Could not encode password", err) + return response.Error(500, "Could not encode password", err) } cmd := models.ChangeUserPasswordCommand{ @@ -79,14 +80,14 @@ func AdminUpdateUserPassword(c *models.ReqContext, form dtos.AdminUpdateUserPass } if err := bus.Dispatch(&cmd); err != nil { - return Error(500, "Failed to update user password", err) + return response.Error(500, "Failed to update user password", err) } - return Success("User password updated") + return response.Success("User password updated") } // PUT /api/admin/users/:id/permissions -func AdminUpdateUserPermissions(c *models.ReqContext, form dtos.AdminUpdateUserPermissionsForm) Response { +func AdminUpdateUserPermissions(c *models.ReqContext, form dtos.AdminUpdateUserPermissionsForm) response.Response { userID := c.ParamsInt64(":id") cmd := models.UpdateUserPermissionsCommand{ @@ -96,96 +97,96 @@ func AdminUpdateUserPermissions(c *models.ReqContext, form dtos.AdminUpdateUserP if err := bus.Dispatch(&cmd); err != nil { if errors.Is(err, models.ErrLastGrafanaAdmin) { - return Error(400, models.ErrLastGrafanaAdmin.Error(), nil) + return response.Error(400, models.ErrLastGrafanaAdmin.Error(), nil) } - return Error(500, "Failed to update user permissions", err) + return response.Error(500, "Failed to update user permissions", err) } - return Success("User permissions updated") + return response.Success("User permissions updated") } -func AdminDeleteUser(c *models.ReqContext) Response { +func AdminDeleteUser(c *models.ReqContext) response.Response { userID := c.ParamsInt64(":id") cmd := models.DeleteUserCommand{UserId: userID} if err := bus.Dispatch(&cmd); err != nil { if errors.Is(err, models.ErrUserNotFound) { - return Error(404, models.ErrUserNotFound.Error(), nil) + return response.Error(404, models.ErrUserNotFound.Error(), nil) } - return Error(500, "Failed to delete user", err) + return response.Error(500, "Failed to delete user", err) } - return Success("User deleted") + return response.Success("User deleted") } // POST /api/admin/users/:id/disable -func (hs *HTTPServer) AdminDisableUser(c *models.ReqContext) Response { +func (hs *HTTPServer) AdminDisableUser(c *models.ReqContext) response.Response { userID := c.ParamsInt64(":id") // External users shouldn't be disabled from API authInfoQuery := &models.GetAuthInfoQuery{UserId: userID} if err := bus.Dispatch(authInfoQuery); !errors.Is(err, models.ErrUserNotFound) { - return Error(500, "Could not disable external user", nil) + return response.Error(500, "Could not disable external user", nil) } disableCmd := models.DisableUserCommand{UserId: userID, IsDisabled: true} if err := bus.Dispatch(&disableCmd); err != nil { if errors.Is(err, models.ErrUserNotFound) { - return Error(404, models.ErrUserNotFound.Error(), nil) + return response.Error(404, models.ErrUserNotFound.Error(), nil) } - return Error(500, "Failed to disable user", err) + return response.Error(500, "Failed to disable user", err) } err := hs.AuthTokenService.RevokeAllUserTokens(c.Req.Context(), userID) if err != nil { - return Error(500, "Failed to disable user", err) + return response.Error(500, "Failed to disable user", err) } - return Success("User disabled") + return response.Success("User disabled") } // POST /api/admin/users/:id/enable -func AdminEnableUser(c *models.ReqContext) Response { +func AdminEnableUser(c *models.ReqContext) response.Response { userID := c.ParamsInt64(":id") // External users shouldn't be disabled from API authInfoQuery := &models.GetAuthInfoQuery{UserId: userID} if err := bus.Dispatch(authInfoQuery); !errors.Is(err, models.ErrUserNotFound) { - return Error(500, "Could not enable external user", nil) + return response.Error(500, "Could not enable external user", nil) } disableCmd := models.DisableUserCommand{UserId: userID, IsDisabled: false} if err := bus.Dispatch(&disableCmd); err != nil { if errors.Is(err, models.ErrUserNotFound) { - return Error(404, models.ErrUserNotFound.Error(), nil) + return response.Error(404, models.ErrUserNotFound.Error(), nil) } - return Error(500, "Failed to enable user", err) + return response.Error(500, "Failed to enable user", err) } - return Success("User enabled") + return response.Success("User enabled") } // POST /api/admin/users/:id/logout -func (hs *HTTPServer) AdminLogoutUser(c *models.ReqContext) Response { +func (hs *HTTPServer) AdminLogoutUser(c *models.ReqContext) response.Response { userID := c.ParamsInt64(":id") if c.UserId == userID { - return Error(400, "You cannot logout yourself", nil) + return response.Error(400, "You cannot logout yourself", nil) } return hs.logoutUserFromAllDevicesInternal(c.Req.Context(), userID) } // GET /api/admin/users/:id/auth-tokens -func (hs *HTTPServer) AdminGetUserAuthTokens(c *models.ReqContext) Response { +func (hs *HTTPServer) AdminGetUserAuthTokens(c *models.ReqContext) response.Response { userID := c.ParamsInt64(":id") return hs.getUserAuthTokensInternal(c, userID) } // POST /api/admin/users/:id/revoke-auth-token -func (hs *HTTPServer) AdminRevokeUserAuthToken(c *models.ReqContext, cmd models.RevokeAuthTokenCmd) Response { +func (hs *HTTPServer) AdminRevokeUserAuthToken(c *models.ReqContext, cmd models.RevokeAuthTokenCmd) response.Response { userID := c.ParamsInt64(":id") return hs.revokeUserAuthTokenInternal(c, userID, cmd) } diff --git a/pkg/api/admin_users_test.go b/pkg/api/admin_users_test.go index e58e6186086..3f229454edf 100644 --- a/pkg/api/admin_users_test.go +++ b/pkg/api/admin_users_test.go @@ -5,6 +5,8 @@ import ( "testing" "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/api/response" + "github.com/grafana/grafana/pkg/api/routing" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/models" @@ -355,7 +357,7 @@ func putAdminScenario(t *testing.T, desc string, url string, routePattern string t.Cleanup(bus.ClearBusHandlers) sc := setupScenarioContext(t, url) - sc.defaultHandler = Wrap(func(c *models.ReqContext) Response { + sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.context = c sc.context.UserId = testUserID sc.context.OrgId = testOrgID @@ -380,7 +382,7 @@ func adminLogoutUserScenario(t *testing.T, desc string, url string, routePattern } sc := setupScenarioContext(t, url) - sc.defaultHandler = Wrap(func(c *models.ReqContext) Response { + sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { t.Log("Route handler invoked", "url", c.Req.URL) sc.context = c @@ -410,7 +412,7 @@ func adminRevokeUserAuthTokenScenario(t *testing.T, desc string, url string, rou sc := setupScenarioContext(t, url) sc.userAuthTokenService = fakeAuthTokenService - sc.defaultHandler = Wrap(func(c *models.ReqContext) Response { + sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.context = c sc.context.UserId = testUserID sc.context.OrgId = testOrgID @@ -438,7 +440,7 @@ func adminGetUserAuthTokensScenario(t *testing.T, desc string, url string, route sc := setupScenarioContext(t, url) sc.userAuthTokenService = fakeAuthTokenService - sc.defaultHandler = Wrap(func(c *models.ReqContext) Response { + sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.context = c sc.context.UserId = testUserID sc.context.OrgId = testOrgID @@ -465,7 +467,7 @@ func adminDisableUserScenario(t *testing.T, desc string, action string, url stri } sc := setupScenarioContext(t, url) - sc.defaultHandler = Wrap(func(c *models.ReqContext) Response { + sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.context = c sc.context.UserId = testUserID @@ -487,7 +489,7 @@ func adminDeleteUserScenario(t *testing.T, desc string, url string, routePattern t.Cleanup(bus.ClearBusHandlers) sc := setupScenarioContext(t, url) - sc.defaultHandler = Wrap(func(c *models.ReqContext) Response { + sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.context = c sc.context.UserId = testUserID @@ -505,7 +507,7 @@ func adminCreateUserScenario(t *testing.T, desc string, url string, routePattern t.Cleanup(bus.ClearBusHandlers) sc := setupScenarioContext(t, url) - sc.defaultHandler = Wrap(func(c *models.ReqContext) Response { + sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.context = c sc.context.UserId = testUserID diff --git a/pkg/api/alerting.go b/pkg/api/alerting.go index 155534d41d5..32a6d031940 100644 --- a/pkg/api/alerting.go +++ b/pkg/api/alerting.go @@ -6,6 +6,7 @@ import ( "strconv" "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/alerting" @@ -29,11 +30,11 @@ func ValidateOrgAlert(c *models.ReqContext) { } } -func GetAlertStatesForDashboard(c *models.ReqContext) Response { +func GetAlertStatesForDashboard(c *models.ReqContext) response.Response { dashboardID := c.QueryInt64("dashboardId") if dashboardID == 0 { - return Error(400, "Missing query parameter dashboardId", nil) + return response.Error(400, "Missing query parameter dashboardId", nil) } query := models.GetAlertStatesForDashboardQuery{ @@ -42,14 +43,14 @@ func GetAlertStatesForDashboard(c *models.ReqContext) Response { } if err := bus.Dispatch(&query); err != nil { - return Error(500, "Failed to fetch alert states", err) + return response.Error(500, "Failed to fetch alert states", err) } - return JSON(200, query.Result) + return response.JSON(200, query.Result) } // GET /api/alerts -func GetAlerts(c *models.ReqContext) Response { +func GetAlerts(c *models.ReqContext) response.Response { dashboardQuery := c.Query("dashboardQuery") dashboardTags := c.QueryStrings("dashboardTag") stringDashboardIDs := c.QueryStrings("dashboardId") @@ -86,7 +87,7 @@ func GetAlerts(c *models.ReqContext) Response { err := bus.Dispatch(&searchQuery) if err != nil { - return Error(500, "List alerts failed", err) + return response.Error(500, "List alerts failed", err) } for _, d := range searchQuery.Result { @@ -97,7 +98,7 @@ func GetAlerts(c *models.ReqContext) Response { // if we didn't find any dashboards, return empty result if len(dashboardIDs) == 0 { - return JSON(200, []*models.AlertListItemDTO{}) + return response.JSON(200, []*models.AlertListItemDTO{}) } } @@ -116,20 +117,20 @@ func GetAlerts(c *models.ReqContext) Response { } if err := bus.Dispatch(&query); err != nil { - return Error(500, "List alerts failed", err) + return response.Error(500, "List alerts failed", err) } for _, alert := range query.Result { alert.Url = models.GetDashboardUrl(alert.DashboardUid, alert.DashboardSlug) } - return JSON(200, query.Result) + return response.JSON(200, query.Result) } // POST /api/alerts/test -func AlertTest(c *models.ReqContext, dto dtos.AlertTestCommand) Response { +func AlertTest(c *models.ReqContext, dto dtos.AlertTestCommand) response.Response { if _, idErr := dto.Dashboard.Get("id").Int64(); idErr != nil { - return Error(400, "The dashboard needs to be saved at least once before you can test an alert rule", nil) + return response.Error(400, "The dashboard needs to be saved at least once before you can test an alert rule", nil) } backendCmd := alerting.AlertTestCommand{ @@ -142,12 +143,12 @@ func AlertTest(c *models.ReqContext, dto dtos.AlertTestCommand) Response { if err := bus.Dispatch(&backendCmd); err != nil { var validationErr alerting.ValidationError if errors.As(err, &validationErr) { - return Error(422, validationErr.Error(), nil) + return response.Error(422, validationErr.Error(), nil) } if errors.Is(err, models.ErrDataSourceAccessDenied) { - return Error(403, "Access denied to datasource", err) + return response.Error(403, "Access denied to datasource", err) } - return Error(500, "Failed to test rule", err) + return response.Error(500, "Failed to test rule", err) } res := backendCmd.Result @@ -170,29 +171,29 @@ func AlertTest(c *models.ReqContext, dto dtos.AlertTestCommand) Response { dtoRes.TimeMs = fmt.Sprintf("%1.3fms", res.GetDurationMs()) - return JSON(200, dtoRes) + return response.JSON(200, dtoRes) } // GET /api/alerts/:id -func GetAlert(c *models.ReqContext) Response { +func GetAlert(c *models.ReqContext) response.Response { id := c.ParamsInt64(":alertId") query := models.GetAlertByIdQuery{Id: id} if err := bus.Dispatch(&query); err != nil { - return Error(500, "List alerts failed", err) + return response.Error(500, "List alerts failed", err) } - return JSON(200, &query.Result) + return response.JSON(200, &query.Result) } -func GetAlertNotifiers(c *models.ReqContext) Response { - return JSON(200, alerting.GetNotifiers()) +func GetAlertNotifiers(c *models.ReqContext) response.Response { + return response.JSON(200, alerting.GetNotifiers()) } -func GetAlertNotificationLookup(c *models.ReqContext) Response { +func GetAlertNotificationLookup(c *models.ReqContext) response.Response { alertNotifications, err := getAlertNotificationsInternal(c) if err != nil { - return Error(500, "Failed to get alert notifications", err) + return response.Error(500, "Failed to get alert notifications", err) } result := make([]*dtos.AlertNotificationLookup, 0) @@ -201,13 +202,13 @@ func GetAlertNotificationLookup(c *models.ReqContext) Response { result = append(result, dtos.NewAlertNotificationLookup(notification)) } - return JSON(200, result) + return response.JSON(200, result) } -func GetAlertNotifications(c *models.ReqContext) Response { +func GetAlertNotifications(c *models.ReqContext) response.Response { alertNotifications, err := getAlertNotificationsInternal(c) if err != nil { - return Error(500, "Failed to get alert notifications", err) + return response.Error(500, "Failed to get alert notifications", err) } result := make([]*dtos.AlertNotification, 0) @@ -216,7 +217,7 @@ func GetAlertNotifications(c *models.ReqContext) Response { result = append(result, dtos.NewAlertNotification(notification)) } - return JSON(200, result) + return response.JSON(200, result) } func getAlertNotificationsInternal(c *models.ReqContext) ([]*models.AlertNotification, error) { @@ -229,74 +230,74 @@ func getAlertNotificationsInternal(c *models.ReqContext) ([]*models.AlertNotific return query.Result, nil } -func GetAlertNotificationByID(c *models.ReqContext) Response { +func GetAlertNotificationByID(c *models.ReqContext) response.Response { query := &models.GetAlertNotificationsQuery{ OrgId: c.OrgId, Id: c.ParamsInt64("notificationId"), } if query.Id == 0 { - return Error(404, "Alert notification not found", nil) + return response.Error(404, "Alert notification not found", nil) } if err := bus.Dispatch(query); err != nil { - return Error(500, "Failed to get alert notifications", err) + return response.Error(500, "Failed to get alert notifications", err) } if query.Result == nil { - return Error(404, "Alert notification not found", nil) + return response.Error(404, "Alert notification not found", nil) } - return JSON(200, dtos.NewAlertNotification(query.Result)) + return response.JSON(200, dtos.NewAlertNotification(query.Result)) } -func GetAlertNotificationByUID(c *models.ReqContext) Response { +func GetAlertNotificationByUID(c *models.ReqContext) response.Response { query := &models.GetAlertNotificationsWithUidQuery{ OrgId: c.OrgId, Uid: c.Params("uid"), } if query.Uid == "" { - return Error(404, "Alert notification not found", nil) + return response.Error(404, "Alert notification not found", nil) } if err := bus.Dispatch(query); err != nil { - return Error(500, "Failed to get alert notifications", err) + return response.Error(500, "Failed to get alert notifications", err) } if query.Result == nil { - return Error(404, "Alert notification not found", nil) + return response.Error(404, "Alert notification not found", nil) } - return JSON(200, dtos.NewAlertNotification(query.Result)) + return response.JSON(200, dtos.NewAlertNotification(query.Result)) } -func CreateAlertNotification(c *models.ReqContext, cmd models.CreateAlertNotificationCommand) Response { +func CreateAlertNotification(c *models.ReqContext, cmd models.CreateAlertNotificationCommand) response.Response { cmd.OrgId = c.OrgId if err := bus.Dispatch(&cmd); err != nil { if errors.Is(err, models.ErrAlertNotificationWithSameNameExists) || errors.Is(err, models.ErrAlertNotificationWithSameUIDExists) { - return Error(409, "Failed to create alert notification", err) + return response.Error(409, "Failed to create alert notification", err) } - return Error(500, "Failed to create alert notification", err) + return response.Error(500, "Failed to create alert notification", err) } - return JSON(200, dtos.NewAlertNotification(cmd.Result)) + return response.JSON(200, dtos.NewAlertNotification(cmd.Result)) } -func UpdateAlertNotification(c *models.ReqContext, cmd models.UpdateAlertNotificationCommand) Response { +func UpdateAlertNotification(c *models.ReqContext, cmd models.UpdateAlertNotificationCommand) response.Response { cmd.OrgId = c.OrgId err := fillWithSecureSettingsData(&cmd) if err != nil { - return Error(500, "Failed to update alert notification", err) + return response.Error(500, "Failed to update alert notification", err) } if err := bus.Dispatch(&cmd); err != nil { if errors.Is(err, models.ErrAlertNotificationNotFound) { - return Error(404, err.Error(), err) + return response.Error(404, err.Error(), err) } - return Error(500, "Failed to update alert notification", err) + return response.Error(500, "Failed to update alert notification", err) } query := models.GetAlertNotificationsQuery{ @@ -305,26 +306,26 @@ func UpdateAlertNotification(c *models.ReqContext, cmd models.UpdateAlertNotific } if err := bus.Dispatch(&query); err != nil { - return Error(500, "Failed to get alert notification", err) + return response.Error(500, "Failed to get alert notification", err) } - return JSON(200, dtos.NewAlertNotification(query.Result)) + return response.JSON(200, dtos.NewAlertNotification(query.Result)) } -func UpdateAlertNotificationByUID(c *models.ReqContext, cmd models.UpdateAlertNotificationWithUidCommand) Response { +func UpdateAlertNotificationByUID(c *models.ReqContext, cmd models.UpdateAlertNotificationWithUidCommand) response.Response { cmd.OrgId = c.OrgId cmd.Uid = c.Params("uid") err := fillWithSecureSettingsDataByUID(&cmd) if err != nil { - return Error(500, "Failed to update alert notification", err) + return response.Error(500, "Failed to update alert notification", err) } if err := bus.Dispatch(&cmd); err != nil { if errors.Is(err, models.ErrAlertNotificationNotFound) { - return Error(404, err.Error(), nil) + return response.Error(404, err.Error(), nil) } - return Error(500, "Failed to update alert notification", err) + return response.Error(500, "Failed to update alert notification", err) } query := models.GetAlertNotificationsWithUidQuery{ @@ -333,10 +334,10 @@ func UpdateAlertNotificationByUID(c *models.ReqContext, cmd models.UpdateAlertNo } if err := bus.Dispatch(&query); err != nil { - return Error(500, "Failed to get alert notification", err) + return response.Error(500, "Failed to get alert notification", err) } - return JSON(200, dtos.NewAlertNotification(query.Result)) + return response.JSON(200, dtos.NewAlertNotification(query.Result)) } func fillWithSecureSettingsData(cmd *models.UpdateAlertNotificationCommand) error { @@ -387,7 +388,7 @@ func fillWithSecureSettingsDataByUID(cmd *models.UpdateAlertNotificationWithUidC return nil } -func DeleteAlertNotification(c *models.ReqContext) Response { +func DeleteAlertNotification(c *models.ReqContext) response.Response { cmd := models.DeleteAlertNotificationCommand{ OrgId: c.OrgId, Id: c.ParamsInt64("notificationId"), @@ -395,15 +396,15 @@ func DeleteAlertNotification(c *models.ReqContext) Response { if err := bus.Dispatch(&cmd); err != nil { if errors.Is(err, models.ErrAlertNotificationNotFound) { - return Error(404, err.Error(), nil) + return response.Error(404, err.Error(), nil) } - return Error(500, "Failed to delete alert notification", err) + return response.Error(500, "Failed to delete alert notification", err) } - return Success("Notification deleted") + return response.Success("Notification deleted") } -func DeleteAlertNotificationByUID(c *models.ReqContext) Response { +func DeleteAlertNotificationByUID(c *models.ReqContext) response.Response { cmd := models.DeleteAlertNotificationWithUidCommand{ OrgId: c.OrgId, Uid: c.Params("uid"), @@ -411,19 +412,19 @@ func DeleteAlertNotificationByUID(c *models.ReqContext) Response { if err := bus.Dispatch(&cmd); err != nil { if errors.Is(err, models.ErrAlertNotificationNotFound) { - return Error(404, err.Error(), nil) + return response.Error(404, err.Error(), nil) } - return Error(500, "Failed to delete alert notification", err) + return response.Error(500, "Failed to delete alert notification", err) } - return JSON(200, util.DynMap{ + return response.JSON(200, util.DynMap{ "message": "Notification deleted", "id": cmd.DeletedAlertNotificationId, }) } // POST /api/alert-notifications/test -func NotificationTest(c *models.ReqContext, dto dtos.NotificationTestCommand) Response { +func NotificationTest(c *models.ReqContext, dto dtos.NotificationTestCommand) response.Response { cmd := &alerting.NotificationTestCommand{ OrgID: c.OrgId, ID: dto.ID, @@ -435,43 +436,43 @@ func NotificationTest(c *models.ReqContext, dto dtos.NotificationTestCommand) Re if err := bus.DispatchCtx(c.Req.Context(), cmd); err != nil { if errors.Is(err, models.ErrSmtpNotEnabled) { - return Error(412, err.Error(), err) + return response.Error(412, err.Error(), err) } - return Error(500, "Failed to send alert notifications", err) + return response.Error(500, "Failed to send alert notifications", err) } - return Success("Test notification sent") + return response.Success("Test notification sent") } // POST /api/alerts/:alertId/pause -func PauseAlert(c *models.ReqContext, dto dtos.PauseAlertCommand) Response { +func PauseAlert(c *models.ReqContext, dto dtos.PauseAlertCommand) response.Response { alertID := c.ParamsInt64("alertId") result := make(map[string]interface{}) result["alertId"] = alertID query := models.GetAlertByIdQuery{Id: alertID} if err := bus.Dispatch(&query); err != nil { - return Error(500, "Get Alert failed", err) + return response.Error(500, "Get Alert failed", err) } guardian := guardian.New(query.Result.DashboardId, c.OrgId, c.SignedInUser) if canEdit, err := guardian.CanEdit(); err != nil || !canEdit { if err != nil { - return Error(500, "Error while checking permissions for Alert", err) + return response.Error(500, "Error while checking permissions for Alert", err) } - return Error(403, "Access denied to this dashboard and alert", nil) + return response.Error(403, "Access denied to this dashboard and alert", nil) } // Alert state validation if query.Result.State != models.AlertStatePaused && !dto.Paused { result["state"] = "un-paused" result["message"] = "Alert is already un-paused" - return JSON(200, result) + return response.JSON(200, result) } else if query.Result.State == models.AlertStatePaused && dto.Paused { result["state"] = models.AlertStatePaused result["message"] = "Alert is already paused" - return JSON(200, result) + return response.JSON(200, result) } cmd := models.PauseAlertCommand{ @@ -481,43 +482,43 @@ func PauseAlert(c *models.ReqContext, dto dtos.PauseAlertCommand) Response { } if err := bus.Dispatch(&cmd); err != nil { - return Error(500, "", err) + return response.Error(500, "", err) } - var response models.AlertStateType = models.AlertStateUnknown + var resp models.AlertStateType = models.AlertStateUnknown pausedState := "un-paused" if cmd.Paused { - response = models.AlertStatePaused + resp = models.AlertStatePaused pausedState = "paused" } - result["state"] = response + result["state"] = resp result["message"] = "Alert " + pausedState - return JSON(200, result) + return response.JSON(200, result) } // POST /api/admin/pause-all-alerts -func PauseAllAlerts(c *models.ReqContext, dto dtos.PauseAllAlertsCommand) Response { +func PauseAllAlerts(c *models.ReqContext, dto dtos.PauseAllAlertsCommand) response.Response { updateCmd := models.PauseAllAlertCommand{ Paused: dto.Paused, } if err := bus.Dispatch(&updateCmd); err != nil { - return Error(500, "Failed to pause alerts", err) + return response.Error(500, "Failed to pause alerts", err) } - var response models.AlertStateType = models.AlertStatePending + var resp models.AlertStateType = models.AlertStatePending pausedState := "un paused" if updateCmd.Paused { - response = models.AlertStatePaused + resp = models.AlertStatePaused pausedState = "paused" } result := map[string]interface{}{ - "state": response, + "state": resp, "message": "alerts " + pausedState, "alertsAffected": updateCmd.ResultCount, } - return JSON(200, result) + return response.JSON(200, result) } diff --git a/pkg/api/alerting_test.go b/pkg/api/alerting_test.go index 3baf9f9ba87..3cedc534c50 100644 --- a/pkg/api/alerting_test.go +++ b/pkg/api/alerting_test.go @@ -4,7 +4,10 @@ import ( "fmt" "testing" + "github.com/grafana/grafana/pkg/api/routing" + "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/search" @@ -162,7 +165,7 @@ func postAlertScenario(t *testing.T, desc string, url string, routePattern strin defer bus.ClearBusHandlers() sc := setupScenarioContext(t, url) - sc.defaultHandler = Wrap(func(c *models.ReqContext) Response { + sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.context = c sc.context.UserId = testUserID sc.context.OrgId = testOrgID diff --git a/pkg/api/annotations.go b/pkg/api/annotations.go index 52754f0993f..c0784cda28c 100644 --- a/pkg/api/annotations.go +++ b/pkg/api/annotations.go @@ -4,13 +4,14 @@ import ( "strings" "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/annotations" "github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/util" ) -func GetAnnotations(c *models.ReqContext) Response { +func GetAnnotations(c *models.ReqContext) response.Response { query := &annotations.ItemQuery{ From: c.QueryInt64("from"), To: c.QueryInt64("to"), @@ -29,7 +30,7 @@ func GetAnnotations(c *models.ReqContext) Response { items, err := repo.Find(query) if err != nil { - return Error(500, "Failed to get annotations", err) + return response.Error(500, "Failed to get annotations", err) } for _, item := range items { @@ -38,7 +39,7 @@ func GetAnnotations(c *models.ReqContext) Response { } } - return JSON(200, items) + return response.JSON(200, items) } type CreateAnnotationError struct { @@ -49,7 +50,7 @@ func (e *CreateAnnotationError) Error() string { return e.message } -func PostAnnotation(c *models.ReqContext, cmd dtos.PostAnnotationsCmd) Response { +func PostAnnotation(c *models.ReqContext, cmd dtos.PostAnnotationsCmd) response.Response { if canSave, err := canSaveByDashboardID(c, cmd.DashboardId); err != nil || !canSave { return dashboardGuardianResponse(err) } @@ -58,7 +59,7 @@ func PostAnnotation(c *models.ReqContext, cmd dtos.PostAnnotationsCmd) Response if cmd.Text == "" { err := &CreateAnnotationError{"text field should not be empty"} - return Error(500, "Failed to save annotation", err) + return response.Error(500, "Failed to save annotation", err) } item := annotations.Item{ @@ -74,12 +75,12 @@ func PostAnnotation(c *models.ReqContext, cmd dtos.PostAnnotationsCmd) Response } if err := repo.Save(&item); err != nil { - return Error(500, "Failed to save annotation", err) + return response.Error(500, "Failed to save annotation", err) } startID := item.Id - return JSON(200, util.DynMap{ + return response.JSON(200, util.DynMap{ "message": "Annotation added", "id": startID, }) @@ -93,12 +94,12 @@ func formatGraphiteAnnotation(what string, data string) string { return text } -func PostGraphiteAnnotation(c *models.ReqContext, cmd dtos.PostGraphiteAnnotationsCmd) Response { +func PostGraphiteAnnotation(c *models.ReqContext, cmd dtos.PostGraphiteAnnotationsCmd) response.Response { repo := annotations.GetRepository() if cmd.What == "" { err := &CreateAnnotationError{"what field should not be empty"} - return Error(500, "Failed to save Graphite annotation", err) + return response.Error(500, "Failed to save Graphite annotation", err) } text := formatGraphiteAnnotation(cmd.What, cmd.Data) @@ -118,12 +119,12 @@ func PostGraphiteAnnotation(c *models.ReqContext, cmd dtos.PostGraphiteAnnotatio tagsArray = append(tagsArray, tagStr) } else { err := &CreateAnnotationError{"tag should be a string"} - return Error(500, "Failed to save Graphite annotation", err) + return response.Error(500, "Failed to save Graphite annotation", err) } } default: err := &CreateAnnotationError{"unsupported tags format"} - return Error(500, "Failed to save Graphite annotation", err) + return response.Error(500, "Failed to save Graphite annotation", err) } item := annotations.Item{ @@ -135,16 +136,16 @@ func PostGraphiteAnnotation(c *models.ReqContext, cmd dtos.PostGraphiteAnnotatio } if err := repo.Save(&item); err != nil { - return Error(500, "Failed to save Graphite annotation", err) + return response.Error(500, "Failed to save Graphite annotation", err) } - return JSON(200, util.DynMap{ + return response.JSON(200, util.DynMap{ "message": "Graphite annotation added", "id": item.Id, }) } -func UpdateAnnotation(c *models.ReqContext, cmd dtos.UpdateAnnotationsCmd) Response { +func UpdateAnnotation(c *models.ReqContext, cmd dtos.UpdateAnnotationsCmd) response.Response { annotationID := c.ParamsInt64(":annotationId") repo := annotations.GetRepository() @@ -164,13 +165,13 @@ func UpdateAnnotation(c *models.ReqContext, cmd dtos.UpdateAnnotationsCmd) Respo } if err := repo.Update(&item); err != nil { - return Error(500, "Failed to update annotation", err) + return response.Error(500, "Failed to update annotation", err) } - return Success("Annotation updated") + return response.Success("Annotation updated") } -func PatchAnnotation(c *models.ReqContext, cmd dtos.PatchAnnotationsCmd) Response { +func PatchAnnotation(c *models.ReqContext, cmd dtos.PatchAnnotationsCmd) response.Response { annotationID := c.ParamsInt64(":annotationId") repo := annotations.GetRepository() @@ -182,7 +183,7 @@ func PatchAnnotation(c *models.ReqContext, cmd dtos.PatchAnnotationsCmd) Respons items, err := repo.Find(&annotations.ItemQuery{AnnotationId: annotationID, OrgId: c.OrgId}) if err != nil || len(items) == 0 { - return Error(404, "Could not find annotation to update", err) + return response.Error(404, "Could not find annotation to update", err) } existing := annotations.Item{ @@ -212,13 +213,13 @@ func PatchAnnotation(c *models.ReqContext, cmd dtos.PatchAnnotationsCmd) Respons } if err := repo.Update(&existing); err != nil { - return Error(500, "Failed to update annotation", err) + return response.Error(500, "Failed to update annotation", err) } - return Success("Annotation patched") + return response.Success("Annotation patched") } -func DeleteAnnotations(c *models.ReqContext, cmd dtos.DeleteAnnotationsCmd) Response { +func DeleteAnnotations(c *models.ReqContext, cmd dtos.DeleteAnnotationsCmd) response.Response { repo := annotations.GetRepository() err := repo.Delete(&annotations.DeleteParams{ @@ -229,13 +230,13 @@ func DeleteAnnotations(c *models.ReqContext, cmd dtos.DeleteAnnotationsCmd) Resp }) if err != nil { - return Error(500, "Failed to delete annotations", err) + return response.Error(500, "Failed to delete annotations", err) } - return Success("Annotations deleted") + return response.Success("Annotations deleted") } -func DeleteAnnotationByID(c *models.ReqContext) Response { +func DeleteAnnotationByID(c *models.ReqContext) response.Response { repo := annotations.GetRepository() annotationID := c.ParamsInt64(":annotationId") @@ -248,10 +249,10 @@ func DeleteAnnotationByID(c *models.ReqContext) Response { Id: annotationID, }) if err != nil { - return Error(500, "Failed to delete annotation", err) + return response.Error(500, "Failed to delete annotation", err) } - return Success("Annotation deleted") + return response.Success("Annotation deleted") } func canSaveByDashboardID(c *models.ReqContext, dashboardID int64) (bool, error) { @@ -269,10 +270,10 @@ func canSaveByDashboardID(c *models.ReqContext, dashboardID int64) (bool, error) return true, nil } -func canSave(c *models.ReqContext, repo annotations.Repository, annotationID int64) Response { +func canSave(c *models.ReqContext, repo annotations.Repository, annotationID int64) response.Response { items, err := repo.Find(&annotations.ItemQuery{AnnotationId: annotationID, OrgId: c.OrgId}) if err != nil || len(items) == 0 { - return Error(500, "Could not find annotation to update", err) + return response.Error(500, "Could not find annotation to update", err) } dashboardID := items[0].DashboardId diff --git a/pkg/api/annotations_test.go b/pkg/api/annotations_test.go index 218bdcaf855..d901bd5d42c 100644 --- a/pkg/api/annotations_test.go +++ b/pkg/api/annotations_test.go @@ -5,6 +5,8 @@ import ( "testing" "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/api/response" + "github.com/grafana/grafana/pkg/api/routing" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/annotations" @@ -266,7 +268,7 @@ func postAnnotationScenario(t *testing.T, desc string, url string, routePattern t.Cleanup(bus.ClearBusHandlers) sc := setupScenarioContext(t, url) - sc.defaultHandler = Wrap(func(c *models.ReqContext) Response { + sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.context = c sc.context.UserId = testUserID sc.context.OrgId = testOrgID @@ -290,7 +292,7 @@ func putAnnotationScenario(t *testing.T, desc string, url string, routePattern s t.Cleanup(bus.ClearBusHandlers) sc := setupScenarioContext(t, url) - sc.defaultHandler = Wrap(func(c *models.ReqContext) Response { + sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.context = c sc.context.UserId = testUserID sc.context.OrgId = testOrgID @@ -313,7 +315,7 @@ func patchAnnotationScenario(t *testing.T, desc string, url string, routePattern defer bus.ClearBusHandlers() sc := setupScenarioContext(t, url) - sc.defaultHandler = Wrap(func(c *models.ReqContext) Response { + sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.context = c sc.context.UserId = testUserID sc.context.OrgId = testOrgID @@ -337,7 +339,7 @@ func deleteAnnotationsScenario(t *testing.T, desc string, url string, routePatte defer bus.ClearBusHandlers() sc := setupScenarioContext(t, url) - sc.defaultHandler = Wrap(func(c *models.ReqContext) Response { + sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.context = c sc.context.UserId = testUserID sc.context.OrgId = testOrgID diff --git a/pkg/api/api.go b/pkg/api/api.go index a0163e8d656..44685636d85 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -33,7 +33,7 @@ func (hs *HTTPServer) registerRoutes() { // not logged in views r.Get("/logout", hs.Logout) - r.Post("/login", quota("session"), bind(dtos.LoginCommand{}), Wrap(hs.LoginPost)) + r.Post("/login", quota("session"), bind(dtos.LoginCommand{}), routing.Wrap(hs.LoginPost)) r.Get("/login/:name", quota("session"), hs.OAuthLogin) r.Get("/login", hs.LoginView) r.Get("/invite/:code", hs.Index) @@ -100,180 +100,180 @@ func (hs *HTTPServer) registerRoutes() { // sign up r.Get("/verify", hs.Index) r.Get("/signup", hs.Index) - r.Get("/api/user/signup/options", Wrap(GetSignUpOptions)) - r.Post("/api/user/signup", quota("user"), bind(dtos.SignUpForm{}), Wrap(SignUp)) - r.Post("/api/user/signup/step2", bind(dtos.SignUpStep2Form{}), Wrap(hs.SignUpStep2)) + 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/step2", bind(dtos.SignUpStep2Form{}), routing.Wrap(hs.SignUpStep2)) // invited - r.Get("/api/user/invite/:code", Wrap(GetInviteInfoByCode)) - r.Post("/api/user/invite/complete", bind(dtos.CompleteInviteForm{}), Wrap(hs.CompleteInvite)) + r.Get("/api/user/invite/:code", routing.Wrap(GetInviteInfoByCode)) + r.Post("/api/user/invite/complete", bind(dtos.CompleteInviteForm{}), routing.Wrap(hs.CompleteInvite)) // reset password r.Get("/user/password/send-reset-email", hs.Index) r.Get("/user/password/reset", hs.Index) - r.Post("/api/user/password/send-reset-email", bind(dtos.SendResetPasswordEmailForm{}), Wrap(SendResetPasswordEmail)) - r.Post("/api/user/password/reset", bind(dtos.ResetUserPasswordForm{}), Wrap(ResetPassword)) + r.Post("/api/user/password/send-reset-email", bind(dtos.SendResetPasswordEmailForm{}), routing.Wrap(SendResetPasswordEmail)) + r.Post("/api/user/password/reset", bind(dtos.ResetUserPasswordForm{}), routing.Wrap(ResetPassword)) // dashboard snapshots r.Get("/dashboard/snapshot/*", hs.Index) r.Get("/dashboard/snapshots/", reqSignedIn, hs.Index) // api renew session based on cookie - r.Get("/api/login/ping", quota("session"), Wrap(hs.LoginAPIPing)) + r.Get("/api/login/ping", quota("session"), routing.Wrap(hs.LoginAPIPing)) // authed api r.Group("/api", func(apiRoute routing.RouteRegister) { // user (signed in) apiRoute.Group("/user", func(userRoute routing.RouteRegister) { - userRoute.Get("/", Wrap(GetSignedInUser)) - userRoute.Put("/", bind(models.UpdateUserCommand{}), Wrap(UpdateSignedInUser)) - userRoute.Post("/using/:id", Wrap(UserSetUsingOrg)) - userRoute.Get("/orgs", Wrap(GetSignedInUserOrgList)) - userRoute.Get("/teams", Wrap(GetSignedInUserTeamList)) + userRoute.Get("/", routing.Wrap(GetSignedInUser)) + userRoute.Put("/", bind(models.UpdateUserCommand{}), routing.Wrap(UpdateSignedInUser)) + userRoute.Post("/using/:id", routing.Wrap(UserSetUsingOrg)) + userRoute.Get("/orgs", routing.Wrap(GetSignedInUserOrgList)) + userRoute.Get("/teams", routing.Wrap(GetSignedInUserTeamList)) - userRoute.Post("/stars/dashboard/:id", Wrap(StarDashboard)) - userRoute.Delete("/stars/dashboard/:id", Wrap(UnstarDashboard)) + userRoute.Post("/stars/dashboard/:id", routing.Wrap(StarDashboard)) + userRoute.Delete("/stars/dashboard/:id", routing.Wrap(UnstarDashboard)) - userRoute.Put("/password", bind(models.ChangeUserPasswordCommand{}), Wrap(ChangeUserPassword)) - userRoute.Get("/quotas", Wrap(GetUserQuotas)) - userRoute.Put("/helpflags/:id", Wrap(SetHelpFlag)) + userRoute.Put("/password", bind(models.ChangeUserPasswordCommand{}), routing.Wrap(ChangeUserPassword)) + userRoute.Get("/quotas", routing.Wrap(GetUserQuotas)) + userRoute.Put("/helpflags/:id", routing.Wrap(SetHelpFlag)) // For dev purpose - userRoute.Get("/helpflags/clear", Wrap(ClearHelpFlags)) + userRoute.Get("/helpflags/clear", routing.Wrap(ClearHelpFlags)) - userRoute.Get("/preferences", Wrap(GetUserPreferences)) - userRoute.Put("/preferences", bind(dtos.UpdatePrefsCmd{}), Wrap(UpdateUserPreferences)) + userRoute.Get("/preferences", routing.Wrap(GetUserPreferences)) + userRoute.Put("/preferences", bind(dtos.UpdatePrefsCmd{}), routing.Wrap(UpdateUserPreferences)) - userRoute.Get("/auth-tokens", Wrap(hs.GetUserAuthTokens)) - userRoute.Post("/revoke-auth-token", bind(models.RevokeAuthTokenCmd{}), Wrap(hs.RevokeUserAuthToken)) + userRoute.Get("/auth-tokens", routing.Wrap(hs.GetUserAuthTokens)) + userRoute.Post("/revoke-auth-token", bind(models.RevokeAuthTokenCmd{}), routing.Wrap(hs.RevokeUserAuthToken)) }) // users (admin permission required) apiRoute.Group("/users", func(usersRoute routing.RouteRegister) { - usersRoute.Get("/", Wrap(SearchUsers)) - usersRoute.Get("/search", Wrap(SearchUsersWithPaging)) - usersRoute.Get("/:id", Wrap(GetUserByID)) - usersRoute.Get("/:id/teams", Wrap(GetUserTeams)) - usersRoute.Get("/:id/orgs", Wrap(GetUserOrgList)) + usersRoute.Get("/", routing.Wrap(SearchUsers)) + usersRoute.Get("/search", routing.Wrap(SearchUsersWithPaging)) + usersRoute.Get("/:id", routing.Wrap(GetUserByID)) + usersRoute.Get("/:id/teams", routing.Wrap(GetUserTeams)) + usersRoute.Get("/:id/orgs", routing.Wrap(GetUserOrgList)) // query parameters /users/lookup?loginOrEmail=admin@example.com - usersRoute.Get("/lookup", Wrap(GetUserByLoginOrEmail)) - usersRoute.Put("/:id", bind(models.UpdateUserCommand{}), Wrap(UpdateUser)) - usersRoute.Post("/:id/using/:orgId", Wrap(UpdateUserActiveOrg)) + usersRoute.Get("/lookup", routing.Wrap(GetUserByLoginOrEmail)) + usersRoute.Put("/:id", bind(models.UpdateUserCommand{}), routing.Wrap(UpdateUser)) + usersRoute.Post("/:id/using/:orgId", routing.Wrap(UpdateUserActiveOrg)) }, reqGrafanaAdmin) // team (admin permission required) apiRoute.Group("/teams", func(teamsRoute routing.RouteRegister) { - teamsRoute.Post("/", bind(models.CreateTeamCommand{}), Wrap(hs.CreateTeam)) - teamsRoute.Put("/:teamId", bind(models.UpdateTeamCommand{}), Wrap(hs.UpdateTeam)) - teamsRoute.Delete("/:teamId", Wrap(hs.DeleteTeamByID)) - teamsRoute.Get("/:teamId/members", Wrap(hs.GetTeamMembers)) - teamsRoute.Post("/:teamId/members", bind(models.AddTeamMemberCommand{}), Wrap(hs.AddTeamMember)) - teamsRoute.Put("/:teamId/members/:userId", bind(models.UpdateTeamMemberCommand{}), Wrap(hs.UpdateTeamMember)) - teamsRoute.Delete("/:teamId/members/:userId", Wrap(hs.RemoveTeamMember)) - teamsRoute.Get("/:teamId/preferences", Wrap(hs.GetTeamPreferences)) - teamsRoute.Put("/:teamId/preferences", bind(dtos.UpdatePrefsCmd{}), Wrap(hs.UpdateTeamPreferences)) + teamsRoute.Post("/", bind(models.CreateTeamCommand{}), routing.Wrap(hs.CreateTeam)) + teamsRoute.Put("/:teamId", bind(models.UpdateTeamCommand{}), routing.Wrap(hs.UpdateTeam)) + teamsRoute.Delete("/:teamId", routing.Wrap(hs.DeleteTeamByID)) + teamsRoute.Get("/:teamId/members", routing.Wrap(hs.GetTeamMembers)) + teamsRoute.Post("/:teamId/members", bind(models.AddTeamMemberCommand{}), routing.Wrap(hs.AddTeamMember)) + teamsRoute.Put("/:teamId/members/:userId", bind(models.UpdateTeamMemberCommand{}), routing.Wrap(hs.UpdateTeamMember)) + teamsRoute.Delete("/:teamId/members/:userId", routing.Wrap(hs.RemoveTeamMember)) + teamsRoute.Get("/:teamId/preferences", routing.Wrap(hs.GetTeamPreferences)) + teamsRoute.Put("/:teamId/preferences", bind(dtos.UpdatePrefsCmd{}), routing.Wrap(hs.UpdateTeamPreferences)) }, reqCanAccessTeams) // team without requirement of user to be org admin apiRoute.Group("/teams", func(teamsRoute routing.RouteRegister) { - teamsRoute.Get("/:teamId", Wrap(hs.GetTeamByID)) - teamsRoute.Get("/search", Wrap(hs.SearchTeams)) + teamsRoute.Get("/:teamId", routing.Wrap(hs.GetTeamByID)) + teamsRoute.Get("/search", routing.Wrap(hs.SearchTeams)) }) // org information available to all users. apiRoute.Group("/org", func(orgRoute routing.RouteRegister) { - orgRoute.Get("/", Wrap(GetOrgCurrent)) - orgRoute.Get("/quotas", Wrap(GetOrgQuotas)) + orgRoute.Get("/", routing.Wrap(GetOrgCurrent)) + orgRoute.Get("/quotas", routing.Wrap(GetOrgQuotas)) }) // current org apiRoute.Group("/org", func(orgRoute routing.RouteRegister) { - orgRoute.Put("/", bind(dtos.UpdateOrgForm{}), Wrap(UpdateOrgCurrent)) - orgRoute.Put("/address", bind(dtos.UpdateOrgAddressForm{}), Wrap(UpdateOrgAddressCurrent)) - orgRoute.Get("/users", Wrap(hs.GetOrgUsersForCurrentOrg)) - orgRoute.Post("/users", quota("user"), bind(models.AddOrgUserCommand{}), Wrap(AddOrgUserToCurrentOrg)) - orgRoute.Patch("/users/:userId", bind(models.UpdateOrgUserCommand{}), Wrap(UpdateOrgUserForCurrentOrg)) - orgRoute.Delete("/users/:userId", Wrap(RemoveOrgUserForCurrentOrg)) + orgRoute.Put("/", bind(dtos.UpdateOrgForm{}), routing.Wrap(UpdateOrgCurrent)) + orgRoute.Put("/address", bind(dtos.UpdateOrgAddressForm{}), routing.Wrap(UpdateOrgAddressCurrent)) + orgRoute.Get("/users", routing.Wrap(hs.GetOrgUsersForCurrentOrg)) + orgRoute.Post("/users", quota("user"), bind(models.AddOrgUserCommand{}), routing.Wrap(AddOrgUserToCurrentOrg)) + orgRoute.Patch("/users/:userId", bind(models.UpdateOrgUserCommand{}), routing.Wrap(UpdateOrgUserForCurrentOrg)) + orgRoute.Delete("/users/:userId", routing.Wrap(RemoveOrgUserForCurrentOrg)) // invites - orgRoute.Get("/invites", Wrap(GetPendingOrgInvites)) - orgRoute.Post("/invites", quota("user"), bind(dtos.AddInviteForm{}), Wrap(AddOrgInvite)) - orgRoute.Patch("/invites/:code/revoke", Wrap(RevokeInvite)) + orgRoute.Get("/invites", routing.Wrap(GetPendingOrgInvites)) + orgRoute.Post("/invites", quota("user"), bind(dtos.AddInviteForm{}), routing.Wrap(AddOrgInvite)) + orgRoute.Patch("/invites/:code/revoke", routing.Wrap(RevokeInvite)) // prefs - orgRoute.Get("/preferences", Wrap(GetOrgPreferences)) - orgRoute.Put("/preferences", bind(dtos.UpdatePrefsCmd{}), Wrap(UpdateOrgPreferences)) + orgRoute.Get("/preferences", routing.Wrap(GetOrgPreferences)) + orgRoute.Put("/preferences", bind(dtos.UpdatePrefsCmd{}), routing.Wrap(UpdateOrgPreferences)) }, reqOrgAdmin) // current org without requirement of user to be org admin apiRoute.Group("/org", func(orgRoute routing.RouteRegister) { - orgRoute.Get("/users/lookup", Wrap(hs.GetOrgUsersForCurrentOrgLookup)) + orgRoute.Get("/users/lookup", routing.Wrap(hs.GetOrgUsersForCurrentOrgLookup)) }) // create new org - apiRoute.Post("/orgs", quota("org"), bind(models.CreateOrgCommand{}), Wrap(CreateOrg)) + apiRoute.Post("/orgs", quota("org"), bind(models.CreateOrgCommand{}), routing.Wrap(CreateOrg)) // search all orgs - apiRoute.Get("/orgs", reqGrafanaAdmin, Wrap(SearchOrgs)) + apiRoute.Get("/orgs", reqGrafanaAdmin, routing.Wrap(SearchOrgs)) // orgs (admin routes) apiRoute.Group("/orgs/:orgId", func(orgsRoute routing.RouteRegister) { - orgsRoute.Get("/", Wrap(GetOrgByID)) - orgsRoute.Put("/", bind(dtos.UpdateOrgForm{}), Wrap(UpdateOrg)) - orgsRoute.Put("/address", bind(dtos.UpdateOrgAddressForm{}), Wrap(UpdateOrgAddress)) - orgsRoute.Delete("/", Wrap(DeleteOrgByID)) - orgsRoute.Get("/users", Wrap(hs.GetOrgUsers)) - orgsRoute.Post("/users", bind(models.AddOrgUserCommand{}), Wrap(AddOrgUser)) - orgsRoute.Patch("/users/:userId", bind(models.UpdateOrgUserCommand{}), Wrap(UpdateOrgUser)) - orgsRoute.Delete("/users/:userId", Wrap(RemoveOrgUser)) - orgsRoute.Get("/quotas", Wrap(GetOrgQuotas)) - orgsRoute.Put("/quotas/:target", bind(models.UpdateOrgQuotaCmd{}), Wrap(UpdateOrgQuota)) + orgsRoute.Get("/", routing.Wrap(GetOrgByID)) + orgsRoute.Put("/", bind(dtos.UpdateOrgForm{}), routing.Wrap(UpdateOrg)) + orgsRoute.Put("/address", bind(dtos.UpdateOrgAddressForm{}), routing.Wrap(UpdateOrgAddress)) + orgsRoute.Delete("/", routing.Wrap(DeleteOrgByID)) + orgsRoute.Get("/users", routing.Wrap(hs.GetOrgUsers)) + orgsRoute.Post("/users", bind(models.AddOrgUserCommand{}), routing.Wrap(AddOrgUser)) + orgsRoute.Patch("/users/:userId", bind(models.UpdateOrgUserCommand{}), routing.Wrap(UpdateOrgUser)) + orgsRoute.Delete("/users/:userId", routing.Wrap(RemoveOrgUser)) + orgsRoute.Get("/quotas", routing.Wrap(GetOrgQuotas)) + orgsRoute.Put("/quotas/:target", bind(models.UpdateOrgQuotaCmd{}), routing.Wrap(UpdateOrgQuota)) }, reqGrafanaAdmin) // orgs (admin routes) apiRoute.Group("/orgs/name/:name", func(orgsRoute routing.RouteRegister) { - orgsRoute.Get("/", Wrap(hs.GetOrgByName)) + orgsRoute.Get("/", routing.Wrap(hs.GetOrgByName)) }, reqGrafanaAdmin) // auth api keys apiRoute.Group("/auth/keys", func(keysRoute routing.RouteRegister) { - keysRoute.Get("/", Wrap(GetAPIKeys)) - keysRoute.Post("/", quota("api_key"), bind(models.AddApiKeyCommand{}), Wrap(hs.AddAPIKey)) - keysRoute.Delete("/:id", Wrap(DeleteAPIKey)) + keysRoute.Get("/", routing.Wrap(GetAPIKeys)) + keysRoute.Post("/", quota("api_key"), bind(models.AddApiKeyCommand{}), routing.Wrap(hs.AddAPIKey)) + keysRoute.Delete("/:id", routing.Wrap(DeleteAPIKey)) }, reqOrgAdmin) // Preferences apiRoute.Group("/preferences", func(prefRoute routing.RouteRegister) { - prefRoute.Post("/set-home-dash", bind(models.SavePreferencesCommand{}), Wrap(SetHomeDashboard)) + prefRoute.Post("/set-home-dash", bind(models.SavePreferencesCommand{}), routing.Wrap(SetHomeDashboard)) }) // Data sources apiRoute.Group("/datasources", func(datasourceRoute routing.RouteRegister) { - datasourceRoute.Get("/", Wrap(hs.GetDataSources)) - datasourceRoute.Post("/", quota("data_source"), bind(models.AddDataSourceCommand{}), Wrap(AddDataSource)) - datasourceRoute.Put("/:id", bind(models.UpdateDataSourceCommand{}), Wrap(UpdateDataSource)) - datasourceRoute.Delete("/:id", Wrap(DeleteDataSourceById)) - datasourceRoute.Delete("/uid/:uid", Wrap(DeleteDataSourceByUID)) - datasourceRoute.Delete("/name/:name", Wrap(DeleteDataSourceByName)) - datasourceRoute.Get("/:id", Wrap(GetDataSourceById)) - datasourceRoute.Get("/uid/:uid", Wrap(GetDataSourceByUID)) - datasourceRoute.Get("/name/:name", Wrap(GetDataSourceByName)) + datasourceRoute.Get("/", routing.Wrap(hs.GetDataSources)) + datasourceRoute.Post("/", quota("data_source"), bind(models.AddDataSourceCommand{}), routing.Wrap(AddDataSource)) + datasourceRoute.Put("/:id", bind(models.UpdateDataSourceCommand{}), routing.Wrap(UpdateDataSource)) + datasourceRoute.Delete("/:id", routing.Wrap(DeleteDataSourceById)) + datasourceRoute.Delete("/uid/:uid", routing.Wrap(DeleteDataSourceByUID)) + datasourceRoute.Delete("/name/:name", routing.Wrap(DeleteDataSourceByName)) + datasourceRoute.Get("/:id", routing.Wrap(GetDataSourceById)) + datasourceRoute.Get("/uid/:uid", routing.Wrap(GetDataSourceByUID)) + datasourceRoute.Get("/name/:name", routing.Wrap(GetDataSourceByName)) }, reqOrgAdmin) - apiRoute.Get("/datasources/id/:name", Wrap(GetDataSourceIdByName), reqSignedIn) + apiRoute.Get("/datasources/id/:name", routing.Wrap(GetDataSourceIdByName), reqSignedIn) - apiRoute.Get("/plugins", Wrap(hs.GetPluginList)) - apiRoute.Get("/plugins/:pluginId/settings", Wrap(GetPluginSettingByID)) - apiRoute.Get("/plugins/:pluginId/markdown/:name", Wrap(GetPluginMarkdown)) - apiRoute.Get("/plugins/:pluginId/health", Wrap(hs.CheckHealth)) + apiRoute.Get("/plugins", routing.Wrap(hs.GetPluginList)) + apiRoute.Get("/plugins/:pluginId/settings", routing.Wrap(GetPluginSettingByID)) + apiRoute.Get("/plugins/:pluginId/markdown/:name", routing.Wrap(GetPluginMarkdown)) + apiRoute.Get("/plugins/:pluginId/health", routing.Wrap(hs.CheckHealth)) apiRoute.Any("/plugins/:pluginId/resources", hs.CallResource) apiRoute.Any("/plugins/:pluginId/resources/*", hs.CallResource) - apiRoute.Any("/plugins/errors", Wrap(hs.GetPluginErrorsList)) + apiRoute.Any("/plugins/errors", routing.Wrap(hs.GetPluginErrorsList)) apiRoute.Group("/plugins", func(pluginRoute routing.RouteRegister) { - pluginRoute.Get("/:pluginId/dashboards/", Wrap(GetPluginDashboards)) - pluginRoute.Post("/:pluginId/settings", bind(models.UpdatePluginSettingCmd{}), Wrap(UpdatePluginSetting)) - pluginRoute.Get("/:pluginId/metrics", Wrap(hs.CollectPluginMetrics)) + pluginRoute.Get("/:pluginId/dashboards/", routing.Wrap(GetPluginDashboards)) + pluginRoute.Post("/:pluginId/settings", bind(models.UpdatePluginSettingCmd{}), routing.Wrap(UpdatePluginSetting)) + pluginRoute.Get("/:pluginId/metrics", routing.Wrap(hs.CollectPluginMetrics)) }, reqOrgAdmin) apiRoute.Get("/frontend/settings/", hs.GetFrontendSettings) @@ -281,153 +281,153 @@ func (hs *HTTPServer) registerRoutes() { apiRoute.Any("/datasources/proxy/:id", reqSignedIn, hs.ProxyDataSourceRequest) apiRoute.Any("/datasources/:id/resources", hs.CallDatasourceResource) apiRoute.Any("/datasources/:id/resources/*", hs.CallDatasourceResource) - apiRoute.Any("/datasources/:id/health", Wrap(hs.CheckDatasourceHealth)) + apiRoute.Any("/datasources/:id/health", routing.Wrap(hs.CheckDatasourceHealth)) // Folders apiRoute.Group("/folders", func(folderRoute routing.RouteRegister) { - folderRoute.Get("/", Wrap(GetFolders)) - folderRoute.Get("/id/:id", Wrap(GetFolderByID)) - folderRoute.Post("/", bind(models.CreateFolderCommand{}), Wrap(hs.CreateFolder)) + folderRoute.Get("/", routing.Wrap(GetFolders)) + folderRoute.Get("/id/:id", routing.Wrap(GetFolderByID)) + folderRoute.Post("/", bind(models.CreateFolderCommand{}), routing.Wrap(hs.CreateFolder)) folderRoute.Group("/:uid", func(folderUidRoute routing.RouteRegister) { - folderUidRoute.Get("/", Wrap(GetFolderByUID)) - folderUidRoute.Put("/", bind(models.UpdateFolderCommand{}), Wrap(UpdateFolder)) - folderUidRoute.Delete("/", Wrap(DeleteFolder)) + folderUidRoute.Get("/", routing.Wrap(GetFolderByUID)) + folderUidRoute.Put("/", bind(models.UpdateFolderCommand{}), routing.Wrap(UpdateFolder)) + folderUidRoute.Delete("/", routing.Wrap(DeleteFolder)) folderUidRoute.Group("/permissions", func(folderPermissionRoute routing.RouteRegister) { - folderPermissionRoute.Get("/", Wrap(hs.GetFolderPermissionList)) - folderPermissionRoute.Post("/", bind(dtos.UpdateDashboardAclCommand{}), Wrap(hs.UpdateFolderPermissions)) + folderPermissionRoute.Get("/", routing.Wrap(hs.GetFolderPermissionList)) + folderPermissionRoute.Post("/", bind(dtos.UpdateDashboardAclCommand{}), routing.Wrap(hs.UpdateFolderPermissions)) }) }) }) // Dashboard apiRoute.Group("/dashboards", func(dashboardRoute routing.RouteRegister) { - dashboardRoute.Get("/uid/:uid", Wrap(hs.GetDashboard)) - dashboardRoute.Delete("/uid/:uid", Wrap(DeleteDashboardByUID)) + dashboardRoute.Get("/uid/:uid", routing.Wrap(hs.GetDashboard)) + dashboardRoute.Delete("/uid/:uid", routing.Wrap(DeleteDashboardByUID)) - dashboardRoute.Get("/db/:slug", Wrap(hs.GetDashboard)) - dashboardRoute.Delete("/db/:slug", Wrap(DeleteDashboardBySlug)) + dashboardRoute.Get("/db/:slug", routing.Wrap(hs.GetDashboard)) + dashboardRoute.Delete("/db/:slug", routing.Wrap(DeleteDashboardBySlug)) - dashboardRoute.Post("/calculate-diff", bind(dtos.CalculateDiffOptions{}), Wrap(CalculateDashboardDiff)) + dashboardRoute.Post("/calculate-diff", bind(dtos.CalculateDiffOptions{}), routing.Wrap(CalculateDashboardDiff)) - dashboardRoute.Post("/db", bind(models.SaveDashboardCommand{}), Wrap(hs.PostDashboard)) - dashboardRoute.Get("/home", Wrap(hs.GetHomeDashboard)) + dashboardRoute.Post("/db", bind(models.SaveDashboardCommand{}), routing.Wrap(hs.PostDashboard)) + dashboardRoute.Get("/home", routing.Wrap(hs.GetHomeDashboard)) dashboardRoute.Get("/tags", GetDashboardTags) - dashboardRoute.Post("/import", bind(dtos.ImportDashboardCommand{}), Wrap(ImportDashboard)) + dashboardRoute.Post("/import", bind(dtos.ImportDashboardCommand{}), routing.Wrap(ImportDashboard)) dashboardRoute.Group("/id/:dashboardId", func(dashIdRoute routing.RouteRegister) { - dashIdRoute.Get("/versions", Wrap(GetDashboardVersions)) - dashIdRoute.Get("/versions/:id", Wrap(GetDashboardVersion)) - dashIdRoute.Post("/restore", bind(dtos.RestoreDashboardVersionCommand{}), Wrap(hs.RestoreDashboardVersion)) + dashIdRoute.Get("/versions", routing.Wrap(GetDashboardVersions)) + dashIdRoute.Get("/versions/:id", routing.Wrap(GetDashboardVersion)) + dashIdRoute.Post("/restore", bind(dtos.RestoreDashboardVersionCommand{}), routing.Wrap(hs.RestoreDashboardVersion)) dashIdRoute.Group("/permissions", func(dashboardPermissionRoute routing.RouteRegister) { - dashboardPermissionRoute.Get("/", Wrap(hs.GetDashboardPermissionList)) - dashboardPermissionRoute.Post("/", bind(dtos.UpdateDashboardAclCommand{}), Wrap(hs.UpdateDashboardPermissions)) + dashboardPermissionRoute.Get("/", routing.Wrap(hs.GetDashboardPermissionList)) + dashboardPermissionRoute.Post("/", bind(dtos.UpdateDashboardAclCommand{}), routing.Wrap(hs.UpdateDashboardPermissions)) }) }) }) // Dashboard snapshots apiRoute.Group("/dashboard/snapshots", func(dashboardRoute routing.RouteRegister) { - dashboardRoute.Get("/", Wrap(SearchDashboardSnapshots)) + dashboardRoute.Get("/", routing.Wrap(SearchDashboardSnapshots)) }) // Playlist apiRoute.Group("/playlists", func(playlistRoute routing.RouteRegister) { - playlistRoute.Get("/", Wrap(SearchPlaylists)) - playlistRoute.Get("/:id", ValidateOrgPlaylist, Wrap(GetPlaylist)) - playlistRoute.Get("/:id/items", ValidateOrgPlaylist, Wrap(GetPlaylistItems)) - playlistRoute.Get("/:id/dashboards", ValidateOrgPlaylist, Wrap(GetPlaylistDashboards)) - playlistRoute.Delete("/:id", reqEditorRole, ValidateOrgPlaylist, Wrap(DeletePlaylist)) - playlistRoute.Put("/:id", reqEditorRole, bind(models.UpdatePlaylistCommand{}), ValidateOrgPlaylist, Wrap(UpdatePlaylist)) - playlistRoute.Post("/", reqEditorRole, bind(models.CreatePlaylistCommand{}), Wrap(CreatePlaylist)) + playlistRoute.Get("/", routing.Wrap(SearchPlaylists)) + playlistRoute.Get("/:id", ValidateOrgPlaylist, routing.Wrap(GetPlaylist)) + playlistRoute.Get("/:id/items", ValidateOrgPlaylist, routing.Wrap(GetPlaylistItems)) + playlistRoute.Get("/:id/dashboards", ValidateOrgPlaylist, routing.Wrap(GetPlaylistDashboards)) + playlistRoute.Delete("/:id", reqEditorRole, ValidateOrgPlaylist, routing.Wrap(DeletePlaylist)) + playlistRoute.Put("/:id", reqEditorRole, bind(models.UpdatePlaylistCommand{}), ValidateOrgPlaylist, routing.Wrap(UpdatePlaylist)) + playlistRoute.Post("/", reqEditorRole, bind(models.CreatePlaylistCommand{}), routing.Wrap(CreatePlaylist)) }) // Search - apiRoute.Get("/search/sorting", Wrap(hs.ListSortOptions)) - apiRoute.Get("/search/", Wrap(Search)) + apiRoute.Get("/search/sorting", routing.Wrap(hs.ListSortOptions)) + apiRoute.Get("/search/", routing.Wrap(Search)) // metrics - apiRoute.Post("/tsdb/query", bind(dtos.MetricRequest{}), Wrap(hs.QueryMetrics)) - apiRoute.Get("/tsdb/testdata/scenarios", Wrap(GetTestDataScenarios)) - apiRoute.Get("/tsdb/testdata/gensql", reqGrafanaAdmin, Wrap(GenerateSQLTestData)) - apiRoute.Get("/tsdb/testdata/random-walk", Wrap(GetTestDataRandomWalk)) + apiRoute.Post("/tsdb/query", bind(dtos.MetricRequest{}), routing.Wrap(hs.QueryMetrics)) + apiRoute.Get("/tsdb/testdata/scenarios", routing.Wrap(GetTestDataScenarios)) + apiRoute.Get("/tsdb/testdata/gensql", reqGrafanaAdmin, routing.Wrap(GenerateSQLTestData)) + apiRoute.Get("/tsdb/testdata/random-walk", routing.Wrap(GetTestDataRandomWalk)) // DataSource w/ expressions - apiRoute.Post("/ds/query", bind(dtos.MetricRequest{}), Wrap(hs.QueryMetricsV2)) + apiRoute.Post("/ds/query", bind(dtos.MetricRequest{}), routing.Wrap(hs.QueryMetricsV2)) apiRoute.Group("/alerts", func(alertsRoute routing.RouteRegister) { - alertsRoute.Post("/test", bind(dtos.AlertTestCommand{}), Wrap(AlertTest)) - alertsRoute.Post("/:alertId/pause", reqEditorRole, bind(dtos.PauseAlertCommand{}), Wrap(PauseAlert)) - alertsRoute.Get("/:alertId", ValidateOrgAlert, Wrap(GetAlert)) - alertsRoute.Get("/", Wrap(GetAlerts)) - alertsRoute.Get("/states-for-dashboard", Wrap(GetAlertStatesForDashboard)) + alertsRoute.Post("/test", bind(dtos.AlertTestCommand{}), routing.Wrap(AlertTest)) + alertsRoute.Post("/:alertId/pause", reqEditorRole, bind(dtos.PauseAlertCommand{}), routing.Wrap(PauseAlert)) + alertsRoute.Get("/:alertId", ValidateOrgAlert, routing.Wrap(GetAlert)) + alertsRoute.Get("/", routing.Wrap(GetAlerts)) + alertsRoute.Get("/states-for-dashboard", routing.Wrap(GetAlertStatesForDashboard)) }) - apiRoute.Get("/alert-notifiers", reqEditorRole, Wrap(GetAlertNotifiers)) + apiRoute.Get("/alert-notifiers", reqEditorRole, routing.Wrap(GetAlertNotifiers)) apiRoute.Group("/alert-notifications", func(alertNotifications routing.RouteRegister) { - alertNotifications.Get("/", Wrap(GetAlertNotifications)) - alertNotifications.Post("/test", bind(dtos.NotificationTestCommand{}), Wrap(NotificationTest)) - alertNotifications.Post("/", bind(models.CreateAlertNotificationCommand{}), Wrap(CreateAlertNotification)) - alertNotifications.Put("/:notificationId", bind(models.UpdateAlertNotificationCommand{}), Wrap(UpdateAlertNotification)) - alertNotifications.Get("/:notificationId", Wrap(GetAlertNotificationByID)) - alertNotifications.Delete("/:notificationId", Wrap(DeleteAlertNotification)) - alertNotifications.Get("/uid/:uid", Wrap(GetAlertNotificationByUID)) - alertNotifications.Put("/uid/:uid", bind(models.UpdateAlertNotificationWithUidCommand{}), Wrap(UpdateAlertNotificationByUID)) - alertNotifications.Delete("/uid/:uid", Wrap(DeleteAlertNotificationByUID)) + alertNotifications.Get("/", routing.Wrap(GetAlertNotifications)) + alertNotifications.Post("/test", bind(dtos.NotificationTestCommand{}), routing.Wrap(NotificationTest)) + alertNotifications.Post("/", bind(models.CreateAlertNotificationCommand{}), routing.Wrap(CreateAlertNotification)) + alertNotifications.Put("/:notificationId", bind(models.UpdateAlertNotificationCommand{}), routing.Wrap(UpdateAlertNotification)) + alertNotifications.Get("/:notificationId", routing.Wrap(GetAlertNotificationByID)) + alertNotifications.Delete("/:notificationId", routing.Wrap(DeleteAlertNotification)) + alertNotifications.Get("/uid/:uid", routing.Wrap(GetAlertNotificationByUID)) + alertNotifications.Put("/uid/:uid", bind(models.UpdateAlertNotificationWithUidCommand{}), routing.Wrap(UpdateAlertNotificationByUID)) + alertNotifications.Delete("/uid/:uid", routing.Wrap(DeleteAlertNotificationByUID)) }, reqEditorRole) // alert notifications without requirement of user to be org editor apiRoute.Group("/alert-notifications", func(orgRoute routing.RouteRegister) { - orgRoute.Get("/lookup", Wrap(GetAlertNotificationLookup)) + orgRoute.Get("/lookup", routing.Wrap(GetAlertNotificationLookup)) }) - apiRoute.Get("/annotations", Wrap(GetAnnotations)) - apiRoute.Post("/annotations/mass-delete", reqOrgAdmin, bind(dtos.DeleteAnnotationsCmd{}), Wrap(DeleteAnnotations)) + apiRoute.Get("/annotations", routing.Wrap(GetAnnotations)) + apiRoute.Post("/annotations/mass-delete", reqOrgAdmin, bind(dtos.DeleteAnnotationsCmd{}), routing.Wrap(DeleteAnnotations)) apiRoute.Group("/annotations", func(annotationsRoute routing.RouteRegister) { - annotationsRoute.Post("/", bind(dtos.PostAnnotationsCmd{}), Wrap(PostAnnotation)) - annotationsRoute.Delete("/:annotationId", Wrap(DeleteAnnotationByID)) - annotationsRoute.Put("/:annotationId", bind(dtos.UpdateAnnotationsCmd{}), Wrap(UpdateAnnotation)) - annotationsRoute.Patch("/:annotationId", bind(dtos.PatchAnnotationsCmd{}), Wrap(PatchAnnotation)) - annotationsRoute.Post("/graphite", reqEditorRole, bind(dtos.PostGraphiteAnnotationsCmd{}), Wrap(PostGraphiteAnnotation)) + annotationsRoute.Post("/", bind(dtos.PostAnnotationsCmd{}), routing.Wrap(PostAnnotation)) + annotationsRoute.Delete("/:annotationId", routing.Wrap(DeleteAnnotationByID)) + annotationsRoute.Put("/:annotationId", bind(dtos.UpdateAnnotationsCmd{}), routing.Wrap(UpdateAnnotation)) + annotationsRoute.Patch("/:annotationId", bind(dtos.PatchAnnotationsCmd{}), routing.Wrap(PatchAnnotation)) + annotationsRoute.Post("/graphite", reqEditorRole, bind(dtos.PostGraphiteAnnotationsCmd{}), routing.Wrap(PostGraphiteAnnotation)) }) // error test - r.Get("/metrics/error", Wrap(GenerateError)) + r.Get("/metrics/error", routing.Wrap(GenerateError)) // short urls - apiRoute.Post("/short-urls", bind(dtos.CreateShortURLCmd{}), Wrap(hs.createShortURL)) + apiRoute.Post("/short-urls", bind(dtos.CreateShortURLCmd{}), routing.Wrap(hs.createShortURL)) }, reqSignedIn) // admin api r.Group("/api/admin", func(adminRoute routing.RouteRegister) { - adminRoute.Get("/settings", Wrap(AdminGetSettings)) - adminRoute.Post("/users", bind(dtos.AdminCreateUserForm{}), Wrap(AdminCreateUser)) - adminRoute.Put("/users/:id/password", bind(dtos.AdminUpdateUserPasswordForm{}), Wrap(AdminUpdateUserPassword)) - adminRoute.Put("/users/:id/permissions", bind(dtos.AdminUpdateUserPermissionsForm{}), Wrap(AdminUpdateUserPermissions)) - adminRoute.Delete("/users/:id", Wrap(AdminDeleteUser)) - adminRoute.Post("/users/:id/disable", Wrap(hs.AdminDisableUser)) - adminRoute.Post("/users/:id/enable", Wrap(AdminEnableUser)) - adminRoute.Get("/users/:id/quotas", Wrap(GetUserQuotas)) - adminRoute.Put("/users/:id/quotas/:target", bind(models.UpdateUserQuotaCmd{}), Wrap(UpdateUserQuota)) - adminRoute.Get("/stats", Wrap(AdminGetStats)) - adminRoute.Post("/pause-all-alerts", bind(dtos.PauseAllAlertsCommand{}), Wrap(PauseAllAlerts)) + adminRoute.Get("/settings", routing.Wrap(AdminGetSettings)) + adminRoute.Post("/users", bind(dtos.AdminCreateUserForm{}), routing.Wrap(AdminCreateUser)) + adminRoute.Put("/users/:id/password", bind(dtos.AdminUpdateUserPasswordForm{}), routing.Wrap(AdminUpdateUserPassword)) + adminRoute.Put("/users/:id/permissions", bind(dtos.AdminUpdateUserPermissionsForm{}), routing.Wrap(AdminUpdateUserPermissions)) + adminRoute.Delete("/users/:id", routing.Wrap(AdminDeleteUser)) + adminRoute.Post("/users/:id/disable", routing.Wrap(hs.AdminDisableUser)) + adminRoute.Post("/users/:id/enable", routing.Wrap(AdminEnableUser)) + adminRoute.Get("/users/:id/quotas", routing.Wrap(GetUserQuotas)) + adminRoute.Put("/users/:id/quotas/:target", bind(models.UpdateUserQuotaCmd{}), routing.Wrap(UpdateUserQuota)) + adminRoute.Get("/stats", routing.Wrap(AdminGetStats)) + adminRoute.Post("/pause-all-alerts", bind(dtos.PauseAllAlertsCommand{}), routing.Wrap(PauseAllAlerts)) - adminRoute.Post("/users/:id/logout", Wrap(hs.AdminLogoutUser)) - adminRoute.Get("/users/:id/auth-tokens", Wrap(hs.AdminGetUserAuthTokens)) - adminRoute.Post("/users/:id/revoke-auth-token", bind(models.RevokeAuthTokenCmd{}), Wrap(hs.AdminRevokeUserAuthToken)) + adminRoute.Post("/users/:id/logout", routing.Wrap(hs.AdminLogoutUser)) + adminRoute.Get("/users/:id/auth-tokens", routing.Wrap(hs.AdminGetUserAuthTokens)) + adminRoute.Post("/users/:id/revoke-auth-token", bind(models.RevokeAuthTokenCmd{}), routing.Wrap(hs.AdminRevokeUserAuthToken)) - adminRoute.Post("/provisioning/dashboards/reload", Wrap(hs.AdminProvisioningReloadDashboards)) - adminRoute.Post("/provisioning/plugins/reload", Wrap(hs.AdminProvisioningReloadPlugins)) - adminRoute.Post("/provisioning/datasources/reload", Wrap(hs.AdminProvisioningReloadDatasources)) - adminRoute.Post("/provisioning/notifications/reload", Wrap(hs.AdminProvisioningReloadNotifications)) - adminRoute.Post("/ldap/reload", Wrap(hs.ReloadLDAPCfg)) - adminRoute.Post("/ldap/sync/:id", Wrap(hs.PostSyncUserWithLDAP)) - adminRoute.Get("/ldap/:username", Wrap(hs.GetUserFromLDAP)) - adminRoute.Get("/ldap/status", Wrap(hs.GetLDAPStatus)) + adminRoute.Post("/provisioning/dashboards/reload", routing.Wrap(hs.AdminProvisioningReloadDashboards)) + adminRoute.Post("/provisioning/plugins/reload", routing.Wrap(hs.AdminProvisioningReloadPlugins)) + adminRoute.Post("/provisioning/datasources/reload", routing.Wrap(hs.AdminProvisioningReloadDatasources)) + adminRoute.Post("/provisioning/notifications/reload", routing.Wrap(hs.AdminProvisioningReloadNotifications)) + adminRoute.Post("/ldap/reload", routing.Wrap(hs.ReloadLDAPCfg)) + adminRoute.Post("/ldap/sync/:id", routing.Wrap(hs.PostSyncUserWithLDAP)) + adminRoute.Get("/ldap/:username", routing.Wrap(hs.GetUserFromLDAP)) + adminRoute.Get("/ldap/status", routing.Wrap(hs.GetLDAPStatus)) }, reqGrafanaAdmin) // rendering @@ -443,10 +443,10 @@ func (hs *HTTPServer) registerRoutes() { // Snapshots r.Post("/api/snapshots/", reqSnapshotPublicModeOrSignedIn, bind(models.CreateDashboardSnapshotCommand{}), CreateDashboardSnapshot) r.Get("/api/snapshot/shared-options/", reqSignedIn, GetSharingOptions) - r.Get("/api/snapshots/:key", Wrap(GetDashboardSnapshot)) - r.Get("/api/snapshots-delete/:deleteKey", reqSnapshotPublicModeOrSignedIn, Wrap(DeleteDashboardSnapshotByDeleteKey)) - r.Delete("/api/snapshots/:key", reqEditorRole, Wrap(DeleteDashboardSnapshot)) + r.Get("/api/snapshots/:key", routing.Wrap(GetDashboardSnapshot)) + r.Get("/api/snapshots-delete/:deleteKey", reqSnapshotPublicModeOrSignedIn, routing.Wrap(DeleteDashboardSnapshotByDeleteKey)) + r.Delete("/api/snapshots/:key", reqEditorRole, routing.Wrap(DeleteDashboardSnapshot)) // Frontend logs - r.Post("/log", middleware.RateLimit(hs.Cfg.Sentry.EndpointRPS, hs.Cfg.Sentry.EndpointBurst, time.Now), bind(frontendSentryEvent{}), Wrap(hs.logFrontendMessage)) + r.Post("/log", middleware.RateLimit(hs.Cfg.Sentry.EndpointRPS, hs.Cfg.Sentry.EndpointBurst, time.Now), bind(frontendSentryEvent{}), routing.Wrap(hs.logFrontendMessage)) } diff --git a/pkg/api/apikey.go b/pkg/api/apikey.go index f3ad3c4b64d..36725995596 100644 --- a/pkg/api/apikey.go +++ b/pkg/api/apikey.go @@ -5,16 +5,17 @@ import ( "time" "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/components/apikeygen" "github.com/grafana/grafana/pkg/models" ) -func GetAPIKeys(c *models.ReqContext) Response { +func GetAPIKeys(c *models.ReqContext) response.Response { query := models.GetApiKeysQuery{OrgId: c.OrgId, IncludeExpired: c.QueryBool("includeExpired")} if err := bus.Dispatch(&query); err != nil { - return Error(500, "Failed to list api keys", err) + return response.Error(500, "Failed to list api keys", err) } result := make([]*models.ApiKeyDTO, len(query.Result)) @@ -32,52 +33,52 @@ func GetAPIKeys(c *models.ReqContext) Response { } } - return JSON(200, result) + return response.JSON(200, result) } -func DeleteAPIKey(c *models.ReqContext) Response { +func DeleteAPIKey(c *models.ReqContext) response.Response { id := c.ParamsInt64(":id") cmd := &models.DeleteApiKeyCommand{Id: id, OrgId: c.OrgId} err := bus.Dispatch(cmd) if err != nil { - return Error(500, "Failed to delete API key", err) + return response.Error(500, "Failed to delete API key", err) } - return Success("API key deleted") + return response.Success("API key deleted") } -func (hs *HTTPServer) AddAPIKey(c *models.ReqContext, cmd models.AddApiKeyCommand) Response { +func (hs *HTTPServer) AddAPIKey(c *models.ReqContext, cmd models.AddApiKeyCommand) response.Response { if !cmd.Role.IsValid() { - return Error(400, "Invalid role specified", nil) + return response.Error(400, "Invalid role specified", nil) } if hs.Cfg.ApiKeyMaxSecondsToLive != -1 { if cmd.SecondsToLive == 0 { - return Error(400, "Number of seconds before expiration should be set", nil) + return response.Error(400, "Number of seconds before expiration should be set", nil) } if cmd.SecondsToLive > hs.Cfg.ApiKeyMaxSecondsToLive { - return Error(400, "Number of seconds before expiration is greater than the global limit", nil) + return response.Error(400, "Number of seconds before expiration is greater than the global limit", nil) } } cmd.OrgId = c.OrgId newKeyInfo, err := apikeygen.New(cmd.OrgId, cmd.Name) if err != nil { - return Error(500, "Generating API key failed", err) + return response.Error(500, "Generating API key failed", err) } cmd.Key = newKeyInfo.HashedKey if err := bus.Dispatch(&cmd); err != nil { if errors.Is(err, models.ErrInvalidApiKeyExpiration) { - return Error(400, err.Error(), nil) + return response.Error(400, err.Error(), nil) } if errors.Is(err, models.ErrDuplicateApiKey) { - return Error(409, err.Error(), nil) + return response.Error(409, err.Error(), nil) } - return Error(500, "Failed to add API Key", err) + return response.Error(500, "Failed to add API Key", err) } result := &dtos.NewApiKeyResult{ @@ -86,5 +87,5 @@ func (hs *HTTPServer) AddAPIKey(c *models.ReqContext, cmd models.AddApiKeyComman Key: newKeyInfo.ClientSecret, } - return JSON(200, result) + return response.JSON(200, result) } diff --git a/pkg/api/common.go b/pkg/api/common.go deleted file mode 100644 index 36faa1f917b..00000000000 --- a/pkg/api/common.go +++ /dev/null @@ -1,109 +0,0 @@ -package api - -import ( - "encoding/json" - "net/http" - - "github.com/grafana/grafana/pkg/models" - "github.com/grafana/grafana/pkg/setting" - "gopkg.in/macaron.v1" -) - -var ( - ServerError = func(err error) Response { - return Error(500, "Server error", err) - } -) - -func Wrap(action interface{}) macaron.Handler { - return func(c *models.ReqContext) { - var res Response - val, err := c.Invoke(action) - if err == nil && val != nil && len(val) > 0 { - res = val[0].Interface().(Response) - } else { - res = ServerError(err) - } - - res.WriteTo(c) - } -} - -// JSON creates a JSON response. -func JSON(status int, body interface{}) *NormalResponse { - return Respond(status, body).Header("Content-Type", "application/json") -} - -// jsonStreaming creates a streaming JSON response. -func jsonStreaming(status int, body interface{}) streamingResponse { - header := make(http.Header) - header.Set("Content-Type", "application/json") - return streamingResponse{ - status: status, - body: body, - header: header, - } -} - -// Success create a successful response -func Success(message string) *NormalResponse { - resp := make(map[string]interface{}) - resp["message"] = message - return JSON(200, resp) -} - -// Error creates an error response. -func Error(status int, message string, err error) *NormalResponse { - data := make(map[string]interface{}) - - switch status { - case 404: - data["message"] = "Not Found" - case 500: - data["message"] = "Internal Server Error" - } - - if message != "" { - data["message"] = message - } - - if err != nil { - if setting.Env != setting.Prod { - data["error"] = err.Error() - } - } - - resp := JSON(status, data) - - if err != nil { - resp.errMessage = message - resp.err = err - } - - return resp -} - -// Respond creates a response. -func Respond(status int, body interface{}) *NormalResponse { - var b []byte - switch t := body.(type) { - case []byte: - b = t - case string: - b = []byte(t) - default: - var err error - if b, err = json.Marshal(body); err != nil { - return Error(500, "body json marshal", err) - } - } - return &NormalResponse{ - body: b, - status: status, - header: make(http.Header), - } -} - -func Redirect(location string) *RedirectResponse { - return &RedirectResponse{location: location} -} diff --git a/pkg/api/common_test.go b/pkg/api/common_test.go index f6e0b9e9677..5784cc47576 100644 --- a/pkg/api/common_test.go +++ b/pkg/api/common_test.go @@ -7,6 +7,8 @@ import ( "path/filepath" "testing" + "github.com/grafana/grafana/pkg/api/response" + "github.com/grafana/grafana/pkg/api/routing" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/infra/fs" "github.com/grafana/grafana/pkg/infra/remotecache" @@ -30,7 +32,7 @@ func loggedInUserScenarioWithRole(t *testing.T, desc string, method string, url t.Cleanup(bus.ClearBusHandlers) sc := setupScenarioContext(t, url) - sc.defaultHandler = Wrap(func(c *models.ReqContext) Response { + sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.context = c sc.context.UserId = testUserID sc.context.OrgId = testOrgID @@ -59,7 +61,7 @@ func anonymousUserScenario(t *testing.T, desc string, method string, url string, defer bus.ClearBusHandlers() sc := setupScenarioContext(t, url) - sc.defaultHandler = Wrap(func(c *models.ReqContext) Response { + sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.context = c if sc.handlerFunc != nil { return sc.handlerFunc(sc.context) @@ -146,7 +148,7 @@ func (sc *scenarioContext) exec() { } type scenarioFunc func(c *scenarioContext) -type handlerFunc func(c *models.ReqContext) Response +type handlerFunc func(c *models.ReqContext) response.Response func getContextHandler(t *testing.T, cfg *setting.Cfg) *contexthandler.ContextHandler { t.Helper() diff --git a/pkg/api/dashboard.go b/pkg/api/dashboard.go index 2e0002aa5f3..d9b2f5ec676 100644 --- a/pkg/api/dashboard.go +++ b/pkg/api/dashboard.go @@ -12,6 +12,7 @@ import ( "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/components/dashdiffs" "github.com/grafana/grafana/pkg/components/simplejson" @@ -38,15 +39,15 @@ func isDashboardStarredByUser(c *models.ReqContext, dashID int64) (bool, error) return query.Result, nil } -func dashboardGuardianResponse(err error) Response { +func dashboardGuardianResponse(err error) response.Response { if err != nil { - return Error(500, "Error while checking dashboard permissions", err) + return response.Error(500, "Error while checking dashboard permissions", err) } - return Error(403, "Access denied to this dashboard", nil) + return response.Error(403, "Access denied to this dashboard", nil) } -func (hs *HTTPServer) GetDashboard(c *models.ReqContext) Response { +func (hs *HTTPServer) GetDashboard(c *models.ReqContext) response.Response { slug := c.Params(":slug") uid := c.Params(":uid") dash, rsp := getDashboardHelper(c.OrgId, slug, 0, uid) @@ -64,7 +65,7 @@ func (hs *HTTPServer) GetDashboard(c *models.ReqContext) Response { } } if isEmptyData { - return Error(500, "Error while loading dashboard, dashboard data is invalid", nil) + return response.Error(500, "Error while loading dashboard, dashboard data is invalid", nil) } } @@ -79,7 +80,7 @@ func (hs *HTTPServer) GetDashboard(c *models.ReqContext) Response { isStarred, err := isDashboardStarredByUser(c, dash.Id) if err != nil { - return Error(500, "Error while checking if dashboard was starred by user", err) + return response.Error(500, "Error while checking if dashboard was starred by user", err) } // Finding creator and last updater of the dashboard @@ -115,7 +116,7 @@ func (hs *HTTPServer) GetDashboard(c *models.ReqContext) Response { if dash.FolderId > 0 { query := models.GetDashboardQuery{Id: dash.FolderId, OrgId: c.OrgId} if err := bus.Dispatch(&query); err != nil { - return Error(500, "Dashboard folder could not be read", err) + return response.Error(500, "Dashboard folder could not be read", err) } meta.FolderTitle = query.Result.Title meta.FolderUrl = query.Result.GetUrl() @@ -123,7 +124,7 @@ func (hs *HTTPServer) GetDashboard(c *models.ReqContext) Response { provisioningData, err := dashboards.NewProvisioningService().GetProvisionedDashboardDataByDashboardID(dash.Id) if err != nil { - return Error(500, "Error while checking if dashboard is provisioned", err) + return response.Error(500, "Error while checking if dashboard is provisioned", err) } if provisioningData != nil { @@ -152,7 +153,7 @@ func (hs *HTTPServer) GetDashboard(c *models.ReqContext) Response { } c.TimeRequest(metrics.MApiDashboardGet) - return JSON(200, dto) + return response.JSON(200, dto) } func getUserLogin(userID int64) string { @@ -164,7 +165,7 @@ func getUserLogin(userID int64) string { return query.Result.Login } -func getDashboardHelper(orgID int64, slug string, id int64, uid string) (*models.Dashboard, Response) { +func getDashboardHelper(orgID int64, slug string, id int64, uid string) (*models.Dashboard, response.Response) { var query models.GetDashboardQuery if len(uid) > 0 { @@ -174,31 +175,31 @@ func getDashboardHelper(orgID int64, slug string, id int64, uid string) (*models } if err := bus.Dispatch(&query); err != nil { - return nil, Error(404, "Dashboard not found", err) + return nil, response.Error(404, "Dashboard not found", err) } return query.Result, nil } -func DeleteDashboardBySlug(c *models.ReqContext) Response { +func DeleteDashboardBySlug(c *models.ReqContext) response.Response { query := models.GetDashboardsBySlugQuery{OrgId: c.OrgId, Slug: c.Params(":slug")} if err := bus.Dispatch(&query); err != nil { - return Error(500, "Failed to retrieve dashboards by slug", err) + return response.Error(500, "Failed to retrieve dashboards by slug", err) } if len(query.Result) > 1 { - return JSON(412, util.DynMap{"status": "multiple-slugs-exists", "message": models.ErrDashboardsWithSameSlugExists.Error()}) + return response.JSON(412, util.DynMap{"status": "multiple-slugs-exists", "message": models.ErrDashboardsWithSameSlugExists.Error()}) } return deleteDashboard(c) } -func DeleteDashboardByUID(c *models.ReqContext) Response { +func DeleteDashboardByUID(c *models.ReqContext) response.Response { return deleteDashboard(c) } -func deleteDashboard(c *models.ReqContext) Response { +func deleteDashboard(c *models.ReqContext) response.Response { dash, rsp := getDashboardHelper(c.OrgId, c.Params(":slug"), 0, c.Params(":uid")) if rsp != nil { return rsp @@ -214,21 +215,21 @@ func deleteDashboard(c *models.ReqContext) Response { var dashboardErr models.DashboardErr if ok := errors.As(err, &dashboardErr); ok { if errors.Is(err, models.ErrDashboardCannotDeleteProvisionedDashboard) { - return Error(dashboardErr.StatusCode, dashboardErr.Error(), err) + return response.Error(dashboardErr.StatusCode, dashboardErr.Error(), err) } } - return Error(500, "Failed to delete dashboard", err) + return response.Error(500, "Failed to delete dashboard", err) } - return JSON(200, util.DynMap{ + return response.JSON(200, util.DynMap{ "title": dash.Title, "message": fmt.Sprintf("Dashboard %s deleted", dash.Title), "id": dash.Id, }) } -func (hs *HTTPServer) PostDashboard(c *models.ReqContext, cmd models.SaveDashboardCommand) Response { +func (hs *HTTPServer) PostDashboard(c *models.ReqContext, cmd models.SaveDashboardCommand) response.Response { cmd.OrgId = c.OrgId cmd.UserId = c.UserId @@ -238,16 +239,16 @@ func (hs *HTTPServer) PostDashboard(c *models.ReqContext, cmd models.SaveDashboa if newDashboard { limitReached, err := hs.QuotaService.QuotaReached(c, "dashboard") if err != nil { - return Error(500, "failed to get quota", err) + return response.Error(500, "failed to get quota", err) } if limitReached { - return Error(403, "Quota reached", nil) + return response.Error(403, "Quota reached", nil) } } provisioningData, err := dashboards.NewProvisioningService().GetProvisionedDashboardDataByDashboardID(dash.Id) if err != nil { - return Error(500, "Error while checking if dashboard is provisioned", err) + return response.Error(500, "Error while checking if dashboard is provisioned", err) } allowUiUpdate := true @@ -288,7 +289,7 @@ func (hs *HTTPServer) PostDashboard(c *models.ReqContext, cmd models.SaveDashboa } c.TimeRequest(metrics.MApiDashboardSave) - return JSON(200, util.DynMap{ + return response.JSON(200, util.DynMap{ "status": "success", "slug": dashboard.Slug, "version": dashboard.Version, @@ -298,25 +299,25 @@ func (hs *HTTPServer) PostDashboard(c *models.ReqContext, cmd models.SaveDashboa }) } -func dashboardSaveErrorToApiResponse(err error) Response { +func dashboardSaveErrorToApiResponse(err error) response.Response { var dashboardErr models.DashboardErr if ok := errors.As(err, &dashboardErr); ok { if body := dashboardErr.Body(); body != nil { - return JSON(dashboardErr.StatusCode, body) + return response.JSON(dashboardErr.StatusCode, body) } if errors.Is(dashboardErr, models.ErrDashboardUpdateAccessDenied) { - return Error(dashboardErr.StatusCode, dashboardErr.Error(), err) + return response.Error(dashboardErr.StatusCode, dashboardErr.Error(), err) } - return Error(dashboardErr.StatusCode, dashboardErr.Error(), nil) + return response.Error(dashboardErr.StatusCode, dashboardErr.Error(), nil) } if errors.Is(err, models.ErrFolderNotFound) { - return Error(400, err.Error(), nil) + return response.Error(400, err.Error(), nil) } var validationErr alerting.ValidationError if ok := errors.As(err, &validationErr); ok { - return Error(422, validationErr.Error(), nil) + return response.Error(422, validationErr.Error(), nil) } var pluginErr models.UpdatePluginDashboardError @@ -326,17 +327,17 @@ func dashboardSaveErrorToApiResponse(err error) Response { if pluginDef, exist := plugins.Plugins[pluginErr.PluginId]; exist { message = fmt.Sprintf("The dashboard belongs to plugin %s.", pluginDef.Name) } - return JSON(412, util.DynMap{"status": "plugin-dashboard", "message": message}) + return response.JSON(412, util.DynMap{"status": "plugin-dashboard", "message": message}) } - return Error(500, "Failed to save dashboard", err) + return response.Error(500, "Failed to save dashboard", err) } // GetHomeDashboard returns the home dashboard. -func (hs *HTTPServer) GetHomeDashboard(c *models.ReqContext) Response { +func (hs *HTTPServer) GetHomeDashboard(c *models.ReqContext) response.Response { prefsQuery := models.GetPreferencesWithDefaultsQuery{User: c.SignedInUser} if err := hs.Bus.Dispatch(&prefsQuery); err != nil { - return Error(500, "Failed to get preferences", err) + return response.Error(500, "Failed to get preferences", err) } if prefsQuery.Result.HomeDashboardId != 0 { @@ -345,7 +346,7 @@ func (hs *HTTPServer) GetHomeDashboard(c *models.ReqContext) Response { if err == nil { url := models.GetDashboardUrl(slugQuery.Result.Uid, slugQuery.Result.Slug) dashRedirect := dtos.DashboardRedirect{RedirectUri: url} - return JSON(200, &dashRedirect) + return response.JSON(200, &dashRedirect) } hs.log.Warn("Failed to get slug from database", "err", err) } @@ -360,7 +361,7 @@ func (hs *HTTPServer) GetHomeDashboard(c *models.ReqContext) Response { // nolint:gosec file, err := os.Open(filePath) if err != nil { - return Error(500, "Failed to load home dashboard", err) + return response.Error(500, "Failed to load home dashboard", err) } defer func() { if err := file.Close(); err != nil { @@ -375,12 +376,12 @@ func (hs *HTTPServer) GetHomeDashboard(c *models.ReqContext) Response { jsonParser := json.NewDecoder(file) if err := jsonParser.Decode(&dash.Dashboard); err != nil { - return Error(500, "Failed to load home dashboard", err) + return response.Error(500, "Failed to load home dashboard", err) } hs.addGettingStartedPanelToHomeDashboard(c, dash.Dashboard) - return JSON(200, &dash) + return response.JSON(200, &dash) } func (hs *HTTPServer) addGettingStartedPanelToHomeDashboard(c *models.ReqContext, dash *simplejson.Json) { @@ -410,7 +411,7 @@ func (hs *HTTPServer) addGettingStartedPanelToHomeDashboard(c *models.ReqContext } // GetDashboardVersions returns all dashboard versions as JSON -func GetDashboardVersions(c *models.ReqContext) Response { +func GetDashboardVersions(c *models.ReqContext) response.Response { dashID := c.ParamsInt64(":dashboardId") guardian := guardian.New(dashID, c.OrgId, c.SignedInUser) @@ -426,7 +427,7 @@ func GetDashboardVersions(c *models.ReqContext) Response { } if err := bus.Dispatch(&query); err != nil { - return Error(404, fmt.Sprintf("No versions found for dashboardId %d", dashID), err) + return response.Error(404, fmt.Sprintf("No versions found for dashboardId %d", dashID), err) } for _, version := range query.Result { @@ -445,11 +446,11 @@ func GetDashboardVersions(c *models.ReqContext) Response { } } - return JSON(200, query.Result) + return response.JSON(200, query.Result) } // GetDashboardVersion returns the dashboard version with the given ID. -func GetDashboardVersion(c *models.ReqContext) Response { +func GetDashboardVersion(c *models.ReqContext) response.Response { dashID := c.ParamsInt64(":dashboardId") guardian := guardian.New(dashID, c.OrgId, c.SignedInUser) @@ -464,7 +465,7 @@ func GetDashboardVersion(c *models.ReqContext) Response { } if err := bus.Dispatch(&query); err != nil { - return Error(500, fmt.Sprintf("Dashboard version %d not found for dashboardId %d", query.Version, dashID), err) + return response.Error(500, fmt.Sprintf("Dashboard version %d not found for dashboardId %d", query.Version, dashID), err) } creator := anonString @@ -484,11 +485,11 @@ func GetDashboardVersion(c *models.ReqContext) Response { CreatedBy: creator, } - return JSON(200, dashVersionMeta) + return response.JSON(200, dashVersionMeta) } // POST /api/dashboards/calculate-diff performs diffs on two dashboards -func CalculateDashboardDiff(c *models.ReqContext, apiOptions dtos.CalculateDiffOptions) Response { +func CalculateDashboardDiff(c *models.ReqContext, apiOptions dtos.CalculateDiffOptions) response.Response { guardianBase := guardian.New(apiOptions.Base.DashboardId, c.OrgId, c.SignedInUser) if canSave, err := guardianBase.CanSave(); err != nil || !canSave { return dashboardGuardianResponse(err) @@ -519,20 +520,20 @@ func CalculateDashboardDiff(c *models.ReqContext, apiOptions dtos.CalculateDiffO result, err := dashdiffs.CalculateDiff(&options) if err != nil { if errors.Is(err, models.ErrDashboardVersionNotFound) { - return Error(404, "Dashboard version not found", err) + return response.Error(404, "Dashboard version not found", err) } - return Error(500, "Unable to compute diff", err) + return response.Error(500, "Unable to compute diff", err) } if options.DiffType == dashdiffs.DiffDelta { - return Respond(200, result.Delta).Header("Content-Type", "application/json") + return response.Respond(200, result.Delta).Header("Content-Type", "application/json") } - return Respond(200, result.Delta).Header("Content-Type", "text/html") + return response.Respond(200, result.Delta).Header("Content-Type", "text/html") } // RestoreDashboardVersion restores a dashboard to the given version. -func (hs *HTTPServer) RestoreDashboardVersion(c *models.ReqContext, apiCmd dtos.RestoreDashboardVersionCommand) Response { +func (hs *HTTPServer) RestoreDashboardVersion(c *models.ReqContext, apiCmd dtos.RestoreDashboardVersionCommand) response.Response { dash, rsp := getDashboardHelper(c.OrgId, "", c.ParamsInt64(":dashboardId"), "") if rsp != nil { return rsp @@ -545,7 +546,7 @@ func (hs *HTTPServer) RestoreDashboardVersion(c *models.ReqContext, apiCmd dtos. versionQuery := models.GetDashboardVersionQuery{DashboardId: dash.Id, Version: apiCmd.Version, OrgId: c.OrgId} if err := bus.Dispatch(&versionQuery); err != nil { - return Error(404, "Dashboard version not found", nil) + return response.Error(404, "Dashboard version not found", nil) } version := versionQuery.Result diff --git a/pkg/api/dashboard_permission.go b/pkg/api/dashboard_permission.go index ec907f0f869..3d5c8553ecc 100644 --- a/pkg/api/dashboard_permission.go +++ b/pkg/api/dashboard_permission.go @@ -5,12 +5,13 @@ import ( "time" "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/guardian" ) -func (hs *HTTPServer) GetDashboardPermissionList(c *models.ReqContext) Response { +func (hs *HTTPServer) GetDashboardPermissionList(c *models.ReqContext) response.Response { dashID := c.ParamsInt64(":dashboardId") _, rsp := getDashboardHelper(c.OrgId, "", dashID, "") @@ -26,7 +27,7 @@ func (hs *HTTPServer) GetDashboardPermissionList(c *models.ReqContext) Response acl, err := g.GetAcl() if err != nil { - return Error(500, "Failed to get dashboard permissions", err) + return response.Error(500, "Failed to get dashboard permissions", err) } filteredAcls := make([]*models.DashboardAclInfoDTO, 0, len(acl)) @@ -47,12 +48,12 @@ func (hs *HTTPServer) GetDashboardPermissionList(c *models.ReqContext) Response filteredAcls = append(filteredAcls, perm) } - return JSON(200, filteredAcls) + return response.JSON(200, filteredAcls) } -func (hs *HTTPServer) UpdateDashboardPermissions(c *models.ReqContext, apiCmd dtos.UpdateDashboardAclCommand) Response { +func (hs *HTTPServer) UpdateDashboardPermissions(c *models.ReqContext, apiCmd dtos.UpdateDashboardAclCommand) response.Response { if err := validatePermissionsUpdate(apiCmd); err != nil { - return Error(400, err.Error(), err) + return response.Error(400, err.Error(), err) } dashID := c.ParamsInt64(":dashboardId") @@ -85,31 +86,31 @@ func (hs *HTTPServer) UpdateDashboardPermissions(c *models.ReqContext, apiCmd dt hiddenACL, err := g.GetHiddenACL(hs.Cfg) if err != nil { - return Error(500, "Error while retrieving hidden permissions", err) + return response.Error(500, "Error while retrieving hidden permissions", err) } cmd.Items = append(cmd.Items, hiddenACL...) if okToUpdate, err := g.CheckPermissionBeforeUpdate(models.PERMISSION_ADMIN, cmd.Items); err != nil || !okToUpdate { if err != nil { if errors.Is(err, guardian.ErrGuardianPermissionExists) || errors.Is(err, guardian.ErrGuardianOverride) { - return Error(400, err.Error(), err) + return response.Error(400, err.Error(), err) } - return Error(500, "Error while checking dashboard permissions", err) + return response.Error(500, "Error while checking dashboard permissions", err) } - return Error(403, "Cannot remove own admin permission for a folder", nil) + return response.Error(403, "Cannot remove own admin permission for a folder", nil) } if err := bus.Dispatch(&cmd); err != nil { if errors.Is(err, models.ErrDashboardAclInfoMissing) || errors.Is(err, models.ErrDashboardPermissionDashboardEmpty) { - return Error(409, err.Error(), err) + return response.Error(409, err.Error(), err) } - return Error(500, "Failed to create permission", err) + return response.Error(500, "Failed to create permission", err) } - return Success("Dashboard permissions updated") + return response.Success("Dashboard permissions updated") } func validatePermissionsUpdate(apiCmd dtos.UpdateDashboardAclCommand) error { diff --git a/pkg/api/dashboard_permission_test.go b/pkg/api/dashboard_permission_test.go index 01738250c68..20a9fe8e45b 100644 --- a/pkg/api/dashboard_permission_test.go +++ b/pkg/api/dashboard_permission_test.go @@ -6,6 +6,8 @@ import ( "testing" "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/api/response" + "github.com/grafana/grafana/pkg/api/routing" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/guardian" @@ -373,7 +375,7 @@ func updateDashboardPermissionScenario(t *testing.T, ctx updatePermissionContext sc := setupScenarioContext(t, ctx.url) - sc.defaultHandler = Wrap(func(c *models.ReqContext) Response { + sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.context = c sc.context.OrgId = testOrgID sc.context.UserId = testUserID diff --git a/pkg/api/dashboard_snapshot.go b/pkg/api/dashboard_snapshot.go index 2af175a1f0b..4f7a4b8d090 100644 --- a/pkg/api/dashboard_snapshot.go +++ b/pkg/api/dashboard_snapshot.go @@ -8,6 +8,7 @@ import ( "time" "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/infra/metrics" @@ -141,25 +142,25 @@ func CreateDashboardSnapshot(c *models.ReqContext, cmd models.CreateDashboardSna } // GET /api/snapshots/:key -func GetDashboardSnapshot(c *models.ReqContext) Response { +func GetDashboardSnapshot(c *models.ReqContext) response.Response { key := c.Params(":key") query := &models.GetDashboardSnapshotQuery{Key: key} err := bus.Dispatch(query) if err != nil { - return Error(500, "Failed to get dashboard snapshot", err) + return response.Error(500, "Failed to get dashboard snapshot", err) } snapshot := query.Result // expired snapshots should also be removed from db if snapshot.Expires.Before(time.Now()) { - return Error(404, "Dashboard snapshot not found", err) + return response.Error(404, "Dashboard snapshot not found", err) } dashboard, err := snapshot.DashboardJSON() if err != nil { - return Error(500, "Failed to get dashboard data for dashboard snapshot", err) + return response.Error(500, "Failed to get dashboard data for dashboard snapshot", err) } dto := dtos.DashboardFullWithMeta{ @@ -174,7 +175,7 @@ func GetDashboardSnapshot(c *models.ReqContext) Response { metrics.MApiDashboardSnapshotGet.Inc() - return JSON(200, dto).Header("Cache-Control", "public, max-age=3600") + return response.JSON(200, dto).Header("Cache-Control", "public, max-age=3600") } func deleteExternalDashboardSnapshot(externalUrl string) error { @@ -207,86 +208,86 @@ func deleteExternalDashboardSnapshot(externalUrl string) error { } // GET /api/snapshots-delete/:deleteKey -func DeleteDashboardSnapshotByDeleteKey(c *models.ReqContext) Response { +func DeleteDashboardSnapshotByDeleteKey(c *models.ReqContext) response.Response { key := c.Params(":deleteKey") query := &models.GetDashboardSnapshotQuery{DeleteKey: key} err := bus.Dispatch(query) if err != nil { - return Error(500, "Failed to get dashboard snapshot", err) + return response.Error(500, "Failed to get dashboard snapshot", err) } if query.Result.External { err := deleteExternalDashboardSnapshot(query.Result.ExternalDeleteUrl) if err != nil { - return Error(500, "Failed to delete external dashboard", err) + return response.Error(500, "Failed to delete external dashboard", err) } } cmd := &models.DeleteDashboardSnapshotCommand{DeleteKey: query.Result.DeleteKey} if err := bus.Dispatch(cmd); err != nil { - return Error(500, "Failed to delete dashboard snapshot", err) + return response.Error(500, "Failed to delete dashboard snapshot", err) } - return JSON(200, util.DynMap{ + return response.JSON(200, util.DynMap{ "message": "Snapshot deleted. It might take an hour before it's cleared from any CDN caches.", "id": query.Result.Id, }) } // DELETE /api/snapshots/:key -func DeleteDashboardSnapshot(c *models.ReqContext) Response { +func DeleteDashboardSnapshot(c *models.ReqContext) response.Response { key := c.Params(":key") query := &models.GetDashboardSnapshotQuery{Key: key} err := bus.Dispatch(query) if err != nil { - return Error(500, "Failed to get dashboard snapshot", err) + return response.Error(500, "Failed to get dashboard snapshot", err) } if query.Result == nil { - return Error(404, "Failed to get dashboard snapshot", nil) + return response.Error(404, "Failed to get dashboard snapshot", nil) } dashboard, err := query.Result.DashboardJSON() if err != nil { - return Error(500, "Failed to get dashboard data for dashboard snapshot", err) + return response.Error(500, "Failed to get dashboard data for dashboard snapshot", err) } dashboardID := dashboard.Get("id").MustInt64() guardian := guardian.New(dashboardID, c.OrgId, c.SignedInUser) canEdit, err := guardian.CanEdit() if err != nil { - return Error(500, "Error while checking permissions for snapshot", err) + return response.Error(500, "Error while checking permissions for snapshot", err) } if !canEdit && query.Result.UserId != c.SignedInUser.UserId { - return Error(403, "Access denied to this snapshot", nil) + return response.Error(403, "Access denied to this snapshot", nil) } if query.Result.External { err := deleteExternalDashboardSnapshot(query.Result.ExternalDeleteUrl) if err != nil { - return Error(500, "Failed to delete external dashboard", err) + return response.Error(500, "Failed to delete external dashboard", err) } } cmd := &models.DeleteDashboardSnapshotCommand{DeleteKey: query.Result.DeleteKey} if err := bus.Dispatch(cmd); err != nil { - return Error(500, "Failed to delete dashboard snapshot", err) + return response.Error(500, "Failed to delete dashboard snapshot", err) } - return JSON(200, util.DynMap{ + return response.JSON(200, util.DynMap{ "message": "Snapshot deleted. It might take an hour before it's cleared from any CDN caches.", "id": query.Result.Id, }) } // GET /api/dashboard/snapshots -func SearchDashboardSnapshots(c *models.ReqContext) Response { +func SearchDashboardSnapshots(c *models.ReqContext) response.Response { query := c.Query("query") limit := c.QueryInt("limit") @@ -303,7 +304,7 @@ func SearchDashboardSnapshots(c *models.ReqContext) Response { err := bus.Dispatch(&searchQuery) if err != nil { - return Error(500, "Search failed", err) + return response.Error(500, "Search failed", err) } dtos := make([]*models.DashboardSnapshotDTO, len(searchQuery.Result)) @@ -322,5 +323,5 @@ func SearchDashboardSnapshots(c *models.ReqContext) Response { } } - return JSON(200, dtos) + return response.JSON(200, dtos) } diff --git a/pkg/api/dashboard_test.go b/pkg/api/dashboard_test.go index d4bc7962c53..45d5d1b5cec 100644 --- a/pkg/api/dashboard_test.go +++ b/pkg/api/dashboard_test.go @@ -8,6 +8,8 @@ import ( "testing" "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/api/response" + "github.com/grafana/grafana/pkg/api/routing" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/models" @@ -61,9 +63,9 @@ func TestGetHomeDashboard(t *testing.T) { require.NoError(t, err, "must be able to marshal object to JSON") res := hs.GetHomeDashboard(req) - nr, ok := res.(*NormalResponse) + nr, ok := res.(*response.NormalResponse) require.True(t, ok, "should return *NormalResponse") - require.Equal(t, b, nr.body, "default home dashboard should equal content on disk") + require.Equal(t, b, nr.Body(), "default home dashboard should equal content on disk") }) } } @@ -1192,7 +1194,7 @@ func postDashboardScenario(t *testing.T, desc string, url string, routePattern s } sc := setupScenarioContext(t, url) - sc.defaultHandler = Wrap(func(c *models.ReqContext) Response { + sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.context = c sc.context.SignedInUser = &models.SignedInUser{OrgId: cmd.OrgId, UserId: cmd.UserId} @@ -1223,7 +1225,7 @@ func postDiffScenario(t *testing.T, desc string, url string, routePattern string defer bus.ClearBusHandlers() sc := setupScenarioContext(t, url) - sc.defaultHandler = Wrap(func(c *models.ReqContext) Response { + sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.context = c sc.context.SignedInUser = &models.SignedInUser{ OrgId: testOrgID, @@ -1255,7 +1257,7 @@ func restoreDashboardVersionScenario(t *testing.T, desc string, url string, rout } sc := setupScenarioContext(t, url) - sc.defaultHandler = Wrap(func(c *models.ReqContext) Response { + sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.context = c sc.context.SignedInUser = &models.SignedInUser{ OrgId: testOrgID, diff --git a/pkg/api/datasources.go b/pkg/api/datasources.go index b70a4a044a6..9a84c8caec4 100644 --- a/pkg/api/datasources.go +++ b/pkg/api/datasources.go @@ -9,6 +9,7 @@ import ( "github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana/pkg/api/datasource" "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/models" @@ -19,11 +20,11 @@ import ( var datasourcesLogger = log.New("datasources") -func (hs *HTTPServer) GetDataSources(c *models.ReqContext) Response { +func (hs *HTTPServer) GetDataSources(c *models.ReqContext) response.Response { query := models.GetDataSourcesQuery{OrgId: c.OrgId, DataSourceLimit: hs.Cfg.DataSourceLimit} if err := bus.Dispatch(&query); err != nil { - return Error(500, "Failed to query datasources", err) + return response.Error(500, "Failed to query datasources", err) } result := make(dtos.DataSourceList, 0) @@ -56,10 +57,10 @@ func (hs *HTTPServer) GetDataSources(c *models.ReqContext) Response { sort.Sort(result) - return JSON(200, &result) + return response.JSON(200, &result) } -func GetDataSourceById(c *models.ReqContext) Response { +func GetDataSourceById(c *models.ReqContext) response.Response { query := models.GetDataSourceQuery{ Id: c.ParamsInt64(":id"), OrgId: c.OrgId, @@ -67,135 +68,135 @@ func GetDataSourceById(c *models.ReqContext) Response { if err := bus.Dispatch(&query); err != nil { if errors.Is(err, models.ErrDataSourceNotFound) { - return Error(404, "Data source not found", nil) + return response.Error(404, "Data source not found", nil) } - return Error(500, "Failed to query datasources", err) + return response.Error(500, "Failed to query datasources", err) } ds := query.Result dtos := convertModelToDtos(ds) - return JSON(200, &dtos) + return response.JSON(200, &dtos) } -func DeleteDataSourceById(c *models.ReqContext) Response { +func DeleteDataSourceById(c *models.ReqContext) response.Response { id := c.ParamsInt64(":id") if id <= 0 { - return Error(400, "Missing valid datasource id", nil) + return response.Error(400, "Missing valid datasource id", nil) } ds, err := getRawDataSourceById(id, c.OrgId) if err != nil { if errors.Is(err, models.ErrDataSourceNotFound) { - return Error(404, "Data source not found", nil) + return response.Error(404, "Data source not found", nil) } - return Error(400, "Failed to delete datasource", nil) + return response.Error(400, "Failed to delete datasource", nil) } if ds.ReadOnly { - return Error(403, "Cannot delete read-only data source", nil) + return response.Error(403, "Cannot delete read-only data source", nil) } cmd := &models.DeleteDataSourceCommand{ID: id, OrgID: c.OrgId} err = bus.Dispatch(cmd) if err != nil { - return Error(500, "Failed to delete datasource", err) + return response.Error(500, "Failed to delete datasource", err) } - return Success("Data source deleted") + return response.Success("Data source deleted") } // GET /api/datasources/uid/:uid -func GetDataSourceByUID(c *models.ReqContext) Response { +func GetDataSourceByUID(c *models.ReqContext) response.Response { ds, err := getRawDataSourceByUID(c.Params(":uid"), c.OrgId) if err != nil { if errors.Is(err, models.ErrDataSourceNotFound) { - return Error(404, "Data source not found", nil) + return response.Error(404, "Data source not found", nil) } - return Error(500, "Failed to query datasources", err) + return response.Error(500, "Failed to query datasources", err) } dtos := convertModelToDtos(ds) - return JSON(200, &dtos) + return response.JSON(200, &dtos) } // DELETE /api/datasources/uid/:uid -func DeleteDataSourceByUID(c *models.ReqContext) Response { +func DeleteDataSourceByUID(c *models.ReqContext) response.Response { uid := c.Params(":uid") if uid == "" { - return Error(400, "Missing datasource uid", nil) + return response.Error(400, "Missing datasource uid", nil) } ds, err := getRawDataSourceByUID(uid, c.OrgId) if err != nil { if errors.Is(err, models.ErrDataSourceNotFound) { - return Error(404, "Data source not found", nil) + return response.Error(404, "Data source not found", nil) } - return Error(400, "Failed to delete datasource", nil) + return response.Error(400, "Failed to delete datasource", nil) } if ds.ReadOnly { - return Error(403, "Cannot delete read-only data source", nil) + return response.Error(403, "Cannot delete read-only data source", nil) } cmd := &models.DeleteDataSourceCommand{UID: uid, OrgID: c.OrgId} err = bus.Dispatch(cmd) if err != nil { - return Error(500, "Failed to delete datasource", err) + return response.Error(500, "Failed to delete datasource", err) } - return Success("Data source deleted") + return response.Success("Data source deleted") } -func DeleteDataSourceByName(c *models.ReqContext) Response { +func DeleteDataSourceByName(c *models.ReqContext) response.Response { name := c.Params(":name") if name == "" { - return Error(400, "Missing valid datasource name", nil) + return response.Error(400, "Missing valid datasource name", nil) } getCmd := &models.GetDataSourceQuery{Name: name, OrgId: c.OrgId} if err := bus.Dispatch(getCmd); err != nil { if errors.Is(err, models.ErrDataSourceNotFound) { - return Error(404, "Data source not found", nil) + return response.Error(404, "Data source not found", nil) } - return Error(500, "Failed to delete datasource", err) + return response.Error(500, "Failed to delete datasource", err) } if getCmd.Result.ReadOnly { - return Error(403, "Cannot delete read-only data source", nil) + return response.Error(403, "Cannot delete read-only data source", nil) } cmd := &models.DeleteDataSourceCommand{Name: name, OrgID: c.OrgId} err := bus.Dispatch(cmd) if err != nil { - return Error(500, "Failed to delete datasource", err) + return response.Error(500, "Failed to delete datasource", err) } - return JSON(200, util.DynMap{ + return response.JSON(200, util.DynMap{ "message": "Data source deleted", "id": getCmd.Result.Id, }) } -func validateURL(tp string, u string) Response { +func validateURL(tp string, u string) response.Response { if u != "" { if _, err := datasource.ValidateURL(tp, u); err != nil { datasourcesLogger.Error("Received invalid data source URL as part of data source command", "url", u) - return Error(400, fmt.Sprintf("Validation error, invalid URL: %q", u), err) + return response.Error(400, fmt.Sprintf("Validation error, invalid URL: %q", u), err) } } return nil } -func AddDataSource(c *models.ReqContext, cmd models.AddDataSourceCommand) Response { +func AddDataSource(c *models.ReqContext, cmd models.AddDataSourceCommand) response.Response { datasourcesLogger.Debug("Received command to add data source", "url", cmd.Url) cmd.OrgId = c.OrgId if resp := validateURL(cmd.Type, cmd.Url); resp != nil { @@ -204,14 +205,14 @@ func AddDataSource(c *models.ReqContext, cmd models.AddDataSourceCommand) Respon if err := bus.Dispatch(&cmd); err != nil { if errors.Is(err, models.ErrDataSourceNameExists) || errors.Is(err, models.ErrDataSourceUidExists) { - return Error(409, err.Error(), err) + return response.Error(409, err.Error(), err) } - return Error(500, "Failed to add datasource", err) + return response.Error(500, "Failed to add datasource", err) } ds := convertModelToDtos(cmd.Result) - return JSON(200, util.DynMap{ + return response.JSON(200, util.DynMap{ "message": "Datasource added", "id": cmd.Result.Id, "name": cmd.Result.Name, @@ -219,7 +220,7 @@ func AddDataSource(c *models.ReqContext, cmd models.AddDataSourceCommand) Respon }) } -func UpdateDataSource(c *models.ReqContext, cmd models.UpdateDataSourceCommand) Response { +func UpdateDataSource(c *models.ReqContext, cmd models.UpdateDataSourceCommand) response.Response { datasourcesLogger.Debug("Received command to update data source", "url", cmd.Url) cmd.OrgId = c.OrgId cmd.Id = c.ParamsInt64(":id") @@ -229,15 +230,15 @@ func UpdateDataSource(c *models.ReqContext, cmd models.UpdateDataSourceCommand) err := fillWithSecureJSONData(&cmd) if err != nil { - return Error(500, "Failed to update datasource", err) + return response.Error(500, "Failed to update datasource", err) } err = bus.Dispatch(&cmd) if err != nil { if errors.Is(err, models.ErrDataSourceUpdatingOldVersion) { - return Error(500, "Failed to update datasource. Reload new version and try again", err) + return response.Error(500, "Failed to update datasource. Reload new version and try again", err) } - return Error(500, "Failed to update datasource", err) + return response.Error(500, "Failed to update datasource", err) } query := models.GetDataSourceQuery{ @@ -247,14 +248,14 @@ func UpdateDataSource(c *models.ReqContext, cmd models.UpdateDataSourceCommand) if err := bus.Dispatch(&query); err != nil { if errors.Is(err, models.ErrDataSourceNotFound) { - return Error(404, "Data source not found", nil) + return response.Error(404, "Data source not found", nil) } - return Error(500, "Failed to query datasources", err) + return response.Error(500, "Failed to query datasources", err) } dtos := convertModelToDtos(query.Result) - return JSON(200, util.DynMap{ + return response.JSON(200, util.DynMap{ "message": "Datasource updated", "id": cmd.Id, "name": cmd.Name, @@ -313,29 +314,29 @@ func getRawDataSourceByUID(uid string, orgID int64) (*models.DataSource, error) } // Get /api/datasources/name/:name -func GetDataSourceByName(c *models.ReqContext) Response { +func GetDataSourceByName(c *models.ReqContext) response.Response { query := models.GetDataSourceQuery{Name: c.Params(":name"), OrgId: c.OrgId} if err := bus.Dispatch(&query); err != nil { if errors.Is(err, models.ErrDataSourceNotFound) { - return Error(404, "Data source not found", nil) + return response.Error(404, "Data source not found", nil) } - return Error(500, "Failed to query datasources", err) + return response.Error(500, "Failed to query datasources", err) } dtos := convertModelToDtos(query.Result) - return JSON(200, &dtos) + return response.JSON(200, &dtos) } // Get /api/datasources/id/:name -func GetDataSourceIdByName(c *models.ReqContext) Response { +func GetDataSourceIdByName(c *models.ReqContext) response.Response { query := models.GetDataSourceQuery{Name: c.Params(":name"), OrgId: c.OrgId} if err := bus.Dispatch(&query); err != nil { if errors.Is(err, models.ErrDataSourceNotFound) { - return Error(404, "Data source not found", nil) + return response.Error(404, "Data source not found", nil) } - return Error(500, "Failed to query datasources", err) + return response.Error(500, "Failed to query datasources", err) } ds := query.Result @@ -343,7 +344,7 @@ func GetDataSourceIdByName(c *models.ReqContext) Response { Id: ds.Id, } - return JSON(200, &dtos) + return response.JSON(200, &dtos) } // /api/datasources/:id/resources/* @@ -414,25 +415,25 @@ func convertModelToDtos(ds *models.DataSource) dtos.DataSource { // CheckDatasourceHealth sends a health check request to the plugin datasource // /api/datasource/:id/health -func (hs *HTTPServer) CheckDatasourceHealth(c *models.ReqContext) Response { +func (hs *HTTPServer) CheckDatasourceHealth(c *models.ReqContext) response.Response { datasourceID := c.ParamsInt64("id") ds, err := hs.DatasourceCache.GetDatasource(datasourceID, c.SignedInUser, c.SkipCache) if err != nil { if errors.Is(err, models.ErrDataSourceAccessDenied) { - return Error(403, "Access denied to datasource", err) + return response.Error(403, "Access denied to datasource", err) } - return Error(500, "Unable to load datasource metadata", err) + return response.Error(500, "Unable to load datasource metadata", err) } plugin, ok := hs.PluginManager.GetDatasource(ds.Type) if !ok { - return Error(500, "Unable to find datasource plugin", err) + return response.Error(500, "Unable to find datasource plugin", err) } dsInstanceSettings, err := wrapper.ModelToInstanceSettings(ds) if err != nil { - return Error(500, "Unable to get datasource model", err) + return response.Error(500, "Unable to get datasource model", err) } pCtx := backend.PluginContext{ User: wrapper.BackendUserFromSignedInUser(c.SignedInUser), @@ -456,15 +457,15 @@ func (hs *HTTPServer) CheckDatasourceHealth(c *models.ReqContext) Response { var jsonDetails map[string]interface{} err = json.Unmarshal(resp.JSONDetails, &jsonDetails) if err != nil { - return Error(500, "Failed to unmarshal detailed response from backend plugin", err) + return response.Error(500, "Failed to unmarshal detailed response from backend plugin", err) } payload["details"] = jsonDetails } if resp.Status != backend.HealthStatusOk { - return JSON(503, payload) + return response.JSON(503, payload) } - return JSON(200, payload) + return response.JSON(200, payload) } diff --git a/pkg/api/datasources_test.go b/pkg/api/datasources_test.go index b6f9ccca329..5aa66144f1b 100644 --- a/pkg/api/datasources_test.go +++ b/pkg/api/datasources_test.go @@ -4,6 +4,8 @@ import ( "encoding/json" "testing" + "github.com/grafana/grafana/pkg/api/response" + "github.com/grafana/grafana/pkg/api/routing" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/setting" "github.com/stretchr/testify/assert" @@ -61,7 +63,7 @@ func TestAddDataSource_InvalidURL(t *testing.T) { sc := setupScenarioContext(t, "/api/datasources") - sc.m.Post(sc.url, Wrap(func(c *models.ReqContext) Response { + sc.m.Post(sc.url, routing.Wrap(func(c *models.ReqContext) response.Response { return AddDataSource(c, models.AddDataSourceCommand{ Name: "Test", Url: "invalid:url", @@ -91,7 +93,7 @@ func TestAddDataSource_URLWithoutProtocol(t *testing.T) { sc := setupScenarioContext(t, "/api/datasources") - sc.m.Post(sc.url, Wrap(func(c *models.ReqContext) Response { + sc.m.Post(sc.url, routing.Wrap(func(c *models.ReqContext) response.Response { return AddDataSource(c, models.AddDataSourceCommand{ Name: name, Url: url, @@ -109,7 +111,7 @@ func TestUpdateDataSource_InvalidURL(t *testing.T) { sc := setupScenarioContext(t, "/api/datasources/1234") - sc.m.Put(sc.url, Wrap(func(c *models.ReqContext) Response { + sc.m.Put(sc.url, routing.Wrap(func(c *models.ReqContext) response.Response { return AddDataSource(c, models.AddDataSourceCommand{ Name: "Test", Url: "invalid:url", @@ -139,7 +141,7 @@ func TestUpdateDataSource_URLWithoutProtocol(t *testing.T) { sc := setupScenarioContext(t, "/api/datasources/1234") - sc.m.Put(sc.url, Wrap(func(c *models.ReqContext) Response { + sc.m.Put(sc.url, routing.Wrap(func(c *models.ReqContext) response.Response { return AddDataSource(c, models.AddDataSourceCommand{ Name: name, Url: url, diff --git a/pkg/api/folder.go b/pkg/api/folder.go index c406f6b10a8..bef99ea7a0a 100644 --- a/pkg/api/folder.go +++ b/pkg/api/folder.go @@ -5,13 +5,14 @@ import ( "fmt" "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/util" ) -func GetFolders(c *models.ReqContext) Response { +func GetFolders(c *models.ReqContext) response.Response { s := dashboards.NewFolderService(c.OrgId, c.SignedInUser) folders, err := s.GetFolders(c.QueryInt64("limit")) @@ -29,10 +30,10 @@ func GetFolders(c *models.ReqContext) Response { }) } - return JSON(200, result) + return response.JSON(200, result) } -func GetFolderByUID(c *models.ReqContext) Response { +func GetFolderByUID(c *models.ReqContext) response.Response { s := dashboards.NewFolderService(c.OrgId, c.SignedInUser) folder, err := s.GetFolderByUID(c.Params(":uid")) @@ -41,10 +42,10 @@ func GetFolderByUID(c *models.ReqContext) Response { } g := guardian.New(folder.Id, c.OrgId, c.SignedInUser) - return JSON(200, toFolderDto(g, folder)) + return response.JSON(200, toFolderDto(g, folder)) } -func GetFolderByID(c *models.ReqContext) Response { +func GetFolderByID(c *models.ReqContext) response.Response { s := dashboards.NewFolderService(c.OrgId, c.SignedInUser) folder, err := s.GetFolderByID(c.ParamsInt64(":id")) if err != nil { @@ -52,10 +53,10 @@ func GetFolderByID(c *models.ReqContext) Response { } g := guardian.New(folder.Id, c.OrgId, c.SignedInUser) - return JSON(200, toFolderDto(g, folder)) + return response.JSON(200, toFolderDto(g, folder)) } -func (hs *HTTPServer) CreateFolder(c *models.ReqContext, cmd models.CreateFolderCommand) Response { +func (hs *HTTPServer) CreateFolder(c *models.ReqContext, cmd models.CreateFolderCommand) response.Response { s := dashboards.NewFolderService(c.OrgId, c.SignedInUser) err := s.CreateFolder(&cmd) if err != nil { @@ -69,10 +70,10 @@ func (hs *HTTPServer) CreateFolder(c *models.ReqContext, cmd models.CreateFolder } g := guardian.New(cmd.Result.Id, c.OrgId, c.SignedInUser) - return JSON(200, toFolderDto(g, cmd.Result)) + return response.JSON(200, toFolderDto(g, cmd.Result)) } -func UpdateFolder(c *models.ReqContext, cmd models.UpdateFolderCommand) Response { +func UpdateFolder(c *models.ReqContext, cmd models.UpdateFolderCommand) response.Response { s := dashboards.NewFolderService(c.OrgId, c.SignedInUser) err := s.UpdateFolder(c.Params(":uid"), &cmd) if err != nil { @@ -80,17 +81,17 @@ func UpdateFolder(c *models.ReqContext, cmd models.UpdateFolderCommand) Response } g := guardian.New(cmd.Result.Id, c.OrgId, c.SignedInUser) - return JSON(200, toFolderDto(g, cmd.Result)) + return response.JSON(200, toFolderDto(g, cmd.Result)) } -func DeleteFolder(c *models.ReqContext) Response { +func DeleteFolder(c *models.ReqContext) response.Response { s := dashboards.NewFolderService(c.OrgId, c.SignedInUser) f, err := s.DeleteFolder(c.Params(":uid")) if err != nil { return toFolderError(err) } - return JSON(200, util.DynMap{ + return response.JSON(200, util.DynMap{ "title": f.Title, "message": fmt.Sprintf("Folder %s deleted", f.Title), "id": f.Id, @@ -128,10 +129,10 @@ func toFolderDto(g guardian.DashboardGuardian, folder *models.Folder) dtos.Folde } } -func toFolderError(err error) Response { +func toFolderError(err error) response.Response { var dashboardErr models.DashboardErr if ok := errors.As(err, &dashboardErr); ok { - return Error(dashboardErr.StatusCode, err.Error(), err) + return response.Error(dashboardErr.StatusCode, err.Error(), err) } if errors.Is(err, models.ErrFolderTitleEmpty) || @@ -140,20 +141,20 @@ func toFolderError(err error) Response { errors.Is(err, models.ErrDashboardTypeMismatch) || errors.Is(err, models.ErrDashboardInvalidUid) || errors.Is(err, models.ErrDashboardUidTooLong) { - return Error(400, err.Error(), nil) + return response.Error(400, err.Error(), nil) } if errors.Is(err, models.ErrFolderAccessDenied) { - return Error(403, "Access denied", err) + return response.Error(403, "Access denied", err) } if errors.Is(err, models.ErrFolderNotFound) { - return JSON(404, util.DynMap{"status": "not-found", "message": models.ErrFolderNotFound.Error()}) + return response.JSON(404, util.DynMap{"status": "not-found", "message": models.ErrFolderNotFound.Error()}) } if errors.Is(err, models.ErrFolderVersionMismatch) { - return JSON(412, util.DynMap{"status": "version-mismatch", "message": models.ErrFolderVersionMismatch.Error()}) + return response.JSON(412, util.DynMap{"status": "version-mismatch", "message": models.ErrFolderVersionMismatch.Error()}) } - return Error(500, "Folder API error", err) + return response.Error(500, "Folder API error", err) } diff --git a/pkg/api/folder_permission.go b/pkg/api/folder_permission.go index cd1b3a7bac7..d7f64643ddb 100644 --- a/pkg/api/folder_permission.go +++ b/pkg/api/folder_permission.go @@ -5,6 +5,7 @@ import ( "time" "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/dashboards" @@ -12,7 +13,7 @@ import ( "github.com/grafana/grafana/pkg/util" ) -func (hs *HTTPServer) GetFolderPermissionList(c *models.ReqContext) Response { +func (hs *HTTPServer) GetFolderPermissionList(c *models.ReqContext) response.Response { s := dashboards.NewFolderService(c.OrgId, c.SignedInUser) folder, err := s.GetFolderByUID(c.Params(":uid")) @@ -28,7 +29,7 @@ func (hs *HTTPServer) GetFolderPermissionList(c *models.ReqContext) Response { acl, err := g.GetAcl() if err != nil { - return Error(500, "Failed to get folder permissions", err) + return response.Error(500, "Failed to get folder permissions", err) } filteredAcls := make([]*models.DashboardAclInfoDTO, 0, len(acl)) @@ -53,12 +54,12 @@ func (hs *HTTPServer) GetFolderPermissionList(c *models.ReqContext) Response { filteredAcls = append(filteredAcls, perm) } - return JSON(200, filteredAcls) + return response.JSON(200, filteredAcls) } -func (hs *HTTPServer) UpdateFolderPermissions(c *models.ReqContext, apiCmd dtos.UpdateDashboardAclCommand) Response { +func (hs *HTTPServer) UpdateFolderPermissions(c *models.ReqContext, apiCmd dtos.UpdateDashboardAclCommand) response.Response { if err := validatePermissionsUpdate(apiCmd); err != nil { - return Error(400, err.Error(), err) + return response.Error(400, err.Error(), err) } s := dashboards.NewFolderService(c.OrgId, c.SignedInUser) @@ -96,7 +97,7 @@ func (hs *HTTPServer) UpdateFolderPermissions(c *models.ReqContext, apiCmd dtos. hiddenACL, err := g.GetHiddenACL(hs.Cfg) if err != nil { - return Error(500, "Error while retrieving hidden permissions", err) + return response.Error(500, "Error while retrieving hidden permissions", err) } cmd.Items = append(cmd.Items, hiddenACL...) @@ -104,13 +105,13 @@ func (hs *HTTPServer) UpdateFolderPermissions(c *models.ReqContext, apiCmd dtos. if err != nil { if errors.Is(err, guardian.ErrGuardianPermissionExists) || errors.Is(err, guardian.ErrGuardianOverride) { - return Error(400, err.Error(), err) + return response.Error(400, err.Error(), err) } - return Error(500, "Error while checking folder permissions", err) + return response.Error(500, "Error while checking folder permissions", err) } - return Error(403, "Cannot remove own admin permission for a folder", nil) + return response.Error(403, "Cannot remove own admin permission for a folder", nil) } if err := bus.Dispatch(&cmd); err != nil { @@ -122,13 +123,13 @@ func (hs *HTTPServer) UpdateFolderPermissions(c *models.ReqContext, apiCmd dtos. } if errors.Is(err, models.ErrFolderAclInfoMissing) || errors.Is(err, models.ErrFolderPermissionFolderEmpty) { - return Error(409, err.Error(), err) + return response.Error(409, err.Error(), err) } - return Error(500, "Failed to create permission", err) + return response.Error(500, "Failed to create permission", err) } - return JSON(200, util.DynMap{ + return response.JSON(200, util.DynMap{ "message": "Folder permissions updated", "id": folder.Id, "title": folder.Title, diff --git a/pkg/api/folder_permission_test.go b/pkg/api/folder_permission_test.go index ca22340d6c7..1a109329255 100644 --- a/pkg/api/folder_permission_test.go +++ b/pkg/api/folder_permission_test.go @@ -6,6 +6,8 @@ import ( "testing" "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/api/response" + "github.com/grafana/grafana/pkg/api/routing" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/dashboards" @@ -384,7 +386,7 @@ func updateFolderPermissionScenario(t *testing.T, ctx updatePermissionContext, h sc := setupScenarioContext(t, ctx.url) - sc.defaultHandler = Wrap(func(c *models.ReqContext) Response { + sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.context = c sc.context.OrgId = testOrgID sc.context.UserId = testUserID diff --git a/pkg/api/folder_test.go b/pkg/api/folder_test.go index e0f96ae0cbf..ca7ec90fb36 100644 --- a/pkg/api/folder_test.go +++ b/pkg/api/folder_test.go @@ -6,6 +6,8 @@ import ( "testing" "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/api/response" + "github.com/grafana/grafana/pkg/api/routing" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/dashboards" @@ -143,7 +145,7 @@ func createFolderScenario(t *testing.T, desc string, url string, routePattern st } sc := setupScenarioContext(t, url) - sc.defaultHandler = Wrap(func(c *models.ReqContext) Response { + sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.context = c sc.context.SignedInUser = &models.SignedInUser{OrgId: testOrgID, UserId: testUserID} @@ -173,7 +175,7 @@ func updateFolderScenario(t *testing.T, desc string, url string, routePattern st defer bus.ClearBusHandlers() sc := setupScenarioContext(t, url) - sc.defaultHandler = Wrap(func(c *models.ReqContext) Response { + sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.context = c sc.context.SignedInUser = &models.SignedInUser{OrgId: testOrgID, UserId: testUserID} diff --git a/pkg/api/frontend_logging.go b/pkg/api/frontend_logging.go index 86cb760bfb0..47d83f390f9 100644 --- a/pkg/api/frontend_logging.go +++ b/pkg/api/frontend_logging.go @@ -5,6 +5,7 @@ import ( "strings" "github.com/getsentry/sentry-go" + "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/models" "github.com/inconshreveable/log15" @@ -77,7 +78,7 @@ func (event *frontendSentryEvent) ToLogContext() log15.Ctx { return ctx } -func (hs *HTTPServer) logFrontendMessage(c *models.ReqContext, event frontendSentryEvent) Response { +func (hs *HTTPServer) logFrontendMessage(c *models.ReqContext, event frontendSentryEvent) response.Response { var msg = "unknown" if len(event.Message) > 0 { @@ -99,5 +100,5 @@ func (hs *HTTPServer) logFrontendMessage(c *models.ReqContext, event frontendSen frontendLogger.Info(msg, ctx) } - return Success("ok") + return response.Success("ok") } diff --git a/pkg/api/frontend_logging_test.go b/pkg/api/frontend_logging_test.go index fb0620d5d58..847a922e737 100644 --- a/pkg/api/frontend_logging_test.go +++ b/pkg/api/frontend_logging_test.go @@ -6,6 +6,8 @@ import ( "time" "github.com/getsentry/sentry-go" + "github.com/grafana/grafana/pkg/api/response" + "github.com/grafana/grafana/pkg/api/routing" "github.com/grafana/grafana/pkg/models" log "github.com/inconshreveable/log15" @@ -30,7 +32,7 @@ func logSentryEventScenario(t *testing.T, desc string, event frontendSentryEvent sc := setupScenarioContext(t, "/log") hs := HTTPServer{} - handler := Wrap(func(w http.ResponseWriter, c *models.ReqContext) Response { + handler := routing.Wrap(func(w http.ResponseWriter, c *models.ReqContext) response.Response { sc.context = c return hs.logFrontendMessage(c, event) }) diff --git a/pkg/api/ldap_debug.go b/pkg/api/ldap_debug.go index 1276cf0ceff..126e760b671 100644 --- a/pkg/api/ldap_debug.go +++ b/pkg/api/ldap_debug.go @@ -5,6 +5,7 @@ import ( "fmt" "net/http" + "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/login" @@ -97,38 +98,38 @@ func (user *LDAPUserDTO) FetchOrgs() error { } // ReloadLDAPCfg reloads the LDAP configuration -func (hs *HTTPServer) ReloadLDAPCfg() Response { +func (hs *HTTPServer) ReloadLDAPCfg() response.Response { if !ldap.IsEnabled() { - return Error(http.StatusBadRequest, "LDAP is not enabled", nil) + return response.Error(http.StatusBadRequest, "LDAP is not enabled", nil) } err := ldap.ReloadConfig() if err != nil { - return Error(http.StatusInternalServerError, "Failed to reload LDAP config", err) + return response.Error(http.StatusInternalServerError, "Failed to reload LDAP config", err) } - return Success("LDAP config reloaded") + return response.Success("LDAP config reloaded") } // GetLDAPStatus attempts to connect to all the configured LDAP servers and returns information on whenever they're available or not. -func (hs *HTTPServer) GetLDAPStatus(c *models.ReqContext) Response { +func (hs *HTTPServer) GetLDAPStatus(c *models.ReqContext) response.Response { if !ldap.IsEnabled() { - return Error(http.StatusBadRequest, "LDAP is not enabled", nil) + return response.Error(http.StatusBadRequest, "LDAP is not enabled", nil) } ldapConfig, err := getLDAPConfig(hs.Cfg) if err != nil { - return Error(http.StatusBadRequest, "Failed to obtain the LDAP configuration. Please verify the configuration and try again", err) + return response.Error(http.StatusBadRequest, "Failed to obtain the LDAP configuration. Please verify the configuration and try again", err) } ldap := newLDAP(ldapConfig.Servers) if ldap == nil { - return Error(http.StatusInternalServerError, "Failed to find the LDAP server", nil) + return response.Error(http.StatusInternalServerError, "Failed to find the LDAP server", nil) } statuses, err := ldap.Ping() if err != nil { - return Error(http.StatusBadRequest, "Failed to connect to the LDAP server(s)", err) + return response.Error(http.StatusBadRequest, "Failed to connect to the LDAP server(s)", err) } serverDTOs := []*LDAPServerDTO{} @@ -146,18 +147,18 @@ func (hs *HTTPServer) GetLDAPStatus(c *models.ReqContext) Response { serverDTOs = append(serverDTOs, s) } - return JSON(http.StatusOK, serverDTOs) + return response.JSON(http.StatusOK, serverDTOs) } // PostSyncUserWithLDAP enables a single Grafana user to be synchronized against LDAP -func (hs *HTTPServer) PostSyncUserWithLDAP(c *models.ReqContext) Response { +func (hs *HTTPServer) PostSyncUserWithLDAP(c *models.ReqContext) response.Response { if !ldap.IsEnabled() { - return Error(http.StatusBadRequest, "LDAP is not enabled", nil) + return response.Error(http.StatusBadRequest, "LDAP is not enabled", nil) } ldapConfig, err := getLDAPConfig(hs.Cfg) if err != nil { - return Error(http.StatusBadRequest, "Failed to obtain the LDAP configuration. Please verify the configuration and try again", err) + return response.Error(http.StatusBadRequest, "Failed to obtain the LDAP configuration. Please verify the configuration and try again", err) } userId := c.ParamsInt64(":id") @@ -166,20 +167,20 @@ func (hs *HTTPServer) PostSyncUserWithLDAP(c *models.ReqContext) Response { if err := bus.Dispatch(&query); err != nil { // validate the userId exists if errors.Is(err, models.ErrUserNotFound) { - return Error(404, models.ErrUserNotFound.Error(), nil) + return response.Error(404, models.ErrUserNotFound.Error(), nil) } - return Error(500, "Failed to get user", err) + return response.Error(500, "Failed to get user", err) } authModuleQuery := &models.GetAuthInfoQuery{UserId: query.Result.Id, AuthModule: models.AuthModuleLDAP} if err := bus.Dispatch(authModuleQuery); err != nil { // validate the userId comes from LDAP if errors.Is(err, models.ErrUserNotFound) { - return Error(404, models.ErrUserNotFound.Error(), nil) + return response.Error(404, models.ErrUserNotFound.Error(), nil) } - return Error(500, "Failed to get user", err) + return response.Error(500, "Failed to get user", err) } ldapServer := newLDAP(ldapConfig.Servers) @@ -189,25 +190,25 @@ func (hs *HTTPServer) PostSyncUserWithLDAP(c *models.ReqContext) Response { if hs.Cfg.AdminUser == query.Result.Login { // User is *the* Grafana Admin. We cannot disable it. errMsg := fmt.Sprintf(`Refusing to sync grafana super admin "%s" - it would be disabled`, query.Result.Login) ldapLogger.Error(errMsg) - return Error(http.StatusBadRequest, errMsg, err) + return response.Error(http.StatusBadRequest, errMsg, err) } // Since the user was not in the LDAP server. Let's disable it. err := login.DisableExternalUser(query.Result.Login) if err != nil { - return Error(http.StatusInternalServerError, "Failed to disable the user", err) + return response.Error(http.StatusInternalServerError, "Failed to disable the user", err) } err = hs.AuthTokenService.RevokeAllUserTokens(c.Req.Context(), userId) if err != nil { - return Error(http.StatusInternalServerError, "Failed to remove session tokens for the user", err) + return response.Error(http.StatusInternalServerError, "Failed to remove session tokens for the user", err) } - return Error(http.StatusBadRequest, "User not found in LDAP. Disabled the user without updating information", nil) // should this be a success? + return response.Error(http.StatusBadRequest, "User not found in LDAP. Disabled the user without updating information", nil) // should this be a success? } ldapLogger.Debug("Failed to sync the user with LDAP", "err", err) - return Error(http.StatusBadRequest, "Something went wrong while finding the user in LDAP", err) + return response.Error(http.StatusBadRequest, "Something went wrong while finding the user in LDAP", err) } upsertCmd := &models.UpsertUserCommand{ @@ -218,21 +219,21 @@ func (hs *HTTPServer) PostSyncUserWithLDAP(c *models.ReqContext) Response { err = bus.Dispatch(upsertCmd) if err != nil { - return Error(http.StatusInternalServerError, "Failed to update the user", err) + return response.Error(http.StatusInternalServerError, "Failed to update the user", err) } - return Success("User synced successfully") + return response.Success("User synced successfully") } // GetUserFromLDAP finds an user based on a username in LDAP. This helps illustrate how would the particular user be mapped in Grafana when synced. -func (hs *HTTPServer) GetUserFromLDAP(c *models.ReqContext) Response { +func (hs *HTTPServer) GetUserFromLDAP(c *models.ReqContext) response.Response { if !ldap.IsEnabled() { - return Error(http.StatusBadRequest, "LDAP is not enabled", nil) + return response.Error(http.StatusBadRequest, "LDAP is not enabled", nil) } ldapConfig, err := getLDAPConfig(hs.Cfg) if err != nil { - return Error(http.StatusBadRequest, "Failed to obtain the LDAP configuration", err) + return response.Error(http.StatusBadRequest, "Failed to obtain the LDAP configuration", err) } ldap := newLDAP(ldapConfig.Servers) @@ -240,13 +241,13 @@ func (hs *HTTPServer) GetUserFromLDAP(c *models.ReqContext) Response { username := c.Params(":username") if len(username) == 0 { - return Error(http.StatusBadRequest, "Validation error. You must specify an username", nil) + return response.Error(http.StatusBadRequest, "Validation error. You must specify an username", nil) } user, serverConfig, err := ldap.User(username) if user == nil { - return Error(http.StatusNotFound, "No user was found in the LDAP server(s) with that username", err) + return response.Error(http.StatusNotFound, "No user was found in the LDAP server(s) with that username", err) } ldapLogger.Debug("user found", "user", user) @@ -301,18 +302,18 @@ func (hs *HTTPServer) GetUserFromLDAP(c *models.ReqContext) Response { ldapLogger.Debug("mapping org roles", "orgsRoles", u.OrgRoles) err = u.FetchOrgs() if err != nil { - return Error(http.StatusBadRequest, "An organization was not found - Please verify your LDAP configuration", err) + return response.Error(http.StatusBadRequest, "An organization was not found - Please verify your LDAP configuration", err) } cmd := &models.GetTeamsForLDAPGroupCommand{Groups: user.Groups} err = bus.Dispatch(cmd) if err != nil && !errors.Is(err, bus.ErrHandlerNotFound) { - return Error(http.StatusBadRequest, "Unable to find the teams for this user", err) + return response.Error(http.StatusBadRequest, "Unable to find the teams for this user", err) } u.Teams = cmd.Result - return JSON(200, u) + return response.JSON(200, u) } // splitName receives the full name of a user and splits it into two parts: A name and a surname. diff --git a/pkg/api/ldap_debug_test.go b/pkg/api/ldap_debug_test.go index 9eb7e1304db..b94df9c95b1 100644 --- a/pkg/api/ldap_debug_test.go +++ b/pkg/api/ldap_debug_test.go @@ -6,6 +6,8 @@ import ( "net/http/httptest" "testing" + "github.com/grafana/grafana/pkg/api/response" + "github.com/grafana/grafana/pkg/api/routing" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/auth" @@ -58,7 +60,7 @@ func getUserFromLDAPContext(t *testing.T, requestURL string) *scenarioContext { hs := &HTTPServer{Cfg: setting.NewCfg()} - sc.defaultHandler = Wrap(func(c *models.ReqContext) Response { + sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.context = c return hs.GetUserFromLDAP(c) }) @@ -327,7 +329,7 @@ func getLDAPStatusContext(t *testing.T) *scenarioContext { hs := &HTTPServer{Cfg: setting.NewCfg()} - sc.defaultHandler = Wrap(func(c *models.ReqContext) Response { + sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.context = c return hs.GetLDAPStatus(c) }) @@ -391,7 +393,7 @@ func postSyncUserWithLDAPContext(t *testing.T, requestURL string, preHook func(* AuthTokenService: auth.NewFakeUserAuthTokenService(), } - sc.defaultHandler = Wrap(func(c *models.ReqContext) Response { + sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.context = c return hs.PostSyncUserWithLDAP(c) }) diff --git a/pkg/api/login.go b/pkg/api/login.go index ed16aa34ecb..c19ae305de0 100644 --- a/pkg/api/login.go +++ b/pkg/api/login.go @@ -8,6 +8,7 @@ import ( "strings" "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/metrics" @@ -159,36 +160,36 @@ func tryOAuthAutoLogin(c *models.ReqContext) bool { return false } -func (hs *HTTPServer) LoginAPIPing(c *models.ReqContext) Response { +func (hs *HTTPServer) LoginAPIPing(c *models.ReqContext) response.Response { if c.IsSignedIn || c.IsAnonymous { - return JSON(200, "Logged in") + return response.JSON(200, "Logged in") } - return Error(401, "Unauthorized", nil) + return response.Error(401, "Unauthorized", nil) } -func (hs *HTTPServer) LoginPost(c *models.ReqContext, cmd dtos.LoginCommand) Response { +func (hs *HTTPServer) LoginPost(c *models.ReqContext, cmd dtos.LoginCommand) response.Response { authModule := "" var user *models.User - var response *NormalResponse + var resp *response.NormalResponse defer func() { - err := response.err - if err == nil && response.errMessage != "" { - err = errors.New(response.errMessage) + err := resp.Err() + if err == nil && resp.ErrMessage() != "" { + err = errors.New(resp.ErrMessage()) } hs.HooksService.RunLoginHook(&models.LoginInfo{ AuthModule: authModule, User: user, LoginUsername: cmd.User, - HTTPStatus: response.status, + HTTPStatus: resp.Status(), Error: err, }, c) }() if setting.DisableLoginForm { - response = Error(http.StatusUnauthorized, "Login is disabled", nil) - return response + resp = response.Error(http.StatusUnauthorized, "Login is disabled", nil) + return resp } authQuery := &models.LoginUserQuery{ @@ -202,29 +203,29 @@ func (hs *HTTPServer) LoginPost(c *models.ReqContext, cmd dtos.LoginCommand) Res err := bus.Dispatch(authQuery) authModule = authQuery.AuthModule if err != nil { - response = Error(401, "Invalid username or password", err) + resp = response.Error(401, "Invalid username or password", err) if errors.Is(err, login.ErrInvalidCredentials) || errors.Is(err, login.ErrTooManyLoginAttempts) || errors.Is(err, models.ErrUserNotFound) { - return response + return resp } // Do not expose disabled status, // just show incorrect user credentials error (see #17947) if errors.Is(err, login.ErrUserDisabled) { hs.log.Warn("User is disabled", "user", cmd.User) - return response + return resp } - response = Error(500, "Error while trying to authenticate user", err) - return response + resp = response.Error(500, "Error while trying to authenticate user", err) + return resp } user = authQuery.User err = hs.loginUserWithUser(user, c) if err != nil { - response = Error(http.StatusInternalServerError, "Error while signing in user", err) - return response + resp = response.Error(http.StatusInternalServerError, "Error while signing in user", err) + return resp } result := map[string]interface{}{ @@ -241,8 +242,8 @@ func (hs *HTTPServer) LoginPost(c *models.ReqContext, cmd dtos.LoginCommand) Res } metrics.MApiLoginPost.Inc() - response = JSON(http.StatusOK, result) - return response + resp = response.JSON(http.StatusOK, result) + return resp } func (hs *HTTPServer) loginUserWithUser(user *models.User, c *models.ReqContext) error { @@ -324,11 +325,11 @@ func (hs *HTTPServer) redirectWithError(ctx *models.ReqContext, err error, v ... ctx.Redirect(setting.AppSubUrl + "/login") } -func (hs *HTTPServer) RedirectResponseWithError(ctx *models.ReqContext, err error, v ...interface{}) *RedirectResponse { +func (hs *HTTPServer) RedirectResponseWithError(ctx *models.ReqContext, err error, v ...interface{}) *response.RedirectResponse { ctx.Logger.Error(err.Error(), v...) if err := hs.trySetEncryptedCookie(ctx, loginErrorCookieName, err.Error(), 60); err != nil { hs.log.Error("Failed to set encrypted cookie", "err", err) } - return Redirect(setting.AppSubUrl + "/login") + return response.Redirect(setting.AppSubUrl + "/login") } diff --git a/pkg/api/login_test.go b/pkg/api/login_test.go index d3d40ba6d12..d1f9b4554d0 100644 --- a/pkg/api/login_test.go +++ b/pkg/api/login_test.go @@ -11,6 +11,8 @@ import ( "testing" "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/api/response" + "github.com/grafana/grafana/pkg/api/routing" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/infra/log" @@ -96,7 +98,7 @@ func TestLoginErrorCookieAPIEndpoint(t *testing.T) { License: &licensing.OSSLicensingService{}, } - sc.defaultHandler = Wrap(func(w http.ResponseWriter, c *models.ReqContext) { + sc.defaultHandler = routing.Wrap(func(w http.ResponseWriter, c *models.ReqContext) { hs.LoginView(c) }) @@ -158,7 +160,7 @@ func TestLoginViewRedirect(t *testing.T) { } hs.Cfg.CookieSecure = true - sc.defaultHandler = Wrap(func(w http.ResponseWriter, c *models.ReqContext) { + sc.defaultHandler = routing.Wrap(func(w http.ResponseWriter, c *models.ReqContext) { c.IsSignedIn = true c.SignedInUser = &models.SignedInUser{ UserId: 10, @@ -335,7 +337,7 @@ func TestLoginPostRedirect(t *testing.T) { } hs.Cfg.CookieSecure = true - sc.defaultHandler = Wrap(func(w http.ResponseWriter, c *models.ReqContext) Response { + sc.defaultHandler = routing.Wrap(func(w http.ResponseWriter, c *models.ReqContext) response.Response { cmd := dtos.LoginCommand{ User: "admin", Password: "admin", @@ -488,7 +490,7 @@ func TestLoginOAuthRedirect(t *testing.T) { License: &licensing.OSSLicensingService{}, } - sc.defaultHandler = Wrap(func(c *models.ReqContext) { + sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) { hs.LoginView(c) }) @@ -522,7 +524,7 @@ func TestLoginInternal(t *testing.T) { log: log.New("test"), } - sc.defaultHandler = Wrap(func(c *models.ReqContext) { + sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) { c.Req.URL.RawQuery = "disableAutoLogin=true" hs.LoginView(c) }) @@ -580,7 +582,7 @@ func setupAuthProxyLoginTest(t *testing.T, enableLoginToken bool) *scenarioConte log: log.New("hello"), } - sc.defaultHandler = Wrap(func(c *models.ReqContext) { + sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) { c.IsSignedIn = true c.SignedInUser = &models.SignedInUser{ UserId: 10, @@ -618,7 +620,7 @@ func TestLoginPostRunLokingHook(t *testing.T) { HooksService: hookService, } - sc.defaultHandler = Wrap(func(w http.ResponseWriter, c *models.ReqContext) Response { + sc.defaultHandler = routing.Wrap(func(w http.ResponseWriter, c *models.ReqContext) response.Response { cmd := dtos.LoginCommand{ User: "admin", Password: "admin", diff --git a/pkg/api/metrics.go b/pkg/api/metrics.go index 8ef0839b48b..4520eef1a31 100644 --- a/pkg/api/metrics.go +++ b/pkg/api/metrics.go @@ -9,6 +9,7 @@ import ( "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/tsdb" @@ -18,9 +19,9 @@ import ( // QueryMetricsV2 returns query metrics. // POST /api/ds/query DataSource query w/ expressions -func (hs *HTTPServer) QueryMetricsV2(c *models.ReqContext, reqDTO dtos.MetricRequest) Response { +func (hs *HTTPServer) QueryMetricsV2(c *models.ReqContext, reqDTO dtos.MetricRequest) response.Response { if len(reqDTO.Queries) == 0 { - return Error(400, "No queries found in query", nil) + return response.Error(400, "No queries found in query", nil) } request := &tsdb.TsdbQuery{ @@ -41,7 +42,7 @@ func (hs *HTTPServer) QueryMetricsV2(c *models.ReqContext, reqDTO dtos.MetricReq datasourceID, err := query.Get("datasourceId").Int64() if err != nil { hs.log.Debug("Can't process query since it's missing data source ID") - return Error(400, "Query missing data source ID", nil) + return response.Error(400, "Query missing data source ID", nil) } if i == 0 && !hasExpr { @@ -49,12 +50,12 @@ func (hs *HTTPServer) QueryMetricsV2(c *models.ReqContext, reqDTO dtos.MetricReq if err != nil { hs.log.Debug("Encountered error getting data source", "err", err, "id", datasourceID) if errors.Is(err, models.ErrDataSourceAccessDenied) { - return Error(403, "Access denied to data source", err) + return response.Error(403, "Access denied to data source", err) } if errors.Is(err, models.ErrDataSourceNotFound) { - return Error(400, "Invalid data source ID", err) + return response.Error(400, "Invalid data source ID", err) } - return Error(500, "Unable to load data source metadata", err) + return response.Error(500, "Unable to load data source metadata", err) } } @@ -73,16 +74,16 @@ func (hs *HTTPServer) QueryMetricsV2(c *models.ReqContext, reqDTO dtos.MetricReq if !hasExpr { resp, err = tsdb.HandleRequest(c.Req.Context(), ds, request) if err != nil { - return Error(500, "Metric request error", err) + return response.Error(500, "Metric request error", err) } } else { if !hs.Cfg.IsExpressionsEnabled() { - return Error(404, "Expressions feature toggle is not enabled", nil) + return response.Error(404, "Expressions feature toggle is not enabled", nil) } resp, err = expr.WrapTransformData(c.Req.Context(), request) if err != nil { - return Error(500, "Transform request error", err) + return response.Error(500, "Transform request error", err) } } @@ -95,29 +96,29 @@ func (hs *HTTPServer) QueryMetricsV2(c *models.ReqContext, reqDTO dtos.MetricReq } } - return jsonStreaming(statusCode, resp) + return response.JSONStreaming(statusCode, resp) } // QueryMetrics returns query metrics // POST /api/tsdb/query -func (hs *HTTPServer) QueryMetrics(c *models.ReqContext, reqDto dtos.MetricRequest) Response { +func (hs *HTTPServer) QueryMetrics(c *models.ReqContext, reqDto dtos.MetricRequest) response.Response { timeRange := tsdb.NewTimeRange(reqDto.From, reqDto.To) if len(reqDto.Queries) == 0 { - return Error(400, "No queries found in query", nil) + return response.Error(400, "No queries found in query", nil) } datasourceId, err := reqDto.Queries[0].Get("datasourceId").Int64() if err != nil { - return Error(400, "Query missing datasourceId", nil) + return response.Error(400, "Query missing datasourceId", nil) } ds, err := hs.DatasourceCache.GetDatasource(datasourceId, c.SignedInUser, c.SkipCache) if err != nil { if errors.Is(err, models.ErrDataSourceAccessDenied) { - return Error(403, "Access denied to datasource", err) + return response.Error(403, "Access denied to datasource", err) } - return Error(500, "Unable to load datasource meta data", err) + return response.Error(500, "Unable to load datasource meta data", err) } request := &tsdb.TsdbQuery{ @@ -138,7 +139,7 @@ func (hs *HTTPServer) QueryMetrics(c *models.ReqContext, reqDto dtos.MetricReque resp, err := tsdb.HandleRequest(c.Req.Context(), ds, request) if err != nil { - return Error(500, "Metric request error", err) + return response.Error(500, "Metric request error", err) } statusCode := 200 @@ -150,11 +151,11 @@ func (hs *HTTPServer) QueryMetrics(c *models.ReqContext, reqDto dtos.MetricReque } } - return JSON(statusCode, &resp) + return response.JSON(statusCode, &resp) } // GET /api/tsdb/testdata/scenarios -func GetTestDataScenarios(c *models.ReqContext) Response { +func GetTestDataScenarios(c *models.ReqContext) response.Response { result := make([]interface{}, 0) scenarioIds := make([]string, 0) @@ -173,27 +174,27 @@ func GetTestDataScenarios(c *models.ReqContext) Response { }) } - return JSON(200, &result) + return response.JSON(200, &result) } // GenerateError generates a index out of range error -func GenerateError(c *models.ReqContext) Response { +func GenerateError(c *models.ReqContext) response.Response { var array []string // nolint: govet - return JSON(200, array[20]) + return response.JSON(200, array[20]) } // GET /api/tsdb/testdata/gensql -func GenerateSQLTestData(c *models.ReqContext) Response { +func GenerateSQLTestData(c *models.ReqContext) response.Response { if err := bus.Dispatch(&models.InsertSQLTestDataCommand{}); err != nil { - return Error(500, "Failed to insert test data", err) + return response.Error(500, "Failed to insert test data", err) } - return JSON(200, &util.DynMap{"message": "OK"}) + return response.JSON(200, &util.DynMap{"message": "OK"}) } // GET /api/tsdb/testdata/random-walk -func GetTestDataRandomWalk(c *models.ReqContext) Response { +func GetTestDataRandomWalk(c *models.ReqContext) response.Response { from := c.Query("from") to := c.Query("to") intervalMs := c.QueryInt64("intervalMs") @@ -213,8 +214,8 @@ func GetTestDataRandomWalk(c *models.ReqContext) Response { resp, err := tsdb.HandleRequest(context.Background(), dsInfo, request) if err != nil { - return Error(500, "Metric request error", err) + return response.Error(500, "Metric request error", err) } - return JSON(200, &resp) + return response.JSON(200, &resp) } diff --git a/pkg/api/org.go b/pkg/api/org.go index 923a24605d0..364a07e2d84 100644 --- a/pkg/api/org.go +++ b/pkg/api/org.go @@ -4,6 +4,7 @@ import ( "errors" "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/infra/metrics" "github.com/grafana/grafana/pkg/models" @@ -12,24 +13,24 @@ import ( ) // GET /api/org -func GetOrgCurrent(c *models.ReqContext) Response { +func GetOrgCurrent(c *models.ReqContext) response.Response { return getOrgHelper(c.OrgId) } // GET /api/orgs/:orgId -func GetOrgByID(c *models.ReqContext) Response { +func GetOrgByID(c *models.ReqContext) response.Response { return getOrgHelper(c.ParamsInt64(":orgId")) } // Get /api/orgs/name/:name -func (hs *HTTPServer) GetOrgByName(c *models.ReqContext) Response { +func (hs *HTTPServer) GetOrgByName(c *models.ReqContext) response.Response { org, err := hs.SQLStore.GetOrgByName(c.Params(":name")) if err != nil { if errors.Is(err, models.ErrOrgNotFound) { - return Error(404, "Organization not found", err) + return response.Error(404, "Organization not found", err) } - return Error(500, "Failed to get organization", err) + return response.Error(500, "Failed to get organization", err) } result := models.OrgDetailsDTO{ Id: org.Id, @@ -44,18 +45,18 @@ func (hs *HTTPServer) GetOrgByName(c *models.ReqContext) Response { }, } - return JSON(200, &result) + return response.JSON(200, &result) } -func getOrgHelper(orgID int64) Response { +func getOrgHelper(orgID int64) response.Response { query := models.GetOrgByIdQuery{Id: orgID} if err := bus.Dispatch(&query); err != nil { if errors.Is(err, models.ErrOrgNotFound) { - return Error(404, "Organization not found", err) + return response.Error(404, "Organization not found", err) } - return Error(500, "Failed to get organization", err) + return response.Error(500, "Failed to get organization", err) } org := query.Result @@ -72,64 +73,64 @@ func getOrgHelper(orgID int64) Response { }, } - return JSON(200, &result) + return response.JSON(200, &result) } // POST /api/orgs -func CreateOrg(c *models.ReqContext, cmd models.CreateOrgCommand) Response { +func CreateOrg(c *models.ReqContext, cmd models.CreateOrgCommand) response.Response { if !c.IsSignedIn || (!setting.AllowUserOrgCreate && !c.IsGrafanaAdmin) { - return Error(403, "Access denied", nil) + return response.Error(403, "Access denied", nil) } cmd.UserId = c.UserId if err := bus.Dispatch(&cmd); err != nil { if errors.Is(err, models.ErrOrgNameTaken) { - return Error(409, "Organization name taken", err) + return response.Error(409, "Organization name taken", err) } - return Error(500, "Failed to create organization", err) + return response.Error(500, "Failed to create organization", err) } metrics.MApiOrgCreate.Inc() - return JSON(200, &util.DynMap{ + return response.JSON(200, &util.DynMap{ "orgId": cmd.Result.Id, "message": "Organization created", }) } // PUT /api/org -func UpdateOrgCurrent(c *models.ReqContext, form dtos.UpdateOrgForm) Response { +func UpdateOrgCurrent(c *models.ReqContext, form dtos.UpdateOrgForm) response.Response { return updateOrgHelper(form, c.OrgId) } // PUT /api/orgs/:orgId -func UpdateOrg(c *models.ReqContext, form dtos.UpdateOrgForm) Response { +func UpdateOrg(c *models.ReqContext, form dtos.UpdateOrgForm) response.Response { return updateOrgHelper(form, c.ParamsInt64(":orgId")) } -func updateOrgHelper(form dtos.UpdateOrgForm, orgID int64) Response { +func updateOrgHelper(form dtos.UpdateOrgForm, orgID int64) response.Response { cmd := models.UpdateOrgCommand{Name: form.Name, OrgId: orgID} if err := bus.Dispatch(&cmd); err != nil { if errors.Is(err, models.ErrOrgNameTaken) { - return Error(400, "Organization name taken", err) + return response.Error(400, "Organization name taken", err) } - return Error(500, "Failed to update organization", err) + return response.Error(500, "Failed to update organization", err) } - return Success("Organization updated") + return response.Success("Organization updated") } // PUT /api/org/address -func UpdateOrgAddressCurrent(c *models.ReqContext, form dtos.UpdateOrgAddressForm) Response { +func UpdateOrgAddressCurrent(c *models.ReqContext, form dtos.UpdateOrgAddressForm) response.Response { return updateOrgAddressHelper(form, c.OrgId) } // PUT /api/orgs/:orgId/address -func UpdateOrgAddress(c *models.ReqContext, form dtos.UpdateOrgAddressForm) Response { +func UpdateOrgAddress(c *models.ReqContext, form dtos.UpdateOrgAddressForm) response.Response { return updateOrgAddressHelper(form, c.ParamsInt64(":orgId")) } -func updateOrgAddressHelper(form dtos.UpdateOrgAddressForm, orgID int64) Response { +func updateOrgAddressHelper(form dtos.UpdateOrgAddressForm, orgID int64) response.Response { cmd := models.UpdateOrgAddressCommand{ OrgId: orgID, Address: models.Address{ @@ -143,24 +144,24 @@ func updateOrgAddressHelper(form dtos.UpdateOrgAddressForm, orgID int64) Respons } if err := bus.Dispatch(&cmd); err != nil { - return Error(500, "Failed to update org address", err) + return response.Error(500, "Failed to update org address", err) } - return Success("Address updated") + return response.Success("Address updated") } // GET /api/orgs/:orgId -func DeleteOrgByID(c *models.ReqContext) Response { +func DeleteOrgByID(c *models.ReqContext) response.Response { if err := bus.Dispatch(&models.DeleteOrgCommand{Id: c.ParamsInt64(":orgId")}); err != nil { if errors.Is(err, models.ErrOrgNotFound) { - return Error(404, "Failed to delete organization. ID not found", nil) + return response.Error(404, "Failed to delete organization. ID not found", nil) } - return Error(500, "Failed to update organization", err) + return response.Error(500, "Failed to update organization", err) } - return Success("Organization deleted") + return response.Success("Organization deleted") } -func SearchOrgs(c *models.ReqContext) Response { +func SearchOrgs(c *models.ReqContext) response.Response { perPage := c.QueryInt("perpage") if perPage <= 0 { perPage = 1000 @@ -176,8 +177,8 @@ func SearchOrgs(c *models.ReqContext) Response { } if err := bus.Dispatch(&query); err != nil { - return Error(500, "Failed to search orgs", err) + return response.Error(500, "Failed to search orgs", err) } - return JSON(200, query.Result) + return response.JSON(200, query.Result) } diff --git a/pkg/api/org_invite.go b/pkg/api/org_invite.go index 39712c97110..815f411bd66 100644 --- a/pkg/api/org_invite.go +++ b/pkg/api/org_invite.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/events" "github.com/grafana/grafana/pkg/infra/metrics" @@ -13,37 +14,37 @@ import ( "github.com/grafana/grafana/pkg/util" ) -func GetPendingOrgInvites(c *models.ReqContext) Response { +func GetPendingOrgInvites(c *models.ReqContext) response.Response { query := models.GetTempUsersQuery{OrgId: c.OrgId, Status: models.TmpUserInvitePending} if err := bus.Dispatch(&query); err != nil { - return Error(500, "Failed to get invites from db", err) + return response.Error(500, "Failed to get invites from db", err) } for _, invite := range query.Result { invite.Url = setting.ToAbsUrl("invite/" + invite.Code) } - return JSON(200, query.Result) + return response.JSON(200, query.Result) } -func AddOrgInvite(c *models.ReqContext, inviteDto dtos.AddInviteForm) Response { +func AddOrgInvite(c *models.ReqContext, inviteDto dtos.AddInviteForm) response.Response { if !inviteDto.Role.IsValid() { - return Error(400, "Invalid role specified", nil) + return response.Error(400, "Invalid role specified", nil) } // first try get existing user userQuery := models.GetUserByLoginQuery{LoginOrEmail: inviteDto.LoginOrEmail} if err := bus.Dispatch(&userQuery); err != nil { if !errors.Is(err, models.ErrUserNotFound) { - return Error(500, "Failed to query db for existing user check", err) + return response.Error(500, "Failed to query db for existing user check", err) } } else { return inviteExistingUserToOrg(c, userQuery.Result, &inviteDto) } if setting.DisableLoginForm { - return Error(400, "Cannot invite when login is disabled.", nil) + return response.Error(400, "Cannot invite when login is disabled.", nil) } cmd := models.CreateTempUserCommand{} @@ -55,13 +56,13 @@ func AddOrgInvite(c *models.ReqContext, inviteDto dtos.AddInviteForm) Response { var err error cmd.Code, err = util.GetRandomString(30) if err != nil { - return Error(500, "Could not generate random string", err) + return response.Error(500, "Could not generate random string", err) } cmd.Role = inviteDto.Role cmd.RemoteAddr = c.Req.RemoteAddr if err := bus.Dispatch(&cmd); err != nil { - return Error(500, "Failed to save invite to database", err) + return response.Error(500, "Failed to save invite to database", err) } // send invite email @@ -80,31 +81,31 @@ func AddOrgInvite(c *models.ReqContext, inviteDto dtos.AddInviteForm) Response { if err := bus.Dispatch(&emailCmd); err != nil { if errors.Is(err, models.ErrSmtpNotEnabled) { - return Error(412, err.Error(), err) + return response.Error(412, err.Error(), err) } - return Error(500, "Failed to send email invite", err) + return response.Error(500, "Failed to send email invite", err) } emailSentCmd := models.UpdateTempUserWithEmailSentCommand{Code: cmd.Result.Code} if err := bus.Dispatch(&emailSentCmd); err != nil { - return Error(500, "Failed to update invite with email sent info", err) + return response.Error(500, "Failed to update invite with email sent info", err) } - return Success(fmt.Sprintf("Sent invite to %s", inviteDto.LoginOrEmail)) + return response.Success(fmt.Sprintf("Sent invite to %s", inviteDto.LoginOrEmail)) } - return Success(fmt.Sprintf("Created invite for %s", inviteDto.LoginOrEmail)) + return response.Success(fmt.Sprintf("Created invite for %s", inviteDto.LoginOrEmail)) } -func inviteExistingUserToOrg(c *models.ReqContext, user *models.User, inviteDto *dtos.AddInviteForm) Response { +func inviteExistingUserToOrg(c *models.ReqContext, user *models.User, inviteDto *dtos.AddInviteForm) response.Response { // user exists, add org role createOrgUserCmd := models.AddOrgUserCommand{OrgId: c.OrgId, UserId: user.Id, Role: inviteDto.Role} if err := bus.Dispatch(&createOrgUserCmd); err != nil { if errors.Is(err, models.ErrOrgUserAlreadyAdded) { - return Error(412, fmt.Sprintf("User %s is already added to organization", inviteDto.LoginOrEmail), err) + return response.Error(412, fmt.Sprintf("User %s is already added to organization", inviteDto.LoginOrEmail), err) } - return Error(500, "Error while trying to create org user", err) + return response.Error(500, "Error while trying to create org user", err) } if inviteDto.SendEmail && util.IsEmail(user.Email) { @@ -119,42 +120,42 @@ func inviteExistingUserToOrg(c *models.ReqContext, user *models.User, inviteDto } if err := bus.Dispatch(&emailCmd); err != nil { - return Error(500, "Failed to send email invited_to_org", err) + return response.Error(500, "Failed to send email invited_to_org", err) } } - return JSON(200, util.DynMap{ + return response.JSON(200, util.DynMap{ "message": fmt.Sprintf("Existing Grafana user %s added to org %s", user.NameOrFallback(), c.OrgName), "userId": user.Id, }) } -func RevokeInvite(c *models.ReqContext) Response { +func RevokeInvite(c *models.ReqContext) response.Response { if ok, rsp := updateTempUserStatus(c.Params(":code"), models.TmpUserRevoked); !ok { return rsp } - return Success("Invite revoked") + return response.Success("Invite revoked") } // GetInviteInfoByCode gets a pending user invite corresponding to a certain code. // A response containing an InviteInfo object is returned if the invite is found. // If a (pending) invite is not found, 404 is returned. -func GetInviteInfoByCode(c *models.ReqContext) Response { +func GetInviteInfoByCode(c *models.ReqContext) response.Response { query := models.GetTempUserByCodeQuery{Code: c.Params(":code")} if err := bus.Dispatch(&query); err != nil { if errors.Is(err, models.ErrTempUserNotFound) { - return Error(404, "Invite not found", nil) + return response.Error(404, "Invite not found", nil) } - return Error(500, "Failed to get invite", err) + return response.Error(500, "Failed to get invite", err) } invite := query.Result if invite.Status != models.TmpUserInvitePending { - return Error(404, "Invite not found", nil) + return response.Error(404, "Invite not found", nil) } - return JSON(200, dtos.InviteInfo{ + return response.JSON(200, dtos.InviteInfo{ Email: invite.Email, Name: invite.Name, Username: invite.Email, @@ -162,19 +163,19 @@ func GetInviteInfoByCode(c *models.ReqContext) Response { }) } -func (hs *HTTPServer) CompleteInvite(c *models.ReqContext, completeInvite dtos.CompleteInviteForm) Response { +func (hs *HTTPServer) CompleteInvite(c *models.ReqContext, completeInvite dtos.CompleteInviteForm) response.Response { query := models.GetTempUserByCodeQuery{Code: completeInvite.InviteCode} if err := bus.Dispatch(&query); err != nil { if errors.Is(err, models.ErrTempUserNotFound) { - return Error(404, "Invite not found", nil) + return response.Error(404, "Invite not found", nil) } - return Error(500, "Failed to get invite", err) + return response.Error(500, "Failed to get invite", err) } invite := query.Result if invite.Status != models.TmpUserInvitePending { - return Error(412, fmt.Sprintf("Invite cannot be used in status %s", invite.Status), nil) + return response.Error(412, fmt.Sprintf("Invite cannot be used in status %s", invite.Status), nil) } cmd := models.CreateUserCommand{ @@ -187,10 +188,10 @@ func (hs *HTTPServer) CompleteInvite(c *models.ReqContext, completeInvite dtos.C if err := bus.Dispatch(&cmd); err != nil { if errors.Is(err, models.ErrUserAlreadyExists) { - return Error(412, fmt.Sprintf("User with email '%s' or username '%s' already exists", completeInvite.Email, completeInvite.Username), err) + return response.Error(412, fmt.Sprintf("User with email '%s' or username '%s' already exists", completeInvite.Email, completeInvite.Username), err) } - return Error(500, "failed to create user", err) + return response.Error(500, "failed to create user", err) } user := &cmd.Result @@ -199,7 +200,7 @@ func (hs *HTTPServer) CompleteInvite(c *models.ReqContext, completeInvite dtos.C Name: user.NameOrFallback(), Email: user.Email, }); err != nil { - return Error(500, "failed to publish event", err) + return response.Error(500, "failed to publish event", err) } if ok, rsp := applyUserInvite(user, invite, true); !ok { @@ -208,34 +209,34 @@ func (hs *HTTPServer) CompleteInvite(c *models.ReqContext, completeInvite dtos.C err := hs.loginUserWithUser(user, c) if err != nil { - return Error(500, "failed to accept invite", err) + return response.Error(500, "failed to accept invite", err) } metrics.MApiUserSignUpCompleted.Inc() metrics.MApiUserSignUpInvite.Inc() - return JSON(200, util.DynMap{ + return response.JSON(200, util.DynMap{ "message": "User created and logged in", "id": user.Id, }) } -func updateTempUserStatus(code string, status models.TempUserStatus) (bool, Response) { +func updateTempUserStatus(code string, status models.TempUserStatus) (bool, response.Response) { // update temp user status updateTmpUserCmd := models.UpdateTempUserStatusCommand{Code: code, Status: status} if err := bus.Dispatch(&updateTmpUserCmd); err != nil { - return false, Error(500, "Failed to update invite status", err) + return false, response.Error(500, "Failed to update invite status", err) } return true, nil } -func applyUserInvite(user *models.User, invite *models.TempUserDTO, setActive bool) (bool, Response) { +func applyUserInvite(user *models.User, invite *models.TempUserDTO, setActive bool) (bool, response.Response) { // add to org addOrgUserCmd := models.AddOrgUserCommand{OrgId: invite.OrgId, UserId: user.Id, Role: invite.Role} if err := bus.Dispatch(&addOrgUserCmd); err != nil { if !errors.Is(err, models.ErrOrgUserAlreadyAdded) { - return false, Error(500, "Error while trying to create org user", err) + return false, response.Error(500, "Error while trying to create org user", err) } } @@ -247,7 +248,7 @@ func applyUserInvite(user *models.User, invite *models.TempUserDTO, setActive bo if setActive { // set org to active if err := bus.Dispatch(&models.SetUsingOrgCommand{OrgId: invite.OrgId, UserId: user.Id}); err != nil { - return false, Error(500, "Failed to set org as active", err) + return false, response.Error(500, "Failed to set org as active", err) } } diff --git a/pkg/api/org_users.go b/pkg/api/org_users.go index 376502d6d03..7c2dc3e6457 100644 --- a/pkg/api/org_users.go +++ b/pkg/api/org_users.go @@ -4,32 +4,33 @@ import ( "errors" "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/util" ) // POST /api/org/users -func AddOrgUserToCurrentOrg(c *models.ReqContext, cmd models.AddOrgUserCommand) Response { +func AddOrgUserToCurrentOrg(c *models.ReqContext, cmd models.AddOrgUserCommand) response.Response { cmd.OrgId = c.OrgId return addOrgUserHelper(cmd) } // POST /api/orgs/:orgId/users -func AddOrgUser(c *models.ReqContext, cmd models.AddOrgUserCommand) Response { +func AddOrgUser(c *models.ReqContext, cmd models.AddOrgUserCommand) response.Response { cmd.OrgId = c.ParamsInt64(":orgId") return addOrgUserHelper(cmd) } -func addOrgUserHelper(cmd models.AddOrgUserCommand) Response { +func addOrgUserHelper(cmd models.AddOrgUserCommand) response.Response { if !cmd.Role.IsValid() { - return Error(400, "Invalid role specified", nil) + return response.Error(400, "Invalid role specified", nil) } userQuery := models.GetUserByLoginQuery{LoginOrEmail: cmd.LoginOrEmail} err := bus.Dispatch(&userQuery) if err != nil { - return Error(404, "User not found", nil) + return response.Error(404, "User not found", nil) } userToAdd := userQuery.Result @@ -38,22 +39,22 @@ func addOrgUserHelper(cmd models.AddOrgUserCommand) Response { if err := bus.Dispatch(&cmd); err != nil { if errors.Is(err, models.ErrOrgUserAlreadyAdded) { - return JSON(409, util.DynMap{ + return response.JSON(409, util.DynMap{ "message": "User is already member of this organization", "userId": cmd.UserId, }) } - return Error(500, "Could not add user to organization", err) + return response.Error(500, "Could not add user to organization", err) } - return JSON(200, util.DynMap{ + return response.JSON(200, util.DynMap{ "message": "User added to organization", "userId": cmd.UserId, }) } // GET /api/org/users -func (hs *HTTPServer) GetOrgUsersForCurrentOrg(c *models.ReqContext) Response { +func (hs *HTTPServer) GetOrgUsersForCurrentOrg(c *models.ReqContext) response.Response { result, err := hs.getOrgUsersHelper(&models.GetOrgUsersQuery{ OrgId: c.OrgId, Query: c.Query("query"), @@ -61,21 +62,21 @@ func (hs *HTTPServer) GetOrgUsersForCurrentOrg(c *models.ReqContext) Response { }, c.SignedInUser) if err != nil { - return Error(500, "Failed to get users for current organization", err) + return response.Error(500, "Failed to get users for current organization", err) } - return JSON(200, result) + return response.JSON(200, result) } // GET /api/org/users/lookup -func (hs *HTTPServer) GetOrgUsersForCurrentOrgLookup(c *models.ReqContext) Response { +func (hs *HTTPServer) GetOrgUsersForCurrentOrgLookup(c *models.ReqContext) response.Response { isAdmin, err := isOrgAdminFolderAdminOrTeamAdmin(c) if err != nil { - return Error(500, "Failed to get users for current organization", err) + return response.Error(500, "Failed to get users for current organization", err) } if !isAdmin { - return Error(403, "Permission denied", nil) + return response.Error(403, "Permission denied", nil) } orgUsers, err := hs.getOrgUsersHelper(&models.GetOrgUsersQuery{ @@ -85,7 +86,7 @@ func (hs *HTTPServer) GetOrgUsersForCurrentOrgLookup(c *models.ReqContext) Respo }, c.SignedInUser) if err != nil { - return Error(500, "Failed to get users for current organization", err) + return response.Error(500, "Failed to get users for current organization", err) } result := make([]*dtos.UserLookupDTO, 0) @@ -98,7 +99,7 @@ func (hs *HTTPServer) GetOrgUsersForCurrentOrgLookup(c *models.ReqContext) Respo }) } - return JSON(200, result) + return response.JSON(200, result) } func isOrgAdminFolderAdminOrTeamAdmin(c *models.ReqContext) (bool, error) { @@ -124,7 +125,7 @@ func isOrgAdminFolderAdminOrTeamAdmin(c *models.ReqContext) (bool, error) { } // GET /api/orgs/:orgId/users -func (hs *HTTPServer) GetOrgUsers(c *models.ReqContext) Response { +func (hs *HTTPServer) GetOrgUsers(c *models.ReqContext) response.Response { result, err := hs.getOrgUsersHelper(&models.GetOrgUsersQuery{ OrgId: c.ParamsInt64(":orgId"), Query: "", @@ -132,10 +133,10 @@ func (hs *HTTPServer) GetOrgUsers(c *models.ReqContext) Response { }, c.SignedInUser) if err != nil { - return Error(500, "Failed to get users for organization", err) + return response.Error(500, "Failed to get users for organization", err) } - return JSON(200, result) + return response.JSON(200, result) } func (hs *HTTPServer) getOrgUsersHelper(query *models.GetOrgUsersQuery, signedInUser *models.SignedInUser) ([]*models.OrgUserDTO, error) { @@ -157,36 +158,36 @@ func (hs *HTTPServer) getOrgUsersHelper(query *models.GetOrgUsersQuery, signedIn } // PATCH /api/org/users/:userId -func UpdateOrgUserForCurrentOrg(c *models.ReqContext, cmd models.UpdateOrgUserCommand) Response { +func UpdateOrgUserForCurrentOrg(c *models.ReqContext, cmd models.UpdateOrgUserCommand) response.Response { cmd.OrgId = c.OrgId cmd.UserId = c.ParamsInt64(":userId") return updateOrgUserHelper(cmd) } // PATCH /api/orgs/:orgId/users/:userId -func UpdateOrgUser(c *models.ReqContext, cmd models.UpdateOrgUserCommand) Response { +func UpdateOrgUser(c *models.ReqContext, cmd models.UpdateOrgUserCommand) response.Response { cmd.OrgId = c.ParamsInt64(":orgId") cmd.UserId = c.ParamsInt64(":userId") return updateOrgUserHelper(cmd) } -func updateOrgUserHelper(cmd models.UpdateOrgUserCommand) Response { +func updateOrgUserHelper(cmd models.UpdateOrgUserCommand) response.Response { if !cmd.Role.IsValid() { - return Error(400, "Invalid role specified", nil) + return response.Error(400, "Invalid role specified", nil) } if err := bus.Dispatch(&cmd); err != nil { if errors.Is(err, models.ErrLastOrgAdmin) { - return Error(400, "Cannot change role so that there is no organization admin left", nil) + return response.Error(400, "Cannot change role so that there is no organization admin left", nil) } - return Error(500, "Failed update org user", err) + return response.Error(500, "Failed update org user", err) } - return Success("Organization user updated") + return response.Success("Organization user updated") } // DELETE /api/org/users/:userId -func RemoveOrgUserForCurrentOrg(c *models.ReqContext) Response { +func RemoveOrgUserForCurrentOrg(c *models.ReqContext) response.Response { return removeOrgUserHelper(&models.RemoveOrgUserCommand{ UserId: c.ParamsInt64(":userId"), OrgId: c.OrgId, @@ -195,24 +196,24 @@ func RemoveOrgUserForCurrentOrg(c *models.ReqContext) Response { } // DELETE /api/orgs/:orgId/users/:userId -func RemoveOrgUser(c *models.ReqContext) Response { +func RemoveOrgUser(c *models.ReqContext) response.Response { return removeOrgUserHelper(&models.RemoveOrgUserCommand{ UserId: c.ParamsInt64(":userId"), OrgId: c.ParamsInt64(":orgId"), }) } -func removeOrgUserHelper(cmd *models.RemoveOrgUserCommand) Response { +func removeOrgUserHelper(cmd *models.RemoveOrgUserCommand) response.Response { if err := bus.Dispatch(cmd); err != nil { if errors.Is(err, models.ErrLastOrgAdmin) { - return Error(400, "Cannot remove last organization admin", nil) + return response.Error(400, "Cannot remove last organization admin", nil) } - return Error(500, "Failed to remove user from organization", err) + return response.Error(500, "Failed to remove user from organization", err) } if cmd.UserWasDeleted { - return Success("User deleted") + return response.Success("User deleted") } - return Success("User removed from organization") + return response.Success("User removed from organization") } diff --git a/pkg/api/password.go b/pkg/api/password.go index e1a0b585f46..4aa338a1fd7 100644 --- a/pkg/api/password.go +++ b/pkg/api/password.go @@ -4,47 +4,48 @@ import ( "errors" "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/util" ) -func SendResetPasswordEmail(c *models.ReqContext, form dtos.SendResetPasswordEmailForm) Response { +func SendResetPasswordEmail(c *models.ReqContext, form dtos.SendResetPasswordEmailForm) response.Response { if setting.LDAPEnabled || setting.AuthProxyEnabled { - return 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) } if setting.DisableLoginForm { - return Error(401, "Not allowed to reset password when login form is disabled", nil) + return response.Error(401, "Not allowed to reset password when login form is disabled", nil) } userQuery := models.GetUserByLoginQuery{LoginOrEmail: form.UserOrEmail} if err := bus.Dispatch(&userQuery); err != nil { c.Logger.Info("Requested password reset for user that was not found", "user", userQuery.LoginOrEmail) - return Error(200, "Email sent", err) + return response.Error(200, "Email sent", err) } emailCmd := models.SendResetPasswordEmailCommand{User: userQuery.Result} if err := bus.Dispatch(&emailCmd); err != nil { - return Error(500, "Failed to send email", err) + return response.Error(500, "Failed to send email", err) } - return Success("Email sent") + return response.Success("Email sent") } -func ResetPassword(c *models.ReqContext, form dtos.ResetUserPasswordForm) Response { +func ResetPassword(c *models.ReqContext, form dtos.ResetUserPasswordForm) response.Response { query := models.ValidateResetPasswordCodeQuery{Code: form.Code} if err := bus.Dispatch(&query); err != nil { if errors.Is(err, models.ErrInvalidEmailCode) { - return Error(400, "Invalid or expired reset password code", nil) + return response.Error(400, "Invalid or expired reset password code", nil) } - return Error(500, "Unknown error validating email code", err) + return response.Error(500, "Unknown error validating email code", err) } if form.NewPassword != form.ConfirmPassword { - return Error(400, "Passwords do not match", nil) + return response.Error(400, "Passwords do not match", nil) } cmd := models.ChangeUserPasswordCommand{} @@ -52,12 +53,12 @@ func ResetPassword(c *models.ReqContext, form dtos.ResetUserPasswordForm) Respon var err error cmd.NewPassword, err = util.EncodePassword(form.NewPassword, query.Result.Salt) if err != nil { - return Error(500, "Failed to encode password", err) + return response.Error(500, "Failed to encode password", err) } if err := bus.Dispatch(&cmd); err != nil { - return Error(500, "Failed to change user password", err) + return response.Error(500, "Failed to change user password", err) } - return Success("User password changed") + return response.Success("User password changed") } diff --git a/pkg/api/playlist.go b/pkg/api/playlist.go index cfe9956987a..86c129153ab 100644 --- a/pkg/api/playlist.go +++ b/pkg/api/playlist.go @@ -1,6 +1,7 @@ package api import ( + "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/models" ) @@ -26,7 +27,7 @@ func ValidateOrgPlaylist(c *models.ReqContext) { } } -func SearchPlaylists(c *models.ReqContext) Response { +func SearchPlaylists(c *models.ReqContext) response.Response { query := c.Query("query") limit := c.QueryInt("limit") @@ -42,18 +43,18 @@ func SearchPlaylists(c *models.ReqContext) Response { err := bus.Dispatch(&searchQuery) if err != nil { - return Error(500, "Search failed", err) + return response.Error(500, "Search failed", err) } - return JSON(200, searchQuery.Result) + return response.JSON(200, searchQuery.Result) } -func GetPlaylist(c *models.ReqContext) Response { +func GetPlaylist(c *models.ReqContext) response.Response { id := c.ParamsInt64(":id") cmd := models.GetPlaylistByIdQuery{Id: id} if err := bus.Dispatch(&cmd); err != nil { - return Error(500, "Playlist not found", err) + return response.Error(500, "Playlist not found", err) } playlistDTOs, _ := LoadPlaylistItemDTOs(id) @@ -66,7 +67,7 @@ func GetPlaylist(c *models.ReqContext) Response { Items: playlistDTOs, } - return JSON(200, dto) + return response.JSON(200, dto) } func LoadPlaylistItemDTOs(id int64) ([]models.PlaylistItemDTO, error) { @@ -101,63 +102,63 @@ func LoadPlaylistItems(id int64) ([]models.PlaylistItem, error) { return *itemQuery.Result, nil } -func GetPlaylistItems(c *models.ReqContext) Response { +func GetPlaylistItems(c *models.ReqContext) response.Response { id := c.ParamsInt64(":id") playlistDTOs, err := LoadPlaylistItemDTOs(id) if err != nil { - return Error(500, "Could not load playlist items", err) + return response.Error(500, "Could not load playlist items", err) } - return JSON(200, playlistDTOs) + return response.JSON(200, playlistDTOs) } -func GetPlaylistDashboards(c *models.ReqContext) Response { +func GetPlaylistDashboards(c *models.ReqContext) response.Response { playlistID := c.ParamsInt64(":id") playlists, err := LoadPlaylistDashboards(c.OrgId, c.SignedInUser, playlistID) if err != nil { - return Error(500, "Could not load dashboards", err) + return response.Error(500, "Could not load dashboards", err) } - return JSON(200, playlists) + return response.JSON(200, playlists) } -func DeletePlaylist(c *models.ReqContext) Response { +func DeletePlaylist(c *models.ReqContext) response.Response { id := c.ParamsInt64(":id") cmd := models.DeletePlaylistCommand{Id: id, OrgId: c.OrgId} if err := bus.Dispatch(&cmd); err != nil { - return Error(500, "Failed to delete playlist", err) + return response.Error(500, "Failed to delete playlist", err) } - return JSON(200, "") + return response.JSON(200, "") } -func CreatePlaylist(c *models.ReqContext, cmd models.CreatePlaylistCommand) Response { +func CreatePlaylist(c *models.ReqContext, cmd models.CreatePlaylistCommand) response.Response { cmd.OrgId = c.OrgId if err := bus.Dispatch(&cmd); err != nil { - return Error(500, "Failed to create playlist", err) + return response.Error(500, "Failed to create playlist", err) } - return JSON(200, cmd.Result) + return response.JSON(200, cmd.Result) } -func UpdatePlaylist(c *models.ReqContext, cmd models.UpdatePlaylistCommand) Response { +func UpdatePlaylist(c *models.ReqContext, cmd models.UpdatePlaylistCommand) response.Response { cmd.OrgId = c.OrgId cmd.Id = c.ParamsInt64(":id") if err := bus.Dispatch(&cmd); err != nil { - return Error(500, "Failed to save playlist", err) + return response.Error(500, "Failed to save playlist", err) } playlistDTOs, err := LoadPlaylistItemDTOs(cmd.Id) if err != nil { - return Error(500, "Failed to save playlist", err) + return response.Error(500, "Failed to save playlist", err) } cmd.Result.Items = playlistDTOs - return JSON(200, cmd.Result) + return response.JSON(200, cmd.Result) } diff --git a/pkg/api/plugins.go b/pkg/api/plugins.go index 00f103bbcce..6e58f1881fc 100644 --- a/pkg/api/plugins.go +++ b/pkg/api/plugins.go @@ -10,6 +10,7 @@ import ( "github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/plugins" @@ -61,7 +62,7 @@ func (hs *HTTPServer) getPluginContext(pluginID string, user *models.SignedInUse }, nil } -func (hs *HTTPServer) GetPluginList(c *models.ReqContext) Response { +func (hs *HTTPServer) GetPluginList(c *models.ReqContext) response.Response { typeFilter := c.Query("type") enabledFilter := c.Query("enabled") embeddedFilter := c.Query("embedded") @@ -75,7 +76,7 @@ func (hs *HTTPServer) GetPluginList(c *models.ReqContext) Response { pluginSettingsMap, err := plugins.GetPluginSettings(c.OrgId) if err != nil { - return Error(500, "Failed to get list of plugins", err) + return response.Error(500, "Failed to get list of plugins", err) } result := make(dtos.PluginList, 0) @@ -139,15 +140,15 @@ func (hs *HTTPServer) GetPluginList(c *models.ReqContext) Response { } sort.Sort(result) - return JSON(200, result) + return response.JSON(200, result) } -func GetPluginSettingByID(c *models.ReqContext) Response { +func GetPluginSettingByID(c *models.ReqContext) response.Response { pluginID := c.Params(":pluginId") def, exists := plugins.Plugins[pluginID] if !exists { - return Error(404, "Plugin not found, no installed plugin with that id", nil) + return response.Error(404, "Plugin not found, no installed plugin with that id", nil) } dto := &dtos.PluginSetting{ @@ -171,7 +172,7 @@ func GetPluginSettingByID(c *models.ReqContext) Response { query := models.GetPluginSettingByIdQuery{PluginId: pluginID, OrgId: c.OrgId} if err := bus.Dispatch(&query); err != nil { if !errors.Is(err, models.ErrPluginSettingNotFound) { - return Error(500, "Failed to get login settings", nil) + return response.Error(500, "Failed to get login settings", nil) } } else { dto.Enabled = query.Result.Enabled @@ -179,43 +180,43 @@ func GetPluginSettingByID(c *models.ReqContext) Response { dto.JsonData = query.Result.JsonData } - return JSON(200, dto) + return response.JSON(200, dto) } -func UpdatePluginSetting(c *models.ReqContext, cmd models.UpdatePluginSettingCmd) Response { +func UpdatePluginSetting(c *models.ReqContext, cmd models.UpdatePluginSettingCmd) response.Response { pluginID := c.Params(":pluginId") cmd.OrgId = c.OrgId cmd.PluginId = pluginID if _, ok := plugins.Apps[cmd.PluginId]; !ok { - return Error(404, "Plugin not installed.", nil) + return response.Error(404, "Plugin not installed.", nil) } if err := bus.Dispatch(&cmd); err != nil { - return Error(500, "Failed to update plugin setting", err) + return response.Error(500, "Failed to update plugin setting", err) } - return Success("Plugin settings updated") + return response.Success("Plugin settings updated") } -func GetPluginDashboards(c *models.ReqContext) Response { +func GetPluginDashboards(c *models.ReqContext) response.Response { pluginID := c.Params(":pluginId") list, err := plugins.GetPluginDashboards(c.OrgId, pluginID) if err != nil { var notFound plugins.PluginNotFoundError if errors.As(err, ¬Found) { - return Error(404, notFound.Error(), nil) + return response.Error(404, notFound.Error(), nil) } - return Error(500, "Failed to get plugin dashboards", err) + return response.Error(500, "Failed to get plugin dashboards", err) } - return JSON(200, list) + return response.JSON(200, list) } -func GetPluginMarkdown(c *models.ReqContext) Response { +func GetPluginMarkdown(c *models.ReqContext) response.Response { pluginID := c.Params(":pluginId") name := c.Params(":name") @@ -223,28 +224,28 @@ func GetPluginMarkdown(c *models.ReqContext) Response { if err != nil { var notFound plugins.PluginNotFoundError if errors.As(err, ¬Found) { - return Error(404, notFound.Error(), nil) + return response.Error(404, notFound.Error(), nil) } - return Error(500, "Could not get markdown file", err) + return response.Error(500, "Could not get markdown file", err) } // fallback try readme if len(content) == 0 { content, err = plugins.GetPluginMarkdown(pluginID, "readme") if err != nil { - return Error(501, "Could not get markdown file", err) + return response.Error(501, "Could not get markdown file", err) } } - resp := Respond(200, content) + resp := response.Respond(200, content) resp.Header("Content-Type", "text/plain; charset=utf-8") return resp } -func ImportDashboard(c *models.ReqContext, apiCmd dtos.ImportDashboardCommand) Response { +func ImportDashboard(c *models.ReqContext, apiCmd dtos.ImportDashboardCommand) response.Response { if apiCmd.PluginId == "" && apiCmd.Dashboard == nil { - return Error(422, "Dashboard must be set", nil) + return response.Error(422, "Dashboard must be set", nil) } cmd := plugins.ImportDashboardCommand{ @@ -262,17 +263,17 @@ func ImportDashboard(c *models.ReqContext, apiCmd dtos.ImportDashboardCommand) R return dashboardSaveErrorToApiResponse(err) } - return JSON(200, cmd.Result) + return response.JSON(200, cmd.Result) } // CollectPluginMetrics collect metrics from a plugin. // // /api/plugins/:pluginId/metrics -func (hs *HTTPServer) CollectPluginMetrics(c *models.ReqContext) Response { +func (hs *HTTPServer) CollectPluginMetrics(c *models.ReqContext) response.Response { pluginID := c.Params("pluginId") plugin, exists := plugins.Plugins[pluginID] if !exists { - return Error(404, "Plugin not found", nil) + return response.Error(404, "Plugin not found", nil) } resp, err := hs.BackendPluginManager.CollectMetrics(c.Req.Context(), plugin.Id) @@ -283,25 +284,21 @@ func (hs *HTTPServer) CollectPluginMetrics(c *models.ReqContext) Response { headers := make(http.Header) headers.Set("Content-Type", "text/plain") - return &NormalResponse{ - header: headers, - body: resp.PrometheusMetrics, - status: http.StatusOK, - } + return response.CreateNormalResponse(headers, resp.PrometheusMetrics, http.StatusOK) } // CheckHealth returns the health of a plugin. // /api/plugins/:pluginId/health -func (hs *HTTPServer) CheckHealth(c *models.ReqContext) Response { +func (hs *HTTPServer) CheckHealth(c *models.ReqContext) response.Response { pluginID := c.Params("pluginId") pCtx, err := hs.getPluginContext(pluginID, c.SignedInUser) if err != nil { if errors.Is(err, ErrPluginNotFound) { - return Error(404, "Plugin not found", nil) + return response.Error(404, "Plugin not found", nil) } - return Error(500, "Failed to get plugin settings", err) + return response.Error(500, "Failed to get plugin settings", err) } resp, err := hs.BackendPluginManager.CheckHealth(c.Req.Context(), pCtx) @@ -319,17 +316,17 @@ func (hs *HTTPServer) CheckHealth(c *models.ReqContext) Response { var jsonDetails map[string]interface{} err = json.Unmarshal(resp.JSONDetails, &jsonDetails) if err != nil { - return Error(500, "Failed to unmarshal detailed response from backend plugin", err) + return response.Error(500, "Failed to unmarshal detailed response from backend plugin", err) } payload["details"] = jsonDetails } if resp.Status != backend.HealthStatusOk { - return JSON(503, payload) + return response.JSON(503, payload) } - return JSON(200, payload) + return response.JSON(200, payload) } // CallResource passes a resource call from a plugin to the backend plugin. @@ -370,26 +367,26 @@ func (hs *HTTPServer) getCachedPluginSettings(pluginID string, user *models.Sign return query.Result, nil } -func (hs *HTTPServer) GetPluginErrorsList(c *models.ReqContext) Response { - return JSON(200, plugins.ScanningErrors()) +func (hs *HTTPServer) GetPluginErrorsList(c *models.ReqContext) response.Response { + return response.JSON(200, plugins.ScanningErrors()) } -func translatePluginRequestErrorToAPIError(err error) Response { +func translatePluginRequestErrorToAPIError(err error) response.Response { if errors.Is(err, backendplugin.ErrPluginNotRegistered) { - return Error(404, "Plugin not found", err) + return response.Error(404, "Plugin not found", err) } if errors.Is(err, backendplugin.ErrMethodNotImplemented) { - return Error(404, "Not found", err) + return response.Error(404, "Not found", err) } if errors.Is(err, backendplugin.ErrHealthCheckFailed) { - return Error(500, "Plugin health check failed", err) + return response.Error(500, "Plugin health check failed", err) } if errors.Is(err, backendplugin.ErrPluginUnavailable) { - return Error(503, "Plugin unavailable", err) + return response.Error(503, "Plugin unavailable", err) } - return Error(500, "Plugin request failed", err) + return response.Error(500, "Plugin request failed", err) } diff --git a/pkg/api/preferences.go b/pkg/api/preferences.go index f9eed7a6ec5..fc4e41aefe9 100644 --- a/pkg/api/preferences.go +++ b/pkg/api/preferences.go @@ -2,32 +2,33 @@ package api import ( "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/models" ) // POST /api/preferences/set-home-dash -func SetHomeDashboard(c *models.ReqContext, cmd models.SavePreferencesCommand) Response { +func SetHomeDashboard(c *models.ReqContext, cmd models.SavePreferencesCommand) response.Response { cmd.UserId = c.UserId cmd.OrgId = c.OrgId if err := bus.Dispatch(&cmd); err != nil { - return Error(500, "Failed to set home dashboard", err) + return response.Error(500, "Failed to set home dashboard", err) } - return Success("Home dashboard set") + return response.Success("Home dashboard set") } // GET /api/user/preferences -func GetUserPreferences(c *models.ReqContext) Response { +func GetUserPreferences(c *models.ReqContext) response.Response { return getPreferencesFor(c.OrgId, c.UserId, 0) } -func getPreferencesFor(orgID, userID, teamID int64) Response { +func getPreferencesFor(orgID, userID, teamID int64) response.Response { prefsQuery := models.GetPreferencesQuery{UserId: userID, OrgId: orgID, TeamId: teamID} if err := bus.Dispatch(&prefsQuery); err != nil { - return Error(500, "Failed to get preferences", err) + return response.Error(500, "Failed to get preferences", err) } dto := dtos.Prefs{ @@ -36,15 +37,15 @@ func getPreferencesFor(orgID, userID, teamID int64) Response { Timezone: prefsQuery.Result.Timezone, } - return JSON(200, &dto) + return response.JSON(200, &dto) } // PUT /api/user/preferences -func UpdateUserPreferences(c *models.ReqContext, dtoCmd dtos.UpdatePrefsCmd) Response { +func UpdateUserPreferences(c *models.ReqContext, dtoCmd dtos.UpdatePrefsCmd) response.Response { return updatePreferencesFor(c.OrgId, c.UserId, 0, &dtoCmd) } -func updatePreferencesFor(orgID, userID, teamId int64, dtoCmd *dtos.UpdatePrefsCmd) Response { +func updatePreferencesFor(orgID, userID, teamId int64, dtoCmd *dtos.UpdatePrefsCmd) response.Response { saveCmd := models.SavePreferencesCommand{ UserId: userID, OrgId: orgID, @@ -55,18 +56,18 @@ func updatePreferencesFor(orgID, userID, teamId int64, dtoCmd *dtos.UpdatePrefsC } if err := bus.Dispatch(&saveCmd); err != nil { - return Error(500, "Failed to save preferences", err) + return response.Error(500, "Failed to save preferences", err) } - return Success("Preferences updated") + return response.Success("Preferences updated") } // GET /api/org/preferences -func GetOrgPreferences(c *models.ReqContext) Response { +func GetOrgPreferences(c *models.ReqContext) response.Response { return getPreferencesFor(c.OrgId, 0, 0) } // PUT /api/org/preferences -func UpdateOrgPreferences(c *models.ReqContext, dtoCmd dtos.UpdatePrefsCmd) Response { +func UpdateOrgPreferences(c *models.ReqContext, dtoCmd dtos.UpdatePrefsCmd) response.Response { return updatePreferencesFor(c.OrgId, 0, 0, &dtoCmd) } diff --git a/pkg/api/quota.go b/pkg/api/quota.go index ad8764f656c..cb13fbdc065 100644 --- a/pkg/api/quota.go +++ b/pkg/api/quota.go @@ -1,67 +1,68 @@ package api import ( + "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/setting" ) -func GetOrgQuotas(c *models.ReqContext) Response { +func GetOrgQuotas(c *models.ReqContext) response.Response { if !setting.Quota.Enabled { - return Error(404, "Quotas not enabled", nil) + return response.Error(404, "Quotas not enabled", nil) } query := models.GetOrgQuotasQuery{OrgId: c.ParamsInt64(":orgId")} if err := bus.Dispatch(&query); err != nil { - return Error(500, "Failed to get org quotas", err) + return response.Error(500, "Failed to get org quotas", err) } - return JSON(200, query.Result) + return response.JSON(200, query.Result) } -func UpdateOrgQuota(c *models.ReqContext, cmd models.UpdateOrgQuotaCmd) Response { +func UpdateOrgQuota(c *models.ReqContext, cmd models.UpdateOrgQuotaCmd) response.Response { if !setting.Quota.Enabled { - return Error(404, "Quotas not enabled", nil) + return response.Error(404, "Quotas not enabled", nil) } cmd.OrgId = c.ParamsInt64(":orgId") cmd.Target = c.Params(":target") if _, ok := setting.Quota.Org.ToMap()[cmd.Target]; !ok { - return Error(404, "Invalid quota target", nil) + return response.Error(404, "Invalid quota target", nil) } if err := bus.Dispatch(&cmd); err != nil { - return Error(500, "Failed to update org quotas", err) + return response.Error(500, "Failed to update org quotas", err) } - return Success("Organization quota updated") + return response.Success("Organization quota updated") } -func GetUserQuotas(c *models.ReqContext) Response { +func GetUserQuotas(c *models.ReqContext) response.Response { if !setting.Quota.Enabled { - return Error(404, "Quotas not enabled", nil) + return response.Error(404, "Quotas not enabled", nil) } query := models.GetUserQuotasQuery{UserId: c.ParamsInt64(":id")} if err := bus.Dispatch(&query); err != nil { - return Error(500, "Failed to get org quotas", err) + return response.Error(500, "Failed to get org quotas", err) } - return JSON(200, query.Result) + return response.JSON(200, query.Result) } -func UpdateUserQuota(c *models.ReqContext, cmd models.UpdateUserQuotaCmd) Response { +func UpdateUserQuota(c *models.ReqContext, cmd models.UpdateUserQuotaCmd) response.Response { if !setting.Quota.Enabled { - return Error(404, "Quotas not enabled", nil) + return response.Error(404, "Quotas not enabled", nil) } cmd.UserId = c.ParamsInt64(":id") cmd.Target = c.Params(":target") if _, ok := setting.Quota.User.ToMap()[cmd.Target]; !ok { - return Error(404, "Invalid quota target", nil) + return response.Error(404, "Invalid quota target", nil) } if err := bus.Dispatch(&cmd); err != nil { - return Error(500, "Failed to update org quotas", err) + return response.Error(500, "Failed to update org quotas", err) } - return Success("Organization quota updated") + return response.Success("Organization quota updated") } diff --git a/pkg/api/response.go b/pkg/api/response/response.go similarity index 50% rename from pkg/api/response.go rename to pkg/api/response/response.go index bae77f64dbe..e4ebbfc0d56 100644 --- a/pkg/api/response.go +++ b/pkg/api/response/response.go @@ -1,9 +1,11 @@ -package api +package response import ( + "encoding/json" "net/http" "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/setting" jsoniter "github.com/json-iterator/go" ) @@ -17,6 +19,14 @@ type Response interface { Status() int } +func CreateNormalResponse(header http.Header, body []byte, status int) *NormalResponse { + return &NormalResponse{ + header: header, + body: body, + status: status, + } +} + type NormalResponse struct { status int body []byte @@ -35,6 +45,16 @@ func (r *NormalResponse) Body() []byte { return r.body } +// Err gets the response's err. +func (r *NormalResponse) Err() error { + return r.err +} + +// ErrMessage gets the response's errMessage. +func (r *NormalResponse) ErrMessage() string { + return r.errMessage +} + func (r *NormalResponse) WriteTo(ctx *models.ReqContext) { if r.err != nil { ctx.Logger.Error(r.errMessage, "error", r.err, "remote_addr", ctx.RemoteAddr()) @@ -55,13 +75,8 @@ func (r *NormalResponse) Header(key, value string) *NormalResponse { return r } -// Empty creates an empty NormalResponse. -func Empty(status int) *NormalResponse { - return Respond(status, nil) -} - -// streamingResponse is a response that streams itself back to the client. -type streamingResponse struct { +// StreamingResponse is a response that streams itself back to the client. +type StreamingResponse struct { body interface{} status int header http.Header @@ -69,19 +84,19 @@ type streamingResponse struct { // Status gets the response's status. // Required to implement api.Response. -func (r streamingResponse) Status() int { +func (r StreamingResponse) Status() int { return r.status } // Body gets the response's body. // Required to implement api.Response. -func (r streamingResponse) Body() []byte { +func (r StreamingResponse) Body() []byte { return nil } // WriteTo writes the response to the provided context. // Required to implement api.Response. -func (r streamingResponse) WriteTo(ctx *models.ReqContext) { +func (r StreamingResponse) WriteTo(ctx *models.ReqContext) { header := ctx.Resp.Header() for k, v := range r.header { header[k] = v @@ -114,3 +129,88 @@ func (*RedirectResponse) Status() int { func (r *RedirectResponse) Body() []byte { return nil } + +// JSON creates a JSON response. +func JSON(status int, body interface{}) *NormalResponse { + return Respond(status, body).Header("Content-Type", "application/json") +} + +// JSONStreaming creates a streaming JSON response. +func JSONStreaming(status int, body interface{}) StreamingResponse { + header := make(http.Header) + header.Set("Content-Type", "application/json") + return StreamingResponse{ + body: body, + status: status, + header: header, + } +} + +// Success create a successful response +func Success(message string) *NormalResponse { + resp := make(map[string]interface{}) + resp["message"] = message + return JSON(200, resp) +} + +// Error creates an error response. +func Error(status int, message string, err error) *NormalResponse { + data := make(map[string]interface{}) + + switch status { + case 404: + data["message"] = "Not Found" + case 500: + data["message"] = "Internal Server Error" + } + + if message != "" { + data["message"] = message + } + + if err != nil { + if setting.Env != setting.Prod { + data["error"] = err.Error() + } + } + + resp := JSON(status, data) + + if err != nil { + resp.errMessage = message + resp.err = err + } + + return resp +} + +// Empty creates an empty NormalResponse. +func Empty(status int) *NormalResponse { + return Respond(status, nil) +} + +// Respond creates a response. +func Respond(status int, body interface{}) *NormalResponse { + var b []byte + switch t := body.(type) { + case []byte: + b = t + case string: + b = []byte(t) + default: + var err error + if b, err = json.Marshal(body); err != nil { + return Error(500, "body json marshal", err) + } + } + + return &NormalResponse{ + status: status, + body: b, + header: make(http.Header), + } +} + +func Redirect(location string) *RedirectResponse { + return &RedirectResponse{location: location} +} diff --git a/pkg/api/routing/routing.go b/pkg/api/routing/routing.go new file mode 100644 index 00000000000..1aed8420b96 --- /dev/null +++ b/pkg/api/routing/routing.go @@ -0,0 +1,27 @@ +package routing + +import ( + "github.com/grafana/grafana/pkg/api/response" + "github.com/grafana/grafana/pkg/models" + "gopkg.in/macaron.v1" +) + +var ( + ServerError = func(err error) response.Response { + return response.Error(500, "Server error", err) + } +) + +func Wrap(action interface{}) macaron.Handler { + return func(c *models.ReqContext) { + var res response.Response + val, err := c.Invoke(action) + if err == nil && val != nil && len(val) > 0 { + res = val[0].Interface().(response.Response) + } else { + res = ServerError(err) + } + + res.WriteTo(c) + } +} diff --git a/pkg/api/search.go b/pkg/api/search.go index 60f31444540..4f095086766 100644 --- a/pkg/api/search.go +++ b/pkg/api/search.go @@ -6,13 +6,14 @@ import ( "github.com/grafana/grafana/pkg/util" + "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/infra/metrics" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/search" ) -func Search(c *models.ReqContext) Response { +func Search(c *models.ReqContext) response.Response { query := c.Query("query") tags := c.QueryStrings("tag") starred := c.Query("starred") @@ -23,7 +24,7 @@ func Search(c *models.ReqContext) Response { permission := models.PERMISSION_VIEW if limit > 5000 { - return Error(422, "Limit is above maximum allowed (5000), use page parameter to access hits beyond limit", nil) + return response.Error(422, "Limit is above maximum allowed (5000), use page parameter to access hits beyond limit", nil) } if c.Query("permission") == "Edit" { @@ -63,14 +64,14 @@ func Search(c *models.ReqContext) Response { err := bus.Dispatch(&searchQuery) if err != nil { - return Error(500, "Search failed", err) + return response.Error(500, "Search failed", err) } c.TimeRequest(metrics.MApiDashboardSearch) - return JSON(200, searchQuery.Result) + return response.JSON(200, searchQuery.Result) } -func (hs *HTTPServer) ListSortOptions(c *models.ReqContext) Response { +func (hs *HTTPServer) ListSortOptions(c *models.ReqContext) response.Response { opts := hs.SearchService.SortOptions() res := []util.DynMap{} @@ -82,7 +83,7 @@ func (hs *HTTPServer) ListSortOptions(c *models.ReqContext) Response { }) } - return JSON(http.StatusOK, util.DynMap{ + return response.JSON(http.StatusOK, util.DynMap{ "sortOptions": res, }) } diff --git a/pkg/api/short_url.go b/pkg/api/short_url.go index e5e4e72e4c2..524842ba438 100644 --- a/pkg/api/short_url.go +++ b/pkg/api/short_url.go @@ -7,25 +7,26 @@ import ( "strings" "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/util" ) // createShortURL handles requests to create short URLs. -func (hs *HTTPServer) createShortURL(c *models.ReqContext, cmd dtos.CreateShortURLCmd) Response { +func (hs *HTTPServer) createShortURL(c *models.ReqContext, cmd dtos.CreateShortURLCmd) response.Response { hs.log.Debug("Received request to create short URL", "path", cmd.Path) cmd.Path = strings.TrimSpace(cmd.Path) if path.IsAbs(cmd.Path) { hs.log.Error("Invalid short URL path", "path", cmd.Path) - return Error(400, "Path should be relative", nil) + return response.Error(400, "Path should be relative", nil) } shortURL, err := hs.ShortURLService.CreateShortURL(c.Req.Context(), c.SignedInUser, cmd.Path) if err != nil { - return Error(500, "Failed to create short URL", err) + return response.Error(500, "Failed to create short URL", err) } url := fmt.Sprintf("%s/goto/%s", strings.TrimSuffix(setting.AppUrl, "/"), shortURL.Uid) @@ -36,7 +37,7 @@ func (hs *HTTPServer) createShortURL(c *models.ReqContext, cmd dtos.CreateShortU URL: url, } - return JSON(200, dto) + return response.JSON(200, dto) } func (hs *HTTPServer) redirectFromShortURL(c *models.ReqContext) { diff --git a/pkg/api/signup.go b/pkg/api/signup.go index a9db121f452..1dd14230455 100644 --- a/pkg/api/signup.go +++ b/pkg/api/signup.go @@ -4,6 +4,7 @@ import ( "errors" "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/events" "github.com/grafana/grafana/pkg/infra/metrics" @@ -13,22 +14,22 @@ import ( ) // GET /api/user/signup/options -func GetSignUpOptions(c *models.ReqContext) Response { - return JSON(200, util.DynMap{ +func GetSignUpOptions(c *models.ReqContext) response.Response { + return response.JSON(200, util.DynMap{ "verifyEmailEnabled": setting.VerifyEmailEnabled, "autoAssignOrg": setting.AutoAssignOrg, }) } // POST /api/user/signup -func SignUp(c *models.ReqContext, form dtos.SignUpForm) Response { +func SignUp(c *models.ReqContext, form dtos.SignUpForm) response.Response { if !setting.AllowUserSignUp { - return Error(401, "User signup is disabled", nil) + return response.Error(401, "User signup is disabled", nil) } existing := models.GetUserByLoginQuery{LoginOrEmail: form.Email} if err := bus.Dispatch(&existing); err == nil { - return Error(422, "User with same email address already exists", nil) + return response.Error(422, "User with same email address already exists", nil) } cmd := models.CreateTempUserCommand{} @@ -39,29 +40,29 @@ func SignUp(c *models.ReqContext, form dtos.SignUpForm) Response { var err error cmd.Code, err = util.GetRandomString(20) if err != nil { - return Error(500, "Failed to generate random string", err) + return response.Error(500, "Failed to generate random string", err) } cmd.RemoteAddr = c.Req.RemoteAddr if err := bus.Dispatch(&cmd); err != nil { - return Error(500, "Failed to create signup", err) + return response.Error(500, "Failed to create signup", err) } if err := bus.Publish(&events.SignUpStarted{ Email: form.Email, Code: cmd.Code, }); err != nil { - return Error(500, "Failed to publish event", err) + return response.Error(500, "Failed to publish event", err) } metrics.MApiUserSignUpStarted.Inc() - return 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 { +func (hs *HTTPServer) SignUpStep2(c *models.ReqContext, form dtos.SignUpStep2Form) response.Response { if !setting.AllowUserSignUp { - return Error(401, "User signup is disabled", nil) + return response.Error(401, "User signup is disabled", nil) } createUserCmd := models.CreateUserCommand{ @@ -83,10 +84,10 @@ func (hs *HTTPServer) SignUpStep2(c *models.ReqContext, form dtos.SignUpStep2For // dispatch create command if err := bus.Dispatch(&createUserCmd); err != nil { if errors.Is(err, models.ErrUserAlreadyExists) { - return Error(401, "User with same email address already exists", nil) + return response.Error(401, "User with same email address already exists", nil) } - return Error(500, "Failed to create user", err) + return response.Error(500, "Failed to create user", err) } // publish signup event @@ -95,7 +96,7 @@ func (hs *HTTPServer) SignUpStep2(c *models.ReqContext, form dtos.SignUpStep2For Email: user.Email, Name: user.NameOrFallback(), }); err != nil { - return Error(500, "Failed to publish event", err) + return response.Error(500, "Failed to publish event", err) } // mark temp user as completed @@ -106,7 +107,7 @@ func (hs *HTTPServer) SignUpStep2(c *models.ReqContext, form dtos.SignUpStep2For // check for pending invites invitesQuery := models.GetTempUsersQuery{Email: form.Email, Status: models.TmpUserInvitePending} if err := bus.Dispatch(&invitesQuery); err != nil { - return Error(500, "Failed to query database for invites", err) + return response.Error(500, "Failed to query database for invites", err) } apiResponse := util.DynMap{"message": "User sign up completed successfully", "code": "redirect-to-landing-page"} @@ -119,27 +120,27 @@ func (hs *HTTPServer) SignUpStep2(c *models.ReqContext, form dtos.SignUpStep2For err := hs.loginUserWithUser(user, c) if err != nil { - return Error(500, "failed to login user", err) + return response.Error(500, "failed to login user", err) } metrics.MApiUserSignUpCompleted.Inc() - return JSON(200, apiResponse) + return response.JSON(200, apiResponse) } -func verifyUserSignUpEmail(email string, code string) (bool, Response) { +func verifyUserSignUpEmail(email string, code string) (bool, response.Response) { query := models.GetTempUserByCodeQuery{Code: code} if err := bus.Dispatch(&query); err != nil { if errors.Is(err, models.ErrTempUserNotFound) { - return false, Error(404, "Invalid email verification code", nil) + return false, response.Error(404, "Invalid email verification code", nil) } - return false, Error(500, "Failed to read temp user", err) + return false, response.Error(500, "Failed to read temp user", err) } tempUser := query.Result if tempUser.Email != email { - return false, Error(404, "Email verification code does not match email", nil) + return false, response.Error(404, "Email verification code does not match email", nil) } return true, nil diff --git a/pkg/api/stars.go b/pkg/api/stars.go index 6af609db9d3..5c344b903be 100644 --- a/pkg/api/stars.go +++ b/pkg/api/stars.go @@ -1,38 +1,39 @@ package api import ( + "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/models" ) -func StarDashboard(c *models.ReqContext) Response { +func StarDashboard(c *models.ReqContext) response.Response { if !c.IsSignedIn { - return Error(412, "You need to sign in to star dashboards", nil) + return response.Error(412, "You need to sign in to star dashboards", nil) } cmd := models.StarDashboardCommand{UserId: c.UserId, DashboardId: c.ParamsInt64(":id")} if cmd.DashboardId <= 0 { - return Error(400, "Missing dashboard id", nil) + return response.Error(400, "Missing dashboard id", nil) } if err := bus.Dispatch(&cmd); err != nil { - return Error(500, "Failed to star dashboard", err) + return response.Error(500, "Failed to star dashboard", err) } - return Success("Dashboard starred!") + return response.Success("Dashboard starred!") } -func UnstarDashboard(c *models.ReqContext) Response { +func UnstarDashboard(c *models.ReqContext) response.Response { cmd := models.UnstarDashboardCommand{UserId: c.UserId, DashboardId: c.ParamsInt64(":id")} if cmd.DashboardId <= 0 { - return Error(400, "Missing dashboard id", nil) + return response.Error(400, "Missing dashboard id", nil) } if err := bus.Dispatch(&cmd); err != nil { - return Error(500, "Failed to unstar dashboard", err) + return response.Error(500, "Failed to unstar dashboard", err) } - return Success("Dashboard unstarred") + return response.Success("Dashboard unstarred") } diff --git a/pkg/api/team.go b/pkg/api/team.go index f858253cb92..e475724e077 100644 --- a/pkg/api/team.go +++ b/pkg/api/team.go @@ -4,6 +4,7 @@ import ( "errors" "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/teamguardian" @@ -11,18 +12,18 @@ import ( ) // POST /api/teams -func (hs *HTTPServer) CreateTeam(c *models.ReqContext, cmd models.CreateTeamCommand) Response { +func (hs *HTTPServer) CreateTeam(c *models.ReqContext, cmd models.CreateTeamCommand) response.Response { cmd.OrgId = c.OrgId if c.OrgRole == models.ROLE_VIEWER { - return Error(403, "Not allowed to create team.", nil) + return response.Error(403, "Not allowed to create team.", nil) } if err := hs.Bus.Dispatch(&cmd); err != nil { if errors.Is(err, models.ErrTeamNameTaken) { - return Error(409, "Team name taken", err) + return response.Error(409, "Team name taken", err) } - return Error(500, "Failed to create Team", err) + return response.Error(500, "Failed to create Team", err) } if c.OrgRole == models.ROLE_EDITOR && hs.Cfg.EditorsCanAdmin { @@ -45,52 +46,52 @@ func (hs *HTTPServer) CreateTeam(c *models.ReqContext, cmd models.CreateTeamComm } } - return JSON(200, &util.DynMap{ + return response.JSON(200, &util.DynMap{ "teamId": cmd.Result.Id, "message": "Team created", }) } // PUT /api/teams/:teamId -func (hs *HTTPServer) UpdateTeam(c *models.ReqContext, cmd models.UpdateTeamCommand) Response { +func (hs *HTTPServer) UpdateTeam(c *models.ReqContext, cmd models.UpdateTeamCommand) response.Response { cmd.OrgId = c.OrgId cmd.Id = c.ParamsInt64(":teamId") if err := teamguardian.CanAdmin(hs.Bus, cmd.OrgId, cmd.Id, c.SignedInUser); err != nil { - return Error(403, "Not allowed to update team", err) + return response.Error(403, "Not allowed to update team", err) } if err := hs.Bus.Dispatch(&cmd); err != nil { if errors.Is(err, models.ErrTeamNameTaken) { - return Error(400, "Team name taken", err) + return response.Error(400, "Team name taken", err) } - return Error(500, "Failed to update Team", err) + return response.Error(500, "Failed to update Team", err) } - return Success("Team updated") + return response.Success("Team updated") } // DELETE /api/teams/:teamId -func (hs *HTTPServer) DeleteTeamByID(c *models.ReqContext) Response { +func (hs *HTTPServer) DeleteTeamByID(c *models.ReqContext) response.Response { orgId := c.OrgId teamId := c.ParamsInt64(":teamId") user := c.SignedInUser if err := teamguardian.CanAdmin(hs.Bus, orgId, teamId, user); err != nil { - return Error(403, "Not allowed to delete team", err) + return response.Error(403, "Not allowed to delete team", err) } if err := hs.Bus.Dispatch(&models.DeleteTeamCommand{OrgId: orgId, Id: teamId}); err != nil { if errors.Is(err, models.ErrTeamNotFound) { - return Error(404, "Failed to delete Team. ID not found", nil) + return response.Error(404, "Failed to delete Team. ID not found", nil) } - return Error(500, "Failed to delete Team", err) + return response.Error(500, "Failed to delete Team", err) } - return Success("Team deleted") + return response.Success("Team deleted") } // GET /api/teams/search -func (hs *HTTPServer) SearchTeams(c *models.ReqContext) Response { +func (hs *HTTPServer) SearchTeams(c *models.ReqContext) response.Response { perPage := c.QueryInt("perpage") if perPage <= 0 { perPage = 1000 @@ -117,7 +118,7 @@ func (hs *HTTPServer) SearchTeams(c *models.ReqContext) Response { } if err := bus.Dispatch(&query); err != nil { - return Error(500, "Failed to search Teams", err) + return response.Error(500, "Failed to search Teams", err) } for _, team := range query.Result.Teams { @@ -127,11 +128,11 @@ func (hs *HTTPServer) SearchTeams(c *models.ReqContext) Response { query.Result.Page = page query.Result.PerPage = perPage - return JSON(200, query.Result) + return response.JSON(200, query.Result) } // GET /api/teams/:teamId -func (hs *HTTPServer) GetTeamByID(c *models.ReqContext) Response { +func (hs *HTTPServer) GetTeamByID(c *models.ReqContext) response.Response { query := models.GetTeamByIdQuery{ OrgId: c.OrgId, Id: c.ParamsInt64(":teamId"), @@ -141,35 +142,35 @@ func (hs *HTTPServer) GetTeamByID(c *models.ReqContext) Response { if err := bus.Dispatch(&query); err != nil { if errors.Is(err, models.ErrTeamNotFound) { - return Error(404, "Team not found", err) + return response.Error(404, "Team not found", err) } - return Error(500, "Failed to get Team", err) + return response.Error(500, "Failed to get Team", err) } query.Result.AvatarUrl = dtos.GetGravatarUrlWithDefault(query.Result.Email, query.Result.Name) - return JSON(200, &query.Result) + return response.JSON(200, &query.Result) } // GET /api/teams/:teamId/preferences -func (hs *HTTPServer) GetTeamPreferences(c *models.ReqContext) Response { +func (hs *HTTPServer) GetTeamPreferences(c *models.ReqContext) response.Response { teamId := c.ParamsInt64(":teamId") orgId := c.OrgId if err := teamguardian.CanAdmin(hs.Bus, orgId, teamId, c.SignedInUser); err != nil { - return Error(403, "Not allowed to view team preferences.", err) + return response.Error(403, "Not allowed to view team preferences.", err) } return getPreferencesFor(orgId, 0, teamId) } // PUT /api/teams/:teamId/preferences -func (hs *HTTPServer) UpdateTeamPreferences(c *models.ReqContext, dtoCmd dtos.UpdatePrefsCmd) Response { +func (hs *HTTPServer) UpdateTeamPreferences(c *models.ReqContext, dtoCmd dtos.UpdatePrefsCmd) response.Response { teamId := c.ParamsInt64(":teamId") orgId := c.OrgId if err := teamguardian.CanAdmin(hs.Bus, orgId, teamId, c.SignedInUser); err != nil { - return Error(403, "Not allowed to update team preferences.", err) + return response.Error(403, "Not allowed to update team preferences.", err) } return updatePreferencesFor(orgId, 0, teamId, &dtoCmd) diff --git a/pkg/api/team_members.go b/pkg/api/team_members.go index aa9cd2e6852..64bad505c93 100644 --- a/pkg/api/team_members.go +++ b/pkg/api/team_members.go @@ -4,6 +4,7 @@ import ( "errors" "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/teamguardian" @@ -11,11 +12,11 @@ import ( ) // GET /api/teams/:teamId/members -func (hs *HTTPServer) GetTeamMembers(c *models.ReqContext) Response { +func (hs *HTTPServer) GetTeamMembers(c *models.ReqContext) response.Response { query := models.GetTeamMembersQuery{OrgId: c.OrgId, TeamId: c.ParamsInt64(":teamId")} if err := bus.Dispatch(&query); err != nil { - return Error(500, "Failed to get Team Members", err) + return response.Error(500, "Failed to get Team Members", err) } filteredMembers := make([]*models.TeamMemberDTO, 0, len(query.Result)) @@ -35,42 +36,42 @@ func (hs *HTTPServer) GetTeamMembers(c *models.ReqContext) Response { filteredMembers = append(filteredMembers, member) } - return JSON(200, filteredMembers) + return response.JSON(200, filteredMembers) } // POST /api/teams/:teamId/members -func (hs *HTTPServer) AddTeamMember(c *models.ReqContext, cmd models.AddTeamMemberCommand) Response { +func (hs *HTTPServer) AddTeamMember(c *models.ReqContext, cmd models.AddTeamMemberCommand) response.Response { cmd.OrgId = c.OrgId cmd.TeamId = c.ParamsInt64(":teamId") if err := teamguardian.CanAdmin(hs.Bus, cmd.OrgId, cmd.TeamId, c.SignedInUser); err != nil { - return Error(403, "Not allowed to add team member", err) + return response.Error(403, "Not allowed to add team member", err) } if err := hs.Bus.Dispatch(&cmd); err != nil { if errors.Is(err, models.ErrTeamNotFound) { - return Error(404, "Team not found", nil) + return response.Error(404, "Team not found", nil) } if errors.Is(err, models.ErrTeamMemberAlreadyAdded) { - return Error(400, "User is already added to this team", nil) + return response.Error(400, "User is already added to this team", nil) } - return Error(500, "Failed to add Member to Team", err) + return response.Error(500, "Failed to add Member to Team", err) } - return JSON(200, &util.DynMap{ + return response.JSON(200, &util.DynMap{ "message": "Member added to Team", }) } // PUT /:teamId/members/:userId -func (hs *HTTPServer) UpdateTeamMember(c *models.ReqContext, cmd models.UpdateTeamMemberCommand) Response { +func (hs *HTTPServer) UpdateTeamMember(c *models.ReqContext, cmd models.UpdateTeamMemberCommand) response.Response { teamId := c.ParamsInt64(":teamId") orgId := c.OrgId if err := teamguardian.CanAdmin(hs.Bus, orgId, teamId, c.SignedInUser); err != nil { - return Error(403, "Not allowed to update team member", err) + return response.Error(403, "Not allowed to update team member", err) } if c.OrgRole != models.ROLE_ADMIN { @@ -83,21 +84,21 @@ func (hs *HTTPServer) UpdateTeamMember(c *models.ReqContext, cmd models.UpdateTe if err := hs.Bus.Dispatch(&cmd); err != nil { if errors.Is(err, models.ErrTeamMemberNotFound) { - return Error(404, "Team member not found.", nil) + return response.Error(404, "Team member not found.", nil) } - return Error(500, "Failed to update team member.", err) + return response.Error(500, "Failed to update team member.", err) } - return Success("Team member updated") + return response.Success("Team member updated") } // DELETE /api/teams/:teamId/members/:userId -func (hs *HTTPServer) RemoveTeamMember(c *models.ReqContext) Response { +func (hs *HTTPServer) RemoveTeamMember(c *models.ReqContext) response.Response { orgId := c.OrgId teamId := c.ParamsInt64(":teamId") userId := c.ParamsInt64(":userId") if err := teamguardian.CanAdmin(hs.Bus, orgId, teamId, c.SignedInUser); err != nil { - return Error(403, "Not allowed to remove team member", err) + return response.Error(403, "Not allowed to remove team member", err) } protectLastAdmin := false @@ -107,14 +108,14 @@ func (hs *HTTPServer) RemoveTeamMember(c *models.ReqContext) Response { if err := hs.Bus.Dispatch(&models.RemoveTeamMemberCommand{OrgId: orgId, TeamId: teamId, UserId: userId, ProtectLastAdmin: protectLastAdmin}); err != nil { if errors.Is(err, models.ErrTeamNotFound) { - return Error(404, "Team not found", nil) + return response.Error(404, "Team not found", nil) } if errors.Is(err, models.ErrTeamMemberNotFound) { - return Error(404, "Team member not found", nil) + return response.Error(404, "Team member not found", nil) } - return Error(500, "Failed to remove Member from Team", err) + return response.Error(500, "Failed to remove Member from Team", err) } - return Success("Team Member removed") + return response.Success("Team Member removed") } diff --git a/pkg/api/user.go b/pkg/api/user.go index 84a4138fb39..7f3aa1fdc7c 100644 --- a/pkg/api/user.go +++ b/pkg/api/user.go @@ -4,6 +4,7 @@ import ( "errors" "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/setting" @@ -11,23 +12,23 @@ import ( ) // GET /api/user (current authenticated user) -func GetSignedInUser(c *models.ReqContext) Response { +func GetSignedInUser(c *models.ReqContext) response.Response { return getUserUserProfile(c.UserId) } // GET /api/users/:id -func GetUserByID(c *models.ReqContext) Response { +func GetUserByID(c *models.ReqContext) response.Response { return getUserUserProfile(c.ParamsInt64(":id")) } -func getUserUserProfile(userID int64) Response { +func getUserUserProfile(userID int64) response.Response { query := models.GetUserProfileQuery{UserId: userID} if err := bus.Dispatch(&query); err != nil { if errors.Is(err, models.ErrUserNotFound) { - return Error(404, models.ErrUserNotFound.Error(), nil) + return response.Error(404, models.ErrUserNotFound.Error(), nil) } - return Error(500, "Failed to get user", err) + return response.Error(500, "Failed to get user", err) } getAuthQuery := models.GetAuthInfoQuery{UserId: userID} @@ -40,17 +41,17 @@ func getUserUserProfile(userID int64) Response { query.Result.AvatarUrl = dtos.GetGravatarUrl(query.Result.Email) - return JSON(200, query.Result) + return response.JSON(200, query.Result) } // GET /api/users/lookup -func GetUserByLoginOrEmail(c *models.ReqContext) Response { +func GetUserByLoginOrEmail(c *models.ReqContext) response.Response { query := models.GetUserByLoginQuery{LoginOrEmail: c.Query("loginOrEmail")} if err := bus.Dispatch(&query); err != nil { if errors.Is(err, models.ErrUserNotFound) { - return Error(404, models.ErrUserNotFound.Error(), nil) + return response.Error(404, models.ErrUserNotFound.Error(), nil) } - return Error(500, "Failed to get user", err) + return response.Error(500, "Failed to get user", err) } user := query.Result result := models.UserProfileDTO{ @@ -64,17 +65,17 @@ func GetUserByLoginOrEmail(c *models.ReqContext) Response { UpdatedAt: user.Updated, CreatedAt: user.Created, } - return JSON(200, &result) + return response.JSON(200, &result) } // POST /api/user -func UpdateSignedInUser(c *models.ReqContext, cmd models.UpdateUserCommand) Response { +func UpdateSignedInUser(c *models.ReqContext, cmd models.UpdateUserCommand) response.Response { if setting.AuthProxyEnabled { if setting.AuthProxyHeaderProperty == "email" && cmd.Email != c.Email { - return 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) } if setting.AuthProxyHeaderProperty == "username" && cmd.Login != c.Login { - return Error(400, "Not allowed to change username when auth proxy is using username property", nil) + return response.Error(400, "Not allowed to change username when auth proxy is using username property", nil) } } cmd.UserId = c.UserId @@ -82,85 +83,85 @@ func UpdateSignedInUser(c *models.ReqContext, cmd models.UpdateUserCommand) Resp } // POST /api/users/:id -func UpdateUser(c *models.ReqContext, cmd models.UpdateUserCommand) Response { +func UpdateUser(c *models.ReqContext, cmd models.UpdateUserCommand) response.Response { cmd.UserId = c.ParamsInt64(":id") return handleUpdateUser(cmd) } // POST /api/users/:id/using/:orgId -func UpdateUserActiveOrg(c *models.ReqContext) Response { +func UpdateUserActiveOrg(c *models.ReqContext) response.Response { userID := c.ParamsInt64(":id") orgID := c.ParamsInt64(":orgId") if !validateUsingOrg(userID, orgID) { - return Error(401, "Not a valid organization", nil) + return response.Error(401, "Not a valid organization", nil) } cmd := models.SetUsingOrgCommand{UserId: userID, OrgId: orgID} if err := bus.Dispatch(&cmd); err != nil { - return Error(500, "Failed to change active organization", err) + return response.Error(500, "Failed to change active organization", err) } - return Success("Active organization changed") + return response.Success("Active organization changed") } -func handleUpdateUser(cmd models.UpdateUserCommand) Response { +func handleUpdateUser(cmd models.UpdateUserCommand) response.Response { if len(cmd.Login) == 0 { cmd.Login = cmd.Email if len(cmd.Login) == 0 { - return Error(400, "Validation error, need to specify either username or email", nil) + return response.Error(400, "Validation error, need to specify either username or email", nil) } } if err := bus.Dispatch(&cmd); err != nil { - return Error(500, "Failed to update user", err) + return response.Error(500, "Failed to update user", err) } - return Success("User updated") + return response.Success("User updated") } // GET /api/user/orgs -func GetSignedInUserOrgList(c *models.ReqContext) Response { +func GetSignedInUserOrgList(c *models.ReqContext) response.Response { return getUserOrgList(c.UserId) } // GET /api/user/teams -func GetSignedInUserTeamList(c *models.ReqContext) Response { +func GetSignedInUserTeamList(c *models.ReqContext) response.Response { return getUserTeamList(c.OrgId, c.UserId) } // GET /api/users/:id/teams -func GetUserTeams(c *models.ReqContext) Response { +func GetUserTeams(c *models.ReqContext) response.Response { return getUserTeamList(c.OrgId, c.ParamsInt64(":id")) } -func getUserTeamList(orgID int64, userID int64) Response { +func getUserTeamList(orgID int64, userID int64) response.Response { query := models.GetTeamsByUserQuery{OrgId: orgID, UserId: userID} if err := bus.Dispatch(&query); err != nil { - return Error(500, "Failed to get user teams", err) + return response.Error(500, "Failed to get user teams", err) } for _, team := range query.Result { team.AvatarUrl = dtos.GetGravatarUrlWithDefault(team.Email, team.Name) } - return JSON(200, query.Result) + return response.JSON(200, query.Result) } // GET /api/users/:id/orgs -func GetUserOrgList(c *models.ReqContext) Response { +func GetUserOrgList(c *models.ReqContext) response.Response { return getUserOrgList(c.ParamsInt64(":id")) } -func getUserOrgList(userID int64) Response { +func getUserOrgList(userID int64) response.Response { query := models.GetUserOrgListQuery{UserId: userID} if err := bus.Dispatch(&query); err != nil { - return Error(500, "Failed to get user organizations", err) + return response.Error(500, "Failed to get user organizations", err) } - return JSON(200, query.Result) + return response.JSON(200, query.Result) } func validateUsingOrg(userID int64, orgID int64) bool { @@ -182,20 +183,20 @@ func validateUsingOrg(userID int64, orgID int64) bool { } // POST /api/user/using/:id -func UserSetUsingOrg(c *models.ReqContext) Response { +func UserSetUsingOrg(c *models.ReqContext) response.Response { orgID := c.ParamsInt64(":id") if !validateUsingOrg(c.UserId, orgID) { - return Error(401, "Not a valid organization", nil) + return response.Error(401, "Not a valid organization", nil) } cmd := models.SetUsingOrgCommand{UserId: c.UserId, OrgId: orgID} if err := bus.Dispatch(&cmd); err != nil { - return Error(500, "Failed to change active organization", err) + return response.Error(500, "Failed to change active organization", err) } - return Success("Active organization changed") + return response.Success("Active organization changed") } // GET /profile/switch-org/:id @@ -215,41 +216,41 @@ func (hs *HTTPServer) ChangeActiveOrgAndRedirectToHome(c *models.ReqContext) { c.Redirect(setting.AppSubUrl + "/") } -func ChangeUserPassword(c *models.ReqContext, cmd models.ChangeUserPasswordCommand) Response { +func ChangeUserPassword(c *models.ReqContext, cmd models.ChangeUserPasswordCommand) response.Response { if setting.LDAPEnabled || setting.AuthProxyEnabled { - return 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) } userQuery := models.GetUserByIdQuery{Id: c.UserId} if err := bus.Dispatch(&userQuery); err != nil { - return Error(500, "Could not read user from database", err) + return response.Error(500, "Could not read user from database", err) } passwordHashed, err := util.EncodePassword(cmd.OldPassword, userQuery.Result.Salt) if err != nil { - return Error(500, "Failed to encode password", err) + return response.Error(500, "Failed to encode password", err) } if passwordHashed != userQuery.Result.Password { - return Error(401, "Invalid old password", nil) + return response.Error(401, "Invalid old password", nil) } password := models.Password(cmd.NewPassword) if password.IsWeak() { - return Error(400, "New password is too short", nil) + return response.Error(400, "New password is too short", nil) } cmd.UserId = c.UserId cmd.NewPassword, err = util.EncodePassword(cmd.NewPassword, userQuery.Result.Salt) if err != nil { - return Error(500, "Failed to encode password", err) + return response.Error(500, "Failed to encode password", err) } if err := bus.Dispatch(&cmd); err != nil { - return Error(500, "Failed to change user password", err) + return response.Error(500, "Failed to change user password", err) } - return Success("User password changed") + return response.Success("User password changed") } // redirectToChangePassword handles GET /.well-known/change-password. @@ -258,23 +259,23 @@ func redirectToChangePassword(c *models.ReqContext) { } // GET /api/users -func SearchUsers(c *models.ReqContext) Response { +func SearchUsers(c *models.ReqContext) response.Response { query, err := searchUser(c) if err != nil { - return Error(500, "Failed to fetch users", err) + return response.Error(500, "Failed to fetch users", err) } - return JSON(200, query.Result.Users) + return response.JSON(200, query.Result.Users) } // GET /api/users/search -func SearchUsersWithPaging(c *models.ReqContext) Response { +func SearchUsersWithPaging(c *models.ReqContext) response.Response { query, err := searchUser(c) if err != nil { - return Error(500, "Failed to fetch users", err) + return response.Error(500, "Failed to fetch users", err) } - return JSON(200, query.Result) + return response.JSON(200, query.Result) } func searchUser(c *models.ReqContext) (*models.SearchUsersQuery, error) { @@ -311,7 +312,7 @@ func searchUser(c *models.ReqContext) (*models.SearchUsersQuery, error) { return query, nil } -func SetHelpFlag(c *models.ReqContext) Response { +func SetHelpFlag(c *models.ReqContext) response.Response { flag := c.ParamsInt64(":id") bitmask := &c.HelpFlags1 @@ -323,23 +324,23 @@ func SetHelpFlag(c *models.ReqContext) Response { } if err := bus.Dispatch(&cmd); err != nil { - return Error(500, "Failed to update help flag", err) + return response.Error(500, "Failed to update help flag", err) } - return JSON(200, &util.DynMap{"message": "Help flag set", "helpFlags1": cmd.HelpFlags1}) + return response.JSON(200, &util.DynMap{"message": "Help flag set", "helpFlags1": cmd.HelpFlags1}) } -func ClearHelpFlags(c *models.ReqContext) Response { +func ClearHelpFlags(c *models.ReqContext) response.Response { cmd := models.SetUserHelpFlagCommand{ UserId: c.UserId, HelpFlags1: models.HelpFlags1(0), } if err := bus.Dispatch(&cmd); err != nil { - return Error(500, "Failed to update help flag", err) + return response.Error(500, "Failed to update help flag", err) } - return JSON(200, &util.DynMap{"message": "Help flag set", "helpFlags1": cmd.HelpFlags1}) + return response.JSON(200, &util.DynMap{"message": "Help flag set", "helpFlags1": cmd.HelpFlags1}) } func GetAuthProviderLabel(authModule string) string { diff --git a/pkg/api/user_token.go b/pkg/api/user_token.go index a76e1cd8244..c143e5e6089 100644 --- a/pkg/api/user_token.go +++ b/pkg/api/user_token.go @@ -6,6 +6,7 @@ import ( "time" "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/util" @@ -13,48 +14,48 @@ import ( ) // GET /api/user/auth-tokens -func (hs *HTTPServer) GetUserAuthTokens(c *models.ReqContext) Response { +func (hs *HTTPServer) GetUserAuthTokens(c *models.ReqContext) response.Response { return hs.getUserAuthTokensInternal(c, c.UserId) } // POST /api/user/revoke-auth-token -func (hs *HTTPServer) RevokeUserAuthToken(c *models.ReqContext, cmd models.RevokeAuthTokenCmd) Response { +func (hs *HTTPServer) RevokeUserAuthToken(c *models.ReqContext, cmd models.RevokeAuthTokenCmd) response.Response { return hs.revokeUserAuthTokenInternal(c, c.UserId, cmd) } -func (hs *HTTPServer) logoutUserFromAllDevicesInternal(ctx context.Context, userID int64) Response { +func (hs *HTTPServer) logoutUserFromAllDevicesInternal(ctx context.Context, userID int64) response.Response { userQuery := models.GetUserByIdQuery{Id: userID} if err := bus.Dispatch(&userQuery); err != nil { if errors.Is(err, models.ErrUserNotFound) { - return Error(404, "User not found", err) + return response.Error(404, "User not found", err) } - return Error(500, "Could not read user from database", err) + return response.Error(500, "Could not read user from database", err) } err := hs.AuthTokenService.RevokeAllUserTokens(ctx, userID) if err != nil { - return Error(500, "Failed to logout user", err) + return response.Error(500, "Failed to logout user", err) } - return JSON(200, util.DynMap{ + return response.JSON(200, util.DynMap{ "message": "User logged out", }) } -func (hs *HTTPServer) getUserAuthTokensInternal(c *models.ReqContext, userID int64) Response { +func (hs *HTTPServer) getUserAuthTokensInternal(c *models.ReqContext, userID int64) response.Response { userQuery := models.GetUserByIdQuery{Id: userID} if err := bus.Dispatch(&userQuery); err != nil { if errors.Is(err, models.ErrUserNotFound) { - return Error(404, "User not found", err) + return response.Error(404, "User not found", err) } - return Error(500, "Failed to get user", err) + return response.Error(500, "Failed to get user", err) } tokens, err := hs.AuthTokenService.GetUserTokens(c.Req.Context(), userID) if err != nil { - return Error(500, "Failed to get user auth tokens", err) + return response.Error(500, "Failed to get user auth tokens", err) } result := []*dtos.UserToken{} @@ -106,40 +107,40 @@ func (hs *HTTPServer) getUserAuthTokensInternal(c *models.ReqContext, userID int }) } - return JSON(200, result) + return response.JSON(200, result) } -func (hs *HTTPServer) revokeUserAuthTokenInternal(c *models.ReqContext, userID int64, cmd models.RevokeAuthTokenCmd) Response { +func (hs *HTTPServer) revokeUserAuthTokenInternal(c *models.ReqContext, userID int64, cmd models.RevokeAuthTokenCmd) response.Response { userQuery := models.GetUserByIdQuery{Id: userID} if err := bus.Dispatch(&userQuery); err != nil { if errors.Is(err, models.ErrUserNotFound) { - return Error(404, "User not found", err) + return response.Error(404, "User not found", err) } - return Error(500, "Failed to get user", err) + return response.Error(500, "Failed to get user", err) } token, err := hs.AuthTokenService.GetUserToken(c.Req.Context(), userID, cmd.AuthTokenId) if err != nil { if errors.Is(err, models.ErrUserTokenNotFound) { - return Error(404, "User auth token not found", err) + return response.Error(404, "User auth token not found", err) } - return Error(500, "Failed to get user auth token", err) + return response.Error(500, "Failed to get user auth token", err) } if c.UserToken != nil && c.UserToken.Id == token.Id { - return Error(400, "Cannot revoke active user auth token", nil) + return response.Error(400, "Cannot revoke active user auth token", nil) } err = hs.AuthTokenService.RevokeToken(c.Req.Context(), token) if err != nil { if errors.Is(err, models.ErrUserTokenNotFound) { - return Error(404, "User auth token not found", err) + return response.Error(404, "User auth token not found", err) } - return Error(500, "Failed to revoke user auth token", err) + return response.Error(500, "Failed to revoke user auth token", err) } - return JSON(200, util.DynMap{ + return response.JSON(200, util.DynMap{ "message": "User auth token revoked", }) } diff --git a/pkg/api/user_token_test.go b/pkg/api/user_token_test.go index e28271b1443..65883fa10dd 100644 --- a/pkg/api/user_token_test.go +++ b/pkg/api/user_token_test.go @@ -6,6 +6,8 @@ import ( "testing" "time" + "github.com/grafana/grafana/pkg/api/response" + "github.com/grafana/grafana/pkg/api/routing" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/auth" @@ -181,7 +183,7 @@ func revokeUserAuthTokenScenario(t *testing.T, desc string, url string, routePat sc := setupScenarioContext(t, url) sc.userAuthTokenService = fakeAuthTokenService - sc.defaultHandler = Wrap(func(c *models.ReqContext) Response { + sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.context = c sc.context.UserId = userId sc.context.OrgId = testOrgID @@ -209,7 +211,7 @@ func getUserAuthTokensScenario(t *testing.T, desc string, url string, routePatte sc := setupScenarioContext(t, url) sc.userAuthTokenService = fakeAuthTokenService - sc.defaultHandler = Wrap(func(c *models.ReqContext) Response { + sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.context = c sc.context.UserId = userId sc.context.OrgId = testOrgID @@ -234,7 +236,7 @@ func logoutUserFromAllDevicesInternalScenario(t *testing.T, desc string, userId } sc := setupScenarioContext(t, "/") - sc.defaultHandler = Wrap(func(c *models.ReqContext) Response { + sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.context = c sc.context.UserId = testUserID sc.context.OrgId = testOrgID @@ -263,7 +265,7 @@ func revokeUserAuthTokenInternalScenario(t *testing.T, desc string, cmd models.R sc := setupScenarioContext(t, "/") sc.userAuthTokenService = fakeAuthTokenService - sc.defaultHandler = Wrap(func(c *models.ReqContext) Response { + sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.context = c sc.context.UserId = testUserID sc.context.OrgId = testOrgID @@ -292,7 +294,7 @@ func getUserAuthTokensInternalScenario(t *testing.T, desc string, token *models. sc := setupScenarioContext(t, "/") sc.userAuthTokenService = fakeAuthTokenService - sc.defaultHandler = Wrap(func(c *models.ReqContext) Response { + sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.context = c sc.context.UserId = testUserID sc.context.OrgId = testOrgID diff --git a/pkg/services/librarypanels/api.go b/pkg/services/librarypanels/api.go index 600fd357afb..b60f28f3f49 100644 --- a/pkg/services/librarypanels/api.go +++ b/pkg/services/librarypanels/api.go @@ -4,7 +4,7 @@ import ( "errors" "github.com/go-macaron/binding" - "github.com/grafana/grafana/pkg/api" + "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/api/routing" "github.com/grafana/grafana/pkg/middleware" "github.com/grafana/grafana/pkg/models" @@ -17,119 +17,119 @@ func (lps *LibraryPanelService) registerAPIEndpoints() { } lps.RouteRegister.Group("/api/library-panels", func(libraryPanels routing.RouteRegister) { - libraryPanels.Post("/", middleware.ReqSignedIn, binding.Bind(createLibraryPanelCommand{}), api.Wrap(lps.createHandler)) - libraryPanels.Post("/:uid/dashboards/:dashboardId", middleware.ReqSignedIn, api.Wrap(lps.connectHandler)) - libraryPanels.Delete("/:uid", middleware.ReqSignedIn, api.Wrap(lps.deleteHandler)) - libraryPanels.Delete("/:uid/dashboards/:dashboardId", middleware.ReqSignedIn, api.Wrap(lps.disconnectHandler)) - libraryPanels.Get("/", middleware.ReqSignedIn, api.Wrap(lps.getAllHandler)) - libraryPanels.Get("/:uid", middleware.ReqSignedIn, api.Wrap(lps.getHandler)) - libraryPanels.Get("/:uid/dashboards/", middleware.ReqSignedIn, api.Wrap(lps.getConnectedDashboardsHandler)) - libraryPanels.Patch("/:uid", middleware.ReqSignedIn, binding.Bind(patchLibraryPanelCommand{}), api.Wrap(lps.patchHandler)) + libraryPanels.Post("/", middleware.ReqSignedIn, binding.Bind(createLibraryPanelCommand{}), routing.Wrap(lps.createHandler)) + libraryPanels.Post("/:uid/dashboards/:dashboardId", middleware.ReqSignedIn, routing.Wrap(lps.connectHandler)) + libraryPanels.Delete("/:uid", middleware.ReqSignedIn, routing.Wrap(lps.deleteHandler)) + libraryPanels.Delete("/:uid/dashboards/:dashboardId", middleware.ReqSignedIn, routing.Wrap(lps.disconnectHandler)) + libraryPanels.Get("/", middleware.ReqSignedIn, routing.Wrap(lps.getAllHandler)) + libraryPanels.Get("/:uid", middleware.ReqSignedIn, routing.Wrap(lps.getHandler)) + libraryPanels.Get("/:uid/dashboards/", middleware.ReqSignedIn, routing.Wrap(lps.getConnectedDashboardsHandler)) + libraryPanels.Patch("/:uid", middleware.ReqSignedIn, binding.Bind(patchLibraryPanelCommand{}), routing.Wrap(lps.patchHandler)) }) } // createHandler handles POST /api/library-panels. -func (lps *LibraryPanelService) createHandler(c *models.ReqContext, cmd createLibraryPanelCommand) api.Response { +func (lps *LibraryPanelService) createHandler(c *models.ReqContext, cmd createLibraryPanelCommand) response.Response { panel, err := lps.createLibraryPanel(c, cmd) if err != nil { if errors.Is(err, errLibraryPanelAlreadyExists) { - return api.Error(400, errLibraryPanelAlreadyExists.Error(), err) + return response.Error(400, errLibraryPanelAlreadyExists.Error(), err) } - return api.Error(500, "Failed to create library panel", err) + return response.Error(500, "Failed to create library panel", err) } - return api.JSON(200, util.DynMap{"result": panel}) + return response.JSON(200, util.DynMap{"result": panel}) } // connectHandler handles POST /api/library-panels/:uid/dashboards/:dashboardId. -func (lps *LibraryPanelService) connectHandler(c *models.ReqContext) api.Response { +func (lps *LibraryPanelService) connectHandler(c *models.ReqContext) response.Response { if err := lps.connectDashboard(c, c.Params(":uid"), c.ParamsInt64(":dashboardId")); err != nil { if errors.Is(err, errLibraryPanelNotFound) { - return api.Error(404, errLibraryPanelNotFound.Error(), err) + return response.Error(404, errLibraryPanelNotFound.Error(), err) } - return api.Error(500, "Failed to connect library panel", err) + return response.Error(500, "Failed to connect library panel", err) } - return api.Success("Library panel connected") + return response.Success("Library panel connected") } // deleteHandler handles DELETE /api/library-panels/:uid. -func (lps *LibraryPanelService) deleteHandler(c *models.ReqContext) api.Response { +func (lps *LibraryPanelService) deleteHandler(c *models.ReqContext) response.Response { err := lps.deleteLibraryPanel(c, c.Params(":uid")) if err != nil { if errors.Is(err, errLibraryPanelNotFound) { - return api.Error(404, errLibraryPanelNotFound.Error(), err) + return response.Error(404, errLibraryPanelNotFound.Error(), err) } - return api.Error(500, "Failed to delete library panel", err) + return response.Error(500, "Failed to delete library panel", err) } - return api.Success("Library panel deleted") + return response.Success("Library panel deleted") } // disconnectHandler handles DELETE /api/library-panels/:uid/dashboards/:dashboardId. -func (lps *LibraryPanelService) disconnectHandler(c *models.ReqContext) api.Response { +func (lps *LibraryPanelService) disconnectHandler(c *models.ReqContext) response.Response { err := lps.disconnectDashboard(c, c.Params(":uid"), c.ParamsInt64(":dashboardId")) if err != nil { if errors.Is(err, errLibraryPanelNotFound) { - return api.Error(404, errLibraryPanelNotFound.Error(), err) + return response.Error(404, errLibraryPanelNotFound.Error(), err) } if errors.Is(err, errLibraryPanelDashboardNotFound) { - return api.Error(404, errLibraryPanelDashboardNotFound.Error(), err) + return response.Error(404, errLibraryPanelDashboardNotFound.Error(), err) } - return api.Error(500, "Failed to disconnect library panel", err) + return response.Error(500, "Failed to disconnect library panel", err) } - return api.Success("Library panel disconnected") + return response.Success("Library panel disconnected") } // getHandler handles GET /api/library-panels/:uid. -func (lps *LibraryPanelService) getHandler(c *models.ReqContext) api.Response { +func (lps *LibraryPanelService) getHandler(c *models.ReqContext) response.Response { libraryPanel, err := lps.getLibraryPanel(c, c.Params(":uid")) if err != nil { if errors.Is(err, errLibraryPanelNotFound) { - return api.Error(404, errLibraryPanelNotFound.Error(), err) + return response.Error(404, errLibraryPanelNotFound.Error(), err) } - return api.Error(500, "Failed to get library panel", err) + return response.Error(500, "Failed to get library panel", err) } - return api.JSON(200, util.DynMap{"result": libraryPanel}) + return response.JSON(200, util.DynMap{"result": libraryPanel}) } // getAllHandler handles GET /api/library-panels/. -func (lps *LibraryPanelService) getAllHandler(c *models.ReqContext) api.Response { +func (lps *LibraryPanelService) getAllHandler(c *models.ReqContext) response.Response { libraryPanels, err := lps.getAllLibraryPanels(c) if err != nil { - return api.Error(500, "Failed to get library panels", err) + return response.Error(500, "Failed to get library panels", err) } - return api.JSON(200, util.DynMap{"result": libraryPanels}) + return response.JSON(200, util.DynMap{"result": libraryPanels}) } // getConnectedDashboardsHandler handles GET /api/library-panels/:uid/dashboards/. -func (lps *LibraryPanelService) getConnectedDashboardsHandler(c *models.ReqContext) api.Response { +func (lps *LibraryPanelService) getConnectedDashboardsHandler(c *models.ReqContext) response.Response { dashboardIDs, err := lps.getConnectedDashboards(c, c.Params(":uid")) if err != nil { if errors.Is(err, errLibraryPanelNotFound) { - return api.Error(404, errLibraryPanelNotFound.Error(), err) + return response.Error(404, errLibraryPanelNotFound.Error(), err) } - return api.Error(500, "Failed to get connected dashboards", err) + return response.Error(500, "Failed to get connected dashboards", err) } - return api.JSON(200, util.DynMap{"result": dashboardIDs}) + return response.JSON(200, util.DynMap{"result": dashboardIDs}) } // patchHandler handles PATCH /api/library-panels/:uid -func (lps *LibraryPanelService) patchHandler(c *models.ReqContext, cmd patchLibraryPanelCommand) api.Response { +func (lps *LibraryPanelService) patchHandler(c *models.ReqContext, cmd patchLibraryPanelCommand) response.Response { libraryPanel, err := lps.patchLibraryPanel(c, cmd, c.Params(":uid")) if err != nil { if errors.Is(err, errLibraryPanelAlreadyExists) { - return api.Error(400, errLibraryPanelAlreadyExists.Error(), err) + return response.Error(400, errLibraryPanelAlreadyExists.Error(), err) } if errors.Is(err, errLibraryPanelNotFound) { - return api.Error(404, errLibraryPanelNotFound.Error(), err) + return response.Error(404, errLibraryPanelNotFound.Error(), err) } - return api.Error(500, "Failed to update library panel", err) + return response.Error(500, "Failed to update library panel", err) } - return api.JSON(200, util.DynMap{"result": libraryPanel}) + return response.JSON(200, util.DynMap{"result": libraryPanel}) } diff --git a/pkg/services/ngalert/api.go b/pkg/services/ngalert/api.go index 1c390f78619..70e7e0620da 100644 --- a/pkg/services/ngalert/api.go +++ b/pkg/services/ngalert/api.go @@ -3,7 +3,7 @@ package ngalert import ( "github.com/go-macaron/binding" "github.com/grafana/grafana-plugin-sdk-go/data" - "github.com/grafana/grafana/pkg/api" + "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/api/routing" "github.com/grafana/grafana/pkg/middleware" "github.com/grafana/grafana/pkg/models" @@ -14,79 +14,79 @@ import ( func (ng *AlertNG) registerAPIEndpoints() { ng.RouteRegister.Group("/api/alert-definitions", func(alertDefinitions routing.RouteRegister) { - alertDefinitions.Get("", middleware.ReqSignedIn, api.Wrap(ng.listAlertDefinitions)) - alertDefinitions.Get("/eval/:alertDefinitionUID", ng.validateOrgAlertDefinition, api.Wrap(ng.alertDefinitionEvalEndpoint)) - alertDefinitions.Post("/eval", middleware.ReqSignedIn, binding.Bind(evalAlertConditionCommand{}), api.Wrap(ng.conditionEvalEndpoint)) - alertDefinitions.Get("/:alertDefinitionUID", ng.validateOrgAlertDefinition, api.Wrap(ng.getAlertDefinitionEndpoint)) - alertDefinitions.Delete("/:alertDefinitionUID", ng.validateOrgAlertDefinition, api.Wrap(ng.deleteAlertDefinitionEndpoint)) - alertDefinitions.Post("/", middleware.ReqSignedIn, binding.Bind(saveAlertDefinitionCommand{}), api.Wrap(ng.createAlertDefinitionEndpoint)) - alertDefinitions.Put("/:alertDefinitionUID", ng.validateOrgAlertDefinition, binding.Bind(updateAlertDefinitionCommand{}), api.Wrap(ng.updateAlertDefinitionEndpoint)) + alertDefinitions.Get("", middleware.ReqSignedIn, routing.Wrap(ng.listAlertDefinitions)) + alertDefinitions.Get("/eval/:alertDefinitionUID", ng.validateOrgAlertDefinition, routing.Wrap(ng.alertDefinitionEvalEndpoint)) + alertDefinitions.Post("/eval", middleware.ReqSignedIn, binding.Bind(evalAlertConditionCommand{}), routing.Wrap(ng.conditionEvalEndpoint)) + alertDefinitions.Get("/:alertDefinitionUID", ng.validateOrgAlertDefinition, routing.Wrap(ng.getAlertDefinitionEndpoint)) + alertDefinitions.Delete("/:alertDefinitionUID", ng.validateOrgAlertDefinition, routing.Wrap(ng.deleteAlertDefinitionEndpoint)) + alertDefinitions.Post("/", middleware.ReqSignedIn, binding.Bind(saveAlertDefinitionCommand{}), routing.Wrap(ng.createAlertDefinitionEndpoint)) + alertDefinitions.Put("/:alertDefinitionUID", ng.validateOrgAlertDefinition, binding.Bind(updateAlertDefinitionCommand{}), routing.Wrap(ng.updateAlertDefinitionEndpoint)) }) ng.RouteRegister.Group("/api/ngalert/", func(schedulerRouter routing.RouteRegister) { - schedulerRouter.Post("/pause", api.Wrap(ng.pauseScheduler)) - schedulerRouter.Post("/unpause", api.Wrap(ng.unpauseScheduler)) + schedulerRouter.Post("/pause", routing.Wrap(ng.pauseScheduler)) + schedulerRouter.Post("/unpause", routing.Wrap(ng.unpauseScheduler)) }, middleware.ReqOrgAdmin) } // conditionEvalEndpoint handles POST /api/alert-definitions/eval. -func (ng *AlertNG) conditionEvalEndpoint(c *models.ReqContext, dto evalAlertConditionCommand) api.Response { +func (ng *AlertNG) conditionEvalEndpoint(c *models.ReqContext, dto evalAlertConditionCommand) response.Response { if err := ng.validateCondition(dto.Condition, c.SignedInUser); err != nil { - return api.Error(400, "invalid condition", err) + return response.Error(400, "invalid condition", err) } evalResults, err := eval.ConditionEval(&dto.Condition, timeNow()) if err != nil { - return api.Error(400, "Failed to evaluate conditions", err) + return response.Error(400, "Failed to evaluate conditions", err) } frame := evalResults.AsDataFrame() df := tsdb.NewDecodedDataFrames([]*data.Frame{&frame}) instances, err := df.Encoded() if err != nil { - return api.Error(400, "Failed to encode result dataframes", err) + return response.Error(400, "Failed to encode result dataframes", err) } - return api.JSON(200, util.DynMap{ + return response.JSON(200, util.DynMap{ "instances": instances, }) } // alertDefinitionEvalEndpoint handles GET /api/alert-definitions/eval/:alertDefinitionUID. -func (ng *AlertNG) alertDefinitionEvalEndpoint(c *models.ReqContext) api.Response { +func (ng *AlertNG) alertDefinitionEvalEndpoint(c *models.ReqContext) response.Response { alertDefinitionUID := c.ParamsEscape(":alertDefinitionUID") condition, err := ng.LoadAlertCondition(alertDefinitionUID, c.SignedInUser.OrgId) if err != nil { - return api.Error(400, "Failed to load alert definition conditions", err) + return response.Error(400, "Failed to load alert definition conditions", err) } if err := ng.validateCondition(*condition, c.SignedInUser); err != nil { - return api.Error(400, "invalid condition", err) + return response.Error(400, "invalid condition", err) } evalResults, err := eval.ConditionEval(condition, timeNow()) if err != nil { - return api.Error(400, "Failed to evaluate alert", err) + return response.Error(400, "Failed to evaluate alert", err) } frame := evalResults.AsDataFrame() df := tsdb.NewDecodedDataFrames([]*data.Frame{&frame}) if err != nil { - return api.Error(400, "Failed to instantiate Dataframes from the decoded frames", err) + return response.Error(400, "Failed to instantiate Dataframes from the decoded frames", err) } instances, err := df.Encoded() if err != nil { - return api.Error(400, "Failed to encode result dataframes", err) + return response.Error(400, "Failed to encode result dataframes", err) } - return api.JSON(200, util.DynMap{ + return response.JSON(200, util.DynMap{ "instances": instances, }) } // getAlertDefinitionEndpoint handles GET /api/alert-definitions/:alertDefinitionUID. -func (ng *AlertNG) getAlertDefinitionEndpoint(c *models.ReqContext) api.Response { +func (ng *AlertNG) getAlertDefinitionEndpoint(c *models.ReqContext) response.Response { alertDefinitionUID := c.ParamsEscape(":alertDefinitionUID") query := getAlertDefinitionByUIDQuery{ @@ -95,14 +95,14 @@ func (ng *AlertNG) getAlertDefinitionEndpoint(c *models.ReqContext) api.Response } if err := ng.getAlertDefinitionByUID(&query); err != nil { - return api.Error(500, "Failed to get alert definition", err) + return response.Error(500, "Failed to get alert definition", err) } - return api.JSON(200, &query.Result) + return response.JSON(200, &query.Result) } // deleteAlertDefinitionEndpoint handles DELETE /api/alert-definitions/:alertDefinitionUID. -func (ng *AlertNG) deleteAlertDefinitionEndpoint(c *models.ReqContext) api.Response { +func (ng *AlertNG) deleteAlertDefinitionEndpoint(c *models.ReqContext) response.Response { alertDefinitionUID := c.ParamsEscape(":alertDefinitionUID") cmd := deleteAlertDefinitionByUIDCommand{ @@ -111,66 +111,66 @@ func (ng *AlertNG) deleteAlertDefinitionEndpoint(c *models.ReqContext) api.Respo } if err := ng.deleteAlertDefinitionByUID(&cmd); err != nil { - return api.Error(500, "Failed to delete alert definition", err) + return response.Error(500, "Failed to delete alert definition", err) } - return api.Success("Alert definition deleted") + return response.Success("Alert definition deleted") } // updateAlertDefinitionEndpoint handles PUT /api/alert-definitions/:alertDefinitionUID. -func (ng *AlertNG) updateAlertDefinitionEndpoint(c *models.ReqContext, cmd updateAlertDefinitionCommand) api.Response { +func (ng *AlertNG) updateAlertDefinitionEndpoint(c *models.ReqContext, cmd updateAlertDefinitionCommand) response.Response { cmd.UID = c.ParamsEscape(":alertDefinitionUID") cmd.OrgID = c.SignedInUser.OrgId if err := ng.validateCondition(cmd.Condition, c.SignedInUser); err != nil { - return api.Error(400, "invalid condition", err) + return response.Error(400, "invalid condition", err) } if err := ng.updateAlertDefinition(&cmd); err != nil { - return api.Error(500, "Failed to update alert definition", err) + return response.Error(500, "Failed to update alert definition", err) } - return api.JSON(200, cmd.Result) + return response.JSON(200, cmd.Result) } // createAlertDefinitionEndpoint handles POST /api/alert-definitions. -func (ng *AlertNG) createAlertDefinitionEndpoint(c *models.ReqContext, cmd saveAlertDefinitionCommand) api.Response { +func (ng *AlertNG) createAlertDefinitionEndpoint(c *models.ReqContext, cmd saveAlertDefinitionCommand) response.Response { cmd.OrgID = c.SignedInUser.OrgId if err := ng.validateCondition(cmd.Condition, c.SignedInUser); err != nil { - return api.Error(400, "invalid condition", err) + return response.Error(400, "invalid condition", err) } if err := ng.saveAlertDefinition(&cmd); err != nil { - return api.Error(500, "Failed to create alert definition", err) + return response.Error(500, "Failed to create alert definition", err) } - return api.JSON(200, cmd.Result) + return response.JSON(200, cmd.Result) } // listAlertDefinitions handles GET /api/alert-definitions. -func (ng *AlertNG) listAlertDefinitions(c *models.ReqContext) api.Response { +func (ng *AlertNG) listAlertDefinitions(c *models.ReqContext) response.Response { query := listAlertDefinitionsQuery{OrgID: c.SignedInUser.OrgId} if err := ng.getOrgAlertDefinitions(&query); err != nil { - return api.Error(500, "Failed to list alert definitions", err) + return response.Error(500, "Failed to list alert definitions", err) } - return api.JSON(200, util.DynMap{"results": query.Result}) + return response.JSON(200, util.DynMap{"results": query.Result}) } -func (ng *AlertNG) pauseScheduler() api.Response { +func (ng *AlertNG) pauseScheduler() response.Response { err := ng.schedule.pause() if err != nil { - return api.Error(500, "Failed to pause scheduler", err) + return response.Error(500, "Failed to pause scheduler", err) } - return api.JSON(200, util.DynMap{"message": "alert definition scheduler paused"}) + return response.JSON(200, util.DynMap{"message": "alert definition scheduler paused"}) } -func (ng *AlertNG) unpauseScheduler() api.Response { +func (ng *AlertNG) unpauseScheduler() response.Response { err := ng.schedule.unpause() if err != nil { - return api.Error(500, "Failed to unpause scheduler", err) + return response.Error(500, "Failed to unpause scheduler", err) } - return api.JSON(200, util.DynMap{"message": "alert definition scheduler unpaused"}) + return response.JSON(200, util.DynMap{"message": "alert definition scheduler unpaused"}) }