ezKit 1.11.0__py3-none-any.whl → 1.11.2__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,217 @@ 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):
27
64
  """Initiation"""
28
65
  self.work_id = work_id
29
66
  self.agent_id = agent_id
30
67
  self.agent_secret = agent_secret
31
68
 
32
69
  """获取 Token"""
33
- self.getaccess_token()
70
+ self.get_access_token()
71
+
72
+ def get_access_token(self) -> bool:
73
+ """获取Token"""
74
+
75
+ info: str = "获取 Token"
34
76
 
35
- def getaccess_token(self) -> str | None:
36
77
  try:
37
- response = requests.get(f"{self.url_prefix}/cgi-bin/gettoken?corpid={self.work_id}&corpsecret={self.agent_secret}", timeout=10)
78
+
79
+ logger.info(f"{info} ......")
80
+
81
+ response = requests.get(f"{self.api_prefix}/cgi-bin/gettoken?corpid={self.work_id}&corpsecret={self.agent_secret}", timeout=10)
38
82
 
39
83
  if response.status_code != 200:
40
- self.access_token = None
41
- return None
84
+ logger.error(f"{info} [状态码错误]")
85
+ return False
42
86
 
43
87
  result: dict = response.json()
44
- self.access_token = result.get('access_token')
45
- return result.get('access_token')
46
88
 
47
- except Exception as e:
48
- logger.exception(e)
49
- return None
89
+ self.access_token = result.get("access_token", "")
50
90
 
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
91
+ if not utils.isTrue(self.access_token, str):
92
+ logger.error(f"{info} [失败]")
93
+ return False
67
94
 
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
95
+ logger.success(f"{info} [成功]")
96
+ return True
85
97
 
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
98
  except Exception as e:
99
+ logger.success(f"{info} [失败]")
101
100
  logger.exception(e)
101
+ return False
102
+
103
+ # def get_agent_list(self) -> dict | str | None:
104
+ # try:
105
+ # if not utils.isTrue(self.access_token, str):
106
+ # self.get_access_token()
107
+ # response = requests.get(f"{self.api_prefix}/cgi-bin/agent/list?access_token={self.access_token}", timeout=10)
108
+ # if response.status_code == 200:
109
+ # response_data: dict = response.json()
110
+ # if response_data.get('errcode') == 42001:
111
+ # self.get_access_token()
112
+ # time.sleep(1)
113
+ # self.get_agent_list()
114
+ # return response_data
115
+ # return response.text
116
+ # except Exception as e:
117
+ # logger.exception(e)
118
+ # return None
119
+
120
+ # def get_department_list(self, eid: str | None = None) -> dict | str | None:
121
+ # """eid: Enterprise ID"""
122
+ # try:
123
+ # if self.access_token is None:
124
+ # self.get_access_token()
125
+ # response = requests.get(f"{self.api_prefix}/cgi-bin/department/list?access_token={self.access_token}&id={eid}", timeout=10)
126
+ # if response.status_code == 200:
127
+ # response_data: dict = response.json()
128
+ # if response_data.get('errcode') == 42001:
129
+ # self.get_access_token()
130
+ # time.sleep(1)
131
+ # self.get_department_list(eid)
132
+ # return response_data
133
+ # return response.text
134
+ # except Exception as e:
135
+ # logger.exception(e)
136
+ # return None
137
+
138
+ # def get_user_list(self, eid: str | None = None) -> dict | str | None:
139
+ # """eid: Enterprise ID"""
140
+ # try:
141
+ # if self.access_token is None:
142
+ # self.get_access_token()
143
+ # response = requests.get(f"{self.api_prefix}/cgi-bin/user/list?access_token={self.access_token}&department_id={eid}", timeout=10)
144
+ # if response.status_code == 200:
145
+ # response_data: dict = response.json()
146
+ # if response_data.get('errcode') == 42001:
147
+ # self.get_access_token()
148
+ # time.sleep(1)
149
+ # self.get_user_list(eid)
150
+ # return response_data
151
+ # return response.text
152
+ # except Exception as e:
153
+ # logger.exception(e)
154
+ # return None
155
+
156
+ def get_user_id_by_mobile(self, mobile: str) -> dict | None:
157
+ """根据电话号码获取用户ID"""
158
+
159
+ info: str = f"根据电话号码获取用户ID: {mobile}"
160
+
161
+ if not utils.check_arguments([(mobile, str, "mobile")]):
162
+ logger.error(f"{info} [错误]")
102
163
  return None
103
164
 
104
- def get_user_id_by_mobile(self, mobile: str | None = None) -> dict | str | None:
105
165
  try:
106
- if self.access_token is None:
107
- self.getaccess_token()
166
+
167
+ logger.info(f"{info} ......")
168
+
169
+ if not utils.isTrue(self.access_token, str):
170
+ self.get_access_token()
171
+
108
172
  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
173
 
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
174
+ response = requests.post(f"{self.api_prefix}/cgi-bin/user/getuserid?access_token={self.access_token}", data=json_string, timeout=10)
175
+
176
+ if response.status_code != 200:
177
+ logger.error(f"{info} [接口请求错误]")
178
+ return None
179
+
180
+ response_data: dict = response.json()
181
+
182
+ if response_data.get('errcode') == 42001:
183
+ self.get_access_token()
184
+ time.sleep(1)
185
+ self.get_user_id_by_mobile(mobile)
186
+
187
+ logger.success(f"{info} [成功]")
188
+
189
+ return response_data
190
+
191
+ # return response.text
192
+
136
193
  except Exception as e:
194
+ logger.error(f"{info} [失败]")
137
195
  logger.exception(e)
138
196
  return None
139
197
 
198
+ # def get_user_info(self, eid: str | None = None) -> dict | str | None:
199
+ # """eid: Enterprise ID"""
200
+ # try:
201
+ # if self.access_token is None:
202
+ # self.get_access_token()
203
+ # response = requests.get(f"{self.api_prefix}/cgi-bin/user/get?access_token={self.access_token}&userid={eid}", timeout=10)
204
+ # if response.status_code == 200:
205
+ # response_data: dict = response.json()
206
+ # if response_data.get('errcode') == 42001:
207
+ # self.get_access_token()
208
+ # time.sleep(1)
209
+ # self.get_user_info(eid)
210
+ # return response_data
211
+ # return response.text
212
+ # except Exception as e:
213
+ # logger.exception(e)
214
+ # return None
215
+
140
216
  def send_message_by_mobile(self, mobile: str | list, message: str) -> bool:
141
217
  """发送消息"""
142
218
 
143
219
  # 参考文档:
144
220
  # https://developer.work.weixin.qq.com/document/path/90235
145
221
 
222
+ info: str = "发送消息"
223
+
224
+ if not utils.check_arguments([(mobile, (str, list), "mobile"), (message, str, "message")]):
225
+ logger.error(f"{info} [失败]")
226
+ return False
227
+
146
228
  try:
147
- if self.access_token is None:
148
- self.getaccess_token()
149
229
 
150
- users: list = []
230
+ logger.info(f"{info} ......")
151
231
 
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 _:
232
+ if not utils.isTrue(self.access_token, str):
233
+ if not self.get_access_token():
234
+ logger.error(f"{info} [失败]")
158
235
  return False
159
236
 
237
+ users: list = []
238
+
239
+ if isinstance(mobile, str) and utils.isTrue(mobile, str):
240
+ users.append(mobile)
241
+ elif isinstance(mobile, list) and utils.isTrue(mobile, list):
242
+ users += mobile
243
+ else:
244
+ logger.error(f"{info} [电话号码错误]")
245
+ return False
246
+
160
247
  for user in users:
248
+
249
+ logger.info(f"{info} [用户 {user}]")
250
+
161
251
  user_object = self.get_user_id_by_mobile(user)
162
252
 
163
- if not isinstance(user_object, dict):
253
+ if not (isinstance(user_object, dict) and utils.isTrue(user_object, dict)):
254
+ logger.error(f"{info} [获取用户ID错误: {user}]")
255
+ continue
256
+
257
+ if user_object.get("errcode", -1) != 0 or user_object.get("errmsg", "") != "ok":
258
+ logger.error(f"{user_object.get('errcode')}: {user_object.get('errmsg')}")
164
259
  continue
165
260
 
166
261
  json_dict = {
@@ -173,17 +268,29 @@ class QYWX:
173
268
  'enable_duplicate_check': 0,
174
269
  'duplicate_check_interval': 1800
175
270
  }
271
+
176
272
  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)
273
+
274
+ response = requests.post(f"{self.api_prefix}/cgi-bin/message/send?access_token={self.access_token}", data=json_string, timeout=10)
275
+
276
+ if response.status_code != 200:
277
+ logger.error(f"{info} [发送消息失败: {user}]")
278
+ continue
279
+
280
+ response_data: dict = response.json()
281
+
282
+ if response_data.get('errcode') == 42001:
283
+ self.get_access_token()
284
+ time.sleep(1)
285
+ self.send_message_by_mobile(mobile, message)
286
+
287
+ logger.success(f"{info} [成功: 用户 {user}]")
288
+
289
+ logger.success(f"{info} [完成]")
184
290
 
185
291
  return True
186
292
 
187
293
  except Exception as e:
294
+ logger.error(f"{info} [失败]")
188
295
  logger.exception(e)
189
296
  return False
ezKit/utils.py CHANGED
@@ -418,26 +418,19 @@ def list_print_by_step(
418
418
 
419
419
  try:
420
420
 
421
- # result: list = []
422
-
423
- # if len(data) <= step:
424
- # result.append(data)
425
- # else:
426
- # data_list = list_split(data, step, debug=debug)
427
- # if data_list is None or isTrue(data_list, list) is False:
428
- # return False
429
- # result = data_list
430
-
431
- # for item in result:
432
- # print(*item, sep=separator)
433
-
434
- # return True
435
-
436
421
  # 打印
437
422
  for i, v in enumerate(data):
423
+
438
424
  if i > 0 and i % step == 0:
439
425
  print()
440
- print(v, end=separator)
426
+
427
+ # print(v, end=separator)
428
+
429
+ # 每行最后一个 或者 所有数据最后一个, 不打印分隔符
430
+ if ((i % step) == (step - 1)) or ((i + 1) == len(data)):
431
+ print(v, end='')
432
+ else:
433
+ print(v, end=separator)
441
434
 
442
435
  print()
443
436
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ezKit
3
- Version: 1.11.0
3
+ Version: 1.11.2
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=GKwcx_L3WCcWEMZuuMpqdAy9ubqSu2RoxndxkkAYRtQ,10301
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
- ezKit/utils.py,sha256=CeRFReOm3afxRYkqaVXWv1x4eKXB1YiHnbeGBxvWhKs,42657
13
+ ezKit/utils.py,sha256=a2RiwOjO83Wi4GmyBRLI1UreaVgNLL66Snbq0HnI37c,42501
13
14
  ezKit/xftp.py,sha256=XyIdr_2rxRVLqPofG6fIYWhAMVsFwTyp46dg5P9FLW4,7774
14
- ezKit-1.11.0.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
15
- ezKit-1.11.0.dist-info/METADATA,sha256=qSEnzYClSlWB_0w9rYxDuVD-tc9Y7hPIv_sw3GuXo8g,191
16
- ezKit-1.11.0.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
17
- ezKit-1.11.0.dist-info/top_level.txt,sha256=aYLB_1WODsqNTsTFWcKP-BN0KCTKcV-HZJ4zlHkCFw8,6
18
- ezKit-1.11.0.dist-info/RECORD,,
15
+ ezKit-1.11.2.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
16
+ ezKit-1.11.2.dist-info/METADATA,sha256=O6yYp94ImOfIjj7pLEWeFsCl1PDBeJNk9nPgme9iOAs,191
17
+ ezKit-1.11.2.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
18
+ ezKit-1.11.2.dist-info/top_level.txt,sha256=aYLB_1WODsqNTsTFWcKP-BN0KCTKcV-HZJ4zlHkCFw8,6
19
+ ezKit-1.11.2.dist-info/RECORD,,
File without changes