forked from baron/baron-sso
merge: integrate origin dev into dev
Includes Worksmobile SSOT sync comparison updates, UUID import conflict resolution, and Playwright route mock stabilization.
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
||||
"baron-sso-backend/internal/repository"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/mail"
|
||||
"os"
|
||||
"sort"
|
||||
@@ -1266,7 +1267,7 @@ func compareWorksmobileUsers(localUsers []domain.User, remoteUsers []Worksmobile
|
||||
if !matched {
|
||||
remote, matched = remoteByEmail[strings.ToLower(strings.TrimSpace(user.Email))]
|
||||
}
|
||||
needsUpdate := matched && worksmobileUserNeedsUpdate(user, remote)
|
||||
needsUpdate := matched && worksmobileUserNeedsUpdate(user, remote, localTenants)
|
||||
if matched && !includeMatched && !needsUpdate {
|
||||
matchedRemoteIDs[remote.ID] = true
|
||||
continue
|
||||
@@ -1364,7 +1365,7 @@ func compareWorksmobileUsers(localUsers []domain.User, remoteUsers []Worksmobile
|
||||
return result
|
||||
}
|
||||
|
||||
func worksmobileUserNeedsUpdate(user domain.User, remote WorksmobileRemoteUser) bool {
|
||||
func worksmobileUserNeedsUpdate(user domain.User, remote WorksmobileRemoteUser, localTenants map[string]domain.Tenant) bool {
|
||||
if strings.TrimSpace(remote.ExternalID) != strings.TrimSpace(user.ID) {
|
||||
return true
|
||||
}
|
||||
@@ -1374,12 +1375,179 @@ func worksmobileUserNeedsUpdate(user domain.User, remote WorksmobileRemoteUser)
|
||||
if strings.ToLower(strings.TrimSpace(remote.Email)) != strings.ToLower(strings.TrimSpace(user.Email)) {
|
||||
return true
|
||||
}
|
||||
if worksmobileUserPhoneNeedsUpdate(user, remote) {
|
||||
return true
|
||||
}
|
||||
if worksmobileUserEmployeeNumberNeedsUpdate(user, remote) {
|
||||
return true
|
||||
}
|
||||
if worksmobileUserOrganizationsNeedUpdate(user, remote, localTenants) {
|
||||
return true
|
||||
}
|
||||
if worksmobileUserManagerNeedsUpdate(user, remote) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func worksmobileUserPhoneNeedsUpdate(user domain.User, remote WorksmobileRemoteUser) bool {
|
||||
localPhone := normalizeWorksmobilePhoneForCompare(user.Phone)
|
||||
remotePhone := normalizeWorksmobilePhoneForCompare(remote.CellPhone)
|
||||
if localPhone == "" && remotePhone == "" {
|
||||
return false
|
||||
}
|
||||
return localPhone != remotePhone
|
||||
}
|
||||
|
||||
func normalizeWorksmobilePhoneForCompare(value string) string {
|
||||
normalized := strings.TrimSpace(value)
|
||||
normalized = strings.NewReplacer("-", "", " ", "", "(", "", ")", "").Replace(normalized)
|
||||
if normalized == "" {
|
||||
return ""
|
||||
}
|
||||
if strings.HasPrefix(normalized, "010") {
|
||||
return "+82" + normalized[1:]
|
||||
}
|
||||
if strings.HasPrefix(normalized, "82") {
|
||||
return "+" + normalized
|
||||
}
|
||||
return normalized
|
||||
}
|
||||
|
||||
func worksmobileUserEmployeeNumberNeedsUpdate(user domain.User, remote WorksmobileRemoteUser) bool {
|
||||
localEmployeeNumber := strings.TrimSpace(metadataEmployeeNumber(user.Metadata))
|
||||
remoteEmployeeNumber := strings.TrimSpace(remote.EmployeeNumber)
|
||||
if localEmployeeNumber == "" && remoteEmployeeNumber == "" {
|
||||
return false
|
||||
}
|
||||
return localEmployeeNumber != remoteEmployeeNumber
|
||||
}
|
||||
|
||||
func worksmobileUserOrganizationsNeedUpdate(user domain.User, remote WorksmobileRemoteUser, localTenants map[string]domain.Tenant) bool {
|
||||
if len(remote.Organizations) == 0 || user.TenantID == nil || localTenants == nil {
|
||||
return false
|
||||
}
|
||||
tenantID := strings.TrimSpace(*user.TenantID)
|
||||
if tenantID == "" {
|
||||
return false
|
||||
}
|
||||
tenant, ok := localTenants[tenantID]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
expected, err := BuildWorksmobileUserPayloadForDomainTenants(user, tenant, localTenants, worksmobileComparisonRootConfig(localTenants))
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return !worksmobileUserOrganizationsEqual(expected.Organizations, remote.Organizations)
|
||||
}
|
||||
|
||||
func worksmobileComparisonRootConfig(localTenants map[string]domain.Tenant) domain.JSONMap {
|
||||
for _, tenant := range localTenants {
|
||||
if strings.TrimSpace(tenant.Slug) == HanmacFamilyTenantSlug {
|
||||
return tenant.Config
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type worksmobileComparableOrgUnit struct {
|
||||
organizationPrimary bool
|
||||
organizationEmail string
|
||||
unitPrimary bool
|
||||
positionID string
|
||||
comparePosition bool
|
||||
manager *bool
|
||||
compareManager bool
|
||||
}
|
||||
|
||||
func worksmobileUserOrganizationsEqual(expected []WorksmobileUserOrganization, remote []WorksmobileUserOrganization) bool {
|
||||
expectedUnits := flattenExpectedWorksmobileUserOrganizations(expected)
|
||||
remoteUnits := flattenRemoteWorksmobileUserOrganizations(remote)
|
||||
if len(expectedUnits) != len(remoteUnits) {
|
||||
return false
|
||||
}
|
||||
for key, expectedUnit := range expectedUnits {
|
||||
remoteUnit, ok := remoteUnits[key]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if expectedUnit.organizationPrimary != remoteUnit.organizationPrimary {
|
||||
return false
|
||||
}
|
||||
if strings.ToLower(expectedUnit.organizationEmail) != strings.ToLower(remoteUnit.organizationEmail) {
|
||||
return false
|
||||
}
|
||||
if expectedUnit.unitPrimary != remoteUnit.unitPrimary {
|
||||
return false
|
||||
}
|
||||
if expectedUnit.comparePosition && strings.TrimSpace(expectedUnit.positionID) != strings.TrimSpace(remoteUnit.positionID) {
|
||||
return false
|
||||
}
|
||||
if expectedUnit.compareManager && !worksmobileBoolPointersEqual(expectedUnit.manager, remoteUnit.manager) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func flattenExpectedWorksmobileUserOrganizations(organizations []WorksmobileUserOrganization) map[string]worksmobileComparableOrgUnit {
|
||||
result := map[string]worksmobileComparableOrgUnit{}
|
||||
for _, organization := range organizations {
|
||||
for _, orgUnit := range organization.OrgUnits {
|
||||
key := worksmobileComparableOrgUnitKey(organization.DomainID, orgUnit.OrgUnitID)
|
||||
if key == "" {
|
||||
continue
|
||||
}
|
||||
result[key] = worksmobileComparableOrgUnit{
|
||||
organizationPrimary: organization.Primary,
|
||||
organizationEmail: strings.TrimSpace(organization.Email),
|
||||
unitPrimary: orgUnit.Primary,
|
||||
positionID: strings.TrimSpace(orgUnit.PositionID),
|
||||
comparePosition: strings.TrimSpace(orgUnit.PositionID) != "",
|
||||
manager: orgUnit.IsManager,
|
||||
compareManager: orgUnit.IsManager != nil,
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func flattenRemoteWorksmobileUserOrganizations(organizations []WorksmobileUserOrganization) map[string]worksmobileComparableOrgUnit {
|
||||
result := map[string]worksmobileComparableOrgUnit{}
|
||||
for _, organization := range organizations {
|
||||
for _, orgUnit := range organization.OrgUnits {
|
||||
key := worksmobileComparableOrgUnitKey(organization.DomainID, orgUnit.OrgUnitID)
|
||||
if key == "" {
|
||||
continue
|
||||
}
|
||||
result[key] = worksmobileComparableOrgUnit{
|
||||
organizationPrimary: organization.Primary,
|
||||
organizationEmail: strings.TrimSpace(organization.Email),
|
||||
unitPrimary: orgUnit.Primary,
|
||||
positionID: strings.TrimSpace(orgUnit.PositionID),
|
||||
manager: orgUnit.IsManager,
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func worksmobileComparableOrgUnitKey(domainID int64, orgUnitID string) string {
|
||||
orgUnitID = strings.TrimSpace(orgUnitID)
|
||||
if domainID == 0 || orgUnitID == "" {
|
||||
return ""
|
||||
}
|
||||
return fmt.Sprintf("%d:%s", domainID, orgUnitID)
|
||||
}
|
||||
|
||||
func worksmobileBoolPointersEqual(left, right *bool) bool {
|
||||
if left == nil || right == nil {
|
||||
return left == nil && right == nil
|
||||
}
|
||||
return *left == *right
|
||||
}
|
||||
|
||||
func worksmobileUserManagerNeedsUpdate(user domain.User, remote WorksmobileRemoteUser) bool {
|
||||
localManagers := worksmobileUserExplicitOrgUnitManagers(user)
|
||||
if len(localManagers) == 0 {
|
||||
|
||||
Reference in New Issue
Block a user