From f858f6b621b185480883c066cfc402ea7a054ed8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Fri, 16 Jan 2015 11:54:19 +0100 Subject: [PATCH] Add collaborator now handles role, added macaron-contrib/binding for binding and validation --- grafana | 2 +- pkg/api/api.go | 77 +++++++++++++------------- pkg/api/collaborators.go | 11 +--- pkg/api/login.go | 2 +- pkg/api/login_oauth.go | 2 +- pkg/api/token.go | 8 +-- pkg/models/account.go | 4 +- pkg/models/collaborator.go | 36 +++++++----- pkg/services/sqlstore/accounts.go | 10 +++- pkg/services/sqlstore/accounts_test.go | 2 +- pkg/services/sqlstore/sqlstore.go | 2 +- 11 files changed, 81 insertions(+), 75 deletions(-) diff --git a/grafana b/grafana index 9d1dacb8d41..500e0006613 160000 --- a/grafana +++ b/grafana @@ -1 +1 @@ -Subproject commit 9d1dacb8d417cac2cc66797e5dae6deba36c3080 +Subproject commit 500e00066139b861a2898db6ef80ef87b8b8daa6 diff --git a/pkg/api/api.go b/pkg/api/api.go index 2829a4d1da1..bbccf34ff81 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -2,76 +2,79 @@ package api import ( "github.com/Unknwon/macaron" + "github.com/macaron-contrib/binding" "github.com/torkelo/grafana-pro/pkg/api/dtos" "github.com/torkelo/grafana-pro/pkg/middleware" + m "github.com/torkelo/grafana-pro/pkg/models" "github.com/torkelo/grafana-pro/pkg/setting" ) // Register adds http routes -func Register(m *macaron.Macaron) { +func Register(r *macaron.Macaron) { reqSignedIn := middleware.Auth(&middleware.AuthOptions{ReqSignedIn: true}) reqAdmin := middleware.Auth(&middleware.AuthOptions{ReqSignedIn: true, ReqAdmin: true}) + bind := binding.Bind // not logged in views - m.Get("/", reqSignedIn, Index) - m.Post("/logout", LogoutPost) - m.Post("/login", LoginPost) - m.Get("/login/:name", OAuthLogin) - m.Get("/login", Index) + r.Get("/", reqSignedIn, Index) + r.Post("/logout", LogoutPost) + r.Post("/login", LoginPost) + r.Get("/login/:name", OAuthLogin) + r.Get("/login", Index) // authed views - m.Get("/account/", reqSignedIn, Index) - m.Get("/account/datasources/", reqSignedIn, Index) - m.Get("/admin", reqSignedIn, Index) - m.Get("/dashboard/*", reqSignedIn, Index) + r.Get("/account/", reqSignedIn, Index) + r.Get("/account/datasources/", reqSignedIn, Index) + r.Get("/admin", reqSignedIn, Index) + r.Get("/dashboard/*", reqSignedIn, Index) // sign up - m.Get("/signup", Index) - m.Post("/api/account/signup", SignUp) + r.Get("/signup", Index) + r.Post("/api/account/signup", SignUp) // authed api - m.Group("/api", func() { + r.Group("/api", func() { // account - m.Group("/account", func() { - m.Get("/", GetAccount) - m.Post("/", UpdateAccount) - m.Put("/collaborators", AddCollaborator) - m.Get("/collaborators", GetCollaborators) - m.Delete("/collaborators/:id", RemoveCollaborator) - m.Post("/using/:id", SetUsingAccount) - m.Get("/others", GetOtherAccounts) + r.Group("/account", func() { + r.Get("/", GetAccount) + r.Post("/", UpdateAccount) + r.Put("/collaborators", bind(m.AddCollaboratorCommand{}), AddCollaborator) + r.Get("/collaborators", GetCollaborators) + r.Delete("/collaborators/:id", RemoveCollaborator) + r.Post("/using/:id", SetUsingAccount) + r.Get("/others", GetOtherAccounts) }) // Token - m.Group("/tokens", func() { - m.Combo("/").Get(GetTokens).Put(AddToken).Post(UpdateToken) - m.Delete("/:id", DeleteToken) + r.Group("/tokens", func() { + r.Combo("/").Get(GetTokens).Put(AddToken).Post(UpdateToken) + r.Delete("/:id", DeleteToken) }) // Data sources - m.Group("/datasources", func() { - m.Combo("/").Get(GetDataSources).Put(AddDataSource).Post(UpdateDataSource) - m.Delete("/:id", DeleteDataSource) - m.Any("/proxy/:id/*", reqSignedIn, ProxyDataSourceRequest) + r.Group("/datasources", func() { + r.Combo("/").Get(GetDataSources).Put(AddDataSource).Post(UpdateDataSource) + r.Delete("/:id", DeleteDataSource) + r.Any("/proxy/:id/*", reqSignedIn, ProxyDataSourceRequest) }) // Dashboard - m.Group("/dashboard", func() { - m.Combo("/:slug").Get(GetDashboard).Delete(DeleteDashboard) - m.Post("/", PostDashboard) + r.Group("/dashboard", func() { + r.Combo("/:slug").Get(GetDashboard).Delete(DeleteDashboard) + r.Post("/", PostDashboard) }) // Search - m.Get("/search/", Search) + r.Get("/search/", Search) // metrics - m.Get("/metrics/test", GetTestMetrics) + r.Get("/metrics/test", GetTestMetrics) }, reqSignedIn) // admin api - m.Group("/api/admin", func() { - m.Get("/accounts", AdminSearchAccounts) + r.Group("/api/admin", func() { + r.Get("/accounts", AdminSearchAccounts) }, reqAdmin) // rendering - m.Get("/render/*", reqSignedIn, RenderToPng) + r.Get("/render/*", reqSignedIn, RenderToPng) - m.NotFound(NotFound) + r.NotFound(NotFound) } func setIndexViewData(c *middleware.Context) error { diff --git a/pkg/api/collaborators.go b/pkg/api/collaborators.go index 178a78e0acd..3fd8e1dc77a 100644 --- a/pkg/api/collaborators.go +++ b/pkg/api/collaborators.go @@ -6,15 +6,9 @@ import ( m "github.com/torkelo/grafana-pro/pkg/models" ) -func AddCollaborator(c *middleware.Context) { - var cmd m.AddCollaboratorCommand +func AddCollaborator(c *middleware.Context, cmd m.AddCollaboratorCommand) { - if !c.JsonBody(&cmd) { - c.JsonApiErr(400, "Invalid request", nil) - return - } - - userQuery := m.GetAccountByLoginQuery{Login: cmd.Email} + userQuery := m.GetAccountByLoginQuery{LoginOrEmail: cmd.LoginOrEmail} err := bus.Dispatch(&userQuery) if err != nil { c.JsonApiErr(404, "Collaborator not found", nil) @@ -30,7 +24,6 @@ func AddCollaborator(c *middleware.Context) { cmd.AccountId = c.UserAccount.Id cmd.CollaboratorId = accountToAdd.Id - cmd.Role = m.ROLE_READ_WRITE err = bus.Dispatch(&cmd) if err != nil { diff --git a/pkg/api/login.go b/pkg/api/login.go index 23598ecc117..5a478ea13c2 100644 --- a/pkg/api/login.go +++ b/pkg/api/login.go @@ -23,7 +23,7 @@ func LoginPost(c *middleware.Context) { return } - userQuery := m.GetAccountByLoginQuery{Login: loginModel.Email} + userQuery := m.GetAccountByLoginQuery{LoginOrEmail: loginModel.Email} err := bus.Dispatch(&userQuery) if err != nil { diff --git a/pkg/api/login_oauth.go b/pkg/api/login_oauth.go index 4fab62dfea7..6dcba373eac 100644 --- a/pkg/api/login_oauth.go +++ b/pkg/api/login_oauth.go @@ -51,7 +51,7 @@ func OAuthLogin(ctx *middleware.Context) { log.Info("login.OAuthLogin(social login): %s", userInfo) - userQuery := m.GetAccountByLoginQuery{Login: userInfo.Email} + userQuery := m.GetAccountByLoginQuery{LoginOrEmail: userInfo.Email} err = bus.Dispatch(&userQuery) // create account if missing diff --git a/pkg/api/token.go b/pkg/api/token.go index 3805ab3e359..a09eb41d700 100644 --- a/pkg/api/token.go +++ b/pkg/api/token.go @@ -49,10 +49,10 @@ func AddToken(c *middleware.Context) { return } - if cmd.Role != m.ROLE_READ_WRITE && cmd.Role != m.ROLE_READ { - c.JsonApiErr(400, "Invalid role specified", nil) - return - } + // if cmd.Role != m.ROLE_READ_WRITE && cmd.Role != m.ROLE_READ { + // c.JsonApiErr(400, "Invalid role specified", nil) + // return + // } cmd.AccountId = c.Account.Id cmd.Token = util.GetRandomString(64) diff --git a/pkg/models/account.go b/pkg/models/account.go index 1f5e5d0c05c..ff499dd0fae 100644 --- a/pkg/models/account.go +++ b/pkg/models/account.go @@ -74,8 +74,8 @@ type GetAccountByIdQuery struct { } type GetAccountByLoginQuery struct { - Login string - Result *Account + LoginOrEmail string + Result *Account } type SearchAccountsQuery struct { diff --git a/pkg/models/collaborator.go b/pkg/models/collaborator.go index 2f6b2a17404..f536b5adc22 100644 --- a/pkg/models/collaborator.go +++ b/pkg/models/collaborator.go @@ -1,16 +1,32 @@ package models import ( + "errors" "time" ) -const ( - ROLE_READ_WRITE RoleType = "ReadWrite" - ROLE_READ = "Read" +// Typed errors +var ( + ErrInvalidRoleType = errors.New("Invalid role type") ) type RoleType string +const ( + ROLE_OWNER RoleType = "Owner" + ROLE_VIEWER RoleType = "Viewer" + ROLE_EDITOR RoleType = "Editor" + ROLE_ADMIN RoleType = "Admin" +) + +func (r RoleType) Validate() error { + if r == ROLE_OWNER || r == ROLE_VIEWER || r == ROLE_ADMIN || r == ROLE_EDITOR { + return nil + } + + return ErrInvalidRoleType +} + type Collaborator struct { Id int64 AccountId int64 `xorm:"not null unique(uix_account_id_for_account_id)"` @@ -21,16 +37,6 @@ type Collaborator struct { Updated time.Time } -func NewCollaborator(accountId int64, collaboratorId int64, role RoleType) *Collaborator { - return &Collaborator{ - AccountId: accountId, - CollaboratorId: collaboratorId, - Role: role, - Created: time.Now(), - Updated: time.Now(), - } -} - // --------------------- // COMMANDS @@ -40,10 +46,10 @@ type RemoveCollaboratorCommand struct { } type AddCollaboratorCommand struct { - Email string `json:"email" binding:"required"` + LoginOrEmail string `json:"loginOrEmail" binding:"Required"` + Role RoleType `json:"role" binding:"Required"` AccountId int64 `json:"-"` CollaboratorId int64 `json:"-"` - Role RoleType `json:"-"` } // ---------------------- diff --git a/pkg/services/sqlstore/accounts.go b/pkg/services/sqlstore/accounts.go index 6b4ceefbc30..700de6e0908 100644 --- a/pkg/services/sqlstore/accounts.go +++ b/pkg/services/sqlstore/accounts.go @@ -134,11 +134,15 @@ func GetAccountByToken(query *m.GetAccountByTokenQuery) error { } func GetAccountByLogin(query *m.GetAccountByLoginQuery) error { + if query.LoginOrEmail == "" { + return m.ErrAccountNotFound + } + account := new(m.Account) - if strings.Contains(query.Login, "@") { - account = &m.Account{Email: query.Login} + if strings.Contains(query.LoginOrEmail, "@") { + account = &m.Account{Email: query.LoginOrEmail} } else { - account = &m.Account{Login: strings.ToLower(query.Login)} + account = &m.Account{Login: strings.ToLower(query.LoginOrEmail)} } has, err := x.Get(account) diff --git a/pkg/services/sqlstore/accounts_test.go b/pkg/services/sqlstore/accounts_test.go index 2d0b87973cd..1372bae59b7 100644 --- a/pkg/services/sqlstore/accounts_test.go +++ b/pkg/services/sqlstore/accounts_test.go @@ -46,7 +46,7 @@ func TestAccountDataAccess(t *testing.T) { cmd := m.AddCollaboratorCommand{ AccountId: ac1.Id, CollaboratorId: ac2.Id, - Role: m.ROLE_READ_WRITE, + Role: m.ROLE_VIEWER, } err := AddCollaborator(&cmd) diff --git a/pkg/services/sqlstore/sqlstore.go b/pkg/services/sqlstore/sqlstore.go index c06b7124b50..de31d808129 100644 --- a/pkg/services/sqlstore/sqlstore.go +++ b/pkg/services/sqlstore/sqlstore.go @@ -45,7 +45,7 @@ func init() { } func EnsureAdminUser() { - adminQuery := m.GetAccountByLoginQuery{Login: setting.AdminUser} + adminQuery := m.GetAccountByLoginQuery{LoginOrEmail: setting.AdminUser} if err := bus.Dispatch(&adminQuery); err == m.ErrAccountNotFound { cmd := m.CreateAccountCommand{}