Refactor: Add UID endpoint for dashboard versions and restore (#48364)

* Refactor: Add UID endpoint for dashboard versions and restore

* Fix: User dashID instead of dash.id

* 💩

* Move apiCmd error handling outside of dashUID check

* fix the panic in test

* Fix handler and update docs

Co-authored-by: Kat Yang <yangkb09@users.noreply.github.com>

* Docs: add deprecated warning to restore and version docs

* Fix hyperlink text

* Add swagger endpoints for restore and versions

* Add deprecated tag on swagger for both endpoints

* Fix: Update access control to be dashboards

* Return UID in response; Update docs to reflect this; Implement Ying suggestion

* Update docs/sources/http_api/dashboard_versions.md

Co-authored-by: Sofia Papagiannaki <1632407+papagian@users.noreply.github.com>

* Update pkg/models/dashboard_version.go

Co-authored-by: Sofia Papagiannaki <1632407+papagian@users.noreply.github.com>

* Update pkg/models/dashboard_version.go

Co-authored-by: Sofia Papagiannaki <1632407+papagian@users.noreply.github.com>

* Update query to refer to DashboardUID

Co-authored-by: Ying WANG <ying.wang@grafana.com>
Co-authored-by: Sofia Papagiannaki <sofia@grafana.com>
Co-authored-by: Kat Yang <yangkb09@users.noreply.github.com>
Co-authored-by: Sofia Papagiannaki <1632407+papagian@users.noreply.github.com>
This commit is contained in:
Kat Yang
2022-05-17 12:57:27 -04:00
committed by GitHub
co-authored by Kat Yang Sofia Papagiannaki Ying WANG Sofia Papagiannaki
parent c652849303
commit 719af24235
9 changed files with 409 additions and 22 deletions
+2
View File
@@ -369,6 +369,8 @@ func (hs *HTTPServer) registerRoutes() {
dashboardRoute.Get("/uid/:uid", authorize(reqSignedIn, ac.EvalPermission(dashboards.ActionDashboardsRead)), routing.Wrap(hs.GetDashboard))
dashboardRoute.Delete("/uid/:uid", authorize(reqSignedIn, ac.EvalPermission(dashboards.ActionDashboardsDelete)), routing.Wrap(hs.DeleteDashboardByUID))
dashboardRoute.Group("/uid/:uid", func(dashUidRoute routing.RouteRegister) {
dashUidRoute.Get("/versions", authorize(reqSignedIn, ac.EvalPermission(dashboards.ActionDashboardsWrite)), routing.Wrap(hs.GetDashboardVersions))
dashUidRoute.Post("/restore", authorize(reqSignedIn, ac.EvalPermission(dashboards.ActionDashboardsWrite)), routing.Wrap(hs.RestoreDashboardVersion))
dashUidRoute.Get("/versions/:id", authorize(reqSignedIn, ac.EvalPermission(dashboards.ActionDashboardsWrite)), routing.Wrap(hs.GetDashboardVersion))
dashUidRoute.Group("/permissions", func(dashboardPermissionRoute routing.RouteRegister) {
dashboardPermissionRoute.Get("/", authorize(reqSignedIn, ac.EvalPermission(dashboards.ActionDashboardsPermissionsRead)), routing.Wrap(hs.GetDashboardPermissionList))
+41 -14
View File
@@ -516,21 +516,37 @@ func (hs *HTTPServer) addGettingStartedPanelToHomeDashboard(c *models.ReqContext
// GetDashboardVersions returns all dashboard versions as JSON
func (hs *HTTPServer) GetDashboardVersions(c *models.ReqContext) response.Response {
dashID, err := strconv.ParseInt(web.Params(c.Req)[":dashboardId"], 10, 64)
if err != nil {
return response.Error(http.StatusBadRequest, "dashboardId is invalid", err)
}
var dashID int64
var err error
dashUID := web.Params(c.Req)[":uid"]
if dashUID == "" {
dashID, err = strconv.ParseInt(web.Params(c.Req)[":dashboardId"], 10, 64)
if err != nil {
return response.Error(http.StatusBadRequest, "dashboardId is invalid", err)
}
} else {
q := models.GetDashboardQuery{
OrgId: c.SignedInUser.OrgId,
Uid: dashUID,
}
if err := hs.SQLStore.GetDashboard(c.Req.Context(), &q); err != nil {
return response.Error(http.StatusBadRequest, "failed to get dashboard by UID", err)
}
dashID = q.Result.Id
}
guardian := guardian.New(c.Req.Context(), dashID, c.OrgId, c.SignedInUser)
if canSave, err := guardian.CanSave(); err != nil || !canSave {
return dashboardGuardianResponse(err)
}
query := models.GetDashboardVersionsQuery{
OrgId: c.OrgId,
DashboardId: dashID,
Limit: c.QueryInt("limit"),
Start: c.QueryInt("start"),
OrgId: c.OrgId,
DashboardId: dashID,
DashboardUID: dashUID,
Limit: c.QueryInt("limit"),
Start: c.QueryInt("start"),
}
if err := hs.SQLStore.GetDashboardVersions(c.Req.Context(), &query); err != nil {
@@ -696,26 +712,37 @@ func (hs *HTTPServer) CalculateDashboardDiff(c *models.ReqContext) response.Resp
// RestoreDashboardVersion restores a dashboard to the given version.
func (hs *HTTPServer) RestoreDashboardVersion(c *models.ReqContext) response.Response {
var dashID int64
var err error
dashUID := web.Params(c.Req)[":uid"]
apiCmd := dtos.RestoreDashboardVersionCommand{}
if err := web.Bind(c.Req, &apiCmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
dashboardId, err := strconv.ParseInt(web.Params(c.Req)[":dashboardId"], 10, 64)
if err != nil {
return response.Error(http.StatusBadRequest, "dashboardId is invalid", err)
if dashUID == "" {
dashID, err = strconv.ParseInt(web.Params(c.Req)[":dashboardId"], 10, 64)
if err != nil {
return response.Error(http.StatusBadRequest, "dashboardId is invalid", err)
}
}
dash, rsp := hs.getDashboardHelper(c.Req.Context(), c.OrgId, dashboardId, "")
dash, rsp := hs.getDashboardHelper(c.Req.Context(), c.OrgId, dashID, dashUID)
if rsp != nil {
return rsp
}
guardian := guardian.New(c.Req.Context(), dash.Id, c.OrgId, c.SignedInUser)
if dash != nil && dash.Id != 0 {
dashID = dash.Id
}
guardian := guardian.New(c.Req.Context(), dashID, c.OrgId, c.SignedInUser)
if canSave, err := guardian.CanSave(); err != nil || !canSave {
return dashboardGuardianResponse(err)
}
versionQuery := models.GetDashboardVersionQuery{DashboardId: dash.Id, Version: apiCmd.Version, OrgId: c.OrgId}
versionQuery := models.GetDashboardVersionQuery{DashboardId: dashID, Version: apiCmd.Version, OrgId: c.OrgId}
if err := hs.SQLStore.GetDashboardVersion(c.Req.Context(), &versionQuery); err != nil {
return response.Error(404, "Dashboard version not found", nil)
}
+1 -2
View File
@@ -1064,7 +1064,6 @@ func postDiffScenario(t *testing.T, desc string, url string, routePattern string
func restoreDashboardVersionScenario(t *testing.T, desc string, url string, routePattern string, mock *dashboards.FakeDashboardService, cmd dtos.RestoreDashboardVersionCommand, fn scenarioFunc, sqlStore sqlstore.Store) {
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
cfg := setting.NewCfg()
mockSQLStore := mockstore.NewSQLStoreMock()
hs := HTTPServer{
Cfg: cfg,
ProvisioningService: provisioning.NewProvisioningServiceMock(context.Background()),
@@ -1078,7 +1077,7 @@ func restoreDashboardVersionScenario(t *testing.T, desc string, url string, rout
}
sc := setupScenarioContext(t, url)
sc.sqlStore = mockSQLStore
sc.sqlStore = sqlStore
sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response {
c.Req.Body = mockRequestBody(cmd)
c.Req.Header.Add("Content-Type", "application/json")
+1
View File
@@ -102,6 +102,7 @@ import (
// 500: internalServerError
// swagger:parameters getDashboardByUID deleteDashboardByUID getDashboardPermissionsWithUid postDashboardPermissionsWithUid getDashboardVersionByUID
// swagger:parameters getDashboardVersionsByUID restoreDashboardVersionByUID
type UID struct {
// in:path
// required:true
+42 -2
View File
@@ -1,11 +1,29 @@
package definitions
import "github.com/grafana/grafana/pkg/models"
import (
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/models"
)
// swagger:route GET /dashboards/id/{DashboardID}/versions dashboard_versions getDashboardVersions
//
// Gets all existing versions for the dashboard.
//
// Please refer to [updated API](#/dashboard_versions/getDashboardVersionsByUID) instead
//
// Deprecated: true
//
// Responses:
// 200: dashboardVersionsResponse
// 401: unauthorisedError
// 403: forbiddenError
// 404: notFoundError
// 500: internalServerError
// swagger:route GET /dashboards/uid/{uid}/versions dashboard_versions getDashboardVersionsByUID
//
// Gets all existing versions for the dashboard using UID.
//
// Responses:
// 200: dashboardVersionsResponse
// 401: unauthorisedError
@@ -43,6 +61,21 @@ import "github.com/grafana/grafana/pkg/models"
//
// Restore a dashboard to a given dashboard version.
//
// Please refer to [updated API](#/dashboard_versions/restoreDashboardVersionByUID) instead
//
// Deprecated: true
//
// Responses:
// 200: postDashboardResponse
// 401: unauthorisedError
// 403: forbiddenError
// 404: notFoundError
// 500: internalServerError
// swagger:route POST /dashboards/uid/{uid}/restore dashboard_versions restoreDashboardVersionByUID
//
// Restore a dashboard to a given dashboard version using UID.
//
// Responses:
// 200: postDashboardResponse
// 401: unauthorisedError
@@ -64,7 +97,14 @@ type DashboardVersionIdParam struct {
DashboardVersionID int64
}
// swagger:parameters getDashboardVersions
// swagger:parameters restoreDashboardVersion restoreDashboardVersionByUID
type RestoreVersionBodyParam struct {
// in:body
// required:true
Body dtos.RestoreDashboardVersionCommand
}
// swagger:parameters getDashboardVersions getDashboardVersionsByUID
type GetDashboardVersionsParams struct {
// Maximum number of results to return
// in:query