mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
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:
parent
b043d8d0e8
commit
9b9c9e83dc
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -12,10 +12,10 @@ import (
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/services/auth/identity"
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
@ -68,8 +68,8 @@ type Service struct {
|
||||
}
|
||||
|
||||
type pluginContextProvider interface {
|
||||
Get(ctx context.Context, pluginID string, user *user.SignedInUser, orgID int64) (backend.PluginContext, error)
|
||||
GetWithDataSource(ctx context.Context, pluginID string, user *user.SignedInUser, ds *datasources.DataSource) (backend.PluginContext, error)
|
||||
Get(ctx context.Context, pluginID string, user identity.Requester, orgID int64) (backend.PluginContext, error)
|
||||
GetWithDataSource(ctx context.Context, pluginID string, user identity.Requester, ds *datasources.DataSource) (backend.PluginContext, error)
|
||||
}
|
||||
|
||||
func ProvideService(cfg *setting.Cfg, pluginClient plugins.Client, pCtxProvider *plugincontext.Provider,
|
||||
|
@ -5,8 +5,8 @@ import (
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/auth/identity"
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
)
|
||||
|
||||
type fakePluginContextProvider struct {
|
||||
@ -20,7 +20,7 @@ type fakePluginContextProvider struct {
|
||||
|
||||
var _ pluginContextProvider = &fakePluginContextProvider{}
|
||||
|
||||
func (f *fakePluginContextProvider) Get(_ context.Context, pluginID string, user *user.SignedInUser, orgID int64) (backend.PluginContext, error) {
|
||||
func (f *fakePluginContextProvider) Get(_ context.Context, pluginID string, user identity.Requester, orgID int64) (backend.PluginContext, error) {
|
||||
f.recordings = append(f.recordings, struct {
|
||||
method string
|
||||
params []interface{}
|
||||
@ -31,9 +31,9 @@ func (f *fakePluginContextProvider) Get(_ context.Context, pluginID string, user
|
||||
var u *backend.User
|
||||
if user != nil {
|
||||
u = &backend.User{
|
||||
Login: user.Login,
|
||||
Name: user.Name,
|
||||
Email: user.Email,
|
||||
Login: user.GetLogin(),
|
||||
Name: user.GetDisplayName(),
|
||||
Email: user.GetEmail(),
|
||||
}
|
||||
}
|
||||
return backend.PluginContext{
|
||||
@ -45,7 +45,7 @@ func (f *fakePluginContextProvider) Get(_ context.Context, pluginID string, user
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (f *fakePluginContextProvider) GetWithDataSource(ctx context.Context, pluginID string, user *user.SignedInUser, ds *datasources.DataSource) (backend.PluginContext, error) {
|
||||
func (f *fakePluginContextProvider) GetWithDataSource(ctx context.Context, pluginID string, user identity.Requester, ds *datasources.DataSource) (backend.PluginContext, error) {
|
||||
f.recordings = append(f.recordings, struct {
|
||||
method string
|
||||
params []interface{}
|
||||
@ -57,7 +57,7 @@ func (f *fakePluginContextProvider) GetWithDataSource(ctx context.Context, plugi
|
||||
|
||||
orgId := int64(1)
|
||||
if user != nil {
|
||||
orgId = user.OrgID
|
||||
orgId = user.GetOrgID()
|
||||
}
|
||||
r, err := f.Get(ctx, pluginID, user, orgId)
|
||||
if ds != nil {
|
||||
|
@ -8,8 +8,8 @@ import (
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/auth/identity"
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
)
|
||||
|
||||
// Request is similar to plugins.DataQuery but with the Time Ranges is per Query.
|
||||
@ -18,7 +18,7 @@ type Request struct {
|
||||
Debug bool
|
||||
OrgId int64
|
||||
Queries []Query
|
||||
User *user.SignedInUser
|
||||
User identity.Requester
|
||||
}
|
||||
|
||||
// Query is like plugins.DataSubQuery, but with a a time range, and only the UID
|
||||
|
@ -4,8 +4,8 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/null"
|
||||
"github.com/grafana/grafana/pkg/services/auth/identity"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
)
|
||||
|
||||
// Job holds state about when the alert rule should be evaluated.
|
||||
@ -46,7 +46,7 @@ type EvalMatch struct {
|
||||
}
|
||||
|
||||
type DashAlertInfo struct {
|
||||
User *user.SignedInUser
|
||||
User identity.Requester
|
||||
Dash *dashboards.Dashboard
|
||||
OrgID int64
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/services/auth/identity"
|
||||
"github.com/grafana/grafana/pkg/services/dashboardimport"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
@ -83,9 +84,12 @@ func TestImportDashboardService(t *testing.T) {
|
||||
require.NotNil(t, resp)
|
||||
require.Equal(t, "UDdpyzz7z", resp.UID)
|
||||
|
||||
userID, err := identity.IntIdentifier(importDashboardArg.User.GetNamespacedID())
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NotNil(t, importDashboardArg)
|
||||
require.Equal(t, int64(3), importDashboardArg.OrgID)
|
||||
require.Equal(t, int64(2), importDashboardArg.User.UserID)
|
||||
require.Equal(t, int64(2), userID)
|
||||
require.Equal(t, "prometheus", importDashboardArg.Dashboard.PluginID)
|
||||
require.Equal(t, int64(5), importDashboardArg.Dashboard.FolderID)
|
||||
|
||||
@ -147,9 +151,12 @@ func TestImportDashboardService(t *testing.T) {
|
||||
require.NotNil(t, resp)
|
||||
require.Equal(t, "UDdpyzz7z", resp.UID)
|
||||
|
||||
userID, err := identity.IntIdentifier(importDashboardArg.User.GetNamespacedID())
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NotNil(t, importDashboardArg)
|
||||
require.Equal(t, int64(3), importDashboardArg.OrgID)
|
||||
require.Equal(t, int64(2), importDashboardArg.User.UserID)
|
||||
require.Equal(t, int64(2), userID)
|
||||
require.Equal(t, "", importDashboardArg.Dashboard.PluginID)
|
||||
require.Equal(t, int64(5), importDashboardArg.Dashboard.FolderID)
|
||||
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/kinds"
|
||||
"github.com/grafana/grafana/pkg/kinds/dashboard"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/auth/identity"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
"github.com/grafana/grafana/pkg/services/quota"
|
||||
@ -337,7 +338,7 @@ type GetDashboardRefByIDQuery struct {
|
||||
type SaveDashboardDTO struct {
|
||||
OrgID int64
|
||||
UpdatedAt time.Time
|
||||
User *user.SignedInUser
|
||||
User identity.Requester
|
||||
Message string
|
||||
Overwrite bool
|
||||
Dashboard *Dashboard
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/alerting"
|
||||
"github.com/grafana/grafana/pkg/services/auth/identity"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
@ -181,12 +182,18 @@ func (dr *DashboardServiceImpl) BuildSaveDashboardCommand(ctx context.Context, d
|
||||
}
|
||||
}
|
||||
|
||||
namespaceID, userIDstr := dto.User.GetNamespacedID()
|
||||
userID, err := identity.IntIdentifier(namespaceID, userIDstr)
|
||||
if err != nil {
|
||||
dr.log.Warn("failed to parse user ID", "namespaceID", namespaceID, "userID", userIDstr, "error", err)
|
||||
}
|
||||
|
||||
cmd := &dashboards.SaveDashboardCommand{
|
||||
Dashboard: dash.Data,
|
||||
Message: dto.Message,
|
||||
OrgID: dto.OrgID,
|
||||
Overwrite: dto.Overwrite,
|
||||
UserID: dto.User.UserID,
|
||||
UserID: userID,
|
||||
FolderID: dash.FolderID,
|
||||
IsFolder: dash.IsFolder,
|
||||
PluginID: dash.PluginID,
|
||||
@ -209,7 +216,7 @@ func (dr *DashboardServiceImpl) DeleteOrphanedProvisionedDashboards(ctx context.
|
||||
|
||||
// getGuardianForSavePermissionCheck returns the guardian to be used for checking permission of dashboard
|
||||
// It replaces deleted Dashboard.GetDashboardIdForSavePermissionCheck()
|
||||
func getGuardianForSavePermissionCheck(ctx context.Context, d *dashboards.Dashboard, user *user.SignedInUser) (guardian.DashboardGuardian, error) {
|
||||
func getGuardianForSavePermissionCheck(ctx context.Context, d *dashboards.Dashboard, user identity.Requester) (guardian.DashboardGuardian, error) {
|
||||
newDashboard := d.ID == 0
|
||||
|
||||
if newDashboard {
|
||||
@ -297,7 +304,8 @@ func (dr *DashboardServiceImpl) SaveProvisionedDashboard(ctx context.Context, dt
|
||||
|
||||
if dto.Dashboard.ID == 0 {
|
||||
if err := dr.setDefaultPermissions(ctx, dto, dash, true); err != nil {
|
||||
dr.log.Error("Could not make user admin", "dashboard", dash.Title, "user", dto.User.UserID, "error", err)
|
||||
namespaceID, userID := dto.User.GetNamespacedID()
|
||||
dr.log.Error("Could not make user admin", "dashboard", dash.Title, "namespaceID", namespaceID, "userID", userID, "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -337,7 +345,8 @@ func (dr *DashboardServiceImpl) SaveFolderForProvisionedDashboards(ctx context.C
|
||||
|
||||
if dto.Dashboard.ID == 0 {
|
||||
if err := dr.setDefaultPermissions(ctx, dto, dash, true); err != nil {
|
||||
dr.log.Error("Could not make user admin", "dashboard", dash.Title, "user", dto.User.UserID, "error", err)
|
||||
namespaceID, userID := dto.User.GetNamespacedID()
|
||||
dr.log.Error("Could not make user admin", "dashboard", dash.Title, "namespaceID", namespaceID, "userID", userID, "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -385,7 +394,8 @@ func (dr *DashboardServiceImpl) SaveDashboard(ctx context.Context, dto *dashboar
|
||||
// new dashboard created
|
||||
if dto.Dashboard.ID == 0 {
|
||||
if err := dr.setDefaultPermissions(ctx, dto, dash, false); err != nil {
|
||||
dr.log.Error("Could not make user admin", "dashboard", dash.Title, "user", dto.User.UserID, "error", err)
|
||||
namespaceID, userID := dto.User.GetNamespacedID()
|
||||
dr.log.Error("Could not make user admin", "dashboard", dash.Title, "namespaceID", namespaceID, "userID", userID, "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -442,7 +452,8 @@ func (dr *DashboardServiceImpl) ImportDashboard(ctx context.Context, dto *dashbo
|
||||
}
|
||||
|
||||
if err := dr.setDefaultPermissions(ctx, dto, dash, false); err != nil {
|
||||
dr.log.Error("Could not make user admin", "dashboard", dash.Title, "user", dto.User.UserID, "error", err)
|
||||
namespaceID, userID := dto.User.GetNamespacedID()
|
||||
dr.log.Error("Could not make user admin", "dashboard", dash.Title, "namespaceID", namespaceID, "userID", userID, "error", err)
|
||||
}
|
||||
|
||||
return dash, nil
|
||||
@ -462,9 +473,16 @@ func (dr *DashboardServiceImpl) setDefaultPermissions(ctx context.Context, dto *
|
||||
inFolder := dash.FolderID > 0
|
||||
var permissions []accesscontrol.SetResourcePermissionCommand
|
||||
|
||||
if !provisioned && dto.User.IsRealUser() && !dto.User.IsAnonymous {
|
||||
namespaceID, userIDstr := dto.User.GetNamespacedID()
|
||||
userID, err := identity.IntIdentifier(namespaceID, userIDstr)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !provisioned && namespaceID == identity.NamespaceUser {
|
||||
permissions = append(permissions, accesscontrol.SetResourcePermissionCommand{
|
||||
UserID: dto.User.UserID, Permission: dashboards.PERMISSION_ADMIN.String(),
|
||||
UserID: userID, Permission: dashboards.PERMISSION_ADMIN.String(),
|
||||
})
|
||||
}
|
||||
|
||||
@ -480,7 +498,7 @@ func (dr *DashboardServiceImpl) setDefaultPermissions(ctx context.Context, dto *
|
||||
svc = dr.folderPermissions
|
||||
}
|
||||
|
||||
_, err := svc.SetPermissions(ctx, dto.OrgID, dash.UID, permissions...)
|
||||
_, err = svc.SetPermissions(ctx, dto.OrgID, dash.UID, permissions...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
|
||||
"github.com/grafana/grafana/pkg/services/alerting"
|
||||
"github.com/grafana/grafana/pkg/services/alerting/models"
|
||||
"github.com/grafana/grafana/pkg/services/auth/identity"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards/database"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
@ -112,9 +113,12 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
|
||||
err := callSaveWithError(t, cmd, sqlStore)
|
||||
assert.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
|
||||
|
||||
userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetNamespacedID())
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, "", sc.dashboardGuardianMock.DashUID)
|
||||
assert.Equal(t, cmd.OrgID, sc.dashboardGuardianMock.OrgID)
|
||||
assert.Equal(t, cmd.UserID, sc.dashboardGuardianMock.User.UserID)
|
||||
assert.Equal(t, cmd.UserID, userID)
|
||||
})
|
||||
|
||||
permissionScenario(t, "When creating a new dashboard in other folder, it should create dashboard guardian for other folder with correct arguments and rsult in access denied error",
|
||||
@ -132,9 +136,12 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
|
||||
err := callSaveWithError(t, cmd, sc.sqlStore)
|
||||
require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
|
||||
|
||||
userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetNamespacedID())
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, sc.otherSavedFolder.ID, sc.dashboardGuardianMock.DashID)
|
||||
assert.Equal(t, cmd.OrgID, sc.dashboardGuardianMock.OrgID)
|
||||
assert.Equal(t, cmd.UserID, sc.dashboardGuardianMock.User.UserID)
|
||||
assert.Equal(t, cmd.UserID, userID)
|
||||
})
|
||||
|
||||
permissionScenario(t, "When creating a new dashboard by existing title in folder, it should create dashboard guardian for dashboard with correct arguments and result in access denied error",
|
||||
@ -152,9 +159,12 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
|
||||
err := callSaveWithError(t, cmd, sc.sqlStore)
|
||||
require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
|
||||
|
||||
userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetNamespacedID())
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, sc.savedDashInFolder.UID, sc.dashboardGuardianMock.DashUID)
|
||||
assert.Equal(t, cmd.OrgID, sc.dashboardGuardianMock.OrgID)
|
||||
assert.Equal(t, cmd.UserID, sc.dashboardGuardianMock.User.UserID)
|
||||
assert.Equal(t, cmd.UserID, userID)
|
||||
})
|
||||
|
||||
permissionScenario(t, "When creating a new dashboard by existing UID in folder, it should create dashboard guardian for dashboard with correct arguments and result in access denied error",
|
||||
@ -173,9 +183,12 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
|
||||
err := callSaveWithError(t, cmd, sc.sqlStore)
|
||||
require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
|
||||
|
||||
userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetNamespacedID())
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, sc.savedDashInFolder.UID, sc.dashboardGuardianMock.DashUID)
|
||||
assert.Equal(t, cmd.OrgID, sc.dashboardGuardianMock.OrgID)
|
||||
assert.Equal(t, cmd.UserID, sc.dashboardGuardianMock.User.UserID)
|
||||
assert.Equal(t, cmd.UserID, userID)
|
||||
})
|
||||
|
||||
permissionScenario(t, "When updating a dashboard by existing id in the General folder, it should create dashboard guardian for dashboard with correct arguments and result in access denied error",
|
||||
@ -194,9 +207,12 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
|
||||
err := callSaveWithError(t, cmd, sc.sqlStore)
|
||||
assert.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
|
||||
|
||||
userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetNamespacedID())
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, sc.savedDashInGeneralFolder.UID, sc.dashboardGuardianMock.DashUID)
|
||||
assert.Equal(t, cmd.OrgID, sc.dashboardGuardianMock.OrgID)
|
||||
assert.Equal(t, cmd.UserID, sc.dashboardGuardianMock.User.UserID)
|
||||
assert.Equal(t, cmd.UserID, userID)
|
||||
})
|
||||
|
||||
permissionScenario(t, "When updating a dashboard by existing id in other folder, it should create dashboard guardian for dashboard with correct arguments and result in access denied error",
|
||||
@ -215,9 +231,12 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
|
||||
err := callSaveWithError(t, cmd, sc.sqlStore)
|
||||
require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
|
||||
|
||||
userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetNamespacedID())
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, sc.savedDashInFolder.UID, sc.dashboardGuardianMock.DashUID)
|
||||
assert.Equal(t, cmd.OrgID, sc.dashboardGuardianMock.OrgID)
|
||||
assert.Equal(t, cmd.UserID, sc.dashboardGuardianMock.User.UserID)
|
||||
assert.Equal(t, cmd.UserID, userID)
|
||||
})
|
||||
|
||||
permissionScenario(t, "When moving a dashboard by existing ID to other folder from General folder, it should create dashboard guardian for dashboard with correct arguments and result in access denied error",
|
||||
@ -236,9 +255,12 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
|
||||
err := callSaveWithError(t, cmd, sc.sqlStore)
|
||||
require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
|
||||
|
||||
userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetNamespacedID())
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, sc.savedDashInGeneralFolder.UID, sc.dashboardGuardianMock.DashUID)
|
||||
assert.Equal(t, cmd.OrgID, sc.dashboardGuardianMock.OrgID)
|
||||
assert.Equal(t, cmd.UserID, sc.dashboardGuardianMock.User.UserID)
|
||||
assert.Equal(t, cmd.UserID, userID)
|
||||
})
|
||||
|
||||
permissionScenario(t, "When moving a dashboard by existing id to the General folder from other folder, it should create dashboard guardian for dashboard with correct arguments and result in access denied error",
|
||||
@ -257,9 +279,12 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
|
||||
err := callSaveWithError(t, cmd, sc.sqlStore)
|
||||
assert.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
|
||||
|
||||
userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetNamespacedID())
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, sc.savedDashInFolder.UID, sc.dashboardGuardianMock.DashUID)
|
||||
assert.Equal(t, cmd.OrgID, sc.dashboardGuardianMock.OrgID)
|
||||
assert.Equal(t, cmd.UserID, sc.dashboardGuardianMock.User.UserID)
|
||||
assert.Equal(t, cmd.UserID, userID)
|
||||
})
|
||||
|
||||
permissionScenario(t, "When moving a dashboard by existing uid to other folder from General folder, it should create dashboard guardian for dashboard with correct arguments and result in access denied error",
|
||||
@ -278,9 +303,12 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
|
||||
err := callSaveWithError(t, cmd, sc.sqlStore)
|
||||
require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
|
||||
|
||||
userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetNamespacedID())
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, sc.savedDashInGeneralFolder.UID, sc.dashboardGuardianMock.DashUID)
|
||||
assert.Equal(t, cmd.OrgID, sc.dashboardGuardianMock.OrgID)
|
||||
assert.Equal(t, cmd.UserID, sc.dashboardGuardianMock.User.UserID)
|
||||
assert.Equal(t, cmd.UserID, userID)
|
||||
})
|
||||
|
||||
permissionScenario(t, "When moving a dashboard by existing UID to the General folder from other folder, it should create dashboard guardian for dashboard with correct arguments and result in access denied error",
|
||||
@ -299,9 +327,12 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
|
||||
err := callSaveWithError(t, cmd, sc.sqlStore)
|
||||
require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
|
||||
|
||||
userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetNamespacedID())
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, sc.savedDashInFolder.UID, sc.dashboardGuardianMock.DashUID)
|
||||
assert.Equal(t, cmd.OrgID, sc.dashboardGuardianMock.OrgID)
|
||||
assert.Equal(t, cmd.UserID, sc.dashboardGuardianMock.User.UserID)
|
||||
assert.Equal(t, cmd.UserID, userID)
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -7,7 +7,7 @@ import (
|
||||
sdkhttpclient "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/httpclient"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/services/auth/identity"
|
||||
)
|
||||
|
||||
// DataSourceService interface for interacting with datasources.
|
||||
@ -64,8 +64,8 @@ type DataSourceService interface {
|
||||
// CacheService interface for retrieving a cached datasource.
|
||||
type CacheService interface {
|
||||
// GetDatasource gets a datasource identified by datasource numeric identifier.
|
||||
GetDatasource(ctx context.Context, datasourceID int64, user *user.SignedInUser, skipCache bool) (*DataSource, error)
|
||||
GetDatasource(ctx context.Context, datasourceID int64, user identity.Requester, skipCache bool) (*DataSource, error)
|
||||
|
||||
// GetDatasourceByUID gets a datasource identified by datasource unique identifier (UID).
|
||||
GetDatasourceByUID(ctx context.Context, datasourceUID string, user *user.SignedInUser, skipCache bool) (*DataSource, error)
|
||||
GetDatasourceByUID(ctx context.Context, datasourceUID string, user identity.Requester, skipCache bool) (*DataSource, error)
|
||||
}
|
||||
|
@ -3,8 +3,8 @@ package datasources
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/auth/identity"
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
)
|
||||
|
||||
type FakeCacheService struct {
|
||||
@ -13,7 +13,7 @@ type FakeCacheService struct {
|
||||
|
||||
var _ datasources.CacheService = &FakeCacheService{}
|
||||
|
||||
func (c *FakeCacheService) GetDatasource(ctx context.Context, datasourceID int64, user *user.SignedInUser, skipCache bool) (*datasources.DataSource, error) {
|
||||
func (c *FakeCacheService) GetDatasource(ctx context.Context, datasourceID int64, user identity.Requester, skipCache bool) (*datasources.DataSource, error) {
|
||||
for _, datasource := range c.DataSources {
|
||||
if datasource.ID == datasourceID {
|
||||
return datasource, nil
|
||||
@ -22,7 +22,7 @@ func (c *FakeCacheService) GetDatasource(ctx context.Context, datasourceID int64
|
||||
return nil, datasources.ErrDataSourceNotFound
|
||||
}
|
||||
|
||||
func (c *FakeCacheService) GetDatasourceByUID(ctx context.Context, datasourceUID string, user *user.SignedInUser, skipCache bool) (*datasources.DataSource, error) {
|
||||
func (c *FakeCacheService) GetDatasourceByUID(ctx context.Context, datasourceUID string, user identity.Requester, skipCache bool) (*datasources.DataSource, error) {
|
||||
for _, datasource := range c.DataSources {
|
||||
if datasource.UID == datasourceUID {
|
||||
return datasource, nil
|
||||
|
@ -1,12 +1,12 @@
|
||||
package guardian
|
||||
|
||||
import (
|
||||
"github.com/grafana/grafana/pkg/services/auth/identity"
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
)
|
||||
|
||||
type DatasourceGuardianProvider interface {
|
||||
New(orgID int64, user *user.SignedInUser, dataSources ...datasources.DataSource) DatasourceGuardian
|
||||
New(orgID int64, user identity.Requester, dataSources ...datasources.DataSource) DatasourceGuardian
|
||||
}
|
||||
|
||||
type DatasourceGuardian interface {
|
||||
@ -20,6 +20,6 @@ func ProvideGuardian() *OSSProvider {
|
||||
|
||||
type OSSProvider struct{}
|
||||
|
||||
func (p *OSSProvider) New(orgID int64, user *user.SignedInUser, dataSources ...datasources.DataSource) DatasourceGuardian {
|
||||
func (p *OSSProvider) New(orgID int64, user identity.Requester, dataSources ...datasources.DataSource) DatasourceGuardian {
|
||||
return &AllowGuardian{}
|
||||
}
|
||||
|
@ -8,9 +8,9 @@ import (
|
||||
"github.com/grafana/grafana/pkg/infra/db"
|
||||
"github.com/grafana/grafana/pkg/infra/localcache"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/services/auth/identity"
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
"github.com/grafana/grafana/pkg/services/datasources/guardian"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -38,7 +38,7 @@ type CacheServiceImpl struct {
|
||||
func (dc *CacheServiceImpl) GetDatasource(
|
||||
ctx context.Context,
|
||||
datasourceID int64,
|
||||
user *user.SignedInUser,
|
||||
user identity.Requester,
|
||||
skipCache bool,
|
||||
) (*datasources.DataSource, error) {
|
||||
cacheKey := idKey(datasourceID)
|
||||
@ -46,7 +46,7 @@ func (dc *CacheServiceImpl) GetDatasource(
|
||||
if !skipCache {
|
||||
if cached, found := dc.CacheService.Get(cacheKey); found {
|
||||
ds := cached.(*datasources.DataSource)
|
||||
if ds.OrgID == user.OrgID {
|
||||
if ds.OrgID == user.GetOrgID() {
|
||||
if err := dc.canQuery(user, ds); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -55,9 +55,9 @@ func (dc *CacheServiceImpl) GetDatasource(
|
||||
}
|
||||
}
|
||||
|
||||
dc.logger.FromContext(ctx).Debug("Querying for data source via SQL store", "id", datasourceID, "orgId", user.OrgID)
|
||||
dc.logger.FromContext(ctx).Debug("Querying for data source via SQL store", "id", datasourceID, "orgId", user.GetOrgID())
|
||||
|
||||
query := &datasources.GetDataSourceQuery{ID: datasourceID, OrgID: user.OrgID}
|
||||
query := &datasources.GetDataSourceQuery{ID: datasourceID, OrgID: user.GetOrgID()}
|
||||
ss := SqlStore{db: dc.SQLStore, logger: dc.logger}
|
||||
ds, err := ss.GetDataSource(ctx, query)
|
||||
if err != nil {
|
||||
@ -79,21 +79,21 @@ func (dc *CacheServiceImpl) GetDatasource(
|
||||
func (dc *CacheServiceImpl) GetDatasourceByUID(
|
||||
ctx context.Context,
|
||||
datasourceUID string,
|
||||
user *user.SignedInUser,
|
||||
user identity.Requester,
|
||||
skipCache bool,
|
||||
) (*datasources.DataSource, error) {
|
||||
if datasourceUID == "" {
|
||||
return nil, fmt.Errorf("can not get data source by uid, uid is empty")
|
||||
}
|
||||
if user.OrgID == 0 {
|
||||
if user.GetOrgID() == 0 {
|
||||
return nil, fmt.Errorf("can not get data source by uid, orgId is missing")
|
||||
}
|
||||
uidCacheKey := uidKey(user.OrgID, datasourceUID)
|
||||
uidCacheKey := uidKey(user.GetOrgID(), datasourceUID)
|
||||
|
||||
if !skipCache {
|
||||
if cached, found := dc.CacheService.Get(uidCacheKey); found {
|
||||
ds := cached.(*datasources.DataSource)
|
||||
if ds.OrgID == user.OrgID {
|
||||
if ds.OrgID == user.GetOrgID() {
|
||||
if err := dc.canQuery(user, ds); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -102,8 +102,8 @@ func (dc *CacheServiceImpl) GetDatasourceByUID(
|
||||
}
|
||||
}
|
||||
|
||||
dc.logger.FromContext(ctx).Debug("Querying for data source via SQL store", "uid", datasourceUID, "orgId", user.OrgID)
|
||||
query := &datasources.GetDataSourceQuery{UID: datasourceUID, OrgID: user.OrgID}
|
||||
dc.logger.FromContext(ctx).Debug("Querying for data source via SQL store", "uid", datasourceUID, "orgId", user.GetOrgID())
|
||||
query := &datasources.GetDataSourceQuery{UID: datasourceUID, OrgID: user.GetOrgID()}
|
||||
ss := SqlStore{db: dc.SQLStore, logger: dc.logger}
|
||||
ds, err := ss.GetDataSource(ctx, query)
|
||||
if err != nil {
|
||||
@ -128,8 +128,8 @@ func uidKey(orgID int64, uid string) string {
|
||||
return fmt.Sprintf("ds-orgid-uid-%d-%s", orgID, uid)
|
||||
}
|
||||
|
||||
func (dc *CacheServiceImpl) canQuery(user *user.SignedInUser, ds *datasources.DataSource) error {
|
||||
guardian := dc.dsGuardian.New(user.OrgID, user, *ds)
|
||||
func (dc *CacheServiceImpl) canQuery(user identity.Requester, ds *datasources.DataSource) error {
|
||||
guardian := dc.dsGuardian.New(user.GetOrgID(), user, *ds)
|
||||
if canQuery, err := guardian.CanQuery(ds.ID); err != nil || !canQuery {
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/infra/db"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/auth/identity"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
@ -280,7 +281,12 @@ func (s *Service) Create(ctx context.Context, cmd *folder.CreateFolderCommand) (
|
||||
dashFolder.SetUID(trimmedUID)
|
||||
|
||||
user := cmd.SignedInUser
|
||||
userID := user.UserID
|
||||
namespaceID, userIDstr := user.GetNamespacedID()
|
||||
userID, err := identity.IntIdentifier(namespaceID, userIDstr)
|
||||
if err != nil {
|
||||
s.log.Warn("failed to parse user ID", "namespaceID", namespaceID, "userID", userIDstr, "error", err)
|
||||
}
|
||||
|
||||
if userID == 0 {
|
||||
userID = -1
|
||||
}
|
||||
@ -763,12 +769,18 @@ func (s *Service) BuildSaveDashboardCommand(ctx context.Context, dto *dashboards
|
||||
}
|
||||
}
|
||||
|
||||
namespaceID, userIDstr := dto.User.GetNamespacedID()
|
||||
userID, err := identity.IntIdentifier(namespaceID, userIDstr)
|
||||
if err != nil {
|
||||
s.log.Warn("failed to parse user ID", "namespaceID", namespaceID, "userID", userIDstr, "error", err)
|
||||
}
|
||||
|
||||
cmd := &dashboards.SaveDashboardCommand{
|
||||
Dashboard: dash.Data,
|
||||
Message: dto.Message,
|
||||
OrgID: dto.OrgID,
|
||||
Overwrite: dto.Overwrite,
|
||||
UserID: dto.User.UserID,
|
||||
UserID: userID,
|
||||
FolderID: dash.FolderID,
|
||||
IsFolder: dash.IsFolder,
|
||||
PluginID: dash.PluginID,
|
||||
@ -783,7 +795,7 @@ func (s *Service) BuildSaveDashboardCommand(ctx context.Context, dto *dashboards
|
||||
|
||||
// getGuardianForSavePermissionCheck returns the guardian to be used for checking permission of dashboard
|
||||
// It replaces deleted Dashboard.GetDashboardIdForSavePermissionCheck()
|
||||
func getGuardianForSavePermissionCheck(ctx context.Context, d *dashboards.Dashboard, user *user.SignedInUser) (guardian.DashboardGuardian, error) {
|
||||
func getGuardianForSavePermissionCheck(ctx context.Context, d *dashboards.Dashboard, user identity.Requester) (guardian.DashboardGuardian, error) {
|
||||
newDashboard := d.ID == 0
|
||||
|
||||
if newDashboard {
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/slugify"
|
||||
"github.com/grafana/grafana/pkg/services/auth/identity"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/util/errutil"
|
||||
@ -138,6 +139,7 @@ type GetFolderQuery struct {
|
||||
OrgID int64
|
||||
|
||||
SignedInUser *user.SignedInUser `json:"-"`
|
||||
Requester identity.Requester `json:"-"`
|
||||
}
|
||||
|
||||
// GetParentsQuery captures the information required by the folder service to
|
||||
|
@ -6,9 +6,9 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/auth/identity"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
@ -16,14 +16,14 @@ var _ DashboardGuardian = new(accessControlDashboardGuardian)
|
||||
|
||||
// NewAccessControlDashboardGuardianByDashboard creates a dashboard guardian by the provided dashboardId.
|
||||
func NewAccessControlDashboardGuardian(
|
||||
ctx context.Context, cfg *setting.Cfg, dashboardId int64, user *user.SignedInUser,
|
||||
ctx context.Context, cfg *setting.Cfg, dashboardId int64, user identity.Requester,
|
||||
ac accesscontrol.AccessControl, dashboardService dashboards.DashboardService,
|
||||
) (DashboardGuardian, error) {
|
||||
var dashboard *dashboards.Dashboard
|
||||
if dashboardId != 0 {
|
||||
q := &dashboards.GetDashboardQuery{
|
||||
ID: dashboardId,
|
||||
OrgID: user.OrgID,
|
||||
OrgID: user.GetOrgID(),
|
||||
}
|
||||
|
||||
qResult, err := dashboardService.GetDashboard(ctx, q)
|
||||
@ -65,14 +65,14 @@ func NewAccessControlDashboardGuardian(
|
||||
|
||||
// NewAccessControlDashboardGuardianByDashboard creates a dashboard guardian by the provided dashboardUID.
|
||||
func NewAccessControlDashboardGuardianByUID(
|
||||
ctx context.Context, cfg *setting.Cfg, dashboardUID string, user *user.SignedInUser,
|
||||
ctx context.Context, cfg *setting.Cfg, dashboardUID string, user identity.Requester,
|
||||
ac accesscontrol.AccessControl, dashboardService dashboards.DashboardService,
|
||||
) (DashboardGuardian, error) {
|
||||
var dashboard *dashboards.Dashboard
|
||||
if dashboardUID != "" {
|
||||
q := &dashboards.GetDashboardQuery{
|
||||
UID: dashboardUID,
|
||||
OrgID: user.OrgID,
|
||||
OrgID: user.GetOrgID(),
|
||||
}
|
||||
|
||||
qResult, err := dashboardService.GetDashboard(ctx, q)
|
||||
@ -116,7 +116,7 @@ func NewAccessControlDashboardGuardianByUID(
|
||||
// This constructor should be preferred over the other two if the dashboard in available
|
||||
// since it avoids querying the database for fetching the dashboard.
|
||||
func NewAccessControlDashboardGuardianByDashboard(
|
||||
ctx context.Context, cfg *setting.Cfg, dashboard *dashboards.Dashboard, user *user.SignedInUser,
|
||||
ctx context.Context, cfg *setting.Cfg, dashboard *dashboards.Dashboard, user identity.Requester,
|
||||
ac accesscontrol.AccessControl, dashboardService dashboards.DashboardService,
|
||||
) (DashboardGuardian, error) {
|
||||
if dashboard != nil && dashboard.IsFolder {
|
||||
@ -148,7 +148,7 @@ func NewAccessControlDashboardGuardianByDashboard(
|
||||
|
||||
// NewAccessControlFolderGuardian creates a folder guardian by the provided folder.
|
||||
func NewAccessControlFolderGuardian(
|
||||
ctx context.Context, cfg *setting.Cfg, f *folder.Folder, user *user.SignedInUser,
|
||||
ctx context.Context, cfg *setting.Cfg, f *folder.Folder, user identity.Requester,
|
||||
ac accesscontrol.AccessControl, dashboardService dashboards.DashboardService,
|
||||
) (DashboardGuardian, error) {
|
||||
return &accessControlFolderGuardian{
|
||||
@ -168,7 +168,7 @@ type accessControlBaseGuardian struct {
|
||||
cfg *setting.Cfg
|
||||
ctx context.Context
|
||||
log log.Logger
|
||||
user *user.SignedInUser
|
||||
user identity.Requester
|
||||
ac accesscontrol.AccessControl
|
||||
dashboardService dashboards.DashboardService
|
||||
}
|
||||
@ -309,12 +309,13 @@ func (a *accessControlFolderGuardian) CanCreate(folderID int64, isFolder bool) (
|
||||
|
||||
func (a *accessControlDashboardGuardian) evaluate(evaluator accesscontrol.Evaluator) (bool, error) {
|
||||
ok, err := a.ac.Evaluate(a.ctx, a.user, evaluator)
|
||||
namespaceID, userID := a.user.GetNamespacedID()
|
||||
if err != nil {
|
||||
id := 0
|
||||
if a.dashboard != nil {
|
||||
id = int(a.dashboard.ID)
|
||||
}
|
||||
a.log.Debug("Failed to evaluate access control to dashboard", "error", err, "userId", a.user.UserID, "id", id)
|
||||
a.log.Debug("Failed to evaluate access control to dashboard", "error", err, "namespaceID", namespaceID, "userId", userID, "id", id)
|
||||
}
|
||||
|
||||
if !ok && err == nil {
|
||||
@ -322,7 +323,7 @@ func (a *accessControlDashboardGuardian) evaluate(evaluator accesscontrol.Evalua
|
||||
if a.dashboard != nil {
|
||||
id = int(a.dashboard.ID)
|
||||
}
|
||||
a.log.Debug("Access denied to dashboard", "userId", a.user.UserID, "id", id, "permissions", evaluator.GoString())
|
||||
a.log.Debug("Access denied to dashboard", "namespaceID", namespaceID, "userId", userID, "id", id, "permissions", evaluator.GoString())
|
||||
}
|
||||
|
||||
return ok, err
|
||||
@ -330,6 +331,7 @@ func (a *accessControlDashboardGuardian) evaluate(evaluator accesscontrol.Evalua
|
||||
|
||||
func (a *accessControlFolderGuardian) evaluate(evaluator accesscontrol.Evaluator) (bool, error) {
|
||||
ok, err := a.ac.Evaluate(a.ctx, a.user, evaluator)
|
||||
namespaceID, userID := a.user.GetNamespacedID()
|
||||
if err != nil {
|
||||
uid := ""
|
||||
orgID := 0
|
||||
@ -337,7 +339,7 @@ func (a *accessControlFolderGuardian) evaluate(evaluator accesscontrol.Evaluator
|
||||
uid = a.folder.UID
|
||||
orgID = int(a.folder.OrgID)
|
||||
}
|
||||
a.log.Debug("Failed to evaluate access control to folder", "error", err, "userId", a.user.UserID, "orgID", orgID, "uid", uid)
|
||||
a.log.Debug("Failed to evaluate access control to folder", "error", err, "namespaceID", namespaceID, "userId", userID, "orgID", orgID, "uid", uid)
|
||||
}
|
||||
|
||||
if !ok && err == nil {
|
||||
@ -347,7 +349,7 @@ func (a *accessControlFolderGuardian) evaluate(evaluator accesscontrol.Evaluator
|
||||
uid = a.folder.UID
|
||||
orgID = int(a.folder.OrgID)
|
||||
}
|
||||
a.log.Debug("Access denied to folder", "userId", a.user.UserID, "orgID", orgID, "uid", uid, "permissions", evaluator.GoString())
|
||||
a.log.Debug("Access denied to folder", "namespaceID", namespaceID, "userId", userID, "orgID", orgID, "uid", uid, "permissions", evaluator.GoString())
|
||||
}
|
||||
|
||||
return ok, err
|
||||
@ -357,7 +359,7 @@ func (a *accessControlDashboardGuardian) loadParentFolder(folderID int64) (*dash
|
||||
if folderID == 0 {
|
||||
return &dashboards.Dashboard{UID: accesscontrol.GeneralFolderUID}, nil
|
||||
}
|
||||
folderQuery := &dashboards.GetDashboardQuery{ID: folderID, OrgID: a.user.OrgID}
|
||||
folderQuery := &dashboards.GetDashboardQuery{ID: folderID, OrgID: a.user.GetOrgID()}
|
||||
folderQueryResult, err := a.dashboardService.GetDashboard(a.ctx, folderQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -369,7 +371,7 @@ func (a *accessControlFolderGuardian) loadParentFolder(folderID int64) (*dashboa
|
||||
if folderID == 0 {
|
||||
return &dashboards.Dashboard{UID: accesscontrol.GeneralFolderUID}, nil
|
||||
}
|
||||
folderQuery := &dashboards.GetDashboardQuery{ID: folderID, OrgID: a.user.OrgID}
|
||||
folderQuery := &dashboards.GetDashboardQuery{ID: folderID, OrgID: a.user.GetOrgID()}
|
||||
folderQueryResult, err := a.dashboardService.GetDashboard(a.ctx, folderQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -6,11 +6,11 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/db"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/services/auth/identity"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
"github.com/grafana/grafana/pkg/services/team"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/util/errutil"
|
||||
)
|
||||
@ -35,7 +35,7 @@ type DashboardGuardian interface {
|
||||
|
||||
type dashboardGuardianImpl struct {
|
||||
cfg *setting.Cfg
|
||||
user *user.SignedInUser
|
||||
user identity.Requester
|
||||
dashId int64
|
||||
orgId int64
|
||||
acl []*dashboards.DashboardACLInfoDTO
|
||||
@ -49,30 +49,30 @@ type dashboardGuardianImpl struct {
|
||||
|
||||
// New factory for creating a new dashboard guardian instance
|
||||
// When using access control this function is replaced on startup and the AccessControlDashboardGuardian is returned
|
||||
var New = func(ctx context.Context, dashId int64, orgId int64, user *user.SignedInUser) (DashboardGuardian, error) {
|
||||
var New = func(ctx context.Context, dashId int64, orgId int64, user identity.Requester) (DashboardGuardian, error) {
|
||||
panic("no guardian factory implementation provided")
|
||||
}
|
||||
|
||||
// NewByUID factory for creating a new dashboard guardian instance
|
||||
// When using access control this function is replaced on startup and the AccessControlDashboardGuardian is returned
|
||||
var NewByUID = func(ctx context.Context, dashUID string, orgId int64, user *user.SignedInUser) (DashboardGuardian, error) {
|
||||
var NewByUID = func(ctx context.Context, dashUID string, orgId int64, user identity.Requester) (DashboardGuardian, error) {
|
||||
panic("no guardian factory implementation provided")
|
||||
}
|
||||
|
||||
// NewByDashboard factory for creating a new dashboard guardian instance
|
||||
// When using access control this function is replaced on startup and the AccessControlDashboardGuardian is returned
|
||||
var NewByDashboard = func(ctx context.Context, dash *dashboards.Dashboard, orgId int64, user *user.SignedInUser) (DashboardGuardian, error) {
|
||||
var NewByDashboard = func(ctx context.Context, dash *dashboards.Dashboard, orgId int64, user identity.Requester) (DashboardGuardian, error) {
|
||||
panic("no guardian factory implementation provided")
|
||||
}
|
||||
|
||||
// NewByFolder factory for creating a new folder guardian instance
|
||||
// When using access control this function is replaced on startup and the AccessControlDashboardGuardian is returned
|
||||
var NewByFolder = func(ctx context.Context, f *folder.Folder, orgId int64, user *user.SignedInUser) (DashboardGuardian, error) {
|
||||
var NewByFolder = func(ctx context.Context, f *folder.Folder, orgId int64, user identity.Requester) (DashboardGuardian, error) {
|
||||
panic("no guardian factory implementation provided")
|
||||
}
|
||||
|
||||
// newDashboardGuardian creates a dashboard guardian by the provided dashId.
|
||||
func newDashboardGuardian(ctx context.Context, cfg *setting.Cfg, dashId int64, orgId int64, user *user.SignedInUser, store db.DB, dashSvc dashboards.DashboardService, teamSvc team.Service) (*dashboardGuardianImpl, error) {
|
||||
func newDashboardGuardian(ctx context.Context, cfg *setting.Cfg, dashId int64, orgId int64, user identity.Requester, store db.DB, dashSvc dashboards.DashboardService, teamSvc team.Service) (*dashboardGuardianImpl, error) {
|
||||
if dashId != 0 {
|
||||
q := &dashboards.GetDashboardQuery{
|
||||
ID: dashId,
|
||||
@ -101,7 +101,7 @@ func newDashboardGuardian(ctx context.Context, cfg *setting.Cfg, dashId int64, o
|
||||
}
|
||||
|
||||
// newDashboardGuardianByUID creates a dashboard guardian by the provided dashUID.
|
||||
func newDashboardGuardianByUID(ctx context.Context, cfg *setting.Cfg, dashUID string, orgId int64, user *user.SignedInUser, store db.DB, dashSvc dashboards.DashboardService, teamSvc team.Service) (*dashboardGuardianImpl, error) {
|
||||
func newDashboardGuardianByUID(ctx context.Context, cfg *setting.Cfg, dashUID string, orgId int64, user identity.Requester, store db.DB, dashSvc dashboards.DashboardService, teamSvc team.Service) (*dashboardGuardianImpl, error) {
|
||||
dashID := int64(0)
|
||||
if dashUID != "" {
|
||||
q := &dashboards.GetDashboardQuery{
|
||||
@ -135,7 +135,7 @@ func newDashboardGuardianByUID(ctx context.Context, cfg *setting.Cfg, dashUID st
|
||||
// newDashboardGuardianByDashboard creates a dashboard guardian by the provided dashboard.
|
||||
// This constructor should be preferred over the other two if the dashboard in available
|
||||
// since it avoids querying the database for fetching the dashboard.
|
||||
func newDashboardGuardianByDashboard(ctx context.Context, cfg *setting.Cfg, dash *dashboards.Dashboard, orgId int64, user *user.SignedInUser, store db.DB, dashSvc dashboards.DashboardService, teamSvc team.Service) (*dashboardGuardianImpl, error) {
|
||||
func newDashboardGuardianByDashboard(ctx context.Context, cfg *setting.Cfg, dash *dashboards.Dashboard, orgId int64, user identity.Requester, store db.DB, dashSvc dashboards.DashboardService, teamSvc team.Service) (*dashboardGuardianImpl, error) {
|
||||
return &dashboardGuardianImpl{
|
||||
cfg: cfg,
|
||||
user: user,
|
||||
@ -153,7 +153,7 @@ func newDashboardGuardianByDashboard(ctx context.Context, cfg *setting.Cfg, dash
|
||||
// This constructor should be preferred over the other two if the dashboard in available
|
||||
// since it avoids querying the database for fetching the dashboard.
|
||||
// The folder.ID should be the sequence ID in the dashboard table.
|
||||
func newDashboardGuardianByFolder(ctx context.Context, cfg *setting.Cfg, f *folder.Folder, orgId int64, user *user.SignedInUser, store db.DB, dashSvc dashboards.DashboardService, teamSvc team.Service) (*dashboardGuardianImpl, error) {
|
||||
func newDashboardGuardianByFolder(ctx context.Context, cfg *setting.Cfg, f *folder.Folder, orgId int64, user identity.Requester, store db.DB, dashSvc dashboards.DashboardService, teamSvc team.Service) (*dashboardGuardianImpl, error) {
|
||||
return &dashboardGuardianImpl{
|
||||
cfg: cfg,
|
||||
user: user,
|
||||
@ -198,7 +198,7 @@ func (g *dashboardGuardianImpl) CanCreate(_ int64, _ bool) (bool, error) {
|
||||
}
|
||||
|
||||
func (g *dashboardGuardianImpl) HasPermission(permission dashboards.PermissionType) (bool, error) {
|
||||
if g.user.OrgRole == org.RoleAdmin {
|
||||
if g.user.HasRole(org.RoleAdmin) {
|
||||
return g.logHasPermissionResult(permission, true, nil)
|
||||
}
|
||||
|
||||
@ -216,32 +216,36 @@ func (g *dashboardGuardianImpl) logHasPermissionResult(permission dashboards.Per
|
||||
return hasPermission, err
|
||||
}
|
||||
|
||||
var debugMessage string
|
||||
if hasPermission {
|
||||
g.log.Debug("User granted access to execute action", "userId", g.user.UserID, "orgId", g.orgId, "uname", g.user.Login, "dashId", g.dashId, "action", permission)
|
||||
debugMessage = "User granted access to execute action"
|
||||
} else {
|
||||
g.log.Debug("User denied access to execute action", "userId", g.user.UserID, "orgId", g.orgId, "uname", g.user.Login, "dashId", g.dashId, "action", permission)
|
||||
debugMessage = "User denied access to execute action"
|
||||
}
|
||||
|
||||
namespaceID, identifier := g.user.GetNamespacedID()
|
||||
g.log.Debug(debugMessage, "namespaceID", namespaceID, "identifier", identifier, "orgId", g.orgId, "uname", g.user.GetLogin(), "dashId", g.dashId, "action", permission)
|
||||
|
||||
return hasPermission, err
|
||||
}
|
||||
|
||||
func (g *dashboardGuardianImpl) checkACL(permission dashboards.PermissionType, acl []*dashboards.DashboardACLInfoDTO) (bool, error) {
|
||||
orgRole := g.user.OrgRole
|
||||
teamACLItems := []*dashboards.DashboardACLInfoDTO{}
|
||||
|
||||
for _, p := range acl {
|
||||
userID, err := identity.IntIdentifier(g.user.GetNamespacedID())
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// user match
|
||||
if !g.user.IsAnonymous && p.UserID > 0 {
|
||||
if p.UserID == g.user.UserID && p.Permission >= permission {
|
||||
return true, nil
|
||||
}
|
||||
if p.UserID > 0 && p.UserID == userID && p.Permission >= permission {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// role match
|
||||
if p.Role != nil {
|
||||
if *p.Role == orgRole && p.Permission >= permission {
|
||||
return true, nil
|
||||
}
|
||||
if p.Role != nil && *p.Role == g.user.GetOrgRole() && p.Permission >= permission {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// remember this rule for later
|
||||
@ -312,7 +316,7 @@ func (g *dashboardGuardianImpl) CheckPermissionBeforeUpdate(permission dashboard
|
||||
}
|
||||
}
|
||||
|
||||
if g.user.OrgRole == org.RoleAdmin {
|
||||
if g.user.HasRole(org.RoleAdmin) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
@ -375,7 +379,12 @@ func (g *dashboardGuardianImpl) getTeams() ([]*team.TeamDTO, error) {
|
||||
return g.teams, nil
|
||||
}
|
||||
|
||||
query := team.GetTeamsByUserQuery{OrgID: g.orgId, UserID: g.user.UserID, SignedInUser: g.user}
|
||||
userIdD, err := identity.IntIdentifier(g.user.GetNamespacedID())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
query := team.GetTeamsByUserQuery{OrgID: g.orgId, UserID: userIdD, SignedInUser: g.user}
|
||||
queryResult, err := g.teamService.GetTeamsByUser(g.ctx, &query)
|
||||
|
||||
g.teams = queryResult
|
||||
@ -384,7 +393,7 @@ func (g *dashboardGuardianImpl) getTeams() ([]*team.TeamDTO, error) {
|
||||
|
||||
func (g *dashboardGuardianImpl) GetHiddenACL(cfg *setting.Cfg) ([]*dashboards.DashboardACL, error) {
|
||||
hiddenACL := make([]*dashboards.DashboardACL, 0)
|
||||
if g.user.IsGrafanaAdmin {
|
||||
if g.user.GetIsGrafanaAdmin() {
|
||||
return hiddenACL, nil
|
||||
}
|
||||
|
||||
@ -394,7 +403,7 @@ func (g *dashboardGuardianImpl) GetHiddenACL(cfg *setting.Cfg) ([]*dashboards.Da
|
||||
}
|
||||
|
||||
for _, item := range existingPermissions {
|
||||
if item.Inherited || item.UserLogin == g.user.Login {
|
||||
if item.Inherited || item.UserLogin == g.user.GetLogin() {
|
||||
continue
|
||||
}
|
||||
|
||||
@ -416,10 +425,11 @@ func (g *dashboardGuardianImpl) GetHiddenACL(cfg *setting.Cfg) ([]*dashboards.Da
|
||||
|
||||
// nolint:unused
|
||||
type FakeDashboardGuardian struct {
|
||||
DashID int64
|
||||
DashUID string
|
||||
DashID int64
|
||||
DashUID string
|
||||
// OrgID can be retrieved from the identity.Requester.GetOrgID
|
||||
OrgID int64
|
||||
User *user.SignedInUser
|
||||
User identity.Requester
|
||||
CanSaveValue bool
|
||||
CanEditValue bool
|
||||
CanViewValue bool
|
||||
@ -461,21 +471,21 @@ func (g *FakeDashboardGuardian) HasPermission(permission dashboards.PermissionTy
|
||||
|
||||
// nolint:unused
|
||||
func MockDashboardGuardian(mock *FakeDashboardGuardian) {
|
||||
New = func(_ context.Context, dashID int64, orgId int64, user *user.SignedInUser) (DashboardGuardian, error) {
|
||||
New = func(_ context.Context, dashID int64, orgId int64, user identity.Requester) (DashboardGuardian, error) {
|
||||
mock.OrgID = orgId
|
||||
mock.DashID = dashID
|
||||
mock.User = user
|
||||
return mock, nil
|
||||
}
|
||||
|
||||
NewByUID = func(_ context.Context, dashUID string, orgId int64, user *user.SignedInUser) (DashboardGuardian, error) {
|
||||
NewByUID = func(_ context.Context, dashUID string, orgId int64, user identity.Requester) (DashboardGuardian, error) {
|
||||
mock.OrgID = orgId
|
||||
mock.DashUID = dashUID
|
||||
mock.User = user
|
||||
return mock, nil
|
||||
}
|
||||
|
||||
NewByDashboard = func(_ context.Context, dash *dashboards.Dashboard, orgId int64, user *user.SignedInUser) (DashboardGuardian, error) {
|
||||
NewByDashboard = func(_ context.Context, dash *dashboards.Dashboard, orgId int64, user identity.Requester) (DashboardGuardian, error) {
|
||||
mock.OrgID = orgId
|
||||
mock.DashUID = dash.UID
|
||||
mock.DashID = dash.ID
|
||||
@ -483,7 +493,7 @@ func MockDashboardGuardian(mock *FakeDashboardGuardian) {
|
||||
return mock, nil
|
||||
}
|
||||
|
||||
NewByFolder = func(_ context.Context, f *folder.Folder, orgId int64, user *user.SignedInUser) (DashboardGuardian, error) {
|
||||
NewByFolder = func(_ context.Context, f *folder.Folder, orgId int64, user identity.Requester) (DashboardGuardian, error) {
|
||||
mock.OrgID = orgId
|
||||
mock.DashUID = f.UID
|
||||
mock.DashID = f.ID
|
||||
|
@ -5,10 +5,10 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/db"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/auth/identity"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
"github.com/grafana/grafana/pkg/services/team"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
@ -28,19 +28,19 @@ func ProvideService(
|
||||
}
|
||||
|
||||
func InitLegacyGuardian(cfg *setting.Cfg, store db.DB, dashSvc dashboards.DashboardService, teamSvc team.Service) {
|
||||
New = func(ctx context.Context, dashId int64, orgId int64, user *user.SignedInUser) (DashboardGuardian, error) {
|
||||
New = func(ctx context.Context, dashId int64, orgId int64, user identity.Requester) (DashboardGuardian, error) {
|
||||
return newDashboardGuardian(ctx, cfg, dashId, orgId, user, store, dashSvc, teamSvc)
|
||||
}
|
||||
|
||||
NewByUID = func(ctx context.Context, dashUID string, orgId int64, user *user.SignedInUser) (DashboardGuardian, error) {
|
||||
NewByUID = func(ctx context.Context, dashUID string, orgId int64, user identity.Requester) (DashboardGuardian, error) {
|
||||
return newDashboardGuardianByUID(ctx, cfg, dashUID, orgId, user, store, dashSvc, teamSvc)
|
||||
}
|
||||
|
||||
NewByDashboard = func(ctx context.Context, dash *dashboards.Dashboard, orgId int64, user *user.SignedInUser) (DashboardGuardian, error) {
|
||||
NewByDashboard = func(ctx context.Context, dash *dashboards.Dashboard, orgId int64, user identity.Requester) (DashboardGuardian, error) {
|
||||
return newDashboardGuardianByDashboard(ctx, cfg, dash, orgId, user, store, dashSvc, teamSvc)
|
||||
}
|
||||
|
||||
NewByFolder = func(ctx context.Context, f *folder.Folder, orgId int64, user *user.SignedInUser) (DashboardGuardian, error) {
|
||||
NewByFolder = func(ctx context.Context, f *folder.Folder, orgId int64, user identity.Requester) (DashboardGuardian, error) {
|
||||
return newDashboardGuardianByFolder(ctx, cfg, f, orgId, user, store, dashSvc, teamSvc)
|
||||
}
|
||||
}
|
||||
@ -48,19 +48,19 @@ func InitLegacyGuardian(cfg *setting.Cfg, store db.DB, dashSvc dashboards.Dashbo
|
||||
func InitAccessControlGuardian(
|
||||
cfg *setting.Cfg, ac accesscontrol.AccessControl, dashboardService dashboards.DashboardService,
|
||||
) {
|
||||
New = func(ctx context.Context, dashId int64, orgId int64, user *user.SignedInUser) (DashboardGuardian, error) {
|
||||
New = func(ctx context.Context, dashId int64, orgId int64, user identity.Requester) (DashboardGuardian, error) {
|
||||
return NewAccessControlDashboardGuardian(ctx, cfg, dashId, user, ac, dashboardService)
|
||||
}
|
||||
|
||||
NewByUID = func(ctx context.Context, dashUID string, orgId int64, user *user.SignedInUser) (DashboardGuardian, error) {
|
||||
NewByUID = func(ctx context.Context, dashUID string, orgId int64, user identity.Requester) (DashboardGuardian, error) {
|
||||
return NewAccessControlDashboardGuardianByUID(ctx, cfg, dashUID, user, ac, dashboardService)
|
||||
}
|
||||
|
||||
NewByDashboard = func(ctx context.Context, dash *dashboards.Dashboard, orgId int64, user *user.SignedInUser) (DashboardGuardian, error) {
|
||||
NewByDashboard = func(ctx context.Context, dash *dashboards.Dashboard, orgId int64, user identity.Requester) (DashboardGuardian, error) {
|
||||
return NewAccessControlDashboardGuardianByDashboard(ctx, cfg, dash, user, ac, dashboardService)
|
||||
}
|
||||
|
||||
NewByFolder = func(ctx context.Context, f *folder.Folder, orgId int64, user *user.SignedInUser) (DashboardGuardian, error) {
|
||||
NewByFolder = func(ctx context.Context, f *folder.Folder, orgId int64, user identity.Requester) (DashboardGuardian, error) {
|
||||
return NewAccessControlFolderGuardian(ctx, cfg, f, user, ac, dashboardService)
|
||||
}
|
||||
}
|
||||
|
@ -6,8 +6,8 @@ import (
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/services/auth/identity"
|
||||
"github.com/grafana/grafana/pkg/services/live/model"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -37,13 +37,13 @@ func (b *BroadcastRunner) GetHandlerForPath(_ string) (model.ChannelHandler, err
|
||||
}
|
||||
|
||||
// OnSubscribe will let anyone connect to the path
|
||||
func (b *BroadcastRunner) OnSubscribe(_ context.Context, u *user.SignedInUser, e model.SubscribeEvent) (model.SubscribeReply, backend.SubscribeStreamStatus, error) {
|
||||
func (b *BroadcastRunner) OnSubscribe(_ context.Context, u identity.Requester, e model.SubscribeEvent) (model.SubscribeReply, backend.SubscribeStreamStatus, error) {
|
||||
reply := model.SubscribeReply{
|
||||
Presence: true,
|
||||
JoinLeave: true,
|
||||
}
|
||||
query := &model.GetLiveMessageQuery{
|
||||
OrgID: u.OrgID,
|
||||
OrgID: u.GetOrgID(),
|
||||
Channel: e.Channel,
|
||||
}
|
||||
msg, ok, err := b.liveMessageStore.GetLiveMessage(query)
|
||||
@ -57,9 +57,9 @@ func (b *BroadcastRunner) OnSubscribe(_ context.Context, u *user.SignedInUser, e
|
||||
}
|
||||
|
||||
// OnPublish is called when a client wants to broadcast on the websocket
|
||||
func (b *BroadcastRunner) OnPublish(_ context.Context, u *user.SignedInUser, e model.PublishEvent) (model.PublishReply, backend.PublishStreamStatus, error) {
|
||||
func (b *BroadcastRunner) OnPublish(_ context.Context, u identity.Requester, e model.PublishEvent) (model.PublishReply, backend.PublishStreamStatus, error) {
|
||||
query := &model.SaveLiveMessageQuery{
|
||||
OrgID: u.OrgID,
|
||||
OrgID: u.GetOrgID(),
|
||||
Channel: e.Channel,
|
||||
Data: e.Data,
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/db"
|
||||
"github.com/grafana/grafana/pkg/services/auth/identity"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/guardian"
|
||||
"github.com/grafana/grafana/pkg/services/live/model"
|
||||
@ -52,7 +53,7 @@ func (h *DashboardHandler) GetHandlerForPath(_ string) (model.ChannelHandler, er
|
||||
}
|
||||
|
||||
// OnSubscribe for now allows anyone to subscribe to any dashboard
|
||||
func (h *DashboardHandler) OnSubscribe(ctx context.Context, user *user.SignedInUser, e model.SubscribeEvent) (model.SubscribeReply, backend.SubscribeStreamStatus, error) {
|
||||
func (h *DashboardHandler) OnSubscribe(ctx context.Context, user identity.Requester, e model.SubscribeEvent) (model.SubscribeReply, backend.SubscribeStreamStatus, error) {
|
||||
parts := strings.Split(e.Path, "/")
|
||||
if parts[0] == "gitops" {
|
||||
// gitops gets all changes for everything, so lets make sure it is an admin user
|
||||
@ -66,7 +67,7 @@ func (h *DashboardHandler) OnSubscribe(ctx context.Context, user *user.SignedInU
|
||||
|
||||
// make sure can view this dashboard
|
||||
if len(parts) == 2 && parts[0] == "uid" {
|
||||
query := dashboards.GetDashboardQuery{UID: parts[1], OrgID: user.OrgID}
|
||||
query := dashboards.GetDashboardQuery{UID: parts[1], OrgID: user.GetOrgID()}
|
||||
queryResult, err := h.DashboardService.GetDashboard(ctx, &query)
|
||||
if err != nil {
|
||||
logger.Error("Error getting dashboard", "query", query, "error", err)
|
||||
@ -74,7 +75,7 @@ func (h *DashboardHandler) OnSubscribe(ctx context.Context, user *user.SignedInU
|
||||
}
|
||||
|
||||
dash := queryResult
|
||||
guard, err := guardian.NewByDashboard(ctx, dash, user.OrgID, user)
|
||||
guard, err := guardian.NewByDashboard(ctx, dash, user.GetOrgID(), user)
|
||||
if err != nil {
|
||||
return model.SubscribeReply{}, backend.SubscribeStreamStatusPermissionDenied, err
|
||||
}
|
||||
@ -94,11 +95,11 @@ func (h *DashboardHandler) OnSubscribe(ctx context.Context, user *user.SignedInU
|
||||
}
|
||||
|
||||
// OnPublish is called when someone begins to edit a dashboard
|
||||
func (h *DashboardHandler) OnPublish(ctx context.Context, user *user.SignedInUser, e model.PublishEvent) (model.PublishReply, backend.PublishStreamStatus, error) {
|
||||
func (h *DashboardHandler) OnPublish(ctx context.Context, requester identity.Requester, e model.PublishEvent) (model.PublishReply, backend.PublishStreamStatus, error) {
|
||||
parts := strings.Split(e.Path, "/")
|
||||
if parts[0] == "gitops" {
|
||||
// gitops gets all changes for everything, so lets make sure it is an admin user
|
||||
if !user.HasRole(org.RoleAdmin) {
|
||||
if !requester.HasRole(org.RoleAdmin) {
|
||||
return model.PublishReply{}, backend.PublishStreamStatusPermissionDenied, nil
|
||||
}
|
||||
|
||||
@ -117,14 +118,14 @@ func (h *DashboardHandler) OnPublish(ctx context.Context, user *user.SignedInUse
|
||||
// just ignore the event
|
||||
return model.PublishReply{}, backend.PublishStreamStatusNotFound, fmt.Errorf("ignore???")
|
||||
}
|
||||
query := dashboards.GetDashboardQuery{UID: parts[1], OrgID: user.OrgID}
|
||||
query := dashboards.GetDashboardQuery{UID: parts[1], OrgID: requester.GetOrgID()}
|
||||
queryResult, err := h.DashboardService.GetDashboard(ctx, &query)
|
||||
if err != nil {
|
||||
logger.Error("Unknown dashboard", "query", query)
|
||||
return model.PublishReply{}, backend.PublishStreamStatusNotFound, nil
|
||||
}
|
||||
|
||||
guard, err := guardian.NewByDashboard(ctx, queryResult, user.OrgID, user)
|
||||
guard, err := guardian.NewByDashboard(ctx, queryResult, requester.GetOrgID(), requester)
|
||||
if err != nil {
|
||||
logger.Error("Failed to create guardian", "err", err)
|
||||
return model.PublishReply{}, backend.PublishStreamStatusNotFound, fmt.Errorf("internal error")
|
||||
@ -141,7 +142,10 @@ func (h *DashboardHandler) OnPublish(ctx context.Context, user *user.SignedInUse
|
||||
}
|
||||
|
||||
// Tell everyone who is editing
|
||||
event.User = user.ToUserDisplayDTO()
|
||||
event.User, err = user.NewUserDisplayDTOFromRequester(requester)
|
||||
if err != nil {
|
||||
return model.PublishReply{}, backend.PublishStreamStatusNotFound, err
|
||||
}
|
||||
|
||||
msg, err := json.Marshal(event)
|
||||
if err != nil {
|
||||
|
@ -7,17 +7,17 @@ import (
|
||||
"github.com/centrifugal/centrifuge"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/auth/identity"
|
||||
"github.com/grafana/grafana/pkg/services/live/model"
|
||||
"github.com/grafana/grafana/pkg/services/live/orgchannel"
|
||||
"github.com/grafana/grafana/pkg/services/live/runstream"
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
)
|
||||
|
||||
//go:generate mockgen -destination=plugin_mock.go -package=features github.com/grafana/grafana/pkg/services/live/features PluginContextGetter
|
||||
|
||||
type PluginContextGetter interface {
|
||||
GetPluginContext(ctx context.Context, user *user.SignedInUser, pluginID string, datasourceUID string, skipCache bool) (backend.PluginContext, error)
|
||||
GetPluginContext(ctx context.Context, user identity.Requester, pluginID string, datasourceUID string, skipCache bool) (backend.PluginContext, error)
|
||||
}
|
||||
|
||||
// PluginRunner can handle streaming operations for channels belonging to plugins.
|
||||
@ -63,7 +63,7 @@ type PluginPathRunner struct {
|
||||
}
|
||||
|
||||
// OnSubscribe passes control to a plugin.
|
||||
func (r *PluginPathRunner) OnSubscribe(ctx context.Context, user *user.SignedInUser, e model.SubscribeEvent) (model.SubscribeReply, backend.SubscribeStreamStatus, error) {
|
||||
func (r *PluginPathRunner) OnSubscribe(ctx context.Context, user identity.Requester, e model.SubscribeEvent) (model.SubscribeReply, backend.SubscribeStreamStatus, error) {
|
||||
pCtx, err := r.pluginContextGetter.GetPluginContext(ctx, user, r.pluginID, r.datasourceUID, false)
|
||||
if err != nil {
|
||||
if errors.Is(err, plugincontext.ErrPluginNotFound) {
|
||||
@ -86,7 +86,7 @@ func (r *PluginPathRunner) OnSubscribe(ctx context.Context, user *user.SignedInU
|
||||
return model.SubscribeReply{}, resp.Status, nil
|
||||
}
|
||||
|
||||
submitResult, err := r.runStreamManager.SubmitStream(ctx, user, orgchannel.PrependOrgID(user.OrgID, e.Channel), r.path, e.Data, pCtx, r.handler, false)
|
||||
submitResult, err := r.runStreamManager.SubmitStream(ctx, user, orgchannel.PrependOrgID(user.GetOrgID(), e.Channel), r.path, e.Data, pCtx, r.handler, false)
|
||||
if err != nil {
|
||||
logger.Error("Error submitting stream to manager", "error", err, "path", r.path)
|
||||
return model.SubscribeReply{}, 0, centrifuge.ErrorInternal
|
||||
@ -107,7 +107,7 @@ func (r *PluginPathRunner) OnSubscribe(ctx context.Context, user *user.SignedInU
|
||||
}
|
||||
|
||||
// OnPublish passes control to a plugin.
|
||||
func (r *PluginPathRunner) OnPublish(ctx context.Context, user *user.SignedInUser, e model.PublishEvent) (model.PublishReply, backend.PublishStreamStatus, error) {
|
||||
func (r *PluginPathRunner) OnPublish(ctx context.Context, user identity.Requester, e model.PublishEvent) (model.PublishReply, backend.PublishStreamStatus, error) {
|
||||
pCtx, err := r.pluginContextGetter.GetPluginContext(ctx, user, r.pluginID, r.datasourceUID, false)
|
||||
if err != nil {
|
||||
if errors.Is(err, plugincontext.ErrPluginNotFound) {
|
||||
|
@ -10,7 +10,7 @@ import (
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
backend "github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
user "github.com/grafana/grafana/pkg/services/user"
|
||||
identity "github.com/grafana/grafana/pkg/services/auth/identity"
|
||||
)
|
||||
|
||||
// MockPluginContextGetter is a mock of PluginContextGetter interface.
|
||||
@ -37,7 +37,7 @@ func (m *MockPluginContextGetter) EXPECT() *MockPluginContextGetterMockRecorder
|
||||
}
|
||||
|
||||
// GetPluginContext mocks base method.
|
||||
func (m *MockPluginContextGetter) GetPluginContext(arg0 context.Context, arg1 *user.SignedInUser, arg2, arg3 string, arg4 bool) (backend.PluginContext, error) {
|
||||
func (m *MockPluginContextGetter) GetPluginContext(arg0 context.Context, arg1 identity.Requester, arg2, arg3 string, arg4 bool) (backend.PluginContext, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetPluginContext", arg0, arg1, arg2, arg3, arg4)
|
||||
ret0, _ := ret[0].(backend.PluginContext)
|
||||
|
@ -32,6 +32,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/annotations"
|
||||
"github.com/grafana/grafana/pkg/services/auth/identity"
|
||||
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
@ -299,10 +300,11 @@ func ProvideService(plugCtxProvider *plugincontext.Provider, cfg *setting.Cfg, r
|
||||
|
||||
g.websocketHandler = func(ctx *contextmodel.ReqContext) {
|
||||
user := ctx.SignedInUser
|
||||
_, userID := user.GetNamespacedID()
|
||||
|
||||
// Centrifuge expects Credentials in context with a current user ID.
|
||||
cred := ¢rifuge.Credentials{
|
||||
UserID: fmt.Sprintf("%d", user.UserID),
|
||||
UserID: userID,
|
||||
}
|
||||
newCtx := centrifuge.SetCredentials(ctx.Req.Context(), cred)
|
||||
newCtx = livecontext.SetContextSignedUser(newCtx, user)
|
||||
@ -593,7 +595,7 @@ func (g *GrafanaLive) handleOnSubscribe(ctx context.Context, client *centrifuge.
|
||||
return centrifuge.SubscribeReply{}, centrifuge.ErrorInternal
|
||||
}
|
||||
|
||||
if user.OrgID != orgID {
|
||||
if user.GetOrgID() != orgID {
|
||||
logger.Info("Error subscribing: wrong orgId", "user", client.UserID(), "client", client.ID(), "channel", e.Channel)
|
||||
return centrifuge.SubscribeReply{}, centrifuge.ErrorPermissionDenied
|
||||
}
|
||||
@ -603,7 +605,7 @@ func (g *GrafanaLive) handleOnSubscribe(ctx context.Context, client *centrifuge.
|
||||
var ruleFound bool
|
||||
|
||||
if g.Pipeline != nil {
|
||||
rule, ok, err := g.Pipeline.Get(user.OrgID, channel)
|
||||
rule, ok, err := g.Pipeline.Get(user.GetOrgID(), channel)
|
||||
if err != nil {
|
||||
logger.Error("Error getting channel rule", "user", client.UserID(), "client", client.ID(), "channel", e.Channel, "error", err)
|
||||
return centrifuge.SubscribeReply{}, centrifuge.ErrorInternal
|
||||
@ -694,13 +696,13 @@ func (g *GrafanaLive) handleOnPublish(ctx context.Context, client *centrifuge.Cl
|
||||
return centrifuge.PublishReply{}, centrifuge.ErrorInternal
|
||||
}
|
||||
|
||||
if user.OrgID != orgID {
|
||||
if user.GetOrgID() != orgID {
|
||||
logger.Info("Error subscribing: wrong orgId", "user", client.UserID(), "client", client.ID(), "channel", e.Channel)
|
||||
return centrifuge.PublishReply{}, centrifuge.ErrorPermissionDenied
|
||||
}
|
||||
|
||||
if g.Pipeline != nil {
|
||||
rule, ok, err := g.Pipeline.Get(user.OrgID, channel)
|
||||
rule, ok, err := g.Pipeline.Get(user.GetOrgID(), channel)
|
||||
if err != nil {
|
||||
logger.Error("Error getting channel rule", "user", client.UserID(), "client", client.ID(), "channel", e.Channel, "error", err)
|
||||
return centrifuge.PublishReply{}, centrifuge.ErrorInternal
|
||||
@ -724,7 +726,7 @@ func (g *GrafanaLive) handleOnPublish(ctx context.Context, client *centrifuge.Cl
|
||||
return centrifuge.PublishReply{}, ¢rifuge.Error{Code: uint32(code), Message: text}
|
||||
}
|
||||
}
|
||||
_, err := g.Pipeline.ProcessInput(client.Context(), user.OrgID, channel, e.Data)
|
||||
_, err := g.Pipeline.ProcessInput(client.Context(), user.GetOrgID(), channel, e.Data)
|
||||
if err != nil {
|
||||
logger.Error("Error processing input", "user", client.UserID(), "client", client.ID(), "channel", e.Channel, "error", err)
|
||||
return centrifuge.PublishReply{}, centrifuge.ErrorInternal
|
||||
@ -805,7 +807,7 @@ func publishStatusToHTTPError(status backend.PublishStreamStatus) (int, string)
|
||||
}
|
||||
|
||||
// GetChannelHandler gives thread-safe access to the channel.
|
||||
func (g *GrafanaLive) GetChannelHandler(ctx context.Context, user *user.SignedInUser, channel string) (model.ChannelHandler, live.Channel, error) {
|
||||
func (g *GrafanaLive) GetChannelHandler(ctx context.Context, user identity.Requester, channel string) (model.ChannelHandler, live.Channel, error) {
|
||||
// Parse the identifier ${scope}/${namespace}/${path}
|
||||
addr, err := live.ParseChannel(channel)
|
||||
if err != nil {
|
||||
@ -846,7 +848,7 @@ func (g *GrafanaLive) GetChannelHandler(ctx context.Context, user *user.SignedIn
|
||||
|
||||
// GetChannelHandlerFactory gets a ChannelHandlerFactory for a namespace.
|
||||
// It gives thread-safe access to the channel.
|
||||
func (g *GrafanaLive) GetChannelHandlerFactory(ctx context.Context, user *user.SignedInUser, scope string, namespace string) (model.ChannelHandlerFactory, error) {
|
||||
func (g *GrafanaLive) GetChannelHandlerFactory(ctx context.Context, user identity.Requester, scope string, namespace string) (model.ChannelHandlerFactory, error) {
|
||||
switch scope {
|
||||
case live.ScopeGrafana:
|
||||
return g.handleGrafanaScope(user, namespace)
|
||||
@ -861,14 +863,14 @@ func (g *GrafanaLive) GetChannelHandlerFactory(ctx context.Context, user *user.S
|
||||
}
|
||||
}
|
||||
|
||||
func (g *GrafanaLive) handleGrafanaScope(_ *user.SignedInUser, namespace string) (model.ChannelHandlerFactory, error) {
|
||||
func (g *GrafanaLive) handleGrafanaScope(_ identity.Requester, namespace string) (model.ChannelHandlerFactory, error) {
|
||||
if p, ok := g.GrafanaScope.Features[namespace]; ok {
|
||||
return p, nil
|
||||
}
|
||||
return nil, fmt.Errorf("unknown feature: %q", namespace)
|
||||
}
|
||||
|
||||
func (g *GrafanaLive) handlePluginScope(ctx context.Context, _ *user.SignedInUser, namespace string) (model.ChannelHandlerFactory, error) {
|
||||
func (g *GrafanaLive) handlePluginScope(ctx context.Context, _ identity.Requester, namespace string) (model.ChannelHandlerFactory, error) {
|
||||
streamHandler, err := g.getStreamPlugin(ctx, namespace)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't find stream plugin: %s", namespace)
|
||||
@ -882,11 +884,11 @@ func (g *GrafanaLive) handlePluginScope(ctx context.Context, _ *user.SignedInUse
|
||||
), nil
|
||||
}
|
||||
|
||||
func (g *GrafanaLive) handleStreamScope(u *user.SignedInUser, namespace string) (model.ChannelHandlerFactory, error) {
|
||||
return g.ManagedStreamRunner.GetOrCreateStream(u.OrgID, live.ScopeStream, namespace)
|
||||
func (g *GrafanaLive) handleStreamScope(u identity.Requester, namespace string) (model.ChannelHandlerFactory, error) {
|
||||
return g.ManagedStreamRunner.GetOrCreateStream(u.GetOrgID(), live.ScopeStream, namespace)
|
||||
}
|
||||
|
||||
func (g *GrafanaLive) handleDatasourceScope(ctx context.Context, user *user.SignedInUser, namespace string) (model.ChannelHandlerFactory, error) {
|
||||
func (g *GrafanaLive) handleDatasourceScope(ctx context.Context, user identity.Requester, namespace string) (model.ChannelHandlerFactory, error) {
|
||||
ds, err := g.DataSourceCache.GetDatasourceByUID(ctx, namespace, user, false)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting datasource: %w", err)
|
||||
@ -929,12 +931,13 @@ func (g *GrafanaLive) HandleHTTPPublish(ctx *contextmodel.ReqContext) response.R
|
||||
return response.Error(http.StatusBadRequest, "invalid channel ID", nil)
|
||||
}
|
||||
|
||||
logger.Debug("Publish API cmd", "user", ctx.SignedInUser.UserID, "channel", cmd.Channel)
|
||||
namespaceID, userID := ctx.SignedInUser.GetNamespacedID()
|
||||
logger.Debug("Publish API cmd", "namespaceID", namespaceID, "userID", userID, "channel", cmd.Channel)
|
||||
user := ctx.SignedInUser
|
||||
channel := cmd.Channel
|
||||
|
||||
if g.Pipeline != nil {
|
||||
rule, ok, err := g.Pipeline.Get(user.OrgID, channel)
|
||||
rule, ok, err := g.Pipeline.Get(user.GetOrgID(), channel)
|
||||
if err != nil {
|
||||
logger.Error("Error getting channel rule", "user", user, "channel", channel, "error", err)
|
||||
return response.Error(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError), nil)
|
||||
@ -954,7 +957,7 @@ func (g *GrafanaLive) HandleHTTPPublish(ctx *contextmodel.ReqContext) response.R
|
||||
return response.Error(http.StatusForbidden, http.StatusText(http.StatusForbidden), nil)
|
||||
}
|
||||
}
|
||||
_, err := g.Pipeline.ProcessInput(ctx.Req.Context(), user.OrgID, channel, cmd.Data)
|
||||
_, err := g.Pipeline.ProcessInput(ctx.Req.Context(), user.GetOrgID(), channel, cmd.Data)
|
||||
if err != nil {
|
||||
logger.Error("Error processing input", "user", user, "channel", channel, "error", err)
|
||||
return response.Error(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError), nil)
|
||||
@ -980,13 +983,13 @@ func (g *GrafanaLive) HandleHTTPPublish(ctx *contextmodel.ReqContext) response.R
|
||||
return response.Error(code, text, nil)
|
||||
}
|
||||
if reply.Data != nil {
|
||||
err = g.Publish(ctx.OrgID, cmd.Channel, cmd.Data)
|
||||
err = g.Publish(ctx.SignedInUser.GetOrgID(), cmd.Channel, cmd.Data)
|
||||
if err != nil {
|
||||
logger.Error("Error publish to channel", "error", err, "channel", cmd.Channel)
|
||||
return response.Error(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError), nil)
|
||||
}
|
||||
}
|
||||
logger.Debug("Publication successful", "user", ctx.SignedInUser.UserID, "channel", cmd.Channel)
|
||||
logger.Debug("Publication successful", "namespaceID", namespaceID, "userID", userID, "channel", cmd.Channel)
|
||||
return response.JSON(http.StatusOK, dtos.LivePublishResponse{})
|
||||
}
|
||||
|
||||
@ -999,9 +1002,9 @@ func (g *GrafanaLive) HandleListHTTP(c *contextmodel.ReqContext) response.Respon
|
||||
var channels []*managedstream.ManagedChannel
|
||||
var err error
|
||||
if g.IsHA() {
|
||||
channels, err = g.surveyCaller.CallManagedStreams(c.SignedInUser.OrgID)
|
||||
channels, err = g.surveyCaller.CallManagedStreams(c.SignedInUser.GetOrgID())
|
||||
} else {
|
||||
channels, err = g.ManagedStreamRunner.GetManagedChannels(c.SignedInUser.OrgID)
|
||||
channels, err = g.ManagedStreamRunner.GetManagedChannels(c.SignedInUser.GetOrgID())
|
||||
}
|
||||
if err != nil {
|
||||
return response.Error(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError), err)
|
||||
@ -1017,7 +1020,7 @@ func (g *GrafanaLive) HandleInfoHTTP(ctx *contextmodel.ReqContext) response.Resp
|
||||
path := web.Params(ctx.Req)["*"]
|
||||
if path == "grafana/dashboards/gitops" {
|
||||
return response.JSON(http.StatusOK, util.DynMap{
|
||||
"active": g.GrafanaScope.Dashboards.HasGitOpsObserver(ctx.SignedInUser.OrgID),
|
||||
"active": g.GrafanaScope.Dashboards.HasGitOpsObserver(ctx.SignedInUser.GetOrgID()),
|
||||
})
|
||||
}
|
||||
return response.JSONStreaming(404, util.DynMap{
|
||||
@ -1027,7 +1030,7 @@ func (g *GrafanaLive) HandleInfoHTTP(ctx *contextmodel.ReqContext) response.Resp
|
||||
|
||||
// HandleChannelRulesListHTTP ...
|
||||
func (g *GrafanaLive) HandleChannelRulesListHTTP(c *contextmodel.ReqContext) response.Response {
|
||||
result, err := g.pipelineStorage.ListChannelRules(c.Req.Context(), c.OrgID)
|
||||
result, err := g.pipelineStorage.ListChannelRules(c.Req.Context(), c.SignedInUser.GetOrgID())
|
||||
if err != nil {
|
||||
return response.Error(http.StatusInternalServerError, "Failed to get channel rules", err)
|
||||
}
|
||||
@ -1112,7 +1115,7 @@ func (g *GrafanaLive) HandlePipelineConvertTestHTTP(c *contextmodel.ReqContext)
|
||||
if err != nil {
|
||||
return response.Error(http.StatusInternalServerError, "Error creating pipeline", err)
|
||||
}
|
||||
rule, ok, err := channelRuleGetter.Get(c.OrgID, req.Channel)
|
||||
rule, ok, err := channelRuleGetter.Get(c.SignedInUser.GetOrgID(), req.Channel)
|
||||
if err != nil {
|
||||
return response.Error(http.StatusInternalServerError, "Error getting channel rule", err)
|
||||
}
|
||||
@ -1122,7 +1125,7 @@ func (g *GrafanaLive) HandlePipelineConvertTestHTTP(c *contextmodel.ReqContext)
|
||||
if rule.Converter == nil {
|
||||
return response.Error(http.StatusNotFound, "No converter found", nil)
|
||||
}
|
||||
channelFrames, err := pipe.DataToChannelFrames(c.Req.Context(), *rule, c.OrgID, req.Channel, []byte(req.Data))
|
||||
channelFrames, err := pipe.DataToChannelFrames(c.Req.Context(), *rule, c.SignedInUser.GetOrgID(), req.Channel, []byte(req.Data))
|
||||
if err != nil {
|
||||
return response.Error(http.StatusInternalServerError, "Error converting data", err)
|
||||
}
|
||||
@ -1142,7 +1145,7 @@ func (g *GrafanaLive) HandleChannelRulesPostHTTP(c *contextmodel.ReqContext) res
|
||||
if err != nil {
|
||||
return response.Error(http.StatusBadRequest, "Error decoding channel rule", err)
|
||||
}
|
||||
rule, err := g.pipelineStorage.CreateChannelRule(c.Req.Context(), c.OrgID, cmd)
|
||||
rule, err := g.pipelineStorage.CreateChannelRule(c.Req.Context(), c.SignedInUser.GetOrgID(), cmd)
|
||||
if err != nil {
|
||||
return response.Error(http.StatusInternalServerError, "Failed to create channel rule", err)
|
||||
}
|
||||
@ -1165,7 +1168,7 @@ func (g *GrafanaLive) HandleChannelRulesPutHTTP(c *contextmodel.ReqContext) resp
|
||||
if cmd.Pattern == "" {
|
||||
return response.Error(http.StatusBadRequest, "Rule pattern required", nil)
|
||||
}
|
||||
rule, err := g.pipelineStorage.UpdateChannelRule(c.Req.Context(), c.OrgID, cmd)
|
||||
rule, err := g.pipelineStorage.UpdateChannelRule(c.Req.Context(), c.SignedInUser.GetOrgID(), cmd)
|
||||
if err != nil {
|
||||
return response.Error(http.StatusInternalServerError, "Failed to update channel rule", err)
|
||||
}
|
||||
@ -1188,7 +1191,7 @@ func (g *GrafanaLive) HandleChannelRulesDeleteHTTP(c *contextmodel.ReqContext) r
|
||||
if cmd.Pattern == "" {
|
||||
return response.Error(http.StatusBadRequest, "Rule pattern required", nil)
|
||||
}
|
||||
err = g.pipelineStorage.DeleteChannelRule(c.Req.Context(), c.OrgID, cmd)
|
||||
err = g.pipelineStorage.DeleteChannelRule(c.Req.Context(), c.SignedInUser.GetOrgID(), cmd)
|
||||
if err != nil {
|
||||
return response.Error(http.StatusInternalServerError, "Failed to delete channel rule", err)
|
||||
}
|
||||
@ -1208,7 +1211,7 @@ func (g *GrafanaLive) HandlePipelineEntitiesListHTTP(_ *contextmodel.ReqContext)
|
||||
|
||||
// HandleWriteConfigsListHTTP ...
|
||||
func (g *GrafanaLive) HandleWriteConfigsListHTTP(c *contextmodel.ReqContext) response.Response {
|
||||
backends, err := g.pipelineStorage.ListWriteConfigs(c.Req.Context(), c.OrgID)
|
||||
backends, err := g.pipelineStorage.ListWriteConfigs(c.Req.Context(), c.SignedInUser.GetOrgID())
|
||||
if err != nil {
|
||||
return response.Error(http.StatusInternalServerError, "Failed to get write configs", err)
|
||||
}
|
||||
@ -1232,7 +1235,7 @@ func (g *GrafanaLive) HandleWriteConfigsPostHTTP(c *contextmodel.ReqContext) res
|
||||
if err != nil {
|
||||
return response.Error(http.StatusBadRequest, "Error decoding write config create command", err)
|
||||
}
|
||||
result, err := g.pipelineStorage.CreateWriteConfig(c.Req.Context(), c.OrgID, cmd)
|
||||
result, err := g.pipelineStorage.CreateWriteConfig(c.Req.Context(), c.SignedInUser.GetOrgID(), cmd)
|
||||
if err != nil {
|
||||
return response.Error(http.StatusInternalServerError, "Failed to create write config", err)
|
||||
}
|
||||
@ -1255,7 +1258,7 @@ func (g *GrafanaLive) HandleWriteConfigsPutHTTP(c *contextmodel.ReqContext) resp
|
||||
if cmd.UID == "" {
|
||||
return response.Error(http.StatusBadRequest, "UID required", nil)
|
||||
}
|
||||
existingBackend, ok, err := g.pipelineStorage.GetWriteConfig(c.Req.Context(), c.OrgID, pipeline.WriteConfigGetCmd{
|
||||
existingBackend, ok, err := g.pipelineStorage.GetWriteConfig(c.Req.Context(), c.SignedInUser.GetOrgID(), pipeline.WriteConfigGetCmd{
|
||||
UID: cmd.UID,
|
||||
})
|
||||
if err != nil {
|
||||
@ -1276,7 +1279,7 @@ func (g *GrafanaLive) HandleWriteConfigsPutHTTP(c *contextmodel.ReqContext) resp
|
||||
}
|
||||
}
|
||||
}
|
||||
result, err := g.pipelineStorage.UpdateWriteConfig(c.Req.Context(), c.OrgID, cmd)
|
||||
result, err := g.pipelineStorage.UpdateWriteConfig(c.Req.Context(), c.SignedInUser.GetOrgID(), cmd)
|
||||
if err != nil {
|
||||
return response.Error(http.StatusInternalServerError, "Failed to update write config", err)
|
||||
}
|
||||
@ -1299,7 +1302,7 @@ func (g *GrafanaLive) HandleWriteConfigsDeleteHTTP(c *contextmodel.ReqContext) r
|
||||
if cmd.UID == "" {
|
||||
return response.Error(http.StatusBadRequest, "UID required", nil)
|
||||
}
|
||||
err = g.pipelineStorage.DeleteWriteConfig(c.Req.Context(), c.OrgID, cmd)
|
||||
err = g.pipelineStorage.DeleteWriteConfig(c.Req.Context(), c.SignedInUser.GetOrgID(), cmd)
|
||||
if err != nil {
|
||||
return response.Error(http.StatusInternalServerError, "Failed to delete write config", err)
|
||||
}
|
||||
|
@ -3,21 +3,21 @@ package livecontext
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/services/auth/identity"
|
||||
)
|
||||
|
||||
type signedUserContextKeyType int
|
||||
|
||||
var signedUserContextKey signedUserContextKeyType
|
||||
|
||||
func SetContextSignedUser(ctx context.Context, user *user.SignedInUser) context.Context {
|
||||
func SetContextSignedUser(ctx context.Context, user identity.Requester) context.Context {
|
||||
ctx = context.WithValue(ctx, signedUserContextKey, user)
|
||||
return ctx
|
||||
}
|
||||
|
||||
func GetContextSignedUser(ctx context.Context) (*user.SignedInUser, bool) {
|
||||
func GetContextSignedUser(ctx context.Context) (identity.Requester, bool) {
|
||||
if val := ctx.Value(signedUserContextKey); val != nil {
|
||||
user, ok := val.(*user.SignedInUser)
|
||||
user, ok := val.(identity.Requester)
|
||||
return user, ok
|
||||
}
|
||||
return nil, false
|
||||
|
@ -7,11 +7,11 @@ import (
|
||||
"github.com/centrifugal/centrifuge"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/auth/identity"
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
"github.com/grafana/grafana/pkg/services/live/orgchannel"
|
||||
"github.com/grafana/grafana/pkg/services/live/pipeline"
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
)
|
||||
|
||||
type ChannelLocalPublisher struct {
|
||||
@ -72,9 +72,9 @@ func NewContextGetter(pluginContextProvider *plugincontext.Provider, dataSourceC
|
||||
}
|
||||
}
|
||||
|
||||
func (g *ContextGetter) GetPluginContext(ctx context.Context, user *user.SignedInUser, pluginID string, datasourceUID string, skipCache bool) (backend.PluginContext, error) {
|
||||
func (g *ContextGetter) GetPluginContext(ctx context.Context, user identity.Requester, pluginID string, datasourceUID string, skipCache bool) (backend.PluginContext, error) {
|
||||
if datasourceUID == "" {
|
||||
return g.pluginContextProvider.Get(ctx, pluginID, user, user.OrgID)
|
||||
return g.pluginContextProvider.Get(ctx, pluginID, user, user.GetOrgID())
|
||||
}
|
||||
|
||||
ds, err := g.dataSourceCache.GetDatasourceByUID(ctx, datasourceUID, user, skipCache)
|
||||
|
@ -13,9 +13,9 @@ import (
|
||||
"github.com/grafana/grafana-plugin-sdk-go/live"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/services/auth/identity"
|
||||
"github.com/grafana/grafana/pkg/services/live/model"
|
||||
"github.com/grafana/grafana/pkg/services/live/orgchannel"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -239,9 +239,9 @@ func (s *NamespaceStream) GetHandlerForPath(_ string) (model.ChannelHandler, err
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (s *NamespaceStream) OnSubscribe(ctx context.Context, u *user.SignedInUser, e model.SubscribeEvent) (model.SubscribeReply, backend.SubscribeStreamStatus, error) {
|
||||
func (s *NamespaceStream) OnSubscribe(ctx context.Context, u identity.Requester, e model.SubscribeEvent) (model.SubscribeReply, backend.SubscribeStreamStatus, error) {
|
||||
reply := model.SubscribeReply{}
|
||||
frameJSON, ok, err := s.frameCache.GetFrame(ctx, u.OrgID, e.Channel)
|
||||
frameJSON, ok, err := s.frameCache.GetFrame(ctx, u.GetOrgID(), e.Channel)
|
||||
if err != nil {
|
||||
return reply, 0, err
|
||||
}
|
||||
@ -251,6 +251,6 @@ func (s *NamespaceStream) OnSubscribe(ctx context.Context, u *user.SignedInUser,
|
||||
return reply, backend.SubscribeStreamStatusOK, nil
|
||||
}
|
||||
|
||||
func (s *NamespaceStream) OnPublish(_ context.Context, _ *user.SignedInUser, _ model.PublishEvent) (model.PublishReply, backend.PublishStreamStatus, error) {
|
||||
func (s *NamespaceStream) OnPublish(_ context.Context, _ identity.Requester, _ model.PublishEvent) (model.PublishReply, backend.PublishStreamStatus, error) {
|
||||
return model.PublishReply{}, backend.PublishStreamStatusPermissionDenied, nil
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ import (
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/services/auth/identity"
|
||||
)
|
||||
|
||||
// ChannelPublisher writes data into a channel. Note that permissions are not checked.
|
||||
@ -54,10 +54,10 @@ type PublishReply struct {
|
||||
// ChannelHandler defines the core channel behavior
|
||||
type ChannelHandler interface {
|
||||
// OnSubscribe is called when a client wants to subscribe to a channel
|
||||
OnSubscribe(ctx context.Context, user *user.SignedInUser, e SubscribeEvent) (SubscribeReply, backend.SubscribeStreamStatus, error)
|
||||
OnSubscribe(ctx context.Context, user identity.Requester, e SubscribeEvent) (SubscribeReply, backend.SubscribeStreamStatus, error)
|
||||
|
||||
// OnPublish is called when a client writes a message to the channel websocket.
|
||||
OnPublish(ctx context.Context, user *user.SignedInUser, e PublishEvent) (PublishReply, backend.PublishStreamStatus, error)
|
||||
OnPublish(ctx context.Context, user identity.Requester, e PublishEvent) (PublishReply, backend.PublishStreamStatus, error)
|
||||
}
|
||||
|
||||
// ChannelHandlerFactory should be implemented by all core features.
|
||||
|
@ -3,8 +3,8 @@ package pipeline
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/auth/identity"
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
)
|
||||
|
||||
type RoleCheckAuthorizer struct {
|
||||
@ -15,10 +15,10 @@ func NewRoleCheckAuthorizer(role org.RoleType) *RoleCheckAuthorizer {
|
||||
return &RoleCheckAuthorizer{role: role}
|
||||
}
|
||||
|
||||
func (s *RoleCheckAuthorizer) CanSubscribe(_ context.Context, u *user.SignedInUser) (bool, error) {
|
||||
func (s *RoleCheckAuthorizer) CanSubscribe(_ context.Context, u identity.Requester) (bool, error) {
|
||||
return u.HasRole(s.role), nil
|
||||
}
|
||||
|
||||
func (s *RoleCheckAuthorizer) CanPublish(_ context.Context, u *user.SignedInUser) (bool, error) {
|
||||
func (s *RoleCheckAuthorizer) CanPublish(_ context.Context, u identity.Requester) (bool, error) {
|
||||
return u.HasRole(s.role), nil
|
||||
}
|
||||
|
@ -17,8 +17,8 @@ import (
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/auth/identity"
|
||||
"github.com/grafana/grafana/pkg/services/live/model"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -113,12 +113,12 @@ type Subscriber interface {
|
||||
|
||||
// PublishAuthChecker checks whether current user can publish to a channel.
|
||||
type PublishAuthChecker interface {
|
||||
CanPublish(ctx context.Context, u *user.SignedInUser) (bool, error)
|
||||
CanPublish(ctx context.Context, u identity.Requester) (bool, error)
|
||||
}
|
||||
|
||||
// SubscribeAuthChecker checks whether current user can subscribe to a channel.
|
||||
type SubscribeAuthChecker interface {
|
||||
CanSubscribe(ctx context.Context, u *user.SignedInUser) (bool, error)
|
||||
CanSubscribe(ctx context.Context, u identity.Requester) (bool, error)
|
||||
}
|
||||
|
||||
// LiveChannelRule is an in-memory representation of each specific rule to be executed by Pipeline.
|
||||
|
@ -6,9 +6,9 @@ import (
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/live"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/auth/identity"
|
||||
"github.com/grafana/grafana/pkg/services/live/livecontext"
|
||||
"github.com/grafana/grafana/pkg/services/live/model"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
)
|
||||
|
||||
type BuiltinSubscriber struct {
|
||||
@ -16,7 +16,7 @@ type BuiltinSubscriber struct {
|
||||
}
|
||||
|
||||
type ChannelHandlerGetter interface {
|
||||
GetChannelHandler(ctx context.Context, user *user.SignedInUser, channel string) (model.ChannelHandler, live.Channel, error)
|
||||
GetChannelHandler(ctx context.Context, user identity.Requester, channel string) (model.ChannelHandler, live.Channel, error)
|
||||
}
|
||||
|
||||
const SubscriberTypeBuiltin = "builtin"
|
||||
|
@ -71,7 +71,7 @@ func (s *PipelinePushHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request)
|
||||
"bodyLength", len(body),
|
||||
)
|
||||
|
||||
ruleFound, err := s.pipeline.ProcessInput(r.Context(), user.OrgID, channelID, body)
|
||||
ruleFound, err := s.pipeline.ProcessInput(r.Context(), user.GetOrgID(), channelID, body)
|
||||
if err != nil {
|
||||
logger.Error("Pipeline input processing error", "error", err, "body", string(body))
|
||||
return
|
||||
|
@ -67,7 +67,7 @@ func (s *Handler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
||||
break
|
||||
}
|
||||
|
||||
stream, err := s.managedStreamRunner.GetOrCreateStream(user.OrgID, liveDto.ScopeStream, streamID)
|
||||
stream, err := s.managedStreamRunner.GetOrCreateStream(user.GetOrgID(), liveDto.ScopeStream, streamID)
|
||||
if err != nil {
|
||||
logger.Error("Error getting stream", "error", err)
|
||||
continue
|
||||
|
@ -11,8 +11,8 @@ import (
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/services/auth/identity"
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -26,7 +26,7 @@ type ChannelLocalPublisher interface {
|
||||
}
|
||||
|
||||
type PluginContextGetter interface {
|
||||
GetPluginContext(ctx context.Context, user *user.SignedInUser, pluginID string, datasourceUID string, skipCache bool) (backend.PluginContext, error)
|
||||
GetPluginContext(ctx context.Context, user identity.Requester, pluginID string, datasourceUID string, skipCache bool) (backend.PluginContext, error)
|
||||
}
|
||||
|
||||
type NumLocalSubscribersGetter interface {
|
||||
@ -374,7 +374,7 @@ func (s *Manager) Run(ctx context.Context) error {
|
||||
type streamRequest struct {
|
||||
Channel string
|
||||
Path string
|
||||
user *user.SignedInUser
|
||||
user identity.Requester
|
||||
PluginContext backend.PluginContext
|
||||
StreamRunner StreamRunner
|
||||
Data []byte
|
||||
@ -401,7 +401,7 @@ var errDatasourceNotFound = errors.New("datasource not found")
|
||||
|
||||
// SubmitStream submits stream handler in Manager to manage.
|
||||
// The stream will be opened and kept till channel has active subscribers.
|
||||
func (s *Manager) SubmitStream(ctx context.Context, user *user.SignedInUser, channel string, path string, data []byte, pCtx backend.PluginContext, streamRunner StreamRunner, isResubmit bool) (*submitResult, error) {
|
||||
func (s *Manager) SubmitStream(ctx context.Context, user identity.Requester, channel string, path string, data []byte, pCtx backend.PluginContext, streamRunner StreamRunner, isResubmit bool) (*submitResult, error) {
|
||||
if isResubmit {
|
||||
// Resolve new plugin context as it could be modified since last call.
|
||||
var datasourceUID string
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/auth/identity"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
)
|
||||
|
||||
@ -71,9 +72,11 @@ func TestStreamManager_SubmitStream_Send(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
mockContextGetter.EXPECT().GetPluginContext(context.Background(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, user *user.SignedInUser, pluginID string, datasourceUID string, skipCache bool) (backend.PluginContext, bool, error) {
|
||||
require.Equal(t, int64(2), user.UserID)
|
||||
require.Equal(t, int64(1), user.OrgID)
|
||||
mockContextGetter.EXPECT().GetPluginContext(context.Background(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, user identity.Requester, pluginID string, datasourceUID string, skipCache bool) (backend.PluginContext, bool, error) {
|
||||
userID, err := identity.IntIdentifier(user.GetNamespacedID())
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, int64(2), userID)
|
||||
require.Equal(t, int64(1), user.GetOrgID())
|
||||
require.Equal(t, testPluginContext.PluginID, pluginID)
|
||||
require.Equal(t, testPluginContext.DataSourceInstanceSettings.UID, datasourceUID)
|
||||
return testPluginContext, true, nil
|
||||
@ -133,7 +136,7 @@ func TestStreamManager_SubmitStream_DifferentOrgID(t *testing.T) {
|
||||
mockPacketSender.EXPECT().PublishLocal("1/test", gomock.Any()).Times(1)
|
||||
mockPacketSender.EXPECT().PublishLocal("2/test", gomock.Any()).Times(1)
|
||||
|
||||
mockContextGetter.EXPECT().GetPluginContext(context.Background(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, user *user.SignedInUser, pluginID string, datasourceUID string, skipCache bool) (backend.PluginContext, bool, error) {
|
||||
mockContextGetter.EXPECT().GetPluginContext(context.Background(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, user identity.Requester, pluginID string, datasourceUID string, skipCache bool) (backend.PluginContext, bool, error) {
|
||||
return backend.PluginContext{}, true, nil
|
||||
}).Times(0)
|
||||
|
||||
@ -205,7 +208,7 @@ func TestStreamManager_SubmitStream_CloseNoSubscribers(t *testing.T) {
|
||||
startedCh := make(chan struct{})
|
||||
doneCh := make(chan struct{})
|
||||
|
||||
mockContextGetter.EXPECT().GetPluginContext(context.Background(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, user *user.SignedInUser, pluginID string, datasourceUID string, skipCache bool) (backend.PluginContext, bool, error) {
|
||||
mockContextGetter.EXPECT().GetPluginContext(context.Background(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, user identity.Requester, pluginID string, datasourceUID string, skipCache bool) (backend.PluginContext, bool, error) {
|
||||
return backend.PluginContext{}, true, nil
|
||||
}).Times(0)
|
||||
|
||||
@ -254,9 +257,11 @@ func TestStreamManager_SubmitStream_ErrorRestartsRunStream(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
mockContextGetter.EXPECT().GetPluginContext(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, user *user.SignedInUser, pluginID string, datasourceUID string, skipCache bool) (backend.PluginContext, bool, error) {
|
||||
require.Equal(t, int64(2), user.UserID)
|
||||
require.Equal(t, int64(1), user.OrgID)
|
||||
mockContextGetter.EXPECT().GetPluginContext(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, user identity.Requester, pluginID string, datasourceUID string, skipCache bool) (backend.PluginContext, bool, error) {
|
||||
userID, err := identity.IntIdentifier(user.GetNamespacedID())
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, int64(2), userID)
|
||||
require.Equal(t, int64(1), user.GetOrgID())
|
||||
require.Equal(t, testPluginContext.PluginID, pluginID)
|
||||
require.Equal(t, testPluginContext.DataSourceInstanceSettings.UID, datasourceUID)
|
||||
return testPluginContext, true, nil
|
||||
@ -296,7 +301,7 @@ func TestStreamManager_SubmitStream_NilErrorStopsRunStream(t *testing.T) {
|
||||
_ = manager.Run(ctx)
|
||||
}()
|
||||
|
||||
mockContextGetter.EXPECT().GetPluginContext(context.Background(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, user *user.SignedInUser, pluginID string, datasourceUID string, skipCache bool) (backend.PluginContext, bool, error) {
|
||||
mockContextGetter.EXPECT().GetPluginContext(context.Background(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, user identity.Requester, pluginID string, datasourceUID string, skipCache bool) (backend.PluginContext, bool, error) {
|
||||
return backend.PluginContext{}, true, nil
|
||||
}).Times(0)
|
||||
|
||||
@ -337,9 +342,12 @@ func TestStreamManager_HandleDatasourceUpdate(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
mockContextGetter.EXPECT().GetPluginContext(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, user *user.SignedInUser, pluginID string, datasourceUID string, skipCache bool) (backend.PluginContext, bool, error) {
|
||||
require.Equal(t, int64(2), user.UserID)
|
||||
require.Equal(t, int64(1), user.OrgID)
|
||||
mockContextGetter.EXPECT().GetPluginContext(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, user identity.Requester, pluginID string, datasourceUID string, skipCache bool) (backend.PluginContext, bool, error) {
|
||||
userID, err := identity.IntIdentifier(user.GetNamespacedID())
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, int64(2), userID)
|
||||
require.Equal(t, int64(1), user.GetOrgID())
|
||||
require.Equal(t, testPluginContext.PluginID, pluginID)
|
||||
require.Equal(t, testPluginContext.DataSourceInstanceSettings.UID, datasourceUID)
|
||||
return testPluginContext, true, nil
|
||||
@ -403,9 +411,11 @@ func TestStreamManager_HandleDatasourceDelete(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
mockContextGetter.EXPECT().GetPluginContext(context.Background(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, user *user.SignedInUser, pluginID string, datasourceUID string, skipCache bool) (backend.PluginContext, bool, error) {
|
||||
require.Equal(t, int64(2), user.UserID)
|
||||
require.Equal(t, int64(1), user.OrgID)
|
||||
mockContextGetter.EXPECT().GetPluginContext(context.Background(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, user identity.Requester, pluginID string, datasourceUID string, skipCache bool) (backend.PluginContext, bool, error) {
|
||||
userID, err := identity.IntIdentifier(user.GetNamespacedID())
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, int64(2), userID)
|
||||
require.Equal(t, int64(1), user.GetOrgID())
|
||||
require.Equal(t, testPluginContext.PluginID, pluginID)
|
||||
require.Equal(t, testPluginContext.DataSourceInstanceSettings.UID, datasourceUID)
|
||||
return testPluginContext, true, nil
|
||||
|
@ -10,7 +10,7 @@ import (
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
backend "github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
user "github.com/grafana/grafana/pkg/services/user"
|
||||
identity "github.com/grafana/grafana/pkg/services/auth/identity"
|
||||
)
|
||||
|
||||
// MockChannelLocalPublisher is a mock of ChannelLocalPublisher interface.
|
||||
@ -149,7 +149,7 @@ func (m *MockPluginContextGetter) EXPECT() *MockPluginContextGetterMockRecorder
|
||||
}
|
||||
|
||||
// GetPluginContext mocks base method.
|
||||
func (m *MockPluginContextGetter) GetPluginContext(arg0 context.Context, arg1 *user.SignedInUser, arg2, arg3 string, arg4 bool) (backend.PluginContext, error) {
|
||||
func (m *MockPluginContextGetter) GetPluginContext(arg0 context.Context, arg1 identity.Requester, arg2, arg3 string, arg4 bool) (backend.PluginContext, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetPluginContext", arg0, arg1, arg2, arg3, arg4)
|
||||
ret0, _ := ret[0].(backend.PluginContext)
|
||||
|
@ -9,10 +9,10 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/services/auth/identity"
|
||||
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
|
||||
"github.com/grafana/grafana/pkg/services/datasourceproxy"
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/web"
|
||||
)
|
||||
|
||||
@ -114,7 +114,7 @@ type fakeCacheService struct {
|
||||
err error
|
||||
}
|
||||
|
||||
func (f fakeCacheService) GetDatasource(_ context.Context, datasourceID int64, _ *user.SignedInUser, _ bool) (*datasources.DataSource, error) {
|
||||
func (f fakeCacheService) GetDatasource(_ context.Context, datasourceID int64, _ identity.Requester, _ bool) (*datasources.DataSource, error) {
|
||||
if f.err != nil {
|
||||
return nil, f.err
|
||||
}
|
||||
@ -122,7 +122,7 @@ func (f fakeCacheService) GetDatasource(_ context.Context, datasourceID int64, _
|
||||
return f.datasource, nil
|
||||
}
|
||||
|
||||
func (f fakeCacheService) GetDatasourceByUID(ctx context.Context, datasourceUID string, user *user.SignedInUser, skipCache bool) (*datasources.DataSource, error) {
|
||||
func (f fakeCacheService) GetDatasourceByUID(ctx context.Context, datasourceUID string, _ identity.Requester, skipCache bool) (*datasources.DataSource, error) {
|
||||
if f.err != nil {
|
||||
return nil, f.err
|
||||
}
|
||||
|
@ -7,8 +7,8 @@ import (
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/auth/identity"
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
)
|
||||
|
||||
// ModelToInstanceSettings converts a datasources.DataSource to a backend.DataSourceInstanceSettings.
|
||||
@ -43,16 +43,16 @@ func ModelToInstanceSettings(ds *datasources.DataSource, decryptFn func(ds *data
|
||||
}, err
|
||||
}
|
||||
|
||||
// BackendUserFromSignedInUser converts Grafana's SignedInUser model
|
||||
// BackendUserFromSignedInUser converts Grafana's context request identity
|
||||
// to the backend plugin's model.
|
||||
func BackendUserFromSignedInUser(su *user.SignedInUser) *backend.User {
|
||||
if su == nil {
|
||||
func BackendUserFromSignedInUser(requester identity.Requester) *backend.User {
|
||||
if requester == nil {
|
||||
return nil
|
||||
}
|
||||
return &backend.User{
|
||||
Login: su.Login,
|
||||
Name: su.Name,
|
||||
Email: su.Email,
|
||||
Role: string(su.OrgRole),
|
||||
Login: requester.GetLogin(),
|
||||
Name: requester.GetDisplayName(),
|
||||
Email: requester.GetEmail(),
|
||||
Role: string(requester.GetOrgRole()),
|
||||
}
|
||||
}
|
||||
|
@ -11,10 +11,10 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/localcache"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/services/auth/identity"
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/adapters"
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginsettings"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
)
|
||||
|
||||
var ErrPluginNotFound = errors.New("plugin not found")
|
||||
@ -39,8 +39,8 @@ type Provider struct {
|
||||
// Get allows getting plugin context by its ID. If datasourceUID is not empty string
|
||||
// then PluginContext.DataSourceInstanceSettings will be resolved and appended to
|
||||
// returned context.
|
||||
// Note: *user.SignedInUser can be nil.
|
||||
func (p *Provider) Get(ctx context.Context, pluginID string, user *user.SignedInUser, orgID int64) (backend.PluginContext, error) {
|
||||
// Note: identity.Requester can be nil.
|
||||
func (p *Provider) Get(ctx context.Context, pluginID string, user identity.Requester, orgID int64) (backend.PluginContext, error) {
|
||||
plugin, exists := p.pluginStore.Plugin(ctx, pluginID)
|
||||
if !exists {
|
||||
return backend.PluginContext{}, ErrPluginNotFound
|
||||
@ -50,7 +50,7 @@ func (p *Provider) Get(ctx context.Context, pluginID string, user *user.SignedIn
|
||||
PluginID: pluginID,
|
||||
}
|
||||
if user != nil {
|
||||
pCtx.OrgID = user.OrgID
|
||||
pCtx.OrgID = user.GetOrgID()
|
||||
pCtx.User = adapters.BackendUserFromSignedInUser(user)
|
||||
}
|
||||
|
||||
@ -68,7 +68,7 @@ func (p *Provider) Get(ctx context.Context, pluginID string, user *user.SignedIn
|
||||
// GetWithDataSource allows getting plugin context by its ID and PluginContext.DataSourceInstanceSettings will be
|
||||
// resolved and appended to the returned context.
|
||||
// Note: *user.SignedInUser can be nil.
|
||||
func (p *Provider) GetWithDataSource(ctx context.Context, pluginID string, user *user.SignedInUser, ds *datasources.DataSource) (backend.PluginContext, error) {
|
||||
func (p *Provider) GetWithDataSource(ctx context.Context, pluginID string, user identity.Requester, ds *datasources.DataSource) (backend.PluginContext, error) {
|
||||
_, exists := p.pluginStore.Plugin(ctx, pluginID)
|
||||
if !exists {
|
||||
return backend.PluginContext{}, ErrPluginNotFound
|
||||
@ -78,7 +78,7 @@ func (p *Provider) GetWithDataSource(ctx context.Context, pluginID string, user
|
||||
PluginID: pluginID,
|
||||
}
|
||||
if user != nil {
|
||||
pCtx.OrgID = user.OrgID
|
||||
pCtx.OrgID = user.GetOrgID()
|
||||
pCtx.User = adapters.BackendUserFromSignedInUser(user)
|
||||
}
|
||||
|
||||
|
@ -16,10 +16,10 @@ import (
|
||||
"github.com/grafana/grafana/pkg/expr"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/services/auth/identity"
|
||||
"github.com/grafana/grafana/pkg/services/contexthandler"
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/services/validations"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/tsdb/grafanads"
|
||||
@ -61,7 +61,7 @@ func ProvideService(
|
||||
//go:generate mockery --name Service --structname FakeQueryService --inpackage --filename query_service_mock.go
|
||||
type Service interface {
|
||||
Run(ctx context.Context) error
|
||||
QueryData(ctx context.Context, user *user.SignedInUser, skipDSCache bool, reqDTO dtos.MetricRequest) (*backend.QueryDataResponse, error)
|
||||
QueryData(ctx context.Context, user identity.Requester, skipDSCache bool, reqDTO dtos.MetricRequest) (*backend.QueryDataResponse, error)
|
||||
}
|
||||
|
||||
// Gives us compile time error if the service does not adhere to the contract of the interface
|
||||
@ -85,7 +85,7 @@ func (s *ServiceImpl) Run(ctx context.Context) error {
|
||||
}
|
||||
|
||||
// QueryData processes queries and returns query responses. It handles queries to single or mixed datasources, as well as expressions.
|
||||
func (s *ServiceImpl) QueryData(ctx context.Context, user *user.SignedInUser, skipDSCache bool, reqDTO dtos.MetricRequest) (*backend.QueryDataResponse, error) {
|
||||
func (s *ServiceImpl) QueryData(ctx context.Context, user identity.Requester, skipDSCache bool, reqDTO dtos.MetricRequest) (*backend.QueryDataResponse, error) {
|
||||
// Parse the request into parsed queries grouped by datasource uid
|
||||
parsedReq, err := s.parseMetricRequest(ctx, user, skipDSCache, reqDTO)
|
||||
if err != nil {
|
||||
@ -111,7 +111,7 @@ type splitResponse struct {
|
||||
}
|
||||
|
||||
// executeConcurrentQueries executes queries to multiple datasources concurrently and returns the aggregate result.
|
||||
func (s *ServiceImpl) executeConcurrentQueries(ctx context.Context, user *user.SignedInUser, skipDSCache bool, reqDTO dtos.MetricRequest, queriesbyDs map[string][]parsedQuery) (*backend.QueryDataResponse, error) {
|
||||
func (s *ServiceImpl) executeConcurrentQueries(ctx context.Context, user identity.Requester, skipDSCache bool, reqDTO dtos.MetricRequest, queriesbyDs map[string][]parsedQuery) (*backend.QueryDataResponse, error) {
|
||||
g, ctx := errgroup.WithContext(ctx)
|
||||
g.SetLimit(s.concurrentQueryLimit) // prevent too many concurrent requests
|
||||
rchan := make(chan splitResponse, len(queriesbyDs))
|
||||
@ -198,14 +198,14 @@ func buildErrorResponses(err error, queries []*simplejson.Json) splitResponse {
|
||||
}
|
||||
|
||||
// handleExpressions handles POST /api/ds/query when there is an expression.
|
||||
func (s *ServiceImpl) handleExpressions(ctx context.Context, user *user.SignedInUser, parsedReq *parsedRequest) (*backend.QueryDataResponse, error) {
|
||||
func (s *ServiceImpl) handleExpressions(ctx context.Context, user identity.Requester, parsedReq *parsedRequest) (*backend.QueryDataResponse, error) {
|
||||
exprReq := expr.Request{
|
||||
Queries: []expr.Query{},
|
||||
}
|
||||
|
||||
if user != nil { // for passthrough authentication, SSE does not authenticate
|
||||
exprReq.User = user
|
||||
exprReq.OrgId = user.OrgID
|
||||
exprReq.OrgId = user.GetOrgID()
|
||||
}
|
||||
|
||||
for _, pq := range parsedReq.getFlattenedQueries() {
|
||||
@ -239,7 +239,7 @@ func (s *ServiceImpl) handleExpressions(ctx context.Context, user *user.SignedIn
|
||||
}
|
||||
|
||||
// handleQuerySingleDatasource handles one or more queries to a single datasource
|
||||
func (s *ServiceImpl) handleQuerySingleDatasource(ctx context.Context, user *user.SignedInUser, parsedReq *parsedRequest) (*backend.QueryDataResponse, error) {
|
||||
func (s *ServiceImpl) handleQuerySingleDatasource(ctx context.Context, user identity.Requester, parsedReq *parsedRequest) (*backend.QueryDataResponse, error) {
|
||||
queries := parsedReq.getFlattenedQueries()
|
||||
ds := queries[0].datasource
|
||||
if err := s.pluginRequestValidator.Validate(ds.URL, nil); err != nil {
|
||||
@ -271,7 +271,7 @@ func (s *ServiceImpl) handleQuerySingleDatasource(ctx context.Context, user *use
|
||||
}
|
||||
|
||||
// parseRequest parses a request into parsed queries grouped by datasource uid
|
||||
func (s *ServiceImpl) parseMetricRequest(ctx context.Context, user *user.SignedInUser, skipDSCache bool, reqDTO dtos.MetricRequest) (*parsedRequest, error) {
|
||||
func (s *ServiceImpl) parseMetricRequest(ctx context.Context, user identity.Requester, skipDSCache bool, reqDTO dtos.MetricRequest) (*parsedRequest, error) {
|
||||
if len(reqDTO.Queries) == 0 {
|
||||
return nil, ErrNoQueriesFound
|
||||
}
|
||||
@ -332,7 +332,7 @@ func (s *ServiceImpl) parseMetricRequest(ctx context.Context, user *user.SignedI
|
||||
return req, req.validateRequest(ctx)
|
||||
}
|
||||
|
||||
func (s *ServiceImpl) getDataSourceFromQuery(ctx context.Context, user *user.SignedInUser, skipDSCache bool, query *simplejson.Json, history map[string]*datasources.DataSource) (*datasources.DataSource, error) {
|
||||
func (s *ServiceImpl) getDataSourceFromQuery(ctx context.Context, user identity.Requester, skipDSCache bool, query *simplejson.Json, history map[string]*datasources.DataSource) (*datasources.DataSource, error) {
|
||||
var err error
|
||||
uid := query.Get("datasource").Get("uid").MustString()
|
||||
|
||||
@ -352,7 +352,7 @@ func (s *ServiceImpl) getDataSourceFromQuery(ctx context.Context, user *user.Sig
|
||||
}
|
||||
|
||||
if uid == grafanads.DatasourceUID {
|
||||
return grafanads.DataSourceModel(user.OrgID), nil
|
||||
return grafanads.DataSourceModel(user.GetOrgID()), nil
|
||||
}
|
||||
|
||||
if uid != "" {
|
||||
|
@ -11,7 +11,7 @@ import (
|
||||
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
|
||||
user "github.com/grafana/grafana/pkg/services/user"
|
||||
identity "github.com/grafana/grafana/pkg/services/auth/identity"
|
||||
)
|
||||
|
||||
// FakeQueryService is an autogenerated mock type for the Service type
|
||||
@ -20,11 +20,11 @@ type FakeQueryService struct {
|
||||
}
|
||||
|
||||
// QueryData provides a mock function with given fields: ctx, _a1, skipDSCache, reqDTO
|
||||
func (_m *FakeQueryService) QueryData(ctx context.Context, _a1 *user.SignedInUser, skipDSCache bool, reqDTO dtos.MetricRequest) (*backend.QueryDataResponse, error) {
|
||||
func (_m *FakeQueryService) QueryData(ctx context.Context, _a1 identity.Requester, skipDSCache bool, reqDTO dtos.MetricRequest) (*backend.QueryDataResponse, error) {
|
||||
ret := _m.Called(ctx, _a1, skipDSCache, reqDTO)
|
||||
|
||||
var r0 *backend.QueryDataResponse
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *user.SignedInUser, bool, dtos.MetricRequest) *backend.QueryDataResponse); ok {
|
||||
if rf, ok := ret.Get(0).(func(context.Context, identity.Requester, bool, dtos.MetricRequest) *backend.QueryDataResponse); ok {
|
||||
r0 = rf(ctx, _a1, skipDSCache, reqDTO)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
@ -33,7 +33,7 @@ func (_m *FakeQueryService) QueryData(ctx context.Context, _a1 *user.SignedInUse
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *user.SignedInUser, bool, dtos.MetricRequest) error); ok {
|
||||
if rf, ok := ret.Get(1).(func(context.Context, identity.Requester, bool, dtos.MetricRequest) error); ok {
|
||||
r1 = rf(ctx, _a1, skipDSCache, reqDTO)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
|
@ -25,6 +25,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/models/roletype"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
pluginFakes "github.com/grafana/grafana/pkg/plugins/manager/fakes"
|
||||
"github.com/grafana/grafana/pkg/services/auth/identity"
|
||||
"github.com/grafana/grafana/pkg/services/contexthandler"
|
||||
"github.com/grafana/grafana/pkg/services/contexthandler/ctxkey"
|
||||
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
|
||||
@ -524,12 +525,12 @@ type fakeDataSourceCache struct {
|
||||
cache []*datasources.DataSource
|
||||
}
|
||||
|
||||
func (c *fakeDataSourceCache) GetDatasource(ctx context.Context, datasourceID int64, user *user.SignedInUser, skipCache bool) (*datasources.DataSource, error) {
|
||||
func (c *fakeDataSourceCache) GetDatasource(ctx context.Context, datasourceID int64, user identity.Requester, skipCache bool) (*datasources.DataSource, error) {
|
||||
// deprecated: fake an error to ensure we are using GetDatasourceByUID
|
||||
return nil, fmt.Errorf("not found")
|
||||
}
|
||||
|
||||
func (c *fakeDataSourceCache) GetDatasourceByUID(ctx context.Context, datasourceUID string, user *user.SignedInUser, skipCache bool) (*datasources.DataSource, error) {
|
||||
func (c *fakeDataSourceCache) GetDatasourceByUID(ctx context.Context, datasourceUID string, user identity.Requester, skipCache bool) (*datasources.DataSource, error) {
|
||||
for _, ds := range c.cache {
|
||||
if ds.UID == datasourceUID {
|
||||
return ds, nil
|
||||
|
@ -43,6 +43,9 @@ func (u *SignedInUser) NameOrFallback() string {
|
||||
return u.Email
|
||||
}
|
||||
|
||||
// TODO: There's a need to remove this struct since it creates a circular dependency
|
||||
|
||||
// DEPRECATED: This function uses `UserDisplayDTO` model which we want to remove
|
||||
func (u *SignedInUser) ToUserDisplayDTO() *UserDisplayDTO {
|
||||
return &UserDisplayDTO{
|
||||
ID: u.UserID,
|
||||
@ -51,6 +54,16 @@ func (u *SignedInUser) ToUserDisplayDTO() *UserDisplayDTO {
|
||||
}
|
||||
}
|
||||
|
||||
// Static function to parse a requester into a UserDisplayDTO
|
||||
func NewUserDisplayDTOFromRequester(requester identity.Requester) (*UserDisplayDTO, error) {
|
||||
userID, _ := identity.IntIdentifier(requester.GetNamespacedID())
|
||||
return &UserDisplayDTO{
|
||||
ID: userID,
|
||||
Login: requester.GetLogin(),
|
||||
Name: requester.GetDisplayName(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (u *SignedInUser) HasRole(role roletype.RoleType) bool {
|
||||
if u.IsGrafanaAdmin {
|
||||
return true
|
||||
|
Loading…
Reference in New Issue
Block a user