package handler import ( "baron-sso-backend/internal/domain" "baron-sso-backend/internal/service" "context" "errors" "fmt" "strings" "github.com/google/uuid" ) func representativeTenantIDFromTraits(traits map[string]any) string { if value := tenantClaimString(traits, "tenant_id"); value != "" { return value } if value := tenantClaimString(traits, "primaryTenantId"); value != "" { return value } if metadata, ok := traits["metadata"].(map[string]any); ok { if value := tenantClaimString(metadata, "primaryTenantId"); value != "" { return value } } appointments := tenantAssignmentAppointmentsFromTraits(traits) for _, appointment := range appointments { if tenantAssignmentBool(appointment, "isPrimary", "primary", "representative", "isRepresentative") { if value := tenantAssignmentTenantID(appointment); value != "" { return value } } } for _, appointment := range appointments { if value := tenantAssignmentTenantID(appointment); value != "" { return value } } for _, tenantID := range tenantNamespaceIDsFromTraits(traits) { return tenantID } return "" } func joinedTenantIDsFromTraits(traits map[string]any, representativeTenantID string) []string { values := make([]string, 0) if representativeTenantID != "" { values = append(values, representativeTenantID) } if value := tenantClaimString(traits, "tenant_id"); value != "" { values = append(values, value) } for _, appointment := range tenantAssignmentAppointmentsFromTraits(traits) { if value := tenantAssignmentTenantID(appointment); value != "" { values = append(values, value) } } values = append(values, tenantNamespaceIDsFromTraits(traits)...) return uniqueSortedStrings(values) } func tenantAssignmentAppointmentsFromTraits(traits map[string]any) []map[string]any { raw := rawAdditionalAppointments(traits) switch values := raw.(type) { case []any: appointments := make([]map[string]any, 0, len(values)) for _, item := range values { if appointment, ok := item.(map[string]any); ok { appointments = append(appointments, appointment) } } return appointments case []map[string]any: return values default: return nil } } func tenantAssignmentTenantID(appointment map[string]any) string { for _, key := range []string{"tenantId", "tenant_id"} { if value := tenantClaimString(appointment, key); value != "" { return value } } return "" } func tenantAssignmentBool(values map[string]any, keys ...string) bool { for _, key := range keys { raw, ok := values[key] if !ok || raw == nil { continue } switch value := raw.(type) { case bool: if value { return true } case string: normalized := strings.ToLower(strings.TrimSpace(value)) if normalized == "true" || normalized == "1" || normalized == "yes" { return true } } } return false } func tenantNamespaceIDsFromTraits(traits map[string]any) []string { if traits == nil { return nil } ids := make([]string, 0) for key, value := range traits { if key == "" || key == "metadata" { continue } switch value.(type) { case map[string]any: ids = append(ids, key) } } return uniqueSortedStrings(ids) } func createPersonalTenantForUser(ctx context.Context, tenantService service.TenantService, email string) (*domain.Tenant, error) { if tenantService == nil { return nil, errors.New("tenant service unavailable") } normalizedEmail := strings.ToLower(strings.TrimSpace(email)) if normalizedEmail == "" { normalizedEmail = "user" } slug := "personal-" + strings.ReplaceAll(uuid.NewString(), "-", "") tenant, err := tenantService.RegisterTenant( ctx, fmt.Sprintf("Personal - %s", normalizedEmail), slug, domain.TenantTypePersonal, "Automatically provisioned personal tenant", nil, nil, "", ) if err != nil { return nil, err } if tenant == nil { return nil, errors.New("personal tenant not created") } return tenant, nil }