diff --git a/.circleci/config.yml b/.circleci/config.yml
index 3aedd49c935..9b729ecfa15 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -221,6 +221,8 @@ workflows:
jobs:
- build-all:
filters: *filter-not-release
+ - build-enterprise:
+ filters: *filter-not-release
- codespell:
filters: *filter-not-release
- gometalinter:
diff --git a/pkg/api/api.go b/pkg/api/api.go
index 39dae56eb69..78c7aaf3f39 100644
--- a/pkg/api/api.go
+++ b/pkg/api/api.go
@@ -9,7 +9,14 @@ import (
m "github.com/grafana/grafana/pkg/models"
)
-// Register adds http routes
+func (hs *HTTPServer) applyRoutes() {
+ hs.RouteRegister.Register(hs.macaron)
+
+ InitAppPluginRoutes(hs.macaron)
+
+ hs.macaron.NotFound(NotFoundHandler)
+}
+
func (hs *HTTPServer) registerRoutes() {
macaronR := hs.macaron
reqSignedIn := middleware.Auth(&middleware.AuthOptions{ReqSignedIn: true})
@@ -393,10 +400,4 @@ func (hs *HTTPServer) registerRoutes() {
// streams
//r.Post("/api/streams/push", reqSignedIn, bind(dtos.StreamMessage{}), liveConn.PushToStream)
-
- r.Register(macaronR)
-
- InitAppPluginRoutes(macaronR)
-
- macaronR.NotFound(NotFoundHandler)
}
diff --git a/pkg/api/frontendsettings.go b/pkg/api/frontendsettings.go
index e7272e68997..06e6405baaf 100644
--- a/pkg/api/frontendsettings.go
+++ b/pkg/api/frontendsettings.go
@@ -132,6 +132,7 @@ func getFrontendSettingsMap(c *m.ReqContext) (map[string]interface{}, error) {
}
jsonObj := map[string]interface{}{
+ "enterprise": setting.Enterprise,
"defaultDatasource": defaultDatasource,
"datasources": datasources,
"panels": panels,
diff --git a/pkg/api/http_server.go b/pkg/api/http_server.go
index e1a10fb468f..627192bb69b 100644
--- a/pkg/api/http_server.go
+++ b/pkg/api/http_server.go
@@ -33,7 +33,11 @@ import (
)
func init() {
- registry.RegisterService(&HTTPServer{})
+ registry.Register(®istry.Descriptor{
+ Name: "HTTPServer",
+ Instance: &HTTPServer{},
+ InitPriority: registry.High,
+ })
}
type HTTPServer struct {
@@ -54,6 +58,10 @@ func (hs *HTTPServer) Init() error {
hs.log = log.New("http.server")
hs.cache = gocache.New(5*time.Minute, 10*time.Minute)
+ hs.streamManager = live.NewStreamManager()
+ hs.macaron = hs.newMacaron()
+ hs.registerRoutes()
+
return nil
}
@@ -61,10 +69,7 @@ func (hs *HTTPServer) Run(ctx context.Context) error {
var err error
hs.context = ctx
- hs.streamManager = live.NewStreamManager()
- hs.macaron = hs.newMacaron()
- hs.registerRoutes()
-
+ hs.applyRoutes()
hs.streamManager.Run(ctx)
listenAddr := fmt.Sprintf("%s:%s", setting.HttpAddr, setting.HttpPort)
diff --git a/pkg/login/ext_user.go b/pkg/login/ext_user.go
index e1d5e3e3b48..d2f1aa1ff52 100644
--- a/pkg/login/ext_user.go
+++ b/pkg/login/ext_user.go
@@ -66,7 +66,21 @@ func UpsertUser(cmd *m.UpsertUserCommand) error {
}
}
- return syncOrgRoles(cmd.Result, extUser)
+ err = syncOrgRoles(cmd.Result, extUser)
+ if err != nil {
+ return err
+ }
+
+ err = bus.Dispatch(&m.SyncTeamsCommand{
+ User: cmd.Result,
+ ExternalUser: extUser,
+ })
+
+ if err == bus.ErrHandlerNotFound {
+ return nil
+ }
+
+ return err
}
func createUser(extUser *m.ExternalUserInfo) (*m.User, error) {
diff --git a/pkg/login/ldap.go b/pkg/login/ldap.go
index 026a94fa43e..bdf87b2db54 100644
--- a/pkg/login/ldap.go
+++ b/pkg/login/ldap.go
@@ -163,6 +163,7 @@ func (a *ldapAuther) GetGrafanaUserFor(ctx *m.ReqContext, ldapUser *LdapUserInfo
Name: fmt.Sprintf("%s %s", ldapUser.FirstName, ldapUser.LastName),
Login: ldapUser.Username,
Email: ldapUser.Email,
+ Groups: ldapUser.MemberOf,
OrgRoles: map[int64]m.RoleType{},
}
@@ -194,6 +195,7 @@ func (a *ldapAuther) GetGrafanaUserFor(ctx *m.ReqContext, ldapUser *LdapUserInfo
ExternalUser: extUser,
SignupAllowed: setting.LdapAllowSignup,
}
+
err := bus.Dispatch(userQuery)
if err != nil {
return nil, err
diff --git a/pkg/login/ldap_test.go b/pkg/login/ldap_test.go
index 34932926406..5080840704e 100644
--- a/pkg/login/ldap_test.go
+++ b/pkg/login/ldap_test.go
@@ -1,6 +1,7 @@
package login
import (
+ "context"
"crypto/tls"
"testing"
@@ -14,6 +15,14 @@ func TestLdapAuther(t *testing.T) {
Convey("When translating ldap user to grafana user", t, func() {
+ var user1 = &m.User{}
+
+ bus.AddHandlerCtx("test", func(ctx context.Context, cmd *m.UpsertUserCommand) error {
+ cmd.Result = user1
+ cmd.Result.Login = "torkelo"
+ return nil
+ })
+
Convey("Given no ldap group map match", func() {
ldapAuther := NewLdapAuthenticator(&LdapServerConf{
LdapGroups: []*LdapGroupToOrgRole{{}},
@@ -23,8 +32,6 @@ func TestLdapAuther(t *testing.T) {
So(err, ShouldEqual, ErrInvalidCredentials)
})
- var user1 = &m.User{}
-
ldapAutherScenario("Given wildcard group match", func(sc *scenarioContext) {
ldapAuther := NewLdapAuthenticator(&LdapServerConf{
LdapGroups: []*LdapGroupToOrgRole{
@@ -96,7 +103,6 @@ func TestLdapAuther(t *testing.T) {
})
Convey("When syncing ldap groups to grafana org roles", t, func() {
-
ldapAutherScenario("given no current user orgs", func(sc *scenarioContext) {
ldapAuther := NewLdapAuthenticator(&LdapServerConf{
LdapGroups: []*LdapGroupToOrgRole{
@@ -322,6 +328,10 @@ func ldapAutherScenario(desc string, fn scenarioFunc) {
bus.AddHandler("test", UpsertUser)
+ bus.AddHandlerCtx("test", func(ctx context.Context, cmd *m.SyncTeamsCommand) error {
+ return nil
+ })
+
bus.AddHandler("test", func(cmd *m.GetUserByAuthInfoQuery) error {
sc.getUserByAuthInfoQuery = cmd
sc.getUserByAuthInfoQuery.Result = &m.User{Login: cmd.Login}
diff --git a/pkg/models/team_member.go b/pkg/models/team_member.go
index 19cf657292d..9434dad8ecd 100644
--- a/pkg/models/team_member.go
+++ b/pkg/models/team_member.go
@@ -42,6 +42,7 @@ type RemoveTeamMemberCommand struct {
type GetTeamMembersQuery struct {
OrgId int64
TeamId int64
+ UserId int64
Result []*TeamMemberDTO
}
diff --git a/pkg/models/user_auth.go b/pkg/models/user_auth.go
index 0ecd144d52c..162a4d867a9 100644
--- a/pkg/models/user_auth.go
+++ b/pkg/models/user_auth.go
@@ -19,6 +19,7 @@ type ExternalUserInfo struct {
Email string
Login string
Name string
+ Groups []string
OrgRoles map[int64]RoleType
}
@@ -70,3 +71,8 @@ type GetAuthInfoQuery struct {
Result *UserAuth
}
+
+type SyncTeamsCommand struct {
+ ExternalUser *ExternalUserInfo
+ User *User
+}
diff --git a/pkg/registry/registry.go b/pkg/registry/registry.go
index 6bbc302c593..87fca27f6c1 100644
--- a/pkg/registry/registry.go
+++ b/pkg/registry/registry.go
@@ -4,6 +4,8 @@ import (
"context"
"reflect"
"sort"
+
+ "github.com/grafana/grafana/pkg/services/sqlstore/migrator"
)
type Descriptor struct {
@@ -57,13 +59,21 @@ type CanBeDisabled interface {
// BackgroundService should be implemented for services that have
// long running tasks in the background.
type BackgroundService interface {
-
// Run starts the background process of the service after `Init` have been called
// on all services. The `context.Context` passed into the function should be used
// to subscribe to ctx.Done() so the service can be notified when Grafana shuts down.
Run(ctx context.Context) error
}
+// DatabaseMigrator allows the caller to add migrations to
+// the migrator passed as argument
+type DatabaseMigrator interface {
+
+ // AddMigrations allows the service to add migrations to
+ // the database migrator.
+ AddMigration(mg *migrator.Migrator)
+}
+
// IsDisabled takes an service and return true if its disabled
func IsDisabled(srv Service) bool {
canBeDisabled, ok := srv.(CanBeDisabled)
diff --git a/pkg/services/sqlstore/migrations/team_mig.go b/pkg/services/sqlstore/migrations/team_mig.go
index eb0641fbc32..9800d27f8ab 100644
--- a/pkg/services/sqlstore/migrations/team_mig.go
+++ b/pkg/services/sqlstore/migrations/team_mig.go
@@ -50,4 +50,5 @@ func addTeamMigrations(mg *Migrator) {
mg.AddMigration("Add column email to team table", NewAddColumnMigration(teamV1, &Column{
Name: "email", Type: DB_NVarchar, Nullable: true, Length: 190,
}))
+
}
diff --git a/pkg/services/sqlstore/sqlstore.go b/pkg/services/sqlstore/sqlstore.go
index b0edc1676e0..13d706b6198 100644
--- a/pkg/services/sqlstore/sqlstore.go
+++ b/pkg/services/sqlstore/sqlstore.go
@@ -132,6 +132,13 @@ func (ss *SqlStore) Init() error {
migrator := migrator.NewMigrator(x)
migrations.AddMigrations(migrator)
+ for _, descriptor := range registry.GetServices() {
+ sc, ok := descriptor.Instance.(registry.DatabaseMigrator)
+ if ok {
+ sc.AddMigration(migrator)
+ }
+ }
+
if err := migrator.Start(); err != nil {
return fmt.Errorf("Migration failed err: %v", err)
}
diff --git a/pkg/services/sqlstore/team.go b/pkg/services/sqlstore/team.go
index 7d53d114235..9378ca37f60 100644
--- a/pkg/services/sqlstore/team.go
+++ b/pkg/services/sqlstore/team.go
@@ -268,7 +268,15 @@ func GetTeamMembers(query *m.GetTeamMembersQuery) error {
query.Result = make([]*m.TeamMemberDTO, 0)
sess := x.Table("team_member")
sess.Join("INNER", "user", fmt.Sprintf("team_member.user_id=%s.id", x.Dialect().Quote("user")))
- sess.Where("team_member.org_id=? and team_member.team_id=?", query.OrgId, query.TeamId)
+ if query.OrgId != 0 {
+ sess.Where("team_member.org_id=?", query.OrgId)
+ }
+ if query.TeamId != 0 {
+ sess.Where("team_member.team_id=?", query.TeamId)
+ }
+ if query.UserId != 0 {
+ sess.Where("team_member.user_id=?", query.UserId)
+ }
sess.Cols("user.org_id", "team_member.team_id", "team_member.user_id", "user.email", "user.login")
sess.Asc("user.login", "user.email")
diff --git a/public/app/core/config.ts b/public/app/core/config.ts
index e111d0d0e9f..83ef17662c8 100644
--- a/public/app/core/config.ts
+++ b/public/app/core/config.ts
@@ -22,6 +22,7 @@ class Settings {
disableUserSignUp: boolean;
loginHint: any;
loginError: any;
+ enterprise: boolean;
constructor(options) {
var defaults = {
diff --git a/public/app/features/org/partials/team_details.html b/public/app/features/org/partials/team_details.html
index 3fce8b3c720..c5ac8bd37a3 100644
--- a/public/app/features/org/partials/team_details.html
+++ b/public/app/features/org/partials/team_details.html
@@ -1,22 +1,22 @@