Dashboards: Add feature restore dashboards backend (#83131)
Co-authored-by: Sofia Papagiannaki <1632407+papagian@users.noreply.github.com>
This commit is contained in:
co-authored by
Sofia Papagiannaki
parent
edae5fc791
commit
42d75ac737
+13
-1
@@ -456,11 +456,23 @@ func (hs *HTTPServer) registerRoutes() {
|
||||
// Dashboard
|
||||
apiRoute.Group("/dashboards", func(dashboardRoute routing.RouteRegister) {
|
||||
dashboardRoute.Get("/uid/:uid", authorize(ac.EvalPermission(dashboards.ActionDashboardsRead)), routing.Wrap(hs.GetDashboard))
|
||||
dashboardRoute.Delete("/uid/:uid", authorize(ac.EvalPermission(dashboards.ActionDashboardsDelete)), routing.Wrap(hs.DeleteDashboardByUID))
|
||||
|
||||
if hs.Features.IsEnabledGlobally(featuremgmt.FlagDashboardRestore) {
|
||||
dashboardRoute.Delete("/uid/:uid", authorize(ac.EvalPermission(dashboards.ActionDashboardsDelete)), routing.Wrap(hs.SoftDeleteDashboard))
|
||||
} else {
|
||||
dashboardRoute.Delete("/uid/:uid", authorize(ac.EvalPermission(dashboards.ActionDashboardsDelete)), routing.Wrap(hs.DeleteDashboardByUID))
|
||||
}
|
||||
|
||||
dashboardRoute.Group("/uid/:uid", func(dashUidRoute routing.RouteRegister) {
|
||||
dashUidRoute.Get("/versions", authorize(ac.EvalPermission(dashboards.ActionDashboardsWrite)), routing.Wrap(hs.GetDashboardVersions))
|
||||
dashUidRoute.Post("/restore", authorize(ac.EvalPermission(dashboards.ActionDashboardsWrite)), routing.Wrap(hs.RestoreDashboardVersion))
|
||||
dashUidRoute.Get("/versions/:id", authorize(ac.EvalPermission(dashboards.ActionDashboardsWrite)), routing.Wrap(hs.GetDashboardVersion))
|
||||
|
||||
if hs.Features.IsEnabledGlobally(featuremgmt.FlagDashboardRestore) {
|
||||
dashUidRoute.Patch("/trash", authorize(ac.EvalPermission(dashboards.ActionDashboardsWrite)), routing.Wrap(hs.RestoreDeletedDashboard))
|
||||
dashUidRoute.Delete("/trash", authorize(ac.EvalPermission(dashboards.ActionDashboardsDelete)), routing.Wrap(hs.HardDeleteDashboardByUID))
|
||||
}
|
||||
|
||||
dashUidRoute.Group("/permissions", func(dashboardPermissionRoute routing.RouteRegister) {
|
||||
dashboardPermissionRoute.Get("/", authorize(ac.EvalPermission(dashboards.ActionDashboardsPermissionsRead)), routing.Wrap(hs.GetDashboardPermissionList))
|
||||
dashboardPermissionRoute.Post("/", authorize(ac.EvalPermission(dashboards.ActionDashboardsPermissionsWrite)), routing.Wrap(hs.UpdateDashboardPermissions))
|
||||
|
||||
+152
-6
@@ -61,6 +61,10 @@ func (hs *HTTPServer) isDashboardStarredByUser(c *contextmodel.ReqContext, dashI
|
||||
|
||||
func dashboardGuardianResponse(err error) response.Response {
|
||||
if err != nil {
|
||||
var dashboardErr dashboards.DashboardErr
|
||||
if ok := errors.As(err, &dashboardErr); ok {
|
||||
return response.Error(dashboardErr.StatusCode, dashboardErr.Error(), err)
|
||||
}
|
||||
return response.Error(http.StatusInternalServerError, "Error while checking dashboard permissions", err)
|
||||
}
|
||||
return response.Error(http.StatusForbidden, "Access denied to this dashboard", nil)
|
||||
@@ -272,6 +276,101 @@ func (hs *HTTPServer) getDashboardHelper(ctx context.Context, orgID int64, id in
|
||||
return queryResult, nil
|
||||
}
|
||||
|
||||
// swagger:route PATCH /dashboards/uid/{uid}/trash dashboards restoreDeletedDashboardByUID
|
||||
//
|
||||
// Restore a dashboard to a given dashboard version using UID.
|
||||
//
|
||||
// Responses:
|
||||
// 200: postDashboardResponse
|
||||
// 400: badRequestError
|
||||
// 401: unauthorisedError
|
||||
// 403: forbiddenError
|
||||
// 404: notFoundError
|
||||
// 500: internalServerError
|
||||
func (hs *HTTPServer) RestoreDeletedDashboard(c *contextmodel.ReqContext) response.Response {
|
||||
uid := web.Params(c.Req)[":uid"]
|
||||
cmd := dashboards.RestoreDeletedDashboardCommand{}
|
||||
|
||||
if err := web.Bind(c.Req, &cmd); err != nil {
|
||||
return response.Error(http.StatusBadRequest, "bad request data", err)
|
||||
}
|
||||
|
||||
dash, err := hs.DashboardService.GetSoftDeletedDashboard(c.Req.Context(), c.SignedInUser.GetOrgID(), uid)
|
||||
if err != nil {
|
||||
return response.Error(http.StatusNotFound, "Dashboard not found", err)
|
||||
}
|
||||
|
||||
guardian, err := guardian.NewByDashboard(c.Req.Context(), dash, c.SignedInUser.GetOrgID(), c.SignedInUser)
|
||||
if err != nil {
|
||||
return response.Err(err)
|
||||
}
|
||||
|
||||
if canRestore, err := guardian.CanSave(); err != nil || !canRestore {
|
||||
return dashboardGuardianResponse(err)
|
||||
}
|
||||
|
||||
err = hs.DashboardService.RestoreDashboard(c.Req.Context(), dash, c.SignedInUser, cmd.FolderUID)
|
||||
if err != nil {
|
||||
var dashboardErr dashboards.DashboardErr
|
||||
if ok := errors.As(err, &dashboardErr); ok {
|
||||
return response.Error(dashboardErr.StatusCode, dashboardErr.Error(), err)
|
||||
}
|
||||
return response.Error(http.StatusInternalServerError, "Dashboard cannot be restored", err)
|
||||
}
|
||||
|
||||
return response.JSON(http.StatusOK, util.DynMap{
|
||||
"title": dash.Title,
|
||||
"message": fmt.Sprintf("Dashboard %s restored", dash.Title),
|
||||
"uid": dash.UID,
|
||||
})
|
||||
}
|
||||
|
||||
// SoftDeleteDashboard swagger:route DELETE /dashboards/uid/{uid} dashboards deleteDashboardByUID
|
||||
//
|
||||
// Delete dashboard by uid.
|
||||
//
|
||||
// Will delete the dashboard given the specified unique identifier (uid).
|
||||
//
|
||||
// Responses:
|
||||
// 200: deleteDashboardResponse
|
||||
// 401: unauthorisedError
|
||||
// 403: forbiddenError
|
||||
// 404: notFoundError
|
||||
// 500: internalServerError
|
||||
func (hs *HTTPServer) SoftDeleteDashboard(c *contextmodel.ReqContext) response.Response {
|
||||
uid := web.Params(c.Req)[":uid"]
|
||||
dash, rsp := hs.getDashboardHelper(c.Req.Context(), c.SignedInUser.GetOrgID(), 0, uid)
|
||||
if rsp != nil {
|
||||
return rsp
|
||||
}
|
||||
|
||||
guardian, err := guardian.NewByDashboard(c.Req.Context(), dash, c.SignedInUser.GetOrgID(), c.SignedInUser)
|
||||
if err != nil {
|
||||
return response.Err(err)
|
||||
}
|
||||
|
||||
if canDelete, err := guardian.CanDelete(); err != nil || !canDelete {
|
||||
return dashboardGuardianResponse(err)
|
||||
}
|
||||
|
||||
err = hs.DashboardService.SoftDeleteDashboard(c.Req.Context(), c.SignedInUser.GetOrgID(), uid)
|
||||
if err != nil {
|
||||
var dashboardErr dashboards.DashboardErr
|
||||
if ok := errors.As(err, &dashboardErr); ok {
|
||||
if errors.Is(err, dashboards.ErrDashboardCannotDeleteProvisionedDashboard) {
|
||||
return response.Error(dashboardErr.StatusCode, dashboardErr.Error(), err)
|
||||
}
|
||||
}
|
||||
return response.Error(http.StatusInternalServerError, "Failed to delete dashboard", err)
|
||||
}
|
||||
|
||||
return response.JSON(http.StatusOK, util.DynMap{
|
||||
"title": dash.Title,
|
||||
"message": fmt.Sprintf("Dashboard %s moved to trash", dash.Title),
|
||||
"uid": dash.UID,
|
||||
})
|
||||
}
|
||||
|
||||
// DeleteDashboardByUID swagger:route DELETE /dashboards/uid/{uid} dashboards deleteDashboardByUID
|
||||
//
|
||||
// Delete dashboard by uid.
|
||||
@@ -288,11 +387,40 @@ func (hs *HTTPServer) DeleteDashboardByUID(c *contextmodel.ReqContext) response.
|
||||
return hs.deleteDashboard(c)
|
||||
}
|
||||
|
||||
// HardDeleteDashboardByUID swagger:route DELETE /dashboards/uid/{uid}/trash dashboards hardDeleteDashboardByUID
|
||||
//
|
||||
// Hard delete dashboard by uid.
|
||||
//
|
||||
// Will delete the dashboard given the specified unique identifier (uid).
|
||||
//
|
||||
// Responses:
|
||||
// 200: deleteDashboardResponse
|
||||
// 401: unauthorisedError
|
||||
// 403: forbiddenError
|
||||
// 404: notFoundError
|
||||
// 500: internalServerError
|
||||
func (hs *HTTPServer) HardDeleteDashboardByUID(c *contextmodel.ReqContext) response.Response {
|
||||
return hs.deleteDashboard(c)
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) deleteDashboard(c *contextmodel.ReqContext) response.Response {
|
||||
dash, rsp := hs.getDashboardHelper(c.Req.Context(), c.SignedInUser.GetOrgID(), 0, web.Params(c.Req)[":uid"])
|
||||
if rsp != nil {
|
||||
return rsp
|
||||
uid := web.Params(c.Req)[":uid"]
|
||||
|
||||
var dash *dashboards.Dashboard
|
||||
if hs.Features.IsEnabledGlobally(featuremgmt.FlagDashboardRestore) {
|
||||
var err error
|
||||
dash, err = hs.DashboardService.GetSoftDeletedDashboard(c.Req.Context(), c.SignedInUser.GetOrgID(), uid)
|
||||
if err != nil {
|
||||
return response.Error(http.StatusNotFound, "Dashboard not found", err)
|
||||
}
|
||||
} else {
|
||||
var rsp response.Response
|
||||
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.SignedInUser.GetOrgID(), c.SignedInUser)
|
||||
if err != nil {
|
||||
return response.Err(err)
|
||||
@@ -346,7 +474,7 @@ func (hs *HTTPServer) deleteDashboard(c *contextmodel.ReqContext) response.Respo
|
||||
return response.JSON(http.StatusOK, util.DynMap{
|
||||
"title": dash.Title,
|
||||
"message": fmt.Sprintf("Dashboard %s deleted", dash.Title),
|
||||
"id": dash.ID,
|
||||
"uid": dash.UID,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1098,6 +1226,13 @@ type DeleteDashboardByUIDParams struct {
|
||||
UID string `json:"uid"`
|
||||
}
|
||||
|
||||
// swagger:parameters hardDeleteDashboardByUID
|
||||
type HardDeleteDashboardByUIDParams struct {
|
||||
// in:path
|
||||
// required:true
|
||||
UID string `json:"uid"`
|
||||
}
|
||||
|
||||
// swagger:parameters postDashboard
|
||||
type PostDashboardParams struct {
|
||||
// in:body
|
||||
@@ -1133,10 +1268,10 @@ type DeleteDashboardResponse struct {
|
||||
// The response message
|
||||
// in: body
|
||||
Body struct {
|
||||
// ID Identifier of the deleted dashboard.
|
||||
// UID Identifier of the deleted dashboard.
|
||||
// required: true
|
||||
// example: 65
|
||||
ID int64 `json:"id"`
|
||||
UID string `json:"uid"`
|
||||
|
||||
// Title Title of the deleted dashboard.
|
||||
// required: true
|
||||
@@ -1231,3 +1366,14 @@ type DashboardVersionResponse struct {
|
||||
// in: body
|
||||
Body *dashver.DashboardVersionMeta `json:"body"`
|
||||
}
|
||||
|
||||
// swagger:parameters restoreDeletedDashboardByUID
|
||||
type RestoreDeletedDashboardByUID struct {
|
||||
// in:path
|
||||
// required:true
|
||||
UID string `json:"uid"`
|
||||
|
||||
// in:body
|
||||
// required:true
|
||||
Body dashboards.RestoreDeletedDashboardCommand
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ func (hs *HTTPServer) Search(c *contextmodel.ReqContext) response.Response {
|
||||
page := c.QueryInt64("page")
|
||||
dashboardType := c.Query("type")
|
||||
sort := c.Query("sort")
|
||||
deleted := c.Query("deleted")
|
||||
permission := dashboardaccess.PERMISSION_VIEW
|
||||
|
||||
if limit > 5000 {
|
||||
@@ -77,6 +78,7 @@ func (hs *HTTPServer) Search(c *contextmodel.ReqContext) response.Response {
|
||||
Limit: limit,
|
||||
Page: page,
|
||||
IsStarred: starred == "true",
|
||||
IsDeleted: deleted == "true",
|
||||
OrgId: c.SignedInUser.GetOrgID(),
|
||||
DashboardIds: dbIDs,
|
||||
DashboardUIDs: dbUIDs,
|
||||
@@ -190,6 +192,10 @@ type SearchParams struct {
|
||||
// default: alpha-asc
|
||||
// Enum: alpha-asc,alpha-desc
|
||||
Sort string `json:"sort"`
|
||||
// Flag indicating if only soft deleted Dashboards should be returned
|
||||
// in:query
|
||||
// required: false
|
||||
Deleted bool `json:"deleted"`
|
||||
}
|
||||
|
||||
// swagger:response searchResponse
|
||||
|
||||
Reference in New Issue
Block a user