forked from baron/baron-sso
네이버 계정 정합성 맞춤
This commit is contained in:
@@ -2,15 +2,18 @@ package main
|
||||
|
||||
import (
|
||||
"baron-sso-backend/internal/bootstrap"
|
||||
"baron-sso-backend/internal/domain"
|
||||
"baron-sso-backend/internal/idp"
|
||||
"baron-sso-backend/internal/logger"
|
||||
"baron-sso-backend/internal/repository"
|
||||
"baron-sso-backend/internal/service"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"log/slog"
|
||||
"maps"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -32,6 +35,16 @@ type clearOrphanUserTenantMembershipsConfig struct {
|
||||
DryRun bool
|
||||
}
|
||||
|
||||
type repairDeletedTenantIdentitiesConfig struct {
|
||||
DryRun bool
|
||||
}
|
||||
|
||||
type repairUserTenantConfig struct {
|
||||
UserID string
|
||||
TenantSlug string
|
||||
RemoveTenantSlug string
|
||||
}
|
||||
|
||||
func main() {
|
||||
loadEnv()
|
||||
logger.Init(logger.Config{
|
||||
@@ -56,6 +69,16 @@ func main() {
|
||||
slog.Error("clear-orphan-user-tenant-memberships failed", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
case "repair-deleted-tenant-identities":
|
||||
if err := runRepairDeletedTenantIdentities(os.Args[2:]); err != nil {
|
||||
slog.Error("repair-deleted-tenant-identities failed", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
case "repair-user-tenant":
|
||||
if err := runRepairUserTenant(os.Args[2:]); err != nil {
|
||||
slog.Error("repair-user-tenant failed", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
case "worksmobile-sync":
|
||||
if err := runWorksmobileSync(os.Args[2:]); err != nil {
|
||||
slog.Error("worksmobile-sync failed", "error", err)
|
||||
@@ -121,6 +144,69 @@ func runCreateSuperAdmin(args []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func runRepairUserTenant(args []string) error {
|
||||
config, err := resolveRepairUserTenantConfig(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
db, err := openDB()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
defer cancel()
|
||||
|
||||
var tenant domain.Tenant
|
||||
if err := db.WithContext(ctx).First(&tenant, "slug = ?", config.TenantSlug).Error; err != nil {
|
||||
return fmt.Errorf("target tenant not found slug=%s: %w", config.TenantSlug, err)
|
||||
}
|
||||
|
||||
var removeTenant *domain.Tenant
|
||||
if config.RemoveTenantSlug != "" {
|
||||
var found domain.Tenant
|
||||
if err := db.WithContext(ctx).First(&found, "slug = ?", config.RemoveTenantSlug).Error; err != nil {
|
||||
return fmt.Errorf("remove tenant not found slug=%s: %w", config.RemoveTenantSlug, err)
|
||||
}
|
||||
removeTenant = &found
|
||||
}
|
||||
|
||||
kratos := service.NewKratosAdminService()
|
||||
identity, err := kratos.GetIdentity(ctx, config.UserID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if identity == nil {
|
||||
return fmt.Errorf("identity not found: %s", config.UserID)
|
||||
}
|
||||
traits := adminctlCloneIdentityTraits(identity.Traits)
|
||||
adminctlSetPrimaryTenantTraits(traits, tenant, removeTenant)
|
||||
updated, err := kratos.UpdateIdentity(ctx, config.UserID, traits, identity.State)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if updated == nil {
|
||||
return fmt.Errorf("kratos update returned empty identity")
|
||||
}
|
||||
|
||||
if err := db.WithContext(ctx).
|
||||
Model(&domain.User{}).
|
||||
Where("id = ?", config.UserID).
|
||||
Updates(map[string]any{
|
||||
"tenant_id": tenant.ID,
|
||||
"metadata": domain.JSONMap(updated.Traits),
|
||||
"updated_at": time.Now(),
|
||||
}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if redisService, err := service.NewRedisService(); err == nil {
|
||||
_, _ = redisService.FlushIdentityCache(ctx)
|
||||
} else {
|
||||
slog.Warn("identity mirror flush skipped", "error", err)
|
||||
}
|
||||
fmt.Printf("user tenant repaired: user=%s tenant=%s<%s> removed=%s\n", config.UserID, tenant.Name, tenant.Slug, config.RemoveTenantSlug)
|
||||
return nil
|
||||
}
|
||||
|
||||
func runClearOrphanUserTenantMemberships(args []string) error {
|
||||
config, err := resolveClearOrphanUserTenantMembershipsConfig(args)
|
||||
if err != nil {
|
||||
@@ -152,6 +238,92 @@ func runClearOrphanUserTenantMemberships(args []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func runRepairDeletedTenantIdentities(args []string) error {
|
||||
config, err := resolveRepairDeletedTenantIdentitiesConfig(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
db, err := openDB()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
|
||||
defer cancel()
|
||||
|
||||
var tenants []domain.Tenant
|
||||
if err := db.WithContext(ctx).Unscoped().Find(&tenants).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
tenantByID, deletedBySlug := adminctlTenantIndexes(tenants)
|
||||
kratos := service.NewKratosAdminService()
|
||||
identities, err := kratos.ListIdentities(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
scanned := 0
|
||||
candidates := 0
|
||||
updated := 0
|
||||
localUpdated := int64(0)
|
||||
for _, identity := range identities {
|
||||
scanned++
|
||||
deletedTenant, targetTenant, ok := adminctlDeletedTenantPromotion(identity.Traits, tenantByID, deletedBySlug)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
candidates++
|
||||
nextTraits, changed := adminctlPromoteIdentityTraits(identity.Traits, deletedTenant, targetTenant)
|
||||
if !changed {
|
||||
continue
|
||||
}
|
||||
fmt.Printf("repair candidate: user=%s email=%s deleted=%s<%s> target=%s<%s>\n",
|
||||
identity.ID,
|
||||
adminctlTraitString(identity.Traits["email"]),
|
||||
deletedTenant.Name,
|
||||
adminctlLegacyTenantSlug(deletedTenant),
|
||||
targetTenant.Name,
|
||||
targetTenant.Slug,
|
||||
)
|
||||
if config.DryRun {
|
||||
continue
|
||||
}
|
||||
if _, err := kratos.UpdateIdentity(ctx, identity.ID, nextTraits, identity.State); err != nil {
|
||||
return fmt.Errorf("update kratos identity user=%s: %w", identity.ID, err)
|
||||
}
|
||||
result := db.WithContext(ctx).
|
||||
Model(&domain.User{}).
|
||||
Where("id = ?", identity.ID).
|
||||
Updates(map[string]any{"tenant_id": targetTenant.ID, "updated_at": time.Now()})
|
||||
if result.Error != nil {
|
||||
return result.Error
|
||||
}
|
||||
localUpdated += result.RowsAffected
|
||||
updated++
|
||||
}
|
||||
|
||||
orphanUpdated := int64(0)
|
||||
if !config.DryRun {
|
||||
affected, err := repository.ClearOrphanUserTenantMemberships(ctx, db)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
orphanUpdated = affected
|
||||
if redisService, err := service.NewRedisService(); err == nil {
|
||||
if _, err := redisService.FlushIdentityCache(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
slog.Warn("identity mirror flush skipped", "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("deleted tenant identity repair: scanned=%d candidates=%d kratos_updated=%d local_users_updated=%d orphan_memberships_updated=%d dry_run=%t\n",
|
||||
scanned, candidates, updated, localUpdated, orphanUpdated, config.DryRun)
|
||||
return nil
|
||||
}
|
||||
|
||||
func resolveCreateSuperAdminConfig(args []string) (createSuperAdminConfig, error) {
|
||||
fs := flag.NewFlagSet("create-super-admin", flag.ContinueOnError)
|
||||
fs.SetOutput(os.Stderr)
|
||||
@@ -193,6 +365,294 @@ func resolveClearOrphanUserTenantMembershipsConfig(args []string) (clearOrphanUs
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func resolveRepairDeletedTenantIdentitiesConfig(args []string) (repairDeletedTenantIdentitiesConfig, error) {
|
||||
fs := flag.NewFlagSet("repair-deleted-tenant-identities", flag.ContinueOnError)
|
||||
fs.SetOutput(os.Stderr)
|
||||
|
||||
config := repairDeletedTenantIdentitiesConfig{}
|
||||
fs.BoolVar(&config.DryRun, "dry-run", false, "print identities that reference deleted tenants without updating Kratos or local DB")
|
||||
|
||||
if err := fs.Parse(args); err != nil {
|
||||
return config, err
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func resolveRepairUserTenantConfig(args []string) (repairUserTenantConfig, error) {
|
||||
fs := flag.NewFlagSet("repair-user-tenant", flag.ContinueOnError)
|
||||
fs.SetOutput(os.Stderr)
|
||||
|
||||
config := repairUserTenantConfig{}
|
||||
fs.StringVar(&config.UserID, "user-id", "", "identity/user id to repair")
|
||||
fs.StringVar(&config.TenantSlug, "tenant-slug", "", "target representative tenant slug")
|
||||
fs.StringVar(&config.RemoveTenantSlug, "remove-tenant-slug", "", "appointment tenant slug to remove")
|
||||
|
||||
if err := fs.Parse(args); err != nil {
|
||||
return config, err
|
||||
}
|
||||
config.UserID = strings.TrimSpace(config.UserID)
|
||||
config.TenantSlug = strings.TrimSpace(config.TenantSlug)
|
||||
config.RemoveTenantSlug = strings.TrimSpace(config.RemoveTenantSlug)
|
||||
if config.UserID == "" {
|
||||
return config, fmt.Errorf("--user-id is required")
|
||||
}
|
||||
if config.TenantSlug == "" {
|
||||
return config, fmt.Errorf("--tenant-slug is required")
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func adminctlSetPrimaryTenantTraits(traits map[string]any, target domain.Tenant, removeTenant *domain.Tenant) {
|
||||
traits["tenant_id"] = target.ID
|
||||
traits["primaryTenantId"] = target.ID
|
||||
traits["primaryTenantSlug"] = target.Slug
|
||||
traits["primaryTenantName"] = target.Name
|
||||
delete(traits, "companyCode")
|
||||
delete(traits, "companyCodes")
|
||||
|
||||
rawAppointments, _ := adminctlPromoteIdentityAppointments(traits["additionalAppointments"], target, target)
|
||||
if rawAppointments == nil {
|
||||
rawAppointments = []any{}
|
||||
}
|
||||
next := make([]any, 0, len(rawAppointments)+1)
|
||||
targetSeen := false
|
||||
for _, raw := range rawAppointments {
|
||||
appointment, ok := raw.(map[string]any)
|
||||
if !ok {
|
||||
next = append(next, raw)
|
||||
continue
|
||||
}
|
||||
if removeTenant != nil && adminctlAppointmentMatchesTenant(appointment, *removeTenant) {
|
||||
continue
|
||||
}
|
||||
copied := maps.Clone(appointment)
|
||||
if adminctlAppointmentMatchesTenant(copied, target) {
|
||||
copied["tenantId"] = target.ID
|
||||
copied["tenantSlug"] = target.Slug
|
||||
copied["tenantName"] = target.Name
|
||||
copied["isPrimary"] = true
|
||||
targetSeen = true
|
||||
} else {
|
||||
copied["isPrimary"] = false
|
||||
}
|
||||
next = append(next, copied)
|
||||
}
|
||||
if !targetSeen {
|
||||
next = append(next, map[string]any{
|
||||
"tenantId": target.ID,
|
||||
"tenantSlug": target.Slug,
|
||||
"tenantName": target.Name,
|
||||
"isPrimary": true,
|
||||
})
|
||||
}
|
||||
traits["additionalAppointments"] = next
|
||||
}
|
||||
|
||||
func adminctlAppointmentMatchesTenant(appointment map[string]any, tenant domain.Tenant) bool {
|
||||
return adminctlTraitMatchesTenant(appointment["tenantId"], tenant) ||
|
||||
adminctlTraitMatchesTenant(appointment["tenantSlug"], tenant)
|
||||
}
|
||||
|
||||
func adminctlTenantIndexes(tenants []domain.Tenant) (map[string]domain.Tenant, map[string]domain.Tenant) {
|
||||
tenantByID := make(map[string]domain.Tenant, len(tenants))
|
||||
deletedBySlug := map[string]domain.Tenant{}
|
||||
for _, tenant := range tenants {
|
||||
tenantByID[tenant.ID] = tenant
|
||||
if tenant.DeletedAt.Valid {
|
||||
if slug := strings.ToLower(strings.TrimSpace(tenant.Slug)); slug != "" {
|
||||
deletedBySlug[slug] = tenant
|
||||
}
|
||||
if legacy := adminctlLegacyTenantSlug(tenant); legacy != "" {
|
||||
deletedBySlug[strings.ToLower(legacy)] = tenant
|
||||
}
|
||||
}
|
||||
}
|
||||
return tenantByID, deletedBySlug
|
||||
}
|
||||
|
||||
func adminctlDeletedTenantPromotion(traits map[string]any, tenantByID map[string]domain.Tenant, deletedBySlug map[string]domain.Tenant) (domain.Tenant, domain.Tenant, bool) {
|
||||
deleted, ok := adminctlFindDeletedTenantInTraits(traits, tenantByID, deletedBySlug)
|
||||
if !ok {
|
||||
return domain.Tenant{}, domain.Tenant{}, false
|
||||
}
|
||||
target, ok := adminctlNearestActiveAncestor(deleted, tenantByID)
|
||||
return deleted, target, ok
|
||||
}
|
||||
|
||||
func adminctlFindDeletedTenantInTraits(traits map[string]any, tenantByID map[string]domain.Tenant, deletedBySlug map[string]domain.Tenant) (domain.Tenant, bool) {
|
||||
for _, key := range []string{"tenant_id", "primaryTenantId", "primaryTenantSlug", "companyCode", "company_code"} {
|
||||
if tenant, ok := adminctlDeletedTenantFromValue(traits[key], tenantByID, deletedBySlug); ok {
|
||||
return tenant, true
|
||||
}
|
||||
}
|
||||
switch appointments := traits["additionalAppointments"].(type) {
|
||||
case []any:
|
||||
for _, raw := range appointments {
|
||||
appointment, ok := raw.(map[string]any)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
for _, key := range []string{"tenantId", "tenantSlug"} {
|
||||
if tenant, ok := adminctlDeletedTenantFromValue(appointment[key], tenantByID, deletedBySlug); ok {
|
||||
return tenant, true
|
||||
}
|
||||
}
|
||||
}
|
||||
case []map[string]any:
|
||||
for _, appointment := range appointments {
|
||||
for _, key := range []string{"tenantId", "tenantSlug"} {
|
||||
if tenant, ok := adminctlDeletedTenantFromValue(appointment[key], tenantByID, deletedBySlug); ok {
|
||||
return tenant, true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return domain.Tenant{}, false
|
||||
}
|
||||
|
||||
func adminctlDeletedTenantFromValue(value any, tenantByID map[string]domain.Tenant, deletedBySlug map[string]domain.Tenant) (domain.Tenant, bool) {
|
||||
raw := strings.TrimSpace(fmt.Sprint(value))
|
||||
if raw == "" || raw == "<nil>" {
|
||||
return domain.Tenant{}, false
|
||||
}
|
||||
if tenant, ok := tenantByID[raw]; ok && tenant.DeletedAt.Valid {
|
||||
return tenant, true
|
||||
}
|
||||
tenant, ok := deletedBySlug[strings.ToLower(raw)]
|
||||
return tenant, ok
|
||||
}
|
||||
|
||||
func adminctlNearestActiveAncestor(deleted domain.Tenant, tenantByID map[string]domain.Tenant) (domain.Tenant, bool) {
|
||||
seen := map[string]bool{}
|
||||
parentID := deleted.ParentID
|
||||
for parentID != nil {
|
||||
id := strings.TrimSpace(*parentID)
|
||||
if id == "" || seen[id] {
|
||||
return domain.Tenant{}, false
|
||||
}
|
||||
seen[id] = true
|
||||
parent, ok := tenantByID[id]
|
||||
if !ok {
|
||||
return domain.Tenant{}, false
|
||||
}
|
||||
if !parent.DeletedAt.Valid {
|
||||
return parent, true
|
||||
}
|
||||
parentID = parent.ParentID
|
||||
}
|
||||
return domain.Tenant{}, false
|
||||
}
|
||||
|
||||
func adminctlPromoteIdentityTraits(traits map[string]any, deletedTenant domain.Tenant, targetTenant domain.Tenant) (map[string]any, bool) {
|
||||
next := adminctlCloneIdentityTraits(traits)
|
||||
changed := false
|
||||
if adminctlTraitMatchesTenant(next["tenant_id"], deletedTenant) || strings.TrimSpace(adminctlTraitString(next["tenant_id"])) == "" {
|
||||
next["tenant_id"] = targetTenant.ID
|
||||
changed = true
|
||||
}
|
||||
if adminctlTraitMatchesTenant(next["primaryTenantId"], deletedTenant) || adminctlTraitMatchesTenant(next["primaryTenantSlug"], deletedTenant) {
|
||||
next["primaryTenantId"] = targetTenant.ID
|
||||
next["primaryTenantSlug"] = targetTenant.Slug
|
||||
next["primaryTenantName"] = targetTenant.Name
|
||||
changed = true
|
||||
}
|
||||
if adminctlTraitMatchesTenant(next["companyCode"], deletedTenant) {
|
||||
next["companyCode"] = targetTenant.Slug
|
||||
changed = true
|
||||
}
|
||||
if adminctlTraitMatchesTenant(next["company_code"], deletedTenant) {
|
||||
next["company_code"] = targetTenant.Slug
|
||||
changed = true
|
||||
}
|
||||
if appointments, appointmentsChanged := adminctlPromoteIdentityAppointments(next["additionalAppointments"], deletedTenant, targetTenant); appointmentsChanged {
|
||||
next["additionalAppointments"] = appointments
|
||||
changed = true
|
||||
}
|
||||
return next, changed
|
||||
}
|
||||
|
||||
func adminctlPromoteIdentityAppointments(raw any, deletedTenant domain.Tenant, targetTenant domain.Tenant) ([]any, bool) {
|
||||
switch appointments := raw.(type) {
|
||||
case []any:
|
||||
next := make([]any, 0, len(appointments))
|
||||
changed := false
|
||||
for _, rawAppointment := range appointments {
|
||||
appointment, ok := rawAppointment.(map[string]any)
|
||||
if !ok {
|
||||
next = append(next, rawAppointment)
|
||||
continue
|
||||
}
|
||||
copied := maps.Clone(appointment)
|
||||
if adminctlTraitMatchesTenant(copied["tenantId"], deletedTenant) || adminctlTraitMatchesTenant(copied["tenantSlug"], deletedTenant) {
|
||||
copied["tenantId"] = targetTenant.ID
|
||||
copied["tenantSlug"] = targetTenant.Slug
|
||||
copied["tenantName"] = targetTenant.Name
|
||||
changed = true
|
||||
}
|
||||
next = append(next, copied)
|
||||
}
|
||||
return next, changed
|
||||
case []map[string]any:
|
||||
next := make([]any, 0, len(appointments))
|
||||
changed := false
|
||||
for _, appointment := range appointments {
|
||||
copied := maps.Clone(appointment)
|
||||
if adminctlTraitMatchesTenant(copied["tenantId"], deletedTenant) || adminctlTraitMatchesTenant(copied["tenantSlug"], deletedTenant) {
|
||||
copied["tenantId"] = targetTenant.ID
|
||||
copied["tenantSlug"] = targetTenant.Slug
|
||||
copied["tenantName"] = targetTenant.Name
|
||||
changed = true
|
||||
}
|
||||
next = append(next, copied)
|
||||
}
|
||||
return next, changed
|
||||
default:
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
|
||||
func adminctlTraitMatchesTenant(value any, tenant domain.Tenant) bool {
|
||||
raw := strings.TrimSpace(adminctlTraitString(value))
|
||||
if raw == "" {
|
||||
return false
|
||||
}
|
||||
if strings.EqualFold(raw, tenant.ID) || strings.EqualFold(raw, tenant.Slug) {
|
||||
return true
|
||||
}
|
||||
return strings.EqualFold(raw, adminctlLegacyTenantSlug(tenant))
|
||||
}
|
||||
|
||||
func adminctlLegacyTenantSlug(tenant domain.Tenant) string {
|
||||
slug := strings.TrimSpace(tenant.Slug)
|
||||
idx := strings.LastIndex(slug, "-deleted-")
|
||||
if idx <= 0 {
|
||||
return slug
|
||||
}
|
||||
return slug[:idx]
|
||||
}
|
||||
|
||||
func adminctlTraitString(value any) string {
|
||||
if value == nil {
|
||||
return ""
|
||||
}
|
||||
return strings.TrimSpace(fmt.Sprint(value))
|
||||
}
|
||||
|
||||
func adminctlCloneIdentityTraits(traits map[string]any) map[string]any {
|
||||
if traits == nil {
|
||||
return map[string]any{}
|
||||
}
|
||||
raw, err := json.Marshal(traits)
|
||||
if err != nil {
|
||||
return maps.Clone(traits)
|
||||
}
|
||||
var next map[string]any
|
||||
if err := json.Unmarshal(raw, &next); err != nil {
|
||||
return maps.Clone(traits)
|
||||
}
|
||||
return next
|
||||
}
|
||||
|
||||
func openDB() (*gorm.DB, error) {
|
||||
dsn := fmt.Sprintf(
|
||||
"host=%s user=%s password=%s dbname=%s port=%s sslmode=disable TimeZone=Asia/Seoul",
|
||||
@@ -232,5 +692,7 @@ func printUsage() {
|
||||
fmt.Fprintln(os.Stderr, "usage:")
|
||||
fmt.Fprintln(os.Stderr, " adminctl create-super-admin [--email EMAIL] [--password PASSWORD] [--name NAME] [--update-password]")
|
||||
fmt.Fprintln(os.Stderr, " adminctl clear-orphan-user-tenant-memberships [--dry-run]")
|
||||
fmt.Fprintln(os.Stderr, " adminctl repair-deleted-tenant-identities [--dry-run]")
|
||||
fmt.Fprintln(os.Stderr, " adminctl repair-user-tenant --user-id ID --tenant-slug SLUG [--remove-tenant-slug SLUG]")
|
||||
fmt.Fprintln(os.Stderr, " adminctl worksmobile-sync [--orgunits] [--users-csv PATH] [--credential-batch-id ID] [--process] [--serialize-orgunits] [--serialize-users-batch ID] [--batch-size N] [--delay DURATION]")
|
||||
}
|
||||
|
||||
@@ -160,7 +160,6 @@ func TestRecreatePendingWorksmobileUsersFromSnapshotCreatesOnlyMatchedUsers(t *t
|
||||
writer,
|
||||
client,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("recreatePendingWorksmobileUsersFromSnapshot returned error: %v", err)
|
||||
}
|
||||
@@ -224,7 +223,6 @@ func TestRecreatePendingWorksmobileUsersFromSnapshotRollsBackWhenCreateFails(t *
|
||||
writer,
|
||||
client,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("recreatePendingWorksmobileUsersFromSnapshot returned error: %v", err)
|
||||
}
|
||||
@@ -283,7 +281,6 @@ func TestImportHanmacWorksmobileUsersFromRowsSkipsExistingRemoteLocalPart(t *tes
|
||||
writer,
|
||||
client,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("importHanmacWorksmobileUsersFromRows returned error: %v", err)
|
||||
}
|
||||
@@ -341,7 +338,6 @@ func TestImportHanmacWorksmobileUsersFromRowsSavesBaronUserAndCreatesWorksmobile
|
||||
writer,
|
||||
client,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("importHanmacWorksmobileUsersFromRows returned error: %v", err)
|
||||
}
|
||||
@@ -409,7 +405,6 @@ func TestImportHanmacWorksmobileUsersFromRowsKeepsExternalSubEmailOutOfWorksmobi
|
||||
writer,
|
||||
client,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("importHanmacWorksmobileUsersFromRows returned error: %v", err)
|
||||
}
|
||||
@@ -441,7 +436,6 @@ func TestBuildAdminctlWorksmobileOrgUnitPayloadClearsDomainRootParent(t *testing
|
||||
companyID: company,
|
||||
orgID: org,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("buildAdminctlWorksmobileOrgUnitPayload returned error: %v", err)
|
||||
}
|
||||
@@ -512,6 +506,10 @@ func (f *fakeWorksmobilePendingRecreateClient) UpsertUser(ctx context.Context, p
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakeWorksmobilePendingRecreateClient) UpdateUserOnly(ctx context.Context, payload service.WorksmobileUserPayload) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakeWorksmobilePendingRecreateClient) AddUserAliasEmail(ctx context.Context, userID string, email string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user