update
This commit is contained in:
parent
ea5e6cca0e
commit
d12cc71bd4
|
|
@ -173,6 +173,50 @@ def _proxy_addresses(email: str, sam: str, alias_domain: str | None) -> list[str
|
||||||
return out
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
def _target_values(value: Any) -> list[str]:
|
||||||
|
if isinstance(value, (list, tuple, set)):
|
||||||
|
return [str(x).strip() for x in value if x is not None and str(x).strip() != ""]
|
||||||
|
if value is None or str(value).strip() == "":
|
||||||
|
return []
|
||||||
|
return [str(value).strip()]
|
||||||
|
|
||||||
|
|
||||||
|
def _ad_values(attrs: dict[str, Any], attr_name: str) -> list[str]:
|
||||||
|
raw = attrs.get(attr_name)
|
||||||
|
if raw is None:
|
||||||
|
lower_attr = attr_name.lower()
|
||||||
|
for key, value in attrs.items():
|
||||||
|
if str(key).lower() == lower_attr:
|
||||||
|
raw = value
|
||||||
|
break
|
||||||
|
if isinstance(raw, (list, tuple, set)):
|
||||||
|
return [str(x).strip() for x in raw if x is not None and str(x).strip() != ""]
|
||||||
|
if raw is None or str(raw).strip() == "":
|
||||||
|
return []
|
||||||
|
return [str(raw).strip()]
|
||||||
|
|
||||||
|
|
||||||
|
def _canonical_values(attr_name: str, values: list[str]) -> list[str]:
|
||||||
|
if attr_name in {"proxyAddresses"}:
|
||||||
|
return sorted(values)
|
||||||
|
if attr_name in {"manager", "mail", "sAMAccountName"}:
|
||||||
|
return sorted([v.lower() for v in values])
|
||||||
|
return sorted(values)
|
||||||
|
|
||||||
|
|
||||||
|
def _diff_ad_attributes(ad_attrs: dict[str, Any], target_attrs: dict[str, Any]) -> dict[str, Any]:
|
||||||
|
diff: dict[str, Any] = {}
|
||||||
|
for attr_name, target_value in target_attrs.items():
|
||||||
|
wanted = _target_values(target_value)
|
||||||
|
if not wanted:
|
||||||
|
continue
|
||||||
|
current = _ad_values(ad_attrs, attr_name)
|
||||||
|
if _canonical_values(attr_name, current) == _canonical_values(attr_name, wanted):
|
||||||
|
continue
|
||||||
|
diff[attr_name] = target_value
|
||||||
|
return diff
|
||||||
|
|
||||||
|
|
||||||
def _location_from_workplace(workplace: str, mappings: dict[str, Any] | None = None) -> dict[str, Any]:
|
def _location_from_workplace(workplace: str, mappings: dict[str, Any] | None = None) -> dict[str, Any]:
|
||||||
text = str(workplace or "").strip()
|
text = str(workplace or "").strip()
|
||||||
defaults: dict[str, dict[str, Any]] = {
|
defaults: dict[str, dict[str, Any]] = {
|
||||||
|
|
@ -409,10 +453,36 @@ class SyncEhrToAdUserJob(BaseJob):
|
||||||
|
|
||||||
processed = 0
|
processed = 0
|
||||||
updated = 0
|
updated = 0
|
||||||
|
skipped_unchanged = 0
|
||||||
skipped_missing_sam = 0
|
skipped_missing_sam = 0
|
||||||
skipped_not_found_ad = 0
|
skipped_not_found_ad = 0
|
||||||
failed = 0
|
failed = 0
|
||||||
manager_dn_cache: dict[str, str] = {}
|
manager_dn_cache: dict[str, str] = {}
|
||||||
|
ad_compare_attributes = [
|
||||||
|
"sAMAccountName",
|
||||||
|
"givenName",
|
||||||
|
"sn",
|
||||||
|
"title",
|
||||||
|
"department",
|
||||||
|
"manager",
|
||||||
|
"proxyAddresses",
|
||||||
|
"co",
|
||||||
|
"c",
|
||||||
|
"countryCode",
|
||||||
|
"company",
|
||||||
|
"displayName",
|
||||||
|
"mail",
|
||||||
|
"employeeID",
|
||||||
|
"employeeType",
|
||||||
|
"mobile",
|
||||||
|
"physicalDeliveryOfficeName",
|
||||||
|
"postalCode",
|
||||||
|
"st",
|
||||||
|
"l",
|
||||||
|
"streetAddress",
|
||||||
|
]
|
||||||
|
if department_code_attr:
|
||||||
|
ad_compare_attributes.append(department_code_attr)
|
||||||
|
|
||||||
for sam_key, item in users_by_sam.items():
|
for sam_key, item in users_by_sam.items():
|
||||||
emp = item.get("employeeInfo") or {}
|
emp = item.get("employeeInfo") or {}
|
||||||
|
|
@ -429,7 +499,7 @@ class SyncEhrToAdUserJob(BaseJob):
|
||||||
processed += 1
|
processed += 1
|
||||||
|
|
||||||
try:
|
try:
|
||||||
ad_user = ad.find_user(sam)
|
ad_user = ad.find_user(sam, attributes=ad_compare_attributes)
|
||||||
if not ad_user:
|
if not ad_user:
|
||||||
skipped_not_found_ad += 1
|
skipped_not_found_ad += 1
|
||||||
logger.warning("AD 用户不存在,跳过:sAMAccountName=%s", sam)
|
logger.warning("AD 用户不存在,跳过:sAMAccountName=%s", sam)
|
||||||
|
|
@ -493,15 +563,22 @@ class SyncEhrToAdUserJob(BaseJob):
|
||||||
if department_code_attr and department_code:
|
if department_code_attr and department_code:
|
||||||
attributes[department_code_attr] = department_code
|
attributes[department_code_attr] = department_code
|
||||||
|
|
||||||
changed = ad.modify_user(str(ad_user["dn"]), attributes, dry_run=dry_run)
|
diff_attributes = _diff_ad_attributes(ad_user.get("attributes") or {}, attributes)
|
||||||
|
if not diff_attributes:
|
||||||
|
skipped_unchanged += 1
|
||||||
|
if verbose_trace:
|
||||||
|
logger.info("AD 用户信息一致,跳过更新:sam=%s dn=%s", sam, ad_user["dn"])
|
||||||
|
continue
|
||||||
|
|
||||||
|
changed = ad.modify_user(str(ad_user["dn"]), diff_attributes, dry_run=dry_run)
|
||||||
if changed:
|
if changed:
|
||||||
updated += 1
|
updated += 1
|
||||||
if verbose_trace:
|
if verbose_trace:
|
||||||
logger.info(
|
logger.info(
|
||||||
"AD 用户同步完成:sam=%s dn=%s attrs=%s",
|
"AD 用户同步完成:sam=%s dn=%s changed_attrs=%s",
|
||||||
sam,
|
sam,
|
||||||
ad_user["dn"],
|
ad_user["dn"],
|
||||||
json.dumps({k: v for k, v in attributes.items() if v}, ensure_ascii=False, default=str),
|
json.dumps({k: v for k, v in diff_attributes.items() if v}, ensure_ascii=False, default=str),
|
||||||
)
|
)
|
||||||
except Exception as e: # noqa: BLE001
|
except Exception as e: # noqa: BLE001
|
||||||
failed += 1
|
failed += 1
|
||||||
|
|
@ -514,6 +591,7 @@ class SyncEhrToAdUserJob(BaseJob):
|
||||||
"ehr_current_users_with_ad_account": len(users_by_sam),
|
"ehr_current_users_with_ad_account": len(users_by_sam),
|
||||||
"processed": processed,
|
"processed": processed,
|
||||||
"updated": updated,
|
"updated": updated,
|
||||||
|
"skipped_unchanged": skipped_unchanged,
|
||||||
"skipped_missing_sam": skipped_missing_sam,
|
"skipped_missing_sam": skipped_missing_sam,
|
||||||
"skipped_not_found_ad": skipped_not_found_ad,
|
"skipped_not_found_ad": skipped_not_found_ad,
|
||||||
"failed": failed,
|
"failed": failed,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue