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:
co-authored by
Kat Yang
Sofia Papagiannaki
Ying WANG
Sofia Papagiannaki
parent
c652849303
commit
719af24235
@@ -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
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user