Browse Source

dashboards: add validation to delete dashboard by slug

Validates that there are only one folder/dashboard having that slug,
otherwise returns 412 Precondition Failed
Marcus Efraimsson 8 years ago
parent
commit
b23560ed5a
4 changed files with 73 additions and 1 deletions
  1. 10 0
      pkg/api/dashboard.go
  2. 43 0
      pkg/api/dashboard_test.go
  3. 9 1
      pkg/models/dashboards.go
  4. 11 0
      pkg/services/sqlstore/dashboard.go

+ 10 - 0
pkg/api/dashboard.go

@@ -146,6 +146,16 @@ func getDashboardHelper(orgId int64, slug string, id int64, uid string) (*m.Dash
 }
 
 func DeleteDashboard(c *middleware.Context) Response {
+	query := m.GetDashboardsBySlugQuery{OrgId: c.OrgId, Slug: c.Params(":slug")}
+
+	if err := bus.Dispatch(&query); err != nil {
+		return ApiError(500, "Failed to retrieve dashboards by slug", err)
+	}
+
+	if len(query.Result) > 1 {
+		return Json(412, util.DynMap{"status": "multiple-slugs-exists", "message": m.ErrDashboardsWithSameSlugExists.Error()})
+	}
+
 	dash, rsp := getDashboardHelper(c.OrgId, c.Params(":slug"), 0, "")
 	if rsp != nil {
 		return rsp

+ 43 - 0
pkg/api/dashboard_test.go

@@ -39,6 +39,12 @@ func TestDashboardApiEndpoint(t *testing.T) {
 		fakeDash.FolderId = 1
 		fakeDash.HasAcl = false
 
+		bus.AddHandler("test", func(query *m.GetDashboardsBySlugQuery) error {
+			dashboards := []*m.Dashboard{fakeDash}
+			query.Result = dashboards
+			return nil
+		})
+
 		var getDashboardQueries []*m.GetDashboardQuery
 
 		bus.AddHandler("test", func(query *m.GetDashboardQuery) error {
@@ -232,6 +238,12 @@ func TestDashboardApiEndpoint(t *testing.T) {
 		fakeDash.HasAcl = true
 		setting.ViewersCanEdit = false
 
+		bus.AddHandler("test", func(query *m.GetDashboardsBySlugQuery) error {
+			dashboards := []*m.Dashboard{fakeDash}
+			query.Result = dashboards
+			return nil
+		})
+
 		aclMockResp := []*m.DashboardAclInfoDTO{
 			{
 				DashboardId: 1,
@@ -671,6 +683,37 @@ func TestDashboardApiEndpoint(t *testing.T) {
 			})
 		})
 	})
+
+	Convey("Given two dashboards with the same title in different folders", t, func() {
+		dashOne := m.NewDashboard("dash")
+		dashOne.Id = 2
+		dashOne.FolderId = 1
+		dashOne.HasAcl = false
+
+		dashTwo := m.NewDashboard("dash")
+		dashTwo.Id = 4
+		dashTwo.FolderId = 3
+		dashTwo.HasAcl = false
+
+		bus.AddHandler("test", func(query *m.GetDashboardsBySlugQuery) error {
+			dashboards := []*m.Dashboard{dashOne, dashTwo}
+			query.Result = dashboards
+			return nil
+		})
+
+		role := m.ROLE_EDITOR
+
+		loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/db/dash", "/api/dashboards/db/:slug", role, func(sc *scenarioContext) {
+			CallDeleteDashboard(sc)
+
+			Convey("Should result in 412 Precondition failed", func() {
+				So(sc.resp.Code, ShouldEqual, 412)
+				result := sc.ToJson()
+				So(result.Get("status").MustString(), ShouldEqual, "multiple-slugs-exists")
+				So(result.Get("message").MustString(), ShouldEqual, m.ErrDashboardsWithSameSlugExists.Error())
+			})
+		})
+	})
 }
 
 func GetDashboardShouldReturn200(sc *scenarioContext) dtos.DashboardFullWithMeta {

+ 9 - 1
pkg/models/dashboards.go

@@ -22,6 +22,7 @@ var (
 	ErrDashboardFolderCannotHaveParent   = errors.New("A Dashboard Folder cannot be added to another folder")
 	ErrDashboardContainsInvalidAlertData = errors.New("Invalid alert data. Cannot save dashboard")
 	ErrDashboardFailedToUpdateAlertData  = errors.New("Failed to save alert data")
+	ErrDashboardsWithSameSlugExists      = errors.New("Multiple dashboards with the same slug exists")
 )
 
 type UpdatePluginDashboardError struct {
@@ -165,7 +166,7 @@ func GetDashboardUrl(uid string, slug string) string {
 
 // GetFolderUrl return the html url for a folder
 func GetFolderUrl(folderUid string, slug string) string {
-	return fmt.Sprintf("%s/f/%v/%s", setting.AppSubUrl, folderUid, slug)
+	return fmt.Sprintf("%s/dashboards/f/%s/%s", setting.AppSubUrl, folderUid, slug)
 }
 
 //
@@ -231,3 +232,10 @@ type GetDashboardSlugByIdQuery struct {
 	Id     int64
 	Result string
 }
+
+type GetDashboardsBySlugQuery struct {
+	OrgId int64
+	Slug  string
+
+	Result []*Dashboard
+}

+ 11 - 0
pkg/services/sqlstore/dashboard.go

@@ -386,3 +386,14 @@ func GetDashboardSlugById(query *m.GetDashboardSlugByIdQuery) error {
 	query.Result = slug.Slug
 	return nil
 }
+
+func GetDashboardsBySlug(query *m.GetDashboardsBySlugQuery) error {
+	var dashboards = make([]*m.Dashboard, 0)
+
+	if err := x.Where("org_id=? AND slug=?", query.OrgId, query.Slug).Find(&dashboards); err != nil {
+		return err
+	}
+
+	query.Result = dashboards
+	return nil
+}