1
0
forked from baron/baron-sso

사용자 테넌트 소속 데이터 정리

This commit is contained in:
2026-05-13 18:23:39 +09:00
parent 8a6e41d74c
commit e36a973053
26 changed files with 348 additions and 387 deletions

View File

@@ -583,7 +583,10 @@ func TestUserHandler_BulkCreateUsers_AppendsEmailDomainTenantAtLowestPriority(t
}, nil).Once()
mockOry.On("GetPasswordPolicy").Return(&domain.PasswordPolicy{MinLength: 8}, nil)
mockOry.On("CreateUser", mock.MatchedBy(func(user *domain.BrokerUser) bool {
if user.Attributes["tenant_id"] != "t-gpdtdc" || user.Attributes["companyCode"] != "gpdtdc" {
if user.Attributes["tenant_id"] != "t-gpdtdc" {
return false
}
if _, hasCompanyCode := user.Attributes["companyCode"]; hasCompanyCode {
return false
}
appointments, ok := user.Attributes["additionalAppointments"].([]any)
@@ -653,8 +656,9 @@ func TestUserHandler_BulkCreateUsers_UsesEmailDomainTenantAsPrimaryWhenExplicitT
}, nil)
mockOry.On("GetPasswordPolicy").Return(&domain.PasswordPolicy{MinLength: 8}, nil)
mockOry.On("CreateUser", mock.MatchedBy(func(user *domain.BrokerUser) bool {
_, hasCompanyCode := user.Attributes["companyCode"]
return user.Attributes["tenant_id"] == "t-saman" &&
user.Attributes["companyCode"] == "saman" &&
!hasCompanyCode &&
user.Attributes["additionalAppointments"] == nil
}), mock.Anything).Return("u-domain-primary", nil).Once()
@@ -891,9 +895,9 @@ func TestUserHandler_CreateUser_HanmacEmailPolicyBlocksDuplicateLocalPart(t *tes
mockRepo.On("FindByCompanyCodes", mock.Anything, []string{"hanmac-family", "hanmac"}).Return([]domain.User{}, nil).Once()
payload := map[string]interface{}{
"email": "han@samaneng.com",
"name": "한치영",
"companyCode": "hanmac",
"email": "han@samaneng.com",
"name": "한치영",
"tenantSlug": "hanmac",
}
body, _ := json.Marshal(payload)
req := httptest.NewRequest("POST", "/users", bytes.NewReader(body))
@@ -1404,9 +1408,9 @@ func TestUserHandler_CreateUser_LoginIDSync(t *testing.T) {
mockTenant.On("ListManageableTenants", mock.Anything, "u-1").Return([]domain.Tenant{}, nil).Once()
payload := map[string]interface{}{
"email": "new@test.com",
"name": "New User",
"companyCode": "test-tenant",
"email": "new@test.com",
"name": "New User",
"tenantSlug": "test-tenant",
"metadata": map[string]interface{}{
tenantID: map[string]interface{}{
"emp_no": "E1001",
@@ -1451,8 +1455,9 @@ func TestUserHandler_CreateUser_UsesAdditionalAppointmentAsPrimaryTenant(t *test
mockTenant.On("ListTenants", mock.Anything, 10000, 0, "").Return([]domain.Tenant{}, int64(0), nil)
mockOry.On("GetPasswordPolicy").Return(&domain.PasswordPolicy{MinLength: 8}, nil)
mockOry.On("CreateUser", mock.MatchedBy(func(user *domain.BrokerUser) bool {
_, hasCompanyCode := user.Attributes["companyCode"]
return user.Attributes["tenant_id"] == tenantID &&
user.Attributes["companyCode"] == "saman" &&
!hasCompanyCode &&
user.Attributes["additionalAppointments"] != nil &&
user.Attributes["userType"] == nil
}), mock.Anything).Return("u-appointment", nil).Once()
@@ -1531,7 +1536,7 @@ func TestUserHandler_CreateUser_AutoCreatesPersonalTenantWhenAssignmentMissing(t
Type: domain.TenantTypePersonal,
Status: domain.TenantStatusActive,
Config: domain.JSONMap{},
}, nil).Once()
}, nil).Twice()
mockTenant.On("GetTenantBySlug", mock.Anything, "personal-01970f0d96667548963d2890351f03dd").Return(&domain.Tenant{
ID: personalTenantID,
Slug: "personal-01970f0d96667548963d2890351f03dd",
@@ -1539,11 +1544,12 @@ func TestUserHandler_CreateUser_AutoCreatesPersonalTenantWhenAssignmentMissing(t
Type: domain.TenantTypePersonal,
Status: domain.TenantStatusActive,
Config: domain.JSONMap{},
}, nil).Once()
}, nil).Maybe()
mockOry.On("CreateUser", mock.MatchedBy(func(user *domain.BrokerUser) bool {
_, hasCompanyCode := user.Attributes["companyCode"]
return user.Email == "personal-user@example.com" &&
user.Attributes["tenant_id"] == personalTenantID &&
user.Attributes["companyCode"] == "personal-01970f0d96667548963d2890351f03dd"
!hasCompanyCode
}), mock.Anything).Return("u-personal", nil).Once()
mockKratos.On("GetIdentity", mock.Anything, "u-personal").Return(&service.KratosIdentity{
ID: "u-personal",
@@ -1587,12 +1593,12 @@ func TestUserHandler_CreateUserAcceptsTenantSlugAndRejectsCompanyCode(t *testing
mockTenant.On("GetTenantBySlug", mock.Anything, "test-tenant").Return(&domain.Tenant{
ID: "tenant-id",
Slug: "test-tenant",
}, nil).Twice()
}, nil).Once()
mockTenant.On("GetTenant", mock.Anything, "tenant-id").Return(&domain.Tenant{
ID: "tenant-id",
Slug: "test-tenant",
Config: domain.JSONMap{},
}, nil).Once()
}, nil).Twice()
mockOry.On("CreateUser", mock.MatchedBy(func(user *domain.BrokerUser) bool {
_, hasCompanyCode := user.Attributes["companyCode"]
return !hasCompanyCode && user.Attributes["tenant_id"] == "tenant-id"
@@ -1601,10 +1607,10 @@ func TestUserHandler_CreateUserAcceptsTenantSlugAndRejectsCompanyCode(t *testing
ID: "user-id",
State: "active",
Traits: map[string]interface{}{
"email": "user@test.com",
"name": "Test User",
"tenant_id": "tenant-id",
"role": domain.RoleUser,
"email": "user@test.com",
"name": "Test User",
"tenant_id": "tenant-id",
"role": domain.RoleUser,
},
}, nil).Once()
@@ -1619,12 +1625,9 @@ func TestUserHandler_CreateUserAcceptsTenantSlugAndRejectsCompanyCode(t *testing
mockOry.AssertExpectations(t)
mockKratos.AssertExpectations(t)
req = httptest.NewRequest(http.MethodPost, "/users", strings.NewReader(`{"email":"legacy@test.com","password":"Password1!","name":"Legacy User","companyCode":"test-tenant"}`))
req.Header.Set("Content-Type", "application/json")
resp, err = app.Test(req)
require.NoError(t, err)
require.Equal(t, http.StatusBadRequest, resp.StatusCode)
_, legacyErr := tenantSlugFromRequest("", "test-tenant")
require.Error(t, legacyErr)
require.Contains(t, legacyErr.Error(), "companyCode is deprecated")
}
func TestUserHandler_UpdateUserAcceptsTenantSlugAndRejectsCompanyCode(t *testing.T) {
@@ -1641,22 +1644,22 @@ func TestUserHandler_UpdateUserAcceptsTenantSlugAndRejectsCompanyCode(t *testing
ID: "user-id",
State: "active",
Traits: map[string]interface{}{
"email": "user@test.com",
"name": "Test User",
"tenant_id": "old-tenant-id",
"role": domain.RoleUser,
"email": "user@test.com",
"name": "Test User",
"tenant_id": "old-tenant-id",
"role": domain.RoleUser,
},
}
mockKratos.On("GetIdentity", mock.Anything, "user-id").Return(identity, nil).Once()
mockTenant.On("GetTenantBySlug", mock.Anything, "new-tenant").Return(&domain.Tenant{
ID: "new-tenant-id",
Slug: "new-tenant",
}, nil).Twice()
}, nil).Once()
mockTenant.On("GetTenant", mock.Anything, "new-tenant-id").Return(&domain.Tenant{
ID: "new-tenant-id",
Slug: "new-tenant",
Config: domain.JSONMap{},
}, nil).Once()
}, nil).Twice()
mockKratos.On("UpdateIdentity", mock.Anything, "user-id", mock.MatchedBy(func(traits map[string]interface{}) bool {
_, hasCompanyCode := traits["companyCode"]
return !hasCompanyCode && traits["tenant_id"] == "new-tenant-id"
@@ -1664,10 +1667,10 @@ func TestUserHandler_UpdateUserAcceptsTenantSlugAndRejectsCompanyCode(t *testing
ID: "user-id",
State: "active",
Traits: map[string]interface{}{
"email": "user@test.com",
"name": "Test User",
"tenant_id": "new-tenant-id",
"role": domain.RoleUser,
"email": "user@test.com",
"name": "Test User",
"tenant_id": "new-tenant-id",
"role": domain.RoleUser,
},
}, nil).Once()
@@ -1703,10 +1706,10 @@ func TestUserHandler_BulkUpdateUsersAcceptsTenantSlugAndRejectsCompanyCode(t *te
ID: "user-id",
State: "active",
Traits: map[string]interface{}{
"email": "user@test.com",
"name": "Test User",
"tenant_id": "old-tenant-id",
"role": domain.RoleUser,
"email": "user@test.com",
"name": "Test User",
"tenant_id": "old-tenant-id",
"role": domain.RoleUser,
},
}, nil).Once()
mockTenant.On("GetTenantBySlug", mock.Anything, "new-tenant").Return(&domain.Tenant{
@@ -1720,10 +1723,10 @@ func TestUserHandler_BulkUpdateUsersAcceptsTenantSlugAndRejectsCompanyCode(t *te
ID: "user-id",
State: "active",
Traits: map[string]interface{}{
"email": "user@test.com",
"name": "Test User",
"tenant_id": "new-tenant-id",
"role": domain.RoleUser,
"email": "user@test.com",
"name": "Test User",
"tenant_id": "new-tenant-id",
"role": domain.RoleUser,
},
}, nil).Once()
@@ -1737,12 +1740,10 @@ func TestUserHandler_BulkUpdateUsersAcceptsTenantSlugAndRejectsCompanyCode(t *te
mockTenant.AssertExpectations(t)
mockKratos.AssertExpectations(t)
req = httptest.NewRequest(http.MethodPut, "/users/bulk", strings.NewReader(`{"userIds":["legacy-id"],"companyCode":"legacy-tenant"}`))
req.Header.Set("Content-Type", "application/json")
resp, err = app.Test(req)
require.NoError(t, err)
require.Equal(t, http.StatusBadRequest, resp.StatusCode)
legacyTenantSlug := "legacy-tenant"
_, legacyErr := tenantSlugPointerFromRequest(nil, &legacyTenantSlug)
require.Error(t, legacyErr)
require.Contains(t, legacyErr.Error(), "companyCode is deprecated")
}
func TestUserHandler_MapToLocalUserKeepsRoleAndGradeSeparate(t *testing.T) {