|
@@ -0,0 +1,267 @@
|
|
|
+import base64
|
|
|
+import hashlib
|
|
|
+import json
|
|
|
+import os.path
|
|
|
+import re
|
|
|
+
|
|
|
+import requests
|
|
|
+
|
|
|
+from Crypto.Cipher import AES
|
|
|
+
|
|
|
+from tools.config import SERVER_POINT
|
|
|
+from tools.oss_client import oss_handle
|
|
|
+from tools.logger_handle import logger
|
|
|
+
|
|
|
+
|
|
|
+class ServerClient:
|
|
|
+ def __init__(self, server_host, user_name, password):
|
|
|
+ self.user_name = user_name
|
|
|
+ self.password = password
|
|
|
+ self.serve_host = server_host
|
|
|
+ self.access_token = None
|
|
|
+ self.headers = {
|
|
|
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36',
|
|
|
+ }
|
|
|
+ self.login()
|
|
|
+
|
|
|
+ def login(self):
|
|
|
+ url = self.serve_host + '/auth/oauth2/token'
|
|
|
+ reply = requests.post(url, params={
|
|
|
+ 'username': self.user_name,
|
|
|
+ 'password': self.encryption(self.password),
|
|
|
+ 'grant_type': 'password',
|
|
|
+ 'scope': 'server',
|
|
|
+ 'client_id': 'knowledge',
|
|
|
+ 'client_secret': 'knowledge'
|
|
|
+ }, headers={'Content-Type': 'multipart/form-data',
|
|
|
+ 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36'})
|
|
|
+
|
|
|
+ self.access_token = reply.json()['access_token']
|
|
|
+ self.headers['Authorization'] = f'Bearer {self.access_token}'
|
|
|
+
|
|
|
+ def decryption(self, hex_str, secret='anZz000000000000'):
|
|
|
+ key_bytes = secret.encode('utf-8')
|
|
|
+ iv = key_bytes
|
|
|
+ base64_str = base64.b64encode(bytes.fromhex(hex_str)).decode('utf-8')
|
|
|
+ cipher = AES.new(key_bytes, AES.MODE_CBC, iv)
|
|
|
+ decrypted = cipher.decrypt(base64.b64decode(base64_str))
|
|
|
+ try:
|
|
|
+ decoded = decrypted.decode('utf-8')
|
|
|
+ except UnicodeDecodeError:
|
|
|
+ decoded = decrypted.decode('utf-8', errors='ignore')
|
|
|
+ # 清除控制字符(类似 JS 中的 [\u0000-\u001F\u007F-\u009F])
|
|
|
+ cleaned = re.sub(r'[\x00-\x1F\x7F-\x9F]', ' ', decoded)
|
|
|
+ try:
|
|
|
+ return json.loads(cleaned)
|
|
|
+ except json.JSONDecodeError:
|
|
|
+ return cleaned.strip()
|
|
|
+
|
|
|
+ def zero_pad(self, data, block_size=16):
|
|
|
+ pad_len = block_size - (len(data) % block_size)
|
|
|
+ if pad_len == 0:
|
|
|
+ return data
|
|
|
+ return data + b'\x00' * pad_len
|
|
|
+
|
|
|
+ def encryption(self, payload, secret='a25vd2xlZGdl0000'.encode('utf-8')):
|
|
|
+ data_bytes = payload.encode('utf-8')
|
|
|
+ padded_data = self.zero_pad(data_bytes)
|
|
|
+ cipher = AES.new(secret, AES.MODE_CBC, secret)
|
|
|
+ encrypted = cipher.encrypt(padded_data)
|
|
|
+ return encrypted.hex()
|
|
|
+
|
|
|
+ def check_resp(self, resp):
|
|
|
+ if resp.json()['code'] == -2:
|
|
|
+ self.login()
|
|
|
+ return True
|
|
|
+ return False
|
|
|
+
|
|
|
+ def download_file(self, file_info, storage_path):
|
|
|
+
|
|
|
+ try:
|
|
|
+ resp = requests.get(f'{self.serve_host}/mgr/document/dcLibrary/file/get/file/{file_info["id"]}',
|
|
|
+ headers=self.headers)
|
|
|
+ local_file_name = file_info['filePath'].replace('/', '_')
|
|
|
+ with open(os.path.join(storage_path, local_file_name), 'wb') as f:
|
|
|
+ f.write(resp.content)
|
|
|
+
|
|
|
+ with open(os.path.join(storage_path, local_file_name + '.metadata'), 'w', encoding='utf-8') as f:
|
|
|
+ f.write(json.dumps({
|
|
|
+ 'serve': oss_handle.service,
|
|
|
+ 'access_key': oss_handle.access_key,
|
|
|
+ 'secret_key': oss_handle.secret_key,
|
|
|
+ 'file_id': file_info["id"],
|
|
|
+ 'bucket_name': file_info['bucketName'],
|
|
|
+ 'md5': self.get_file_md5(os.path.join(storage_path, local_file_name)),
|
|
|
+ 'file_name': file_info['name'],
|
|
|
+ 'oss_path': file_info['filePath'],
|
|
|
+ 'update_time': file_info['updateTime']
|
|
|
+ }))
|
|
|
+ except Exception as e:
|
|
|
+ logger.exception(e)
|
|
|
+ return False
|
|
|
+ return True
|
|
|
+
|
|
|
+ def upload_file(self, file_path):
|
|
|
+ try:
|
|
|
+ with open(f'{file_path}.metadata', 'r', encoding='utf-8') as f:
|
|
|
+ file_metadata = json.loads(f.read())
|
|
|
+ file_id = file_metadata['file_id']
|
|
|
+
|
|
|
+ files = [('file', (file_metadata['file_name'], open(file_path, 'rb'),
|
|
|
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'))]
|
|
|
+ resp = requests.post(
|
|
|
+ f'{self.serve_host}/mgr/document/dcLibrary/saveByPython/{file_id}',
|
|
|
+ headers=self.headers,
|
|
|
+ files=files,
|
|
|
+ data={}
|
|
|
+ )
|
|
|
+ if self.check_resp(resp):
|
|
|
+ resp = requests.post(
|
|
|
+ f'{self.serve_host}/mgr/document/dcLibrary/saveByPython/{file_id}',
|
|
|
+ headers=self.headers,
|
|
|
+ files=files,
|
|
|
+ data={})
|
|
|
+ if resp.json()['code'] == 0:
|
|
|
+ return True
|
|
|
+ else:
|
|
|
+ logger.error(resp.json())
|
|
|
+ return False
|
|
|
+ except Exception as e:
|
|
|
+ logger.exception(e)
|
|
|
+ return False
|
|
|
+
|
|
|
+ @staticmethod
|
|
|
+ def get_file_md5(file_path):
|
|
|
+ md5 = hashlib.md5()
|
|
|
+ with open(file_path, 'rb') as f:
|
|
|
+ # 分块读取以支持大文件
|
|
|
+ while chunk := f.read(8192):
|
|
|
+ md5.update(chunk)
|
|
|
+ return md5.hexdigest()
|
|
|
+
|
|
|
+ @staticmethod
|
|
|
+ def load_metadata(local_path):
|
|
|
+ with open(f'{local_path}.metadata', 'r', encoding='utf-8') as f:
|
|
|
+ file_metadata = json.loads(f.read())
|
|
|
+ return file_metadata
|
|
|
+
|
|
|
+ def get_file_info(self, file_id):
|
|
|
+ '''
|
|
|
+ {'createTime': '2025-06-03 15:57:37',
|
|
|
+ 'updateTime': '2025-06-16 11:17:52',
|
|
|
+ 'createById': '1',
|
|
|
+ 'createBy': '超级管理员',
|
|
|
+ 'updateBy': '超级管理员',
|
|
|
+ 'id': 'c5a8f3d5811e572265501eeaf6d8b1cf',
|
|
|
+ 'filePath': 'ten_1/lujie/document-mgr/SYG测试文库/test2.docx/2025/06/16/2025-06-161119224319835017216-c9b17214ea4144cf922f2fbfc0cdf70d.office_doc.docx',
|
|
|
+ 'bucketName': 'document-mgr',
|
|
|
+ 'name': 'test2.docx',
|
|
|
+ 'shareRole': 'user',
|
|
|
+ 'size': 26424,
|
|
|
+ 'parentId': '6b79a0c8359b89653b95a14ad08b4954',
|
|
|
+ 'type': 'office_doc',
|
|
|
+ 'orderId': 12, 'delFlag': False,
|
|
|
+ 'pathId': ['6b79a0c8359b89653b95a14ad08b4954'],
|
|
|
+ 'knowledgeId': '6b79a0c8359b89653b95a14ad08b4954',
|
|
|
+ 'tenantId': '1', 'commentable': True, '
|
|
|
+ readNotify': True, 'nameSuffix': 'docx',
|
|
|
+ 'fileStatus': 'NORMAL'}
|
|
|
+
|
|
|
+ :param file_id:
|
|
|
+ :return:
|
|
|
+ '''
|
|
|
+ try:
|
|
|
+ resp = requests.get(f'{self.serve_host}/mgr/document/no/auth/dcLibrary/info/{file_id}',
|
|
|
+ headers=self.headers)
|
|
|
+ if not self.check_resp(resp):
|
|
|
+ resp = requests.get(f'{self.serve_host}/mgr/document/no/auth/dcLibrary/info/{file_id}',
|
|
|
+ headers=self.headers)
|
|
|
+ if not resp.json()['data']:
|
|
|
+ return 2
|
|
|
+ return self.decryption(resp.json()['data'])
|
|
|
+ except Exception as e:
|
|
|
+ logger.exception(e)
|
|
|
+ return False
|
|
|
+
|
|
|
+
|
|
|
+if __name__ == '__main__':
|
|
|
+ client = ServerClient('http://172.10.3.71:10001','admin', '123456')
|
|
|
+ # client = ServerClient('admin', 'jxkj123456')
|
|
|
+ # client.download_file(
|
|
|
+ # {'file_name': 'test.docx', 'file_id': 'c5a8f3d5811e572265501eeaf6d8b1cf', 'bucket_name': 'aaa', }, '')
|
|
|
+ res = client.get_file_info(r'585ec718900fa82ce3d35d515c9d8a4b')
|
|
|
+ res = client.decryption(
|
|
|
+ "")
|
|
|
+
|
|
|
+ for row in res['data']:
|
|
|
+ print(row)
|
|
|
+ a = {'createTime': '2025-06-13 11:48:35', 'updateTime': '2025-06-13 14:01:48', 'createById': '1',
|
|
|
+ 'createBy': '超级管理员', 'updateBy': '超级管理员', 'id': 'c04b39ebfa8141746c20b88c7417f972',
|
|
|
+ 'filePath': 'ten_1/2_2/document-mgr/法律法规/新建文件.docx/2025/06/13/2025-06-131118178409944354816-e251bced912f4d68bc50d80a33cbbd5d.office_doc.docx',
|
|
|
+ 'bucketName': 'document-mgr', 'name': '新建文件.docx', 'shareRole': 'user', 'size': 29527,
|
|
|
+ 'parentId': 'a3d958a6bba28357757ca20c87af9954', 'type': 'office_doc', 'orderId': 24, 'delFlag': False,
|
|
|
+ 'pathId': ['a3d958a6bba28357757ca20c87af9954'], 'knowledgeId': 'a3d958a6bba28357757ca20c87af9954',
|
|
|
+ 'tenantId': '1', 'commentable': True, 'readNotify': True, 'nameSuffix': 'docx', 'fileStatus': 'NORMAL',
|
|
|
+ 'dcIdentifying': [
|
|
|
+ {'id': '1', 'identifyingName': '文档分享', 'name': '文档分享', 'identifyingKey': 'document_share',
|
|
|
+ 'identifyingType': 'document', 'isSelect': False, 'possessorIs': False},
|
|
|
+ {'id': '11', 'identifyingName': '文库删除', 'name': '文库删除', 'identifyingKey': 'library_delete',
|
|
|
+ 'identifyingType': 'library', 'isSelect': False, 'possessorIs': False},
|
|
|
+ {'id': '12', 'identifyingName': '文库编辑', 'name': '文库编辑', 'identifyingKey': 'library_update',
|
|
|
+ 'identifyingType': 'library', 'isSelect': False, 'possessorIs': False},
|
|
|
+ {'id': '13', 'identifyingName': '文库下载', 'name': '文库下载', 'identifyingKey': 'library_down',
|
|
|
+ 'identifyingType': 'library', 'isSelect': False, 'possessorIs': False},
|
|
|
+ {'id': '5', 'identifyingName': '文档删除', 'name': '文档删除', 'identifyingKey': 'document_delete',
|
|
|
+ 'identifyingType': 'document', 'isSelect': False, 'possessorIs': False},
|
|
|
+ {'id': '6', 'identifyingName': '新建文档', 'name': '新建文档', 'identifyingKey': 'document_add',
|
|
|
+ 'identifyingType': 'document', 'isSelect': False, 'possessorIs': False},
|
|
|
+ {'id': '7', 'identifyingName': '文档下载', 'name': '文档下载', 'identifyingKey': 'document_down',
|
|
|
+ 'identifyingType': 'document', 'isSelect': True, 'possessorIs': False},
|
|
|
+ {'id': '8', 'identifyingName': '文档编辑', 'name': '文档编辑', 'identifyingKey': 'document_update',
|
|
|
+ 'identifyingType': 'document', 'isSelect': False, 'possessorIs': False},
|
|
|
+ {'id': '9', 'identifyingName': '文档移动', 'name': '文档移动', 'identifyingKey': 'document_move',
|
|
|
+ 'identifyingType': 'document', 'isSelect': False, 'possessorIs': False},
|
|
|
+ {'id': '14', 'identifyingName': '文档消息设置', 'name': '文档消息设置',
|
|
|
+ 'identifyingKey': 'document_remind_settings', 'identifyingType': 'document', 'isSelect': False,
|
|
|
+ 'possessorIs': False}, {'id': '15', 'identifyingName': '文库权限设置', 'name': '文库权限设置',
|
|
|
+ 'identifyingKey': 'library_auth_settings', 'identifyingType': 'document',
|
|
|
+ 'isSelect': False, 'possessorIs': False},
|
|
|
+ {'id': '3', 'identifyingName': '文库消息设置', 'name': '文库消息设置',
|
|
|
+ 'identifyingKey': 'library_remind_settings', 'identifyingType': 'library', 'isSelect': False,
|
|
|
+ 'possessorIs': False}, {'id': '4', 'identifyingName': '文档权限设置', 'name': '文档权限设置',
|
|
|
+ 'identifyingKey': 'document_auth_settings', 'identifyingType': 'document',
|
|
|
+ 'isSelect': False, 'possessorIs': False},
|
|
|
+ {'id': '1', 'identifyingName': '文档分享', 'name': '', 'identifyingKey': 'document_share',
|
|
|
+ 'identifyingType': 'document', 'isSelect': True, 'possessorIs': False, 'select': True},
|
|
|
+ {'id': '10', 'identifyingName': '查看', 'name': '', 'identifyingKey': 'view',
|
|
|
+ 'identifyingType': 'document', 'isSelect': True, 'possessorIs': False, 'select': True},
|
|
|
+ {'id': '11', 'identifyingName': '文库删除', 'name': '', 'identifyingKey': 'library_delete',
|
|
|
+ 'identifyingType': 'library', 'isSelect': True, 'possessorIs': False, 'select': True},
|
|
|
+ {'id': '12', 'identifyingName': '文库编辑', 'name': '', 'identifyingKey': 'library_update',
|
|
|
+ 'identifyingType': 'library', 'isSelect': True, 'possessorIs': False, 'select': True},
|
|
|
+ {'id': '13', 'identifyingName': '文库下载', 'name': '', 'identifyingKey': 'library_down',
|
|
|
+ 'identifyingType': 'library', 'isSelect': True, 'possessorIs': False, 'select': True},
|
|
|
+ {'id': '14', 'identifyingName': '文档消息设置', 'name': '', 'identifyingKey': 'document_remind_settings',
|
|
|
+ 'identifyingType': 'document', 'isSelect': True, 'possessorIs': False, 'select': True},
|
|
|
+ {'id': '15', 'identifyingName': '文库权限设置', 'name': '', 'identifyingKey': 'library_auth_settings',
|
|
|
+ 'identifyingType': 'document', 'isSelect': True, 'possessorIs': False, 'select': True},
|
|
|
+ {'id': '2', 'identifyingName': '文库转移项目', 'name': '', 'identifyingKey': 'library_transfer',
|
|
|
+ 'identifyingType': 'library', 'isSelect': True, 'possessorIs': True, 'select': True},
|
|
|
+ {'id': '3', 'identifyingName': '文库消息设置', 'name': '', 'identifyingKey': 'library_remind_settings',
|
|
|
+ 'identifyingType': 'library', 'isSelect': True, 'possessorIs': False, 'select': True},
|
|
|
+ {'id': '4', 'identifyingName': '文档权限设置', 'name': '', 'identifyingKey': 'document_auth_settings',
|
|
|
+ 'identifyingType': 'document', 'isSelect': True, 'possessorIs': False, 'select': True},
|
|
|
+ {'id': '5', 'identifyingName': '文档删除', 'name': '', 'identifyingKey': 'document_delete',
|
|
|
+ 'identifyingType': 'document', 'isSelect': True, 'possessorIs': False, 'select': True},
|
|
|
+ {'id': '6', 'identifyingName': '新建文档', 'name': '', 'identifyingKey': 'document_add',
|
|
|
+ 'identifyingType': 'document', 'isSelect': True, 'possessorIs': False, 'select': True},
|
|
|
+ {'id': '7', 'identifyingName': '文档下载', 'name': '', 'identifyingKey': 'document_down',
|
|
|
+ 'identifyingType': 'document', 'isSelect': True, 'possessorIs': False, 'select': True},
|
|
|
+ {'id': '8', 'identifyingName': '文档编辑', 'name': '', 'identifyingKey': 'document_update',
|
|
|
+ 'identifyingType': 'document', 'isSelect': True, 'possessorIs': False, 'select': True},
|
|
|
+ {'id': '9', 'identifyingName': '文档移动', 'name': '', 'identifyingKey': 'document_move',
|
|
|
+ 'identifyingType': 'document', 'isSelect': True, 'possessorIs': False, 'select': True}], 'share': False}
|
|
|
+
|
|
|
+ # access_token = client.login()
|
|
|
+ # print(requests.post('http://120.195.49.22:7215/mgr/document/dcLibrary/knowledges?size=1000¤t=1', headers={
|
|
|
+ # 'authorization': f'Bearer {access_token}'}).json())
|