1
0
forked from baron/baron-sso

feat: automatically create default user groups upon tenant registration/approval

This commit is contained in:
2026-03-04 14:16:43 +09:00
parent 39b41a4c42
commit a973cd746b
2 changed files with 87 additions and 9 deletions

View File

@@ -265,7 +265,7 @@ func main() {
kratosAdminService := service.NewKratosAdminService()
oryAdminProvider := service.NewOryProvider()
tenantService := service.NewTenantService(tenantRepo, userRepo, ketoOutboxRepo)
tenantService := service.NewTenantService(tenantRepo, userRepo, userGroupRepo, ketoOutboxRepo)
userGroupService := service.NewUserGroupService(userGroupRepo, userRepo, tenantRepo, ketoService, ketoOutboxRepo, kratosAdminService)
tenantService.SetKetoService(ketoService) // Keto 주입

View File

@@ -26,17 +26,19 @@ type TenantService interface {
}
type tenantService struct {
repo repository.TenantRepository
userRepo repository.UserRepository
keto KetoService
outboxRepo repository.KetoOutboxRepository
repo repository.TenantRepository
userRepo repository.UserRepository
userGroupRepo repository.UserGroupRepository
keto KetoService
outboxRepo repository.KetoOutboxRepository
}
func NewTenantService(repo repository.TenantRepository, userRepo repository.UserRepository, outboxRepo repository.KetoOutboxRepository) TenantService {
func NewTenantService(repo repository.TenantRepository, userRepo repository.UserRepository, userGroupRepo repository.UserGroupRepository, outboxRepo repository.KetoOutboxRepository) TenantService {
return &tenantService{
repo: repo,
userRepo: userRepo,
outboxRepo: outboxRepo,
repo: repo,
userRepo: userRepo,
userGroupRepo: userGroupRepo,
outboxRepo: outboxRepo,
}
}
@@ -110,6 +112,51 @@ func (s *tenantService) RegisterTenant(ctx context.Context, name, slug, tenantTy
return nil, err
}
// [New] Create Default User Groups
if s.userGroupRepo != nil {
groups := []struct {
Name string
Slug string
}{
{Name: "임직원", Slug: "members"},
{Name: "관리자", Slug: "admins"},
}
for _, g := range groups {
newGroup := &domain.UserGroup{
TenantID: tenant.ID,
Name: g.Name,
Slug: g.Slug,
Description: tenant.Name + " " + g.Name + " 그룹",
}
if err := s.userGroupRepo.Create(ctx, newGroup); err == nil {
// Sync group to Keto via Outbox
if s.outboxRepo != nil {
_ = s.outboxRepo.Create(ctx, &domain.KetoOutbox{
Namespace: "UserGroup",
Object: newGroup.ID,
Relation: "tenants",
Subject: "Tenant:" + tenant.ID,
Action: domain.KetoOutboxActionCreate,
})
// If this is the 'admins' group and we have a creatorID, add creator to this group
if g.Slug == "admins" && creatorID != "" {
_ = s.outboxRepo.Create(ctx, &domain.KetoOutbox{
Namespace: "UserGroup",
Object: newGroup.ID,
Relation: "members",
Subject: "User:" + creatorID,
Action: domain.KetoOutboxActionCreate,
})
}
}
} else {
slog.Error("Failed to create default group", "group", g.Slug, "tenant", tenant.ID, "error", err)
}
}
}
// [Keto] Sync hierarchy and ownership via Outbox
if s.outboxRepo != nil {
// Sync hierarchy
@@ -209,6 +256,37 @@ func (s *tenantService) ApproveTenant(ctx context.Context, id string) error {
return err
}
// [New] Create Default User Groups upon approval
if s.userGroupRepo != nil {
groups := []struct {
Name string
Slug string
}{
{Name: "임직원", Slug: "members"},
{Name: "관리자", Slug: "admins"},
}
for _, g := range groups {
newGroup := &domain.UserGroup{
TenantID: tenant.ID,
Name: g.Name,
Slug: g.Slug,
Description: tenant.Name + " " + g.Name + " 그룹",
}
if err := s.userGroupRepo.Create(ctx, newGroup); err == nil {
if s.outboxRepo != nil {
_ = s.outboxRepo.Create(ctx, &domain.KetoOutbox{
Namespace: "UserGroup",
Object: newGroup.ID,
Relation: "tenants",
Subject: "Tenant:" + tenant.ID,
Action: domain.KetoOutboxActionCreate,
})
}
}
}
}
// [Keto] Sync relation via Outbox
if s.outboxRepo != nil {
if adminEmail, ok := tenant.Config["adminEmail"].(string); ok && adminEmail != "" {