ezKit 1.11.1__tar.gz → 1.11.3__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -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
@@ -0,0 +1,297 @@
1
+ """企业微信"""
2
+ #
3
+ # 企业微信开发者中心
4
+ # https://developer.work.weixin.qq.com/
5
+ # https://developer.work.weixin.qq.com/document/path/90313 (全局错误码)
6
+ # 参考文档:
7
+ # https://www.gaoyuanqi.cn/python-yingyong-qiyewx/
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
+ #
36
+ import json
37
+ import time
38
+
39
+ import requests
40
+ from loguru import logger
41
+
42
+ from . import utils
43
+
44
+
45
+ class QYWX:
46
+ """企业微信"""
47
+
48
+ # API前缀
49
+ api_prefix = "https://qyapi.weixin.qq.com"
50
+
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"):
64
+ """Initiation"""
65
+ self.api_prefix = api_prefix
66
+ self.work_id = work_id
67
+ self.agent_id = agent_id
68
+ self.agent_secret = agent_secret
69
+
70
+ """获取 Token"""
71
+ self.get_access_token()
72
+
73
+ def get_access_token(self) -> bool:
74
+ """获取Token"""
75
+
76
+ info: str = "获取 Token"
77
+
78
+ try:
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)
83
+
84
+ if response.status_code != 200:
85
+ logger.error(f"{info} [状态码错误]")
86
+ return False
87
+
88
+ result: dict = response.json()
89
+
90
+ self.access_token = result.get("access_token", "")
91
+
92
+ if not utils.isTrue(self.access_token, str):
93
+ logger.error(f"{info} [失败]")
94
+ return False
95
+
96
+ logger.success(f"{info} [成功]")
97
+ return True
98
+
99
+ except Exception as e:
100
+ logger.success(f"{info} [失败]")
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} [错误]")
164
+ return None
165
+
166
+ try:
167
+
168
+ logger.info(f"{info} ......")
169
+
170
+ if not utils.isTrue(self.access_token, str):
171
+ self.get_access_token()
172
+
173
+ json_string = json.dumps({'mobile': mobile})
174
+
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
+
194
+ except Exception as e:
195
+ logger.error(f"{info} [失败]")
196
+ logger.exception(e)
197
+ return None
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
+
217
+ def send_message_by_mobile(self, mobile: str | list, message: str) -> bool:
218
+ """发送消息"""
219
+
220
+ # 参考文档:
221
+ # https://developer.work.weixin.qq.com/document/path/90235
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
+
229
+ try:
230
+
231
+ logger.info(f"{info} ......")
232
+
233
+ if not utils.isTrue(self.access_token, str):
234
+ if not self.get_access_token():
235
+ logger.error(f"{info} [失败]")
236
+ return False
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
+
248
+ for user in users:
249
+
250
+ logger.info(f"{info} [用户 {user}]")
251
+
252
+ user_object = self.get_user_id_by_mobile(user)
253
+
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')}")
260
+ continue
261
+
262
+ json_dict = {
263
+ 'touser': user_object.get('userid'),
264
+ 'msgtype': 'text',
265
+ 'agentid': self.agent_id,
266
+ 'text': {'content': message},
267
+ 'safe': 0,
268
+ 'enable_id_trans': 0,
269
+ 'enable_duplicate_check': 0,
270
+ 'duplicate_check_interval': 1800
271
+ }
272
+
273
+ json_string = json.dumps(json_dict)
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} [完成]")
291
+
292
+ return True
293
+
294
+ except Exception as e:
295
+ logger.error(f"{info} [失败]")
296
+ logger.exception(e)
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
@@ -3,6 +3,7 @@ MANIFEST.in
3
3
  README.md
4
4
  setup.py
5
5
  ezKit/__init__.py
6
+ ezKit/_file.py
6
7
  ezKit/bottle.py
7
8
  ezKit/bottle_extensions.py
8
9
  ezKit/cipher.py
@@ -3,7 +3,7 @@ from setuptools import find_packages, setup
3
3
 
4
4
  setup(
5
5
  name='ezKit',
6
- version='1.11.1',
6
+ version='1.11.3',
7
7
  author='septvean',
8
8
  author_email='septvean@gmail.com',
9
9
  description='Easy Kit',
@@ -1,189 +0,0 @@
1
- """企业微信"""
2
- # 企业微信开发者中心
3
- # https://developer.work.weixin.qq.com/
4
- # https://developer.work.weixin.qq.com/document/path/90313 (全局错误码)
5
- # 参考文档:
6
- # https://www.gaoyuanqi.cn/python-yingyong-qiyewx/
7
- # https://www.jianshu.com/p/020709b130d3
8
- import json
9
- import time
10
-
11
- import requests
12
- from loguru import logger
13
-
14
- from . import utils
15
-
16
-
17
- class QYWX:
18
- """企业微信"""
19
-
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
25
-
26
- def __init__(self, work_id: str | None, agent_id: str | None, agent_secret: str | None):
27
- """Initiation"""
28
- self.work_id = work_id
29
- self.agent_id = agent_id
30
- self.agent_secret = agent_secret
31
-
32
- """获取 Token"""
33
- self.getaccess_token()
34
-
35
- def getaccess_token(self) -> str | None:
36
- try:
37
- response = requests.get(f"{self.url_prefix}/cgi-bin/gettoken?corpid={self.work_id}&corpsecret={self.agent_secret}", timeout=10)
38
-
39
- if response.status_code != 200:
40
- self.access_token = None
41
- return None
42
-
43
- result: dict = response.json()
44
- self.access_token = result.get('access_token')
45
- return result.get('access_token')
46
-
47
- except Exception as e:
48
- logger.exception(e)
49
- return None
50
-
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
67
-
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
85
-
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
- except Exception as e:
101
- logger.exception(e)
102
- return None
103
-
104
- def get_user_id_by_mobile(self, mobile: str | None = None) -> dict | str | None:
105
- try:
106
- if self.access_token is None:
107
- self.getaccess_token()
108
- 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
-
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
136
- except Exception as e:
137
- logger.exception(e)
138
- return None
139
-
140
- def send_message_by_mobile(self, mobile: str | list, message: str) -> bool:
141
- """发送消息"""
142
-
143
- # 参考文档:
144
- # https://developer.work.weixin.qq.com/document/path/90235
145
-
146
- try:
147
- if self.access_token is None:
148
- self.getaccess_token()
149
-
150
- users: list = []
151
-
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 _:
158
- return False
159
-
160
- for user in users:
161
- user_object = self.get_user_id_by_mobile(user)
162
-
163
- if not isinstance(user_object, dict):
164
- continue
165
-
166
- json_dict = {
167
- 'touser': user_object.get('userid'),
168
- 'msgtype': 'text',
169
- 'agentid': self.agent_id,
170
- 'text': {'content': message},
171
- 'safe': 0,
172
- 'enable_id_trans': 0,
173
- 'enable_duplicate_check': 0,
174
- 'duplicate_check_interval': 1800
175
- }
176
- 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)
184
-
185
- return True
186
-
187
- except Exception as e:
188
- logger.exception(e)
189
- return False
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes