Selaa lähdekoodia

Big Backend Refatoring: Renamed Account -> Org

Torkel Ödegaard 10 vuotta sitten
vanhempi
commit
26e4809e2e

+ 3 - 3
main.go

@@ -32,9 +32,9 @@ func main() {
 	app.Usage = "grafana web"
 	app.Version = version
 	app.Commands = []cli.Command{
-		cmd.ListAccounts,
-		cmd.CreateAccount,
-		cmd.DeleteAccount,
+		cmd.ListOrgs,
+		cmd.CreateOrg,
+		cmd.DeleteOrg,
 		cmd.ImportDashboard,
 		cmd.ListDataSources,
 		cmd.CreateDataSource,

+ 0 - 50
pkg/api/account.go

@@ -1,50 +0,0 @@
-package api
-
-import (
-	"github.com/grafana/grafana/pkg/bus"
-	"github.com/grafana/grafana/pkg/middleware"
-	m "github.com/grafana/grafana/pkg/models"
-)
-
-func GetOrg(c *middleware.Context) {
-	query := m.GetAccountByIdQuery{Id: c.AccountId}
-
-	if err := bus.Dispatch(&query); err != nil {
-		if err == m.ErrAccountNotFound {
-			c.JsonApiErr(404, "Account not found", err)
-			return
-		}
-
-		c.JsonApiErr(500, "Failed to get account", err)
-		return
-	}
-
-	account := m.AccountDTO{
-		Id:   query.Result.Id,
-		Name: query.Result.Name,
-	}
-
-	c.JSON(200, &account)
-}
-
-func CreateOrg(c *middleware.Context, cmd m.CreateAccountCommand) {
-	cmd.UserId = c.UserId
-
-	if err := bus.Dispatch(&cmd); err != nil {
-		c.JsonApiErr(500, "Failed to create account", err)
-		return
-	}
-
-	c.JsonOK("Account created")
-}
-
-func UpdateOrg(c *middleware.Context, cmd m.UpdateAccountCommand) {
-	cmd.AccountId = c.AccountId
-
-	if err := bus.Dispatch(&cmd); err != nil {
-		c.JsonApiErr(500, "Failed to update account", err)
-		return
-	}
-
-	c.JsonOK("Account updated")
-}

+ 5 - 5
pkg/api/api.go

@@ -46,8 +46,8 @@ func Register(r *macaron.Macaron) {
 		r.Group("/user", func() {
 			r.Get("/", GetUser)
 			r.Put("/", bind(m.UpdateUserCommand{}), UpdateUser)
-			r.Post("/using/:id", SetUsingAccount)
-			r.Get("/accounts", GetUserAccounts)
+			r.Post("/using/:id", UserSetUsingOrg)
+			r.Get("/orgs", GetUserOrgList)
 			r.Post("/stars/dashboard/:id", StarDashboard)
 			r.Delete("/stars/dashboard/:id", UnstarDashboard)
 			r.Put("/password", bind(m.ChangeUserPasswordCommand{}), ChangeUserPassword)
@@ -56,9 +56,9 @@ func Register(r *macaron.Macaron) {
 		// account
 		r.Group("/org", func() {
 			r.Get("/", GetOrg)
-			r.Post("/", bind(m.CreateAccountCommand{}), CreateOrg)
-			r.Put("/", bind(m.UpdateAccountCommand{}), UpdateOrg)
-			r.Post("/users", bind(m.AddAccountUserCommand{}), AddOrgUser)
+			r.Post("/", bind(m.CreateOrgCommand{}), CreateOrg)
+			r.Put("/", bind(m.UpdateOrgCommand{}), UpdateOrg)
+			r.Post("/users", bind(m.AddOrgUserCommand{}), AddOrgUser)
 			r.Get("/users", GetOrgUsers)
 			r.Delete("/users/:id", RemoveOrgUser)
 		}, reqAccountAdmin)

+ 4 - 4
pkg/api/apikey.go

@@ -8,7 +8,7 @@ import (
 )
 
 func GetApiKeys(c *middleware.Context) {
-	query := m.GetApiKeysQuery{AccountId: c.AccountId}
+	query := m.GetApiKeysQuery{OrgId: c.OrgId}
 
 	if err := bus.Dispatch(&query); err != nil {
 		c.JsonApiErr(500, "Failed to list api keys", err)
@@ -30,7 +30,7 @@ func GetApiKeys(c *middleware.Context) {
 func DeleteApiKey(c *middleware.Context) {
 	id := c.ParamsInt64(":id")
 
-	cmd := &m.DeleteApiKeyCommand{Id: id, AccountId: c.AccountId}
+	cmd := &m.DeleteApiKeyCommand{Id: id, OrgId: c.OrgId}
 
 	err := bus.Dispatch(cmd)
 	if err != nil {
@@ -47,7 +47,7 @@ func AddApiKey(c *middleware.Context, cmd m.AddApiKeyCommand) {
 		return
 	}
 
-	cmd.AccountId = c.AccountId
+	cmd.OrgId = c.OrgId
 	cmd.Key = util.GetRandomString(64)
 
 	if err := bus.Dispatch(&cmd); err != nil {
@@ -71,7 +71,7 @@ func UpdateApiKey(c *middleware.Context, cmd m.UpdateApiKeyCommand) {
 		return
 	}
 
-	cmd.AccountId = c.AccountId
+	cmd.OrgId = c.OrgId
 
 	err := bus.Dispatch(&cmd)
 	if err != nil {

+ 4 - 4
pkg/api/dashboard.go

@@ -29,7 +29,7 @@ func isDasboardStarredByUser(c *middleware.Context, dashId int64) (bool, error)
 func GetDashboard(c *middleware.Context) {
 	slug := c.Params(":slug")
 
-	query := m.GetDashboardQuery{Slug: slug, AccountId: c.AccountId}
+	query := m.GetDashboardQuery{Slug: slug, OrgId: c.OrgId}
 	err := bus.Dispatch(&query)
 	if err != nil {
 		c.JsonApiErr(404, "Dashboard not found", nil)
@@ -54,13 +54,13 @@ func GetDashboard(c *middleware.Context) {
 func DeleteDashboard(c *middleware.Context) {
 	slug := c.Params(":slug")
 
-	query := m.GetDashboardQuery{Slug: slug, AccountId: c.AccountId}
+	query := m.GetDashboardQuery{Slug: slug, OrgId: c.OrgId}
 	if err := bus.Dispatch(&query); err != nil {
 		c.JsonApiErr(404, "Dashboard not found", nil)
 		return
 	}
 
-	cmd := m.DeleteDashboardCommand{Slug: slug, AccountId: c.AccountId}
+	cmd := m.DeleteDashboardCommand{Slug: slug, OrgId: c.OrgId}
 	if err := bus.Dispatch(&cmd); err != nil {
 		c.JsonApiErr(500, "Failed to delete dashboard", err)
 		return
@@ -72,7 +72,7 @@ func DeleteDashboard(c *middleware.Context) {
 }
 
 func PostDashboard(c *middleware.Context, cmd m.SaveDashboardCommand) {
-	cmd.AccountId = c.AccountId
+	cmd.OrgId = c.OrgId
 
 	err := bus.Dispatch(&cmd)
 	if err != nil {

+ 2 - 2
pkg/api/dataproxy.go

@@ -39,8 +39,8 @@ func ProxyDataSourceRequest(c *middleware.Context) {
 	id := c.ParamsInt64(":id")
 
 	query := m.GetDataSourceByIdQuery{
-		Id:        id,
-		AccountId: c.AccountId,
+		Id:    id,
+		OrgId: c.OrgId,
 	}
 
 	err := bus.Dispatch(&query)

+ 8 - 8
pkg/api/datasources.go

@@ -8,7 +8,7 @@ import (
 )
 
 func GetDataSources(c *middleware.Context) {
-	query := m.GetDataSourcesQuery{AccountId: c.AccountId}
+	query := m.GetDataSourcesQuery{OrgId: c.OrgId}
 
 	if err := bus.Dispatch(&query); err != nil {
 		c.JsonApiErr(500, "Failed to query datasources", err)
@@ -19,7 +19,7 @@ func GetDataSources(c *middleware.Context) {
 	for i, ds := range query.Result {
 		result[i] = &dtos.DataSource{
 			Id:        ds.Id,
-			AccountId: ds.AccountId,
+			OrgId:     ds.OrgId,
 			Name:      ds.Name,
 			Url:       ds.Url,
 			Type:      ds.Type,
@@ -37,8 +37,8 @@ func GetDataSources(c *middleware.Context) {
 
 func GetDataSourceById(c *middleware.Context) {
 	query := m.GetDataSourceByIdQuery{
-		Id:        c.ParamsInt64(":id"),
-		AccountId: c.AccountId,
+		Id:    c.ParamsInt64(":id"),
+		OrgId: c.OrgId,
 	}
 
 	if err := bus.Dispatch(&query); err != nil {
@@ -50,7 +50,7 @@ func GetDataSourceById(c *middleware.Context) {
 
 	c.JSON(200, &dtos.DataSource{
 		Id:        ds.Id,
-		AccountId: ds.AccountId,
+		OrgId:     ds.OrgId,
 		Name:      ds.Name,
 		Url:       ds.Url,
 		Type:      ds.Type,
@@ -71,7 +71,7 @@ func DeleteDataSource(c *middleware.Context) {
 		return
 	}
 
-	cmd := &m.DeleteDataSourceCommand{Id: id, AccountId: c.AccountId}
+	cmd := &m.DeleteDataSourceCommand{Id: id, OrgId: c.OrgId}
 
 	err := bus.Dispatch(cmd)
 	if err != nil {
@@ -90,7 +90,7 @@ func AddDataSource(c *middleware.Context) {
 		return
 	}
 
-	cmd.AccountId = c.AccountId
+	cmd.OrgId = c.OrgId
 
 	if err := bus.Dispatch(&cmd); err != nil {
 		c.JsonApiErr(500, "Failed to add datasource", err)
@@ -108,7 +108,7 @@ func UpdateDataSource(c *middleware.Context) {
 		return
 	}
 
-	cmd.AccountId = c.AccountId
+	cmd.OrgId = c.OrgId
 
 	err := bus.Dispatch(&cmd)
 	if err != nil {

+ 3 - 3
pkg/api/dtos/models.go

@@ -19,8 +19,8 @@ type CurrentUser struct {
 	Login          string     `json:"login"`
 	Email          string     `json:"email"`
 	Name           string     `json:"name"`
-	AccountRole    m.RoleType `json:"accountRole"`
-	AccountName    string     `json:"accountName"`
+	OrgRole        m.RoleType `json:"orgRole"`
+	OrgName        string     `json:"orgName"`
 	IsGrafanaAdmin bool       `json:"isGrafanaAdmin"`
 	GravatarUrl    string     `json:"gravatarUrl"`
 }
@@ -38,7 +38,7 @@ type Dashboard struct {
 
 type DataSource struct {
 	Id        int64      `json:"id"`
-	AccountId int64      `json:"accountId"`
+	OrgId     int64      `json:"orgId"`
 	Name      string     `json:"name"`
 	Type      m.DsType   `json:"type"`
 	Access    m.DsAccess `json:"access"`

+ 4 - 4
pkg/api/frontendsettings.go

@@ -10,22 +10,22 @@ import (
 )
 
 func getFrontendSettingsMap(c *middleware.Context) (map[string]interface{}, error) {
-	accountDataSources := make([]*m.DataSource, 0)
+	orgDataSources := make([]*m.DataSource, 0)
 
 	if c.IsSignedIn {
-		query := m.GetDataSourcesQuery{AccountId: c.AccountId}
+		query := m.GetDataSourcesQuery{OrgId: c.OrgId}
 		err := bus.Dispatch(&query)
 
 		if err != nil {
 			return nil, err
 		}
 
-		accountDataSources = query.Result
+		orgDataSources = query.Result
 	}
 
 	datasources := make(map[string]interface{})
 
-	for _, ds := range accountDataSources {
+	for _, ds := range orgDataSources {
 		url := ds.Url
 
 		if ds.Access == m.DS_ACCESS_PROXY {

+ 2 - 2
pkg/api/index.go

@@ -17,8 +17,8 @@ func setIndexViewData(c *middleware.Context) error {
 		Login:          c.Login,
 		Email:          c.Email,
 		Name:           c.Name,
-		AccountName:    c.AccountName,
-		AccountRole:    c.AccountRole,
+		OrgName:        c.OrgName,
+		OrgRole:        c.OrgRole,
 		GravatarUrl:    dtos.GetGravatarUrl(c.Email),
 		IsGrafanaAdmin: c.IsGrafanaAdmin,
 	}

+ 50 - 0
pkg/api/org.go

@@ -0,0 +1,50 @@
+package api
+
+import (
+	"github.com/grafana/grafana/pkg/bus"
+	"github.com/grafana/grafana/pkg/middleware"
+	m "github.com/grafana/grafana/pkg/models"
+)
+
+func GetOrg(c *middleware.Context) {
+	query := m.GetOrgByIdQuery{Id: c.OrgId}
+
+	if err := bus.Dispatch(&query); err != nil {
+		if err == m.ErrOrgNotFound {
+			c.JsonApiErr(404, "Organization not found", err)
+			return
+		}
+
+		c.JsonApiErr(500, "Failed to get organization", err)
+		return
+	}
+
+	org := m.OrgDTO{
+		Id:   query.Result.Id,
+		Name: query.Result.Name,
+	}
+
+	c.JSON(200, &org)
+}
+
+func CreateOrg(c *middleware.Context, cmd m.CreateOrgCommand) {
+	cmd.UserId = c.UserId
+
+	if err := bus.Dispatch(&cmd); err != nil {
+		c.JsonApiErr(500, "Failed to create organization", err)
+		return
+	}
+
+	c.JsonOK("Organization created")
+}
+
+func UpdateOrg(c *middleware.Context, cmd m.UpdateOrgCommand) {
+	cmd.OrgId = c.OrgId
+
+	if err := bus.Dispatch(&cmd); err != nil {
+		c.JsonApiErr(500, "Failed to update organization", err)
+		return
+	}
+
+	c.JsonOK("Organization updated")
+}

+ 10 - 10
pkg/api/account_users.go → pkg/api/org_users.go

@@ -6,7 +6,7 @@ import (
 	m "github.com/grafana/grafana/pkg/models"
 )
 
-func AddOrgUser(c *middleware.Context, cmd m.AddAccountUserCommand) {
+func AddOrgUser(c *middleware.Context, cmd m.AddOrgUserCommand) {
 	if !cmd.Role.IsValid() {
 		c.JsonApiErr(400, "Invalid role specified", nil)
 		return
@@ -26,19 +26,19 @@ func AddOrgUser(c *middleware.Context, cmd m.AddAccountUserCommand) {
 		return
 	}
 
-	cmd.AccountId = c.AccountId
+	cmd.OrgId = c.OrgId
 	cmd.UserId = userToAdd.Id
 
 	if err := bus.Dispatch(&cmd); err != nil {
-		c.JsonApiErr(500, "Could not add user to account", err)
+		c.JsonApiErr(500, "Could not add user to organization", err)
 		return
 	}
 
-	c.JsonOK("User added to account")
+	c.JsonOK("User added to organization")
 }
 
 func GetOrgUsers(c *middleware.Context) {
-	query := m.GetAccountUsersQuery{AccountId: c.AccountId}
+	query := m.GetOrgUsersQuery{OrgId: c.OrgId}
 
 	if err := bus.Dispatch(&query); err != nil {
 		c.JsonApiErr(500, "Failed to get account user", err)
@@ -51,15 +51,15 @@ func GetOrgUsers(c *middleware.Context) {
 func RemoveOrgUser(c *middleware.Context) {
 	userId := c.ParamsInt64(":id")
 
-	cmd := m.RemoveAccountUserCommand{AccountId: c.AccountId, UserId: userId}
+	cmd := m.RemoveOrgUserCommand{OrgId: c.OrgId, UserId: userId}
 
 	if err := bus.Dispatch(&cmd); err != nil {
-		if err == m.ErrLastAccountAdmin {
-			c.JsonApiErr(400, "Cannot remove last account admin", nil)
+		if err == m.ErrLastOrgAdmin {
+			c.JsonApiErr(400, "Cannot remove last organization admin", nil)
 			return
 		}
-		c.JsonApiErr(500, "Failed to remove user from account", err)
+		c.JsonApiErr(500, "Failed to remove user from organization", err)
 	}
 
-	c.JsonOK("User removed from account")
+	c.JsonOK("User removed from organization")
 }

+ 2 - 2
pkg/api/search.go

@@ -44,7 +44,7 @@ func Search(c *middleware.Context) {
 
 	if tagcloud == "true" {
 
-		query := m.GetDashboardTagsQuery{AccountId: c.AccountId}
+		query := m.GetDashboardTagsQuery{OrgId: c.OrgId}
 		err := bus.Dispatch(&query)
 		if err != nil {
 			c.JsonApiErr(500, "Failed to get tags from database", err)
@@ -60,7 +60,7 @@ func Search(c *middleware.Context) {
 			UserId:    c.UserId,
 			Limit:     limit,
 			IsStarred: starred == "true",
-			AccountId: c.AccountId,
+			OrgId:     c.OrgId,
 		}
 
 		err := bus.Dispatch(&query)

+ 20 - 20
pkg/api/user.go

@@ -11,7 +11,7 @@ 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)
+		c.JsonApiErr(500, "Failed to get user", err)
 		return
 	}
 
@@ -22,23 +22,23 @@ 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)
+		c.JsonApiErr(400, "Failed to update user", err)
 		return
 	}
 
-	c.JsonOK("Account updated")
+	c.JsonOK("User updated")
 }
 
-func GetUserAccounts(c *middleware.Context) {
-	query := m.GetUserAccountsQuery{UserId: c.UserId}
+func GetUserOrgList(c *middleware.Context) {
+	query := m.GetUserOrgListQuery{UserId: c.UserId}
 
 	if err := bus.Dispatch(&query); err != nil {
-		c.JsonApiErr(500, "Failed to get user accounts", err)
+		c.JsonApiErr(500, "Failed to get user organizations", err)
 		return
 	}
 
 	for _, ac := range query.Result {
-		if ac.AccountId == c.AccountId {
+		if ac.OrgId == c.OrgId {
 			ac.IsUsing = true
 			break
 		}
@@ -47,17 +47,17 @@ func GetUserAccounts(c *middleware.Context) {
 	c.JSON(200, query.Result)
 }
 
-func validateUsingAccount(userId int64, accountId int64) bool {
-	query := m.GetUserAccountsQuery{UserId: userId}
+func validateUsingOrg(userId int64, orgId int64) bool {
+	query := m.GetUserOrgListQuery{UserId: userId}
 
 	if err := bus.Dispatch(&query); err != nil {
 		return false
 	}
 
-	// validate that the account id in the list
+	// validate that the org id in the list
 	valid := false
 	for _, other := range query.Result {
-		if other.AccountId == accountId {
+		if other.OrgId == orgId {
 			valid = true
 		}
 	}
@@ -65,25 +65,25 @@ func validateUsingAccount(userId int64, accountId int64) bool {
 	return valid
 }
 
-func SetUsingAccount(c *middleware.Context) {
-	usingAccountId := c.ParamsInt64(":id")
+func UserSetUsingOrg(c *middleware.Context) {
+	orgId := c.ParamsInt64(":id")
 
-	if !validateUsingAccount(c.UserId, usingAccountId) {
-		c.JsonApiErr(401, "Not a valid account", nil)
+	if !validateUsingOrg(c.UserId, orgId) {
+		c.JsonApiErr(401, "Not a valid organization", nil)
 		return
 	}
 
-	cmd := m.SetUsingAccountCommand{
-		UserId:    c.UserId,
-		AccountId: usingAccountId,
+	cmd := m.SetUsingOrgCommand{
+		UserId: c.UserId,
+		OrgId:  orgId,
 	}
 
 	if err := bus.Dispatch(&cmd); err != nil {
-		c.JsonApiErr(500, "Failed change active account", err)
+		c.JsonApiErr(500, "Failed change active organization", err)
 		return
 	}
 
-	c.JsonOK("Active account changed")
+	c.JsonOK("Active organization changed")
 }
 
 func ChangeUserPassword(c *middleware.Context, cmd m.ChangeUserPasswordCommand) {

+ 0 - 99
pkg/cmd/accounts.go

@@ -1,99 +0,0 @@
-package cmd
-
-import (
-	"fmt"
-	"os"
-	"text/tabwriter"
-
-	"github.com/codegangsta/cli"
-
-	"github.com/grafana/grafana/pkg/bus"
-	"github.com/grafana/grafana/pkg/log"
-	m "github.com/grafana/grafana/pkg/models"
-	"github.com/grafana/grafana/pkg/setting"
-)
-
-var ListAccounts = cli.Command{
-	Name:        "accounts",
-	Usage:       "list accounts",
-	Description: "Lists the accounts in the system",
-	Action:      listAccounts,
-}
-
-var CreateAccount = cli.Command{
-	Name:        "accounts:create",
-	Usage:       "create a new account",
-	Description: "Creates a new account",
-	Action:      createAccount,
-}
-
-var DeleteAccount = cli.Command{
-	Name:        "accounts:delete",
-	Usage:       "delete an existing account",
-	Description: "Deletes an existing account",
-	Action:      deleteAccount,
-}
-
-func listAccounts(c *cli.Context) {
-	initRuntime(c)
-
-	accountsQuery := m.GetAccountsQuery{}
-	if err := bus.Dispatch(&accountsQuery); err != nil {
-		log.ConsoleFatalf("Failed to find accounts: %s", err)
-	}
-
-	w := tabwriter.NewWriter(os.Stdout, 8, 1, 4, ' ', 0)
-
-	fmt.Fprintf(w, "ID\tNAME\n")
-	for _, account := range accountsQuery.Result {
-		fmt.Fprintf(w, "%d\t%s\n", account.Id, account.Name)
-	}
-	w.Flush()
-}
-
-func createAccount(c *cli.Context) {
-	initRuntime(c)
-
-	if !c.Args().Present() {
-		log.ConsoleFatal("Account name arg is required")
-	}
-
-	name := c.Args().First()
-
-	adminQuery := m.GetUserByLoginQuery{LoginOrEmail: setting.AdminUser}
-
-	if err := bus.Dispatch(&adminQuery); err == m.ErrUserNotFound {
-		log.ConsoleFatalf("Failed to find default admin user: %s", err)
-	}
-
-	adminUser := adminQuery.Result
-
-	cmd := m.CreateAccountCommand{Name: name, UserId: adminUser.Id}
-	if err := bus.Dispatch(&cmd); err != nil {
-		log.ConsoleFatalf("Failed to create account: %s", err)
-	}
-
-	log.ConsoleInfof("Account %s created for admin user %s\n", name, adminUser.Email)
-}
-
-func deleteAccount(c *cli.Context) {
-	initRuntime(c)
-
-	if !c.Args().Present() {
-		log.ConsoleFatal("Account name arg is required")
-	}
-
-	name := c.Args().First()
-	accountQuery := m.GetAccountByNameQuery{Name: name}
-	if err := bus.Dispatch(&accountQuery); err != nil {
-		log.ConsoleFatalf("Failed to find account: %s", err)
-	}
-
-	accountId := accountQuery.Result.Id
-	cmd := m.DeleteAccountCommand{Id: accountId}
-	if err := bus.Dispatch(&cmd); err != nil {
-		log.ConsoleFatalf("Failed to delete account: %s", err)
-	}
-
-	log.ConsoleInfof("Account %s deleted", name)
-}

+ 8 - 8
pkg/cmd/dashboard.go

@@ -41,19 +41,19 @@ func runImport(c *cli.Context) {
 	}
 
 	if !c.Args().Present() {
-		log.ConsoleFatal("Account name arg is required")
+		log.ConsoleFatal("Organization name arg is required")
 	}
 
-	accountName := c.Args().First()
+	orgName := c.Args().First()
 
 	initRuntime(c)
 
-	accountQuery := m.GetAccountByNameQuery{Name: accountName}
-	if err := bus.Dispatch(&accountQuery); err != nil {
+	orgQuery := m.GetOrgByNameQuery{Name: orgName}
+	if err := bus.Dispatch(&orgQuery); err != nil {
 		log.ConsoleFatalf("Failed to find account", err)
 	}
 
-	accountId := accountQuery.Result.Id
+	orgId := orgQuery.Result.Id
 
 	visitor := func(path string, f os.FileInfo, err error) error {
 		if err != nil {
@@ -63,7 +63,7 @@ func runImport(c *cli.Context) {
 			return nil
 		}
 		if strings.HasSuffix(f.Name(), ".json") {
-			if err := importDashboard(path, accountId); err != nil {
+			if err := importDashboard(path, orgId); err != nil {
 				log.ConsoleFatalf("Failed to import dashboard file: %v,  err: %v", path, err)
 			}
 		}
@@ -75,7 +75,7 @@ func runImport(c *cli.Context) {
 	}
 }
 
-func importDashboard(path string, accountId int64) error {
+func importDashboard(path string, orgId int64) error {
 	log.ConsoleInfof("Importing %v", path)
 
 	reader, err := os.Open(path)
@@ -92,7 +92,7 @@ func importDashboard(path string, accountId int64) error {
 	dash.Data["id"] = nil
 
 	cmd := m.SaveDashboardCommand{
-		AccountId: accountId,
+		OrgId:     orgId,
 		Dashboard: dash.Data,
 	}
 

+ 23 - 23
pkg/cmd/datasource.go

@@ -81,14 +81,14 @@ func createDataSource(c *cli.Context) {
 	dsAccess := c.String("access")
 	dsDefault := c.Bool("default")
 
-	accountQuery := m.GetAccountByNameQuery{Name: name}
-	if err := bus.Dispatch(&accountQuery); err != nil {
-		log.ConsoleFatalf("Failed to find account: %s", err)
+	orgQuery := m.GetOrgByNameQuery{Name: name}
+	if err := bus.Dispatch(&orgQuery); err != nil {
+		log.ConsoleFatalf("Failed to find organization: %s", err)
 	}
 
-	accountId := accountQuery.Result.Id
+	orgId := orgQuery.Result.Id
 
-	query := m.GetDataSourceByNameQuery{AccountId: accountId, Name: ds}
+	query := m.GetDataSourceByNameQuery{OrgId: orgId, Name: ds}
 	if err := bus.Dispatch(&query); err != nil {
 		if err != m.ErrDataSourceNotFound {
 			log.ConsoleFatalf("Failed to query for existing datasource: %s", err)
@@ -100,7 +100,7 @@ func createDataSource(c *cli.Context) {
 	}
 
 	cmd := m.AddDataSourceCommand{
-		AccountId: accountId,
+		OrgId:     orgId,
 		Name:      ds,
 		Url:       url,
 		Type:      m.DsType(dsType),
@@ -135,14 +135,14 @@ func listDatasources(c *cli.Context) {
 	}
 
 	name := c.Args().First()
-	accountQuery := m.GetAccountByNameQuery{Name: name}
-	if err := bus.Dispatch(&accountQuery); err != nil {
-		log.ConsoleFatalf("Failed to find account: %s", err)
+	orgQuery := m.GetOrgByNameQuery{Name: name}
+	if err := bus.Dispatch(&orgQuery); err != nil {
+		log.ConsoleFatalf("Failed to find organization: %s", err)
 	}
 
-	accountId := accountQuery.Result.Id
+	orgId := orgQuery.Result.Id
 
-	query := m.GetDataSourcesQuery{AccountId: accountId}
+	query := m.GetDataSourcesQuery{OrgId: orgId}
 	if err := bus.Dispatch(&query); err != nil {
 		log.ConsoleFatalf("Failed to find datasources: %s", err)
 	}
@@ -161,20 +161,20 @@ func describeDataSource(c *cli.Context) {
 	initRuntime(c)
 
 	if len(c.Args()) != 2 {
-		log.ConsoleFatal("Account and datasource name args are required")
+		log.ConsoleFatal("Organization and datasource name args are required")
 	}
 
 	name := c.Args().First()
 	ds := c.Args()[1]
 
-	accountQuery := m.GetAccountByNameQuery{Name: name}
-	if err := bus.Dispatch(&accountQuery); err != nil {
-		log.ConsoleFatalf("Failed to find account: %s", err)
+	orgQuery := m.GetOrgByNameQuery{Name: name}
+	if err := bus.Dispatch(&orgQuery); err != nil {
+		log.ConsoleFatalf("Failed to find organization: %s", err)
 	}
 
-	accountId := accountQuery.Result.Id
+	orgId := orgQuery.Result.Id
 
-	query := m.GetDataSourceByNameQuery{AccountId: accountId, Name: ds}
+	query := m.GetDataSourceByNameQuery{OrgId: orgId, Name: ds}
 	if err := bus.Dispatch(&query); err != nil {
 		log.ConsoleFatalf("Failed to find datasource: %s", err)
 	}
@@ -208,20 +208,20 @@ func deleteDataSource(c *cli.Context) {
 	name := c.Args().First()
 	ds := c.Args()[1]
 
-	accountQuery := m.GetAccountByNameQuery{Name: name}
-	if err := bus.Dispatch(&accountQuery); err != nil {
-		log.ConsoleFatalf("Failed to find account: %s", err)
+	orgQuery := m.GetOrgByNameQuery{Name: name}
+	if err := bus.Dispatch(&orgQuery); err != nil {
+		log.ConsoleFatalf("Failed to find organization: %s", err)
 	}
 
-	accountId := accountQuery.Result.Id
+	orgId := orgQuery.Result.Id
 
-	query := m.GetDataSourceByNameQuery{AccountId: accountId, Name: ds}
+	query := m.GetDataSourceByNameQuery{OrgId: orgId, Name: ds}
 	if err := bus.Dispatch(&query); err != nil {
 		log.ConsoleFatalf("Failed to find datasource: %s", err)
 	}
 	datasource := query.Result
 
-	cmd := m.DeleteDataSourceCommand{AccountId: accountId, Id: datasource.Id}
+	cmd := m.DeleteDataSourceCommand{OrgId: orgId, Id: datasource.Id}
 	if err := bus.Dispatch(&cmd); err != nil {
 		log.ConsoleFatalf("Failed to delete datasource: %s", err)
 	}

+ 99 - 0
pkg/cmd/orgs.go

@@ -0,0 +1,99 @@
+package cmd
+
+import (
+	"fmt"
+	"os"
+	"text/tabwriter"
+
+	"github.com/codegangsta/cli"
+
+	"github.com/grafana/grafana/pkg/bus"
+	"github.com/grafana/grafana/pkg/log"
+	m "github.com/grafana/grafana/pkg/models"
+	"github.com/grafana/grafana/pkg/setting"
+)
+
+var ListOrgs = cli.Command{
+	Name:        "orgs",
+	Usage:       "list organizations",
+	Description: "Lists the organizations in the system",
+	Action:      listOrgs,
+}
+
+var CreateOrg = cli.Command{
+	Name:        "orgs:create",
+	Usage:       "Creates a new organization",
+	Description: "Creates a new organization",
+	Action:      createOrg,
+}
+
+var DeleteOrg = cli.Command{
+	Name:        "orgs:delete",
+	Usage:       "Delete an existing organization",
+	Description: "Deletes an existing organization",
+	Action:      deleteOrg,
+}
+
+func listOrgs(c *cli.Context) {
+	initRuntime(c)
+
+	orgsQuery := m.GetOrgListQuery{}
+	if err := bus.Dispatch(&orgsQuery); err != nil {
+		log.ConsoleFatalf("Failed to find organizations: %s", err)
+	}
+
+	w := tabwriter.NewWriter(os.Stdout, 8, 1, 4, ' ', 0)
+
+	fmt.Fprintf(w, "ID\tNAME\n")
+	for _, org := range orgsQuery.Result {
+		fmt.Fprintf(w, "%d\t%s\n", org.Id, org.Name)
+	}
+	w.Flush()
+}
+
+func createOrg(c *cli.Context) {
+	initRuntime(c)
+
+	if !c.Args().Present() {
+		log.ConsoleFatal("Organization name arg is required")
+	}
+
+	name := c.Args().First()
+
+	adminQuery := m.GetUserByLoginQuery{LoginOrEmail: setting.AdminUser}
+
+	if err := bus.Dispatch(&adminQuery); err == m.ErrUserNotFound {
+		log.ConsoleFatalf("Failed to find default admin user: %s", err)
+	}
+
+	adminUser := adminQuery.Result
+
+	cmd := m.CreateOrgCommand{Name: name, UserId: adminUser.Id}
+	if err := bus.Dispatch(&cmd); err != nil {
+		log.ConsoleFatalf("Failed to create organization: %s", err)
+	}
+
+	log.ConsoleInfof("Organization %s created for admin user %s\n", name, adminUser.Email)
+}
+
+func deleteOrg(c *cli.Context) {
+	initRuntime(c)
+
+	if !c.Args().Present() {
+		log.ConsoleFatal("Organization name arg is required")
+	}
+
+	name := c.Args().First()
+	orgQuery := m.GetOrgByNameQuery{Name: name}
+	if err := bus.Dispatch(&orgQuery); err != nil {
+		log.ConsoleFatalf("Failed to find organization: %s", err)
+	}
+
+	orgId := orgQuery.Result.Id
+	cmd := m.DeleteOrgCommand{Id: orgId}
+	if err := bus.Dispatch(&cmd); err != nil {
+		log.ConsoleFatalf("Failed to delete organization: %s", err)
+	}
+
+	log.ConsoleInfof("Organization %s deleted", name)
+}

+ 2 - 2
pkg/events/events.go

@@ -50,13 +50,13 @@ func ToOnWriteEvent(event interface{}) (*OnTheWireEvent, error) {
 	return &wireEvent, nil
 }
 
-type AccountCreated struct {
+type OrgCreated struct {
 	Timestamp time.Time `json:"timestamp"`
 	Id        int64     `json:"id"`
 	Name      string    `json:"name"`
 }
 
-type AccountUpdated struct {
+type OrgUpdated struct {
 	Timestamp time.Time `json:"timestamp"`
 	Id        int64     `json:"id"`
 	Name      string    `json:"name"`

+ 1 - 1
pkg/middleware/auth.go

@@ -56,7 +56,7 @@ func RoleAuth(roles ...m.RoleType) macaron.Handler {
 	return func(c *Context) {
 		ok := false
 		for _, role := range roles {
-			if role == c.AccountRole {
+			if role == c.OrgRole {
 				ok = true
 				break
 			}

+ 9 - 8
pkg/middleware/middleware.go

@@ -56,22 +56,23 @@ func GetContextHandler() macaron.Handler {
 				ctx.SignedInUser = &m.SignedInUser{}
 
 				// TODO: fix this
-				ctx.AccountRole = keyInfo.Role
+				ctx.OrgRole = keyInfo.Role
 				ctx.ApiKeyId = keyInfo.Id
-				ctx.AccountId = keyInfo.AccountId
+				ctx.OrgId = keyInfo.OrgId
 			}
 		} else if setting.AnonymousEnabled {
-			accountQuery := m.GetAccountByNameQuery{Name: setting.AnonymousAccountName}
-			if err := bus.Dispatch(&accountQuery); err != nil {
-				if err == m.ErrAccountNotFound {
-					log.Error(3, "Anonymous access account name does not exist", nil)
+			orgQuery := m.GetOrgByNameQuery{Name: setting.AnonymousOrgName}
+			if err := bus.Dispatch(&orgQuery); err != nil {
+				if err == m.ErrOrgNotFound {
+					log.Error(3, "Anonymous access organization name does not exist", nil)
 				}
 			} else {
 				ctx.IsSignedIn = false
 				ctx.HasAnonymousAccess = true
 				ctx.SignedInUser = &m.SignedInUser{}
-				ctx.AccountRole = m.RoleType(setting.AnonymousAccountRole)
-				ctx.AccountId = accountQuery.Result.Id
+				ctx.OrgRole = m.RoleType(setting.AnonymousOrgRole)
+				ctx.OrgId = orgQuery.Result.Id
+				ctx.OrgName = orgQuery.Result.Name
 			}
 		}
 

+ 0 - 70
pkg/models/account.go

@@ -1,70 +0,0 @@
-package models
-
-import (
-	"errors"
-	"time"
-)
-
-// Typed errors
-var (
-	ErrAccountNotFound = errors.New("Account not found")
-)
-
-type Account struct {
-	Id      int64
-	Version int
-	Name    string
-	Created time.Time
-	Updated time.Time
-}
-
-// ---------------------
-// COMMANDS
-
-type CreateAccountCommand struct {
-	Name string `json:"name" binding:"Required"`
-
-	// initial admin user for account
-	UserId int64   `json:"-"`
-	Result Account `json:"-"`
-}
-
-type DeleteAccountCommand struct {
-	Id int64
-}
-
-type UpdateAccountCommand struct {
-	Name      string `json:"name" binding:"Required"`
-	AccountId int64  `json:"-"`
-}
-
-type GetUserAccountsQuery struct {
-	UserId int64
-	Result []*UserAccountDTO
-}
-
-type GetAccountByIdQuery struct {
-	Id     int64
-	Result *Account
-}
-
-type GetAccountByNameQuery struct {
-	Name   string
-	Result *Account
-}
-
-type GetAccountsQuery struct {
-	Result []*Account
-}
-
-type AccountDTO struct {
-	Id   int64  `json:"id"`
-	Name string `json:"name"`
-}
-
-type UserAccountDTO struct {
-	AccountId int64    `json:"accountId"`
-	Name      string   `json:"name"`
-	Role      RoleType `json:"role"`
-	IsUsing   bool     `json:"isUsing"`
-}

+ 0 - 67
pkg/models/account_user.go

@@ -1,67 +0,0 @@
-package models
-
-import (
-	"errors"
-	"time"
-)
-
-// Typed errors
-var (
-	ErrInvalidRoleType  = errors.New("Invalid role type")
-	ErrLastAccountAdmin = errors.New("Cannot remove last account admin")
-)
-
-type RoleType string
-
-const (
-	ROLE_VIEWER RoleType = "Viewer"
-	ROLE_EDITOR RoleType = "Editor"
-	ROLE_ADMIN  RoleType = "Admin"
-)
-
-func (r RoleType) IsValid() bool {
-	return r == ROLE_VIEWER || r == ROLE_ADMIN || r == ROLE_EDITOR
-}
-
-type AccountUser struct {
-	AccountId int64
-	UserId    int64
-	Role      RoleType
-	Created   time.Time
-	Updated   time.Time
-}
-
-// ---------------------
-// COMMANDS
-
-type RemoveAccountUserCommand struct {
-	UserId    int64
-	AccountId int64
-}
-
-type AddAccountUserCommand struct {
-	LoginOrEmail string   `json:"loginOrEmail" binding:"Required"`
-	Role         RoleType `json:"role" binding:"Required"`
-
-	AccountId int64 `json:"-"`
-	UserId    int64 `json:"-"`
-}
-
-// ----------------------
-// QUERIES
-
-type GetAccountUsersQuery struct {
-	AccountId int64
-	Result    []*AccountUserDTO
-}
-
-// ----------------------
-// Projections and DTOs
-
-type AccountUserDTO struct {
-	AccountId int64  `json:"accountId"`
-	UserId    int64  `json:"userId"`
-	Email     string `json:"email"`
-	Login     string `json:"login"`
-	Role      string `json:"role"`
-}

+ 16 - 16
pkg/models/apikey.go

@@ -8,22 +8,22 @@ import (
 var ErrInvalidApiKey = errors.New("Invalid API Key")
 
 type ApiKey struct {
-	Id        int64
-	AccountId int64
-	Name      string
-	Key       string
-	Role      RoleType
-	Created   time.Time
-	Updated   time.Time
+	Id      int64
+	OrgId   int64
+	Name    string
+	Key     string
+	Role    RoleType
+	Created time.Time
+	Updated time.Time
 }
 
 // ---------------------
 // COMMANDS
 type AddApiKeyCommand struct {
-	Name      string   `json:"name" binding:"Required"`
-	Role      RoleType `json:"role" binding:"Required"`
-	AccountId int64    `json:"-"`
-	Key       string   `json:"-"`
+	Name  string   `json:"name" binding:"Required"`
+	Role  RoleType `json:"role" binding:"Required"`
+	OrgId int64    `json:"-"`
+	Key   string   `json:"-"`
 
 	Result *ApiKey `json:"-"`
 }
@@ -33,20 +33,20 @@ type UpdateApiKeyCommand struct {
 	Name string   `json:"name"`
 	Role RoleType `json:"role"`
 
-	AccountId int64 `json:"-"`
+	OrgId int64 `json:"-"`
 }
 
 type DeleteApiKeyCommand struct {
-	Id        int64 `json:"id"`
-	AccountId int64 `json:"-"`
+	Id    int64 `json:"id"`
+	OrgId int64 `json:"-"`
 }
 
 // ----------------------
 // QUERIES
 
 type GetApiKeysQuery struct {
-	AccountId int64
-	Result    []*ApiKey
+	OrgId  int64
+	Result []*ApiKey
 }
 
 type GetApiKeyByKeyQuery struct {

+ 10 - 10
pkg/models/dashboards.go

@@ -14,10 +14,10 @@ var (
 )
 
 type Dashboard struct {
-	Id        int64
-	Slug      string
-	AccountId int64
-	Version   int
+	Id      int64
+	Slug    string
+	OrgId   int64
+	Version int
 
 	Created time.Time
 	Updated time.Time
@@ -53,7 +53,7 @@ func (cmd *SaveDashboardCommand) GetDashboardModel() *Dashboard {
 	dash := &Dashboard{}
 	dash.Data = cmd.Dashboard
 	dash.Title = dash.Data["title"].(string)
-	dash.AccountId = cmd.AccountId
+	dash.OrgId = cmd.OrgId
 	dash.UpdateSlug()
 
 	if dash.Data["id"] != nil {
@@ -80,14 +80,14 @@ func (dash *Dashboard) UpdateSlug() {
 
 type SaveDashboardCommand struct {
 	Dashboard map[string]interface{} `json:"dashboard"`
-	AccountId int64                  `json:"-"`
+	OrgId     int64                  `json:"-"`
 
 	Result *Dashboard
 }
 
 type DeleteDashboardCommand struct {
-	Slug      string
-	AccountId int64
+	Slug  string
+	OrgId int64
 }
 
 //
@@ -95,8 +95,8 @@ type DeleteDashboardCommand struct {
 //
 
 type GetDashboardQuery struct {
-	Slug      string
-	AccountId int64
+	Slug  string
+	OrgId int64
 
 	Result *Dashboard
 }

+ 15 - 15
pkg/models/datasource.go

@@ -23,9 +23,9 @@ type DsType string
 type DsAccess string
 
 type DataSource struct {
-	Id        int64
-	AccountId int64
-	Version   int
+	Id      int64
+	OrgId   int64
+	Version int
 
 	Name              string
 	Type              DsType
@@ -48,7 +48,7 @@ type DataSource struct {
 
 // Also acts as api DTO
 type AddDataSourceCommand struct {
-	AccountId int64 `json:"-"`
+	OrgId     int64 `json:"-"`
 	Name      string
 	Type      DsType
 	Access    DsAccess
@@ -64,7 +64,7 @@ type AddDataSourceCommand struct {
 // Also acts as api DTO
 type UpdateDataSourceCommand struct {
 	Id        int64
-	AccountId int64
+	OrgId     int64
 	Name      string
 	Type      DsType
 	Access    DsAccess
@@ -76,28 +76,28 @@ type UpdateDataSourceCommand struct {
 }
 
 type DeleteDataSourceCommand struct {
-	Id        int64
-	AccountId int64
+	Id    int64
+	OrgId int64
 }
 
 // ---------------------
 // QUERIES
 
 type GetDataSourcesQuery struct {
-	AccountId int64
-	Result    []*DataSource
+	OrgId  int64
+	Result []*DataSource
 }
 
 type GetDataSourceByIdQuery struct {
-	Id        int64
-	AccountId int64
-	Result    DataSource
+	Id     int64
+	OrgId  int64
+	Result DataSource
 }
 
 type GetDataSourceByNameQuery struct {
-	Name      string
-	AccountId int64
-	Result    DataSource
+	Name   string
+	OrgId  int64
+	Result DataSource
 }
 
 // ---------------------

+ 65 - 0
pkg/models/org.go

@@ -0,0 +1,65 @@
+package models
+
+import (
+	"errors"
+	"time"
+)
+
+// Typed errors
+var (
+	ErrOrgNotFound = errors.New("Organization not found")
+)
+
+type Org struct {
+	Id      int64
+	Version int
+	Name    string
+	Created time.Time
+	Updated time.Time
+}
+
+// ---------------------
+// COMMANDS
+
+type CreateOrgCommand struct {
+	Name string `json:"name" binding:"Required"`
+
+	// initial admin user for account
+	UserId int64 `json:"-"`
+	Result Org   `json:"-"`
+}
+
+type DeleteOrgCommand struct {
+	Id int64
+}
+
+type UpdateOrgCommand struct {
+	Name  string `json:"name" binding:"Required"`
+	OrgId int64  `json:"-"`
+}
+
+type GetOrgByIdQuery struct {
+	Id     int64
+	Result *Org
+}
+
+type GetOrgByNameQuery struct {
+	Name   string
+	Result *Org
+}
+
+type GetOrgListQuery struct {
+	Result []*Org
+}
+
+type OrgDTO struct {
+	Id   int64  `json:"id"`
+	Name string `json:"name"`
+}
+
+type UserOrgDTO struct {
+	OrgId   int64    `json:"orgId"`
+	Name    string   `json:"name"`
+	Role    RoleType `json:"role"`
+	IsUsing bool     `json:"isUsing"`
+}

+ 67 - 0
pkg/models/org_user.go

@@ -0,0 +1,67 @@
+package models
+
+import (
+	"errors"
+	"time"
+)
+
+// Typed errors
+var (
+	ErrInvalidRoleType = errors.New("Invalid role type")
+	ErrLastOrgAdmin    = errors.New("Cannot remove last organization admin")
+)
+
+type RoleType string
+
+const (
+	ROLE_VIEWER RoleType = "Viewer"
+	ROLE_EDITOR RoleType = "Editor"
+	ROLE_ADMIN  RoleType = "Admin"
+)
+
+func (r RoleType) IsValid() bool {
+	return r == ROLE_VIEWER || r == ROLE_ADMIN || r == ROLE_EDITOR
+}
+
+type OrgUser struct {
+	OrgId   int64
+	UserId  int64
+	Role    RoleType
+	Created time.Time
+	Updated time.Time
+}
+
+// ---------------------
+// COMMANDS
+
+type RemoveOrgUserCommand struct {
+	UserId int64
+	OrgId  int64
+}
+
+type AddOrgUserCommand struct {
+	LoginOrEmail string   `json:"loginOrEmail" binding:"Required"`
+	Role         RoleType `json:"role" binding:"Required"`
+
+	OrgId  int64 `json:"-"`
+	UserId int64 `json:"-"`
+}
+
+// ----------------------
+// QUERIES
+
+type GetOrgUsersQuery struct {
+	OrgId  int64
+	Result []*OrgUserDTO
+}
+
+// ----------------------
+// Projections and DTOs
+
+type OrgUserDTO struct {
+	OrgId  int64  `json:"orgId"`
+	UserId int64  `json:"userId"`
+	Email  string `json:"email"`
+	Login  string `json:"login"`
+	Role   string `json:"role"`
+}

+ 3 - 3
pkg/models/search.go

@@ -22,7 +22,7 @@ type DashboardTagCloudItem struct {
 type SearchDashboardsQuery struct {
 	Title     string
 	Tag       string
-	AccountId int64
+	OrgId     int64
 	UserId    int64
 	Limit     int
 	IsStarred bool
@@ -31,6 +31,6 @@ type SearchDashboardsQuery struct {
 }
 
 type GetDashboardTagsQuery struct {
-	AccountId int64
-	Result    []*DashboardTagCloudItem
+	OrgId  int64
+	Result []*DashboardTagCloudItem
 }

+ 13 - 8
pkg/models/user.go

@@ -23,8 +23,8 @@ type User struct {
 	EmailVerified bool
 	Theme         string
 
-	IsAdmin   bool
-	AccountId int64
+	IsAdmin bool
+	OrgId   int64
 
 	Created time.Time
 	Updated time.Time
@@ -63,9 +63,9 @@ type DeleteUserCommand struct {
 	UserId int64
 }
 
-type SetUsingAccountCommand struct {
-	UserId    int64
-	AccountId int64
+type SetUsingOrgCommand struct {
+	UserId int64
+	OrgId  int64
 }
 
 // ----------------------
@@ -99,14 +99,19 @@ type SearchUsersQuery struct {
 	Result []*UserSearchHitDTO
 }
 
+type GetUserOrgListQuery struct {
+	UserId int64
+	Result []*UserOrgDTO
+}
+
 // ------------------------
 // DTO & Projections
 
 type SignedInUser struct {
 	UserId         int64
-	AccountId      int64
-	AccountName    string
-	AccountRole    RoleType
+	OrgId          int64
+	OrgName        string
+	OrgRole        RoleType
 	Login          string
 	Name           string
 	Email          string

+ 0 - 135
pkg/services/sqlstore/account.go

@@ -1,135 +0,0 @@
-package sqlstore
-
-import (
-	"time"
-
-	"github.com/grafana/grafana/pkg/bus"
-	"github.com/grafana/grafana/pkg/events"
-	"github.com/grafana/grafana/pkg/log"
-	m "github.com/grafana/grafana/pkg/models"
-)
-
-func init() {
-	bus.AddHandler("sql", GetAccountById)
-	bus.AddHandler("sql", CreateAccount)
-	bus.AddHandler("sql", SetUsingAccount)
-	bus.AddHandler("sql", UpdateAccount)
-	bus.AddHandler("sql", GetAccountByName)
-	bus.AddHandler("sql", GetAccountsQuery)
-	bus.AddHandler("sql", DeleteAccount)
-}
-
-func GetAccountsQuery(query *m.GetAccountsQuery) error {
-	return x.Find(&query.Result)
-}
-
-func GetAccountById(query *m.GetAccountByIdQuery) error {
-	var account m.Account
-	exists, err := x.Id(query.Id).Get(&account)
-	if err != nil {
-		return err
-	}
-
-	if !exists {
-		return m.ErrAccountNotFound
-	}
-
-	query.Result = &account
-	return nil
-}
-
-func GetAccountByName(query *m.GetAccountByNameQuery) error {
-	var account m.Account
-	exists, err := x.Where("name=?", query.Name).Get(&account)
-	if err != nil {
-		return err
-	}
-
-	if !exists {
-		return m.ErrAccountNotFound
-	}
-
-	query.Result = &account
-	return nil
-}
-
-func CreateAccount(cmd *m.CreateAccountCommand) error {
-	return inTransaction2(func(sess *session) error {
-
-		account := m.Account{
-			Name:    cmd.Name,
-			Created: time.Now(),
-			Updated: time.Now(),
-		}
-
-		if _, err := sess.Insert(&account); err != nil {
-			return err
-		}
-
-		user := m.AccountUser{
-			AccountId: account.Id,
-			UserId:    cmd.UserId,
-			Role:      m.ROLE_ADMIN,
-			Created:   time.Now(),
-			Updated:   time.Now(),
-		}
-
-		_, err := sess.Insert(&user)
-		cmd.Result = account
-
-		sess.publishAfterCommit(&events.AccountCreated{
-			Timestamp: account.Created,
-			Id:        account.Id,
-			Name:      account.Name,
-		})
-
-		return err
-	})
-}
-
-func UpdateAccount(cmd *m.UpdateAccountCommand) error {
-	return inTransaction2(func(sess *session) error {
-
-		account := m.Account{
-			Name:    cmd.Name,
-			Updated: time.Now(),
-		}
-
-		if _, err := sess.Id(cmd.AccountId).Update(&account); err != nil {
-			return err
-		}
-
-		sess.publishAfterCommit(&events.AccountUpdated{
-			Timestamp: account.Updated,
-			Id:        account.Id,
-			Name:      account.Name,
-		})
-
-		return nil
-	})
-}
-
-func DeleteAccount(cmd *m.DeleteAccountCommand) error {
-	return inTransaction2(func(sess *session) error {
-
-		deletes := []string{
-			"DELETE FROM star WHERE EXISTS (SELECT 1 FROM dashboard WHERE account_id = ?)",
-			"DELETE FROM dashboard_tag WHERE EXISTS (SELECT 1 FROM dashboard WHERE account_id = ?)",
-			"DELETE FROM dashboard WHERE account_id = ?",
-			"DELETE FROM api_key WHERE account_id = ?",
-			"DELETE FROM data_source WHERE account_id = ?",
-			"DELETE FROM account_user WHERE account_id = ?",
-			"DELETE FROM account WHERE id = ?",
-		}
-
-		for _, sql := range deletes {
-			log.Trace(sql)
-			_, err := sess.Exec(sql, cmd.Id)
-			if err != nil {
-				return err
-			}
-		}
-
-		return nil
-	})
-}

+ 0 - 67
pkg/services/sqlstore/account_users.go

@@ -1,67 +0,0 @@
-package sqlstore
-
-import (
-	"fmt"
-	"time"
-
-	"github.com/go-xorm/xorm"
-
-	"github.com/grafana/grafana/pkg/bus"
-	m "github.com/grafana/grafana/pkg/models"
-)
-
-func init() {
-	bus.AddHandler("sql", AddAccountUser)
-	bus.AddHandler("sql", RemoveAccountUser)
-	bus.AddHandler("sql", GetAccountUsers)
-}
-
-func AddAccountUser(cmd *m.AddAccountUserCommand) error {
-	return inTransaction(func(sess *xorm.Session) error {
-
-		entity := m.AccountUser{
-			AccountId: cmd.AccountId,
-			UserId:    cmd.UserId,
-			Role:      cmd.Role,
-			Created:   time.Now(),
-			Updated:   time.Now(),
-		}
-
-		_, err := sess.Insert(&entity)
-		return err
-	})
-}
-
-func GetAccountUsers(query *m.GetAccountUsersQuery) error {
-	query.Result = make([]*m.AccountUserDTO, 0)
-	sess := x.Table("account_user")
-	sess.Join("INNER", "user", fmt.Sprintf("account_user.user_id=%s.id", x.Dialect().Quote("user")))
-	sess.Where("account_user.account_id=?", query.AccountId)
-	sess.Cols("account_user.account_id", "account_user.user_id", "user.email", "user.login", "account_user.role")
-	sess.Asc("user.email", "user.login")
-
-	err := sess.Find(&query.Result)
-	return err
-}
-
-func RemoveAccountUser(cmd *m.RemoveAccountUserCommand) error {
-	return inTransaction(func(sess *xorm.Session) error {
-		var rawSql = "DELETE FROM account_user WHERE account_id=? and user_id=?"
-		_, err := sess.Exec(rawSql, cmd.AccountId, cmd.UserId)
-		if err != nil {
-			return err
-		}
-
-		// validate that there is an admin user left
-		res, err := sess.Query("SELECT 1 from account_user WHERE account_id=? and role='Admin'", cmd.AccountId)
-		if err != nil {
-			return err
-		}
-
-		if len(res) == 0 {
-			return m.ErrLastAccountAdmin
-		}
-
-		return err
-	})
-}

+ 15 - 15
pkg/services/sqlstore/apikey.go

@@ -17,7 +17,7 @@ func init() {
 }
 
 func GetApiKeys(query *m.GetApiKeysQuery) error {
-	sess := x.Limit(100, 0).Where("account_id=?", query.AccountId).Asc("name")
+	sess := x.Limit(100, 0).Where("org_id=?", query.OrgId).Asc("name")
 
 	query.Result = make([]*m.ApiKey, 0)
 	return sess.Find(&query.Result)
@@ -25,8 +25,8 @@ func GetApiKeys(query *m.GetApiKeysQuery) error {
 
 func DeleteApiKey(cmd *m.DeleteApiKeyCommand) error {
 	return inTransaction(func(sess *xorm.Session) error {
-		var rawSql = "DELETE FROM api_key WHERE id=? and account_id=?"
-		_, err := sess.Exec(rawSql, cmd.Id, cmd.AccountId)
+		var rawSql = "DELETE FROM api_key WHERE id=? and org_id=?"
+		_, err := sess.Exec(rawSql, cmd.Id, cmd.OrgId)
 		return err
 	})
 }
@@ -34,12 +34,12 @@ func DeleteApiKey(cmd *m.DeleteApiKeyCommand) error {
 func AddApiKey(cmd *m.AddApiKeyCommand) error {
 	return inTransaction(func(sess *xorm.Session) error {
 		t := m.ApiKey{
-			AccountId: cmd.AccountId,
-			Name:      cmd.Name,
-			Role:      cmd.Role,
-			Key:       cmd.Key,
-			Created:   time.Now(),
-			Updated:   time.Now(),
+			OrgId:   cmd.OrgId,
+			Name:    cmd.Name,
+			Role:    cmd.Role,
+			Key:     cmd.Key,
+			Created: time.Now(),
+			Updated: time.Now(),
 		}
 
 		if _, err := sess.Insert(&t); err != nil {
@@ -53,13 +53,13 @@ func AddApiKey(cmd *m.AddApiKeyCommand) error {
 func UpdateApiKey(cmd *m.UpdateApiKeyCommand) error {
 	return inTransaction(func(sess *xorm.Session) error {
 		t := m.ApiKey{
-			Id:        cmd.Id,
-			AccountId: cmd.AccountId,
-			Name:      cmd.Name,
-			Role:      cmd.Role,
-			Updated:   time.Now(),
+			Id:      cmd.Id,
+			OrgId:   cmd.OrgId,
+			Name:    cmd.Name,
+			Role:    cmd.Role,
+			Updated: time.Now(),
 		}
-		_, err := sess.Where("id=? and account_id=?", t.Id, t.AccountId).Update(&t)
+		_, err := sess.Where("id=? and org_id=?", t.Id, t.OrgId).Update(&t)
 		return err
 	})
 }

+ 1 - 1
pkg/services/sqlstore/apikey_test.go

@@ -14,7 +14,7 @@ func TestApiKeyDataAccess(t *testing.T) {
 		InitTestDB(t)
 
 		Convey("Given saved api key", func() {
-			cmd := m.AddApiKeyCommand{AccountId: 1, Key: "hello"}
+			cmd := m.AddApiKeyCommand{OrgId: 1, Key: "hello"}
 			err := AddApiKey(&cmd)
 			So(err, ShouldBeNil)
 

+ 8 - 8
pkg/services/sqlstore/dashboard.go

@@ -22,7 +22,7 @@ func SaveDashboard(cmd *m.SaveDashboardCommand) error {
 		dash := cmd.GetDashboardModel()
 
 		// try get existing dashboard
-		existing := m.Dashboard{Slug: dash.Slug, AccountId: dash.AccountId}
+		existing := m.Dashboard{Slug: dash.Slug, OrgId: dash.OrgId}
 		hasExisting, err := sess.Get(&existing)
 		if err != nil {
 			return err
@@ -61,7 +61,7 @@ func SaveDashboard(cmd *m.SaveDashboardCommand) error {
 }
 
 func GetDashboard(query *m.GetDashboardQuery) error {
-	dashboard := m.Dashboard{Slug: query.Slug, AccountId: query.AccountId}
+	dashboard := m.Dashboard{Slug: query.Slug, OrgId: query.OrgId}
 	has, err := x.Get(&dashboard)
 	if err != nil {
 		return err
@@ -98,9 +98,9 @@ func SearchDashboards(query *m.SearchDashboardsQuery) error {
 		sql.WriteString(" INNER JOIN star on star.dashboard_id = dashboard.id")
 	}
 
-	sql.WriteString(` WHERE dashboard.account_id=?`)
+	sql.WriteString(` WHERE dashboard.org_id=?`)
 
-	params = append(params, query.AccountId)
+	params = append(params, query.OrgId)
 
 	if query.IsStarred {
 		sql.WriteString(` AND star.user_id=?`)
@@ -158,11 +158,11 @@ func GetDashboardTags(query *m.GetDashboardTagsQuery) error {
 						term
 					FROM dashboard
 					INNER JOIN dashboard_tag on dashboard_tag.dashboard_id = dashboard.id
-					WHERE dashboard.account_id=?
+					WHERE dashboard.org_id=?
 					GROUP BY term`
 
 	query.Result = make([]*m.DashboardTagCloudItem, 0)
-	sess := x.Sql(sql, query.AccountId)
+	sess := x.Sql(sql, query.OrgId)
 	err := sess.Find(&query.Result)
 	return err
 }
@@ -171,8 +171,8 @@ func DeleteDashboard(cmd *m.DeleteDashboardCommand) error {
 	sess := x.NewSession()
 	defer sess.Close()
 
-	rawSql := "DELETE FROM Dashboard WHERE account_id=? and slug=?"
-	_, err := sess.Exec(rawSql, cmd.AccountId, cmd.Slug)
+	rawSql := "DELETE FROM Dashboard WHERE org_id=? and slug=?"
+	_, err := sess.Exec(rawSql, cmd.OrgId, cmd.Slug)
 
 	return err
 }

+ 11 - 11
pkg/services/sqlstore/dashboard_test.go

@@ -8,9 +8,9 @@ import (
 	m "github.com/grafana/grafana/pkg/models"
 )
 
-func insertTestDashboard(title string, accountId int64, tags ...interface{}) *m.Dashboard {
+func insertTestDashboard(title string, orgId int64, tags ...interface{}) *m.Dashboard {
 	cmd := m.SaveDashboardCommand{
-		AccountId: accountId,
+		OrgId: orgId,
 		Dashboard: map[string]interface{}{
 			"id":    nil,
 			"title": title,
@@ -40,8 +40,8 @@ func TestDashboardDataAccess(t *testing.T) {
 
 			Convey("Should be able to get dashboard", func() {
 				query := m.GetDashboardQuery{
-					Slug:      "test-dash-23",
-					AccountId: 1,
+					Slug:  "test-dash-23",
+					OrgId: 1,
 				}
 
 				err := GetDashboard(&query)
@@ -53,8 +53,8 @@ func TestDashboardDataAccess(t *testing.T) {
 
 			Convey("Should be able to search for dashboard", func() {
 				query := m.SearchDashboardsQuery{
-					Title:     "test",
-					AccountId: 1,
+					Title: "test",
+					OrgId: 1,
 				}
 
 				err := SearchDashboards(&query)
@@ -66,8 +66,8 @@ func TestDashboardDataAccess(t *testing.T) {
 			})
 
 			Convey("Should be able to search for dashboards using tags", func() {
-				query1 := m.SearchDashboardsQuery{Tag: "webapp", AccountId: 1}
-				query2 := m.SearchDashboardsQuery{Tag: "tagdoesnotexist", AccountId: 1}
+				query1 := m.SearchDashboardsQuery{Tag: "webapp", OrgId: 1}
+				query2 := m.SearchDashboardsQuery{Tag: "tagdoesnotexist", OrgId: 1}
 
 				err := SearchDashboards(&query1)
 				err = SearchDashboards(&query2)
@@ -79,7 +79,7 @@ func TestDashboardDataAccess(t *testing.T) {
 
 			Convey("Should not be able to save dashboard with same name", func() {
 				cmd := m.SaveDashboardCommand{
-					AccountId: 1,
+					OrgId: 1,
 					Dashboard: map[string]interface{}{
 						"id":    nil,
 						"title": "test dash 23",
@@ -92,7 +92,7 @@ func TestDashboardDataAccess(t *testing.T) {
 			})
 
 			Convey("Should be able to get dashboard tags", func() {
-				query := m.GetDashboardTagsQuery{AccountId: 1}
+				query := m.GetDashboardTagsQuery{OrgId: 1}
 
 				err := GetDashboardTags(&query)
 				So(err, ShouldBeNil)
@@ -113,7 +113,7 @@ func TestDashboardDataAccess(t *testing.T) {
 				})
 
 				Convey("Should be able to search for starred dashboards", func() {
-					query := m.SearchDashboardsQuery{AccountId: 1, UserId: 10, IsStarred: true}
+					query := m.SearchDashboardsQuery{OrgId: 1, UserId: 10, IsStarred: true}
 					err := SearchDashboards(&query)
 
 					So(err, ShouldBeNil)

+ 10 - 10
pkg/services/sqlstore/datasource.go

@@ -19,7 +19,7 @@ func init() {
 }
 
 func GetDataSourceById(query *m.GetDataSourceByIdQuery) error {
-	sess := x.Limit(100, 0).Where("account_id=? AND id=?", query.AccountId, query.Id)
+	sess := x.Limit(100, 0).Where("org_id=? AND id=?", query.OrgId, query.Id)
 	has, err := sess.Get(&query.Result)
 
 	if !has {
@@ -29,7 +29,7 @@ func GetDataSourceById(query *m.GetDataSourceByIdQuery) error {
 }
 
 func GetDataSourceByName(query *m.GetDataSourceByNameQuery) error {
-	sess := x.Limit(100, 0).Where("account_id=? AND name=?", query.AccountId, query.Name)
+	sess := x.Limit(100, 0).Where("org_id=? AND name=?", query.OrgId, query.Name)
 	has, err := sess.Get(&query.Result)
 
 	if !has {
@@ -39,7 +39,7 @@ func GetDataSourceByName(query *m.GetDataSourceByNameQuery) error {
 }
 
 func GetDataSources(query *m.GetDataSourcesQuery) error {
-	sess := x.Limit(100, 0).Where("account_id=?", query.AccountId).Asc("name")
+	sess := x.Limit(100, 0).Where("org_id=?", query.OrgId).Asc("name")
 
 	query.Result = make([]*m.DataSource, 0)
 	return sess.Find(&query.Result)
@@ -47,8 +47,8 @@ func GetDataSources(query *m.GetDataSourcesQuery) error {
 
 func DeleteDataSource(cmd *m.DeleteDataSourceCommand) error {
 	return inTransaction(func(sess *xorm.Session) error {
-		var rawSql = "DELETE FROM data_source WHERE id=? and account_id=?"
-		_, err := sess.Exec(rawSql, cmd.Id, cmd.AccountId)
+		var rawSql = "DELETE FROM data_source WHERE id=? and org_id=?"
+		_, err := sess.Exec(rawSql, cmd.Id, cmd.OrgId)
 		return err
 	})
 }
@@ -57,7 +57,7 @@ func AddDataSource(cmd *m.AddDataSourceCommand) error {
 
 	return inTransaction(func(sess *xorm.Session) error {
 		ds := &m.DataSource{
-			AccountId: cmd.AccountId,
+			OrgId:     cmd.OrgId,
 			Name:      cmd.Name,
 			Type:      cmd.Type,
 			Access:    cmd.Access,
@@ -85,8 +85,8 @@ func AddDataSource(cmd *m.AddDataSourceCommand) error {
 func updateIsDefaultFlag(ds *m.DataSource, sess *xorm.Session) error {
 	// Handle is default flag
 	if ds.IsDefault {
-		rawSql := "UPDATE data_source SET is_default = 0 WHERE account_id=? AND id <> ?"
-		if _, err := sess.Exec(rawSql, ds.AccountId, ds.Id); err != nil {
+		rawSql := "UPDATE data_source SET is_default = 0 WHERE org_id=? AND id <> ?"
+		if _, err := sess.Exec(rawSql, ds.OrgId, ds.Id); err != nil {
 			return err
 		}
 	}
@@ -98,7 +98,7 @@ func UpdateDataSource(cmd *m.UpdateDataSourceCommand) error {
 	return inTransaction(func(sess *xorm.Session) error {
 		ds := &m.DataSource{
 			Id:        cmd.Id,
-			AccountId: cmd.AccountId,
+			OrgId:     cmd.OrgId,
 			Name:      cmd.Name,
 			Type:      cmd.Type,
 			Access:    cmd.Access,
@@ -112,7 +112,7 @@ func UpdateDataSource(cmd *m.UpdateDataSourceCommand) error {
 
 		sess.UseBool("is_default")
 
-		_, err := sess.Where("id=? and account_id=?", ds.Id, ds.AccountId).Update(ds)
+		_, err := sess.Where("id=? and org_id=?", ds.Id, ds.OrgId).Update(ds)
 		if err != nil {
 			return err
 		}

+ 15 - 15
pkg/services/sqlstore/datasource_test.go

@@ -42,16 +42,16 @@ func TestDataAccess(t *testing.T) {
 		Convey("Can add datasource", func() {
 
 			err := AddDataSource(&m.AddDataSourceCommand{
-				AccountId: 10,
-				Type:      m.DS_INFLUXDB,
-				Access:    m.DS_ACCESS_DIRECT,
-				Url:       "http://test",
-				Database:  "site",
+				OrgId:    10,
+				Type:     m.DS_INFLUXDB,
+				Access:   m.DS_ACCESS_DIRECT,
+				Url:      "http://test",
+				Database: "site",
 			})
 
 			So(err, ShouldBeNil)
 
-			query := m.GetDataSourcesQuery{AccountId: 10}
+			query := m.GetDataSourcesQuery{OrgId: 10}
 			err = GetDataSources(&query)
 			So(err, ShouldBeNil)
 
@@ -59,33 +59,33 @@ func TestDataAccess(t *testing.T) {
 
 			ds := query.Result[0]
 
-			So(ds.AccountId, ShouldEqual, 10)
+			So(ds.OrgId, ShouldEqual, 10)
 			So(ds.Database, ShouldEqual, "site")
 		})
 
 		Convey("Given a datasource", func() {
 
 			AddDataSource(&m.AddDataSourceCommand{
-				AccountId: 10,
-				Type:      m.DS_GRAPHITE,
-				Access:    m.DS_ACCESS_DIRECT,
-				Url:       "http://test",
+				OrgId:  10,
+				Type:   m.DS_GRAPHITE,
+				Access: m.DS_ACCESS_DIRECT,
+				Url:    "http://test",
 			})
 
-			query := m.GetDataSourcesQuery{AccountId: 10}
+			query := m.GetDataSourcesQuery{OrgId: 10}
 			GetDataSources(&query)
 			ds := query.Result[0]
 
 			Convey("Can delete datasource", func() {
-				err := DeleteDataSource(&m.DeleteDataSourceCommand{Id: ds.Id, AccountId: ds.AccountId})
+				err := DeleteDataSource(&m.DeleteDataSourceCommand{Id: ds.Id, OrgId: ds.OrgId})
 				So(err, ShouldBeNil)
 
 				GetDataSources(&query)
 				So(len(query.Result), ShouldEqual, 0)
 			})
 
-			Convey("Can not delete datasource with wrong accountId", func() {
-				err := DeleteDataSource(&m.DeleteDataSourceCommand{Id: ds.Id, AccountId: 123123})
+			Convey("Can not delete datasource with wrong orgId", func() {
+				err := DeleteDataSource(&m.DeleteDataSourceCommand{Id: ds.Id, OrgId: 123123})
 				So(err, ShouldBeNil)
 
 				GetDataSources(&query)

+ 134 - 0
pkg/services/sqlstore/org.go

@@ -0,0 +1,134 @@
+package sqlstore
+
+import (
+	"time"
+
+	"github.com/grafana/grafana/pkg/bus"
+	"github.com/grafana/grafana/pkg/events"
+	"github.com/grafana/grafana/pkg/log"
+	m "github.com/grafana/grafana/pkg/models"
+)
+
+func init() {
+	bus.AddHandler("sql", GetOrgById)
+	bus.AddHandler("sql", CreateOrg)
+	bus.AddHandler("sql", UpdateOrg)
+	bus.AddHandler("sql", GetOrgByName)
+	bus.AddHandler("sql", GetOrgList)
+	bus.AddHandler("sql", DeleteOrg)
+}
+
+func GetOrgList(query *m.GetOrgListQuery) error {
+	return x.Find(&query.Result)
+}
+
+func GetOrgById(query *m.GetOrgByIdQuery) error {
+	var org m.Org
+	exists, err := x.Id(query.Id).Get(&org)
+	if err != nil {
+		return err
+	}
+
+	if !exists {
+		return m.ErrOrgNotFound
+	}
+
+	query.Result = &org
+	return nil
+}
+
+func GetOrgByName(query *m.GetOrgByNameQuery) error {
+	var org m.Org
+	exists, err := x.Where("name=?", query.Name).Get(&org)
+	if err != nil {
+		return err
+	}
+
+	if !exists {
+		return m.ErrOrgNotFound
+	}
+
+	query.Result = &org
+	return nil
+}
+
+func CreateOrg(cmd *m.CreateOrgCommand) error {
+	return inTransaction2(func(sess *session) error {
+
+		org := m.Org{
+			Name:    cmd.Name,
+			Created: time.Now(),
+			Updated: time.Now(),
+		}
+
+		if _, err := sess.Insert(&org); err != nil {
+			return err
+		}
+
+		user := m.OrgUser{
+			OrgId:   org.Id,
+			UserId:  cmd.UserId,
+			Role:    m.ROLE_ADMIN,
+			Created: time.Now(),
+			Updated: time.Now(),
+		}
+
+		_, err := sess.Insert(&user)
+		cmd.Result = org
+
+		sess.publishAfterCommit(&events.OrgCreated{
+			Timestamp: org.Created,
+			Id:        org.Id,
+			Name:      org.Name,
+		})
+
+		return err
+	})
+}
+
+func UpdateOrg(cmd *m.UpdateOrgCommand) error {
+	return inTransaction2(func(sess *session) error {
+
+		org := m.Org{
+			Name:    cmd.Name,
+			Updated: time.Now(),
+		}
+
+		if _, err := sess.Id(cmd.OrgId).Update(&org); err != nil {
+			return err
+		}
+
+		sess.publishAfterCommit(&events.OrgUpdated{
+			Timestamp: org.Updated,
+			Id:        org.Id,
+			Name:      org.Name,
+		})
+
+		return nil
+	})
+}
+
+func DeleteOrg(cmd *m.DeleteOrgCommand) error {
+	return inTransaction2(func(sess *session) error {
+
+		deletes := []string{
+			"DELETE FROM star WHERE EXISTS (SELECT 1 FROM dashboard WHERE org_id = ?)",
+			"DELETE FROM dashboard_tag WHERE EXISTS (SELECT 1 FROM dashboard WHERE org_id = ?)",
+			"DELETE FROM dashboard WHERE org_id = ?",
+			"DELETE FROM api_key WHERE org_id = ?",
+			"DELETE FROM data_source WHERE org_id = ?",
+			"DELETE FROM org_user WHERE org_id = ?",
+			"DELETE FROM org WHERE id = ?",
+		}
+
+		for _, sql := range deletes {
+			log.Trace(sql)
+			_, err := sess.Exec(sql, cmd.Id)
+			if err != nil {
+				return err
+			}
+		}
+
+		return nil
+	})
+}

+ 7 - 7
pkg/services/sqlstore/account_test.go → pkg/services/sqlstore/org_test.go

@@ -15,11 +15,11 @@ func TestAccountDataAccess(t *testing.T) {
 		InitTestDB(t)
 
 		Convey("Given single account mode", func() {
-			setting.SingleAccountMode = true
-			setting.DefaultAccountName = "test"
-			setting.DefaultAccountRole = "Viewer"
+			setting.SingleOrgMode = true
+			setting.DefaultOrgName = "test"
+			setting.DefaultOrgRole = "Viewer"
 
-			Convey("Users should be added to default account", func() {
+			Convey("Users should be added to default organization", func() {
 				ac1cmd := m.CreateUserCommand{Login: "ac1", Email: "ac1@test.com", Name: "ac1 name"}
 				ac2cmd := m.CreateUserCommand{Login: "ac2", Email: "ac2@test.com", Name: "ac2 name"}
 
@@ -33,15 +33,15 @@ func TestAccountDataAccess(t *testing.T) {
 				GetUserAccounts(&q1)
 				GetUserAccounts(&q2)
 
-				So(q1.Result[0].AccountId, ShouldEqual, q2.Result[0].AccountId)
+				So(q1.Result[0].OrgId, ShouldEqual, q2.Result[0].OrgId)
 				So(q1.Result[0].Role, ShouldEqual, "Viewer")
 			})
 		})
 
 		Convey("Given two saved users", func() {
-			setting.SingleAccountMode = false
+			setting.SingleOrgMode = false
+			setting.DefaultOrgName = "test"
 
-			setting.DefaultAccountName = "test"
 			ac1cmd := m.CreateUserCommand{Login: "ac1", Email: "ac1@test.com", Name: "ac1 name"}
 			ac2cmd := m.CreateUserCommand{Login: "ac2", Email: "ac2@test.com", Name: "ac2 name", IsAdmin: true}
 

+ 67 - 0
pkg/services/sqlstore/org_users.go

@@ -0,0 +1,67 @@
+package sqlstore
+
+import (
+	"fmt"
+	"time"
+
+	"github.com/go-xorm/xorm"
+
+	"github.com/grafana/grafana/pkg/bus"
+	m "github.com/grafana/grafana/pkg/models"
+)
+
+func init() {
+	bus.AddHandler("sql", AddOrgUser)
+	bus.AddHandler("sql", RemoveOrgUser)
+	bus.AddHandler("sql", GetOrgUsers)
+}
+
+func AddOrgUser(cmd *m.AddOrgUserCommand) error {
+	return inTransaction(func(sess *xorm.Session) error {
+
+		entity := m.OrgUser{
+			OrgId:   cmd.OrgId,
+			UserId:  cmd.UserId,
+			Role:    cmd.Role,
+			Created: time.Now(),
+			Updated: time.Now(),
+		}
+
+		_, err := sess.Insert(&entity)
+		return err
+	})
+}
+
+func GetOrgUsers(query *m.GetOrgUsersQuery) error {
+	query.Result = make([]*m.OrgUserDTO, 0)
+	sess := x.Table("org_user")
+	sess.Join("INNER", "user", fmt.Sprintf("account_user.user_id=%s.id", x.Dialect().Quote("user")))
+	sess.Where("org_user.org_id=?", query.OrgId)
+	sess.Cols("org_user.org_id", "org_user.user_id", "user.email", "user.login", "org_user.role")
+	sess.Asc("user.email", "user.login")
+
+	err := sess.Find(&query.Result)
+	return err
+}
+
+func RemoveOrgUser(cmd *m.RemoveOrgUserCommand) error {
+	return inTransaction(func(sess *xorm.Session) error {
+		var rawSql = "DELETE FROM org_user WHERE org_id=? and user_id=?"
+		_, err := sess.Exec(rawSql, cmd.OrgId, cmd.UserId)
+		if err != nil {
+			return err
+		}
+
+		// validate that there is an admin user left
+		res, err := sess.Query("SELECT 1 from org_user WHERE org_id=? and role='Admin'", cmd.OrgId)
+		if err != nil {
+			return err
+		}
+
+		if len(res) == 0 {
+			return m.ErrLastOrgAdmin
+		}
+
+		return err
+	})
+}

+ 46 - 45
pkg/services/sqlstore/user.go

@@ -20,58 +20,59 @@ func init() {
 	bus.AddHandler("sql", UpdateUser)
 	bus.AddHandler("sql", ChangeUserPassword)
 	bus.AddHandler("sql", GetUserByLogin)
-	bus.AddHandler("sql", SetUsingAccount)
+	bus.AddHandler("sql", SetUsingOrg)
 	bus.AddHandler("sql", GetUserInfo)
 	bus.AddHandler("sql", GetSignedInUser)
 	bus.AddHandler("sql", SearchUsers)
-	bus.AddHandler("sql", GetUserAccounts)
+	bus.AddHandler("sql", GetUserOrgList)
 	bus.AddHandler("sql", DeleteUser)
+	bus.AddHandler("sql", SetUsingOrg)
 }
 
-func getAccountIdForNewUser(userEmail string, sess *session) (int64, error) {
-	var account m.Account
+func getOrgIdForNewUser(userEmail string, sess *session) (int64, error) {
+	var org m.Org
 
-	if setting.SingleAccountMode {
-		has, err := sess.Where("name=?", setting.DefaultAccountName).Get(&account)
+	if setting.SingleOrgMode {
+		has, err := sess.Where("name=?", setting.DefaultOrgName).Get(&org)
 		if err != nil {
 			return 0, err
 		}
 		if has {
-			return account.Id, nil
+			return org.Id, nil
 		} else {
-			account.Name = setting.DefaultAccountName
+			org.Name = setting.DefaultOrgName
 		}
 	} else {
-		account.Name = userEmail
+		org.Name = userEmail
 	}
 
-	account.Created = time.Now()
-	account.Updated = time.Now()
+	org.Created = time.Now()
+	org.Updated = time.Now()
 
-	if _, err := sess.Insert(&account); err != nil {
+	if _, err := sess.Insert(&org); err != nil {
 		return 0, err
 	}
 
-	return account.Id, nil
+	return org.Id, nil
 }
 
 func CreateUser(cmd *m.CreateUserCommand) error {
 	return inTransaction2(func(sess *session) error {
-		accountId, err := getAccountIdForNewUser(cmd.Email, sess)
+		orgId, err := getOrgIdForNewUser(cmd.Email, sess)
 		if err != nil {
 			return err
 		}
 
 		// create user
 		user := m.User{
-			Email:     cmd.Email,
-			Name:      cmd.Name,
-			Login:     cmd.Login,
-			Company:   cmd.Company,
-			IsAdmin:   cmd.IsAdmin,
-			AccountId: accountId,
-			Created:   time.Now(),
-			Updated:   time.Now(),
+			Email:   cmd.Email,
+			Name:    cmd.Name,
+			Login:   cmd.Login,
+			Company: cmd.Company,
+			IsAdmin: cmd.IsAdmin,
+			OrgId:   orgId,
+			Created: time.Now(),
+			Updated: time.Now(),
 		}
 
 		if len(cmd.Password) > 0 {
@@ -86,20 +87,20 @@ func CreateUser(cmd *m.CreateUserCommand) error {
 			return err
 		}
 
-		// create account user link
-		accountUser := m.AccountUser{
-			AccountId: accountId,
-			UserId:    user.Id,
-			Role:      m.ROLE_ADMIN,
-			Created:   time.Now(),
-			Updated:   time.Now(),
+		// create org user link
+		orgUser := m.OrgUser{
+			OrgId:   orgId,
+			UserId:  user.Id,
+			Role:    m.ROLE_ADMIN,
+			Created: time.Now(),
+			Updated: time.Now(),
 		}
 
-		if setting.SingleAccountMode && !user.IsAdmin {
-			accountUser.Role = m.RoleType(setting.DefaultAccountRole)
+		if setting.SingleOrgMode && !user.IsAdmin {
+			orgUser.Role = m.RoleType(setting.DefaultOrgRole)
 		}
 
-		if _, err = sess.Insert(&accountUser); err != nil {
+		if _, err = sess.Insert(&orgUser); err != nil {
 			return err
 		}
 
@@ -198,12 +199,12 @@ func ChangeUserPassword(cmd *m.ChangeUserPasswordCommand) error {
 	})
 }
 
-func SetUsingAccount(cmd *m.SetUsingAccountCommand) error {
+func SetUsingOrg(cmd *m.SetUsingOrgCommand) error {
 	return inTransaction(func(sess *xorm.Session) error {
 		user := m.User{}
 		sess.Id(cmd.UserId).Get(&user)
 
-		user.AccountId = cmd.AccountId
+		user.OrgId = cmd.OrgId
 		_, err := sess.Id(user.Id).Update(&user)
 		return err
 	})
@@ -228,12 +229,12 @@ func GetUserInfo(query *m.GetUserInfoQuery) error {
 	return err
 }
 
-func GetUserAccounts(query *m.GetUserAccountsQuery) error {
-	query.Result = make([]*m.UserAccountDTO, 0)
-	sess := x.Table("account_user")
-	sess.Join("INNER", "account", "account_user.account_id=account.id")
-	sess.Where("account_user.user_id=?", query.UserId)
-	sess.Cols("account.name", "account_user.role", "account_user.account_id")
+func GetUserOrgList(query *m.GetUserOrgListQuery) error {
+	query.Result = make([]*m.UserOrgDTO, 0)
+	sess := x.Table("org_user")
+	sess.Join("INNER", "org", "org_user.org_id=org.id")
+	sess.Where("org_user.user_id=?", query.UserId)
+	sess.Cols("org.name", "org_user.role", "org_user.account_id")
 	err := sess.Find(&query.Result)
 	return err
 }
@@ -245,12 +246,12 @@ func GetSignedInUser(query *m.GetSignedInUserQuery) error {
 	                u.email        as email,
 	                u.login        as login,
 									u.name         as name,
-	                account.name      as account_name,
-	                account_user.role as account_role,
-	                account.id        as account_id
+	                org.name       as org_name,
+	                org_user.role  as org_role,
+	                org.id         as org_id
 	                FROM ` + dialect.Quote("user") + ` as u
-									LEFT OUTER JOIN account_user on account_user.account_id = u.account_id and account_user.user_id = u.id
-	                LEFT OUTER JOIN account on account.id = u.account_id
+									LEFT OUTER JOIN org_user on org_user.org_id = u.org_id and org_user.user_id = u.id
+	                LEFT OUTER JOIN org on org.id = u.org_id
 	                WHERE u.id=?`
 
 	var user m.SignedInUser

+ 12 - 12
pkg/setting/setting.go

@@ -66,18 +66,18 @@ var (
 	CookieRememberName string
 	DisableUserSignUp  bool
 
-	// single account
-	SingleAccountMode  bool
-	DefaultAccountName string
-	DefaultAccountRole string
+	// single organization
+	SingleOrgMode  bool
+	DefaultOrgName string
+	DefaultOrgRole string
 
 	// Http auth
 	AdminUser     string
 	AdminPassword string
 
-	AnonymousEnabled     bool
-	AnonymousAccountName string
-	AnonymousAccountRole string
+	AnonymousEnabled bool
+	AnonymousOrgName string
+	AnonymousOrgRole string
 
 	// Session settings.
 	SessionOptions session.Options
@@ -220,14 +220,14 @@ func NewConfigContext(config string) {
 	AdminPassword = security.Key("admin_password").String()
 
 	// single account
-	SingleAccountMode = Cfg.Section("account.single").Key("enabled").MustBool(false)
-	DefaultAccountName = Cfg.Section("account.single").Key("account_name").MustString("main")
-	DefaultAccountRole = Cfg.Section("account.single").Key("default_role").In("Editor", []string{"Editor", "Admin", "Viewer"})
+	SingleOrgMode = Cfg.Section("organization.single").Key("enabled").MustBool(false)
+	DefaultOrgName = Cfg.Section("organization.single").Key("org_name").MustString("main")
+	DefaultOrgRole = Cfg.Section("organization.single").Key("default_role").In("Editor", []string{"Editor", "Admin", "Viewer"})
 
 	// anonymous access
 	AnonymousEnabled = Cfg.Section("auth.anonymous").Key("enabled").MustBool(false)
-	AnonymousAccountName = Cfg.Section("auth.anonymous").Key("account_name").String()
-	AnonymousAccountRole = Cfg.Section("auth.anonymous").Key("account_role").String()
+	AnonymousOrgName = Cfg.Section("auth.anonymous").Key("org_name").String()
+	AnonymousOrgRole = Cfg.Section("auth.anonymous").Key("org_role").String()
 
 	// PhantomJS rendering
 	ImagesDir = "data/png"