diff --git a/grafana b/grafana index 344812f1e0f..34427f34e89 160000 --- a/grafana +++ b/grafana @@ -1 +1 @@ -Subproject commit 344812f1e0f0e804f9e9dd425168069d63c3fae3 +Subproject commit 34427f34e89fe3913523b5b236a149b88931b71d diff --git a/pkg/api/dashboard.go b/pkg/api/dashboard.go index 6791eda8223..45f3fb3e951 100644 --- a/pkg/api/dashboard.go +++ b/pkg/api/dashboard.go @@ -69,6 +69,10 @@ func PostDashboard(c *middleware.Context) { err := bus.Dispatch(&cmd) if err != nil { + if err == m.ErrDashboardWithSameNameExists { + c.JsonApiErr(400, "Dashboard with the same title already exists", nil) + return + } c.JsonApiErr(500, "Failed to save dashboard", err) return } diff --git a/pkg/models/dashboards.go b/pkg/models/dashboards.go index 2aa5020a3e5..f03a300f0dc 100644 --- a/pkg/models/dashboards.go +++ b/pkg/models/dashboards.go @@ -9,7 +9,8 @@ import ( // Typed errors var ( - ErrDashboardNotFound = errors.New("Account not found") + ErrDashboardNotFound = errors.New("Account not found") + ErrDashboardWithSameNameExists = errors.New("A dashboard with the same name already exists") ) type Dashboard struct { @@ -39,8 +40,6 @@ type SearchDashboardsQuery struct { } type SaveDashboardCommand struct { - Id string `json:"id"` - Title string `json:"title"` Dashboard map[string]interface{} `json:"dashboard"` AccountId int64 `json:"-"` diff --git a/pkg/stores/sqlstore/dashboards.go b/pkg/stores/sqlstore/dashboards.go index 827993f7f3f..6670da827d1 100644 --- a/pkg/stores/sqlstore/dashboards.go +++ b/pkg/stores/sqlstore/dashboards.go @@ -17,7 +17,17 @@ func SaveDashboard(cmd *m.SaveDashboardCommand) error { return inTransaction(func(sess *xorm.Session) error { dash := cmd.GetDashboardModel() - var err error + // try get existing dashboard + existing := m.Dashboard{Slug: dash.Slug, AccountId: dash.AccountId} + hasExisting, err := sess.Get(&existing) + if err != nil { + return err + } + + if hasExisting && dash.Id != existing.Id { + return m.ErrDashboardWithSameNameExists + } + if dash.Id == 0 { _, err = sess.Insert(dash) } else { diff --git a/pkg/stores/sqlstore/dashboards_test.go b/pkg/stores/sqlstore/dashboards_test.go new file mode 100644 index 00000000000..272f4c6ae14 --- /dev/null +++ b/pkg/stores/sqlstore/dashboards_test.go @@ -0,0 +1,70 @@ +package sqlstore + +import ( + "testing" + + . "github.com/smartystreets/goconvey/convey" + + m "github.com/torkelo/grafana-pro/pkg/models" +) + +func TestDashboardDataAccess(t *testing.T) { + + Convey("Testing DB", t, func() { + InitTestDB(t) + + Convey("Given saved dashboard", func() { + var savedDash *m.Dashboard + + cmd := m.SaveDashboardCommand{ + AccountId: 1, + Dashboard: map[string]interface{}{ + "id": nil, + "title": "test dash 23", + "tags": make([]interface{}, 0), + }, + } + + err := SaveDashboard(&cmd) + So(err, ShouldBeNil) + + savedDash = cmd.Result + + Convey("Should return dashboard model", func() { + So(savedDash.Title, ShouldEqual, "test dash 23") + So(savedDash.Slug, ShouldEqual, "test-dash-23") + So(savedDash.Id, ShouldNotEqual, 0) + }) + + Convey("Should be able to get dashboard", func() { + query := m.GetDashboardQuery{ + Slug: "test-dash-23", + AccountId: 1, + } + + err := GetDashboard(&query) + So(err, ShouldBeNil) + + So(query.Result.Title, ShouldEqual, "test dash 23") + So(query.Result.Slug, ShouldEqual, "test-dash-23") + }) + + Convey("Should not be able to save dashboard with same name", func() { + cmd := m.SaveDashboardCommand{ + AccountId: 1, + Dashboard: map[string]interface{}{ + "id": nil, + "title": "test dash 23", + "tags": make([]interface{}, 0), + }, + } + + err := SaveDashboard(&cmd) + So(err, ShouldNotBeNil) + }) + + }) + + }) + +} diff --git a/pkg/stores/sqlstore/sqlstore_datasource.go b/pkg/stores/sqlstore/datasource.go similarity index 100% rename from pkg/stores/sqlstore/sqlstore_datasource.go rename to pkg/stores/sqlstore/datasource.go