From 31fe471da55771fb3ac2562ab713b0a5a9eb68dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Fri, 22 Aug 2014 18:05:37 +0200 Subject: [PATCH] working on account registration and more --- pkg/api/api.go | 4 +-- pkg/api/api_dashboard.go | 9 ++++--- pkg/api/api_login.go | 38 ++++++++++++++++++--------- pkg/api/api_register.go | 45 ++++++++++++++++++++++++++++++++ pkg/models/dashboards.go | 20 ++++++++++++++ pkg/stores/rethinkdb.go | 5 ++++ pkg/stores/rethinkdb_accounts.go | 29 +++++++++++++++----- pkg/stores/rethinkdb_test.go | 15 +++++++---- pkg/stores/store.go | 2 ++ 9 files changed, 137 insertions(+), 30 deletions(-) create mode 100644 pkg/api/api_register.go diff --git a/pkg/api/api.go b/pkg/api/api.go index 0ff584805ee..59c5079dde1 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -51,8 +51,8 @@ func (self *HttpServer) ListenAndServe() { } // register default route - self.router.GET("/", self.authMiddleware(), self.index) - self.router.GET("/dashboard/*_", self.authMiddleware(), self.index) + self.router.GET("/", self.auth(), self.index) + self.router.GET("/dashboard/*_", self.auth(), self.index) self.router.Run(":" + self.port) } diff --git a/pkg/api/api_dashboard.go b/pkg/api/api_dashboard.go index b2374f2e096..208b25c7b1f 100644 --- a/pkg/api/api_dashboard.go +++ b/pkg/api/api_dashboard.go @@ -8,16 +8,17 @@ import ( func init() { addRoutes(func(self *HttpServer) { - self.router.GET("/api/dashboards/:id", self.getDashboard) - self.router.GET("/api/search/", self.search) - self.router.POST("/api/dashboard", self.postDashboard) + self.router.GET("/api/dashboards/:id", self.auth(), self.getDashboard) + self.router.GET("/api/search/", self.auth(), self.search) + self.router.POST("/api/dashboard", self.auth(), self.postDashboard) }) } func (self *HttpServer) getDashboard(c *gin.Context) { id := c.Params.ByName("id") + accountId, err := c.Get("accountId") - dash, err := self.store.GetDashboard(id, 1) + dash, err := self.store.GetDashboard(id, accountId.(int)) if err != nil { c.JSON(404, newErrorResponse("Dashboard not found")) return diff --git a/pkg/api/api_login.go b/pkg/api/api_login.go index c722f0cdeb2..fa493ba65b9 100644 --- a/pkg/api/api_login.go +++ b/pkg/api/api_login.go @@ -5,7 +5,6 @@ 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) }) @@ -20,18 +19,28 @@ type loginJsonModel struct { func (self *HttpServer) loginPost(c *gin.Context) { var loginModel loginJsonModel - if c.EnsureBody(&loginModel) { - if loginModel.Email == "manu" && loginModel.Password == "123" { - - session, _ := sessionStore.Get(c.Request, "grafana-session") - session.Values["login"] = true - session.Save(c.Request, c.Writer) - - c.JSON(200, gin.H{"status": "you are logged in"}) - } else { - c.JSON(401, gin.H{"status": "unauthorized"}) - } + if !c.EnsureBody(&loginModel) { + c.JSON(400, gin.H{"status": "bad request"}) + return } + + account, err := self.store.GetUserAccountLogin(loginModel.Email) + if err != nil { + c.JSON(400, gin.H{"status": "some error"}) + } + + if loginModel.Password != account.Password { + c.JSON(401, gin.H{"status": "unauthorized"}) + return + } + + session, _ := sessionStore.Get(c.Request, "grafana-session") + session.Values["login"] = true + session.Values["accountId"] = account.DatabaseId + + session.Save(c.Request, c.Writer) + + c.JSON(200, gin.H{"status": "you are logged in"}) } func (self *HttpServer) logoutPost(c *gin.Context) { @@ -42,15 +51,18 @@ func (self *HttpServer) logoutPost(c *gin.Context) { c.JSON(200, gin.H{"status": "logged out"}) } -func (self *HttpServer) authMiddleware() gin.HandlerFunc { +func (self *HttpServer) auth() gin.HandlerFunc { return func(c *gin.Context) { session, _ := sessionStore.Get(c.Request, "grafana-session") if c.Request.URL.Path != "/login" && session.Values["login"] == nil { c.Writer.Header().Set("Location", "/login") c.Abort(302) + return } + c.Set("accountId", session.Values["accountId"]) + session.Save(c.Request, c.Writer) } } diff --git a/pkg/api/api_register.go b/pkg/api/api_register.go new file mode 100644 index 00000000000..fdc0875df95 --- /dev/null +++ b/pkg/api/api_register.go @@ -0,0 +1,45 @@ +package api + +import ( + log "github.com/alecthomas/log4go" + "github.com/gin-gonic/gin" + "github.com/torkelo/grafana-pro/pkg/models" +) + +func init() { + addRoutes(func(self *HttpServer) { + self.router.GET("/register/*_", self.index) + self.router.POST("/api/register/user", self.registerUserPost) + }) +} + +type registerAccountJsonModel struct { + Email string `json:"email" binding:"required"` + Password string `json:"password" binding:"required"` + Password2 bool `json:"remember2"` +} + +func (self *HttpServer) registerUserPost(c *gin.Context) { + var registerModel registerAccountJsonModel + + if !c.EnsureBody(®isterModel) { + c.JSON(400, gin.H{"status": "bad request"}) + return + } + + account := models.UserAccount{ + UserName: registerModel.Email, + Login: registerModel.Email, + Email: registerModel.Email, + Password: registerModel.Password, + } + + err := self.store.SaveUserAccount(&account) + if err != nil { + log.Error("Failed to create user account, email: %v, error: %v", registerModel.Email, err) + c.JSON(500, gin.H{"status": "failed to create account"}) + return + } + + c.JSON(200, gin.H{"status": "ok"}) +} diff --git a/pkg/models/dashboards.go b/pkg/models/dashboards.go index a2d733d4053..53bd41d6bf8 100644 --- a/pkg/models/dashboards.go +++ b/pkg/models/dashboards.go @@ -21,6 +21,26 @@ type Dashboard struct { Data map[string]interface{} } +type UserAccountLink struct { + UserId int + Role string + ModifiedOn time.Time + CreatedOn time.Time +} + +type UserAccount struct { + DatabaseId int `gorethink:"id"` + UserName string + Login string + Email string + Password string + NextDashboardId int + UsingAccountId int + GrantedAccess []UserAccountLink + CreatedOn time.Time + ModifiedOn time.Time +} + type UserContext struct { UserId string AccountId string diff --git a/pkg/stores/rethinkdb.go b/pkg/stores/rethinkdb.go index 4d9d7864f16..abb974fdd29 100644 --- a/pkg/stores/rethinkdb.go +++ b/pkg/stores/rethinkdb.go @@ -39,10 +39,15 @@ func NewRethinkStore(config *RethinkCfg) *rethinkStore { r.Db(config.DatabaseName).TableCreate("dashboards").Exec(session) 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) + r.Db(config.DatabaseName).Table("accounts").IndexCreateFunc("AccountLogin", func(row r.Term) interface{} { + return []interface{}{row.Field("Login")} + }).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) diff --git a/pkg/stores/rethinkdb_accounts.go b/pkg/stores/rethinkdb_accounts.go index 60905d8ca8e..e2a337146ae 100644 --- a/pkg/stores/rethinkdb_accounts.go +++ b/pkg/stores/rethinkdb_accounts.go @@ -4,6 +4,7 @@ import ( "errors" r "github.com/dancannon/gorethink" + "github.com/torkelo/grafana-pro/pkg/models" ) func (self *rethinkStore) getNextAccountId() (int, error) { @@ -22,24 +23,40 @@ func (self *rethinkStore) getNextAccountId() (int, error) { return int(resp.NewValue.(map[string]interface{})["NextAccountId"].(float64)), nil } -func (self *rethinkStore) createAccount() (*Account, error) { +func (self *rethinkStore) SaveUserAccount(account *models.UserAccount) error { accountId, err := self.getNextAccountId() if err != nil { - return nil, err + return err } - account := &Account{Id: accountId, NextDashboardId: 0} + account.DatabaseId = accountId resp, err := r.Table("accounts").Insert(account).RunWrite(self.session) if err != nil { - return nil, err + return err } if resp.Inserted == 0 { - return nil, errors.New("Failed to insert acccount") + return errors.New("Failed to insert acccount") } - return account, nil + return nil +} + +func (self *rethinkStore) GetUserAccountLogin(emailOrName string) (*models.UserAccount, error) { + resp, err := r.Table("accounts").GetAllByIndex("AccountLogin", []interface{}{emailOrName}).Run(self.session) + + if err != nil { + return nil, err + } + + var account models.UserAccount + err = resp.One(&account) + if err != nil { + return nil, errors.New("Not found") + } + + return &account, nil } func (self *rethinkStore) getNextDashboardNumber(accountId int) (int, error) { diff --git a/pkg/stores/rethinkdb_test.go b/pkg/stores/rethinkdb_test.go index b7766671e4b..e90abb785e8 100644 --- a/pkg/stores/rethinkdb_test.go +++ b/pkg/stores/rethinkdb_test.go @@ -35,15 +35,20 @@ func TestRethinkStore(t *testing.T) { }) Convey("can create account", t, func() { - account, err := store.createAccount() + account := &models.UserAccount{UserName: "torkelo", Email: "mupp", Login: "test@test.com"} + err := store.SaveUserAccount(account) So(err, ShouldBeNil) - So(account, ShouldNotBeNil) - So(account.Id, ShouldNotEqual, 0) + So(account.DatabaseId, ShouldNotEqual, 0) + + read, err := store.GetUserAccountLogin("test@test.com") + So(err, ShouldBeNil) + So(read.DatabaseId, ShouldEqual, account.DatabaseId) }) Convey("can get next dashboard id", t, func() { - account, err := store.createAccount() - dashId, err := store.getNextDashboardNumber(account.Id) + account := &models.UserAccount{UserName: "torkelo", Email: "mupp"} + err := store.SaveUserAccount(account) + dashId, err := store.getNextDashboardNumber(account.DatabaseId) So(err, ShouldBeNil) So(dashId, ShouldEqual, 1) }) diff --git a/pkg/stores/store.go b/pkg/stores/store.go index 7b233e72294..8319e7ca86f 100644 --- a/pkg/stores/store.go +++ b/pkg/stores/store.go @@ -8,6 +8,8 @@ type Store interface { GetDashboard(title string, accountId int) (*models.Dashboard, error) SaveDashboard(dash *models.Dashboard) error Query(query string) ([]*models.SearchResult, error) + SaveUserAccount(acccount *models.UserAccount) error + GetUserAccountLogin(emailOrName string) (*models.UserAccount, error) Close() }