Chore: Remove endpoints that contain the slug field (#35104)

* Chore: Remove endpoints that contain the slug field

* More cleanups

* Lint fixes

* Remove unnecessary funcs

* Cleanup frontend code

* Remove deprecated endpoints from docs

* Revert change according to reviewer's comments
This commit is contained in:
Dimitris Sotirakis 2021-06-03 16:20:13 +03:00 committed by GitHub
parent aa4c5bbfe4
commit 1c49986b2f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 7 additions and 467 deletions

View File

@ -439,105 +439,3 @@ Content-Type: application/json
## Dashboard Search
See [Folder/Dashboard Search API]({{< relref "folder_dashboard_search.md" >}}).
## Deprecated resources
Please note that these resource have been deprecated and will be removed in a future release.
### Get dashboard by slug
**Deprecated starting from Grafana v5.0. Please update to use the new *Get dashboard by uid* resource instead**
`GET /api/dashboards/db/:slug`
Will return the dashboard given the dashboard slug. Slug is the URL friendly version of the dashboard title.
If there exists multiple dashboards with the same slug, one of them will be returned in the response.
**Example Request**:
```http
GET /api/dashboards/db/production-overview HTTP/1.1
Accept: application/json
Content-Type: application/json
Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
```
**Example Response**:
```http
HTTP/1.1 200
Content-Type: application/json
{
"dashboard": {
"id": 1,
"uid": "cIBgcSjkk",
"title": "Production Overview",
"tags": [ "templated" ],
"timezone": "browser",
"schemaVersion": 16,
"version": 0
},
"meta": {
"isStarred": false,
"url": "/d/cIBgcSjkk/production-overview",
"slug": "production-overview" // deprecated in Grafana v5.0
}
}
```
Status Codes:
- **200** Found
- **401** Unauthorized
- **403** Access denied
- **404** Not found
### Delete dashboard by slug
**Deprecated starting from Grafana v5.0. Please update to use the *Delete dashboard by uid* resource instead.**
`DELETE /api/dashboards/db/:slug`
Will delete the dashboard given the specified slug. Slug is the URL friendly version of the dashboard title.
**Example Request**:
```http
DELETE /api/dashboards/db/test HTTP/1.1
Accept: application/json
Content-Type: application/json
Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
```
**Example Response**:
```http
HTTP/1.1 200
Content-Type: application/json
{
"title": "Production Overview",
"message": "Dashboard Production Overview deleted",
"id": 2
}
```
Status Codes:
- **200** Deleted
- **401** Unauthorized
- **403** Access denied
- **404** Not found
- **412** Precondition failed
The **412** status code is used when there exists multiple dashboards with the same slug.
The response body will look like this:
```http
HTTP/1.1 412 Precondition Failed
Content-Type: application/json; charset=UTF-8
Content-Length: 97
{
"message": "Multiple dashboards with the same slug exists",
"status": "multiple-slugs-exists"
}
```

View File

@ -29,8 +29,6 @@ func (hs *HTTPServer) registerRoutes() {
reqOrgAdmin := middleware.ReqOrgAdmin
reqCanAccessTeams := middleware.AdminOrFeatureEnabled(hs.Cfg.EditorsCanAdmin)
reqSnapshotPublicModeOrSignedIn := middleware.SnapshotPublicModeOrSignedIn(hs.Cfg)
redirectFromLegacyDashboardURL := middleware.RedirectFromLegacyDashboardURL()
redirectFromLegacyDashboardSoloURL := middleware.RedirectFromLegacyDashboardSoloURL(hs.Cfg)
redirectFromLegacyPanelEditURL := middleware.RedirectFromLegacyPanelEditURL(hs.Cfg)
authorize := acmiddleware.Middleware(hs.AccessControl)
quota := middleware.Quota(hs.QuotaService)
@ -84,13 +82,11 @@ func (hs *HTTPServer) registerRoutes() {
r.Get("/d/:uid/:slug", reqSignedIn, redirectFromLegacyPanelEditURL, hs.Index)
r.Get("/d/:uid", reqSignedIn, redirectFromLegacyPanelEditURL, hs.Index)
r.Get("/dashboard/db/:slug", reqSignedIn, redirectFromLegacyDashboardURL, hs.Index)
r.Get("/dashboard/script/*", reqSignedIn, hs.Index)
r.Get("/dashboard/new", reqSignedIn, hs.Index)
r.Get("/dashboard-solo/snapshot/*", hs.Index)
r.Get("/d-solo/:uid/:slug", reqSignedIn, hs.Index)
r.Get("/d-solo/:uid", reqSignedIn, hs.Index)
r.Get("/dashboard-solo/db/:slug", reqSignedIn, redirectFromLegacyDashboardSoloURL, hs.Index)
r.Get("/dashboard-solo/script/*", reqSignedIn, hs.Index)
r.Get("/import/dashboard", reqSignedIn, hs.Index)
r.Get("/dashboards/", reqSignedIn, hs.Index)
@ -327,9 +323,6 @@ func (hs *HTTPServer) registerRoutes() {
dashboardRoute.Get("/uid/:uid", routing.Wrap(hs.GetDashboard))
dashboardRoute.Delete("/uid/:uid", routing.Wrap(hs.DeleteDashboardByUID))
dashboardRoute.Get("/db/:slug", routing.Wrap(hs.GetDashboard))
dashboardRoute.Delete("/db/:slug", routing.Wrap(hs.DeleteDashboardBySlug))
dashboardRoute.Post("/calculate-diff", bind(dtos.CalculateDiffOptions{}), routing.Wrap(CalculateDashboardDiff))
dashboardRoute.Post("/trim", bind(models.TrimDashboardCommand{}), routing.Wrap(hs.TrimDashboard))

View File

@ -69,9 +69,8 @@ func (hs *HTTPServer) TrimDashboard(c *models.ReqContext, cmd models.TrimDashboa
}
func (hs *HTTPServer) GetDashboard(c *models.ReqContext) response.Response {
slug := c.Params(":slug")
uid := c.Params(":uid")
dash, rsp := getDashboardHelper(c.OrgId, slug, 0, uid)
dash, rsp := getDashboardHelper(c.OrgId, 0, uid)
if rsp != nil {
return rsp
}
@ -197,13 +196,13 @@ func getUserLogin(userID int64) string {
return query.Result.Login
}
func getDashboardHelper(orgID int64, slug string, id int64, uid string) (*models.Dashboard, response.Response) {
func getDashboardHelper(orgID int64, id int64, uid string) (*models.Dashboard, response.Response) {
var query models.GetDashboardQuery
if len(uid) > 0 {
query = models.GetDashboardQuery{Uid: uid, Id: id, OrgId: orgID}
} else {
query = models.GetDashboardQuery{Slug: slug, Id: id, OrgId: orgID}
query = models.GetDashboardQuery{Id: id, OrgId: orgID}
}
if err := bus.Dispatch(&query); err != nil {
@ -232,7 +231,7 @@ func (hs *HTTPServer) DeleteDashboardByUID(c *models.ReqContext) response.Respon
}
func (hs *HTTPServer) deleteDashboard(c *models.ReqContext) response.Response {
dash, rsp := getDashboardHelper(c.OrgId, c.Params(":slug"), 0, c.Params(":uid"))
dash, rsp := getDashboardHelper(c.OrgId, 0, c.Params(":uid"))
if rsp != nil {
return rsp
}
@ -626,7 +625,7 @@ func CalculateDashboardDiff(c *models.ReqContext, apiOptions dtos.CalculateDiffO
// RestoreDashboardVersion restores a dashboard to the given version.
func (hs *HTTPServer) RestoreDashboardVersion(c *models.ReqContext, apiCmd dtos.RestoreDashboardVersionCommand) response.Response {
dash, rsp := getDashboardHelper(c.OrgId, "", c.ParamsInt64(":dashboardId"), "")
dash, rsp := getDashboardHelper(c.OrgId, c.ParamsInt64(":dashboardId"), "")
if rsp != nil {
return rsp
}

View File

@ -13,7 +13,7 @@ import (
func (hs *HTTPServer) GetDashboardPermissionList(c *models.ReqContext) response.Response {
dashID := c.ParamsInt64(":dashboardId")
_, rsp := getDashboardHelper(c.OrgId, "", dashID, "")
_, rsp := getDashboardHelper(c.OrgId, dashID, "")
if rsp != nil {
return rsp
}
@ -57,7 +57,7 @@ func (hs *HTTPServer) UpdateDashboardPermissions(c *models.ReqContext, apiCmd dt
dashID := c.ParamsInt64(":dashboardId")
_, rsp := getDashboardHelper(c.OrgId, "", dashID, "")
_, rsp := getDashboardHelper(c.OrgId, dashID, "")
if rsp != nil {
return rsp
}

View File

@ -144,19 +144,6 @@ func TestDashboardAPIEndpoint(t *testing.T) {
t.Run("When user is an Org Viewer", func(t *testing.T) {
role := models.ROLE_VIEWER
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/db/child-dash",
"/api/dashboards/db/:slug", role, func(sc *scenarioContext) {
state := setUp()
dash := getDashboardShouldReturn200(sc)
assert.Equal(t, "child-dash", state.dashQueries[0].Slug)
assert.False(t, dash.Meta.CanEdit)
assert.False(t, dash.Meta.CanSave)
assert.False(t, dash.Meta.CanAdmin)
})
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi",
"/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
state := setUp()
@ -170,20 +157,6 @@ func TestDashboardAPIEndpoint(t *testing.T) {
assert.False(t, dash.Meta.CanAdmin)
})
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/db/child-dash",
"/api/dashboards/db/:slug", role, func(sc *scenarioContext) {
state := setUp()
callDeleteDashboardBySlug(sc, &HTTPServer{
Cfg: setting.NewCfg(),
LibraryPanelService: &mockLibraryPanelService{},
LibraryElementService: &mockLibraryElementService{},
})
assert.Equal(t, 403, sc.resp.Code)
assert.Equal(t, "child-dash", state.dashQueries[0].Slug)
})
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi",
"/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
state := setUp()
@ -218,19 +191,6 @@ func TestDashboardAPIEndpoint(t *testing.T) {
t.Run("When user is an Org Editor", func(t *testing.T) {
role := models.ROLE_EDITOR
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/db/child-dash",
"/api/dashboards/db/:slug", role, func(sc *scenarioContext) {
state := setUp()
dash := getDashboardShouldReturn200(sc)
assert.Equal(t, "child-dash", state.dashQueries[0].Slug)
assert.True(t, dash.Meta.CanEdit)
assert.True(t, dash.Meta.CanSave)
assert.False(t, dash.Meta.CanAdmin)
})
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi",
"/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
state := setUp()
@ -243,19 +203,6 @@ func TestDashboardAPIEndpoint(t *testing.T) {
assert.False(t, dash.Meta.CanAdmin)
})
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/db/child-dash",
"/api/dashboards/db/:slug", role, func(sc *scenarioContext) {
state := setUp()
callDeleteDashboardBySlug(sc, &HTTPServer{
Cfg: setting.NewCfg(),
LibraryPanelService: &mockLibraryPanelService{},
LibraryElementService: &mockLibraryElementService{},
})
assert.Equal(t, 200, sc.resp.Code)
assert.Equal(t, "child-dash", state.dashQueries[0].Slug)
})
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi",
"/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
state := setUp()
@ -353,16 +300,6 @@ func TestDashboardAPIEndpoint(t *testing.T) {
t.Run("When user is an Org Viewer and has no permissions for this dashboard", func(t *testing.T) {
role := models.ROLE_VIEWER
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/db/child-dash",
"/api/dashboards/db/:slug", role, func(sc *scenarioContext) {
state := setUp()
sc.handlerFunc = hs.GetDashboard
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
assert.Equal(t, "child-dash", state.dashQueries[0].Slug)
assert.Equal(t, 403, sc.resp.Code)
})
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi",
"/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
state := setUp()
@ -373,15 +310,6 @@ func TestDashboardAPIEndpoint(t *testing.T) {
assert.Equal(t, 403, sc.resp.Code)
})
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/db/child-dash",
"/api/dashboards/db/:slug", role, func(sc *scenarioContext) {
state := setUp()
callDeleteDashboardBySlug(sc, hs)
assert.Equal(t, 403, sc.resp.Code)
assert.Equal(t, "child-dash", state.dashQueries[0].Slug)
})
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi",
"/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
state := setUp()
@ -411,17 +339,6 @@ func TestDashboardAPIEndpoint(t *testing.T) {
t.Run("When user is an Org Editor and has no permissions for this dashboard", func(t *testing.T) {
role := models.ROLE_EDITOR
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/db/child-dash",
"/api/dashboards/db/:slug", role, func(sc *scenarioContext) {
state := setUp()
sc.handlerFunc = hs.GetDashboard
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
assert.Equal(t, "child-dash", state.dashQueries[0].Slug)
assert.Equal(t, 403, sc.resp.Code)
})
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi",
"/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
state := setUp()
@ -433,15 +350,6 @@ func TestDashboardAPIEndpoint(t *testing.T) {
assert.Equal(t, 403, sc.resp.Code)
})
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/db/child-dash",
"/api/dashboards/db/:slug", role, func(sc *scenarioContext) {
state := setUp()
callDeleteDashboardBySlug(sc, hs)
assert.Equal(t, 403, sc.resp.Code)
assert.Equal(t, "child-dash", state.dashQueries[0].Slug)
})
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi",
"/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
state := setUp()
@ -484,22 +392,6 @@ func TestDashboardAPIEndpoint(t *testing.T) {
return state
}
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/db/child-dash",
"/api/dashboards/db/:slug", role, func(sc *scenarioContext) {
state := setUpInner()
bus.AddHandler("test", func(query *models.GetDashboardAclInfoListQuery) error {
query.Result = mockResult
return nil
})
dash := getDashboardShouldReturn200(sc)
assert.Equal(t, "child-dash", state.dashQueries[0].Slug)
assert.True(t, dash.Meta.CanEdit)
assert.True(t, dash.Meta.CanSave)
assert.False(t, dash.Meta.CanAdmin)
})
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi",
"/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
state := setUpInner()
@ -512,14 +404,6 @@ func TestDashboardAPIEndpoint(t *testing.T) {
assert.False(t, dash.Meta.CanAdmin)
})
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/db/child-dash", "/api/dashboards/db/:slug", role, func(sc *scenarioContext) {
state := setUpInner()
callDeleteDashboardBySlug(sc, hs)
assert.Equal(t, 200, sc.resp.Code)
assert.Equal(t, "child-dash", state.dashQueries[0].Slug)
})
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
state := setUpInner()
@ -567,17 +451,6 @@ func TestDashboardAPIEndpoint(t *testing.T) {
return state
}
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/db/child-dash", "/api/dashboards/db/:slug", role, func(sc *scenarioContext) {
state := setUpInner()
dash := getDashboardShouldReturn200(sc)
assert.Equal(t, "child-dash", state.dashQueries[0].Slug)
assert.True(t, dash.Meta.CanEdit)
assert.False(t, dash.Meta.CanSave)
assert.False(t, dash.Meta.CanAdmin)
})
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
state := setUpInner()
@ -590,14 +463,6 @@ func TestDashboardAPIEndpoint(t *testing.T) {
assert.False(t, dash.Meta.CanAdmin)
})
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/db/child-dash", "/api/dashboards/db/:slug", role, func(sc *scenarioContext) {
state := setUpInner()
callDeleteDashboardBySlug(sc, hs)
assert.Equal(t, 403, sc.resp.Code)
assert.Equal(t, "child-dash", state.dashQueries[0].Slug)
})
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
state := setUpInner()
@ -623,16 +488,6 @@ func TestDashboardAPIEndpoint(t *testing.T) {
return state
}
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/db/child-dash", "/api/dashboards/db/:slug", role, func(sc *scenarioContext) {
state := setUpInner()
dash := getDashboardShouldReturn200(sc)
assert.Equal(t, "child-dash", state.dashQueries[0].Slug)
assert.True(t, dash.Meta.CanEdit)
assert.True(t, dash.Meta.CanSave)
assert.True(t, dash.Meta.CanAdmin)
})
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
state := setUpInner()
@ -644,14 +499,6 @@ func TestDashboardAPIEndpoint(t *testing.T) {
assert.True(t, dash.Meta.CanAdmin)
})
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/db/child-dash", "/api/dashboards/db/:slug", role, func(sc *scenarioContext) {
state := setUpInner()
callDeleteDashboardBySlug(sc, hs)
assert.Equal(t, 200, sc.resp.Code)
assert.Equal(t, "child-dash", state.dashQueries[0].Slug)
})
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
state := setUpInner()
@ -691,16 +538,6 @@ func TestDashboardAPIEndpoint(t *testing.T) {
return state
}
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/db/child-dash", "/api/dashboards/db/:slug", role, func(sc *scenarioContext) {
state := setUpInner()
dash := getDashboardShouldReturn200(sc)
assert.Equal(t, "child-dash", state.dashQueries[0].Slug)
assert.False(t, dash.Meta.CanEdit)
assert.False(t, dash.Meta.CanSave)
})
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
state := setUpInner()
@ -710,14 +547,6 @@ func TestDashboardAPIEndpoint(t *testing.T) {
assert.False(t, dash.Meta.CanSave)
})
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/db/child-dash", "/api/dashboards/db/:slug", role, func(sc *scenarioContext) {
state := setUpInner()
callDeleteDashboardBySlug(sc, hs)
assert.Equal(t, 403, sc.resp.Code)
assert.Equal(t, "child-dash", state.dashQueries[0].Slug)
})
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
state := setUpInner()
@ -758,18 +587,6 @@ func TestDashboardAPIEndpoint(t *testing.T) {
query.Result = dashboards
return nil
})
role := models.ROLE_EDITOR
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/db/dash",
"/api/dashboards/db/:slug", role, func(sc *scenarioContext) {
callDeleteDashboardBySlug(sc, &HTTPServer{Cfg: setting.NewCfg()})
assert.Equal(t, 412, sc.resp.Code)
result := sc.ToJSON()
assert.Equal(t, "multiple-slugs-exists", result.Get("status").MustString())
assert.Equal(t, models.ErrDashboardsWithSameSlugExists.Error(), result.Get("message").MustString())
})
})
t.Run("Post dashboard response tests", func(t *testing.T) {
@ -1132,21 +949,6 @@ func TestDashboardAPIEndpoint(t *testing.T) {
})
}
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/db/dash",
"/api/dashboards/db/:slug", models.ROLE_EDITOR, func(sc *scenarioContext) {
setUp()
callDeleteDashboardBySlug(sc, &HTTPServer{
Cfg: setting.NewCfg(),
LibraryPanelService: &mockLibraryPanelService{},
LibraryElementService: &mockLibraryElementService{},
})
assert.Equal(t, 400, sc.resp.Code)
result := sc.ToJSON()
assert.Equal(t, models.ErrDashboardCannotDeleteProvisionedDashboard.Error(), result.Get("error").MustString())
})
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/db/abcdefghi", "/api/dashboards/db/:uid", models.ROLE_EDITOR, func(sc *scenarioContext) {
setUp()

View File

@ -4,35 +4,10 @@ import (
"fmt"
"strings"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/setting"
)
func getDashboardURLBySlug(orgID int64, slug string) (string, error) {
// TODO: Drop bus call
query := models.GetDashboardQuery{Slug: slug, OrgId: orgID}
if err := bus.Dispatch(&query); err != nil {
return "", models.ErrDashboardNotFound
}
return models.GetDashboardUrl(query.Result.Uid, query.Result.Slug), nil
}
func RedirectFromLegacyDashboardURL() func(c *models.ReqContext) {
return func(c *models.ReqContext) {
slug := c.Params("slug")
if slug != "" {
if url, err := getDashboardURLBySlug(c.OrgId, slug); err == nil {
url = fmt.Sprintf("%s?%s", url, c.Req.URL.RawQuery)
c.Redirect(url, 301)
return
}
}
}
}
// In Grafana v7.0 we changed panel edit & view query parameters.
// This middleware tries to detect those old url parameters and direct to the new url query params
func RedirectFromLegacyPanelEditURL(cfg *setting.Cfg) func(c *models.ReqContext) {
@ -59,26 +34,3 @@ func RedirectFromLegacyPanelEditURL(cfg *setting.Cfg) func(c *models.ReqContext)
}
}
}
func RedirectFromLegacyDashboardSoloURL(cfg *setting.Cfg) func(c *models.ReqContext) {
return func(c *models.ReqContext) {
slug := c.Params("slug")
renderRequest := c.QueryBool("render")
if slug != "" {
url, err := getDashboardURLBySlug(c.OrgId, slug)
if err != nil {
return
}
if renderRequest && strings.Contains(url, cfg.AppSubURL) {
url = strings.Replace(url, cfg.AppSubURL, "", 1)
}
url = strings.Replace(url, "/d/", "/d-solo/", 1)
url = fmt.Sprintf("%s?%s", url, c.Req.URL.RawQuery)
c.Redirect(url, 301)
return
}
}
}

View File

@ -1,81 +1,12 @@
package middleware
import (
"strings"
"testing"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/util"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestMiddlewareDashboardRedirect(t *testing.T) {
bus.ClearBusHandlers()
fakeDash := models.NewDashboard("Child dash")
fakeDash.Id = 1
fakeDash.FolderId = 1
fakeDash.HasAcl = false
fakeDash.Uid = util.GenerateShortUID()
middlewareScenario(t, "GET dashboard by legacy url", func(t *testing.T, sc *scenarioContext) {
redirectFromLegacyDashboardURL := RedirectFromLegacyDashboardURL()
bus.AddHandler("test", func(query *models.GetDashboardQuery) error {
t.Log("Returning fake dashboard")
query.Result = fakeDash
return nil
})
sc.handlerFunc = redirectFromLegacyDashboardURL
sc.m.Get("/dashboard/db/:slug", sc.defaultHandler)
sc.fakeReqWithParams("GET", "/dashboard/db/dash?orgId=1&panelId=2", map[string]string{}).exec()
assert.Equal(t, 301, sc.resp.Code)
// nolint:bodyclose
resp := sc.resp.Result()
t.Cleanup(func() {
err := resp.Body.Close()
assert.NoError(t, err)
})
redirectURL, err := resp.Location()
require.NoError(t, err)
assert.Equal(t, models.GetDashboardUrl(fakeDash.Uid, fakeDash.Slug), redirectURL.Path)
assert.Len(t, redirectURL.Query(), 2)
})
middlewareScenario(t, "GET dashboard solo by legacy url", func(t *testing.T, sc *scenarioContext) {
redirectFromLegacyDashboardSoloURL := RedirectFromLegacyDashboardSoloURL(sc.cfg)
bus.AddHandler("test", func(query *models.GetDashboardQuery) error {
t.Log("Returning fake dashboard")
query.Result = fakeDash
return nil
})
sc.handlerFunc = redirectFromLegacyDashboardSoloURL
sc.m.Get("/dashboard-solo/db/:slug", sc.defaultHandler)
sc.fakeReqWithParams("GET", "/dashboard-solo/db/dash?orgId=1&panelId=2", map[string]string{}).exec()
require.Equal(t, 301, sc.resp.Code)
// nolint:bodyclose
resp := sc.resp.Result()
t.Cleanup(func() {
err := resp.Body.Close()
assert.NoError(t, err)
})
redirectURL, err := resp.Location()
require.NoError(t, err)
// XXX: Should this be called path??
expectedURL := models.GetDashboardUrl(fakeDash.Uid, fakeDash.Slug)
expectedURL = strings.Replace(expectedURL, "/d/", "/d-solo/", 1)
assert.Equal(t, expectedURL, redirectURL.Path)
assert.Len(t, redirectURL.Query(), 2)
})
}
func TestMiddlewareDashboardRedirect_legacyEditPanel(t *testing.T) {
middlewareScenario(t, "GET dashboard by legacy edit URL", func(t *testing.T, sc *scenarioContext) {
sc.handlerFunc = RedirectFromLegacyPanelEditURL(sc.cfg)

View File

@ -403,10 +403,6 @@ export class BackendSrv implements BackendService {
return this.get('/api/search', query);
}
getDashboardBySlug(slug: string) {
return this.get(`/api/dashboards/db/${slug}`);
}
getDashboardByUid(uid: string) {
return this.get(`/api/dashboards/uid/${uid}`);
}

View File

@ -34,23 +34,6 @@ export interface InitDashboardArgs {
fixUrl: boolean;
}
async function redirectToNewUrl(slug: string) {
const res = await backendSrv.getDashboardBySlug(slug);
if (res) {
const location = locationService.getLocation();
let newUrl = res.meta.url;
// fix solo route urls
if (location.pathname.indexOf('dashboard-solo') !== -1) {
newUrl = newUrl.replace('/d/', '/d-solo/');
}
const url = locationUtil.stripBaseFromUrl(newUrl);
locationService.replace(url);
}
}
async function fetchDashboard(
args: InitDashboardArgs,
dispatch: ThunkDispatch,
@ -76,12 +59,6 @@ async function fetchDashboard(
return dashDTO;
}
case DashboardRoutes.Normal: {
// for old db routes we redirect
if (args.urlType === 'db') {
redirectToNewUrl(args.urlSlug!);
return null;
}
const dashDTO: DashboardDTO = await dashboardLoaderSrv.loadDashboard(args.urlType, args.urlSlug, args.urlUid);
if (args.fixUrl && dashDTO.meta.url) {

View File

@ -64,14 +64,6 @@ export function getAppRoutes(): RouteDescriptor[] {
() => import(/* webpackChunkName: "SoloPanelPage" */ '../features/dashboard/containers/SoloPanelPage')
),
},
{
path: '/dashboard-solo/:type/:slug',
pageClass: 'dashboard-solo',
routeName: DashboardRoutes.Normal,
component: SafeDynamicImport(
() => import(/* webpackChunkName: "SoloPanelPage" */ '../features/dashboard/containers/SoloPanelPage')
),
},
{
path: '/dashboard/import',
component: SafeDynamicImport(