Selaa lähdekoodia

More work on collaborators, and sql store

Torkel Ödegaard 11 vuotta sitten
vanhempi
commit
f04932aa67

+ 7 - 5
pkg/models/account.go

@@ -6,11 +6,13 @@ import (
 )
 
 var (
-	CreateAccount       func(acccount *Account) error
-	UpdateAccount       func(acccount *Account) error
-	GetAccountByLogin   func(emailOrName string) (*Account, error)
-	GetAccount          func(accountId int64) (*Account, error)
-	GetOtherAccountsFor func(accountId int64) ([]*OtherAccount, error)
+	CreateAccount              func(acccount *Account) error
+	UpdateAccount              func(acccount *Account) error
+	GetAccountByLogin          func(emailOrName string) (*Account, error)
+	GetAccount                 func(accountId int64) (*Account, error)
+	GetOtherAccountsFor        func(accountId int64) ([]*OtherAccount, error)
+	GetCollaboratorsForAccount func(accountId int64) ([]*CollaboratorInfo, error)
+	AddCollaborator            func(collaborator *Collaborator) error
 )
 
 // Typed errors

+ 38 - 0
pkg/models/collaborator.go

@@ -0,0 +1,38 @@
+package models
+
+import (
+	"time"
+)
+
+const (
+	ROLE_READ_WRITE = "ReadWrite"
+	ROLE_READ       = "Read"
+)
+
+type RoleType string
+
+type Collaborator struct {
+	Id           int64
+	AccountId    int64    `xorm:"not null unique(uix_account_id_for_account_id)"` // The account that can use another account
+	Role         RoleType `xorm:"not null"`                                       // Permission type
+	ForAccountId int64    `xorm:"not null unique(uix_account_id_for_account_id)"` // The account being given access to
+	Created      time.Time
+	Updated      time.Time
+}
+
+// read only projection
+type CollaboratorInfo struct {
+	AccountId int64
+	Role      string
+	Email     string
+}
+
+func NewCollaborator(accountId int64, forAccountId int64) *Collaborator {
+	return &Collaborator{
+		AccountId:    accountId,
+		ForAccountId: forAccountId,
+		Role:         ROLE_READ,
+		Created:      time.Now(),
+		Updated:      time.Now(),
+	}
+}

+ 62 - 0
pkg/routes/api/api_account.go

@@ -0,0 +1,62 @@
+package api
+
+import (
+	"github.com/torkelo/grafana-pro/pkg/middleware"
+	"github.com/torkelo/grafana-pro/pkg/models"
+	"github.com/torkelo/grafana-pro/pkg/routes/dtos"
+	"github.com/torkelo/grafana-pro/pkg/utils"
+)
+
+func GetAccount(c *middleware.Context) {
+	model := dtos.AccountInfo{
+		Name:  c.UserAccount.Name,
+		Email: c.UserAccount.Email,
+	}
+
+	collaborators, err := models.GetCollaboratorsForAccount(c.UserAccount.Id)
+	if err != nil {
+		c.JsonApiErr(500, "Failed to fetch collaboratos", err)
+		return
+	}
+
+	for _, collaborator := range collaborators {
+		model.Collaborators = append(model.Collaborators, &dtos.Collaborator{
+			AccountId: collaborator.AccountId,
+			Role:      collaborator.Role,
+			Email:     collaborator.Email,
+		})
+	}
+
+	c.JSON(200, model)
+}
+
+func AddCollaborator(c *middleware.Context) {
+	var model dtos.AddCollaboratorCommand
+
+	if !c.JsonBody(&model) {
+		c.JSON(400, utils.DynMap{"message": "Invalid request"})
+		return
+	}
+
+	accountToAdd, err := models.GetAccountByLogin(model.Email)
+	if err != nil {
+		c.JSON(404, utils.DynMap{"message": "Collaborator not found"})
+		return
+	}
+
+	if accountToAdd.Id == c.UserAccount.Id {
+		c.JSON(400, utils.DynMap{"message": "Cannot add yourself as collaborator"})
+		return
+	}
+
+	var collaborator = models.NewCollaborator(accountToAdd.Id, c.UserAccount.Id)
+	collaborator.Role = models.ROLE_READ_WRITE
+
+	err = models.AddCollaborator(collaborator)
+	if err != nil {
+		c.JSON(400, utils.DynMap{"message": err.Error()})
+		return
+	}
+
+	c.Status(204)
+}

+ 2 - 2
pkg/routes/api/api_dashboard.go

@@ -3,7 +3,7 @@ package api
 import (
 	"github.com/torkelo/grafana-pro/pkg/middleware"
 	"github.com/torkelo/grafana-pro/pkg/models"
-	"github.com/torkelo/grafana-pro/pkg/routes/apimodel"
+	"github.com/torkelo/grafana-pro/pkg/routes/dtos"
 	"github.com/torkelo/grafana-pro/pkg/utils"
 )
 
@@ -63,7 +63,7 @@ func convertToStringArray(arr []interface{}) []string {
 }
 
 func PostDashboard(c *middleware.Context) {
-	var command apimodel.SaveDashboardCommand
+	var command dtos.SaveDashboardCommand
 
 	if !c.JsonBody(&command) {
 		c.JsonApiErr(400, "bad request", nil)

+ 23 - 7
pkg/routes/apimodel/models.go → pkg/routes/dtos/models.go

@@ -1,4 +1,4 @@
-package apimodel
+package dtos
 
 import (
 	"crypto/md5"
@@ -8,19 +8,35 @@ import (
 	"github.com/torkelo/grafana-pro/pkg/models"
 )
 
-type LoginResultDto struct {
-	Status string         `json:"status"`
-	User   CurrentUserDto `json:"user"`
+type LoginResult struct {
+	Status string      `json:"status"`
+	User   CurrentUser `json:"user"`
 }
 
-type CurrentUserDto struct {
+type CurrentUser struct {
 	Login       string `json:"login"`
 	Email       string `json:"email"`
 	GravatarUrl string `json:"gravatarUrl"`
 }
 
-func NewCurrentUserDto(account *models.Account) *CurrentUserDto {
-	model := &CurrentUserDto{}
+type AccountInfo struct {
+	Email         string          `json:"email"`
+	Name          string          `json:"name"`
+	Collaborators []*Collaborator `json:"collaborators"`
+}
+
+type Collaborator struct {
+	AccountId int64  `json:"accountId"`
+	Email     string `json:"email"`
+	Role      string `json:"role"`
+}
+
+type AddCollaboratorCommand struct {
+	Email string `json:"email" binding:"required"`
+}
+
+func NewCurrentUser(account *models.Account) *CurrentUser {
+	model := &CurrentUser{}
 	if account != nil {
 		model.Login = account.Login
 		model.Email = account.Email

+ 7 - 2
pkg/routes/index.go

@@ -4,7 +4,7 @@ import (
 	"github.com/Unknwon/macaron"
 	"github.com/torkelo/grafana-pro/pkg/middleware"
 	"github.com/torkelo/grafana-pro/pkg/routes/api"
-	"github.com/torkelo/grafana-pro/pkg/routes/apimodel"
+	"github.com/torkelo/grafana-pro/pkg/routes/dtos"
 	"github.com/torkelo/grafana-pro/pkg/routes/login"
 )
 
@@ -20,6 +20,11 @@ func Register(m *macaron.Macaron) {
 	m.Get("/login", Index)
 	m.Get("/login/:name", login.OAuthLogin)
 
+	// account
+	m.Get("/account/", auth, Index)
+	m.Get("/api/account/", auth, api.GetAccount)
+	m.Post("/api/account/collaborators/add", auth, api.AddCollaborator)
+
 	// user register
 	m.Get("/register/*_", Index)
 	m.Post("/api/account", api.CreateAccount)
@@ -36,7 +41,7 @@ func Register(m *macaron.Macaron) {
 }
 
 func Index(ctx *middleware.Context) {
-	ctx.Data["User"] = apimodel.NewCurrentUserDto(ctx.UserAccount)
+	ctx.Data["User"] = dtos.NewCurrentUser(ctx.UserAccount)
 	ctx.HTML(200, "index")
 }
 

+ 7 - 7
pkg/routes/login/login.go

@@ -1,11 +1,11 @@
 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"
+	"github.com/torkelo/grafana-pro/pkg/routes/dtos"
+	"github.com/torkelo/grafana-pro/pkg/utils"
 )
 
 type loginJsonModel struct {
@@ -18,24 +18,24 @@ func LoginPost(c *middleware.Context) {
 	var loginModel loginJsonModel
 
 	if !c.JsonBody(&loginModel) {
-		c.JSON(400, gin.H{"status": "bad request"})
+		c.JSON(400, utils.DynMap{"status": "bad request"})
 		return
 	}
 
 	account, err := models.GetAccountByLogin(loginModel.Email)
 	if err != nil {
-		c.JSON(401, gin.H{"status": "unauthorized"})
+		c.JSON(401, utils.DynMap{"status": "unauthorized"})
 		return
 	}
 
 	if loginModel.Password != account.Password {
-		c.JSON(401, gin.H{"status": "unauthorized"})
+		c.JSON(401, utils.DynMap{"status": "unauthorized"})
 		return
 	}
 
 	loginUserWithAccount(account, c)
 
-	var resp = &apimodel.LoginResultDto{}
+	var resp = &dtos.LoginResult{}
 	resp.Status = "Logged in"
 	resp.User.Login = account.Login
 
@@ -52,5 +52,5 @@ func loginUserWithAccount(account *models.Account, c *middleware.Context) {
 
 func LogoutPost(c *middleware.Context) {
 	c.Session.Delete("accountId")
-	c.JSON(200, gin.H{"status": "logged out"})
+	c.JSON(200, utils.DynMap{"status": "logged out"})
 }

+ 3 - 1
pkg/stores/sqlstore/sqlstore.go

@@ -27,7 +27,7 @@ var (
 )
 
 func Init() {
-	tables = append(tables, new(models.Account), new(models.Dashboard))
+	tables = append(tables, new(models.Account), new(models.Dashboard), new(models.Collaborator))
 
 	models.CreateAccount = CreateAccount
 	models.GetAccount = GetAccount
@@ -36,6 +36,8 @@ func Init() {
 	models.SaveDashboard = SaveDashboard
 	models.SearchQuery = SearchQuery
 	models.DeleteDashboard = DeleteDashboard
+	models.GetCollaboratorsForAccount = GetCollaboratorsForAccount
+	models.AddCollaborator = AddCollaborator
 }
 
 func LoadModelsConfig() {

+ 28 - 0
pkg/stores/sqlstore/sqlstore_accounts.go

@@ -57,3 +57,31 @@ func GetAccountByLogin(emailOrLogin string) (*models.Account, error) {
 
 	return account, nil
 }
+
+func GetCollaboratorsForAccount(accountId int64) ([]*models.CollaboratorInfo, error) {
+	collaborators := make([]*models.CollaboratorInfo, 0)
+	sess := x.Table("Collaborator")
+	sess.Join("INNER", "Account", "Account.id=Collaborator.account_Id")
+	err := sess.Find(&collaborators)
+	return collaborators, err
+}
+
+func AddCollaborator(collaborator *models.Collaborator) error {
+	var err error
+
+	sess := x.NewSession()
+	defer sess.Close()
+
+	if err = sess.Begin(); err != nil {
+		return err
+	}
+
+	if _, err = sess.Insert(collaborator); err != nil {
+		sess.Rollback()
+		return err
+	} else if err = sess.Commit(); err != nil {
+		return err
+	}
+
+	return nil
+}