dashboard load/save work and began work on register

This commit is contained in:
Torkel Ödegaard 2014-08-22 15:32:42 +02:00
parent 07d8b542bf
commit c684b1ddab
9 changed files with 143 additions and 21 deletions

@ -1 +1 @@
Subproject commit 06de80f2a764b76df6047fc4700c74aaf5734521
Subproject commit 477f66f56bdd7f310d439ac428cb646fbb9b1949

View File

@ -17,7 +17,7 @@ func init() {
func (self *HttpServer) getDashboard(c *gin.Context) {
id := c.Params.ByName("id")
dash, err := self.store.GetDashboardByTitle(id, "test")
dash, err := self.store.GetDashboard(id, 1)
if err != nil {
c.JSON(404, newErrorResponse("Dashboard not found"))
return
@ -46,6 +46,8 @@ func (self *HttpServer) postDashboard(c *gin.Context) {
dashboard := models.NewDashboard("test")
dashboard.Data = command.Dashboard
dashboard.Title = dashboard.Data["title"].(string)
dashboard.AccountId = 1
dashboard.UpdateSlug()
if dashboard.Data["id"] != nil {
dashboard.Id = dashboard.Data["id"].(string)
@ -53,7 +55,7 @@ func (self *HttpServer) postDashboard(c *gin.Context) {
err := self.store.SaveDashboard(dashboard)
if err == nil {
c.JSON(200, gin.H{"status": "success", "id": dashboard.Id})
c.JSON(200, gin.H{"status": "success", "slug": dashboard.Slug})
return
}
}

View File

@ -5,6 +5,7 @@ import "github.com/gin-gonic/gin"
func init() {
addRoutes(func(self *HttpServer) {
self.router.GET("/login/*_", self.index)
self.router.GET("/register/*_", self.index)
self.router.POST("/login", self.loginPost)
self.router.POST("/logout", self.logoutPost)
})

View File

@ -0,0 +1,18 @@
package models
import (
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestDashboardModel(t *testing.T) {
Convey("When generating slug", t, func() {
dashboard := NewDashboard("Grafana Play Home")
dashboard.UpdateSlug()
So(dashboard.Slug, ShouldEqual, "grafana-play-home")
})
}

View File

@ -3,12 +3,15 @@ package models
import (
"encoding/json"
"io"
"regexp"
"strings"
"time"
)
type Dashboard struct {
Id string `gorethink:"id,omitempty"`
AccountId string
Slug string
AccountId int
LastModifiedByUserId string
LastModifiedByDate time.Time
CreatedDate time.Time
@ -26,18 +29,19 @@ type UserContext struct {
type SearchResult struct {
Id string `json:"id"`
Title string `json:"title"`
Slug string `json:"slug"`
}
func NewDashboard(title string) *Dashboard {
dash := &Dashboard{}
dash.Id = ""
dash.AccountId = "test"
dash.LastModifiedByDate = time.Now()
dash.CreatedDate = time.Now()
dash.LastModifiedByUserId = "123"
dash.Title = title
dash.Data = make(map[string]interface{})
dash.Data["title"] = title
dash.Title = title
dash.UpdateSlug()
return dash
}
@ -50,11 +54,16 @@ func NewFromJson(reader io.Reader) (*Dashboard, error) {
return nil, err
}
dash.Title = dash.Data["title"].(string)
return dash, nil
}
func (dash *Dashboard) GetString(prop string) string {
return dash.Data[prop].(string)
}
func (dash *Dashboard) UpdateSlug() {
title := strings.ToLower(dash.Data["title"].(string))
re := regexp.MustCompile("[^\\w ]+")
re2 := regexp.MustCompile("\\s")
dash.Slug = re2.ReplaceAllString(re.ReplaceAllString(title, ""), "-")
}

View File

@ -16,6 +16,11 @@ type RethinkCfg struct {
DatabaseName string
}
type Account struct {
Id int `gorethink:"id"`
NextDashboardId int
}
func NewRethinkStore(config *RethinkCfg) *rethinkStore {
log.Info("Initializing rethink storage")
@ -32,17 +37,24 @@ func NewRethinkStore(config *RethinkCfg) *rethinkStore {
r.DbCreate(config.DatabaseName).Exec(session)
r.Db(config.DatabaseName).TableCreate("dashboards").Exec(session)
r.Db(config.DatabaseName).Table("dashboards").IndexCreateFunc("AccountIdTitle", func(row r.Term) interface{} {
return []interface{}{row.Field("AccountId"), row.Field("Title")}
r.Db(config.DatabaseName).TableCreate("accounts").Exec(session)
r.Db(config.DatabaseName).TableCreate("master").Exec(session)
r.Db(config.DatabaseName).Table("dashboards").IndexCreateFunc("AccountIdSlug", func(row r.Term) interface{} {
return []interface{}{row.Field("AccountId"), row.Field("Slug")}
}).Exec(session)
_, err = r.Table("master").Insert(map[string]interface{}{"id": "ids", "NextAccountId": 0}).RunWrite(session)
if err != nil {
log.Error("Failed to insert master ids row", err)
}
return &rethinkStore{
session: session,
}
}
func (self *rethinkStore) SaveDashboard(dash *models.Dashboard) error {
resp, err := r.Table("dashboards").Insert(dash).RunWrite(self.session)
resp, err := r.Table("dashboards").Insert(dash, r.InsertOpts{Upsert: true}).RunWrite(self.session)
if err != nil {
return err
}
@ -56,8 +68,8 @@ func (self *rethinkStore) SaveDashboard(dash *models.Dashboard) error {
return nil
}
func (self *rethinkStore) GetDashboardByTitle(title string, accountId string) (*models.Dashboard, error) {
resp, err := r.Table("dashboards").GetAllByIndex("AccountIdTitle", []interface{}{accountId, title}).Run(self.session)
func (self *rethinkStore) GetDashboard(slug string, accountId int) (*models.Dashboard, error) {
resp, err := r.Table("dashboards").GetAllByIndex("AccountIdSlug", []interface{}{accountId, slug}).Run(self.session)
if err != nil {
return nil, err
}
@ -81,10 +93,9 @@ func (self *rethinkStore) Query(query string) ([]*models.SearchResult, error) {
results := make([]*models.SearchResult, 0, 50)
var dashboard models.Dashboard
for docs.Next(&dashboard) {
log.Info("title: ", dashboard.Title)
results = append(results, &models.SearchResult{
Title: dashboard.Title,
Id: dashboard.Id,
Id: dashboard.Slug,
})
}

View File

@ -0,0 +1,59 @@
package stores
import (
"errors"
r "github.com/dancannon/gorethink"
)
func (self *rethinkStore) getNextAccountId() (int, error) {
resp, err := r.Table("master").Get("ids").Update(map[string]interface{}{
"NextAccountId": r.Row.Field("NextAccountId").Add(1),
}, r.UpdateOpts{ReturnVals: true}).RunWrite(self.session)
if err != nil {
return 0, err
}
if resp.NewValue == nil {
return 0, errors.New("Failed to get new value after incrementing account id")
}
return int(resp.NewValue.(map[string]interface{})["NextAccountId"].(float64)), nil
}
func (self *rethinkStore) createAccount() (*Account, error) {
accountId, err := self.getNextAccountId()
if err != nil {
return nil, err
}
account := &Account{Id: accountId, NextDashboardId: 0}
resp, err := r.Table("accounts").Insert(account).RunWrite(self.session)
if err != nil {
return nil, err
}
if resp.Inserted == 0 {
return nil, errors.New("Failed to insert acccount")
}
return account, nil
}
func (self *rethinkStore) getNextDashboardNumber(accountId int) (int, error) {
resp, err := r.Table("accounts").Get(accountId).Update(map[string]interface{}{
"NextDashboardId": r.Row.Field("NextDashboardId").Add(1),
}, r.UpdateOpts{ReturnVals: true}).RunWrite(self.session)
if err != nil {
return 0, err
}
if resp.NewValue == nil {
return 0, errors.New("Failed to get next dashboard id, no new value after update")
}
return int(resp.NewValue.(map[string]interface{})["NextDashboardId"].(float64)), nil
}

View File

@ -3,27 +3,49 @@ package stores
import (
"testing"
"github.com/dancannon/gorethink"
. "github.com/smartystreets/goconvey/convey"
"github.com/torkelo/grafana-pro/pkg/models"
)
func TestRethinkStore(t *testing.T) {
store := NewRethinkStore(&RethinkCfg{DatabaseName: "tests"})
defer gorethink.DbDrop("tests").Exec(store.session)
Convey("Insert dashboard", t, func() {
store := NewRethinkStore(&RethinkCfg{DatabaseName: "tests"})
//defer r.DbDrop("tests").Exec(store.session)
dashboard := models.NewDashboard("test")
dashboard.AccountId = "123"
dashboard.AccountId = 1
err := store.SaveDashboard(dashboard)
So(err, ShouldBeNil)
So(dashboard.Id, ShouldNotBeEmpty)
read, err := store.GetDashboardByTitle("test", "123")
read, err := store.GetDashboard("test", 1)
So(err, ShouldBeNil)
So(read, ShouldNotBeNil)
})
Convey("can get next account id", t, func() {
id, err := store.getNextAccountId()
So(err, ShouldBeNil)
So(id, ShouldNotEqual, 0)
id2, err := store.getNextAccountId()
So(id2, ShouldEqual, id+1)
})
Convey("can create account", t, func() {
account, err := store.createAccount()
So(err, ShouldBeNil)
So(account, ShouldNotBeNil)
So(account.Id, ShouldNotEqual, 0)
})
Convey("can get next dashboard id", t, func() {
account, err := store.createAccount()
dashId, err := store.getNextDashboardNumber(account.Id)
So(err, ShouldBeNil)
So(dashId, ShouldEqual, 1)
})
}

View File

@ -5,7 +5,7 @@ import (
)
type Store interface {
GetDashboardByTitle(id string, accountId string) (*models.Dashboard, error)
GetDashboard(title string, accountId int) (*models.Dashboard, error)
SaveDashboard(dash *models.Dashboard) error
Query(query string) ([]*models.SearchResult, error)
Close()