ezKit 1.11.1__py3-none-any.whl → 1.11.3__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
ezKit/_file.py ADDED
@@ -0,0 +1,36 @@
1
+ from loguru import logger
2
+
3
+ from . import utils
4
+
5
+
6
+ def markdown_to_html(markdown_file: str, html_file: str, header_file: str = "markdown.html") -> bool:
7
+ """Markdown to HTML"""
8
+
9
+ # Markdown to HTML
10
+ # 使用 MacDown 生成 HTML, 然后提取样式到 markdown.html
11
+ # pandoc 生成的 HTML 默认 max-width: 36em, 如果表格内容很长, 会导致表格样式难看
12
+ # 所以在 markdown.html 的 body{...} 中添加配置 max-width: unset, 解决内容过长的样式问题
13
+ # 所有 a 标签添加 text-decoration: none; 去除链接下划线
14
+ # pandoc --no-highlight -s --quiet -f markdown -t html -H markdown.html -o data.html data.md
15
+
16
+ info: str = "markdown to html"
17
+
18
+ logger.info(f"{info} ......")
19
+
20
+ try:
21
+
22
+ result = utils.shell(
23
+ f"pandoc --no-highlight -s --quiet -f markdown -t html -H {header_file} -o {html_file} {markdown_file}"
24
+ )
25
+
26
+ if result is None or result.returncode != 0:
27
+ logger.error(f"{info} [failure]")
28
+ return False
29
+
30
+ logger.success(f"{info} [success]")
31
+ return True
32
+
33
+ except Exception as e:
34
+ logger.error(f"{info} [failure]")
35
+ logger.exception(e)
36
+ return False
ezKit/qywx.py CHANGED
@@ -1,10 +1,38 @@
1
1
  """企业微信"""
2
+ #
2
3
  # 企业微信开发者中心
3
4
  # https://developer.work.weixin.qq.com/
4
5
  # https://developer.work.weixin.qq.com/document/path/90313 (全局错误码)
5
6
  # 参考文档:
6
7
  # https://www.gaoyuanqi.cn/python-yingyong-qiyewx/
7
8
  # https://www.jianshu.com/p/020709b130d3
9
+ #
10
+ # 应用管理
11
+ # https://work.weixin.qq.com/wework_admin/frame#apps
12
+ # 自建 -> 创建应用
13
+ # https://work.weixin.qq.com/wework_admin/frame#apps/createApiApp
14
+ # 上传 Logo -> 应用名称 -> 选择部门 / 成员 -> 创建应用
15
+ #
16
+ # 服务端API
17
+ # https://developer.work.weixin.qq.com/document/path/90664
18
+ # 基本概念
19
+ # https://developer.work.weixin.qq.com/document/path/90665
20
+ # 企业ID:
21
+ # https://work.weixin.qq.com/wework_admin/frame#profile
22
+ # AgentId 和 Secret:
23
+ # 进入已创建的应用, 即可获取
24
+ #
25
+ # 应用管理 -> 应用 -> 开发者接口 -> 网页授权及JS-SDK
26
+ #
27
+ # 可作为应用OAuth2.0网页授权功能的回调域名
28
+ # 下载 配置可信域名需完成域名归属认证 的文件
29
+ # 保存到域名下
30
+ # 配置可信域名需完成域名归属认证 已验证
31
+ #
32
+ # 应用管理 -> 应用 -> 开发者接口 -> 企业可信IP
33
+ #
34
+ # 添加IP
35
+ #
8
36
  import json
9
37
  import time
10
38
 
@@ -17,150 +45,218 @@ from . import utils
17
45
  class QYWX:
18
46
  """企业微信"""
19
47
 
20
- url_prefix = "https://qyapi.weixin.qq.com"
21
- work_id: str | None = None
22
- agent_id: str | None = None
23
- agent_secret: str | None = None
24
- access_token: str | None = None
48
+ # API前缀
49
+ api_prefix = "https://qyapi.weixin.qq.com"
25
50
 
26
- def __init__(self, work_id: str | None, agent_id: str | None, agent_secret: str | None):
51
+ # 企业ID: https://developer.work.weixin.qq.com/document/path/90665#corpid
52
+ work_id: str = ""
53
+
54
+ # 应用ID: https://developer.work.weixin.qq.com/document/path/90665#agentid
55
+ agent_id: str = ""
56
+
57
+ # 应用Secret: https://developer.work.weixin.qq.com/document/path/90665#secret
58
+ agent_secret: str = ""
59
+
60
+ # Token: https://developer.work.weixin.qq.com/document/path/90665#access-token
61
+ access_token: str = ""
62
+
63
+ def __init__(self, work_id: str, agent_id: str, agent_secret: str, api_prefix: str = "https://qyapi.weixin.qq.com"):
27
64
  """Initiation"""
65
+ self.api_prefix = api_prefix
28
66
  self.work_id = work_id
29
67
  self.agent_id = agent_id
30
68
  self.agent_secret = agent_secret
31
69
 
32
70
  """获取 Token"""
33
- self.getaccess_token()
71
+ self.get_access_token()
72
+
73
+ def get_access_token(self) -> bool:
74
+ """获取Token"""
75
+
76
+ info: str = "获取 Token"
34
77
 
35
- def getaccess_token(self) -> str | None:
36
78
  try:
37
- response = requests.get(f"{self.url_prefix}/cgi-bin/gettoken?corpid={self.work_id}&corpsecret={self.agent_secret}", timeout=10)
79
+
80
+ logger.info(f"{info} ......")
81
+
82
+ response = requests.get(f"{self.api_prefix}/cgi-bin/gettoken?corpid={self.work_id}&corpsecret={self.agent_secret}", timeout=10)
38
83
 
39
84
  if response.status_code != 200:
40
- self.access_token = None
41
- return None
85
+ logger.error(f"{info} [状态码错误]")
86
+ return False
42
87
 
43
88
  result: dict = response.json()
44
- self.access_token = result.get('access_token')
45
- return result.get('access_token')
46
89
 
47
- except Exception as e:
48
- logger.exception(e)
49
- return None
90
+ self.access_token = result.get("access_token", "")
50
91
 
51
- def get_agent_list(self) -> dict | str | None:
52
- try:
53
- if self.access_token is None:
54
- self.getaccess_token()
55
- response = requests.get(f"{self.url_prefix}/cgi-bin/agent/list?access_token={self.access_token}", timeout=10)
56
- if response.status_code == 200:
57
- response_data: dict = response.json()
58
- if response_data.get('errcode') == 42001:
59
- self.getaccess_token()
60
- time.sleep(1)
61
- self.get_agent_list()
62
- return response_data
63
- return response.text
64
- except Exception as e:
65
- logger.exception(e)
66
- return None
92
+ if not utils.isTrue(self.access_token, str):
93
+ logger.error(f"{info} [失败]")
94
+ return False
67
95
 
68
- def get_department_list(self, eid: str | None = None) -> dict | str | None:
69
- """eid: Enterprise ID"""
70
- try:
71
- if self.access_token is None:
72
- self.getaccess_token()
73
- response = requests.get(f"{self.url_prefix}/cgi-bin/department/list?access_token={self.access_token}&id={eid}", timeout=10)
74
- if response.status_code == 200:
75
- response_data: dict = response.json()
76
- if response_data.get('errcode') == 42001:
77
- self.getaccess_token()
78
- time.sleep(1)
79
- self.get_department_list(eid)
80
- return response_data
81
- return response.text
82
- except Exception as e:
83
- logger.exception(e)
84
- return None
96
+ logger.success(f"{info} [成功]")
97
+ return True
85
98
 
86
- def get_user_list(self, eid: str | None = None) -> dict | str | None:
87
- """eid: Enterprise ID"""
88
- try:
89
- if self.access_token is None:
90
- self.getaccess_token()
91
- response = requests.get(f"{self.url_prefix}/cgi-bin/user/list?access_token={self.access_token}&department_id={eid}", timeout=10)
92
- if response.status_code == 200:
93
- response_data: dict = response.json()
94
- if response_data.get('errcode') == 42001:
95
- self.getaccess_token()
96
- time.sleep(1)
97
- self.get_user_list(eid)
98
- return response_data
99
- return response.text
100
99
  except Exception as e:
100
+ logger.success(f"{info} [失败]")
101
101
  logger.exception(e)
102
+ return False
103
+
104
+ # def get_agent_list(self) -> dict | str | None:
105
+ # try:
106
+ # if not utils.isTrue(self.access_token, str):
107
+ # self.get_access_token()
108
+ # response = requests.get(f"{self.api_prefix}/cgi-bin/agent/list?access_token={self.access_token}", timeout=10)
109
+ # if response.status_code == 200:
110
+ # response_data: dict = response.json()
111
+ # if response_data.get('errcode') == 42001:
112
+ # self.get_access_token()
113
+ # time.sleep(1)
114
+ # self.get_agent_list()
115
+ # return response_data
116
+ # return response.text
117
+ # except Exception as e:
118
+ # logger.exception(e)
119
+ # return None
120
+
121
+ # def get_department_list(self, eid: str | None = None) -> dict | str | None:
122
+ # """eid: Enterprise ID"""
123
+ # try:
124
+ # if self.access_token is None:
125
+ # self.get_access_token()
126
+ # response = requests.get(f"{self.api_prefix}/cgi-bin/department/list?access_token={self.access_token}&id={eid}", timeout=10)
127
+ # if response.status_code == 200:
128
+ # response_data: dict = response.json()
129
+ # if response_data.get('errcode') == 42001:
130
+ # self.get_access_token()
131
+ # time.sleep(1)
132
+ # self.get_department_list(eid)
133
+ # return response_data
134
+ # return response.text
135
+ # except Exception as e:
136
+ # logger.exception(e)
137
+ # return None
138
+
139
+ # def get_user_list(self, eid: str | None = None) -> dict | str | None:
140
+ # """eid: Enterprise ID"""
141
+ # try:
142
+ # if self.access_token is None:
143
+ # self.get_access_token()
144
+ # response = requests.get(f"{self.api_prefix}/cgi-bin/user/list?access_token={self.access_token}&department_id={eid}", timeout=10)
145
+ # if response.status_code == 200:
146
+ # response_data: dict = response.json()
147
+ # if response_data.get('errcode') == 42001:
148
+ # self.get_access_token()
149
+ # time.sleep(1)
150
+ # self.get_user_list(eid)
151
+ # return response_data
152
+ # return response.text
153
+ # except Exception as e:
154
+ # logger.exception(e)
155
+ # return None
156
+
157
+ def get_user_id_by_mobile(self, mobile: str) -> dict | None:
158
+ """根据电话号码获取用户ID"""
159
+
160
+ info: str = f"根据电话号码获取用户ID: {mobile}"
161
+
162
+ if not utils.check_arguments([(mobile, str, "mobile")]):
163
+ logger.error(f"{info} [错误]")
102
164
  return None
103
165
 
104
- def get_user_id_by_mobile(self, mobile: str | None = None) -> dict | str | None:
105
166
  try:
106
- if self.access_token is None:
107
- self.getaccess_token()
167
+
168
+ logger.info(f"{info} ......")
169
+
170
+ if not utils.isTrue(self.access_token, str):
171
+ self.get_access_token()
172
+
108
173
  json_string = json.dumps({'mobile': mobile})
109
- response = requests.post(f"{self.url_prefix}/cgi-bin/user/getuserid?access_token={self.access_token}", data=json_string, timeout=10)
110
- if response.status_code == 200:
111
- response_data: dict = response.json()
112
- if response_data.get('errcode') == 42001:
113
- self.getaccess_token()
114
- time.sleep(1)
115
- self.get_user_id_by_mobile(mobile)
116
- return response_data
117
- return response.text
118
- except Exception as e:
119
- logger.exception(e)
120
- return None
121
174
 
122
- def get_user_info(self, eid: str | None = None) -> dict | str | None:
123
- """eid: Enterprise ID"""
124
- try:
125
- if self.access_token is None:
126
- self.getaccess_token()
127
- response = requests.get(f"{self.url_prefix}/cgi-bin/user/get?access_token={self.access_token}&userid={eid}", timeout=10)
128
- if response.status_code == 200:
129
- response_data: dict = response.json()
130
- if response_data.get('errcode') == 42001:
131
- self.getaccess_token()
132
- time.sleep(1)
133
- self.get_user_info(eid)
134
- return response_data
135
- return response.text
175
+ response = requests.post(f"{self.api_prefix}/cgi-bin/user/getuserid?access_token={self.access_token}", data=json_string, timeout=10)
176
+
177
+ if response.status_code != 200:
178
+ logger.error(f"{info} [接口请求错误]")
179
+ return None
180
+
181
+ response_data: dict = response.json()
182
+
183
+ if response_data.get('errcode') == 42001:
184
+ self.get_access_token()
185
+ time.sleep(1)
186
+ self.get_user_id_by_mobile(mobile)
187
+
188
+ logger.success(f"{info} [成功]")
189
+
190
+ return response_data
191
+
192
+ # return response.text
193
+
136
194
  except Exception as e:
195
+ logger.error(f"{info} [失败]")
137
196
  logger.exception(e)
138
197
  return None
139
198
 
199
+ # def get_user_info(self, eid: str | None = None) -> dict | str | None:
200
+ # """eid: Enterprise ID"""
201
+ # try:
202
+ # if self.access_token is None:
203
+ # self.get_access_token()
204
+ # response = requests.get(f"{self.api_prefix}/cgi-bin/user/get?access_token={self.access_token}&userid={eid}", timeout=10)
205
+ # if response.status_code == 200:
206
+ # response_data: dict = response.json()
207
+ # if response_data.get('errcode') == 42001:
208
+ # self.get_access_token()
209
+ # time.sleep(1)
210
+ # self.get_user_info(eid)
211
+ # return response_data
212
+ # return response.text
213
+ # except Exception as e:
214
+ # logger.exception(e)
215
+ # return None
216
+
140
217
  def send_message_by_mobile(self, mobile: str | list, message: str) -> bool:
141
218
  """发送消息"""
142
219
 
143
220
  # 参考文档:
144
221
  # https://developer.work.weixin.qq.com/document/path/90235
145
222
 
223
+ info: str = "发送消息"
224
+
225
+ if not utils.check_arguments([(mobile, (str, list), "mobile"), (message, str, "message")]):
226
+ logger.error(f"{info} [失败]")
227
+ return False
228
+
146
229
  try:
147
- if self.access_token is None:
148
- self.getaccess_token()
149
230
 
150
- users: list = []
231
+ logger.info(f"{info} ......")
151
232
 
152
- match True:
153
- case True if isinstance(mobile, list) and utils.isTrue(mobile, list):
154
- users = mobile
155
- case True if isinstance(mobile, str) and utils.isTrue(mobile, str):
156
- users.append(mobile)
157
- case _:
233
+ if not utils.isTrue(self.access_token, str):
234
+ if not self.get_access_token():
235
+ logger.error(f"{info} [失败]")
158
236
  return False
159
237
 
238
+ users: list = []
239
+
240
+ if isinstance(mobile, str) and utils.isTrue(mobile, str):
241
+ users.append(mobile)
242
+ elif isinstance(mobile, list) and utils.isTrue(mobile, list):
243
+ users += mobile
244
+ else:
245
+ logger.error(f"{info} [电话号码错误]")
246
+ return False
247
+
160
248
  for user in users:
249
+
250
+ logger.info(f"{info} [用户 {user}]")
251
+
161
252
  user_object = self.get_user_id_by_mobile(user)
162
253
 
163
- if not isinstance(user_object, dict):
254
+ if not (isinstance(user_object, dict) and utils.isTrue(user_object, dict)):
255
+ logger.error(f"{info} [获取用户ID错误: {user}]")
256
+ continue
257
+
258
+ if user_object.get("errcode", -1) != 0 or user_object.get("errmsg", "") != "ok":
259
+ logger.error(f"{user_object.get('errcode')}: {user_object.get('errmsg')}")
164
260
  continue
165
261
 
166
262
  json_dict = {
@@ -173,17 +269,29 @@ class QYWX:
173
269
  'enable_duplicate_check': 0,
174
270
  'duplicate_check_interval': 1800
175
271
  }
272
+
176
273
  json_string = json.dumps(json_dict)
177
- response = requests.post(f"{self.url_prefix}/cgi-bin/message/send?access_token={self.access_token}", data=json_string, timeout=10)
178
- if response.status_code == 200:
179
- response_data: dict = response.json()
180
- if response_data.get('errcode') == 42001:
181
- self.getaccess_token()
182
- time.sleep(1)
183
- self.send_message_by_mobile(mobile, message)
274
+
275
+ response = requests.post(f"{self.api_prefix}/cgi-bin/message/send?access_token={self.access_token}", data=json_string, timeout=10)
276
+
277
+ if response.status_code != 200:
278
+ logger.error(f"{info} [发送消息失败: {user}]")
279
+ continue
280
+
281
+ response_data: dict = response.json()
282
+
283
+ if response_data.get('errcode') == 42001:
284
+ self.get_access_token()
285
+ time.sleep(1)
286
+ self.send_message_by_mobile(mobile, message)
287
+
288
+ logger.success(f"{info} [成功: 用户 {user}]")
289
+
290
+ logger.success(f"{info} [完成]")
184
291
 
185
292
  return True
186
293
 
187
294
  except Exception as e:
295
+ logger.error(f"{info} [失败]")
188
296
  logger.exception(e)
189
297
  return False
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ezKit
3
- Version: 1.11.1
3
+ Version: 1.11.3
4
4
  Summary: Easy Kit
5
5
  Author: septvean
6
6
  Author-email: septvean@gmail.com
@@ -1,18 +1,19 @@
1
1
  ezKit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ ezKit/_file.py,sha256=0qRZhwYuagTgTGrhm-tzAMvEQT4HTJA_xZKqF2bo0ho,1207
2
3
  ezKit/bottle.py,sha256=usKK1wVaZw4_D-4VwMYmOIc8jtz4TrpM30nck59HMFw,180178
3
4
  ezKit/bottle_extensions.py,sha256=3reEQVZuHklXTl6r7F8kiBFFPb0RaAGc3mYJJnrMDjQ,1129
4
5
  ezKit/cipher.py,sha256=0T_StbjiNI4zgrjVgcfU-ffKgu1waBA9UDudAnqFcNM,2896
5
6
  ezKit/database.py,sha256=r5YNoEzeOeVTlEWI99xXtHTmPZ73_DopS8DTzZk8Lts,12432
6
7
  ezKit/http.py,sha256=ysXzqXFi9zmuVKINbYGwmf9Q5xDVW_DZWrSh6HSVq8M,1800
7
8
  ezKit/mongo.py,sha256=l3jRMmoGrTm16OG4daSCn0JLU1nbYAmTtHokwjLXzoA,2390
8
- ezKit/qywx.py,sha256=X_H4fzP-iEqeDEbumr7D1bXi6dxczaxfO8iyutzy02s,7171
9
+ ezKit/qywx.py,sha256=dGChIIf2V81MwufcPn6hwgSenPuxqK994KRH7ECT-CM,10387
9
10
  ezKit/redis.py,sha256=tdiqfizPYQQTIUumkJGUJsJVlv0zVTSTYGQN0QutYs4,1963
10
11
  ezKit/sendemail.py,sha256=tRXCsJm_RfTJ9xEWe_lTQ5kOs2JxHGPXvq0oWA7prq0,7263
11
12
  ezKit/token.py,sha256=HKREyZj_T2S8-aFoFIrBXTaCKExQq4zE66OHXhGHqQg,1750
12
13
  ezKit/utils.py,sha256=a2RiwOjO83Wi4GmyBRLI1UreaVgNLL66Snbq0HnI37c,42501
13
14
  ezKit/xftp.py,sha256=XyIdr_2rxRVLqPofG6fIYWhAMVsFwTyp46dg5P9FLW4,7774
14
- ezKit-1.11.1.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
15
- ezKit-1.11.1.dist-info/METADATA,sha256=yJa5E_HlQaNWl0vp7gHIS1c_NalJnQtTvO9nzQK4mpU,191
16
- ezKit-1.11.1.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
17
- ezKit-1.11.1.dist-info/top_level.txt,sha256=aYLB_1WODsqNTsTFWcKP-BN0KCTKcV-HZJ4zlHkCFw8,6
18
- ezKit-1.11.1.dist-info/RECORD,,
15
+ ezKit-1.11.3.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
16
+ ezKit-1.11.3.dist-info/METADATA,sha256=DdwCdJ3vRgC-lWWRYXxG7viLD_44xAkZQVngFvwEFlk,191
17
+ ezKit-1.11.3.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
18
+ ezKit-1.11.3.dist-info/top_level.txt,sha256=aYLB_1WODsqNTsTFWcKP-BN0KCTKcV-HZJ4zlHkCFw8,6
19
+ ezKit-1.11.3.dist-info/RECORD,,
File without changes