User / Account model split, User and account now seperate entities, collaborators are now AccountUsers

This commit is contained in:
Torkel Ödegaard
2015-01-19 18:01:04 +01:00
parent f1996a9f1f
commit 90925273a0
29 changed files with 592 additions and 705 deletions
-96
View File
@@ -1,96 +0,0 @@
package api
import (
"github.com/torkelo/grafana-pro/pkg/bus"
"github.com/torkelo/grafana-pro/pkg/middleware"
m "github.com/torkelo/grafana-pro/pkg/models"
)
func GetAccount(c *middleware.Context) {
query := m.GetAccountInfoQuery{Id: c.AccountId}
if err := bus.Dispatch(&query); err != nil {
c.JsonApiErr(500, "Failed to fetch collaboratos", err)
return
}
c.JSON(200, query.Result)
}
func UpdateAccount(c *middleware.Context, cmd m.UpdateAccountCommand) {
cmd.AccountId = c.AccountId
if err := bus.Dispatch(&cmd); err != nil {
c.JsonApiErr(400, "Failed to update account", nil)
return
}
c.JsonOK("Account updated")
}
func GetOtherAccounts(c *middleware.Context) {
query := m.GetOtherAccountsQuery{AccountId: c.AccountId}
if err := bus.Dispatch(&query); err != nil {
c.JsonApiErr(500, "Failed to get other accounts", err)
return
}
result := append(query.Result, &m.OtherAccountDTO{
AccountId: c.AccountId,
Role: m.ROLE_OWNER,
Email: c.UserEmail,
})
for _, ac := range result {
if ac.AccountId == c.UsingAccountId {
ac.IsUsing = true
break
}
}
c.JSON(200, result)
}
func validateUsingAccount(accountId int64, otherId int64) bool {
if accountId == otherId {
return true
}
query := m.GetOtherAccountsQuery{AccountId: accountId}
err := bus.Dispatch(&query)
if err != nil {
return false
}
// validate that the account id in the list
valid := false
for _, other := range query.Result {
if other.AccountId == otherId {
valid = true
}
}
return valid
}
func SetUsingAccount(c *middleware.Context) {
usingAccountId := c.ParamsInt64(":id")
if !validateUsingAccount(c.AccountId, usingAccountId) {
c.JsonApiErr(401, "Not a valid account", nil)
return
}
cmd := m.SetUsingAccountCommand{
AccountId: c.AccountId,
UsingAccountId: usingAccountId,
}
err := bus.Dispatch(&cmd)
if err != nil {
c.JsonApiErr(500, "Failed to update account", err)
return
}
c.JsonOK("Active account changed")
}
+61
View File
@@ -0,0 +1,61 @@
package api
import (
"github.com/torkelo/grafana-pro/pkg/bus"
"github.com/torkelo/grafana-pro/pkg/middleware"
m "github.com/torkelo/grafana-pro/pkg/models"
)
func AddAccountUser(c *middleware.Context, cmd m.AddAccountUserCommand) {
if !cmd.Role.IsValid() {
c.JsonApiErr(400, "Invalid role specified", nil)
return
}
userQuery := m.GetUserByLoginQuery{LoginOrEmail: cmd.LoginOrEmail}
err := bus.Dispatch(&userQuery)
if err != nil {
c.JsonApiErr(404, "User not found", nil)
return
}
userToAdd := userQuery.Result
if userToAdd.Id == c.UserId {
c.JsonApiErr(400, "Cannot add yourself as user", nil)
return
}
cmd.AccountId = c.AccountId
cmd.UserId = userToAdd.Id
if err := bus.Dispatch(&cmd); err != nil {
c.JsonApiErr(500, "Could not add user to account", err)
return
}
c.JsonOK("User added to account")
}
func GetAccountUsers(c *middleware.Context) {
query := m.GetAccountUsersQuery{AccountId: c.AccountId}
if err := bus.Dispatch(&query); err != nil {
c.JsonApiErr(500, "Failed to get account user", err)
return
}
c.JSON(200, query.Result)
}
func RemoveAccountUser(c *middleware.Context) {
userId := c.ParamsInt64(":id")
cmd := m.RemoveAccountUserCommand{AccountId: c.AccountId, UserId: userId}
if err := bus.Dispatch(&cmd); err != nil {
c.JsonApiErr(500, "Failed to remove user from account", err)
}
c.JsonOK("User removed from account")
}
@@ -6,11 +6,11 @@ import (
m "github.com/torkelo/grafana-pro/pkg/models"
)
func AdminSearchAccounts(c *middleware.Context) {
func AdminSearchUsers(c *middleware.Context) {
// query := c.QueryStrings("q")
// page := c.QueryStrings("p")
query := m.SearchAccountsQuery{Query: "", Page: 0, Limit: 20}
query := m.SearchUsersQuery{Query: "", Page: 0, Limit: 20}
if err := bus.Dispatch(&query); err != nil {
c.JsonApiErr(500, "Failed to fetch collaboratos", err)
return
+22 -15
View File
@@ -13,7 +13,7 @@ import (
func Register(r *macaron.Macaron) {
reqSignedIn := middleware.Auth(&middleware.AuthOptions{ReqSignedIn: true})
reqGrafanaAdmin := middleware.Auth(&middleware.AuthOptions{ReqSignedIn: true, ReqGrafanaAdmin: true})
reqEditorRole := middleware.RoleAuth(m.ROLE_EDITOR, m.ROLE_OWNER)
reqEditorRole := middleware.RoleAuth(m.ROLE_EDITOR, m.ROLE_ADMIN)
bind := binding.Bind
// not logged in views
@@ -24,6 +24,7 @@ func Register(r *macaron.Macaron) {
r.Get("/login", Index)
// authed views
r.Get("/user/", reqSignedIn, Index)
r.Get("/account/", reqSignedIn, Index)
r.Get("/account/datasources/", reqSignedIn, Index)
r.Get("/account/collaborators/", reqSignedIn, Index)
@@ -38,15 +39,21 @@ func Register(r *macaron.Macaron) {
// authed api
r.Group("/api", func() {
// user
r.Group("/user", func() {
r.Get("/", GetUser)
r.Post("/", bind(m.UpdateUserCommand{}), UpdateUser)
r.Post("/using/:id", SetUsingAccount)
r.Get("/accounts", GetUserAccounts)
})
// account
r.Group("/account", func() {
r.Get("/", GetAccount)
r.Post("/", bind(m.UpdateAccountCommand{}), 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)
//r.Get("/", GetAccount)
//r.Post("/", bind(m.UpdateAccountCommand{}), UpdateAccount)
r.Put("/users", bind(m.AddAccountUserCommand{}), AddAccountUser)
r.Get("/users", GetAccountUsers)
r.Delete("/users/:id", RemoveAccountUser)
})
// Token
r.Group("/tokens", func() {
@@ -75,7 +82,7 @@ func Register(r *macaron.Macaron) {
// admin api
r.Group("/api/admin", func() {
r.Get("/accounts", AdminSearchAccounts)
r.Get("/users", AdminSearchUsers)
}, reqGrafanaAdmin)
// rendering
@@ -94,13 +101,13 @@ func setIndexViewData(c *middleware.Context) error {
if c.IsSignedIn {
currentUser = &dtos.CurrentUser{
Login: c.UserLogin,
Email: c.UserEmail,
Name: c.UserName,
UsingAccountName: c.UsingAccountName,
GravatarUrl: dtos.GetGravatarUrl(c.UserEmail),
Login: c.Login,
Email: c.Email,
Name: c.Name,
UsingAccountName: c.AccountName,
GravatarUrl: dtos.GetGravatarUrl(c.Email),
IsGrafanaAdmin: c.IsGrafanaAdmin,
Role: c.UserRole,
Role: c.AccountRole,
}
}
-61
View File
@@ -1,61 +0,0 @@
package api
import (
"github.com/torkelo/grafana-pro/pkg/bus"
"github.com/torkelo/grafana-pro/pkg/middleware"
m "github.com/torkelo/grafana-pro/pkg/models"
)
func AddCollaborator(c *middleware.Context, cmd m.AddCollaboratorCommand) {
if !cmd.Role.IsValid() {
c.JsonApiErr(400, "Invalid role specified", nil)
return
}
userQuery := m.GetAccountByLoginQuery{LoginOrEmail: cmd.LoginOrEmail}
err := bus.Dispatch(&userQuery)
if err != nil {
c.JsonApiErr(404, "Collaborator not found", nil)
return
}
accountToAdd := userQuery.Result
if accountToAdd.Id == c.AccountId {
c.JsonApiErr(400, "Cannot add yourself as collaborator", nil)
return
}
cmd.AccountId = c.AccountId
cmd.CollaboratorId = accountToAdd.Id
err = bus.Dispatch(&cmd)
if err != nil {
c.JsonApiErr(500, "Could not add collaborator", err)
return
}
c.JsonOK("Collaborator added")
}
func GetCollaborators(c *middleware.Context) {
query := m.GetCollaboratorsQuery{AccountId: c.AccountId}
if err := bus.Dispatch(&query); err != nil {
c.JsonApiErr(500, "Failed to get collaborators", err)
return
}
c.JSON(200, query.Result)
}
func RemoveCollaborator(c *middleware.Context) {
collaboratorId := c.ParamsInt64(":id")
cmd := m.RemoveCollaboratorCommand{AccountId: c.AccountId, CollaboratorId: collaboratorId}
if err := bus.Dispatch(&cmd); err != nil {
c.JsonApiErr(500, "Failed to remove collaborator", err)
}
c.JsonOK("Collaborator removed")
}
+4 -4
View File
@@ -10,7 +10,7 @@ import (
func GetDashboard(c *middleware.Context) {
slug := c.Params(":slug")
query := m.GetDashboardQuery{Slug: slug, AccountId: c.UsingAccountId}
query := m.GetDashboardQuery{Slug: slug, AccountId: c.AccountId}
err := bus.Dispatch(&query)
if err != nil {
c.JsonApiErr(404, "Dashboard not found", nil)
@@ -25,13 +25,13 @@ func GetDashboard(c *middleware.Context) {
func DeleteDashboard(c *middleware.Context) {
slug := c.Params(":slug")
query := m.GetDashboardQuery{Slug: slug, AccountId: c.UsingAccountId}
query := m.GetDashboardQuery{Slug: slug, AccountId: c.AccountId}
if err := bus.Dispatch(&query); err != nil {
c.JsonApiErr(404, "Dashboard not found", nil)
return
}
cmd := m.DeleteDashboardCommand{Slug: slug, AccountId: c.UsingAccountId}
cmd := m.DeleteDashboardCommand{Slug: slug, AccountId: c.AccountId}
if err := bus.Dispatch(&cmd); err != nil {
c.JsonApiErr(500, "Failed to delete dashboard", err)
return
@@ -43,7 +43,7 @@ func DeleteDashboard(c *middleware.Context) {
}
func PostDashboard(c *middleware.Context, cmd m.SaveDashboardCommand) {
cmd.AccountId = c.UsingAccountId
cmd.AccountId = c.AccountId
err := bus.Dispatch(&cmd)
if err != nil {
+1 -1
View File
@@ -39,7 +39,7 @@ func ProxyDataSourceRequest(c *middleware.Context) {
query := m.GetDataSourceByIdQuery{
Id: id,
AccountId: c.UsingAccountId,
AccountId: c.AccountId,
}
err := bus.Dispatch(&query)
+4 -4
View File
@@ -8,7 +8,7 @@ import (
)
func GetDataSources(c *middleware.Context) {
query := m.GetDataSourcesQuery{AccountId: c.UsingAccountId}
query := m.GetDataSourcesQuery{AccountId: c.AccountId}
err := bus.Dispatch(&query)
if err != nil {
@@ -44,7 +44,7 @@ func DeleteDataSource(c *middleware.Context) {
return
}
cmd := &m.DeleteDataSourceCommand{Id: id, AccountId: c.UsingAccountId}
cmd := &m.DeleteDataSourceCommand{Id: id, AccountId: c.AccountId}
err := bus.Dispatch(cmd)
if err != nil {
@@ -63,7 +63,7 @@ func AddDataSource(c *middleware.Context) {
return
}
cmd.AccountId = c.UsingAccountId
cmd.AccountId = c.AccountId
if err := bus.Dispatch(&cmd); err != nil {
c.JsonApiErr(500, "Failed to add datasource", err)
@@ -81,7 +81,7 @@ func UpdateDataSource(c *middleware.Context) {
return
}
cmd.AccountId = c.UsingAccountId
cmd.AccountId = c.AccountId
err := bus.Dispatch(&cmd)
if err != nil {
+1 -1
View File
@@ -13,7 +13,7 @@ func getFrontendSettings(c *middleware.Context) (map[string]interface{}, error)
accountDataSources := make([]*m.DataSource, 0)
if c.IsSignedIn {
query := m.GetDataSourcesQuery{AccountId: c.UsingAccountId}
query := m.GetDataSourcesQuery{AccountId: c.AccountId}
err := bus.Dispatch(&query)
if err != nil {
+11 -11
View File
@@ -23,7 +23,7 @@ func LoginPost(c *middleware.Context) {
return
}
userQuery := m.GetAccountByLoginQuery{LoginOrEmail: loginModel.Email}
userQuery := m.GetUserByLoginQuery{LoginOrEmail: loginModel.Email}
err := bus.Dispatch(&userQuery)
if err != nil {
@@ -31,32 +31,32 @@ func LoginPost(c *middleware.Context) {
return
}
account := userQuery.Result
user := userQuery.Result
passwordHashed := util.EncodePassword(loginModel.Password, account.Salt)
if passwordHashed != account.Password {
passwordHashed := util.EncodePassword(loginModel.Password, user.Salt)
if passwordHashed != user.Password {
c.JsonApiErr(401, "Invalid username or password", err)
return
}
loginUserWithAccount(account, c)
loginUserWithUser(user, c)
var resp = &dtos.LoginResult{}
resp.Status = "Logged in"
resp.User.Login = account.Login
resp.User.Login = user.Login
c.JSON(200, resp)
}
func loginUserWithAccount(account *m.Account, c *middleware.Context) {
if account == nil {
log.Error(3, "Account login with nil account")
func loginUserWithUser(user *m.User, c *middleware.Context) {
if user == nil {
log.Error(3, "User login with nil user")
}
c.Session.Set("accountId", account.Id)
c.Session.Set("userId", user.Id)
}
func LogoutPost(c *middleware.Context) {
c.Session.Delete("accountId")
c.Session.Delete("userId")
c.JSON(200, util.DynMap{"status": "logged out"})
}
+4 -4
View File
@@ -51,12 +51,12 @@ func OAuthLogin(ctx *middleware.Context) {
log.Info("login.OAuthLogin(social login): %s", userInfo)
userQuery := m.GetAccountByLoginQuery{LoginOrEmail: userInfo.Email}
userQuery := m.GetUserByLoginQuery{LoginOrEmail: userInfo.Email}
err = bus.Dispatch(&userQuery)
// create account if missing
if err == m.ErrAccountNotFound {
cmd := m.CreateAccountCommand{
if err == m.ErrUserNotFound {
cmd := m.CreateUserCommand{
Login: userInfo.Email,
Email: userInfo.Email,
Name: userInfo.Name,
@@ -74,7 +74,7 @@ func OAuthLogin(ctx *middleware.Context) {
}
// login
loginUserWithAccount(userQuery.Result, ctx)
loginUserWithUser(userQuery.Result, ctx)
ctx.Redirect(setting.AppSubUrl + "/")
}
+1 -1
View File
@@ -10,7 +10,7 @@ import (
)
func RenderToPng(c *middleware.Context) {
accountId := c.UsingAccountId
accountId := c.AccountId
queryReader := util.NewUrlQueryReader(c.Req.URL)
queryParams := "?render=1&accountId=" + strconv.FormatInt(accountId, 10) + "&" + c.Req.URL.RawQuery
+1 -1
View File
@@ -31,7 +31,7 @@ func Search(c *middleware.Context) {
query := m.SearchDashboardsQuery{
Title: matches[3],
Tag: matches[2],
AccountId: c.UsingAccountId,
AccountId: c.AccountId,
}
err := bus.Dispatch(&query)
if err != nil {
+3 -3
View File
@@ -9,7 +9,7 @@ import (
// POST /api/account/signup
func SignUp(c *middleware.Context) {
var cmd m.CreateAccountCommand
var cmd m.CreateUserCommand
if !c.JsonBody(&cmd) {
c.JsonApiErr(400, "Validation error", nil)
@@ -21,9 +21,9 @@ func SignUp(c *middleware.Context) {
cmd.Password = util.EncodePassword(cmd.Password, cmd.Salt)
if err := bus.Dispatch(&cmd); err != nil {
c.JsonApiErr(500, "failed to create account", err)
c.JsonApiErr(500, "failed to create user", err)
return
}
c.JsonOK("Account created")
c.JsonOK("User created")
}
+86
View File
@@ -0,0 +1,86 @@
package api
import (
"github.com/torkelo/grafana-pro/pkg/bus"
"github.com/torkelo/grafana-pro/pkg/middleware"
m "github.com/torkelo/grafana-pro/pkg/models"
)
func GetUser(c *middleware.Context) {
query := m.GetUserInfoQuery{UserId: c.UserId}
if err := bus.Dispatch(&query); err != nil {
c.JsonApiErr(500, "Failed to get account", err)
return
}
c.JSON(200, query.Result)
}
func UpdateUser(c *middleware.Context, cmd m.UpdateUserCommand) {
cmd.UserId = c.UserId
if err := bus.Dispatch(&cmd); err != nil {
c.JsonApiErr(400, "Failed to update account", err)
return
}
c.JsonOK("Account updated")
}
func GetUserAccounts(c *middleware.Context) {
query := m.GetUserAccountsQuery{UserId: c.UserId}
if err := bus.Dispatch(&query); err != nil {
c.JsonApiErr(500, "Failed to get user accounts", err)
return
}
for _, ac := range query.Result {
if ac.AccountId == c.AccountId {
ac.IsUsing = true
break
}
}
c.JSON(200, query.Result)
}
func validateUsingAccount(userId int64, accountId int64) bool {
query := m.GetUserAccountsQuery{UserId: userId}
if err := bus.Dispatch(&query); err != nil {
return false
}
// validate that the account id in the list
valid := false
for _, other := range query.Result {
if other.AccountId == accountId {
valid = true
}
}
return valid
}
func SetUsingAccount(c *middleware.Context) {
usingAccountId := c.ParamsInt64(":id")
if !validateUsingAccount(c.AccountId, usingAccountId) {
c.JsonApiErr(401, "Not a valid account", nil)
return
}
cmd := m.SetUsingAccountCommand{
UserId: c.UserId,
AccountId: usingAccountId,
}
if err := bus.Dispatch(&cmd); err != nil {
c.JsonApiErr(500, "Failed change active account", err)
return
}
c.JsonOK("Active account changed")
}