Replace signed in user for identity.requester (#73750)

* Make identity.Requester available at Context

* Clean pkg/services/guardian/guardian.go

* Clean guardian provider and guardian AC

* Clean pkg/api/team.go

* Clean ctxhandler, datasources, plugin and live

* Question: what to do with the UserDisplayDTO?

* Clean dashboards and guardian

* Remove identity.Requester from ReqContext

* Implement NewUserDisplayDTOFromRequester

* Fix tests

* Change status code numbers for http constants

* Upgrade signature of ngalert services

* log parsing errors instead of throwing error

* Fix tests and add logs

* linting
This commit is contained in:
linoman
2023-08-28 19:04:36 +02:00
committed by GitHub
parent b043d8d0e8
commit 9b9c9e83dc
43 changed files with 523 additions and 359 deletions
+110 -62
View File
@@ -20,6 +20,7 @@ import (
"github.com/grafana/grafana/pkg/kinds/dashboard"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/auth/identity"
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
"github.com/grafana/grafana/pkg/services/dashboards"
dashver "github.com/grafana/grafana/pkg/services/dashboardversion"
@@ -32,6 +33,7 @@ import (
"github.com/grafana/grafana/pkg/services/star"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/util"
"github.com/grafana/grafana/pkg/util/errutil"
"github.com/grafana/grafana/pkg/web"
)
@@ -44,15 +46,27 @@ func (hs *HTTPServer) isDashboardStarredByUser(c *contextmodel.ReqContext, dashI
return false, nil
}
query := star.IsStarredByUserQuery{UserID: c.UserID, DashboardID: dashID}
namespaceID, userIDstr := c.SignedInUser.GetNamespacedID()
if namespaceID != identity.NamespaceUser {
return false, errutil.BadRequest("User does not belong to a user namespace")
}
userID, err := identity.IntIdentifier(namespaceID, userIDstr)
if err != nil {
return false, err
}
query := star.IsStarredByUserQuery{UserID: userID, DashboardID: dashID}
return hs.starService.IsStarredByUser(c.Req.Context(), &query)
}
func dashboardGuardianResponse(err error) response.Response {
if err != nil {
return response.Error(500, "Error while checking dashboard permissions", err)
return response.Error(http.StatusInternalServerError, "Error while checking dashboard permissions", err)
}
return response.Error(403, "Access denied to this dashboard", nil)
return response.Error(http.StatusForbidden, "Access denied to this dashboard", nil)
}
// swagger:route POST /dashboards/trim dashboards trimDashboard
@@ -95,7 +109,7 @@ func (hs *HTTPServer) TrimDashboard(c *contextmodel.ReqContext) response.Respons
// 500: internalServerError
func (hs *HTTPServer) GetDashboard(c *contextmodel.ReqContext) response.Response {
uid := web.Params(c.Req)[":uid"]
dash, rsp := hs.getDashboardHelper(c.Req.Context(), c.OrgID, 0, uid)
dash, rsp := hs.getDashboardHelper(c.Req.Context(), c.SignedInUser.GetOrgID(), 0, uid)
if rsp != nil {
return rsp
}
@@ -108,9 +122,9 @@ func (hs *HTTPServer) GetDashboard(c *contextmodel.ReqContext) response.Response
// If public dashboards is enabled and we have a public dashboard, update meta
// values
if hs.Features.IsEnabled(featuremgmt.FlagPublicDashboards) {
publicDashboard, err := hs.PublicDashboardsApi.PublicDashboardService.FindByDashboardUid(c.Req.Context(), c.OrgID, dash.UID)
publicDashboard, err := hs.PublicDashboardsApi.PublicDashboardService.FindByDashboardUid(c.Req.Context(), c.SignedInUser.GetOrgID(), dash.UID)
if err != nil && !errors.Is(err, publicdashboardModels.ErrPublicDashboardNotFound) {
return response.Error(500, "Error while retrieving public dashboards", err)
return response.Error(http.StatusInternalServerError, "Error while retrieving public dashboards", err)
}
if publicDashboard != nil {
@@ -128,10 +142,10 @@ func (hs *HTTPServer) GetDashboard(c *contextmodel.ReqContext) response.Response
}
}
if isEmptyData {
return response.Error(500, "Error while loading dashboard, dashboard data is invalid", nil)
return response.Error(http.StatusInternalServerError, "Error while loading dashboard, dashboard data is invalid", nil)
}
}
guardian, err := guardian.NewByDashboard(c.Req.Context(), dash, c.OrgID, c.SignedInUser)
guardian, err := guardian.NewByDashboard(c.Req.Context(), dash, c.SignedInUser.GetOrgID(), c.SignedInUser)
if err != nil {
return response.Err(err)
}
@@ -146,7 +160,7 @@ func (hs *HTTPServer) GetDashboard(c *contextmodel.ReqContext) response.Response
isStarred, err := hs.isDashboardStarredByUser(c, dash.ID)
if err != nil {
return response.Error(500, "Error while checking if dashboard was starred by user", err)
return response.Error(http.StatusInternalServerError, "Error while checking if dashboard was starred by user", err)
}
// Finding creator and last updater of the dashboard
updater, creator := anonString, anonString
@@ -186,13 +200,13 @@ func (hs *HTTPServer) GetDashboard(c *contextmodel.ReqContext) response.Response
// lookup folder title
if dash.FolderID > 0 {
query := dashboards.GetDashboardQuery{ID: dash.FolderID, OrgID: c.OrgID}
query := dashboards.GetDashboardQuery{ID: dash.FolderID, OrgID: c.SignedInUser.GetOrgID()}
queryResult, err := hs.DashboardService.GetDashboard(c.Req.Context(), &query)
if err != nil {
if errors.Is(err, dashboards.ErrFolderNotFound) {
return response.Error(404, "Folder not found", err)
return response.Error(http.StatusNotFound, "Folder not found", err)
}
return response.Error(500, "Dashboard folder could not be read", err)
return response.Error(http.StatusInternalServerError, "Dashboard folder could not be read", err)
}
meta.FolderUid = queryResult.UID
meta.FolderTitle = queryResult.Title
@@ -201,7 +215,7 @@ func (hs *HTTPServer) GetDashboard(c *contextmodel.ReqContext) response.Response
provisioningData, err := hs.dashboardProvisioningService.GetProvisionedDashboardDataByDashboardID(c.Req.Context(), dash.ID)
if err != nil {
return response.Error(500, "Error while checking if dashboard is provisioned", err)
return response.Error(http.StatusInternalServerError, "Error while checking if dashboard is provisioned", err)
}
if provisioningData != nil {
@@ -275,7 +289,7 @@ func (hs *HTTPServer) getDashboardHelper(ctx context.Context, orgID int64, id in
queryResult, err := hs.DashboardService.GetDashboard(ctx, &query)
if err != nil {
return nil, response.Error(404, "Dashboard not found", err)
return nil, response.Error(http.StatusNotFound, "Dashboard not found", err)
}
return queryResult, nil
@@ -298,11 +312,11 @@ func (hs *HTTPServer) DeleteDashboardByUID(c *contextmodel.ReqContext) response.
}
func (hs *HTTPServer) deleteDashboard(c *contextmodel.ReqContext) response.Response {
dash, rsp := hs.getDashboardHelper(c.Req.Context(), c.OrgID, 0, web.Params(c.Req)[":uid"])
dash, rsp := hs.getDashboardHelper(c.Req.Context(), c.SignedInUser.GetOrgID(), 0, web.Params(c.Req)[":uid"])
if rsp != nil {
return rsp
}
guardian, err := guardian.NewByDashboard(c.Req.Context(), dash, c.OrgID, c.SignedInUser)
guardian, err := guardian.NewByDashboard(c.Req.Context(), dash, c.SignedInUser.GetOrgID(), c.SignedInUser)
if err != nil {
return response.Err(err)
}
@@ -311,10 +325,17 @@ func (hs *HTTPServer) deleteDashboard(c *contextmodel.ReqContext) response.Respo
return dashboardGuardianResponse(err)
}
namespaceID, userIDStr := c.SignedInUser.GetNamespacedID()
// disconnect all library elements for this dashboard
err = hs.LibraryElementService.DisconnectElementsFromDashboard(c.Req.Context(), dash.ID)
if err != nil {
hs.log.Error("Failed to disconnect library elements", "dashboard", dash.ID, "user", c.SignedInUser.UserID, "error", err)
hs.log.Error(
"Failed to disconnect library elements",
"dashboard", dash.ID,
"namespaceID", namespaceID,
"user", userIDStr,
"error", err)
}
// deletes all related public dashboard entities
@@ -323,7 +344,7 @@ func (hs *HTTPServer) deleteDashboard(c *contextmodel.ReqContext) response.Respo
hs.log.Error("Failed to delete public dashboard")
}
err = hs.DashboardService.DeleteDashboard(c.Req.Context(), dash.ID, c.OrgID)
err = hs.DashboardService.DeleteDashboard(c.Req.Context(), dash.ID, c.SignedInUser.GetOrgID())
if err != nil {
var dashboardErr dashboards.DashboardErr
if ok := errors.As(err, &dashboardErr); ok {
@@ -331,11 +352,16 @@ func (hs *HTTPServer) deleteDashboard(c *contextmodel.ReqContext) response.Respo
return response.Error(dashboardErr.StatusCode, dashboardErr.Error(), err)
}
}
return response.Error(500, "Failed to delete dashboard", err)
return response.Error(http.StatusInternalServerError, "Failed to delete dashboard", err)
}
userDTODisplay, err := user.NewUserDisplayDTOFromRequester(c.SignedInUser)
if err != nil {
return response.Error(http.StatusInternalServerError, "Error while parsing the user DTO model", err)
}
if hs.Live != nil {
err := hs.Live.GrafanaScope.Dashboards.DashboardDeleted(c.OrgID, c.ToUserDisplayDTO(), dash.UID)
err := hs.Live.GrafanaScope.Dashboards.DashboardDeleted(c.SignedInUser.GetOrgID(), userDTODisplay, dash.UID)
if err != nil {
hs.log.Error("Failed to broadcast delete info", "dashboard", dash.UID, "error", err)
}
@@ -396,19 +422,26 @@ func (hs *HTTPServer) PostDashboard(c *contextmodel.ReqContext) response.Respons
func (hs *HTTPServer) postDashboard(c *contextmodel.ReqContext, cmd dashboards.SaveDashboardCommand) response.Response {
ctx := c.Req.Context()
var err error
cmd.OrgID = c.OrgID
cmd.UserID = c.UserID
namespaceID, userIDstr := c.SignedInUser.GetNamespacedID()
userID, err := identity.IntIdentifier(namespaceID, userIDstr)
if err != nil {
hs.log.Warn("Error while parsing user ID", "namespaceID", namespaceID, "userID", userIDstr)
}
cmd.OrgID = c.SignedInUser.GetOrgID()
cmd.UserID = userID
if cmd.FolderUID != "" {
folder, err := hs.folderService.Get(ctx, &folder.GetFolderQuery{
OrgID: c.OrgID,
OrgID: c.SignedInUser.GetOrgID(),
UID: &cmd.FolderUID,
SignedInUser: c.SignedInUser,
})
if err != nil {
if errors.Is(err, dashboards.ErrFolderNotFound) {
return response.Error(400, "Folder not found", err)
return response.Error(http.StatusBadRequest, "Folder not found", err)
}
return response.Error(500, "Error while checking folder ID", err)
return response.Error(http.StatusInternalServerError, "Error while checking folder ID", err)
}
cmd.FolderID = folder.ID
}
@@ -418,10 +451,10 @@ func (hs *HTTPServer) postDashboard(c *contextmodel.ReqContext, cmd dashboards.S
if newDashboard {
limitReached, err := hs.QuotaService.QuotaReached(c, dashboards.QuotaTargetSrv)
if err != nil {
return response.Error(500, "failed to get quota", err)
return response.Error(http.StatusInternalServerError, "failed to get quota", err)
}
if limitReached {
return response.Error(403, "Quota reached", nil)
return response.Error(http.StatusForbidden, "Quota reached", nil)
}
}
@@ -429,13 +462,13 @@ func (hs *HTTPServer) postDashboard(c *contextmodel.ReqContext, cmd dashboards.S
if dash.ID != 0 {
data, err := hs.dashboardProvisioningService.GetProvisionedDashboardDataByDashboardID(c.Req.Context(), dash.ID)
if err != nil {
return response.Error(500, "Error while checking if dashboard is provisioned using ID", err)
return response.Error(http.StatusInternalServerError, "Error while checking if dashboard is provisioned using ID", err)
}
provisioningData = data
} else if dash.UID != "" {
data, err := hs.dashboardProvisioningService.GetProvisionedDashboardDataByDashboardUID(c.Req.Context(), dash.OrgID, dash.UID)
if err != nil && !errors.Is(err, dashboards.ErrProvisionedDashboardNotFound) && !errors.Is(err, dashboards.ErrDashboardNotFound) {
return response.Error(500, "Error while checking if dashboard is provisioned", err)
return response.Error(http.StatusInternalServerError, "Error while checking if dashboard is provisioned", err)
}
provisioningData = data
}
@@ -448,7 +481,7 @@ func (hs *HTTPServer) postDashboard(c *contextmodel.ReqContext, cmd dashboards.S
dashItem := &dashboards.SaveDashboardDTO{
Dashboard: dash,
Message: cmd.Message,
OrgID: c.OrgID,
OrgID: c.SignedInUser.GetOrgID(),
User: c.SignedInUser,
Overwrite: cmd.Overwrite,
}
@@ -461,14 +494,19 @@ func (hs *HTTPServer) postDashboard(c *contextmodel.ReqContext, cmd dashboards.S
dashboard = dash // the original request
}
userDTODisplay, err := user.NewUserDisplayDTOFromRequester(c.SignedInUser)
if err != nil {
return response.Error(http.StatusInternalServerError, "Error while parsing the user DTO model", err)
}
// This will broadcast all save requests only if a `gitops` observer exists.
// gitops is useful when trying to save dashboards in an environment where the user can not save
channel := hs.Live.GrafanaScope.Dashboards
liveerr := channel.DashboardSaved(c.SignedInUser.OrgID, c.SignedInUser.ToUserDisplayDTO(), cmd.Message, dashboard, err)
liveerr := channel.DashboardSaved(c.SignedInUser.GetOrgID(), userDTODisplay, cmd.Message, dashboard, err)
// When an error exists, but the value broadcast to a gitops listener return 202
if liveerr == nil && err != nil && channel.HasGitOpsObserver(c.SignedInUser.OrgID) {
return response.JSON(202, util.DynMap{
if liveerr == nil && err != nil && channel.HasGitOpsObserver(c.SignedInUser.GetOrgID()) {
return response.JSON(http.StatusAccepted, util.DynMap{
"status": "pending",
"message": "changes were broadcast to the gitops listener",
})
@@ -492,7 +530,7 @@ func (hs *HTTPServer) postDashboard(c *contextmodel.ReqContext, cmd dashboards.S
// connect library panels for this dashboard after the dashboard is stored and has an ID
err = hs.LibraryPanelService.ConnectLibraryPanelsForDashboard(ctx, c.SignedInUser, dashboard)
if err != nil {
return response.Error(500, "Error while connecting library panels", err)
return response.Error(http.StatusInternalServerError, "Error while connecting library panels", err)
}
c.TimeRequest(metrics.MApiDashboardSave)
@@ -515,12 +553,17 @@ func (hs *HTTPServer) postDashboard(c *contextmodel.ReqContext, cmd dashboards.S
// 401: unauthorisedError
// 500: internalServerError
func (hs *HTTPServer) GetHomeDashboard(c *contextmodel.ReqContext) response.Response {
prefsQuery := pref.GetPreferenceWithDefaultsQuery{OrgID: c.OrgID, UserID: c.SignedInUser.UserID, Teams: c.Teams}
namespaceID, userIDstr := c.SignedInUser.GetNamespacedID()
userID, err := identity.IntIdentifier(namespaceID, userIDstr)
if err != nil {
hs.log.Warn("Error while parsing user ID", "namespaceID", namespaceID, "userID", userIDstr, "err", err)
}
prefsQuery := pref.GetPreferenceWithDefaultsQuery{OrgID: c.SignedInUser.GetOrgID(), UserID: userID, Teams: c.SignedInUser.GetTeams()}
homePage := hs.Cfg.HomePage
preference, err := hs.preferenceService.GetWithDefaults(c.Req.Context(), &prefsQuery)
if err != nil {
return response.Error(500, "Failed to get preferences", err)
return response.Error(http.StatusInternalServerError, "Failed to get preferences", err)
}
if preference.HomeDashboardID == 0 && len(homePage) > 0 {
@@ -549,7 +592,7 @@ func (hs *HTTPServer) GetHomeDashboard(c *contextmodel.ReqContext) response.Resp
// nolint:gosec
file, err := os.Open(filePath)
if err != nil {
return response.Error(500, "Failed to load home dashboard", err)
return response.Error(http.StatusInternalServerError, "Failed to load home dashboard", err)
}
defer func() {
if err := file.Close(); err != nil {
@@ -564,7 +607,7 @@ func (hs *HTTPServer) GetHomeDashboard(c *contextmodel.ReqContext) response.Resp
jsonParser := json.NewDecoder(file)
if err := jsonParser.Decode(dash.Dashboard); err != nil {
return response.Error(500, "Failed to load home dashboard", err)
return response.Error(http.StatusInternalServerError, "Failed to load home dashboard", err)
}
hs.addGettingStartedPanelToHomeDashboard(c, dash.Dashboard)
@@ -636,12 +679,12 @@ func (hs *HTTPServer) GetDashboardVersions(c *contextmodel.ReqContext) response.
}
}
dash, rsp := hs.getDashboardHelper(c.Req.Context(), c.OrgID, dashID, dashUID)
dash, rsp := hs.getDashboardHelper(c.Req.Context(), c.SignedInUser.GetOrgID(), dashID, dashUID)
if rsp != nil {
return rsp
}
guardian, err := guardian.NewByDashboard(c.Req.Context(), dash, c.OrgID, c.SignedInUser)
guardian, err := guardian.NewByDashboard(c.Req.Context(), dash, c.SignedInUser.GetOrgID(), c.SignedInUser)
if err != nil {
return response.Err(err)
}
@@ -650,7 +693,7 @@ func (hs *HTTPServer) GetDashboardVersions(c *contextmodel.ReqContext) response.
}
query := dashver.ListDashboardVersionsQuery{
OrgID: c.OrgID,
OrgID: c.SignedInUser.GetOrgID(),
DashboardID: dash.ID,
DashboardUID: dash.UID,
Limit: c.QueryInt("limit"),
@@ -659,7 +702,7 @@ func (hs *HTTPServer) GetDashboardVersions(c *contextmodel.ReqContext) response.
versions, err := hs.dashboardVersionService.List(c.Req.Context(), &query)
if err != nil {
return response.Error(404, fmt.Sprintf("No versions found for dashboardId %d", dash.ID), err)
return response.Error(http.StatusNotFound, fmt.Sprintf("No versions found for dashboardId %d", dash.ID), err)
}
loginMem := make(map[int64]string, len(versions))
@@ -747,12 +790,12 @@ func (hs *HTTPServer) GetDashboardVersion(c *contextmodel.ReqContext) response.R
}
}
dash, rsp := hs.getDashboardHelper(c.Req.Context(), c.OrgID, dashID, dashUID)
dash, rsp := hs.getDashboardHelper(c.Req.Context(), c.SignedInUser.GetOrgID(), dashID, dashUID)
if rsp != nil {
return rsp
}
guardian, err := guardian.NewByDashboard(c.Req.Context(), dash, c.OrgID, c.SignedInUser)
guardian, err := guardian.NewByDashboard(c.Req.Context(), dash, c.SignedInUser.GetOrgID(), c.SignedInUser)
if err != nil {
return response.Err(err)
}
@@ -763,7 +806,7 @@ func (hs *HTTPServer) GetDashboardVersion(c *contextmodel.ReqContext) response.R
version, _ := strconv.ParseInt(web.Params(c.Req)[":id"], 10, 32)
query := dashver.GetDashboardVersionQuery{
OrgID: c.OrgID,
OrgID: c.SignedInUser.GetOrgID(),
DashboardID: dash.ID,
DashboardUID: dash.UID,
Version: int(version),
@@ -771,7 +814,7 @@ func (hs *HTTPServer) GetDashboardVersion(c *contextmodel.ReqContext) response.R
res, err := hs.dashboardVersionService.Get(c.Req.Context(), &query)
if err != nil {
return response.Error(500, fmt.Sprintf("Dashboard version %d not found for dashboardId %d", query.Version, dash.ID), err)
return response.Error(http.StatusInternalServerError, fmt.Sprintf("Dashboard version %d not found for dashboardId %d", query.Version, dash.ID), err)
}
creator := anonString
@@ -879,7 +922,7 @@ func (hs *HTTPServer) CalculateDashboardDiff(c *contextmodel.ReqContext) respons
if err := web.Bind(c.Req, &apiOptions); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
guardianBase, err := guardian.New(c.Req.Context(), apiOptions.Base.DashboardId, c.OrgID, c.SignedInUser)
guardianBase, err := guardian.New(c.Req.Context(), apiOptions.Base.DashboardId, c.SignedInUser.GetOrgID(), c.SignedInUser)
if err != nil {
return response.Err(err)
}
@@ -889,7 +932,7 @@ func (hs *HTTPServer) CalculateDashboardDiff(c *contextmodel.ReqContext) respons
}
if apiOptions.Base.DashboardId != apiOptions.New.DashboardId {
guardianNew, err := guardian.New(c.Req.Context(), apiOptions.New.DashboardId, c.OrgID, c.SignedInUser)
guardianNew, err := guardian.New(c.Req.Context(), apiOptions.New.DashboardId, c.SignedInUser.GetOrgID(), c.SignedInUser)
if err != nil {
return response.Err(err)
}
@@ -900,7 +943,7 @@ func (hs *HTTPServer) CalculateDashboardDiff(c *contextmodel.ReqContext) respons
}
options := dashdiffs.Options{
OrgId: c.OrgID,
OrgId: c.SignedInUser.GetOrgID(),
DiffType: dashdiffs.ParseDiffType(apiOptions.DiffType),
Base: dashdiffs.DiffTarget{
DashboardId: apiOptions.Base.DashboardId,
@@ -923,9 +966,9 @@ func (hs *HTTPServer) CalculateDashboardDiff(c *contextmodel.ReqContext) respons
baseVersionRes, err := hs.dashboardVersionService.Get(c.Req.Context(), &baseVersionQuery)
if err != nil {
if errors.Is(err, dashver.ErrDashboardVersionNotFound) {
return response.Error(404, "Dashboard version not found", err)
return response.Error(http.StatusNotFound, "Dashboard version not found", err)
}
return response.Error(500, "Unable to compute diff", err)
return response.Error(http.StatusInternalServerError, "Unable to compute diff", err)
}
newVersionQuery := dashver.GetDashboardVersionQuery{
@@ -937,9 +980,9 @@ func (hs *HTTPServer) CalculateDashboardDiff(c *contextmodel.ReqContext) respons
newVersionRes, err := hs.dashboardVersionService.Get(c.Req.Context(), &newVersionQuery)
if err != nil {
if errors.Is(err, dashver.ErrDashboardVersionNotFound) {
return response.Error(404, "Dashboard version not found", err)
return response.Error(http.StatusNotFound, "Dashboard version not found", err)
}
return response.Error(500, "Unable to compute diff", err)
return response.Error(http.StatusInternalServerError, "Unable to compute diff", err)
}
baseData := baseVersionRes.Data
@@ -949,9 +992,9 @@ func (hs *HTTPServer) CalculateDashboardDiff(c *contextmodel.ReqContext) respons
if err != nil {
if errors.Is(err, dashver.ErrDashboardVersionNotFound) {
return response.Error(404, "Dashboard version not found", err)
return response.Error(http.StatusNotFound, "Dashboard version not found", err)
}
return response.Error(500, "Unable to compute diff", err)
return response.Error(http.StatusInternalServerError, "Unable to compute diff", err)
}
if options.DiffType == dashdiffs.DiffDelta {
@@ -1003,12 +1046,12 @@ func (hs *HTTPServer) RestoreDashboardVersion(c *contextmodel.ReqContext) respon
}
}
dash, rsp := hs.getDashboardHelper(c.Req.Context(), c.OrgID, dashID, dashUID)
dash, rsp := hs.getDashboardHelper(c.Req.Context(), c.SignedInUser.GetOrgID(), dashID, dashUID)
if rsp != nil {
return rsp
}
guardian, err := guardian.NewByDashboard(c.Req.Context(), dash, c.OrgID, c.SignedInUser)
guardian, err := guardian.NewByDashboard(c.Req.Context(), dash, c.SignedInUser.GetOrgID(), c.SignedInUser)
if err != nil {
return response.Err(err)
}
@@ -1017,16 +1060,21 @@ func (hs *HTTPServer) RestoreDashboardVersion(c *contextmodel.ReqContext) respon
return dashboardGuardianResponse(err)
}
versionQuery := dashver.GetDashboardVersionQuery{DashboardID: dashID, DashboardUID: dash.UID, Version: apiCmd.Version, OrgID: c.OrgID}
versionQuery := dashver.GetDashboardVersionQuery{DashboardID: dashID, DashboardUID: dash.UID, Version: apiCmd.Version, OrgID: c.SignedInUser.GetOrgID()}
version, err := hs.dashboardVersionService.Get(c.Req.Context(), &versionQuery)
if err != nil {
return response.Error(404, "Dashboard version not found", nil)
return response.Error(http.StatusNotFound, "Dashboard version not found", nil)
}
userID, err := identity.IntIdentifier(c.SignedInUser.GetNamespacedID())
if err != nil {
return response.Error(http.StatusInternalServerError, "failed to get user id", err)
}
saveCmd := dashboards.SaveDashboardCommand{}
saveCmd.RestoredFrom = version.Version
saveCmd.OrgID = c.OrgID
saveCmd.UserID = c.UserID
saveCmd.OrgID = c.SignedInUser.GetOrgID()
saveCmd.UserID = userID
saveCmd.Dashboard = version.Data
saveCmd.Dashboard.Set("version", dash.Version)
saveCmd.Dashboard.Set("uid", dash.UID)
@@ -1045,7 +1093,7 @@ func (hs *HTTPServer) RestoreDashboardVersion(c *contextmodel.ReqContext) respon
// 401: unauthorisedError
// 500: internalServerError
func (hs *HTTPServer) GetDashboardTags(c *contextmodel.ReqContext) {
query := dashboards.GetDashboardTagsQuery{OrgID: c.OrgID}
query := dashboards.GetDashboardTagsQuery{OrgID: c.SignedInUser.GetOrgID()}
queryResult, err := hs.DashboardService.GetDashboardTags(c.Req.Context(), &query)
if err != nil {
c.JsonApiErr(500, "Failed to get tags from database", err)
+52 -50
View File
@@ -78,6 +78,7 @@ func TestGetHomeDashboard(t *testing.T) {
preferenceService: prefService,
dashboardVersionService: dashboardVersionService,
Kinds: corekind.NewBase(nil),
log: log.New("test-logger"),
}
tests := []struct {
@@ -202,7 +203,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
sc.sqlStore = mockSQLStore
hs.callGetDashboardVersion(sc)
assert.Equal(t, 403, sc.resp.Code)
assert.Equal(t, http.StatusForbidden, sc.resp.Code)
}, mockSQLStore)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions",
@@ -211,7 +212,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
sc.sqlStore = mockSQLStore
hs.callGetDashboardVersions(sc)
assert.Equal(t, 403, sc.resp.Code)
assert.Equal(t, http.StatusForbidden, sc.resp.Code)
}, mockSQLStore)
})
@@ -234,7 +235,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
sc.sqlStore = mockSQLStore
hs.callGetDashboardVersion(sc)
assert.Equal(t, 200, sc.resp.Code)
assert.Equal(t, http.StatusOK, sc.resp.Code)
var version *dashver.DashboardVersionMeta
err := json.NewDecoder(sc.resp.Body).Decode(&version)
require.NoError(t, err)
@@ -246,7 +247,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
setUp()
hs.callGetDashboardVersions(sc)
assert.Equal(t, 200, sc.resp.Code)
assert.Equal(t, http.StatusOK, sc.resp.Code)
}, mockSQLStore)
})
})
@@ -310,7 +311,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
sc.handlerFunc = hs.GetDashboard
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
assert.Equal(t, 403, sc.resp.Code)
assert.Equal(t, http.StatusForbidden, sc.resp.Code)
}, mockSQLStore)
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi",
@@ -319,7 +320,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
sc.sqlStore = mockSQLStore
hs.callDeleteDashboardByUID(t, sc, dashboardService, nil)
assert.Equal(t, 403, sc.resp.Code)
assert.Equal(t, http.StatusForbidden, sc.resp.Code)
}, mockSQLStore)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions/1",
@@ -328,7 +329,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
sc.sqlStore = mockSQLStore
hs.callGetDashboardVersion(sc)
assert.Equal(t, 403, sc.resp.Code)
assert.Equal(t, http.StatusForbidden, sc.resp.Code)
}, mockSQLStore)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions",
@@ -336,7 +337,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
setUp()
hs.callGetDashboardVersions(sc)
assert.Equal(t, 403, sc.resp.Code)
assert.Equal(t, http.StatusForbidden, sc.resp.Code)
}, mockSQLStore)
})
@@ -349,7 +350,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
sc.handlerFunc = hs.GetDashboard
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
assert.Equal(t, 403, sc.resp.Code)
assert.Equal(t, http.StatusForbidden, sc.resp.Code)
}, mockSQLStore)
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi",
@@ -357,7 +358,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
setUp()
hs.callDeleteDashboardByUID(t, sc, dashboardService, nil)
assert.Equal(t, 403, sc.resp.Code)
assert.Equal(t, http.StatusForbidden, sc.resp.Code)
}, mockSQLStore)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions/1",
@@ -365,7 +366,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
setUp()
hs.callGetDashboardVersion(sc)
assert.Equal(t, 403, sc.resp.Code)
assert.Equal(t, http.StatusForbidden, sc.resp.Code)
}, mockSQLStore)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions",
@@ -373,7 +374,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
setUp()
hs.callGetDashboardVersions(sc)
assert.Equal(t, 403, sc.resp.Code)
assert.Equal(t, http.StatusForbidden, sc.resp.Code)
}, mockSQLStore)
})
@@ -413,7 +414,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
pubdashService.On("DeleteByDashboard", mock.Anything, mock.Anything).Return(nil)
hs.callDeleteDashboardByUID(t, sc, dashboardService, pubdashService)
assert.Equal(t, 200, sc.resp.Code)
assert.Equal(t, http.StatusOK, sc.resp.Code)
}, mockSQLStore)
})
@@ -447,7 +448,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
setUpInner()
hs.callDeleteDashboardByUID(t, sc, dashboardService, nil)
assert.Equal(t, 403, sc.resp.Code)
assert.Equal(t, http.StatusForbidden, sc.resp.Code)
}, mockSQLStore)
})
@@ -486,21 +487,21 @@ func TestDashboardAPIEndpoint(t *testing.T) {
pubdashService.On("DeleteByDashboard", mock.Anything, mock.Anything).Return(nil)
hs.callDeleteDashboardByUID(t, sc, dashboardService, pubdashService)
assert.Equal(t, 200, sc.resp.Code)
assert.Equal(t, http.StatusOK, sc.resp.Code)
}, mockSQLStore)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions/1", "/api/dashboards/id/:dashboardId/versions/:id", role, func(sc *scenarioContext) {
setUpInner()
hs.callGetDashboardVersion(sc)
assert.Equal(t, 200, sc.resp.Code)
assert.Equal(t, http.StatusOK, sc.resp.Code)
}, mockSQLStore)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions", "/api/dashboards/id/:dashboardId/versions", role, func(sc *scenarioContext) {
setUpInner()
hs.callGetDashboardVersions(sc)
assert.Equal(t, 200, sc.resp.Code)
assert.Equal(t, http.StatusOK, sc.resp.Code)
}, mockSQLStore)
})
@@ -530,21 +531,21 @@ func TestDashboardAPIEndpoint(t *testing.T) {
setUpInner()
hs.callDeleteDashboardByUID(t, sc, dashboardService, nil)
assert.Equal(t, 403, sc.resp.Code)
assert.Equal(t, http.StatusForbidden, sc.resp.Code)
}, mockSQLStore)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions/1", "/api/dashboards/id/:dashboardId/versions/:id", role, func(sc *scenarioContext) {
setUpInner()
hs.callGetDashboardVersion(sc)
assert.Equal(t, 403, sc.resp.Code)
assert.Equal(t, http.StatusForbidden, sc.resp.Code)
}, mockSQLStore)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions", "/api/dashboards/id/:dashboardId/versions", role, func(sc *scenarioContext) {
setUpInner()
hs.callGetDashboardVersions(sc)
assert.Equal(t, 403, sc.resp.Code)
assert.Equal(t, http.StatusForbidden, sc.resp.Code)
}, mockSQLStore)
})
})
@@ -654,7 +655,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
postDashboardScenario(t, "When calling POST on", "/api/dashboards", "/api/dashboards", cmd, dashboardService, mockFolder, func(sc *scenarioContext) {
callPostDashboard(sc)
assert.Equal(t, 500, sc.resp.Code)
assert.Equal(t, http.StatusInternalServerError, sc.resp.Code)
})
})
@@ -664,23 +665,23 @@ func TestDashboardAPIEndpoint(t *testing.T) {
SaveError error
ExpectedStatusCode int
}{
{SaveError: dashboards.ErrDashboardNotFound, ExpectedStatusCode: 404},
{SaveError: dashboards.ErrFolderNotFound, ExpectedStatusCode: 400},
{SaveError: dashboards.ErrDashboardWithSameUIDExists, ExpectedStatusCode: 400},
{SaveError: dashboards.ErrDashboardWithSameNameInFolderExists, ExpectedStatusCode: 412},
{SaveError: dashboards.ErrDashboardVersionMismatch, ExpectedStatusCode: 412},
{SaveError: dashboards.ErrDashboardTitleEmpty, ExpectedStatusCode: 400},
{SaveError: dashboards.ErrDashboardFolderCannotHaveParent, ExpectedStatusCode: 400},
{SaveError: alerting.ValidationError{Reason: "Mu"}, ExpectedStatusCode: 422},
{SaveError: dashboards.ErrDashboardTypeMismatch, ExpectedStatusCode: 400},
{SaveError: dashboards.ErrDashboardFolderWithSameNameAsDashboard, ExpectedStatusCode: 400},
{SaveError: dashboards.ErrDashboardWithSameNameAsFolder, ExpectedStatusCode: 400},
{SaveError: dashboards.ErrDashboardFolderNameExists, ExpectedStatusCode: 400},
{SaveError: dashboards.ErrDashboardUpdateAccessDenied, ExpectedStatusCode: 403},
{SaveError: dashboards.ErrDashboardInvalidUid, ExpectedStatusCode: 400},
{SaveError: dashboards.ErrDashboardUidTooLong, ExpectedStatusCode: 400},
{SaveError: dashboards.ErrDashboardCannotSaveProvisionedDashboard, ExpectedStatusCode: 400},
{SaveError: dashboards.UpdatePluginDashboardError{PluginId: "plug"}, ExpectedStatusCode: 412},
{SaveError: dashboards.ErrDashboardNotFound, ExpectedStatusCode: http.StatusNotFound},
{SaveError: dashboards.ErrFolderNotFound, ExpectedStatusCode: http.StatusBadRequest},
{SaveError: dashboards.ErrDashboardWithSameUIDExists, ExpectedStatusCode: http.StatusBadRequest},
{SaveError: dashboards.ErrDashboardWithSameNameInFolderExists, ExpectedStatusCode: http.StatusPreconditionFailed},
{SaveError: dashboards.ErrDashboardVersionMismatch, ExpectedStatusCode: http.StatusPreconditionFailed},
{SaveError: dashboards.ErrDashboardTitleEmpty, ExpectedStatusCode: http.StatusBadRequest},
{SaveError: dashboards.ErrDashboardFolderCannotHaveParent, ExpectedStatusCode: http.StatusBadRequest},
{SaveError: alerting.ValidationError{Reason: "Mu"}, ExpectedStatusCode: http.StatusUnprocessableEntity},
{SaveError: dashboards.ErrDashboardTypeMismatch, ExpectedStatusCode: http.StatusBadRequest},
{SaveError: dashboards.ErrDashboardFolderWithSameNameAsDashboard, ExpectedStatusCode: http.StatusBadRequest},
{SaveError: dashboards.ErrDashboardWithSameNameAsFolder, ExpectedStatusCode: http.StatusBadRequest},
{SaveError: dashboards.ErrDashboardFolderNameExists, ExpectedStatusCode: http.StatusBadRequest},
{SaveError: dashboards.ErrDashboardUpdateAccessDenied, ExpectedStatusCode: http.StatusForbidden},
{SaveError: dashboards.ErrDashboardInvalidUid, ExpectedStatusCode: http.StatusBadRequest},
{SaveError: dashboards.ErrDashboardUidTooLong, ExpectedStatusCode: http.StatusBadRequest},
{SaveError: dashboards.ErrDashboardCannotSaveProvisionedDashboard, ExpectedStatusCode: http.StatusBadRequest},
{SaveError: dashboards.UpdatePluginDashboardError{PluginId: "plug"}, ExpectedStatusCode: http.StatusPreconditionFailed},
}
cmd := dashboards.SaveDashboardCommand{
@@ -697,7 +698,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
postDashboardScenario(t, fmt.Sprintf("Expect '%s' error when calling POST on", tc.SaveError.Error()),
"/api/dashboards", "/api/dashboards", cmd, dashboardService, nil, func(sc *scenarioContext) {
callPostDashboard(sc)
assert.Equal(t, tc.ExpectedStatusCode, sc.resp.Code)
assert.Equal(t, tc.ExpectedStatusCode, sc.resp.Code, sc.resp.Body.String())
})
}
})
@@ -716,7 +717,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
callPostDashboard(sc)
result := sc.ToJSON()
assert.Equal(t, 422, sc.resp.Code)
assert.Equal(t, http.StatusUnprocessableEntity, sc.resp.Code)
assert.False(t, result.Get("isValid").MustBool())
assert.NotEmpty(t, result.Get("message").MustString())
}, sqlmock)
@@ -732,7 +733,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
callPostDashboard(sc)
result := sc.ToJSON()
assert.Equal(t, 412, sc.resp.Code)
assert.Equal(t, http.StatusPreconditionFailed, sc.resp.Code)
assert.False(t, result.Get("isValid").MustBool())
assert.Equal(t, "invalid schema version", result.Get("message").MustString())
}, sqlmock)
@@ -751,7 +752,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
callPostDashboard(sc)
result := sc.ToJSON()
assert.Equal(t, 200, sc.resp.Code)
assert.Equal(t, http.StatusOK, sc.resp.Code)
assert.True(t, result.Get("isValid").MustBool())
}, sqlmock)
})
@@ -803,7 +804,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
setUp()
callPostDashboard(sc)
assert.Equal(t, 403, sc.resp.Code)
assert.Equal(t, http.StatusForbidden, sc.resp.Code)
}, sqlmock, fakeDashboardVersionService)
})
@@ -813,7 +814,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
// This test shouldn't hit GetDashboardACLInfoList, so no setup needed
sc.dashboardVersionService = fakeDashboardVersionService
callPostDashboard(sc)
assert.Equal(t, 200, sc.resp.Code)
assert.Equal(t, http.StatusOK, sc.resp.Code)
}, sqlmock, fakeDashboardVersionService)
})
})
@@ -850,7 +851,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
sc.dashboardVersionService = fakeDashboardVersionService
callRestoreDashboardVersion(sc)
assert.Equal(t, 200, sc.resp.Code)
assert.Equal(t, http.StatusOK, sc.resp.Code)
}, mockSQLStore)
})
@@ -883,7 +884,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
restoreDashboardVersionScenario(t, "When calling POST on", "/api/dashboards/id/1/restore",
"/api/dashboards/id/:dashboardId/restore", dashboardService, fakeDashboardVersionService, cmd, func(sc *scenarioContext) {
callRestoreDashboardVersion(sc)
assert.Equal(t, 200, sc.resp.Code)
assert.Equal(t, http.StatusOK, sc.resp.Code)
}, mockSQLStore)
})
@@ -939,7 +940,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
}
hs.callGetDashboard(sc)
assert.Equal(t, 200, sc.resp.Code)
assert.Equal(t, http.StatusOK, sc.resp.Code)
dash := dtos.DashboardFullWithMeta{}
err := json.NewDecoder(sc.resp.Body).Decode(&dash)
@@ -1011,7 +1012,7 @@ func TestDashboardVersionsAPIEndpoint(t *testing.T) {
ExpectedUser: &user.User{ID: 1, Login: "test-user"},
}).callGetDashboardVersions(sc)
assert.Equal(t, 200, sc.resp.Code)
assert.Equal(t, http.StatusOK, sc.resp.Code)
var versions []dashver.DashboardVersionMeta
err := json.NewDecoder(sc.resp.Body).Decode(&versions)
require.NoError(t, err)
@@ -1037,7 +1038,7 @@ func TestDashboardVersionsAPIEndpoint(t *testing.T) {
ExpectedError: user.ErrUserNotFound,
}).callGetDashboardVersions(sc)
assert.Equal(t, 200, sc.resp.Code)
assert.Equal(t, http.StatusOK, sc.resp.Code)
var versions []dashver.DashboardVersionMeta
err := json.NewDecoder(sc.resp.Body).Decode(&versions)
require.NoError(t, err)
@@ -1063,7 +1064,7 @@ func TestDashboardVersionsAPIEndpoint(t *testing.T) {
ExpectedError: fmt.Errorf("some error"),
}).callGetDashboardVersions(sc)
assert.Equal(t, 200, sc.resp.Code)
assert.Equal(t, http.StatusOK, sc.resp.Code)
var versions []dashver.DashboardVersionMeta
err := json.NewDecoder(sc.resp.Body).Decode(&versions)
require.NoError(t, err)
@@ -1192,6 +1193,7 @@ func postDashboardScenario(t *testing.T, desc string, url string, routePattern s
Features: featuremgmt.WithFeatures(),
Kinds: corekind.NewBase(nil),
accesscontrolService: actest.FakeService{},
log: log.New("test-logger"),
}
sc := setupScenarioContext(t, url)