Team: Add columns external_uid and is_provisioned to the team table (#103285)

* add columns external_id and is_provisioned to the team table

* generate openapi specs

* rename column to external_uid

* generate open api specs

* increase limit for external_uid to 256
This commit is contained in:
Mihai Doarna
2025-04-04 11:00:14 +03:00
committed by GitHub
parent f19e4f95d5
commit 10411361e7
15 changed files with 143 additions and 42 deletions
@@ -187,7 +187,11 @@ func TestAccessControlStore_GetTeamsPermissions(t *testing.T) {
teams := make([]team.Team, 0)
for i := 0; i < len(tt.teamsPermissions); i++ {
team, err := teamSvc.CreateTeam(context.Background(), fmt.Sprintf("team-%v", i), "", tt.orgID)
teamCmd := team.CreateTeamCommand{
Name: fmt.Sprintf("team-%v", i),
OrgID: tt.orgID,
}
team, err := teamSvc.CreateTeam(context.Background(), &teamCmd)
require.NoError(t, err)
teams = append(teams, team)
}
@@ -388,7 +392,11 @@ func createUserAndTeam(t *testing.T, store db.DB, userSrv user.Service, teamSvc
})
require.NoError(t, err)
createdTeam, err := teamSvc.CreateTeam(context.Background(), "team", "", orgID)
teamCmd := team.CreateTeamCommand{
Name: "team",
OrgID: orgID,
}
createdTeam, err := teamSvc.CreateTeam(context.Background(), &teamCmd)
require.NoError(t, err)
err = store.WithDbSession(context.Background(), func(sess *db.Session) error {
@@ -438,7 +446,11 @@ func createUsersAndTeams(t *testing.T, store db.DB, svcs helperServices, orgID i
continue
}
createdTeam, err := svcs.teamSvc.CreateTeam(context.Background(), fmt.Sprintf("team%v", i+1), "", orgID)
teamCmd := team.CreateTeamCommand{
Name: fmt.Sprintf("team%v", i+1),
OrgID: orgID,
}
createdTeam, err := svcs.teamSvc.CreateTeam(context.Background(), &teamCmd)
require.NoError(t, err)
err = store.WithDbSession(context.Background(), func(sess *db.Session) error {
@@ -331,7 +331,12 @@ func TestApi_setTeamPermission(t *testing.T) {
server := setupTestServer(t, &user.SignedInUser{OrgID: 1, Permissions: map[int64]map[string][]string{1: accesscontrol.GroupScopesByActionContext(context.Background(), tt.permissions)}}, service)
// seed team
team, err := teamSvc.CreateTeam(context.Background(), "test", "test@test.com", 1)
teamCmd := team.CreateTeamCommand{
Name: "test",
Email: "test@test.com",
OrgID: 1,
}
team, err := teamSvc.CreateTeam(context.Background(), &teamCmd)
require.NoError(t, err)
assignTo := strconv.Itoa(int(tt.teamID))
@@ -520,7 +525,12 @@ func seedPermissions(t *testing.T, resourceID string, usrSvc user.Service, teamS
t.Helper()
// seed team 1 with "Edit" permission on dashboard 1
team, err := teamSvc.CreateTeam(context.Background(), "test", "test@test.com", 1)
teamCmd := team.CreateTeamCommand{
Name: "test",
Email: "test@test.com",
OrgID: 1,
}
team, err := teamSvc.CreateTeam(context.Background(), &teamCmd)
require.NoError(t, err)
_, err = service.SetTeamPermission(context.Background(), team.OrgID, team.ID, resourceID, "Edit")
require.NoError(t, err)
@@ -96,7 +96,12 @@ func TestService_SetTeamPermission(t *testing.T) {
})
// seed team
team, err := teamSvc.CreateTeam(context.Background(), "test", "test@test.com", 1)
teamCmd := team.CreateTeamCommand{
Name: "test",
Email: "test@test.com",
OrgID: 1,
}
team, err := teamSvc.CreateTeam(context.Background(), &teamCmd)
require.NoError(t, err)
var hookCalled bool
@@ -211,7 +216,12 @@ func TestService_SetPermissions(t *testing.T) {
// seed user
_, err := usrSvc.Create(context.Background(), &user.CreateUserCommand{Login: "user", OrgID: 1})
require.NoError(t, err)
_, err = teamSvc.CreateTeam(context.Background(), "team", "", 1)
teamCmd := team.CreateTeamCommand{
Name: "test",
OrgID: 1,
}
_, err = teamSvc.CreateTeam(context.Background(), &teamCmd)
require.NoError(t, err)
permissions, err := service.SetPermissions(context.Background(), 1, "1", tt.commands...)
@@ -19,6 +19,7 @@ import (
"github.com/grafana/grafana/pkg/services/org/orgimpl"
"github.com/grafana/grafana/pkg/services/quota/quotatest"
"github.com/grafana/grafana/pkg/services/supportbundles/supportbundlestest"
"github.com/grafana/grafana/pkg/services/team"
"github.com/grafana/grafana/pkg/services/team/teamimpl"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/services/user/userimpl"
@@ -155,9 +156,12 @@ func generateTeamsAndUsers(b *testing.B, store db.DB, cfg *setting.Cfg, users in
teamIds := make([]int64, 0)
for i := 0; i < numberOfTeams; i++ {
// Create team
teamName := fmt.Sprintf("%s%v", "team", i)
teamEmail := fmt.Sprintf("%s@example.org", teamName)
team, err := teamSvc.CreateTeam(context.Background(), teamName, teamEmail, 1)
teamCmd := team.CreateTeamCommand{
Name: fmt.Sprintf("%s%v", "team", i),
Email: fmt.Sprintf("%s%v@example.org", "team", i),
OrgID: 1,
}
team, err := teamSvc.CreateTeam(context.Background(), &teamCmd)
require.NoError(b, err)
teamId := team.ID
teamIds = append(teamIds, teamId)
@@ -37,6 +37,14 @@ func addTeamMigrations(mg *Migrator) {
Cols: []string{"org_id", "uid"}, Type: UniqueIndex,
}))
mg.AddMigration("Add column external_uid in team", NewAddColumnMigration(teamV1, &Column{
Name: "external_uid", Type: DB_NVarchar, Length: 256, Nullable: true,
}))
mg.AddMigration("Add column is_provisioned in team", NewAddColumnMigration(teamV1, &Column{
Name: "is_provisioned", Type: DB_Bool, Nullable: true,
}))
teamMemberV1 := Table{
Name: "team_member",
Columns: []*Column{
+14 -8
View File
@@ -22,11 +22,13 @@ var (
// Team model
type Team struct {
ID int64 `json:"id" xorm:"pk autoincr 'id'"`
UID string `json:"uid" xorm:"uid"`
OrgID int64 `json:"orgId" xorm:"org_id"`
Name string `json:"name"`
Email string `json:"email"`
ID int64 `json:"id" xorm:"pk autoincr 'id'"`
UID string `json:"uid" xorm:"uid"`
OrgID int64 `json:"orgId" xorm:"org_id"`
Name string `json:"name"`
Email string `json:"email"`
ExternalUID string `json:"externalUID" xorm:"external_uid"`
IsProvisioned bool `json:"isProvisioned" xorm:"is_provisioned"`
Created time.Time `json:"created"`
Updated time.Time `json:"updated"`
@@ -36,9 +38,11 @@ type Team struct {
// COMMANDS
type CreateTeamCommand struct {
Name string `json:"name" binding:"Required"`
Email string `json:"email"`
OrgID int64 `json:"-"`
Name string `json:"name" binding:"Required"`
Email string `json:"email"`
ExternalUID string `json:"-"`
IsProvisioned bool `json:"-"`
OrgID int64 `json:"-"`
}
type UpdateTeamCommand struct {
@@ -94,6 +98,8 @@ type TeamDTO struct {
OrgID int64 `json:"orgId" xorm:"org_id"`
Name string `json:"name"`
Email string `json:"email"`
ExternalUID string `json:"externalUID"`
IsProvisioned bool `json:"isProvisioned"`
AvatarURL string `json:"avatarUrl"`
MemberCount int64 `json:"memberCount"`
Permission PermissionType `json:"permission"`
+1 -1
View File
@@ -10,7 +10,7 @@ import (
)
type Service interface {
CreateTeam(ctx context.Context, name, email string, orgID int64) (Team, error)
CreateTeam(ctx context.Context, cmd *CreateTeamCommand) (Team, error)
UpdateTeam(ctx context.Context, cmd *UpdateTeamCommand) error
DeleteTeam(ctx context.Context, cmd *DeleteTeamCommand) error
SearchTeams(ctx context.Context, query *SearchTeamsQuery) (SearchTeamQueryResult, error)
+1 -1
View File
@@ -34,7 +34,7 @@ func (tapi *TeamAPI) createTeam(c *contextmodel.ReqContext) response.Response {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
t, err := tapi.teamService.CreateTeam(c.Req.Context(), cmd.Name, cmd.Email, c.SignedInUser.GetOrgID())
t, err := tapi.teamService.CreateTeam(c.Req.Context(), &cmd)
if err != nil {
if errors.Is(err, team.ErrTeamNameTaken) {
return response.Error(http.StatusConflict, "Team name taken", err)
+15 -11
View File
@@ -17,7 +17,7 @@ import (
)
type store interface {
Create(name, email string, orgID int64) (team.Team, error)
Create(ctx context.Context, cmd *team.CreateTeamCommand) (team.Team, error)
Update(ctx context.Context, cmd *team.UpdateTeamCommand) error
Delete(ctx context.Context, cmd *team.DeleteTeamCommand) error
Search(ctx context.Context, query *team.SearchTeamsQuery) (team.SearchTeamQueryResult, error)
@@ -71,22 +71,26 @@ func getTeamSelectSQLBase(db db.DB, filteredUsers []string) string {
team.uid,
team.org_id,
team.name as name,
team.email as email, ` +
team.email as email,
team.external_uid as external_uid,
team.is_provisioned as is_provisioned, ` +
getTeamMemberCount(db, filteredUsers) +
` FROM team as team `
}
func (ss *xormStore) Create(name, email string, orgID int64) (team.Team, error) {
func (ss *xormStore) Create(ctx context.Context, cmd *team.CreateTeamCommand) (team.Team, error) {
t := team.Team{
UID: util.GenerateShortUID(),
Name: name,
Email: email,
OrgID: orgID,
Created: time.Now(),
Updated: time.Now(),
UID: util.GenerateShortUID(),
Name: cmd.Name,
Email: cmd.Email,
OrgID: cmd.OrgID,
ExternalUID: cmd.ExternalUID,
IsProvisioned: cmd.IsProvisioned,
Created: time.Now(),
Updated: time.Now(),
}
err := ss.db.WithTransactionalDbSession(context.Background(), func(sess *db.Session) error {
if isNameTaken, err := isTeamNameTaken(orgID, name, 0, sess); err != nil {
err := ss.db.WithTransactionalDbSession(ctx, func(sess *db.Session) error {
if isNameTaken, err := isTeamNameTaken(cmd.OrgID, cmd.Name, 0, sess); err != nil {
return err
} else if isNameTaken {
return team.ErrTeamNameTaken
+35 -5
View File
@@ -77,9 +77,21 @@ func TestIntegrationTeamCommandsAndQueries(t *testing.T) {
userIds = append(userIds, usr.ID)
userUIDs = append(userUIDs, usr.UID)
}
team1, err = teamSvc.CreateTeam(context.Background(), "group1 name", "test1@test.com", testOrgID)
team1Cmd := team.CreateTeamCommand{
Name: "group1 name",
Email: "test1@test.com",
OrgID: testOrgID,
}
team1, err = teamSvc.CreateTeam(context.Background(), &team1Cmd)
require.NoError(t, err)
team2, err = teamSvc.CreateTeam(context.Background(), "group2 name", "test2@test.com", testOrgID)
team2Cmd := team.CreateTeamCommand{
Name: "group2 name",
Email: "test2@test.com",
OrgID: testOrgID,
}
team2, err = teamSvc.CreateTeam(context.Background(), &team2Cmd)
require.NoError(t, err)
}
setup()
@@ -540,7 +552,12 @@ func TestIntegrationSQLStore_SearchTeams(t *testing.T) {
// Seed 10 teams
for i := 1; i <= 10; i++ {
_, err := teamSvc.CreateTeam(context.Background(), fmt.Sprintf("team-%d", i), fmt.Sprintf("team-%d@example.org", i), 1)
teamCmd := team.CreateTeamCommand{
Name: fmt.Sprintf("team-%d", i),
Email: fmt.Sprintf("team-%d@example.org", i),
OrgID: 1,
}
_, err := teamSvc.CreateTeam(context.Background(), &teamCmd)
require.NoError(t, err)
}
@@ -574,10 +591,23 @@ func TestIntegrationSQLStore_GetTeamMembers_ACFilter(t *testing.T) {
setup := func(store db.DB, cfg *setting.Cfg) {
teamSvc, err := ProvideService(store, cfg, tracing.InitializeTracerForTest())
require.NoError(t, err)
team1, errCreateTeam := teamSvc.CreateTeam(context.Background(), "group1 name", "test1@example.org", testOrgID)
team1Cmd := team.CreateTeamCommand{
Name: "group1 name",
Email: "test1@example.org",
OrgID: testOrgID,
}
team1, errCreateTeam := teamSvc.CreateTeam(context.Background(), &team1Cmd)
require.NoError(t, errCreateTeam)
team2, errCreateTeam := teamSvc.CreateTeam(context.Background(), "group2 name", "test2@example.org", testOrgID)
team2Cmd := team.CreateTeamCommand{
Name: "group2 name",
Email: "test2@example.org",
OrgID: testOrgID,
}
team2, errCreateTeam := teamSvc.CreateTeam(context.Background(), &team2Cmd)
require.NoError(t, errCreateTeam)
quotaService := quotaimpl.ProvideService(store, cfg)
orgSvc, err := orgimpl.ProvideService(store, cfg, quotaService)
require.NoError(t, err)
+4 -4
View File
@@ -32,13 +32,13 @@ func ProvideService(db db.DB, cfg *setting.Cfg, tracer tracing.Tracer) (team.Ser
}, nil
}
func (s *Service) CreateTeam(ctx context.Context, name, email string, orgID int64) (team.Team, error) {
func (s *Service) CreateTeam(ctx context.Context, cmd *team.CreateTeamCommand) (team.Team, error) {
_, span := s.tracer.Start(ctx, "team.CreateTeam", trace.WithAttributes(
attribute.Int64("orgID", orgID),
attribute.String("name", name),
attribute.Int64("orgID", cmd.OrgID),
attribute.String("name", cmd.Name),
))
defer span.End()
return s.store.Create(name, email, orgID)
return s.store.Create(ctx, cmd)
}
func (s *Service) UpdateTeam(ctx context.Context, cmd *team.UpdateTeamCommand) error {
+1 -1
View File
@@ -20,7 +20,7 @@ func NewFakeService() *FakeService {
return &FakeService{}
}
func (s *FakeService) CreateTeam(ctx context.Context, name, email string, orgID int64) (team.Team, error) {
func (s *FakeService) CreateTeam(ctx context.Context, cmd *team.CreateTeamCommand) (team.Team, error) {
return s.ExpectedTeam, s.ExpectedError
}
+6 -1
View File
@@ -688,7 +688,12 @@ func (c *K8sTestHelper) CreateDS(cmd *datasources.AddDataSourceCommand) *datasou
func (c *K8sTestHelper) CreateTeam(name, email string, orgID int64) team.Team {
c.t.Helper()
team, err := c.teamSvc.CreateTeam(context.Background(), name, email, orgID)
teamCmd := team.CreateTeamCommand{
Name: name,
Email: email,
OrgID: orgID,
}
team, err := c.teamSvc.CreateTeam(context.Background(), &teamCmd)
require.NoError(c.t, err)
return team
}
+6
View File
@@ -21063,10 +21063,16 @@
"email": {
"type": "string"
},
"externalUID": {
"type": "string"
},
"id": {
"type": "integer",
"format": "int64"
},
"isProvisioned": {
"type": "boolean"
},
"memberCount": {
"type": "integer",
"format": "int64"
+6
View File
@@ -11135,10 +11135,16 @@
"email": {
"type": "string"
},
"externalUID": {
"type": "string"
},
"id": {
"format": "int64",
"type": "integer"
},
"isProvisioned": {
"type": "boolean"
},
"memberCount": {
"format": "int64",
"type": "integer"