mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
macaron transition progress
This commit is contained in:
parent
201e1d3e6d
commit
222319d924
BIN
data/sessions/5/e/5e40ff05d87ac75cba0634e7350c263c4c45f202
Normal file
BIN
data/sessions/5/e/5e40ff05d87ac75cba0634e7350c263c4c45f202
Normal file
Binary file not shown.
BIN
grafana-pro
BIN
grafana-pro
Binary file not shown.
@ -10,11 +10,14 @@ import (
|
|||||||
|
|
||||||
"github.com/Unknwon/macaron"
|
"github.com/Unknwon/macaron"
|
||||||
"github.com/codegangsta/cli"
|
"github.com/codegangsta/cli"
|
||||||
|
"github.com/macaron-contrib/session"
|
||||||
|
|
||||||
"github.com/torkelo/grafana-pro/pkg/log"
|
"github.com/torkelo/grafana-pro/pkg/log"
|
||||||
"github.com/torkelo/grafana-pro/pkg/middleware"
|
"github.com/torkelo/grafana-pro/pkg/middleware"
|
||||||
"github.com/torkelo/grafana-pro/pkg/routes"
|
"github.com/torkelo/grafana-pro/pkg/routes"
|
||||||
|
"github.com/torkelo/grafana-pro/pkg/routes/login"
|
||||||
"github.com/torkelo/grafana-pro/pkg/setting"
|
"github.com/torkelo/grafana-pro/pkg/setting"
|
||||||
|
"github.com/torkelo/grafana-pro/pkg/stores/rethink"
|
||||||
)
|
)
|
||||||
|
|
||||||
var CmdWeb = cli.Command{
|
var CmdWeb = cli.Command{
|
||||||
@ -29,27 +32,15 @@ func newMacaron() *macaron.Macaron {
|
|||||||
m := macaron.New()
|
m := macaron.New()
|
||||||
m.Use(middleware.Logger())
|
m.Use(middleware.Logger())
|
||||||
m.Use(macaron.Recovery())
|
m.Use(macaron.Recovery())
|
||||||
m.Use(macaron.Static(
|
|
||||||
path.Join(setting.StaticRootPath, "public"),
|
mapStatic(m, "public", "public")
|
||||||
macaron.StaticOptions{
|
mapStatic(m, "public/app", "app")
|
||||||
SkipLogging: true,
|
mapStatic(m, "public/img", "img")
|
||||||
Prefix: "public",
|
|
||||||
},
|
m.Use(session.Sessioner(session.Options{
|
||||||
))
|
Provider: setting.SessionProvider,
|
||||||
m.Use(macaron.Static(
|
Config: *setting.SessionConfig,
|
||||||
path.Join(setting.StaticRootPath, "public/app"),
|
}))
|
||||||
macaron.StaticOptions{
|
|
||||||
SkipLogging: true,
|
|
||||||
Prefix: "app",
|
|
||||||
},
|
|
||||||
))
|
|
||||||
m.Use(macaron.Static(
|
|
||||||
path.Join(setting.StaticRootPath, "public/img"),
|
|
||||||
macaron.StaticOptions{
|
|
||||||
SkipLogging: true,
|
|
||||||
Prefix: "img",
|
|
||||||
},
|
|
||||||
))
|
|
||||||
|
|
||||||
m.Use(macaron.Renderer(macaron.RenderOptions{
|
m.Use(macaron.Renderer(macaron.RenderOptions{
|
||||||
Directory: path.Join(setting.StaticRootPath, "views"),
|
Directory: path.Join(setting.StaticRootPath, "views"),
|
||||||
@ -61,16 +52,31 @@ func newMacaron() *macaron.Macaron {
|
|||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func mapStatic(m *macaron.Macaron, dir string, prefix string) {
|
||||||
|
m.Use(macaron.Static(
|
||||||
|
path.Join(setting.StaticRootPath, dir),
|
||||||
|
macaron.StaticOptions{
|
||||||
|
SkipLogging: true,
|
||||||
|
Prefix: prefix,
|
||||||
|
},
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
func runWeb(*cli.Context) {
|
func runWeb(*cli.Context) {
|
||||||
setting.NewConfigContext()
|
setting.NewConfigContext()
|
||||||
setting.InitServices()
|
setting.InitServices()
|
||||||
|
rethink.Init()
|
||||||
|
|
||||||
log.Info("Starting Grafana-Pro v.1-alpha")
|
log.Info("Starting Grafana-Pro v.1-alpha")
|
||||||
|
|
||||||
m := newMacaron()
|
m := newMacaron()
|
||||||
|
|
||||||
|
auth := middleware.Auth()
|
||||||
|
|
||||||
// index
|
// index
|
||||||
m.Get("/", routes.Index)
|
m.Get("/", auth, routes.Index)
|
||||||
|
m.Get("/login", routes.Index)
|
||||||
|
m.Post("/login", login.LoginPost)
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
listenAddr := fmt.Sprintf("%s:%s", setting.HttpAddr, setting.HttpPort)
|
listenAddr := fmt.Sprintf("%s:%s", setting.HttpAddr, setting.HttpPort)
|
||||||
|
57
pkg/middleware/auth.go
Normal file
57
pkg/middleware/auth.go
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/Unknwon/macaron"
|
||||||
|
"github.com/macaron-contrib/session"
|
||||||
|
"github.com/torkelo/grafana-pro/pkg/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
func authGetRequestAccountId(c *Context, sess session.Store) (int, error) {
|
||||||
|
accountId := sess.Get("accountId")
|
||||||
|
|
||||||
|
urlQuery := c.Req.URL.Query()
|
||||||
|
if len(urlQuery["render"]) > 0 {
|
||||||
|
accId, _ := strconv.Atoi(urlQuery["accountId"][0])
|
||||||
|
sess.Set("accountId", accId)
|
||||||
|
accountId = accId
|
||||||
|
}
|
||||||
|
|
||||||
|
if accountId == nil {
|
||||||
|
return -1, errors.New("Auth: session account id not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
return accountId.(int), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func authDenied(c *Context) {
|
||||||
|
c.Redirect("/login")
|
||||||
|
}
|
||||||
|
|
||||||
|
func Auth() macaron.Handler {
|
||||||
|
return func(c *Context, sess session.Store) {
|
||||||
|
accountId, err := authGetRequestAccountId(c, sess)
|
||||||
|
|
||||||
|
if err != nil && c.Req.URL.Path != "/login" {
|
||||||
|
authDenied(c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
account, err := models.GetAccount(accountId)
|
||||||
|
if err != nil {
|
||||||
|
authDenied(c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
usingAccount, err := models.GetAccount(account.UsingAccountId)
|
||||||
|
if err != nil {
|
||||||
|
authDenied(c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.UserAccount = account
|
||||||
|
c.Account = usingAccount
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,8 @@
|
|||||||
package middleware
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
"encoding/json"
|
||||||
|
"io/ioutil"
|
||||||
|
|
||||||
"github.com/Unknwon/macaron"
|
"github.com/Unknwon/macaron"
|
||||||
"github.com/macaron-contrib/session"
|
"github.com/macaron-contrib/session"
|
||||||
@ -21,13 +22,12 @@ type Context struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetContextHandler() macaron.Handler {
|
func GetContextHandler() macaron.Handler {
|
||||||
return func(c *macaron.Context) {
|
return func(c *macaron.Context, sess session.Store) {
|
||||||
ctx := &Context{
|
ctx := &Context{
|
||||||
Context: c,
|
Context: c,
|
||||||
|
Session: sess,
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Data["PageStartTime"] = time.Now()
|
|
||||||
|
|
||||||
c.Map(ctx)
|
c.Map(ctx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -50,3 +50,9 @@ func (ctx *Context) Handle(status int, title string, err error) {
|
|||||||
|
|
||||||
ctx.HTML(status, "index")
|
ctx.HTML(status, "index")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ctx *Context) JsonBody(model interface{}) bool {
|
||||||
|
b, _ := ioutil.ReadAll(ctx.Req.Body)
|
||||||
|
err := json.Unmarshal(b, &model)
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
|
@ -5,6 +5,19 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
CreateAccount func(acccount *Account) error
|
||||||
|
UpdateAccount func(acccount *Account) error
|
||||||
|
GetAccountByLogin func(emailOrName string) (*Account, error)
|
||||||
|
GetAccount func(accountId int) (*Account, error)
|
||||||
|
GetOtherAccountsFor func(accountId int) ([]*OtherAccount, error)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Typed errors
|
||||||
|
var (
|
||||||
|
ErrAccountNotFound = errors.New("Account not found")
|
||||||
|
)
|
||||||
|
|
||||||
type CollaboratorLink struct {
|
type CollaboratorLink struct {
|
||||||
AccountId int
|
AccountId int
|
||||||
Role string
|
Role string
|
||||||
|
36
pkg/routes/apimodel/models.go
Normal file
36
pkg/routes/apimodel/models.go
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
package apimodel
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/md5"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/torkelo/grafana-pro/pkg/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LoginResultDto struct {
|
||||||
|
Status string `json:"status"`
|
||||||
|
User CurrentUserDto `json:"user"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CurrentUserDto struct {
|
||||||
|
Login string `json:"login"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
GravatarUrl string `json:"gravatarUrl"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCurrentUserDto(account *models.Account) *CurrentUserDto {
|
||||||
|
model := &CurrentUserDto{}
|
||||||
|
if account != nil {
|
||||||
|
model.Login = account.Login
|
||||||
|
model.Email = account.Email
|
||||||
|
model.GravatarUrl = getGravatarUrl(account.Email)
|
||||||
|
}
|
||||||
|
return model
|
||||||
|
}
|
||||||
|
|
||||||
|
func getGravatarUrl(text string) string {
|
||||||
|
hasher := md5.New()
|
||||||
|
hasher.Write([]byte(strings.ToLower(text)))
|
||||||
|
return fmt.Sprintf("https://secure.gravatar.com/avatar/%x?s=90&default=mm", hasher.Sum(nil))
|
||||||
|
}
|
@ -1,12 +1,15 @@
|
|||||||
package routes
|
package routes
|
||||||
|
|
||||||
import "github.com/torkelo/grafana-pro/pkg/middleware"
|
import (
|
||||||
|
"github.com/torkelo/grafana-pro/pkg/middleware"
|
||||||
|
"github.com/torkelo/grafana-pro/pkg/routes/apimodel"
|
||||||
|
)
|
||||||
|
|
||||||
func Index(ctx *middleware.Context) {
|
func Index(ctx *middleware.Context) {
|
||||||
|
ctx.Data["User"] = apimodel.NewCurrentUserDto(ctx.UserAccount)
|
||||||
ctx.HTML(200, "index")
|
ctx.HTML(200, "index")
|
||||||
}
|
}
|
||||||
|
|
||||||
func NotFound(ctx *middleware.Context) {
|
func NotFound(ctx *middleware.Context) {
|
||||||
ctx.Data["Title"] = "Page Not Found"
|
|
||||||
ctx.Handle(404, "index", nil)
|
ctx.Handle(404, "index", nil)
|
||||||
}
|
}
|
||||||
|
56
pkg/routes/login/login.go
Normal file
56
pkg/routes/login/login.go
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
package login
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/torkelo/grafana-pro/pkg/log"
|
||||||
|
"github.com/torkelo/grafana-pro/pkg/middleware"
|
||||||
|
"github.com/torkelo/grafana-pro/pkg/models"
|
||||||
|
"github.com/torkelo/grafana-pro/pkg/routes/apimodel"
|
||||||
|
)
|
||||||
|
|
||||||
|
type loginJsonModel struct {
|
||||||
|
Email string `json:"email" binding:"required"`
|
||||||
|
Password string `json:"password" binding:"required"`
|
||||||
|
Remember bool `json:"remember"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoginPost(c *middleware.Context) {
|
||||||
|
var loginModel loginJsonModel
|
||||||
|
|
||||||
|
if !c.JsonBody(&loginModel) {
|
||||||
|
c.JSON(400, gin.H{"status": "bad request"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
account, err := models.GetAccountByLogin(loginModel.Email)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(401, gin.H{"status": "unauthorized"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if loginModel.Password != account.Password {
|
||||||
|
c.JSON(401, gin.H{"status": "unauthorized"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
loginUserWithAccount(account, c)
|
||||||
|
|
||||||
|
var resp = &apimodel.LoginResultDto{}
|
||||||
|
resp.Status = "Logged in"
|
||||||
|
resp.User.Login = account.Login
|
||||||
|
|
||||||
|
c.JSON(200, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func loginUserWithAccount(account *models.Account, c *middleware.Context) {
|
||||||
|
if account == nil {
|
||||||
|
log.Error(3, "Account login with nil account")
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Session.Set("accountId", account.Id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func LogoutPost(c *middleware.Context) {
|
||||||
|
c.Session.Delete("accountId")
|
||||||
|
c.JSON(200, gin.H{"status": "logged out"})
|
||||||
|
}
|
197
pkg/stores/rethink/rethink.go
Normal file
197
pkg/stores/rethink/rethink.go
Normal file
@ -0,0 +1,197 @@
|
|||||||
|
package rethink
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
r "github.com/dancannon/gorethink"
|
||||||
|
|
||||||
|
"github.com/torkelo/grafana-pro/pkg/log"
|
||||||
|
"github.com/torkelo/grafana-pro/pkg/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
session *r.Session
|
||||||
|
dbName string = "grafana"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Init() {
|
||||||
|
log.Info("Initializing rethink storage")
|
||||||
|
|
||||||
|
var err error
|
||||||
|
session, err = r.Connect(r.ConnectOpts{
|
||||||
|
Address: "localhost:28015",
|
||||||
|
Database: dbName,
|
||||||
|
MaxIdle: 10,
|
||||||
|
IdleTimeout: time.Second * 10,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Error(3, "Failed to connect to rethink database %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
createRethinkDBTablesAndIndices()
|
||||||
|
|
||||||
|
models.GetAccount = GetAccount
|
||||||
|
models.GetAccountByLogin = GetAccountByLogin
|
||||||
|
}
|
||||||
|
|
||||||
|
func createRethinkDBTablesAndIndices() {
|
||||||
|
|
||||||
|
r.DbCreate(dbName).Exec(session)
|
||||||
|
|
||||||
|
// create tables
|
||||||
|
r.Db(dbName).TableCreate("dashboards").Exec(session)
|
||||||
|
r.Db(dbName).TableCreate("accounts").Exec(session)
|
||||||
|
r.Db(dbName).TableCreate("master").Exec(session)
|
||||||
|
|
||||||
|
// create dashboard accountId + slug index
|
||||||
|
r.Db(dbName).Table("dashboards").IndexCreateFunc("AccountIdSlug", func(row r.Term) interface{} {
|
||||||
|
return []interface{}{row.Field("AccountId"), row.Field("Slug")}
|
||||||
|
}).Exec(session)
|
||||||
|
|
||||||
|
r.Db(dbName).Table("dashboards").IndexCreate("AccountId").Exec(session)
|
||||||
|
r.Db(dbName).Table("accounts").IndexCreate("Login").Exec(session)
|
||||||
|
|
||||||
|
// create account collaborator index
|
||||||
|
r.Db(dbName).Table("accounts").
|
||||||
|
IndexCreateFunc("CollaboratorAccountId", func(row r.Term) interface{} {
|
||||||
|
return row.Field("Collaborators").Map(func(row r.Term) interface{} {
|
||||||
|
return row.Field("AccountId")
|
||||||
|
})
|
||||||
|
}, r.IndexCreateOpts{Multi: true}).Exec(session)
|
||||||
|
|
||||||
|
// make sure master ids row exists
|
||||||
|
_, err := r.Table("master").Insert(map[string]interface{}{"id": "ids", "NextAccountId": 0}).RunWrite(session)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(3, "Failed to insert master ids row", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getNextAccountId() (int, error) {
|
||||||
|
resp, err := r.Table("master").Get("ids").Update(map[string]interface{}{
|
||||||
|
"NextAccountId": r.Row.Field("NextAccountId").Add(1),
|
||||||
|
}, r.UpdateOpts{ReturnChanges: true}).RunWrite(session)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
change := resp.Changes[0]
|
||||||
|
|
||||||
|
if change.NewValue == nil {
|
||||||
|
return 0, errors.New("Failed to get new value after incrementing account id")
|
||||||
|
}
|
||||||
|
|
||||||
|
return int(change.NewValue.(map[string]interface{})["NextAccountId"].(float64)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateAccount(account *models.Account) error {
|
||||||
|
accountId, err := getNextAccountId()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
account.Id = accountId
|
||||||
|
account.UsingAccountId = accountId
|
||||||
|
|
||||||
|
resp, err := r.Table("accounts").Insert(account).RunWrite(session)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.Inserted == 0 {
|
||||||
|
return errors.New("Failed to insert acccount")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetAccountByLogin(emailOrName string) (*models.Account, error) {
|
||||||
|
resp, err := r.Table("accounts").GetAllByIndex("Login", emailOrName).Run(session)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var account models.Account
|
||||||
|
err = resp.One(&account)
|
||||||
|
if err != nil {
|
||||||
|
return nil, models.ErrAccountNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
return &account, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetAccount(id int) (*models.Account, error) {
|
||||||
|
resp, err := r.Table("accounts").Get(id).Run(session)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var account models.Account
|
||||||
|
err = resp.One(&account)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("Not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &account, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateAccount(account *models.Account) error {
|
||||||
|
resp, err := r.Table("accounts").Update(account).RunWrite(session)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.Replaced == 0 && resp.Unchanged == 0 {
|
||||||
|
return errors.New("Could not find account to update")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func 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{ReturnChanges: true}).RunWrite(session)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
change := resp.Changes[0]
|
||||||
|
|
||||||
|
if change.NewValue == nil {
|
||||||
|
return 0, errors.New("Failed to get next dashboard id, no new value after update")
|
||||||
|
}
|
||||||
|
|
||||||
|
return int(change.NewValue.(map[string]interface{})["NextDashboardId"].(float64)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetOtherAccountsFor(accountId int) ([]*models.OtherAccount, error) {
|
||||||
|
resp, err := r.Table("accounts").
|
||||||
|
GetAllByIndex("CollaboratorAccountId", accountId).
|
||||||
|
Map(func(row r.Term) interface{} {
|
||||||
|
return map[string]interface{}{
|
||||||
|
"id": row.Field("id"),
|
||||||
|
"Name": row.Field("Email"),
|
||||||
|
"Role": row.Field("Collaborators").Filter(map[string]interface{}{
|
||||||
|
"AccountId": accountId,
|
||||||
|
}).Nth(0).Field("Role"),
|
||||||
|
}
|
||||||
|
}).Run(session)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var list []*models.OtherAccount
|
||||||
|
err = resp.All(&list)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("Failed to read available accounts")
|
||||||
|
}
|
||||||
|
|
||||||
|
return list, nil
|
||||||
|
}
|
@ -1,10 +1,6 @@
|
|||||||
package stores
|
package stores
|
||||||
|
|
||||||
import (
|
import "github.com/torkelo/grafana-pro/pkg/models"
|
||||||
"errors"
|
|
||||||
|
|
||||||
"github.com/torkelo/grafana-pro/pkg/models"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Store interface {
|
type Store interface {
|
||||||
GetDashboard(slug string, accountId int) (*models.Dashboard, error)
|
GetDashboard(slug string, accountId int) (*models.Dashboard, error)
|
||||||
@ -19,11 +15,6 @@ type Store interface {
|
|||||||
Close()
|
Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Typed errors
|
|
||||||
var (
|
|
||||||
ErrAccountNotFound = errors.New("Account not found")
|
|
||||||
)
|
|
||||||
|
|
||||||
func New() Store {
|
func New() Store {
|
||||||
return NewRethinkStore(&RethinkCfg{DatabaseName: "grafana"})
|
return NewRethinkStore(&RethinkCfg{DatabaseName: "grafana"})
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user