diff --git a/grafana b/grafana index 1b9b8ba2bff..1d769fe41cf 160000 --- a/grafana +++ b/grafana @@ -1 +1 @@ -Subproject commit 1b9b8ba2bff651a38592805c9210bd1864dc1e79 +Subproject commit 1d769fe41cf348d88636938fcb06afcf3425d45b diff --git a/pkg/api/datasources.go b/pkg/api/datasources.go index 37a1cedbfae..f5d43647269 100644 --- a/pkg/api/datasources.go +++ b/pkg/api/datasources.go @@ -29,6 +29,7 @@ func GetDataSources(c *middleware.Context) { Database: ds.Database, User: ds.User, BasicAuth: ds.BasicAuth, + IsDefault: ds.IsDefault, } } @@ -69,8 +70,6 @@ func AddDataSource(c *middleware.Context) { return } - //bus.Publish(&m.DataSourceCreatedEvent{Account: c.GetAccountId(), }) - c.JsonOK("Datasource added") } diff --git a/pkg/api/dtos/models.go b/pkg/api/dtos/models.go index 34bb721231b..ea5fc7f4c85 100644 --- a/pkg/api/dtos/models.go +++ b/pkg/api/dtos/models.go @@ -30,6 +30,7 @@ type DataSource struct { User string `json:"user"` Database string `json:"database"` BasicAuth bool `json:"basicAuth"` + IsDefault bool `json:"isDefault"` } type MetricQueryResultDto struct { diff --git a/pkg/api/frontendsettings.go b/pkg/api/frontendsettings.go index 9a035146e83..0e0e75699b6 100644 --- a/pkg/api/frontendsettings.go +++ b/pkg/api/frontendsettings.go @@ -33,8 +33,9 @@ func getFrontendSettings(c *middleware.Context) (map[string]interface{}, error) } var dsMap = map[string]interface{}{ - "type": ds.Type, - "url": url, + "type": ds.Type, + "url": url, + "default": ds.IsDefault, } if ds.Type == m.DS_INFLUXDB { diff --git a/pkg/bus/bus.go b/pkg/bus/bus.go index c9ae790f254..7afff22eb4e 100644 --- a/pkg/bus/bus.go +++ b/pkg/bus/bus.go @@ -10,11 +10,14 @@ type Msg interface{} type Bus interface { Dispatch(msg Msg) error + Publish(msg Msg) error AddHandler(handler HandlerFunc) + AddEventListener(handler HandlerFunc) } type InProcBus struct { - handlers map[string]HandlerFunc + handlers map[string]HandlerFunc + listeners map[string][]HandlerFunc } // temp stuff, not sure how to handle bus instance, and init yet @@ -23,6 +26,7 @@ var globalBus = New() func New() Bus { bus := &InProcBus{} bus.handlers = make(map[string]HandlerFunc) + bus.listeners = make(map[string][]HandlerFunc) return bus } @@ -46,17 +50,55 @@ func (b *InProcBus) Dispatch(msg Msg) error { } } +func (b *InProcBus) Publish(msg Msg) error { + var msgName = reflect.TypeOf(msg).Elem().Name() + + var listeners = b.listeners[msgName] + if len(listeners) == 0 { + return nil + } + + var params = make([]reflect.Value, 1) + params[0] = reflect.ValueOf(msg) + + for listenerHandler := range listeners { + ret := reflect.ValueOf(listenerHandler).Call(params) + err := ret[0].Interface() + if err != nil { + return err.(error) + } + } + + return nil +} + func (b *InProcBus) AddHandler(handler HandlerFunc) { handlerType := reflect.TypeOf(handler) queryTypeName := handlerType.In(0).Elem().Name() b.handlers[queryTypeName] = handler } +func (b *InProcBus) AddEventListener(handler HandlerFunc) { + handlerType := reflect.TypeOf(handler) + eventName := handlerType.In(0).Elem().Name() + list, exists := b.listeners[eventName] + if !exists { + list = make([]HandlerFunc, 0) + b.listeners[eventName] = list + } + list = append(list, handler) +} + // Package level functions func AddHandler(implName string, handler HandlerFunc) { globalBus.AddHandler(handler) } +// Package level functions +func AddEventListener(handler HandlerFunc) { + globalBus.AddEventListener(handler) +} + func Dispatch(msg Msg) error { return globalBus.Dispatch(msg) } diff --git a/pkg/bus/bus_test.go b/pkg/bus/bus_test.go index d72853eb88d..45191eeb682 100644 --- a/pkg/bus/bus_test.go +++ b/pkg/bus/bus_test.go @@ -43,3 +43,26 @@ func TestQueryHandlerReturn(t *testing.T) { t.Fatal("Failed to get response from handler") } } + +func TestEventListeners(t *testing.T) { + bus := New() + count := 0 + + bus.AddEventListener(func(query *TestQuery) error { + count += 1 + return nil + }) + + bus.AddEventListener(func(query *TestQuery) error { + count += 10 + return nil + }) + + err := bus.Publish(&TestQuery{}) + + if err != nil { + t.Fatal("Publish event failed " + err.Error()) + } else if count != 0 { + t.Fatal("Publish event failed, listeners called: %v, expected: %v", count, 11) + } +} diff --git a/pkg/models/account.go b/pkg/models/account.go index 4d06a70d41c..d39de09514a 100644 --- a/pkg/models/account.go +++ b/pkg/models/account.go @@ -12,18 +12,17 @@ var ( ) type Account struct { - Id int64 - Login string `xorm:"UNIQUE NOT NULL"` - Email string `xorm:"UNIQUE NOT NULL"` - Name string - FullName string - Password string - IsAdmin bool - Salt string `xorm:"VARCHAR(10)"` - Company string - NextDashboardId int - UsingAccountId int64 - DefaultDataSourceId int64 + Id int64 + Login string `xorm:"UNIQUE NOT NULL"` + Email string `xorm:"UNIQUE NOT NULL"` + Name string + FullName string + Password string + IsAdmin bool + Salt string `xorm:"VARCHAR(10)"` + Company string + NextDashboardId int + UsingAccountId int64 Created time.Time Updated time.Time @@ -48,11 +47,6 @@ type SetUsingAccountCommand struct { UsingAccountId int64 } -type SetDefaultDataSourceCommand struct { - AccountId int64 - DataSourceId int64 -} - // ---------------------- // QUERIES diff --git a/pkg/models/datasource.go b/pkg/models/datasource.go index 12ff5bbadc0..19a5d903fbe 100644 --- a/pkg/models/datasource.go +++ b/pkg/models/datasource.go @@ -33,6 +33,7 @@ type DataSource struct { User string Database string BasicAuth bool + IsDefault bool Created time.Time Updated time.Time @@ -41,8 +42,9 @@ type DataSource struct { // ---------------------- // COMMANDS +// Also acts as api DTO type AddDataSourceCommand struct { - AccountId int64 + AccountId int64 `json:"-"` Name string Type DsType Access DsAccess @@ -50,10 +52,12 @@ type AddDataSourceCommand struct { Password string Database string User string + IsDefault bool Result *DataSource } +// Also acts as api DTO type UpdateDataSourceCommand struct { Id int64 AccountId int64 @@ -64,6 +68,7 @@ type UpdateDataSourceCommand struct { Password string User string Database string + IsDefault bool } type DeleteDataSourceCommand struct { diff --git a/pkg/services/account/handlers.go b/pkg/services/account/handlers.go deleted file mode 100644 index 07857f5e642..00000000000 --- a/pkg/services/account/handlers.go +++ /dev/null @@ -1,9 +0,0 @@ -package account - -import ( - "github.com/torkelo/grafana-pro/pkg/bus" -) - -func InitAccountService() { - bus.ListenTo() -} diff --git a/pkg/stores/sqlstore/datasource.go b/pkg/stores/sqlstore/datasource.go index 95986126297..6360d50cc02 100644 --- a/pkg/stores/sqlstore/datasource.go +++ b/pkg/stores/sqlstore/datasource.go @@ -45,9 +45,7 @@ func DeleteDataSource(cmd *m.DeleteDataSourceCommand) error { func AddDataSource(cmd *m.AddDataSourceCommand) error { return inTransaction(func(sess *xorm.Session) error { - var err error - - ds := m.DataSource{ + ds := &m.DataSource{ AccountId: cmd.AccountId, Name: cmd.Name, Type: cmd.Type, @@ -56,23 +54,38 @@ func AddDataSource(cmd *m.AddDataSourceCommand) error { User: cmd.User, Password: cmd.Password, Database: cmd.Database, + IsDefault: cmd.IsDefault, Created: time.Now(), Updated: time.Now(), } - _, err = sess.Insert(&ds) - cmd.Result = &ds + if _, err := sess.Insert(ds); err != nil { + return err + } + if err := updateIsDefaultFlag(ds, sess); err != nil { + return err + } - return err + cmd.Result = ds + return nil }) } +func updateIsDefaultFlag(ds *m.DataSource, sess *xorm.Session) error { + // Handle is default flag + if ds.IsDefault { + rawSql := "UPDATE data_source SET is_default = 0 WHERE account_id=? AND id <> ?" + if _, err := sess.Exec(rawSql, ds.AccountId, ds.Id); err != nil { + return err + } + } + return nil +} + func UpdateDataSource(cmd *m.UpdateDataSourceCommand) error { return inTransaction(func(sess *xorm.Session) error { - var err error - - ds := m.DataSource{ + ds := &m.DataSource{ Id: cmd.Id, AccountId: cmd.AccountId, Name: cmd.Name, @@ -83,9 +96,17 @@ func UpdateDataSource(cmd *m.UpdateDataSourceCommand) error { Password: cmd.Password, Database: cmd.Database, Updated: time.Now(), + IsDefault: cmd.IsDefault, } - _, err = sess.Where("id=? and account_id=?", ds.Id, ds.AccountId).Update(&ds) + sess.UseBool("is_default") + + _, err := sess.Where("id=? and account_id=?", ds.Id, ds.AccountId).Update(ds) + if err != nil { + return err + } + + err = updateIsDefaultFlag(ds, sess) return err }) } diff --git a/pkg/stores/sqlstore/sqlstore_test.go b/pkg/stores/sqlstore/datasource_test.go similarity index 100% rename from pkg/stores/sqlstore/sqlstore_test.go rename to pkg/stores/sqlstore/datasource_test.go