Commit 22156fe3 by Torkel Ödegaard

Big refactoring for context.User, and how current user info is fetching, now…

Big refactoring for context.User, and how current user info is fetching, now included collaborator role
parent 52992928
Subproject commit aaa717aac2c1f5e440d61cbe08e55357b4d2570b
Subproject commit 9637efd5eed391f36603bf4674d84ceec2c6e647
......@@ -7,7 +7,7 @@ import (
)
func GetAccount(c *middleware.Context) {
query := m.GetAccountInfoQuery{Id: c.UserAccount.Id}
query := m.GetAccountInfoQuery{Id: c.AccountId}
err := bus.Dispatch(&query)
if err != nil {
......@@ -26,7 +26,7 @@ func UpdateAccount(c *middleware.Context) {
return
}
cmd.AccountId = c.UserAccount.Id
cmd.AccountId = c.AccountId
if err := bus.Dispatch(&cmd); err != nil {
c.JsonApiErr(400, "Failed to update account", nil)
......@@ -37,7 +37,7 @@ func UpdateAccount(c *middleware.Context) {
}
func GetOtherAccounts(c *middleware.Context) {
query := m.GetOtherAccountsQuery{AccountId: c.UserAccount.Id}
query := m.GetOtherAccountsQuery{AccountId: c.AccountId}
err := bus.Dispatch(&query)
if err != nil {
......@@ -46,13 +46,13 @@ func GetOtherAccounts(c *middleware.Context) {
}
result := append(query.Result, &m.OtherAccountDTO{
AccountId: c.UserAccount.Id,
Role: "owner",
Email: c.UserAccount.Email,
AccountId: c.AccountId,
Role: m.ROLE_OWNER,
Email: c.UserEmail,
})
for _, ac := range result {
if ac.AccountId == c.UserAccount.UsingAccountId {
if ac.AccountId == c.UsingAccountId {
ac.IsUsing = true
break
}
......@@ -85,13 +85,13 @@ func validateUsingAccount(accountId int64, otherId int64) bool {
func SetUsingAccount(c *middleware.Context) {
usingAccountId := c.ParamsInt64(":id")
if !validateUsingAccount(c.UserAccount.Id, usingAccountId) {
if !validateUsingAccount(c.AccountId, usingAccountId) {
c.JsonApiErr(401, "Not a valid account", nil)
return
}
cmd := m.SetUsingAccountCommand{
AccountId: c.UserAccount.Id,
AccountId: c.AccountId,
UsingAccountId: usingAccountId,
}
......
......@@ -12,7 +12,7 @@ import (
// Register adds http routes
func Register(r *macaron.Macaron) {
reqSignedIn := middleware.Auth(&middleware.AuthOptions{ReqSignedIn: true})
reqAdmin := middleware.Auth(&middleware.AuthOptions{ReqSignedIn: true, ReqAdmin: true})
reqGrafanaAdmin := middleware.Auth(&middleware.AuthOptions{ReqSignedIn: true, ReqGrafanaAdmin: true})
bind := binding.Bind
// not logged in views
......@@ -63,7 +63,7 @@ func Register(r *macaron.Macaron) {
// Dashboard
r.Group("/dashboard", func() {
r.Combo("/:slug").Get(GetDashboard).Delete(DeleteDashboard)
r.Post("/", PostDashboard)
r.Post("/", bind(m.SaveDashboardCommand{}), PostDashboard)
})
// Search
r.Get("/search/", Search)
......@@ -74,7 +74,7 @@ func Register(r *macaron.Macaron) {
// admin api
r.Group("/api/admin", func() {
r.Get("/accounts", AdminSearchAccounts)
}, reqAdmin)
}, reqGrafanaAdmin)
// rendering
r.Get("/render/*", reqSignedIn, RenderToPng)
......@@ -88,7 +88,21 @@ func setIndexViewData(c *middleware.Context) error {
return err
}
c.Data["User"] = dtos.NewCurrentUser(c.UserAccount)
currentUser := &dtos.CurrentUser{}
if c.IsSignedIn {
currentUser = &dtos.CurrentUser{
Login: c.UserLogin,
Email: c.UserEmail,
Name: c.UserName,
UsingAccountName: c.UsingAccountName,
GravatarUrl: dtos.GetGravatarUrl(c.UserEmail),
IsGrafanaAdmin: c.IsGrafanaAdmin,
Role: c.UserRole,
}
}
c.Data["User"] = currentUser
c.Data["Settings"] = settings
c.Data["AppUrl"] = setting.AppUrl
c.Data["AppSubUrl"] = setting.AppSubUrl
......
......@@ -21,12 +21,12 @@ func AddCollaborator(c *middleware.Context, cmd m.AddCollaboratorCommand) {
accountToAdd := userQuery.Result
if accountToAdd.Id == c.UserAccount.Id {
if accountToAdd.Id == c.AccountId {
c.JsonApiErr(400, "Cannot add yourself as collaborator", nil)
return
}
cmd.AccountId = c.UserAccount.Id
cmd.AccountId = c.AccountId
cmd.CollaboratorId = accountToAdd.Id
err = bus.Dispatch(&cmd)
......@@ -39,7 +39,7 @@ func AddCollaborator(c *middleware.Context, cmd m.AddCollaboratorCommand) {
}
func GetCollaborators(c *middleware.Context) {
query := m.GetCollaboratorsQuery{AccountId: c.UserAccount.Id}
query := m.GetCollaboratorsQuery{AccountId: c.AccountId}
if err := bus.Dispatch(&query); err != nil {
c.JsonApiErr(500, "Failed to get collaborators", err)
return
......@@ -51,7 +51,7 @@ func GetCollaborators(c *middleware.Context) {
func RemoveCollaborator(c *middleware.Context) {
collaboratorId := c.ParamsInt64(":id")
cmd := m.RemoveCollaboratorCommand{AccountId: c.UserAccount.Id, CollaboratorId: collaboratorId}
cmd := m.RemoveCollaboratorCommand{AccountId: c.AccountId, CollaboratorId: collaboratorId}
if err := bus.Dispatch(&cmd); err != nil {
c.JsonApiErr(500, "Failed to remove collaborator", err)
......
......@@ -10,7 +10,7 @@ import (
func GetDashboard(c *middleware.Context) {
slug := c.Params(":slug")
query := m.GetDashboardQuery{Slug: slug, AccountId: c.GetAccountId()}
query := m.GetDashboardQuery{Slug: slug, AccountId: c.UsingAccountId}
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.GetAccountId()}
query := m.GetDashboardQuery{Slug: slug, AccountId: c.UsingAccountId}
if err := bus.Dispatch(&query); err != nil {
c.JsonApiErr(404, "Dashboard not found", nil)
return
}
cmd := m.DeleteDashboardCommand{Slug: slug, AccountId: c.GetAccountId()}
cmd := m.DeleteDashboardCommand{Slug: slug, AccountId: c.UsingAccountId}
if err := bus.Dispatch(&cmd); err != nil {
c.JsonApiErr(500, "Failed to delete dashboard", err)
return
......@@ -42,15 +42,8 @@ func DeleteDashboard(c *middleware.Context) {
c.JSON(200, resp)
}
func PostDashboard(c *middleware.Context) {
var cmd m.SaveDashboardCommand
if !c.JsonBody(&cmd) {
c.JsonApiErr(400, "bad request", nil)
return
}
cmd.AccountId = c.GetAccountId()
func PostDashboard(c *middleware.Context, cmd m.SaveDashboardCommand) {
cmd.AccountId = c.UsingAccountId
err := bus.Dispatch(&cmd)
if err != nil {
......
......@@ -39,7 +39,7 @@ func ProxyDataSourceRequest(c *middleware.Context) {
query := m.GetDataSourceByIdQuery{
Id: id,
AccountId: c.GetAccountId(),
AccountId: c.UsingAccountId,
}
err := bus.Dispatch(&query)
......
......@@ -8,7 +8,7 @@ import (
)
func GetDataSources(c *middleware.Context) {
query := m.GetDataSourcesQuery{AccountId: c.Account.Id}
query := m.GetDataSourcesQuery{AccountId: c.UsingAccountId}
err := bus.Dispatch(&query)
if err != nil {
......@@ -44,7 +44,7 @@ func DeleteDataSource(c *middleware.Context) {
return
}
cmd := &m.DeleteDataSourceCommand{Id: id, AccountId: c.UserAccount.Id}
cmd := &m.DeleteDataSourceCommand{Id: id, AccountId: c.UsingAccountId}
err := bus.Dispatch(cmd)
if err != nil {
......@@ -63,7 +63,7 @@ func AddDataSource(c *middleware.Context) {
return
}
cmd.AccountId = c.Account.Id
cmd.AccountId = c.UsingAccountId
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.Account.Id
cmd.AccountId = c.UsingAccountId
err := bus.Dispatch(&cmd)
if err != nil {
......
......@@ -5,7 +5,7 @@ import (
"fmt"
"strings"
"github.com/torkelo/grafana-pro/pkg/models"
m "github.com/torkelo/grafana-pro/pkg/models"
)
type LoginResult struct {
......@@ -14,24 +14,27 @@ type LoginResult struct {
}
type CurrentUser struct {
Login string `json:"login"`
Email string `json:"email"`
IsAdmin bool `json:"isAdmin"`
GravatarUrl string `json:"gravatarUrl"`
Login string `json:"login"`
Email string `json:"email"`
Role m.RoleType `json:"role"`
Name string `json:"name"`
UsingAccountName string `json:"usingAccountName"`
IsGrafanaAdmin bool `json:"isGrafanaAdmin"`
GravatarUrl string `json:"gravatarUrl"`
}
type DataSource struct {
Id int64 `json:"id"`
AccountId int64 `json:"accountId"`
Name string `json:"name"`
Type models.DsType `json:"type"`
Access models.DsAccess `json:"access"`
Url string `json:"url"`
Password string `json:"password"`
User string `json:"user"`
Database string `json:"database"`
BasicAuth bool `json:"basicAuth"`
IsDefault bool `json:"isDefault"`
Id int64 `json:"id"`
AccountId int64 `json:"accountId"`
Name string `json:"name"`
Type m.DsType `json:"type"`
Access m.DsAccess `json:"access"`
Url string `json:"url"`
Password string `json:"password"`
User string `json:"user"`
Database string `json:"database"`
BasicAuth bool `json:"basicAuth"`
IsDefault bool `json:"isDefault"`
}
type MetricQueryResultDto struct {
......@@ -43,18 +46,11 @@ type MetricQueryResultDataDto struct {
DataPoints [][2]float64 `json:"datapoints"`
}
func NewCurrentUser(account *models.Account) *CurrentUser {
model := &CurrentUser{}
if account != nil {
model.Login = account.Login
model.Email = account.Email
model.GravatarUrl = getGravatarUrl(account.Email)
model.IsAdmin = account.IsAdmin
func GetGravatarUrl(text string) string {
if text == "" {
return ""
}
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))
......
......@@ -12,8 +12,8 @@ import (
func getFrontendSettings(c *middleware.Context) (map[string]interface{}, error) {
accountDataSources := make([]*m.DataSource, 0)
if c.Account != nil {
query := m.GetDataSourcesQuery{AccountId: c.Account.Id}
if c.IsSignedIn {
query := m.GetDataSourcesQuery{AccountId: c.UsingAccountId}
err := bus.Dispatch(&query)
if err != nil {
......
......@@ -10,7 +10,7 @@ import (
)
func RenderToPng(c *middleware.Context) {
accountId := c.GetAccountId()
accountId := c.UsingAccountId
queryReader := util.NewUrlQueryReader(c.Req.URL)
queryParams := "?render&accountId=" + strconv.FormatInt(accountId, 10) + "&" + c.Req.URL.RawQuery
......
......@@ -31,7 +31,7 @@ func Search(c *middleware.Context) {
query := m.SearchDashboardsQuery{
Title: matches[3],
Tag: matches[2],
AccountId: c.GetAccountId(),
AccountId: c.UsingAccountId,
}
err := bus.Dispatch(&query)
if err != nil {
......
......@@ -8,7 +8,7 @@ import (
)
func GetTokens(c *middleware.Context) {
query := m.GetTokensQuery{AccountId: c.UserAccount.Id}
query := m.GetTokensQuery{AccountId: c.AccountId}
err := bus.Dispatch(&query)
if err != nil {
......@@ -30,7 +30,7 @@ func GetTokens(c *middleware.Context) {
func DeleteToken(c *middleware.Context) {
id := c.ParamsInt64(":id")
cmd := &m.DeleteTokenCommand{Id: id, AccountId: c.UserAccount.Id}
cmd := &m.DeleteTokenCommand{Id: id, AccountId: c.AccountId}
err := bus.Dispatch(cmd)
if err != nil {
......@@ -47,7 +47,7 @@ func AddToken(c *middleware.Context, cmd m.AddTokenCommand) {
return
}
cmd.AccountId = c.UserAccount.Id
cmd.AccountId = c.AccountId
cmd.Token = util.GetRandomString(64)
if err := bus.Dispatch(&cmd); err != nil {
......@@ -71,7 +71,7 @@ func UpdateToken(c *middleware.Context, cmd m.UpdateTokenCommand) {
return
}
cmd.AccountId = c.UserAccount.Id
cmd.AccountId = c.AccountId
err := bus.Dispatch(&cmd)
if err != nil {
......
......@@ -13,8 +13,8 @@ import (
)
type AuthOptions struct {
ReqAdmin bool
ReqSignedIn bool
ReqGrafanaAdmin bool
ReqSignedIn bool
}
func getRequestAccountId(c *Context) (int64, error) {
......@@ -68,7 +68,7 @@ func Auth(options *AuthOptions) macaron.Handler {
return
}
if !c.IsAdmin && options.ReqAdmin {
if !c.IsGrafanaAdmin && options.ReqGrafanaAdmin {
authDenied(c)
return
}
......
......@@ -16,17 +16,11 @@ import (
type Context struct {
*macaron.Context
*m.SignInUser
Session session.Store
IsSignedIn bool
IsAdmin bool
Account *m.Account
UserAccount *m.Account
}
func (c *Context) GetAccountId() int64 {
return c.Account.Id
}
func GetContextHandler() macaron.Handler {
......@@ -38,27 +32,15 @@ func GetContextHandler() macaron.Handler {
// try get account id from request
if accountId, err := getRequestAccountId(ctx); err == nil {
// fetch user
userQuery := m.GetAccountByIdQuery{Id: accountId}
if err := bus.Dispatch(&userQuery); err != nil {
query := m.GetSignedInUserQuery{AccountId: accountId}
if err := bus.Dispatch(&query); err != nil {
log.Error(3, "Failed to get user by id, %v, %v", accountId, err)
} else {
// fetch using account
ctx.UserAccount = userQuery.Result
usingQuery := m.GetAccountByIdQuery{Id: ctx.UserAccount.UsingAccountId}
if err := bus.Dispatch(&usingQuery); err != nil {
log.Error(3, "Faild to get account's using account, account: %v, usingAccountId: %v, err:%v", accountId, ctx.UserAccount.Id, err)
} else {
ctx.Account = usingQuery.Result
}
ctx.IsSignedIn = true
ctx.SignInUser = query.Result
}
}
if ctx.Account != nil {
ctx.IsSignedIn = true
ctx.IsAdmin = ctx.Account.IsAdmin
}
c.Map(ctx)
}
}
......
......@@ -85,14 +85,29 @@ type SearchAccountsQuery struct {
Result []*AccountSearchHitDTO
}
type GetSignedInUserQuery struct {
AccountId int64
Result *SignInUser
}
// ------------------------
// DTO & Projections
type SignInUser struct {
AccountId int64
UsingAccountId int64
UsingAccountName string
UserRole RoleType
UserLogin string
UserName string
UserEmail string
IsGrafanaAdmin bool
}
type OtherAccountDTO struct {
AccountId int64 `json:"accountId"`
Email string `json:"email"`
Role string `json:"role"`
IsUsing bool `json:"isUsing"`
AccountId int64 `json:"accountId"`
Email string `json:"email"`
Role RoleType `json:"role"`
IsUsing bool `json:"isUsing"`
}
type AccountSearchHitDTO struct {
......
......@@ -20,6 +20,7 @@ func init() {
bus.AddHandler("sql", GetAccountByToken)
bus.AddHandler("sql", SearchAccounts)
bus.AddHandler("sql", UpdateAccount)
bus.AddHandler("sql", GetSignedInUser)
}
func CreateAccount(cmd *m.CreateAccountCommand) error {
......@@ -27,6 +28,7 @@ func CreateAccount(cmd *m.CreateAccountCommand) error {
account := m.Account{
Email: cmd.Email,
Name: cmd.Name,
Login: cmd.Login,
Password: cmd.Password,
Salt: cmd.Salt,
......@@ -180,5 +182,38 @@ func SearchAccounts(query *m.SearchAccountsQuery) error {
sess.Cols("id", "email", "name", "login", "is_admin")
err := sess.Find(&query.Result)
return err
}
func GetSignedInUser(query *m.GetSignedInUserQuery) error {
var rawSql = `SELECT
userAccount.id as account_id,
userAccount.is_admin as is_grafana_admin,
userAccount.email as user_email,
userAccount.name as user_name,
userAccount.login as user_login,
usingAccount.id as using_account_id,
usingAccount.name as using_account_name,
collaborator.role as user_role
FROM account as userAccount
LEFT OUTER JOIN account as usingAccount on usingAccount.id = userAccount.using_account_id
LEFT OUTER JOIN collaborator on collaborator.account_id = usingAccount.id AND collaborator.collaborator_id = userAccount.id
WHERE userAccount.id=?`
var user m.SignInUser
sess := x.Table("account")
has, err := sess.Sql(rawSql, query.AccountId).Get(&user)
if err != nil {
return err
} else if !has {
return m.ErrAccountNotFound
}
if user.UsingAccountId == 0 || user.UsingAccountId == user.AccountId {
user.UsingAccountId = query.AccountId
user.UsingAccountName = user.UserName
user.UserRole = m.ROLE_OWNER
}
query.Result = &user
return err
}
......@@ -14,8 +14,8 @@ func TestAccountDataAccess(t *testing.T) {
InitTestDB(t)
Convey("Given two saved accounts", func() {
ac1cmd := m.CreateAccountCommand{Login: "ac1", Email: "ac1@test.com"}
ac2cmd := m.CreateAccountCommand{Login: "ac2", Email: "ac2@test.com"}
ac1cmd := m.CreateAccountCommand{Login: "ac1", Email: "ac1@test.com", Name: "ac1 name"}
ac2cmd := m.CreateAccountCommand{Login: "ac2", Email: "ac2@test.com", Name: "ac2 name", IsAdmin: true}
err := CreateAccount(&ac1cmd)
err = CreateAccount(&ac2cmd)
......@@ -42,7 +42,7 @@ func TestAccountDataAccess(t *testing.T) {
So(query.Result[1].Email, ShouldEqual, "ac2@test.com")
})
Convey("Can add collaborator", func() {
Convey("Given an added collaborator", func() {
cmd := m.AddCollaboratorCommand{
AccountId: ac1.Id,
CollaboratorId: ac2.Id,
......@@ -50,10 +50,25 @@ func TestAccountDataAccess(t *testing.T) {
}
err := AddCollaborator(&cmd)
Convey("Saved without error", func() {
Convey("Should have been saved without error", func() {
So(err, ShouldBeNil)
})
Convey("Can get logged in user projection", func() {
query := m.GetSignedInUserQuery{AccountId: ac2.Id}
err := GetSignedInUser(&query)
So(err, ShouldBeNil)
So(query.Result.AccountId, ShouldEqual, ac2.Id)
So(query.Result.UserEmail, ShouldEqual, "ac2@test.com")
So(query.Result.UserName, ShouldEqual, "ac2 name")
So(query.Result.UserLogin, ShouldEqual, "ac2")
So(query.Result.UserRole, ShouldEqual, "Owner")
So(query.Result.UsingAccountName, ShouldEqual, "ac2 name")
So(query.Result.UsingAccountId, ShouldEqual, ac2.Id)
So(query.Result.IsGrafanaAdmin, ShouldBeTrue)
})
Convey("Can get other accounts", func() {
query := m.GetOtherAccountsQuery{AccountId: ac2.Id}
err := GetOtherAccounts(&query)
......@@ -66,6 +81,20 @@ func TestAccountDataAccess(t *testing.T) {
cmd := m.SetUsingAccountCommand{AccountId: ac2.Id, UsingAccountId: ac1.Id}
err := SetUsingAccount(&cmd)
So(err, ShouldBeNil)
Convey("Logged in user query should return correct using account info", func() {
query := m.GetSignedInUserQuery{AccountId: ac2.Id}
err := GetSignedInUser(&query)
So(err, ShouldBeNil)
So(query.Result.AccountId, ShouldEqual, ac2.Id)
So(query.Result.UserEmail, ShouldEqual, "ac2@test.com")
So(query.Result.UserName, ShouldEqual, "ac2 name")
So(query.Result.UserLogin, ShouldEqual, "ac2")
So(query.Result.UsingAccountName, ShouldEqual, "ac1 name")
So(query.Result.UsingAccountId, ShouldEqual, ac1.Id)
So(query.Result.UserRole, ShouldEqual, "Viewer")
})
})
})
})
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment