ezKit 1.0.0__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.
- ezKit/__init__.py +1 -0
- ezKit/bottle.py +3809 -0
- ezKit/cipher.py +74 -0
- ezKit/database.py +168 -0
- ezKit/files.py +348 -0
- ezKit/http.py +92 -0
- ezKit/mongo.py +62 -0
- ezKit/plots.py +155 -0
- ezKit/redis.py +51 -0
- ezKit/reports.py +274 -0
- ezKit/sendemail.py +146 -0
- ezKit/utils.py +1257 -0
- ezKit/weixin.py +148 -0
- ezKit/xftp.py +194 -0
- ezKit/zabbix.py +866 -0
- ezKit-1.0.0.dist-info/LICENSE +674 -0
- ezKit-1.0.0.dist-info/METADATA +10 -0
- ezKit-1.0.0.dist-info/RECORD +20 -0
- ezKit-1.0.0.dist-info/WHEEL +5 -0
- ezKit-1.0.0.dist-info/top_level.txt +1 -0
ezKit/weixin.py
ADDED
@@ -0,0 +1,148 @@
|
|
1
|
+
import json
|
2
|
+
import time
|
3
|
+
|
4
|
+
import requests
|
5
|
+
|
6
|
+
|
7
|
+
class WeiXin(object):
|
8
|
+
|
9
|
+
'''
|
10
|
+
企业微信开发者中心
|
11
|
+
|
12
|
+
https://developer.work.weixin.qq.com/
|
13
|
+
https://developer.work.weixin.qq.com/document/path/90313 (全局错误码)
|
14
|
+
|
15
|
+
参考文档:
|
16
|
+
|
17
|
+
https://www.gaoyuanqi.cn/python-yingyong-qiyewx/
|
18
|
+
https://www.jianshu.com/p/020709b130d3
|
19
|
+
'''
|
20
|
+
|
21
|
+
_work_id, _agent_id, _agent_secret, _access_token = None, None, None, None
|
22
|
+
|
23
|
+
def __init__(self, work_id, agent_id, agent_secret):
|
24
|
+
''' Initiation '''
|
25
|
+
self._work_id = work_id
|
26
|
+
self._agent_id = agent_id
|
27
|
+
self._agent_secret = agent_secret
|
28
|
+
|
29
|
+
''' 获取 Token '''
|
30
|
+
self.get_access_token()
|
31
|
+
|
32
|
+
def get_access_token(self):
|
33
|
+
_response = requests.get(f'https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={self._work_id}&corpsecret={self._agent_secret}')
|
34
|
+
if _response.status_code == 200:
|
35
|
+
_result = _response.json()
|
36
|
+
self._access_token = _result.get('access_token')
|
37
|
+
else:
|
38
|
+
self._access_token = None
|
39
|
+
|
40
|
+
def get_agent_list(self):
|
41
|
+
|
42
|
+
self.get_access_token() if self._access_token == None else next
|
43
|
+
|
44
|
+
_response = requests.get(f'https://qyapi.weixin.qq.com/cgi-bin/agent/list?access_token={self._access_token}')
|
45
|
+
|
46
|
+
if _response.status_code == 200:
|
47
|
+
_response_data = _response.json()
|
48
|
+
if _response_data.get('errcode') == 42001:
|
49
|
+
self.get_access_token()
|
50
|
+
time.sleep(1)
|
51
|
+
self.get_agent_list()
|
52
|
+
return _response_data
|
53
|
+
return {'response': _response.text}
|
54
|
+
|
55
|
+
def get_department_list(self, id):
|
56
|
+
|
57
|
+
self.get_access_token() if self._access_token == None else next
|
58
|
+
|
59
|
+
_response = requests.get(f'https://qyapi.weixin.qq.com/cgi-bin/department/list?access_token={self._access_token}&id={id}')
|
60
|
+
|
61
|
+
if _response.status_code == 200:
|
62
|
+
_response_data = _response.json()
|
63
|
+
if _response_data.get('errcode') == 42001:
|
64
|
+
self.get_access_token()
|
65
|
+
time.sleep(1)
|
66
|
+
self.get_department_list(id)
|
67
|
+
return _response_data
|
68
|
+
return {'response': _response.text}
|
69
|
+
|
70
|
+
def get_user_list(self, id):
|
71
|
+
|
72
|
+
self.get_access_token() if self._access_token == None else next
|
73
|
+
|
74
|
+
_response = requests.get(f'https://qyapi.weixin.qq.com/cgi-bin/user/list?access_token={self._access_token}&department_id={id}')
|
75
|
+
|
76
|
+
if _response.status_code == 200:
|
77
|
+
_response_data = _response.json()
|
78
|
+
if _response_data.get('errcode') == 42001:
|
79
|
+
self.get_access_token()
|
80
|
+
time.sleep(1)
|
81
|
+
self.get_user_list(id)
|
82
|
+
return _response_data
|
83
|
+
return {'response': _response.text}
|
84
|
+
|
85
|
+
def get_user_id_by_mobile(self, mobile):
|
86
|
+
|
87
|
+
self.get_access_token() if self._access_token == None else next
|
88
|
+
|
89
|
+
_json_dict = {'mobile': mobile}
|
90
|
+
|
91
|
+
_json_string = json.dumps(_json_dict)
|
92
|
+
|
93
|
+
_response = requests.post(f'https://qyapi.weixin.qq.com/cgi-bin/user/getuserid?access_token={self._access_token}', data=_json_string)
|
94
|
+
|
95
|
+
if _response.status_code == 200:
|
96
|
+
_response_data = _response.json()
|
97
|
+
if _response_data.get('errcode') == 42001:
|
98
|
+
self.get_access_token()
|
99
|
+
time.sleep(1)
|
100
|
+
self.get_user_id_by_mobile(id)
|
101
|
+
return _response_data
|
102
|
+
return {'response': _response.text}
|
103
|
+
|
104
|
+
def get_user_info(self, id):
|
105
|
+
|
106
|
+
self.get_access_token() if self._access_token == None else next
|
107
|
+
|
108
|
+
_response = requests.get(f'https://qyapi.weixin.qq.com/cgi-bin/user/get?access_token={self._access_token}&userid={id}')
|
109
|
+
|
110
|
+
if _response.status_code == 200:
|
111
|
+
_response_data = _response.json()
|
112
|
+
if _response_data.get('errcode') == 42001:
|
113
|
+
self.get_access_token()
|
114
|
+
time.sleep(1)
|
115
|
+
self.get_user_info(id)
|
116
|
+
return _response_data
|
117
|
+
return {'response': _response.text}
|
118
|
+
|
119
|
+
def send_text(self, users, message):
|
120
|
+
'''
|
121
|
+
https://developer.work.weixin.qq.com/document/path/90235
|
122
|
+
'''
|
123
|
+
|
124
|
+
self.get_access_token() if self._access_token == None else next
|
125
|
+
|
126
|
+
_json_dict = {
|
127
|
+
'touser': users,
|
128
|
+
'msgtype': 'text',
|
129
|
+
'agentid': self._agent_id,
|
130
|
+
'text': {'content': message},
|
131
|
+
'safe': 0,
|
132
|
+
'enable_id_trans': 0,
|
133
|
+
'enable_duplicate_check': 0,
|
134
|
+
'duplicate_check_interval': 1800
|
135
|
+
}
|
136
|
+
|
137
|
+
_json_string = json.dumps(_json_dict)
|
138
|
+
|
139
|
+
_response = requests.post(f'https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token={self._access_token}', data=_json_string)
|
140
|
+
|
141
|
+
if _response.status_code == 200:
|
142
|
+
_response_data = _response.json()
|
143
|
+
if _response_data.get('errcode') == 42001:
|
144
|
+
self.get_access_token()
|
145
|
+
time.sleep(1)
|
146
|
+
self.send_text(users, message)
|
147
|
+
return _response_data
|
148
|
+
return {'response': _response.text}
|
ezKit/xftp.py
ADDED
@@ -0,0 +1,194 @@
|
|
1
|
+
'''
|
2
|
+
ftplib: https://docs.python.org/3.10/library/ftplib.html
|
3
|
+
'''
|
4
|
+
import os
|
5
|
+
from ftplib import FTP
|
6
|
+
from pathlib import Path
|
7
|
+
|
8
|
+
|
9
|
+
class XFTP:
|
10
|
+
|
11
|
+
def __init__(self, host='127.0.0.1', port=21, username='anonymous', password='', encoding='UTF-8', debuglevel=0):
|
12
|
+
''' Initiation '''
|
13
|
+
self.ftp = FTP()
|
14
|
+
self.ftp.set_debuglevel(debuglevel)
|
15
|
+
self.host = host
|
16
|
+
self.port = port
|
17
|
+
self.username = username
|
18
|
+
self.password = password
|
19
|
+
self.encoding = encoding
|
20
|
+
self.retry = 1
|
21
|
+
|
22
|
+
def connect(self):
|
23
|
+
''' FTP connect '''
|
24
|
+
try:
|
25
|
+
self.ftp.connect(host=self.host, port=self.port, timeout=10)
|
26
|
+
self.ftp.encoding = self.encoding
|
27
|
+
self.ftp.login(user=self.username, passwd=self.password)
|
28
|
+
print('FTP connect success')
|
29
|
+
print('-' * 80)
|
30
|
+
return True
|
31
|
+
except Exception as e:
|
32
|
+
print(f'FTP connect error: {e}, retry...')
|
33
|
+
if self.retry >= 3:
|
34
|
+
print('FTP connect faild')
|
35
|
+
return False
|
36
|
+
self.retry += 1
|
37
|
+
self.connect()
|
38
|
+
|
39
|
+
def close(self, info=None):
|
40
|
+
''' FTP close '''
|
41
|
+
print(info) if info else None
|
42
|
+
try:
|
43
|
+
self.ftp.quit()
|
44
|
+
except:
|
45
|
+
self.ftp.close()
|
46
|
+
print('-' * 80)
|
47
|
+
print('FTP connect closed')
|
48
|
+
|
49
|
+
def get_file_list(self, dir='/'):
|
50
|
+
''' Get file list '''
|
51
|
+
self.chdir_to_remote(dir)
|
52
|
+
return self.ftp.nlst()
|
53
|
+
|
54
|
+
def get_file_size(self, dir='/', file=None):
|
55
|
+
''' Get file size '''
|
56
|
+
self.chdir_to_remote(dir)
|
57
|
+
return self.ftp.size(file)
|
58
|
+
|
59
|
+
def mkdir(self, dir_string='/'):
|
60
|
+
''' 创建目录 (从 / 目录依次递增创建子目录. 如果目录存在, 创建目录时会报错, 所以这里忽略所有错误.) '''
|
61
|
+
try:
|
62
|
+
dir_list = dir_string.split("/")
|
63
|
+
for i, _ in enumerate(dir_list):
|
64
|
+
dir = '/'.join(dir_list[:i + 1])
|
65
|
+
try:
|
66
|
+
self.ftp.mkd(dir)
|
67
|
+
except:
|
68
|
+
pass
|
69
|
+
return True
|
70
|
+
except:
|
71
|
+
return False
|
72
|
+
|
73
|
+
def chdir_to_remote(self, dir='/'):
|
74
|
+
''' change to remote directory'''
|
75
|
+
try:
|
76
|
+
self.ftp.cwd(dir)
|
77
|
+
except:
|
78
|
+
self.close(f'Remote directory error: {dir}')
|
79
|
+
|
80
|
+
def x_exit(self, info=None):
|
81
|
+
''' Exit '''
|
82
|
+
print(info) if info else None
|
83
|
+
# 注意: exit() 并不会退出脚本, 配合 try 使用
|
84
|
+
exit()
|
85
|
+
|
86
|
+
def x_exec(self, local_dir='.', local_file='', remote_dir='/', remote_file='', upload=False):
|
87
|
+
''' Download or Upload '''
|
88
|
+
|
89
|
+
bufsize = 1024
|
90
|
+
local_path = local_dir + '/' + local_file
|
91
|
+
remote_path = remote_dir + '/' + remote_file
|
92
|
+
info = 'Upload' if upload else 'Download'
|
93
|
+
|
94
|
+
# 检查参数
|
95
|
+
if upload:
|
96
|
+
if local_file == '':
|
97
|
+
self.close('Argument Miss: local file')
|
98
|
+
# 如果没有设置 远程文件 名称, 则使用 本地文件 名称
|
99
|
+
if remote_file == '':
|
100
|
+
remote_file = local_file
|
101
|
+
remote_path = remote_dir + '/' + remote_file
|
102
|
+
else:
|
103
|
+
if remote_file == '':
|
104
|
+
self.close('Argument Miss: remote file')
|
105
|
+
# 如果没有设置 本地文件 名称, 则使用 远程文件 名称
|
106
|
+
if local_file == '':
|
107
|
+
local_file = remote_file
|
108
|
+
local_path = local_dir + '/' + local_file
|
109
|
+
|
110
|
+
# 进入本地目录
|
111
|
+
try:
|
112
|
+
if upload:
|
113
|
+
# 检查本地目录
|
114
|
+
stat = Path(local_dir)
|
115
|
+
self.close(f'Local directory error: {local_dir}') if stat.exists() == False else None
|
116
|
+
else:
|
117
|
+
# 创建本地目录
|
118
|
+
Path(local_dir).mkdir(parents=True, exist_ok=True)
|
119
|
+
# 进入本地目录
|
120
|
+
os.chdir(local_dir)
|
121
|
+
except:
|
122
|
+
# 第一层 try 使用 self.x_exit() 无效, 直接使用 self.close()
|
123
|
+
self.close(f'Local directory error: {local_dir}')
|
124
|
+
|
125
|
+
# 上传或下载
|
126
|
+
try:
|
127
|
+
|
128
|
+
if upload:
|
129
|
+
|
130
|
+
''' 上传 '''
|
131
|
+
|
132
|
+
# 创建远程目录
|
133
|
+
if remote_dir != '/':
|
134
|
+
self.mkdir(remote_dir)
|
135
|
+
|
136
|
+
# 进入远程目录
|
137
|
+
self.chdir_to_remote(remote_dir)
|
138
|
+
|
139
|
+
# 上传文件
|
140
|
+
stat = Path(local_file)
|
141
|
+
if stat.exists() and stat.is_file():
|
142
|
+
with open(local_file, 'rb') as fid:
|
143
|
+
self.ftp.storbinary(f'STOR {remote_file}', fid, bufsize)
|
144
|
+
print('{} success: {} -> {}'.format(info, local_path.replace('//', '/'), remote_path.replace('//', '/')))
|
145
|
+
return True
|
146
|
+
else:
|
147
|
+
self.x_exit('{} error: {} is not exist'.format(info, local_path.replace('//', '/')))
|
148
|
+
|
149
|
+
else:
|
150
|
+
|
151
|
+
''' 下载 '''
|
152
|
+
|
153
|
+
# 进入远程目录
|
154
|
+
self.chdir_to_remote(remote_dir)
|
155
|
+
|
156
|
+
# 下载文件
|
157
|
+
if remote_file in self.ftp.nlst():
|
158
|
+
with open(local_file, 'wb') as fid:
|
159
|
+
self.ftp.retrbinary(f'RETR {remote_file}', fid.write, bufsize)
|
160
|
+
print('{} success: {} -> {}'.format(info, remote_path.replace('//', '/'), local_path.replace('//', '/')))
|
161
|
+
return True
|
162
|
+
else:
|
163
|
+
self.x_exit('{} error: {} is not exist'.format(info, remote_path.replace('//', '/')))
|
164
|
+
|
165
|
+
except Exception as e:
|
166
|
+
# 第一层 try 使用 self.x_exit() 无效, 直接使用 self.close()
|
167
|
+
# self.close('{} faild! Please check {} or {}'.format(info, local_path, remote_path))
|
168
|
+
self.close(f'{info} error: {e}')
|
169
|
+
return False
|
170
|
+
|
171
|
+
def handle_all(self, local_dir='.', remote_dir='/', upload=False):
|
172
|
+
''' Handle All '''
|
173
|
+
if upload:
|
174
|
+
# 检查本地目录
|
175
|
+
stat = Path(local_dir)
|
176
|
+
self.close(f'Local directory error: {local_dir}') if stat.exists() == False else None
|
177
|
+
# 获取文件列表
|
178
|
+
local_files = [f for f in os.listdir(local_dir) if os.path.isfile(os.path.join(local_dir, f))]
|
179
|
+
for i in local_files:
|
180
|
+
self.x_exec(local_dir=local_dir, remote_dir=remote_dir, local_file=i, upload=True)
|
181
|
+
else:
|
182
|
+
remote_files = self.get_file_list(remote_dir)
|
183
|
+
for i in remote_files:
|
184
|
+
self.x_exec(local_dir=local_dir, remote_dir=remote_dir, remote_file=i)
|
185
|
+
|
186
|
+
def retrlines(self, remote_dir='/', cmd='LIST'):
|
187
|
+
''' Retrlines '''
|
188
|
+
try:
|
189
|
+
self.chdir_to_remote(remote_dir)
|
190
|
+
print(self.ftp.retrlines(cmd))
|
191
|
+
self.close()
|
192
|
+
except Exception as e:
|
193
|
+
# 第一层 try 使用 self.x_exit() 无效, 直接使用 self.close()
|
194
|
+
self.close(e)
|