pixelarraylib 1.2.2__tar.gz → 1.2.4__tar.gz

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.
Files changed (51) hide show
  1. {pixelarraylib-1.2.2/pixelarraylib.egg-info → pixelarraylib-1.2.4}/PKG-INFO +1 -1
  2. {pixelarraylib-1.2.2 → pixelarraylib-1.2.4}/pixelarraylib/__init__.py +1 -1
  3. {pixelarraylib-1.2.2 → pixelarraylib-1.2.4}/pixelarraylib/monitor/feishu.py +223 -0
  4. pixelarraylib-1.2.4/pixelarraylib/object_storage/object_storage.py +1592 -0
  5. {pixelarraylib-1.2.2 → pixelarraylib-1.2.4}/pixelarraylib/scripts/__init__.py +1 -1
  6. {pixelarraylib-1.2.2 → pixelarraylib-1.2.4/pixelarraylib.egg-info}/PKG-INFO +1 -1
  7. {pixelarraylib-1.2.2 → pixelarraylib-1.2.4}/pixelarraylib.egg-info/SOURCES.txt +1 -0
  8. {pixelarraylib-1.2.2 → pixelarraylib-1.2.4}/pyproject.toml +1 -1
  9. {pixelarraylib-1.2.2 → pixelarraylib-1.2.4}/requirements.txt +1 -0
  10. {pixelarraylib-1.2.2 → pixelarraylib-1.2.4}/LICENSE +0 -0
  11. {pixelarraylib-1.2.2 → pixelarraylib-1.2.4}/MANIFEST.in +0 -0
  12. {pixelarraylib-1.2.2 → pixelarraylib-1.2.4}/README.md +0 -0
  13. {pixelarraylib-1.2.2 → pixelarraylib-1.2.4}/pixelarraylib/__main__.py +0 -0
  14. {pixelarraylib-1.2.2 → pixelarraylib-1.2.4}/pixelarraylib/aliyun/__init__.py +0 -0
  15. {pixelarraylib-1.2.2 → pixelarraylib-1.2.4}/pixelarraylib/aliyun/acr.py +0 -0
  16. {pixelarraylib-1.2.2 → pixelarraylib-1.2.4}/pixelarraylib/aliyun/aliyun_email.py +0 -0
  17. {pixelarraylib-1.2.2 → pixelarraylib-1.2.4}/pixelarraylib/aliyun/billing.py +0 -0
  18. {pixelarraylib-1.2.2 → pixelarraylib-1.2.4}/pixelarraylib/aliyun/content_scanner.py +0 -0
  19. {pixelarraylib-1.2.2 → pixelarraylib-1.2.4}/pixelarraylib/aliyun/domain.py +0 -0
  20. {pixelarraylib-1.2.2 → pixelarraylib-1.2.4}/pixelarraylib/aliyun/eci.py +0 -0
  21. {pixelarraylib-1.2.2 → pixelarraylib-1.2.4}/pixelarraylib/aliyun/ecs.py +0 -0
  22. {pixelarraylib-1.2.2 → pixelarraylib-1.2.4}/pixelarraylib/aliyun/eip.py +0 -0
  23. {pixelarraylib-1.2.2 → pixelarraylib-1.2.4}/pixelarraylib/aliyun/fc.py +0 -0
  24. {pixelarraylib-1.2.2 → pixelarraylib-1.2.4}/pixelarraylib/aliyun/oss.py +0 -0
  25. {pixelarraylib-1.2.2 → pixelarraylib-1.2.4}/pixelarraylib/aliyun/polardb.py +0 -0
  26. {pixelarraylib-1.2.2 → pixelarraylib-1.2.4}/pixelarraylib/aliyun/sms.py +0 -0
  27. {pixelarraylib-1.2.2 → pixelarraylib-1.2.4}/pixelarraylib/aliyun/sts.py +0 -0
  28. {pixelarraylib-1.2.2 → pixelarraylib-1.2.4}/pixelarraylib/db_utils/mysql.py +0 -0
  29. {pixelarraylib-1.2.2 → pixelarraylib-1.2.4}/pixelarraylib/db_utils/redis.py +0 -0
  30. {pixelarraylib-1.2.2 → pixelarraylib-1.2.4}/pixelarraylib/decorators/__init__.py +0 -0
  31. {pixelarraylib-1.2.2 → pixelarraylib-1.2.4}/pixelarraylib/decorators/decorators.py +0 -0
  32. {pixelarraylib-1.2.2 → pixelarraylib-1.2.4}/pixelarraylib/gitlab/__init__.py +0 -0
  33. {pixelarraylib-1.2.2 → pixelarraylib-1.2.4}/pixelarraylib/gitlab/code_analyzer.py +0 -0
  34. {pixelarraylib-1.2.2 → pixelarraylib-1.2.4}/pixelarraylib/gitlab/pypi_package_manager.py +0 -0
  35. {pixelarraylib-1.2.2 → pixelarraylib-1.2.4}/pixelarraylib/monitor/__init__.py +0 -0
  36. {pixelarraylib-1.2.2 → pixelarraylib-1.2.4}/pixelarraylib/scripts/build_website.py +0 -0
  37. {pixelarraylib-1.2.2 → pixelarraylib-1.2.4}/pixelarraylib/scripts/collect_code_to_txt.py +0 -0
  38. {pixelarraylib-1.2.2 → pixelarraylib-1.2.4}/pixelarraylib/scripts/create_test_case_files.py +0 -0
  39. {pixelarraylib-1.2.2 → pixelarraylib-1.2.4}/pixelarraylib/scripts/nginx_proxy_to_ecs.py +0 -0
  40. {pixelarraylib-1.2.2 → pixelarraylib-1.2.4}/pixelarraylib/scripts/remove_empty_lines.py +0 -0
  41. {pixelarraylib-1.2.2 → pixelarraylib-1.2.4}/pixelarraylib/scripts/tson_convert.py +0 -0
  42. {pixelarraylib-1.2.2 → pixelarraylib-1.2.4}/pixelarraylib/system/__init__.py +0 -0
  43. {pixelarraylib-1.2.2 → pixelarraylib-1.2.4}/pixelarraylib/system/common.py +0 -0
  44. {pixelarraylib-1.2.2 → pixelarraylib-1.2.4}/pixelarraylib/system/cron_manager.py +0 -0
  45. {pixelarraylib-1.2.2 → pixelarraylib-1.2.4}/pixelarraylib/system/tson.py +0 -0
  46. {pixelarraylib-1.2.2 → pixelarraylib-1.2.4}/pixelarraylib/utils/name_generator.py +0 -0
  47. {pixelarraylib-1.2.2 → pixelarraylib-1.2.4}/pixelarraylib.egg-info/dependency_links.txt +0 -0
  48. {pixelarraylib-1.2.2 → pixelarraylib-1.2.4}/pixelarraylib.egg-info/entry_points.txt +0 -0
  49. {pixelarraylib-1.2.2 → pixelarraylib-1.2.4}/pixelarraylib.egg-info/requires.txt +0 -0
  50. {pixelarraylib-1.2.2 → pixelarraylib-1.2.4}/pixelarraylib.egg-info/top_level.txt +0 -0
  51. {pixelarraylib-1.2.2 → pixelarraylib-1.2.4}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pixelarraylib
3
- Version: 1.2.2
3
+ Version: 1.2.4
4
4
  Summary: PixelArray Python开发工具库 - 包含阿里云服务、数据库工具、装饰器、监控等功能
5
5
  Author-email: Lu qi <qi.lu@pixelarrayai.com>
6
6
  License-Expression: MIT
@@ -20,7 +20,7 @@ PixelArray Python开发工具库
20
20
  from pixelarraylib.gitlab import pypi_package_manager
21
21
  """
22
22
 
23
- __version__ = "1.2.2"
23
+ __version__ = "1.2.4"
24
24
  __author__ = "PixelArray"
25
25
  __email__ = "qi.lu@pixelarrayai.com"
26
26
 
@@ -20,6 +20,8 @@ class Feishu:
20
20
  "picturetransform服务报警": "https://open.feishu.cn/open-apis/bot/v2/hook/e975aa0a-acef-4e3f-bee4-6dc507b87ebd",
21
21
  "cloudstorage服务报警": "https://open.feishu.cn/open-apis/bot/v2/hook/a632d0bc-e400-40ce-a3bb-1b9b9ee634f4",
22
22
  "deployengine服务报警": "https://open.feishu.cn/open-apis/bot/v2/hook/9a347a63-58fb-4e10-9a3d-ff4918ddb3a9",
23
+ "browseruse服务报警": "https://open.feishu.cn/open-apis/bot/v2/hook/a7cf22c5-f50d-4031-b17f-a75f92a3aa91",
24
+ "openpaper_manage_console服务报警": "https://open.feishu.cn/open-apis/bot/v2/hook/2829b285-03ae-4282-9ae5-c93cec4d62a0",
23
25
  }
24
26
 
25
27
  def __init__(
@@ -571,3 +573,224 @@ class FeishuDocumentManager:
571
573
  return result, True
572
574
  except requests.RequestException as e:
573
575
  return {"code": -1, "msg": f"请求失败: {str(e)}"}, False
576
+
577
+
578
+ class FeishuUserManager:
579
+ """
580
+ 飞书用户管理器,用于管理飞书用户的发送消息和查询
581
+ """
582
+
583
+ def __init__(
584
+ self,
585
+ app_id: Optional[str] = None,
586
+ app_secret: Optional[str] = None,
587
+ ):
588
+ """
589
+ description:
590
+ 初始化飞书用户管理器
591
+ parameters:
592
+ app_id(Optional[str]): 飞书应用ID,如果不提供则从settings中读取
593
+ app_secret(Optional[str]): 飞书应用密钥,如果不提供则从settings中读取
594
+ """
595
+ try:
596
+ from settings import FEISHU_APP_ID, FEISHU_APP_SECRET
597
+ self.app_id = app_id or FEISHU_APP_ID
598
+ self.app_secret = app_secret or FEISHU_APP_SECRET
599
+ except ImportError:
600
+ if not app_id or not app_secret:
601
+ raise ValueError(
602
+ "必须提供app_id和app_secret,或者在settings中配置FEISHU_APP_ID和FEISHU_APP_SECRET"
603
+ )
604
+ self.app_id = app_id
605
+ self.app_secret = app_secret
606
+
607
+ self.base_url = "https://open.feishu.cn/open-apis"
608
+ self._tenant_access_token = None
609
+ self._token_expire_time = 0
610
+
611
+ def _get_tenant_access_token(self) -> str:
612
+ """
613
+ description:
614
+ 获取飞书应用的租户访问令牌(tenant_access_token,带缓存机制)
615
+ return:
616
+ str: 租户访问令牌
617
+ """
618
+ import time
619
+
620
+ # 如果token未过期,直接返回缓存的token
621
+ if self._tenant_access_token and time.time() < self._token_expire_time:
622
+ return self._tenant_access_token
623
+
624
+ url = f"{self.base_url}/auth/v3/tenant_access_token/internal"
625
+ headers = {"Content-Type": "application/json; charset=utf-8"}
626
+ data = {
627
+ "app_id": self.app_id,
628
+ "app_secret": self.app_secret,
629
+ }
630
+
631
+ try:
632
+ response = requests.post(url, headers=headers, json=data)
633
+ response.raise_for_status()
634
+ result = response.json()
635
+
636
+ if result.get("code") != 0:
637
+ raise Exception(
638
+ f"获取tenant_access_token失败: {result.get('msg', 'unknown error')}"
639
+ )
640
+
641
+ self._tenant_access_token = result.get("tenant_access_token")
642
+ # token有效期默认7200秒,提前300秒刷新
643
+ expire = result.get("expire", 7200)
644
+ self._token_expire_time = time.time() + expire - 300
645
+
646
+ return self._tenant_access_token
647
+ except requests.RequestException as e:
648
+ raise Exception(f"请求tenant_access_token时发生错误: {str(e)}")
649
+
650
+ def _get_headers(self) -> dict:
651
+ """
652
+ description:
653
+ 获取请求头,包含tenant_access_token
654
+ return:
655
+ dict: 请求头字典
656
+ """
657
+ return {
658
+ "Authorization": f"Bearer {self._get_tenant_access_token()}",
659
+ "Content-Type": "application/json; charset=utf-8",
660
+ }
661
+
662
+ def send_message_to_user(
663
+ self,
664
+ receive_id: str,
665
+ text: str,
666
+ receive_id_type: str = "open_id",
667
+ ) -> tuple[dict, bool]:
668
+ """
669
+ description:
670
+ 发送消息给指定的飞书用户
671
+ parameters:
672
+ receive_id(str): 接收者ID(用户ID)
673
+ text(str): 要发送的文本内容
674
+ receive_id_type(str): 接收者ID类型,默认为"open_id",可选值:"open_id"、"user_id"、"union_id"、"email"、"chat_id"
675
+ return:
676
+ result(dict): API返回的结果
677
+ success(bool): 是否成功
678
+ """
679
+ url = f"{self.base_url}/im/v1/messages"
680
+ headers = self._get_headers()
681
+ # receive_id 和 receive_id_type 作为查询参数
682
+ params = {
683
+ "receive_id_type": receive_id_type,
684
+ }
685
+ # 请求体只包含消息类型和内容
686
+ data = {
687
+ "receive_id": receive_id,
688
+ "msg_type": "text",
689
+ "content": json.dumps({"text": text}),
690
+ }
691
+
692
+ try:
693
+ response = requests.post(url, headers=headers, params=params, json=data)
694
+ response.raise_for_status()
695
+ result = response.json()
696
+
697
+ if result.get("code") != 0:
698
+ return result, False
699
+
700
+ return result, True
701
+ except requests.RequestException as e:
702
+ # 尝试获取更详细的错误信息
703
+ error_detail = {}
704
+ if hasattr(e, 'response') and e.response is not None:
705
+ try:
706
+ error_detail = e.response.json()
707
+ except:
708
+ error_detail = {"text": e.response.text if hasattr(e.response, 'text') else str(e)}
709
+ return {"code": -1, "msg": f"请求失败: {str(e)}", "detail": error_detail}, False
710
+
711
+ async def send_message_to_user_async(
712
+ self,
713
+ receive_id: str,
714
+ text: str,
715
+ receive_id_type: str = "open_id",
716
+ ) -> tuple[dict, bool]:
717
+ """
718
+ description:
719
+ 异步发送消息给指定的飞书用户
720
+ parameters:
721
+ receive_id(str): 接收者ID(用户ID)
722
+ text(str): 要发送的文本内容
723
+ receive_id_type(str): 接收者ID类型,默认为"open_id"
724
+ return:
725
+ result(dict): API返回的结果
726
+ success(bool): 是否成功
727
+ """
728
+ return await asyncio.to_thread(
729
+ self.send_message_to_user, receive_id, text, receive_id_type
730
+ )
731
+
732
+ def list_users(
733
+ self,
734
+ department_id: Optional[str] = None,
735
+ page_size: int = 50,
736
+ page_token: Optional[str] = None,
737
+ user_id_type: str = "open_id",
738
+ ) -> tuple[dict, bool]:
739
+ """
740
+ description:
741
+ 列出飞书中的所有用户(支持按部门筛选)
742
+ parameters:
743
+ department_id(Optional[str]): 部门ID,如果提供则只返回该部门的用户
744
+ page_size(int): 每页数量,默认50,最大100
745
+ page_token(Optional[str]): 分页token,用于获取下一页
746
+ user_id_type(str): 用户ID类型,默认为"open_id",可选值:"open_id"、"user_id"、"union_id"
747
+ return:
748
+ result(dict): API返回的结果,包含用户列表
749
+ success(bool): 是否成功
750
+ """
751
+ url = f"{self.base_url}/contact/v3/users"
752
+ headers = self._get_headers()
753
+ params = {
754
+ "page_size": min(page_size, 100), # 限制最大值为100
755
+ "user_id_type": user_id_type,
756
+ }
757
+
758
+ if department_id:
759
+ params["department_id"] = department_id
760
+ if page_token:
761
+ params["page_token"] = page_token
762
+
763
+ try:
764
+ response = requests.get(url, headers=headers, params=params)
765
+ response.raise_for_status()
766
+ result = response.json()
767
+
768
+ if result.get("code") != 0:
769
+ return result, False
770
+
771
+ return result, True
772
+ except requests.RequestException as e:
773
+ return {"code": -1, "msg": f"请求失败: {str(e)}"}, False
774
+
775
+ async def list_users_async(
776
+ self,
777
+ department_id: Optional[str] = None,
778
+ page_size: int = 50,
779
+ page_token: Optional[str] = None,
780
+ user_id_type: str = "open_id",
781
+ ) -> tuple[dict, bool]:
782
+ """
783
+ description:
784
+ 异步列出飞书中的所有用户
785
+ parameters:
786
+ department_id(Optional[str]): 部门ID,如果提供则只返回该部门的用户
787
+ page_size(int): 每页数量,默认50
788
+ page_token(Optional[str]): 分页token,用于获取下一页
789
+ user_id_type(str): 用户ID类型,默认为"open_id"
790
+ return:
791
+ result(dict): API返回的结果,包含用户列表
792
+ success(bool): 是否成功
793
+ """
794
+ return await asyncio.to_thread(
795
+ self.list_users, department_id, page_size, page_token, user_id_type
796
+ )