sycommon-python-lib 0.2.6a0__py3-none-any.whl → 0.2.6a1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -73,7 +73,8 @@ class LDAPFullUser(BaseModel):
73
73
  class WeComLDAPUser(BaseModel):
74
74
  """企微-LDAP 关联用户(最终返回结果)"""
75
75
 
76
- wecom_userid: str # 企微 userid
76
+ wecom_userid: str # 企微 userid(明文工号,如 "0633")
77
+ employee_id: Optional[str] = None # 员工工号(与 wecom_userid 同值,语义更明确)
77
78
  wecom_name: str # 企微中文名
78
79
  wecom_english_name: Optional[str] = None # 企微英文名
79
80
  wecom_departments: List[str] = [] # 企微部门列表
@@ -603,8 +604,9 @@ class WeComLDAPService(metaclass=SingletonMeta):
603
604
 
604
605
  # 3. 合并返回
605
606
  result = await self._build_wecom_ldap_user(user_data, ldap_index)
606
- # 保留原始传入的 wecom_userid
607
- result.wecom_userid = wecom_userid
607
+ # 保留解码后的明文 userid(工号),而非原始密文
608
+ result.wecom_userid = decoded_userid
609
+ result.employee_id = decoded_userid
608
610
  return result
609
611
 
610
612
  async def get_all_users(self) -> List[WeComLDAPUser]:
@@ -623,6 +625,7 @@ class WeComLDAPService(metaclass=SingletonMeta):
623
625
  results = []
624
626
  for u in wecom_users:
625
627
  result = await self._build_wecom_ldap_user(u, ldap_index)
628
+ result.employee_id = result.wecom_userid
626
629
  results.append(result)
627
630
 
628
631
  matched = sum(1 for r in results if r.matched)
@@ -671,3 +674,137 @@ class WeComLDAPService(metaclass=SingletonMeta):
671
674
  if user.matched and user.ldap_user:
672
675
  return user.ldap_user.username
673
676
  return None
677
+
678
+ # ─── Redis 映射缓存 ───
679
+
680
+ # Redis key 前缀(保持与旧版 digital_work 命名兼容)
681
+ _UID_MAP_PREFIX = "digital_work:wecom_uid_map:"
682
+ _LDAP_TO_WECOM_PREFIX = "digital_work:ldap_to_wecom:"
683
+ _EMPLOYEE_ID_PREFIX = "digital_work:wecom_employee_id:"
684
+ _MAP_TTL = 7 * 24 * 3600 # 7 天
685
+
686
+ @staticmethod
687
+ def _get_redis():
688
+ """获取 RedisService(懒加载)"""
689
+ from sycommon.database.redis_service import RedisService
690
+ return RedisService
691
+
692
+ async def _get_cached_mapping(self, wecom_userid: str) -> Optional[str]:
693
+ """从 Redis 读取 wecom_userid -> unified_id 映射"""
694
+ try:
695
+ rs = self._get_redis()
696
+ val = await rs.get(f"{self._UID_MAP_PREFIX}{wecom_userid}")
697
+ if val:
698
+ return val
699
+ except Exception:
700
+ pass
701
+ return None
702
+
703
+ async def _set_cached_mapping(self, wecom_userid: str, unified_id: str):
704
+ """将 wecom_userid <-> unified_id 双向映射写入 Redis,同时保存工号"""
705
+ try:
706
+ rs = self._get_redis()
707
+ # 正向: wecom_userid -> unified_id (LDAP sAMAccountName)
708
+ await rs.set(
709
+ f"{self._UID_MAP_PREFIX}{wecom_userid}",
710
+ unified_id,
711
+ ex=self._MAP_TTL,
712
+ )
713
+ # 反向: unified_id -> wecom_userid(用于定时任务等主动推送场景)
714
+ await rs.set(
715
+ f"{self._LDAP_TO_WECOM_PREFIX}{unified_id}",
716
+ wecom_userid,
717
+ ex=self._MAP_TTL,
718
+ )
719
+ # 员工工号: unified_id -> wecom_userid(即工号,如 "0633")
720
+ await rs.set(
721
+ f"{self._EMPLOYEE_ID_PREFIX}{unified_id}",
722
+ wecom_userid,
723
+ ex=self._MAP_TTL,
724
+ )
725
+ except Exception as e:
726
+ SYLogger.warning(f"[WeComLDAP] 缓存映射到 Redis 失败: {e}")
727
+
728
+ async def resolve_unified_user_id(self, wecom_userid: str) -> str:
729
+ """将企微 userid 解析为统一 user_id(LDAP sAMAccountName)
730
+
731
+ 优先从 Redis 缓存读取,缓存未命中时查 LDAP 并写入 Redis。
732
+ 匹配到 LDAP 返回 sAMAccountName,否则直接使用企微 userid。
733
+
734
+ Args:
735
+ wecom_userid: 企微用户ID(如 "0633"、密文 open_userid)
736
+
737
+ Returns:
738
+ 统一 user_id(小写,如 "osulcode.xiao")
739
+ """
740
+ # 1. 查 Redis 缓存
741
+ cached = await self._get_cached_mapping(wecom_userid)
742
+ if cached:
743
+ return cached
744
+
745
+ # 2. 查企微 + LDAP
746
+ unified_id = wecom_userid
747
+ employee_id = wecom_userid # 默认用工号就是原始 userid
748
+ try:
749
+ result = await self.get_user_info(wecom_userid)
750
+ employee_id = result.wecom_userid # get_user_info 返回解码后的明文工号
751
+ if result.matched and result.ldap_user and result.ldap_user.username:
752
+ unified_id = result.ldap_user.username
753
+ SYLogger.info(
754
+ f"[WeComLDAP] 用户映射: wecom={wecom_userid} -> ldap={unified_id}")
755
+ else:
756
+ SYLogger.info(
757
+ f"[WeComLDAP] 用户映射: wecom={wecom_userid} -> 未匹配LDAP,回退={unified_id}")
758
+ except Exception as e:
759
+ SYLogger.warning(
760
+ f"[WeComLDAP] 解析统一 user_id 失败: wecom_userid={wecom_userid}, error={e}")
761
+
762
+ # 3. 写入 Redis 缓存(统一小写)
763
+ unified_id = unified_id.lower().replace(" ", "")
764
+ await self._set_cached_mapping(employee_id, unified_id)
765
+
766
+ return unified_id
767
+
768
+ async def get_employee_id(self, unified_id: str) -> Optional[str]:
769
+ """从 Redis 获取企微员工工号
770
+
771
+ Args:
772
+ unified_id: 统一用户 ID(LDAP sAMAccountName,如 "osulcode.xiao")
773
+
774
+ Returns:
775
+ 员工工号(如 "0633"),未找到返回 None
776
+ """
777
+ try:
778
+ rs = self._get_redis()
779
+ uid = unified_id.lower().replace(" ", "")
780
+ val = await rs.get(f"{self._EMPLOYEE_ID_PREFIX}{uid}")
781
+ if val:
782
+ return val
783
+ except Exception:
784
+ pass
785
+ return None
786
+
787
+ async def batch_set_uid_mapping(self, mapping: dict[str, str]):
788
+ """批量写入企微-LDAP 映射到 Redis(pipeline 优化,含反向映射和工号)
789
+
790
+ Args:
791
+ mapping: {wecom_userid: unified_id, ...}
792
+ """
793
+ if not mapping:
794
+ return
795
+ try:
796
+ rs = self._get_redis()
797
+ client = rs.get_client()
798
+ async with client.pipeline(transaction=True) as pipe:
799
+ for wecom_userid, unified_id in mapping.items():
800
+ uid = unified_id.lower().replace(" ", "")
801
+ # 正向
802
+ pipe.set(f"{self._UID_MAP_PREFIX}{wecom_userid}", uid, ex=self._MAP_TTL)
803
+ # 反向
804
+ pipe.set(f"{self._LDAP_TO_WECOM_PREFIX}{uid}", wecom_userid, ex=self._MAP_TTL)
805
+ # 员工工号
806
+ pipe.set(f"{self._EMPLOYEE_ID_PREFIX}{uid}", wecom_userid, ex=self._MAP_TTL)
807
+ await pipe.execute()
808
+ logging.info(f"[WeComLDAP] 批量写入 {len(mapping)} 条映射到 Redis")
809
+ except Exception as e:
810
+ SYLogger.warning(f"[WeComLDAP] 批量缓存映射到 Redis 失败: {e}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sycommon-python-lib
3
- Version: 0.2.6a0
3
+ Version: 0.2.6a1
4
4
  Summary: Add your description here
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -147,7 +147,7 @@ sycommon/auth/ldap_service.py,sha256=fOcpVov5LWJkBk62qbTaltks1c4la7JsbD104KfdBOI
147
147
  sycommon/auth/oa_cache.py,sha256=u673y-mK-xo24pSqvfjL68_YFASO2zoxd_iAQ0HetCo,3491
148
148
  sycommon/auth/oa_crypto.py,sha256=xpY1R1Bj3KLENXB0TuThB6Eku1E9PYjcoSpOdgDmCgc,1898
149
149
  sycommon/auth/oa_service.py,sha256=kLepV9zgqpZoaB73DRPpMA5tJJQjoaDtQPdzBcGXeak,6235
150
- sycommon/auth/wecom_ldap_service.py,sha256=VTGw8UQFBCH-lhJZ3N5TRcLy7Qk3Q4uENisXYFhkESk,24817
150
+ sycommon/auth/wecom_ldap_service.py,sha256=lo_t3sSQAYSGVofg1xe3YQik7VsI2ItFNZLxLVqlJmw,30530
151
151
  sycommon/config/Config.py,sha256=J5VjolqHmhYTBZwTyfSHv9X5cHMfN6kqY2ryHF4LJPw,6785
152
152
  sycommon/config/DatabaseConfig.py,sha256=ILiUuYT9_xJZE2W-RYuC3JCt_YLKc1sbH13-MHIOPhg,804
153
153
  sycommon/config/ElasticsearchConfig.py,sha256=fO9ZPMgJxSg1-UyDJ90wO6UvYy-jscwPJsSkXgx9qTU,2308
@@ -282,8 +282,8 @@ sycommon/tools/syemail.py,sha256=BDFhgf7WDOQeTcjxJEQdu0dQhnHFPO_p3eI0-Ni3LhQ,561
282
282
  sycommon/tools/timing.py,sha256=OiiE7P07lRoMzX9kzb8sZU9cDb0zNnqIlY5pWqHcnkY,2064
283
283
  sycommon/xxljob/__init__.py,sha256=7eoBlQxv-B39IfRSCY2bkqdGYs1QRe1umAWd88VMEEM,86
284
284
  sycommon/xxljob/xxljob_service.py,sha256=JIEJaGXhqrTLcyxlyynSrsHg9bBnDNzX-D4qIWLRPUE,6815
285
- sycommon_python_lib-0.2.6a0.dist-info/METADATA,sha256=SZCYl4eAehrnZBS5MnF5Rr-VMP3XbDcKv5XbHQ8GPhI,7913
286
- sycommon_python_lib-0.2.6a0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
287
- sycommon_python_lib-0.2.6a0.dist-info/entry_points.txt,sha256=gsR4SssKxDWjRU8ggidzNcdMXDPRSKRS7UaGyNP84Qg,92
288
- sycommon_python_lib-0.2.6a0.dist-info/top_level.txt,sha256=RgphKrg7nJyZ7irJqbxFr-5H2LUYTvI7ivoWZH2hcD0,29
289
- sycommon_python_lib-0.2.6a0.dist-info/RECORD,,
285
+ sycommon_python_lib-0.2.6a1.dist-info/METADATA,sha256=kubGNvAaxxgtJBUXszJQbZLD5CZwm29ACii7lzTJWMM,7913
286
+ sycommon_python_lib-0.2.6a1.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
287
+ sycommon_python_lib-0.2.6a1.dist-info/entry_points.txt,sha256=gsR4SssKxDWjRU8ggidzNcdMXDPRSKRS7UaGyNP84Qg,92
288
+ sycommon_python_lib-0.2.6a1.dist-info/top_level.txt,sha256=RgphKrg7nJyZ7irJqbxFr-5H2LUYTvI7ivoWZH2hcD0,29
289
+ sycommon_python_lib-0.2.6a1.dist-info/RECORD,,