1
0
forked from baron/baron-sso

feat: update worksmobile sync and restore planning

This commit is contained in:
2026-06-01 17:01:53 +09:00
parent 6574fb54b9
commit 5c8a338085
36 changed files with 3922 additions and 243 deletions

View File

@@ -2,6 +2,7 @@ package service
import (
"baron-sso-backend/internal/domain"
"encoding/json"
"strings"
"testing"
@@ -134,6 +135,36 @@ func TestBuildWorksmobileUserPayloadMapsBaronUserAndPrimaryTenant(t *testing.T)
require.Equal(t, "externalKey:"+tenantID, payload.Organizations[0].OrgUnits[0].OrgUnitID)
}
func TestBuildWorksmobileUserPayloadNormalizesLegacyCharacterMapEmployeeID(t *testing.T) {
t.Setenv("SAMAN_DOMAIN_ID", "1001")
tenantID := "33333333-3333-3333-3333-333333333333"
user := domain.User{
ID: "44444444-4444-4444-4444-444444444444",
Email: "john1@samaneng.com",
Name: "John Doe",
TenantID: &tenantID,
Metadata: domain.JSONMap{
"employee_id": map[string]any{
"0": "j",
"1": "o",
"2": "h",
"3": "n",
},
},
}
tenant := domain.Tenant{
ID: tenantID,
Slug: "saman",
Name: "Saman",
Domains: []domain.TenantDomain{{Domain: "samaneng.com"}},
}
payload, err := BuildWorksmobileUserPayload(user, tenant, nil)
require.NoError(t, err)
require.Equal(t, "john", payload.EmployeeNumber)
}
func TestBuildWorksmobileUserPayloadMapsAdditionalAppointmentsToOrgUnits(t *testing.T) {
t.Setenv("SAMAN_DOMAIN_ID", "1001")
t.Setenv("HANMAC_DOMAIN_ID", "1002")
@@ -198,7 +229,7 @@ func TestBuildWorksmobileUserPayloadMapsAdditionalAppointmentsToOrgUnits(t *test
require.Equal(t, int64(1002), payload.Organizations[1].DomainID)
require.False(t, payload.Organizations[1].Primary)
require.Equal(t, "externalKey:"+secondaryTenantID, payload.Organizations[1].OrgUnits[0].OrgUnitID)
require.False(t, payload.Organizations[1].OrgUnits[0].Primary)
require.True(t, payload.Organizations[1].OrgUnits[0].Primary)
require.NotNil(t, payload.Organizations[1].OrgUnits[0].IsManager)
require.True(t, *payload.Organizations[1].OrgUnits[0].IsManager)
}
@@ -259,7 +290,7 @@ func TestBuildWorksmobileUserPayloadKeepsFirstAffiliationPrimaryWhenBaronReprese
)
require.NoError(t, err)
require.Equal(t, int64(1003), payload.DomainID)
require.Equal(t, int64(1001), payload.DomainID)
require.Equal(t, "First affiliation task", payload.Task)
require.Len(t, payload.Organizations, 2)
require.Equal(t, int64(1001), payload.Organizations[0].DomainID)
@@ -269,7 +300,99 @@ func TestBuildWorksmobileUserPayloadKeepsFirstAffiliationPrimaryWhenBaronReprese
require.Equal(t, int64(1003), payload.Organizations[1].DomainID)
require.False(t, payload.Organizations[1].Primary)
require.Equal(t, "externalKey:"+secondTenantID, payload.Organizations[1].OrgUnits[0].OrgUnitID)
require.False(t, payload.Organizations[1].OrgUnits[0].Primary)
require.True(t, payload.Organizations[1].OrgUnits[0].Primary)
}
func TestBuildWorksmobileUserPayloadUsesEmailDomainForAccountDomainWhenPrimaryOrgIsGPDTDC(t *testing.T) {
t.Setenv("SAMAN_DOMAIN_ID", "1001")
t.Setenv("GPDTDC_DOMAIN_ID", "1003")
samanID := "11111111-1111-1111-1111-111111111111"
gpdtdcID := "5530ca6e-c5e6-4bf0-84d6-76c6a8fb70ee"
leafTenantID := "52f06c97-9d6f-4819-971b-43303062e193"
user := domain.User{
ID: "44444444-4444-4444-4444-444444444444",
Email: "dhlee@samaneng.com",
Name: "GPDTDC Saman User",
TenantID: &leafTenantID,
Metadata: domain.JSONMap{
"additionalAppointments": []any{
map[string]any{
"tenantId": leafTenantID,
"isPrimary": true,
},
},
},
}
samanTenant := domain.Tenant{
ID: samanID,
Slug: "saman",
Name: "삼안",
Domains: []domain.TenantDomain{{Domain: "samaneng.com"}},
}
gpdtdcTenant := domain.Tenant{
ID: gpdtdcID,
Slug: "gpdtdc",
Name: "총괄기획&기술개발센터",
}
leafTenant := domain.Tenant{
ID: leafTenantID,
Slug: "infra-bim2",
Name: "인프라 BIM2",
ParentID: &gpdtdcID,
}
payload, err := BuildWorksmobileUserPayloadForDomainTenants(
user,
leafTenant,
map[string]domain.Tenant{
samanID: samanTenant,
gpdtdcID: gpdtdcTenant,
leafTenantID: leafTenant,
},
nil,
)
require.NoError(t, err)
require.Equal(t, int64(1001), payload.DomainID)
require.Len(t, payload.Organizations, 2)
require.Equal(t, int64(1001), payload.Organizations[0].DomainID)
require.True(t, payload.Organizations[0].Primary)
require.Equal(t, "dhlee@samaneng.com", payload.Organizations[0].Email)
require.Equal(t, "externalKey:"+samanID, payload.Organizations[0].OrgUnits[0].OrgUnitID)
require.True(t, payload.Organizations[0].OrgUnits[0].Primary)
require.Equal(t, int64(1003), payload.Organizations[1].DomainID)
require.False(t, payload.Organizations[1].Primary)
require.Equal(t, "dhlee@baroncs.co.kr", payload.Organizations[1].Email)
require.Equal(t, "externalKey:"+leafTenantID, payload.Organizations[1].OrgUnits[0].OrgUnitID)
require.True(t, payload.Organizations[1].OrgUnits[0].Primary)
}
func TestWorksmobileUserPayloadJSONIncludesFalsePrimaryFields(t *testing.T) {
payload := WorksmobileUserPayload{
Email: "user@samaneng.com",
Organizations: []WorksmobileUserOrganization{
{
DomainID: 1001,
Primary: true,
OrgUnits: []WorksmobileUserOrgUnit{
{OrgUnitID: "externalKey:primary", Primary: true},
},
},
{
DomainID: 1003,
Primary: false,
OrgUnits: []WorksmobileUserOrgUnit{
{OrgUnitID: "externalKey:secondary", Primary: false},
},
},
},
}
data, err := json.Marshal(payload)
require.NoError(t, err)
require.Contains(t, string(data), `"primary":false`)
require.Contains(t, string(data), `"orgUnitId":"externalKey:secondary","primary":false`)
}
func TestResolveWorksmobileDomainIDFromTenantIgnoresRootDomainMappings(t *testing.T) {
@@ -441,19 +564,51 @@ func TestBuildWorksmobileUserPayloadAddsSubEmailMetadataAlias(t *testing.T) {
require.Equal(t, []string{"alias1@hanmaceng.co.kr", "alias2@hanmaceng.co.kr"}, payload.AliasEmails)
}
func TestValidateWorksmobileAliasLocalPartsRejectsPrimaryAndAliasCollisions(t *testing.T) {
err := ValidateWorksmobileAliasLocalParts(
func TestBuildWorksmobileUserPayloadKeepsSubEmailAliasWithPrimaryLocalPart(t *testing.T) {
t.Setenv("SAMAN_DOMAIN_ID", "1001")
tenantID := "33333333-3333-3333-3333-333333333333"
user := domain.User{
ID: "44444444-4444-4444-4444-444444444444",
Email: "ypshim@samaneng.com",
Name: "Saman User",
TenantID: &tenantID,
Metadata: domain.JSONMap{
"sub_email": "ypshim@hanmaceng.co.kr",
},
}
tenant := domain.Tenant{
ID: tenantID,
Slug: "saman",
Name: "삼안",
Domains: []domain.TenantDomain{{Domain: "samaneng.com"}},
}
payload, err := BuildWorksmobileUserPayload(user, tenant, nil)
require.NoError(t, err)
require.Equal(t, []string{"ypshim@hanmaceng.co.kr"}, payload.AliasEmails)
}
func TestValidateWorksmobileAliasEmailsAllowsSameLocalPartOnDifferentDomains(t *testing.T) {
err := ValidateWorksmobileAliasEmails(
"main@samaneng.com",
[]string{"main@hanmaceng.co.kr"},
map[string]string{},
)
require.Error(t, err)
require.Contains(t, err.Error(), "local-part")
require.NoError(t, err)
err = ValidateWorksmobileAliasLocalParts(
err = ValidateWorksmobileAliasEmails(
"main@samaneng.com",
[]string{"main@samaneng.com"},
map[string]string{},
)
require.Error(t, err)
require.Contains(t, err.Error(), "duplicates")
err = ValidateWorksmobileAliasEmails(
"main@samaneng.com",
[]string{"alias@hanmaceng.co.kr"},
map[string]string{"alias": "existing-user"},
map[string]string{"alias@hanmaceng.co.kr": "existing-user"},
)
require.Error(t, err)
require.Contains(t, err.Error(), "이미 사용 중")