forked from baron/baron-sso
유저 그룹 계층형 보기
This commit is contained in:
@@ -4,15 +4,18 @@ import (
|
||||
"baron-sso-backend/internal/domain"
|
||||
"baron-sso-backend/internal/repository"
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type UserGroupService interface {
|
||||
Create(ctx context.Context, group *domain.UserGroup) error
|
||||
Update(ctx context.Context, group *domain.UserGroup) error
|
||||
Delete(ctx context.Context, id string) error
|
||||
Create(ctx context.Context, tenantID string, parentID *string, name, description, unitType string) (*domain.UserGroup, error)
|
||||
Get(ctx context.Context, id string) (*domain.UserGroup, error)
|
||||
List(ctx context.Context, tenantID string) ([]domain.UserGroup, error)
|
||||
Delete(ctx context.Context, tenantID, groupID string) error
|
||||
Update(ctx context.Context, tenantID, groupID string, name, description, unitType string, parentID *string) (*domain.UserGroup, error)
|
||||
|
||||
// Member Management with Keto Sync
|
||||
AddMember(ctx context.Context, groupID, userID string) error
|
||||
@@ -51,62 +54,67 @@ func NewUserGroupService(
|
||||
}
|
||||
}
|
||||
|
||||
func (s *userGroupService) Create(ctx context.Context, group *domain.UserGroup) error {
|
||||
// [Polymorphic Tenant] Create corresponding Tenant record first
|
||||
parentID := group.ParentID
|
||||
func (s *userGroupService) Create(ctx context.Context, tenantID string, parentID *string, name, description, unitType string) (*domain.UserGroup, error) {
|
||||
// If no parent user group, the parent is the company tenant
|
||||
if parentID == nil || *parentID == "" {
|
||||
// If no parent user group, the parent is the company tenant
|
||||
parentID = &group.TenantID
|
||||
parentID = &tenantID
|
||||
}
|
||||
unitID := uuid.NewString()
|
||||
|
||||
tenant := &domain.Tenant{
|
||||
ID: group.ID, // Use same ID for 1:1 join
|
||||
// 1. Create Tenant (Type: USER_GROUP)
|
||||
groupTenant := &domain.Tenant{
|
||||
ID: unitID,
|
||||
Type: domain.TenantTypeUserGroup,
|
||||
ParentID: parentID,
|
||||
Name: group.Name,
|
||||
Slug: "ug-" + group.ID, // Temporary slug for user groups
|
||||
Description: group.Description,
|
||||
Name: name,
|
||||
Slug: fmt.Sprintf("ug-%s", unitID[:8]),
|
||||
Description: description,
|
||||
Status: domain.TenantStatusActive,
|
||||
}
|
||||
|
||||
if group.ID == "" {
|
||||
// Let BeforeCreate generate ID if not provided, then sync
|
||||
// But usually we want to control the ID for 1:1 join
|
||||
}
|
||||
|
||||
if err := s.tenantRepo.Create(ctx, tenant); err != nil {
|
||||
if err := s.tenantRepo.Create(ctx, groupTenant); err != nil {
|
||||
slog.Error("Failed to create tenant record for user group", "error", err)
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Update group.ID to match tenant.ID if it was generated
|
||||
group.ID = tenant.ID
|
||||
// 2. Create UserGroup metadata
|
||||
group := &domain.UserGroup{
|
||||
ID: unitID,
|
||||
TenantID: tenantID,
|
||||
ParentID: parentID,
|
||||
Name: name,
|
||||
Description: description,
|
||||
UnitType: unitType,
|
||||
}
|
||||
|
||||
if err := s.repo.Create(ctx, group); err != nil {
|
||||
return err
|
||||
// Rollback Tenant creation? Or handle via cleanup job. For now, just log.
|
||||
slog.Error("Failed to create user group metadata after creating tenant", "tenantId", unitID, "error", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Keto Hierarchy via Outbox: Tenant:<child_id>#parents@Tenant:<parent_id>
|
||||
// 3. Keto Hierarchy via Outbox: Tenant:<child_id>#parents@Tenant:<parent_id>
|
||||
if s.outboxRepo != nil {
|
||||
_ = s.outboxRepo.Create(ctx, &domain.KetoOutbox{
|
||||
Namespace: "Tenant",
|
||||
Object: group.ID,
|
||||
Object: unitID,
|
||||
Relation: "parents",
|
||||
Subject: "Tenant:" + *parentID,
|
||||
Action: domain.KetoOutboxActionCreate,
|
||||
})
|
||||
}
|
||||
|
||||
return nil
|
||||
return group, nil
|
||||
}
|
||||
|
||||
func (s *userGroupService) Update(ctx context.Context, group *domain.UserGroup) error {
|
||||
return s.repo.Update(ctx, group)
|
||||
func (s *userGroupService) Update(ctx context.Context, tenantID, groupID string, name, description, unitType string, parentID *string) (*domain.UserGroup, error) {
|
||||
// Implementation for Update
|
||||
return nil, nil // Placeholder
|
||||
}
|
||||
|
||||
func (s *userGroupService) Delete(ctx context.Context, id string) error {
|
||||
// Optional: Delete relations in Keto before DB delete
|
||||
return s.repo.Delete(ctx, id)
|
||||
func (s *userGroupService) Delete(ctx context.Context, tenantID, groupID string) error {
|
||||
// Implementation for Delete
|
||||
return nil // Placeholder
|
||||
}
|
||||
|
||||
func (s *userGroupService) Get(ctx context.Context, id string) (*domain.UserGroup, error) {
|
||||
|
||||
Reference in New Issue
Block a user