1 Commits

Author SHA1 Message Date
guojiabao
84b8382a31 new joyhub_backend 2026-05-18 15:20:48 +08:00
21717 changed files with 210623 additions and 2234135 deletions

208181
HubOps.md Normal file

File diff suppressed because one or more lines are too long

View File

@@ -3486,239 +3486,3 @@ LINE 1: UPDATE system_users SET fingerprint = '' WHERE username = 'j...
2026-05-06 10:01:02,073 [tid:14556 pid:31208] runner.py[line:202] INFO ------状态码200 返回信息:{'code': 401, 'msg': '账号未登录', 'data': None} 2026-05-06 10:01:02,073 [tid:14556 pid:31208] runner.py[line:202] INFO ------状态码200 返回信息:{'code': 401, 'msg': '账号未登录', 'data': None}
2026-05-06 10:01:02,075 [tid:14556 pid:31208] runner.py[line:221] WARNING 缓存session过期清理缓存 2026-05-06 10:01:02,075 [tid:14556 pid:31208] runner.py[line:221] WARNING 缓存session过期清理缓存
2026-05-06 10:01:02,076 [tid:14556 pid:31208] runner.py[line:235] INFO 返回数据:{'code': 401, 'msg': '账号未登录', 'data': None} 2026-05-06 10:01:02,076 [tid:14556 pid:31208] runner.py[line:235] INFO 返回数据:{'code': 401, 'msg': '账号未登录', 'data': None}
2026-05-06 16:32:24,371 [tid:9812 pid:10540] UserManage.py[line:44] INFO 尝试读取配置文件: d:\zhyy\smart-management-auto-test\dulizhan\library\BusinessKw\JoyHub\../../../../test_case/Resource/AdapterKws/hh-qa.robot
2026-05-06 16:32:24,372 [tid:9812 pid:10540] UserManage.py[line:57] ERROR 读取robot配置文件失败: [Errno 2] No such file or directory: 'd:\\zhyy\\smart-management-auto-test\\dulizhan\\library\\BusinessKw\\JoyHub\\../../../../test_case/Resource/AdapterKws/hh-qa.robot'
2026-05-06 16:32:24,372 [tid:9812 pid:10540] UserManage.py[line:37] WARNING 未从配置文件读取到JoyHub Token
2026-05-06 16:32:24,510 [tid:9812 pid:10540] RoleManage.py[line:41] INFO 尝试读取配置文件: C:\Users\a\PyCharmMiscProject\smart-management-auto-test\dulizhan\test_case\Resource\AdapterKws\hh-qa.robot
2026-05-06 16:32:24,512 [tid:9812 pid:10540] RoleManage.py[line:53] ERROR 读取robot配置文件失败: [Errno 2] No such file or directory: 'C:\\Users\\a\\PyCharmMiscProject\\smart-management-auto-test\\dulizhan\\test_case\\Resource\\AdapterKws\\hh-qa.robot'
2026-05-06 16:32:24,513 [tid:9812 pid:10540] RoleManage.py[line:36] WARNING 未从配置文件读取到JoyHub Token
2026-05-06 16:32:25,019 [tid:9812 pid:10540] Dlizhan_interface.py[line:71] INFO 清除用户 joytest 的指纹锁,影响行数: 1
2026-05-06 16:32:25,389 [tid:9812 pid:10540] AgreementManage.py[line:116] INFO 获得协议分页列表 - 参数: {'page_no': 1, 'page_size': 10, 'type': '', 'title': '', 'content': '', 'status': ''}
2026-05-06 16:32:25,390 [tid:9812 pid:10540] Dlizhan_interface.py[line:45] INFO =========== 获得协议分页 ===========
2026-05-06 16:32:25,636 [tid:9812 pid:10540] AgreementManage.py[line:35] INFO 创建协议 - type: 1, title: 测试协议_1778056345, content: 这是测试协议内容_1778056345..., terminal: web, lang: de, rank_num: 345, status: 2
2026-05-06 16:32:25,637 [tid:9812 pid:10540] Dlizhan_interface.py[line:45] INFO =========== 创建协议 ===========
2026-05-06 16:32:25,815 [tid:9812 pid:10540] AgreementManage.py[line:35] INFO 创建协议 - type: 2, title: 详情测试协议_1778056345, content: 详情测试协议内容_1778056345..., terminal: app, lang: ja, rank_num: 1345, status: 1
2026-05-06 16:32:25,817 [tid:9812 pid:10540] Dlizhan_interface.py[line:45] INFO =========== 创建协议 ===========
2026-05-06 16:32:26,045 [tid:9812 pid:10540] AgreementManage.py[line:35] INFO 创建协议 - type: 1, title: 待更新协议_1778056346, content: 待更新协议内容_1778056346..., terminal: app, lang: de, rank_num: 2346, status: 1
2026-05-06 16:32:26,046 [tid:9812 pid:10540] Dlizhan_interface.py[line:45] INFO =========== 创建协议 ===========
2026-05-06 16:32:26,226 [tid:9812 pid:10540] AgreementManage.py[line:35] INFO 创建协议 - type: 1, title: 待删除协议_1778056346, content: 待删除协议内容_1778056346..., terminal: web, lang: ja, rank_num: 4346, status: 2
2026-05-06 16:32:26,227 [tid:9812 pid:10540] Dlizhan_interface.py[line:45] INFO =========== 创建协议 ===========
2026-05-06 16:32:26,413 [tid:9812 pid:10540] AgreementManage.py[line:35] INFO 创建协议 - type: 2, title: 批量删除协议1_1778056346, content: 批量删除协议内容1_1778056346..., terminal: app, lang: de, rank_num: 5346, status: 2
2026-05-06 16:32:26,414 [tid:9812 pid:10540] Dlizhan_interface.py[line:45] INFO =========== 创建协议 ===========
2026-05-06 16:32:26,634 [tid:9812 pid:10540] AgreementManage.py[line:88] INFO 导出协议Excel - 参数: {'type': '', 'title': '', 'content': '', 'status': ''}
2026-05-06 16:32:26,635 [tid:9812 pid:10540] Dlizhan_interface.py[line:45] INFO =========== 导出协议 Excel ===========
2026-05-06 16:32:26,929 [tid:9812 pid:10540] Dlizhan_interface.py[line:71] INFO 清除用户 joytest 的指纹锁,影响行数: 1
2026-05-06 16:32:27,017 [tid:9812 pid:10540] Dlizhan_interface.py[line:45] INFO =========== 获得app版本号管理分页 ===========
2026-05-06 16:32:27,251 [tid:9812 pid:10540] Dlizhan_interface.py[line:45] INFO =========== 创建app版本号管理 ===========
2026-05-06 16:32:27,433 [tid:9812 pid:10540] Dlizhan_interface.py[line:45] INFO =========== 创建app版本号管理 ===========
2026-05-06 16:32:27,652 [tid:9812 pid:10540] Dlizhan_interface.py[line:45] INFO =========== 创建app版本号管理 ===========
2026-05-06 16:32:27,852 [tid:9812 pid:10540] Dlizhan_interface.py[line:45] INFO =========== 创建app版本号管理 ===========
2026-05-06 16:32:28,031 [tid:9812 pid:10540] Dlizhan_interface.py[line:45] INFO =========== 创建app版本号管理 ===========
2026-05-06 16:32:28,238 [tid:9812 pid:10540] Dlizhan_interface.py[line:45] INFO =========== 获得导入app版本号管理模板 ===========
2026-05-06 16:32:28,453 [tid:9812 pid:10540] Dlizhan_interface.py[line:45] INFO =========== 导出app版本号管理 Excel ===========
2026-05-06 16:32:28,796 [tid:9812 pid:10540] Dlizhan_interface.py[line:71] INFO 清除用户 joytest 的指纹锁,影响行数: 1
2026-05-06 16:32:28,927 [tid:9812 pid:10540] Dlizhan_interface.py[line:45] INFO =========== 获得Banner管理分页 ===========
2026-05-06 16:32:29,122 [tid:9812 pid:10540] Dlizhan_interface.py[line:45] INFO =========== 创建Banner管理 ===========
2026-05-06 16:32:29,327 [tid:9812 pid:10540] Dlizhan_interface.py[line:45] INFO =========== 创建Banner管理 ===========
2026-05-06 16:32:29,497 [tid:9812 pid:10540] Dlizhan_interface.py[line:45] INFO =========== 创建Banner管理 ===========
2026-05-06 16:32:29,667 [tid:9812 pid:10540] Dlizhan_interface.py[line:45] INFO =========== 创建Banner管理 ===========
2026-05-06 16:32:29,887 [tid:9812 pid:10540] Dlizhan_interface.py[line:45] INFO =========== 创建Banner管理 ===========
2026-05-06 16:32:30,207 [tid:9812 pid:10540] Dlizhan_interface.py[line:71] INFO 清除用户 joytest 的指纹锁,影响行数: 1
2026-05-06 16:32:30,433 [tid:9812 pid:10540] Dlizhan_interface.py[line:71] INFO 清除用户 joytest 的指纹锁,影响行数: 1
2026-05-06 16:32:30,629 [tid:9812 pid:10540] Dlizhan_interface.py[line:45] INFO =========== 获得角色分页 ===========
2026-05-06 16:32:30,890 [tid:9812 pid:10540] Dlizhan_interface.py[line:45] INFO =========== 创建角色 ===========
2026-05-06 16:32:31,116 [tid:9812 pid:10540] Dlizhan_interface.py[line:45] INFO =========== 创建角色 ===========
2026-05-06 16:32:31,335 [tid:9812 pid:10540] Dlizhan_interface.py[line:45] INFO =========== 创建角色 ===========
2026-05-06 16:32:31,542 [tid:9812 pid:10540] Dlizhan_interface.py[line:45] INFO =========== 创建角色 ===========
2026-05-06 16:32:31,798 [tid:9812 pid:10540] Dlizhan_interface.py[line:45] INFO =========== 创建角色 ===========
2026-05-06 16:32:31,990 [tid:9812 pid:10540] Dlizhan_interface.py[line:45] INFO =========== 获取角色精简信息列表 ===========
2026-05-06 16:32:32,263 [tid:9812 pid:10540] Dlizhan_interface.py[line:45] INFO =========== 获取角色精简信息列表 ===========
2026-05-06 16:32:32,573 [tid:9812 pid:10540] Dlizhan_interface.py[line:71] INFO 清除用户 joytest 的指纹锁,影响行数: 1
2026-05-06 16:32:32,780 [tid:9812 pid:10540] Dlizhan_interface.py[line:71] INFO 清除用户 joytest 的指纹锁,影响行数: 1
2026-05-06 16:32:33,139 [tid:9812 pid:10540] Dlizhan_interface.py[line:45] INFO =========== 获得用户分页列表 ===========
2026-05-06 16:32:33,390 [tid:9812 pid:10540] Dlizhan_interface.py[line:45] INFO =========== 获取用户精简信息列表 ===========
2026-05-06 16:32:33,583 [tid:9812 pid:10540] Dlizhan_interface.py[line:45] INFO =========== 创建用户 ===========
2026-05-06 16:32:33,810 [tid:9812 pid:10540] Dlizhan_interface.py[line:45] INFO =========== 创建用户 ===========
2026-05-06 16:32:34,012 [tid:9812 pid:10540] Dlizhan_interface.py[line:45] INFO =========== 创建用户 ===========
2026-05-06 16:32:34,246 [tid:9812 pid:10540] Dlizhan_interface.py[line:45] INFO =========== 创建用户 ===========
2026-05-06 16:32:34,435 [tid:9812 pid:10540] Dlizhan_interface.py[line:45] INFO =========== 创建用户 ===========
2026-05-06 16:32:34,673 [tid:9812 pid:10540] Dlizhan_interface.py[line:45] INFO =========== 创建用户 ===========
2026-05-06 16:32:34,848 [tid:9812 pid:10540] Dlizhan_interface.py[line:45] INFO =========== 创建用户 ===========
2026-05-06 16:32:35,191 [tid:9812 pid:10540] Dlizhan_interface.py[line:71] INFO 清除用户 joytest 的指纹锁,影响行数: 1
2026-05-06 16:37:18,921 [tid:3648 pid:26928] UserManage.py[line:44] INFO 尝试读取配置文件: d:\zhyy\smart-management-auto-test\dulizhan\library\BusinessKw\JoyHub\../../../../test_case/Resource/AdapterKws/hh-qa.robot
2026-05-06 16:37:18,971 [tid:3648 pid:26928] UserManage.py[line:57] ERROR 读取robot配置文件失败: [Errno 2] No such file or directory: 'd:\\zhyy\\smart-management-auto-test\\dulizhan\\library\\BusinessKw\\JoyHub\\../../../../test_case/Resource/AdapterKws/hh-qa.robot'
2026-05-06 16:37:18,972 [tid:3648 pid:26928] UserManage.py[line:37] WARNING 未从配置文件读取到JoyHub Token
2026-05-06 16:37:19,058 [tid:3648 pid:26928] RoleManage.py[line:41] INFO 尝试读取配置文件: C:\Users\a\PyCharmMiscProject\smart-management-auto-test\dulizhan\test_case\Resource\AdapterKws\hh-qa.robot
2026-05-06 16:37:19,059 [tid:3648 pid:26928] RoleManage.py[line:53] ERROR 读取robot配置文件失败: [Errno 2] No such file or directory: 'C:\\Users\\a\\PyCharmMiscProject\\smart-management-auto-test\\dulizhan\\test_case\\Resource\\AdapterKws\\hh-qa.robot'
2026-05-06 16:37:19,060 [tid:3648 pid:26928] RoleManage.py[line:36] WARNING 未从配置文件读取到JoyHub Token
2026-05-06 16:37:19,570 [tid:3648 pid:26928] Dlizhan_interface.py[line:71] INFO 清除用户 joytest 的指纹锁,影响行数: 1
2026-05-06 16:37:19,899 [tid:3648 pid:26928] AgreementManage.py[line:116] INFO 获得协议分页列表 - 参数: {'page_no': 1, 'page_size': 10, 'type': '', 'title': '', 'content': '', 'status': ''}
2026-05-06 16:37:19,900 [tid:3648 pid:26928] Dlizhan_interface.py[line:45] INFO =========== 获得协议分页 ===========
2026-05-06 16:37:20,091 [tid:3648 pid:26928] AgreementManage.py[line:35] INFO 创建协议 - type: 1, title: 测试协议_1778056640, content: 这是测试协议内容_1778056640..., terminal: web, lang: de, rank_num: 640, status: 2
2026-05-06 16:37:20,092 [tid:3648 pid:26928] Dlizhan_interface.py[line:45] INFO =========== 创建协议 ===========
2026-05-06 16:37:20,300 [tid:3648 pid:26928] AgreementManage.py[line:35] INFO 创建协议 - type: 2, title: 详情测试协议_1778056640, content: 详情测试协议内容_1778056640..., terminal: app, lang: ja, rank_num: 1640, status: 1
2026-05-06 16:37:20,301 [tid:3648 pid:26928] Dlizhan_interface.py[line:45] INFO =========== 创建协议 ===========
2026-05-06 16:37:20,473 [tid:3648 pid:26928] AgreementManage.py[line:35] INFO 创建协议 - type: 1, title: 待更新协议_1778056640, content: 待更新协议内容_1778056640..., terminal: app, lang: de, rank_num: 2640, status: 1
2026-05-06 16:37:20,475 [tid:3648 pid:26928] Dlizhan_interface.py[line:45] INFO =========== 创建协议 ===========
2026-05-06 16:37:20,716 [tid:3648 pid:26928] AgreementManage.py[line:35] INFO 创建协议 - type: 1, title: 待删除协议_1778056640, content: 待删除协议内容_1778056640..., terminal: web, lang: ja, rank_num: 4640, status: 2
2026-05-06 16:37:20,717 [tid:3648 pid:26928] Dlizhan_interface.py[line:45] INFO =========== 创建协议 ===========
2026-05-06 16:37:20,915 [tid:3648 pid:26928] AgreementManage.py[line:35] INFO 创建协议 - type: 2, title: 批量删除协议1_1778056640, content: 批量删除协议内容1_1778056640..., terminal: app, lang: de, rank_num: 5640, status: 2
2026-05-06 16:37:20,916 [tid:3648 pid:26928] Dlizhan_interface.py[line:45] INFO =========== 创建协议 ===========
2026-05-06 16:37:21,131 [tid:3648 pid:26928] AgreementManage.py[line:88] INFO 导出协议Excel - 参数: {'type': '', 'title': '', 'content': '', 'status': ''}
2026-05-06 16:37:21,132 [tid:3648 pid:26928] Dlizhan_interface.py[line:45] INFO =========== 导出协议 Excel ===========
2026-05-06 16:37:21,431 [tid:3648 pid:26928] Dlizhan_interface.py[line:71] INFO 清除用户 joytest 的指纹锁,影响行数: 1
2026-05-06 16:37:21,516 [tid:3648 pid:26928] Dlizhan_interface.py[line:45] INFO =========== 获得app版本号管理分页 ===========
2026-05-06 16:37:21,683 [tid:3648 pid:26928] Dlizhan_interface.py[line:45] INFO =========== 创建app版本号管理 ===========
2026-05-06 16:37:21,877 [tid:3648 pid:26928] Dlizhan_interface.py[line:45] INFO =========== 创建app版本号管理 ===========
2026-05-06 16:37:22,052 [tid:3648 pid:26928] Dlizhan_interface.py[line:45] INFO =========== 创建app版本号管理 ===========
2026-05-06 16:37:22,284 [tid:3648 pid:26928] Dlizhan_interface.py[line:45] INFO =========== 创建app版本号管理 ===========
2026-05-06 16:37:22,451 [tid:3648 pid:26928] Dlizhan_interface.py[line:45] INFO =========== 创建app版本号管理 ===========
2026-05-06 16:37:22,667 [tid:3648 pid:26928] Dlizhan_interface.py[line:45] INFO =========== 获得导入app版本号管理模板 ===========
2026-05-06 16:37:22,873 [tid:3648 pid:26928] Dlizhan_interface.py[line:45] INFO =========== 导出app版本号管理 Excel ===========
2026-05-06 16:37:23,178 [tid:3648 pid:26928] Dlizhan_interface.py[line:71] INFO 清除用户 joytest 的指纹锁,影响行数: 1
2026-05-06 16:37:23,321 [tid:3648 pid:26928] Dlizhan_interface.py[line:45] INFO =========== 获得Banner管理分页 ===========
2026-05-06 16:37:23,489 [tid:3648 pid:26928] Dlizhan_interface.py[line:45] INFO =========== 创建Banner管理 ===========
2026-05-06 16:37:23,651 [tid:3648 pid:26928] Dlizhan_interface.py[line:45] INFO =========== 创建Banner管理 ===========
2026-05-06 16:37:23,923 [tid:3648 pid:26928] Dlizhan_interface.py[line:45] INFO =========== 创建Banner管理 ===========
2026-05-06 16:37:24,106 [tid:3648 pid:26928] Dlizhan_interface.py[line:45] INFO =========== 创建Banner管理 ===========
2026-05-06 16:37:24,302 [tid:3648 pid:26928] Dlizhan_interface.py[line:45] INFO =========== 创建Banner管理 ===========
2026-05-06 16:37:24,599 [tid:3648 pid:26928] Dlizhan_interface.py[line:71] INFO 清除用户 joytest 的指纹锁,影响行数: 1
2026-05-06 16:37:24,818 [tid:3648 pid:26928] Dlizhan_interface.py[line:71] INFO 清除用户 joytest 的指纹锁,影响行数: 1
2026-05-06 16:37:24,995 [tid:3648 pid:26928] Dlizhan_interface.py[line:45] INFO =========== 获得角色分页 ===========
2026-05-06 16:37:25,198 [tid:3648 pid:26928] Dlizhan_interface.py[line:45] INFO =========== 创建角色 ===========
2026-05-06 16:37:25,415 [tid:3648 pid:26928] Dlizhan_interface.py[line:45] INFO =========== 创建角色 ===========
2026-05-06 16:37:25,623 [tid:3648 pid:26928] Dlizhan_interface.py[line:45] INFO =========== 创建角色 ===========
2026-05-06 16:37:25,803 [tid:3648 pid:26928] Dlizhan_interface.py[line:45] INFO =========== 创建角色 ===========
2026-05-06 16:37:25,987 [tid:3648 pid:26928] Dlizhan_interface.py[line:45] INFO =========== 创建角色 ===========
2026-05-06 16:37:26,204 [tid:3648 pid:26928] Dlizhan_interface.py[line:45] INFO =========== 获取角色精简信息列表 ===========
2026-05-06 16:37:26,380 [tid:3648 pid:26928] Dlizhan_interface.py[line:45] INFO =========== 获取角色精简信息列表 ===========
2026-05-06 16:37:26,721 [tid:3648 pid:26928] Dlizhan_interface.py[line:71] INFO 清除用户 joytest 的指纹锁,影响行数: 1
2026-05-06 16:37:26,937 [tid:3648 pid:26928] Dlizhan_interface.py[line:71] INFO 清除用户 joytest 的指纹锁,影响行数: 1
2026-05-06 16:37:27,183 [tid:3648 pid:26928] Dlizhan_interface.py[line:45] INFO =========== 获得用户分页列表 ===========
2026-05-06 16:37:27,397 [tid:3648 pid:26928] Dlizhan_interface.py[line:45] INFO =========== 获取用户精简信息列表 ===========
2026-05-06 16:37:27,571 [tid:3648 pid:26928] Dlizhan_interface.py[line:45] INFO =========== 创建用户 ===========
2026-05-06 16:37:27,799 [tid:3648 pid:26928] Dlizhan_interface.py[line:45] INFO =========== 创建用户 ===========
2026-05-06 16:37:28,006 [tid:3648 pid:26928] Dlizhan_interface.py[line:45] INFO =========== 创建用户 ===========
2026-05-06 16:37:28,247 [tid:3648 pid:26928] Dlizhan_interface.py[line:45] INFO =========== 创建用户 ===========
2026-05-06 16:37:28,510 [tid:3648 pid:26928] Dlizhan_interface.py[line:45] INFO =========== 创建用户 ===========
2026-05-06 16:37:28,788 [tid:3648 pid:26928] Dlizhan_interface.py[line:45] INFO =========== 创建用户 ===========
2026-05-06 16:37:29,004 [tid:3648 pid:26928] Dlizhan_interface.py[line:45] INFO =========== 创建用户 ===========
2026-05-06 16:37:29,298 [tid:3648 pid:26928] Dlizhan_interface.py[line:71] INFO 清除用户 joytest 的指纹锁,影响行数: 1
2026-05-06 16:44:25,759 [tid:9412 pid:1312] UserManage.py[line:44] INFO 尝试读取配置文件: D:\zhyy\smart-management-auto-test\dulizhan\library\BusinessKw\JoyHub\../../../../test_case/Resource/AdapterKws/hh-qa.robot
2026-05-06 16:44:25,759 [tid:9412 pid:1312] UserManage.py[line:57] ERROR 读取robot配置文件失败: [Errno 2] No such file or directory: 'D:\\zhyy\\smart-management-auto-test\\dulizhan\\library\\BusinessKw\\JoyHub\\../../../../test_case/Resource/AdapterKws/hh-qa.robot'
2026-05-06 16:44:25,762 [tid:9412 pid:1312] UserManage.py[line:37] WARNING 未从配置文件读取到JoyHub Token
2026-05-06 16:44:25,853 [tid:9412 pid:1312] RoleManage.py[line:41] INFO 尝试读取配置文件: C:\Users\a\PyCharmMiscProject\smart-management-auto-test\dulizhan\test_case\Resource\AdapterKws\hh-qa.robot
2026-05-06 16:44:25,854 [tid:9412 pid:1312] RoleManage.py[line:53] ERROR 读取robot配置文件失败: [Errno 2] No such file or directory: 'C:\\Users\\a\\PyCharmMiscProject\\smart-management-auto-test\\dulizhan\\test_case\\Resource\\AdapterKws\\hh-qa.robot'
2026-05-06 16:44:25,855 [tid:9412 pid:1312] RoleManage.py[line:36] WARNING 未从配置文件读取到JoyHub Token
2026-05-06 16:44:26,358 [tid:9412 pid:1312] Dlizhan_interface.py[line:71] INFO 清除用户 joytest 的指纹锁,影响行数: 1
2026-05-06 16:44:26,707 [tid:9412 pid:1312] AgreementManage.py[line:116] INFO 获得协议分页列表 - 参数: {'page_no': 1, 'page_size': 10, 'type': '', 'title': '', 'content': '', 'status': ''}
2026-05-06 16:44:26,708 [tid:9412 pid:1312] Dlizhan_interface.py[line:45] INFO =========== 获得协议分页 ===========
2026-05-06 16:44:26,903 [tid:9412 pid:1312] AgreementManage.py[line:35] INFO 创建协议 - type: 1, title: 测试协议_1778057066, content: 这是测试协议内容_1778057066..., terminal: web, lang: de, rank_num: 66, status: 2
2026-05-06 16:44:26,904 [tid:9412 pid:1312] Dlizhan_interface.py[line:45] INFO =========== 创建协议 ===========
2026-05-06 16:44:27,111 [tid:9412 pid:1312] AgreementManage.py[line:35] INFO 创建协议 - type: 2, title: 详情测试协议_1778057067, content: 详情测试协议内容_1778057067..., terminal: app, lang: ja, rank_num: 1067, status: 1
2026-05-06 16:44:27,112 [tid:9412 pid:1312] Dlizhan_interface.py[line:45] INFO =========== 创建协议 ===========
2026-05-06 16:44:27,290 [tid:9412 pid:1312] AgreementManage.py[line:35] INFO 创建协议 - type: 1, title: 待更新协议_1778057067, content: 待更新协议内容_1778057067..., terminal: app, lang: de, rank_num: 2067, status: 1
2026-05-06 16:44:27,291 [tid:9412 pid:1312] Dlizhan_interface.py[line:45] INFO =========== 创建协议 ===========
2026-05-06 16:44:27,516 [tid:9412 pid:1312] AgreementManage.py[line:35] INFO 创建协议 - type: 1, title: 待删除协议_1778057067, content: 待删除协议内容_1778057067..., terminal: web, lang: ja, rank_num: 4067, status: 2
2026-05-06 16:44:27,518 [tid:9412 pid:1312] Dlizhan_interface.py[line:45] INFO =========== 创建协议 ===========
2026-05-06 16:44:27,692 [tid:9412 pid:1312] AgreementManage.py[line:35] INFO 创建协议 - type: 2, title: 批量删除协议1_1778057067, content: 批量删除协议内容1_1778057067..., terminal: app, lang: de, rank_num: 5067, status: 2
2026-05-06 16:44:27,692 [tid:9412 pid:1312] Dlizhan_interface.py[line:45] INFO =========== 创建协议 ===========
2026-05-06 16:44:27,894 [tid:9412 pid:1312] AgreementManage.py[line:88] INFO 导出协议Excel - 参数: {'type': '', 'title': '', 'content': '', 'status': ''}
2026-05-06 16:44:27,894 [tid:9412 pid:1312] Dlizhan_interface.py[line:45] INFO =========== 导出协议 Excel ===========
2026-05-06 16:44:28,193 [tid:9412 pid:1312] Dlizhan_interface.py[line:71] INFO 清除用户 joytest 的指纹锁,影响行数: 1
2026-05-06 16:44:28,296 [tid:9412 pid:1312] Dlizhan_interface.py[line:45] INFO =========== 获得app版本号管理分页 ===========
2026-05-06 16:44:28,462 [tid:9412 pid:1312] Dlizhan_interface.py[line:45] INFO =========== 创建app版本号管理 ===========
2026-05-06 16:44:28,694 [tid:9412 pid:1312] Dlizhan_interface.py[line:45] INFO =========== 创建app版本号管理 ===========
2026-05-06 16:44:28,866 [tid:9412 pid:1312] Dlizhan_interface.py[line:45] INFO =========== 创建app版本号管理 ===========
2026-05-06 16:44:29,075 [tid:9412 pid:1312] Dlizhan_interface.py[line:45] INFO =========== 创建app版本号管理 ===========
2026-05-06 16:44:29,246 [tid:9412 pid:1312] Dlizhan_interface.py[line:45] INFO =========== 创建app版本号管理 ===========
2026-05-06 16:44:29,464 [tid:9412 pid:1312] Dlizhan_interface.py[line:45] INFO =========== 获得导入app版本号管理模板 ===========
2026-05-06 16:44:29,657 [tid:9412 pid:1312] Dlizhan_interface.py[line:45] INFO =========== 导出app版本号管理 Excel ===========
2026-05-06 16:44:29,974 [tid:9412 pid:1312] Dlizhan_interface.py[line:71] INFO 清除用户 joytest 的指纹锁,影响行数: 1
2026-05-06 16:44:30,056 [tid:9412 pid:1312] Dlizhan_interface.py[line:45] INFO =========== 获得Banner管理分页 ===========
2026-05-06 16:44:30,228 [tid:9412 pid:1312] Dlizhan_interface.py[line:45] INFO =========== 创建Banner管理 ===========
2026-05-06 16:44:30,437 [tid:9412 pid:1312] Dlizhan_interface.py[line:45] INFO =========== 创建Banner管理 ===========
2026-05-06 16:44:30,652 [tid:9412 pid:1312] Dlizhan_interface.py[line:45] INFO =========== 创建Banner管理 ===========
2026-05-06 16:44:30,835 [tid:9412 pid:1312] Dlizhan_interface.py[line:45] INFO =========== 创建Banner管理 ===========
2026-05-06 16:44:31,052 [tid:9412 pid:1312] Dlizhan_interface.py[line:45] INFO =========== 创建Banner管理 ===========
2026-05-06 16:44:31,365 [tid:9412 pid:1312] Dlizhan_interface.py[line:71] INFO 清除用户 joytest 的指纹锁,影响行数: 1
2026-05-06 16:44:31,601 [tid:9412 pid:1312] Dlizhan_interface.py[line:71] INFO 清除用户 joytest 的指纹锁,影响行数: 1
2026-05-06 16:44:31,823 [tid:9412 pid:1312] Dlizhan_interface.py[line:45] INFO =========== 获得角色分页 ===========
2026-05-06 16:44:32,025 [tid:9412 pid:1312] Dlizhan_interface.py[line:45] INFO =========== 创建角色 ===========
2026-05-06 16:44:32,195 [tid:9412 pid:1312] Dlizhan_interface.py[line:45] INFO =========== 创建角色 ===========
2026-05-06 16:44:32,409 [tid:9412 pid:1312] Dlizhan_interface.py[line:45] INFO =========== 创建角色 ===========
2026-05-06 16:44:32,581 [tid:9412 pid:1312] Dlizhan_interface.py[line:45] INFO =========== 创建角色 ===========
2026-05-06 16:44:32,753 [tid:9412 pid:1312] Dlizhan_interface.py[line:45] INFO =========== 创建角色 ===========
2026-05-06 16:44:32,996 [tid:9412 pid:1312] Dlizhan_interface.py[line:45] INFO =========== 获取角色精简信息列表 ===========
2026-05-06 16:44:33,186 [tid:9412 pid:1312] Dlizhan_interface.py[line:45] INFO =========== 获取角色精简信息列表 ===========
2026-05-06 16:44:33,578 [tid:9412 pid:1312] Dlizhan_interface.py[line:71] INFO 清除用户 joytest 的指纹锁,影响行数: 1
2026-05-06 16:44:33,809 [tid:9412 pid:1312] Dlizhan_interface.py[line:71] INFO 清除用户 joytest 的指纹锁,影响行数: 1
2026-05-06 16:44:34,103 [tid:9412 pid:1312] Dlizhan_interface.py[line:45] INFO =========== 获得用户分页列表 ===========
2026-05-06 16:44:34,330 [tid:9412 pid:1312] Dlizhan_interface.py[line:45] INFO =========== 获取用户精简信息列表 ===========
2026-05-06 16:44:34,511 [tid:9412 pid:1312] Dlizhan_interface.py[line:45] INFO =========== 创建用户 ===========
2026-05-06 16:44:34,763 [tid:9412 pid:1312] Dlizhan_interface.py[line:45] INFO =========== 创建用户 ===========
2026-05-06 16:44:34,980 [tid:9412 pid:1312] Dlizhan_interface.py[line:45] INFO =========== 创建用户 ===========
2026-05-06 16:44:35,261 [tid:9412 pid:1312] Dlizhan_interface.py[line:45] INFO =========== 创建用户 ===========
2026-05-06 16:44:35,504 [tid:9412 pid:1312] Dlizhan_interface.py[line:45] INFO =========== 创建用户 ===========
2026-05-06 16:44:35,778 [tid:9412 pid:1312] Dlizhan_interface.py[line:45] INFO =========== 创建用户 ===========
2026-05-06 16:44:36,023 [tid:9412 pid:1312] Dlizhan_interface.py[line:45] INFO =========== 创建用户 ===========
2026-05-06 16:44:36,364 [tid:9412 pid:1312] Dlizhan_interface.py[line:71] INFO 清除用户 joytest 的指纹锁,影响行数: 1
2026-05-06 16:48:36,755 [tid:19952 pid:28040] UserManage.py[line:44] INFO 尝试读取配置文件: d:\zhyy\smart-management-auto-test\dulizhan\library\BusinessKw\JoyHub\../../../../test_case/Resource/AdapterKws/hh-qa.robot
2026-05-06 16:48:36,757 [tid:19952 pid:28040] UserManage.py[line:57] ERROR 读取robot配置文件失败: [Errno 2] No such file or directory: 'd:\\zhyy\\smart-management-auto-test\\dulizhan\\library\\BusinessKw\\JoyHub\\../../../../test_case/Resource/AdapterKws/hh-qa.robot'
2026-05-06 16:48:36,758 [tid:19952 pid:28040] UserManage.py[line:37] WARNING 未从配置文件读取到JoyHub Token
2026-05-06 16:48:36,956 [tid:19952 pid:28040] RoleManage.py[line:41] INFO 尝试读取配置文件: C:\Users\a\PyCharmMiscProject\smart-management-auto-test\dulizhan\test_case\Resource\AdapterKws\hh-qa.robot
2026-05-06 16:48:36,957 [tid:19952 pid:28040] RoleManage.py[line:53] ERROR 读取robot配置文件失败: [Errno 2] No such file or directory: 'C:\\Users\\a\\PyCharmMiscProject\\smart-management-auto-test\\dulizhan\\test_case\\Resource\\AdapterKws\\hh-qa.robot'
2026-05-06 16:48:36,958 [tid:19952 pid:28040] RoleManage.py[line:36] WARNING 未从配置文件读取到JoyHub Token
2026-05-06 16:48:37,521 [tid:19952 pid:28040] Dlizhan_interface.py[line:71] INFO 清除用户 joytest 的指纹锁,影响行数: 1
2026-05-06 16:48:38,068 [tid:19952 pid:28040] AgreementManage.py[line:116] INFO 获得协议分页列表 - 参数: {'page_no': 1, 'page_size': 10, 'type': '', 'title': '', 'content': '', 'status': ''}
2026-05-06 16:48:38,070 [tid:19952 pid:28040] Dlizhan_interface.py[line:45] INFO =========== 获得协议分页 ===========
2026-05-06 16:48:38,262 [tid:19952 pid:28040] AgreementManage.py[line:35] INFO 创建协议 - type: 1, title: 测试协议_1778057318, content: 这是测试协议内容_1778057318..., terminal: web, lang: de, rank_num: 318, status: 2
2026-05-06 16:48:38,263 [tid:19952 pid:28040] Dlizhan_interface.py[line:45] INFO =========== 创建协议 ===========
2026-05-06 16:48:38,472 [tid:19952 pid:28040] AgreementManage.py[line:35] INFO 创建协议 - type: 2, title: 详情测试协议_1778057318, content: 详情测试协议内容_1778057318..., terminal: app, lang: ja, rank_num: 1318, status: 1
2026-05-06 16:48:38,473 [tid:19952 pid:28040] Dlizhan_interface.py[line:45] INFO =========== 创建协议 ===========
2026-05-06 16:48:38,693 [tid:19952 pid:28040] AgreementManage.py[line:35] INFO 创建协议 - type: 1, title: 待更新协议_1778057318, content: 待更新协议内容_1778057318..., terminal: app, lang: de, rank_num: 2318, status: 1
2026-05-06 16:48:38,694 [tid:19952 pid:28040] Dlizhan_interface.py[line:45] INFO =========== 创建协议 ===========
2026-05-06 16:48:38,910 [tid:19952 pid:28040] AgreementManage.py[line:35] INFO 创建协议 - type: 1, title: 待删除协议_1778057318, content: 待删除协议内容_1778057318..., terminal: web, lang: ja, rank_num: 4318, status: 2
2026-05-06 16:48:38,911 [tid:19952 pid:28040] Dlizhan_interface.py[line:45] INFO =========== 创建协议 ===========
2026-05-06 16:48:39,098 [tid:19952 pid:28040] AgreementManage.py[line:35] INFO 创建协议 - type: 2, title: 批量删除协议1_1778057319, content: 批量删除协议内容1_1778057319..., terminal: app, lang: de, rank_num: 5319, status: 2
2026-05-06 16:48:39,100 [tid:19952 pid:28040] Dlizhan_interface.py[line:45] INFO =========== 创建协议 ===========
2026-05-06 16:48:39,328 [tid:19952 pid:28040] AgreementManage.py[line:88] INFO 导出协议Excel - 参数: {'type': '', 'title': '', 'content': '', 'status': ''}
2026-05-06 16:48:39,330 [tid:19952 pid:28040] Dlizhan_interface.py[line:45] INFO =========== 导出协议 Excel ===========
2026-05-06 16:48:39,658 [tid:19952 pid:28040] Dlizhan_interface.py[line:71] INFO 清除用户 joytest 的指纹锁,影响行数: 1
2026-05-06 16:48:39,748 [tid:19952 pid:28040] Dlizhan_interface.py[line:45] INFO =========== 获得app版本号管理分页 ===========
2026-05-06 16:48:39,951 [tid:19952 pid:28040] Dlizhan_interface.py[line:45] INFO =========== 创建app版本号管理 ===========
2026-05-06 16:48:40,184 [tid:19952 pid:28040] Dlizhan_interface.py[line:45] INFO =========== 创建app版本号管理 ===========
2026-05-06 16:48:40,372 [tid:19952 pid:28040] Dlizhan_interface.py[line:45] INFO =========== 创建app版本号管理 ===========
2026-05-06 16:48:40,593 [tid:19952 pid:28040] Dlizhan_interface.py[line:45] INFO =========== 创建app版本号管理 ===========
2026-05-06 16:48:40,782 [tid:19952 pid:28040] Dlizhan_interface.py[line:45] INFO =========== 创建app版本号管理 ===========
2026-05-06 16:48:41,021 [tid:19952 pid:28040] Dlizhan_interface.py[line:45] INFO =========== 获得导入app版本号管理模板 ===========
2026-05-06 16:48:41,222 [tid:19952 pid:28040] Dlizhan_interface.py[line:45] INFO =========== 导出app版本号管理 Excel ===========
2026-05-06 16:48:41,566 [tid:19952 pid:28040] Dlizhan_interface.py[line:71] INFO 清除用户 joytest 的指纹锁,影响行数: 1
2026-05-06 16:48:41,693 [tid:19952 pid:28040] Dlizhan_interface.py[line:45] INFO =========== 获得Banner管理分页 ===========
2026-05-06 16:48:41,901 [tid:19952 pid:28040] Dlizhan_interface.py[line:45] INFO =========== 创建Banner管理 ===========
2026-05-06 16:48:42,103 [tid:19952 pid:28040] Dlizhan_interface.py[line:45] INFO =========== 创建Banner管理 ===========
2026-05-06 16:48:42,317 [tid:19952 pid:28040] Dlizhan_interface.py[line:45] INFO =========== 创建Banner管理 ===========
2026-05-06 16:48:42,522 [tid:19952 pid:28040] Dlizhan_interface.py[line:45] INFO =========== 创建Banner管理 ===========
2026-05-06 16:48:42,745 [tid:19952 pid:28040] Dlizhan_interface.py[line:45] INFO =========== 创建Banner管理 ===========
2026-05-06 16:48:43,046 [tid:19952 pid:28040] Dlizhan_interface.py[line:71] INFO 清除用户 joytest 的指纹锁,影响行数: 1
2026-05-06 16:48:43,273 [tid:19952 pid:28040] Dlizhan_interface.py[line:71] INFO 清除用户 joytest 的指纹锁,影响行数: 1
2026-05-06 16:48:43,469 [tid:19952 pid:28040] Dlizhan_interface.py[line:45] INFO =========== 获得角色分页 ===========
2026-05-06 16:48:43,720 [tid:19952 pid:28040] Dlizhan_interface.py[line:45] INFO =========== 创建角色 ===========
2026-05-06 16:48:43,910 [tid:19952 pid:28040] Dlizhan_interface.py[line:45] INFO =========== 创建角色 ===========
2026-05-06 16:48:44,148 [tid:19952 pid:28040] Dlizhan_interface.py[line:45] INFO =========== 创建角色 ===========
2026-05-06 16:48:44,331 [tid:19952 pid:28040] Dlizhan_interface.py[line:45] INFO =========== 创建角色 ===========
2026-05-06 16:48:44,518 [tid:19952 pid:28040] Dlizhan_interface.py[line:45] INFO =========== 创建角色 ===========
2026-05-06 16:48:44,772 [tid:19952 pid:28040] Dlizhan_interface.py[line:45] INFO =========== 获取角色精简信息列表 ===========
2026-05-06 16:48:45,000 [tid:19952 pid:28040] Dlizhan_interface.py[line:45] INFO =========== 获取角色精简信息列表 ===========
2026-05-06 16:48:45,333 [tid:19952 pid:28040] Dlizhan_interface.py[line:71] INFO 清除用户 joytest 的指纹锁,影响行数: 1
2026-05-06 16:48:45,580 [tid:19952 pid:28040] Dlizhan_interface.py[line:71] INFO 清除用户 joytest 的指纹锁,影响行数: 1
2026-05-06 16:48:45,921 [tid:19952 pid:28040] Dlizhan_interface.py[line:45] INFO =========== 获得用户分页列表 ===========
2026-05-06 16:48:46,183 [tid:19952 pid:28040] Dlizhan_interface.py[line:45] INFO =========== 获取用户精简信息列表 ===========
2026-05-06 16:48:46,389 [tid:19952 pid:28040] Dlizhan_interface.py[line:45] INFO =========== 创建用户 ===========
2026-05-06 16:48:46,626 [tid:19952 pid:28040] Dlizhan_interface.py[line:45] INFO =========== 创建用户 ===========
2026-05-06 16:48:46,833 [tid:19952 pid:28040] Dlizhan_interface.py[line:45] INFO =========== 创建用户 ===========
2026-05-06 16:48:47,076 [tid:19952 pid:28040] Dlizhan_interface.py[line:45] INFO =========== 创建用户 ===========
2026-05-06 16:48:47,270 [tid:19952 pid:28040] Dlizhan_interface.py[line:45] INFO =========== 创建用户 ===========
2026-05-06 16:48:47,506 [tid:19952 pid:28040] Dlizhan_interface.py[line:45] INFO =========== 创建用户 ===========
2026-05-06 16:48:47,706 [tid:19952 pid:28040] Dlizhan_interface.py[line:45] INFO =========== 创建用户 ===========
2026-05-06 16:48:48,019 [tid:19952 pid:28040] Dlizhan_interface.py[line:71] INFO 清除用户 joytest 的指纹锁,影响行数: 1

View File

@@ -1,46 +0,0 @@
{
"metadata": {
"name": "ui-automation-agent-skills-config",
"version": "1.0.0",
"description": "Configuration for UI automation agents and skills"
},
"defaults": {
"agent": "ui-automation-agent",
"skill": "webapp-testing",
"enabled": true
},
"agents": {
"ui-automation-agent": {
"enabled": true,
"type": "custom",
"description": "default agent profile for UI automation testing",
"model": "",
"entry": "",
"env": {
"PLAYWRIGHT_HEADLESS": "true"
},
"skills": [
"webapp-testing"
]
}
},
"skills": {
"webapp-testing": {
"enabled": true,
"display_name": "UI自动化测试",
"description": "Toolkit for interacting with and testing local web applications using Playwright. Supports verifying frontend functionality, debugging UI behavior, capturing browser screenshots, and viewing browser logs.",
"source": "D:\\software\\SKILL.md",
"entry": "D:\\software\\SKILL.md",
"type": "ui-automation",
"framework": "playwright",
"language": "python",
"recommended_mode": "headless",
"params": {
"browser": "chromium",
"headless": true,
"wait_until": "networkidle",
"close_browser_on_finish": true
}
}
}
}

View File

@@ -5,7 +5,6 @@
zhyy = https://smart-management-api-st.best-envision.com/admin-api zhyy = https://smart-management-api-st.best-envision.com/admin-api
zhyy_login = https://smart-management-api-dev.best-envision.com/admin-api/system/auth/login-dev zhyy_login = https://smart-management-api-dev.best-envision.com/admin-api/system/auth/login-dev
ZZYY = https://smart-management-api-st.best-envision.com/admin-api ZZYY = https://smart-management-api-st.best-envision.com/admin-api
switch4 = https://switch4.best-envision.com/activity/form-review?userLanguage=jp&webKey=JyOJY1HaUWBQ00oooiNOEjTEwMDg3ODA3LCJ1c2VyTmFtZSI6InRveTFrbHNOeTExMSIsImVtYWlsIjoidG8xQGpveWh1Yi5uZXQiLCJwdXNoX2lkIjoxMDc4LCJwdXNoX3R5cGUiOjgsInByb2R1Y3RzIjoiXHU3MmVlXHU1YjUwXHU5OGRlXHU2NzNhXHU2NzZmIiwiYnJhbmRfdWlkIjoyMTA1LCJjaGFuIjoiaW0iLCJwcm9kdWN0X2lkIjo3fQO0O0OO0O0O
# uat环境 # uat环境
[UAT] [UAT]

View File

@@ -1,6 +1,6 @@
[run_evn_name] [run_evn_name]
current_business = hh current_business = hh
current_evn = QA current_evn = qa
current_team = ZZYY current_team = ZZYY
[run_jira_id] [run_jira_id]

View File

@@ -1,3 +0,0 @@
/logs/
/venv/
.idea/

View File

@@ -1,4 +0,0 @@
### IT接口管理
* git clone
* pip3 install -r requirements
* gunicorn --config=gunicorn.conf.py manage:app

View File

@@ -1,18 +0,0 @@
from flask import Flask
from ..app.api.views import api
from flask_docs import ApiDoc
from logger import logger
def create_app():
app = Flask(__name__)
app.register_blueprint(api, url_prefix='/api')
ApiDoc(
app,
title="Effekt Interface App",
version="1.0.0",
description="Effekt Interface app API",
)
app.config["API_DOC_MEMBER"] = ["api", "platform"]
logger.info("app start-------")
return app

View File

@@ -1,128 +0,0 @@
# encoding: UTF-8
import time
import subprocess
from subprocess import PIPE
import os
class OSType:
WIN, LINUX, UNKNOWN = range(3)
def __init__(self):
pass
@staticmethod
def get_type():
import platform
system_name = platform.system()
if system_name.lower() == 'windows':
return OSType.WIN
elif system_name.lower() == 'linux':
return OSType.LINUX
else:
return OSType.UNKNOWN
class tool(object):
def __init__(self):
self.env_port = 5011
def run_process(self, cmd_str, out_p=False):
"""
run command
cmd_str unicode string.
"""
if OSType.WIN == OSType.get_type():
# cmd_str = cmd_str.encode('gbk')
cmd_str = cmd_str
elif OSType.LINUX == OSType.get_type():
cmd_str = cmd_str.encode('utf-8')
else:
raise RuntimeError("your os is not support.")
close_fds = False if OSType.WIN == OSType.get_type() else True
if out_p:
p = subprocess.Popen(cmd_str, shell=True, close_fds=close_fds, stdout=PIPE)
p.wait()
return p.returncode, p.stdout.read()
else:
c = self.get_devnull()
p = subprocess.Popen(cmd_str, shell=True, close_fds=close_fds, stdout=c)
p.wait()
return p.returncode, None
def get_devnull(self):
try:
return subprocess.DEVNULL
except AttributeError:
# Python 2.x or older
return open(os.devnull, 'r+')
def _kills_pid(self):
if OSType.WIN == OSType.get_type():
kill_pid_cmd = "taskkill /f /pid {}".format(self.pid)
elif OSType.LINUX == OSType.get_type():
kill_pid_cmd = "kill -9 {}".format(self.pid)
else:
raise RuntimeError("your os is not support.")
res_code, res_context = self.run_process(kill_pid_cmd)
if res_code:
raise RuntimeError("kill pid: {} failed. error: {}".format(self.pid, res_context))
def check_port(self):
if OSType.WIN == OSType.get_type():
find_pid_win_cmd = 'netstat -ano | findstr {} | findstr LISTENING'.format(self.env_port)
print(find_pid_win_cmd)
res_code, res_context = self.run_process(find_pid_win_cmd, out_p=True)
if res_code == 0:
if len(res_context) > 0:
try:
self.pid = str(res_context).split()[-1].replace("\\r\\n'", "")
self._kills_pid()
except IndexError:
pass
elif OSType.LINUX == OSType.get_type():
find_pid_linux_cmd = "lsof -i:{}".format(self.env_port)
res_code, res_context = self.run_process(find_pid_linux_cmd, out_p=True)
if res_code == 0:
# 获取pid
if len(res_context) > 0:
try:
self.pid = str(res_context).split("\n")[1].split()[1]
self._kills_pid()
except IndexError:
pass
else:
raise RuntimeError("your os is not support.")
def run_manage(self):
count = 3
while count > 0:
self.run_manages()
find_pid_linux_cmd = "lsof -i:{}".format(self.env_port)
res_code, res_context = self.run_process(find_pid_linux_cmd, out_p=True)
print(res_code,"---res_code---",res_context,"---res_context---")
if len(res_context) > 0:
time.sleep(2)
pid = str(res_context).split("\n")[1].split()[1]
print(pid,"pid####")
count -= 1
if pid:
break
else:
continue
else:
break
def run_manages(self):
lod = "nohup python3 platform_tools/aida/manage.py &."
subprocess.call(["./5011.sh"])
# self.run_process(lod)
if __name__ == '__main__':
test = tool()
test.check_port()
time.sleep(3)
test.run_manage()

View File

@@ -1,527 +0,0 @@
# encoding: UTF-8
from ....common.sqlSession import SqlSession
from ..service.createDataDetailService import CreateDetailService
from ..service.createDataDictService import CreateDictService
from ..service.createDataInfoService import CreateInfoService
from ..service.createDataNumberService import CreateNumberService
from ..service.createDataResultService import CreateResultService
from ..model.createDataInfo import CreateInfo
from ..model.createDetailInfo import CreateDetail
from ..model.createDictInfo import CreateDict
from datetime import datetime, timedelta
from logger import logger
import ast
from operator import methodcaller
import astunparse
import os
import re
import time
from sqlalchemy.exc import SQLAlchemyError
class CommonController(object):
def __init__(self):
self.session = SqlSession()
def create_all_info(self, team_name, list_detail):
"""
对比造数基础表数据,新增的进行录库
:return:
"""
for detail in list_detail:
file_name = detail.get("file_name")
get_class_name = detail.get("class_name")
module_names = detail.get("module_name")
method_name = detail.get("method_name")
module_name = module_names.split(".")[0]
method_detail = detail.get("method_detail")
request_parameter = list(eval(detail.get("request_parameter")))
create_dict_service = CreateDictService()
create_detail_service = CreateDetailService()
create_info_service = CreateInfoService()
filter_detail_list = list()
filter_detail_list.append(CreateDetail.class_name == get_class_name)
filter_detail_list.append(CreateDetail.method_name == method_name)
filter_detail_list.append(CreateDetail.module_name == module_name)
get_data_detail = create_detail_service.get_detail_simple_data_by_filters(self.session,
filter_detail_list)
# 数据字典中业务线配置的路径,用于获取各个业务线下的业务名称
filter_dict_list = list()
filter_dict_list.append(CreateDict.data_type == 1)
filter_dict_list.append(CreateDict.dict_key == team_name)
get_dict_detail = create_dict_service.get_dict_simple_data_by_filters(self.session, filter_dict_list)
get_split_team_name = get_dict_detail.dict_value.split(".")[-1]
get_split_file_name = file_name.split(get_split_team_name)[-1]
if get_split_file_name:
get_file_name = get_split_file_name[1:].replace("\\", ".")
else:
get_file_name = ""
if get_data_detail:
compare_class_name = self.compare_string(get_data_detail.class_name, get_class_name)
compare_module_name = self.compare_string(get_data_detail.module_name, module_name)
compare_method_name = self.compare_string(get_data_detail.method_name, method_name)
compare_method_detail = self.compare_string(get_data_detail.method_detail, method_detail)
# compare_file_name = self.compare_string(get_data_detail.file_name, get_file_name)
update_info = {}
if compare_class_name:
update_info["class_name"] = get_class_name
elif compare_module_name:
update_info["module_name"] = module_name
elif compare_method_name:
update_info["method_name"] = method_name
elif compare_method_detail:
update_info["method_detail"] = method_detail
# elif compare_file_name:
# get_data_detail.file_name = get_file_name
else:
continue
update_info["modified_time"] = update_time()
print(update_info)
err_msg = create_detail_service.update_service_detail_data(self.session, update_info,
get_data_detail.create_data_detail_id)
if err_msg:
return err_msg
else:
if method_name == "__init__":
continue
if re.findall("__", method_name):
continue
if method_name.startswith("_"):
continue
dict_parameter = {}
if request_parameter:
for parameter in request_parameter:
if parameter != 'self':
dict_parameter[parameter] = ""
else:
dict_parameter = {}
get_method_detail = self.handle_method_detail(method_detail)
get_creator = self.get_creator_info(team=team_name, method_detail=method_detail)
if get_method_detail:
get_function_details = get_method_detail
else:
get_function_details = str(module_name) + "." + str(get_class_name) + "." + str(method_name)
add_detail_data = {}
add_info_data = {}
add_dict_data = {}
add_detail_data["create_data_detail_id"] = get_uuid()
add_detail_data["team_name"] = team_name
add_detail_data["file_name"] = get_file_name
add_detail_data["class_name"] = get_class_name
add_detail_data["del_flag"] = 0
add_detail_data["module_name"] = module_name
add_detail_data["method_name"] = method_name
add_detail_data["method_detail"] = method_detail
add_detail_data["method_function_detail"] = get_function_details
add_detail_data["creator"] = get_creator
add_detail_data["status"] = 0
add_detail_data["created_time"] = update_time()
add_detail_data["modified_time"] = update_time()
create_data_detail_id = create_detail_service.create_service_detail_data(self.session,
add_detail_data)
add_info_data["create_data_info_id"] = get_uuid()
add_info_data["create_data_detail_id"] = create_data_detail_id
add_info_data["class_name"] = get_class_name
add_info_data["del_flag"] = 0
add_info_data["method_name"] = method_name
add_info_data["request_parameter"] = dict_parameter
add_info_data["created_time"] = get_time()
add_info_data["modified_time"] = get_time()
info_id = create_info_service.create_service_info_data(self.session, add_info_data)
filter_dict_type_list = list()
filter_dict_type_list.append(CreateDict.team_name == team_name.upper())
filter_dict_type_list.append(CreateDict.data_type == 3)
filter_dict_type_list.append(CreateDict.dict_key == get_file_name)
get_dict_detail = create_dict_service.get_dict_simple_data_by_filters(self.session,
filter_dict_type_list)
add_dict_data["create_dict_data_id"] = get_uuid()
add_dict_data["data_type"] = 3
add_dict_data["team_name"] = team_name
add_dict_data["dict_key"] = get_file_name
add_dict_data["dict_value"] = get_file_name
add_dict_data["del_flag"] = 0
add_dict_data["created_time"] = get_time()
add_dict_data["modified_time"] = get_time()
if get_dict_detail or get_file_name == "":
continue
else:
dict_id = create_dict_service.create_service_dict_data(self.session, add_dict_data)
return True
def compare_string(self, sub_str1, sub_str2):
'''
对两个字符串进行比较,查看字符串是否相同
:param sub_str1:
:param sub_str2:
:return:
'''
if sub_str1 == sub_str2:
return False
else:
return True
def handle_dict_data(self, create_data_detail_id, data_type, dict_key):
'''
处理数据字典的路径类型,进行初始化路径组装
:return:
'''
create_detail_service = CreateDetailService()
create_dict_service = CreateDictService()
filter_detail_list = list()
filter_dict_list = list()
filter_detail_list.append(CreateDetail.create_data_detail_id == create_data_detail_id)
filter_dict_list.append(CreateDict.data_type == data_type)
filter_dict_list.append(CreateDict.dict_key == dict_key)
get_data_detail = create_detail_service.get_detail_simple_data_by_filters(self.session, filter_detail_list)
get_dict_data = create_dict_service.get_dict_simple_data_by_filters(self.session, filter_dict_list)
if get_dict_data:
if get_data_detail.file_name:
get_new_path = get_dict_data.dict_value + "." + get_data_detail.file_name + "." + get_data_detail.module_name
else:
get_new_path = get_dict_data.dict_value + "." + get_data_detail.module_name
return {"get_new_path": get_new_path, "class_name": get_data_detail.class_name}
else:
return False
def handle_result_data(self, create_data_detail_id, create_data_info_id):
"""
处理数据结果表
:return:
"""
create_detail_service = CreateDetailService()
create_info_service = CreateInfoService()
filter_detail_list = list()
filter_data_list = list()
filter_detail_list.append(CreateDetail.create_data_detail_id == create_data_detail_id)
filter_data_list.append(CreateInfo.create_data_info_id == create_data_info_id)
get_data_detail = create_detail_service.get_detail_simple_data_by_filters(self.session, filter_detail_list)
get_data_info = create_info_service.get_data_simple_data_by_filters(self.session, filter_data_list)
dict_data = {"team_name": get_data_detail.team_name, "module_name": get_data_detail.module_name,
"file_name": get_data_detail.file_name, "class_name": get_data_detail.class_name,
"method_name": get_data_detail.method_name, "request_parameter": get_data_info.request_parameter,
"method_function_detail": get_data_detail.method_function_detail}
return dict_data
def handle_method_detail(self, method_detail):
'''
对方法描述进行匹配出主要功能信息
:return:
'''
if method_detail:
get_function_detail = re.findall("功能说明: \|(.*)\|", method_detail)
else:
get_function_detail = "请补充方法注释"
if get_function_detail:
return get_function_detail
else:
get_function_details = re.findall("\s*功能(.+)", method_detail)
if get_function_details:
return get_function_details
else:
return False
def get_creator_info(self, team, method_detail):
'''
获取负责人信息
:return:
'''
if method_detail:
get_creators = re.findall("作者信息: \|(.*?)\|", method_detail)
else:
get_creators = ""
if get_creators:
return get_creators
else:
create_dict_service = CreateDictService()
filter_dict_list = list()
filter_dict_list.append(CreateDict.data_type == 5)
filter_dict_list.append(CreateDict.dict_key == team.upper())
get_data_detail = create_dict_service.get_dict_simple_data_by_filters(self.session, filter_dict_list)
if get_data_detail:
return get_data_detail.dict_value
else:
return "未找到负责人"
def get_login_creator(self, token):
'''
获取造数使用者信息
:return:
'''
if token:
return token
else:
return "administrator"
def get_team_name(self, team):
"""
各业务线对应枚举
:return:
"""
# 业务线枚举映射
create_dict_service = CreateDictService()
filter_list = list()
filter_list.append(CreateDict.dict_key == team.upper())
filter_list.append(CreateDict.data_type == 2)
get_dict_data = create_dict_service.get_dict_simple_data_by_filters(self.session, filter_list)
if get_dict_data:
return get_dict_data.dict_value
else:
return team
def get_module_name(self, team, dict_key):
"""
各业务线模块对应枚举
:return:
"""
# 业务线模块名称映射
create_dict_service = CreateDictService()
filter_list = list()
filter_list.append(CreateDict.team_name == team.upper())
filter_list.append(CreateDict.data_type == 3)
filter_list.append(CreateDict.dict_key == dict_key)
get_dict_data = create_dict_service.get_dict_simple_data_by_filters(self.session, filter_list)
if get_dict_data:
return get_dict_data.dict_value
else:
return dict_key
def get_keyword_path(self, team, file_name=""):
"""
获取某个组的关键字路径
:return:
"""
# 业务线模块名称映射
create_dict_service = CreateDictService()
filter_list = list()
filter_list.append(CreateDict.dict_key == team.upper())
filter_list.append(CreateDict.data_type == 1)
get_data_detail = create_dict_service.get_dict_simple_data_by_filters(self.session, filter_list)
get_list_path = get_data_detail.dict_value.split(".")
basic_path = os.path.dirname(os.path.abspath(__file__))
team_path = os.path.abspath(os.path.join(basic_path, '../../../../../../'))
if file_name.endswith(".py"):
return os.path.join(team_path, *get_list_path, file_name)
else:
return os.path.join(team_path, *get_list_path)
def get_model_name(self, team, dict_key):
'''
各业务线对应枚举
:param files_path:
:return:
'''
# 业务线模块名称映射
create_dict_service = CreateDictService()
filter_list = list()
filter_list.append(CreateDict.team_name == team.upper())
filter_list.append(CreateDict.dict_key == dict_key)
filter_list.append(CreateDict.data_type == 3)
get_data_detail = create_dict_service.get_dict_simple_data_by_filters(self.session, filter_list)
if get_data_detail:
return get_data_detail.dict_value
else:
return dict_key
def daily_task_update_month_number(self):
"""
定时任务,每天更新月使用次数
:return:
"""
create_detail_service = CreateDetailService()
create_number_service = CreateNumberService()
create_result_service = CreateResultService()
# 假设时间字段为 `created_time`,格式为 'YYYYMMDDHHMM'
time_field_format = '%Y%m%d%H%M'
# 获取当前时间
now = datetime.now()
# 计算一个月前的时间
one_month_ago = now - timedelta(days=30)
# 将时间转换为目标格式的字符串
one_month_ago_str = one_month_ago.strftime(time_field_format)
all_number_methods = create_number_service.get_service_number_all_no_filters(session=self.session)
if len(all_number_methods) == 0:
return ""
for number in all_number_methods:
try:
if not self.session.object_session(number):
self.session.add(number) # 重新绑定对象到会话
get_number = create_result_service.get_service_result_numbers_by_month(session=self.session,
create_data_detail_id=number.create_data_detail_id,
one_month_ago_str=one_month_ago_str)
if get_number is None:
get_number = 0
else:
get_number = get_number[0]
create_number_service.update_service_number_data(session=self.session,
update_info={"month_number": get_number},
create_data_detail_id=number.create_data_detail_id)
except SQLAlchemyError as e:
self.session.rollback()
finally:
self.session.close()
return {"code": 20000, "message": "更新成功"}
class LambdaCheck(ast.NodeVisitor):
def __init__(self):
self.illegal_args_list = []
self._cur_file = None
self._cur_lambda_args = []
def set_cur_file(self, cur_file):
assert os.path.isfile(cur_file), cur_file
self._cur_file = os.path.realpath(cur_file)
def visit_Lambda(self, node):
"""
lambda 闭包检查原则:
只需检测lambda expr body中args是否引用了lambda args list之外的参数
"""
self._cur_lambda_args = [a.id for a in node.args.args]
print(astunparse.unparse(node))
self.get_lambda_body_args(node.body)
self.generic_visit(node)
def record_args(self, name_node):
if isinstance(name_node, ast.Name) and name_node.id not in self._cur_lambda_args:
self.illegal_args_list.append((self._cur_file, 'line no:%s' % name_node.lineno, 'var:%s' % name_node.id))
def _is_args(self, node):
if isinstance(node, ast.Name):
self.record_args(node)
return True
if isinstance(node, ast.Call):
map(self.record_args, node.args)
return True
return False
def get_lambda_body_args(self, node):
if self._is_args(node): return
# for cnode in ast.walk(node):
for cnode in ast.iter_child_nodes(node):
if not self._is_args(cnode):
self.get_lambda_body_args(cnode)
list_info = [] # 存爬取出来的方法列表
class CodeVisitor(ast.NodeVisitor):
def __init__(self, file, file_name):
self.file = file
self.file_name = file_name
self.dict_info = {}
def visit_BinOp(self, node): # 这个函数的访问是由于 Visit_FunctionDef的先访问再generic_visit才访问的
# print('Bin') # 如果Visit_FunctionDef中没有generic_visit的话则这个函数是不会访问的
if isinstance(node.op, ast.Add):
node.op = ast.Sub()
self.generic_visit(node)
def visit_ClassDef(self, node):
# print('Class Name: %s' % node.name)
global class_name
class_name = node.name
self.generic_visit(node) # ClassDef中还包含有 BinOp,因此会进去visit BinOP
# print(dict_info)
def visit_FunctionDef(self, node):
# print('Function Name: %s' % node.name)
self.dict_info = {}
is_kwargs = node.args.kwarg
args = list([arg.arg for arg in node.args.args])
if is_kwargs is not None:
args.append("is_kwargs")
# print(str(args))
self.dict_info["file_name"] = self.file_name
self.dict_info["class_name"] = class_name
self.dict_info["module_name"] = self.file
self.dict_info["method_name"] = node.name
self.dict_info["request_parameter"] = str(args)
self.dict_info["method_detail"] = ast.get_docstring(node)
# print(ast.get_docstring(node))
list_info.append(self.dict_info)
self.generic_visit(node) # FunctionDef中还包含有 BinOp,因此会进去visit BinOP
def run(files_path, end_file, remove_file):
"""
用于执行获取各个类中的方法与方法注解
:param files_path:需要爬取关键字的路径
:param end_file:爬取需要什么结尾的文件
:param remove_file:不需要爬取的文件路径的文件名称
:return:
"""
if files_path.endswith(end_file):
checker = LambdaCheck()
checker.set_cur_file(files_path)
with open(files_path, 'rb') as f:
root_node = ast.parse(f.read())
visitor = CodeVisitor(os.path.basename(files_path), file_name="")
visitor.visit(root_node)
else:
for root, dirs, files in os.walk(files_path):
file_name = os.path.basename(root)
# if re.findall(remove_file, root):
# continue
py_files = filter(lambda file: file.endswith(end_file), files)
checker = LambdaCheck()
for file in py_files:
file_path = os.path.join(root, file)
checker.set_cur_file(file_path)
with open(file_path, 'rb') as f:
root_node = ast.parse(f.read())
# print(file_name)
visitor = CodeVisitor(file, root)
visitor.visit(root_node)
return list_info
def call_method(class_name, method_info):
'''
主要用于动态调用方法,
:param class_name:传入定义后的类名
:param method_name:传入方法与参数 eg:{"methodName":"kw_astwb_create_classes","requestParameter":{"user":"qiaoxinjiu","post_data_input={'studentMin':'2'}"}
:return:
'''
method_name = method_info.get("methodName")
if method_name:
request_data = method_info.get("requestParameter")
return methodcaller(method_name, **request_data)(class_name())
else:
return {"方法名输入错误"}
def get_time():
"""
获取当前时间
:return:
"""
# now_time = datetime.datetime.now().strftime("%Y%m%d%H%M%S.%f")
now_time = time.strftime("%Y%m%d%H%M%S", time.localtime())
return now_time
def update_time():
"""
录入数据库时间
:return:
"""
import datetime
now_time = datetime.datetime.now().strftime("%Y%m%d%H%M%S.%f")
return now_time
def get_uuid():
'''
获取uuid
:return:
'''
import uuid
test_id = str(uuid.uuid1())
return test_id

View File

@@ -1,304 +0,0 @@
# encoding: UTF-8
from ....common.sqlSession import SqlSession
from ..service.createDataDetailService import CreateDetailService
from ..service.createDataInfoService import CreateInfoService
from ..service.createDataGroupService import CreateGroupService
from ..service.createDataNumberService import CreateNumberService
from ..model.createDetailInfo import CreateDetail
from ..controller import commonController
from ..controller.createDataResultController import CreateDataResultController
from ..controller.createDataNumberController import CreateDataNumberController
from logger import logger
import time
import json
import importlib
import sys
class CreateDataDetailController(object):
def __init__(self, req_json, token):
self.session = SqlSession()
self.page = req_json.get('pageNo')
self.limit = req_json.get('pageSize')
self.create_data_detail_id = req_json.get('create_data_detail_id')
self.create_data_info_id = req_json.get('create_data_info_id')
self.team_name = req_json.get('team_name')
self.file_name = req_json.get('file_name')
self.module_name = req_json.get('module_name')
self.method_name = req_json.get('method_name')
self.detail_name = req_json.get('detail_name')
self.method_detail = req_json.get('method_detail')
self.method_function_detail = req_json.get('method_function_detail')
self.request_parameter = req_json.get('request_parameter')
self.dict_key = req_json.get('dict_key')
self.get_tag = req_json.get('get_tag')
self.email = req_json.get('email')
self.status = req_json.get('status')
self.token = token
self.del_flag = 0
self.req_json = req_json
def create_detail_data(self):
"""
对造数列表进行新增
:return:
"""
def update_detail_data(self):
"""
对造数信息进行修改
:return:
"""
def delete_detail_data(self):
"""
对造数信息进行删除
:return:
"""
create_detail_service = CreateDetailService()
del_info = create_detail_service.delete_service_detail_data(self.session,
create_data_detail_id=self.create_data_detail_id)
return del_info
def count_sucess_rate(self, total_number, right_number):
"""
计算成功率
:return:
"""
if total_number == 0:
return 0
else:
get_result = right_number / total_number
return round(get_result, 2)
def get_number_data(self, create_data_detail_id):
"""
根据造数详情id查询对应的次数信息
:return:
"""
create_number_service = CreateNumberService()
get_query_info, message = create_number_service.get_service_number_by_id(session=self.session,
create_data_detail_id=create_data_detail_id)
if message:
if get_query_info:
return {"total_number": get_query_info.total_number,
"success_rate": self.count_sucess_rate(get_query_info.total_number,
get_query_info.right_number)}
else:
return {"total_number": 0,
"success_rate": 0}
else:
return {"total_number": 0,
"success_rate": 0}
def approve_detail_status(self):
"""
审核状态
:return:
"""
create_detail_service = CreateDetailService()
update_info = {"status": 1}
err_msg = create_detail_service.update_service_detail_data(self.session, update_info,
self.create_data_detail_id)
if err_msg:
return {"code": 40010, "message": err_msg}
else:
return {"code": 20000, "message": "审核成功"}
def get_detail_query_advance(self):
"""
列表页查询
:return:
"""
create_group_service = CreateGroupService()
if self.page is None:
self.page = 1
if self.limit is None:
self.limit = 10
create_detail_service = CreateDetailService()
common_controller = commonController.CommonController()
get_group_data = create_group_service.get_service_group_info_data_by_email(self.session, email=self.email)
list_group_user = ["ALL"]
filter_list = []
team_name = self.team_name
file_name = self.file_name
module_name = self.module_name
detail_name = self.detail_name
status = self.status
if team_name:
filter_list.append(CreateDetail.team_name == team_name)
if file_name:
filter_list.append(CreateDetail.file_name == file_name)
if module_name:
filter_list.append(CreateDetail.module_name == module_name)
if detail_name:
filter_list.append(CreateDetail.method_function_detail.like('%' + self.detail_name + '%'))
if status:
filter_list.append(CreateDetail.status == 1)
if filter_list:
if get_group_data:
list_group_user.append(get_group_data.team_name)
detail_list, total = create_detail_service.get_detail_list_by_filters_team_page(self.session,
filter_list,
list_group_user,
self.page, self.limit)
else:
if get_group_data:
list_group_user.append(get_group_data.team_name)
detail_list, total = create_detail_service.get_detail_list_no_filters_team_page(self.session,
list_group_user, self.page,
self.limit)
ret_ls = []
for obj in detail_list:
ret_ls.append({
'create_data_detail_id': obj.create_data_detail_id,
'team_name': common_controller.get_team_name(obj.team_name),
'total_number': self.get_number_data(obj.create_data_detail_id).get("total_number"),
'success_rate': self.get_number_data(obj.create_data_detail_id).get("success_rate"),
'file_name': common_controller.get_module_name(team=obj.team_name, dict_key=obj.file_name),
'class_name': obj.class_name,
'module_name': obj.module_name,
'method_name': obj.method_name,
'method_function_detail': obj.method_function_detail,
'method_detail': obj.method_detail,
'status': obj.status,
'creator': obj.creator,
'created_time': obj.created_time,
'modified_time': obj.modified_time
})
return {"list": ret_ls, "total": total}
def get_request_parameter(self, request_parameter):
"""
组成详情获取组装请求参数信息
:return:
"""
try:
get_dict_parameter = request_parameter
# get_dict_parameter = json.loads(request_parameter)
dict_data = {}
for key, value in get_dict_parameter.items():
if key == "post_data_input":
dict_data.update(get_dict_parameter.get("post_data_input"))
else:
dict_data[key] = value
return dict_data
except:
return request_parameter
def get_detail_advance(self):
"""
关键字基础信息详情页查询
:return:
"""
create_info_service = CreateInfoService()
get_data_info = create_info_service.get_create_data_info_by_detail_id(session=self.session,
detail_id=self.create_data_detail_id)
create_detail_service = CreateDetailService()
get_detail_info = create_detail_service.get_create_detail_info_by_id(session=self.session,
create_data_detail_id=self.create_data_detail_id)
common_controller = commonController.CommonController()
_data = {'create_data_detail_id': get_data_info.create_data_detail_id,
'create_data_info_id': get_data_info.create_data_info_id,
'team_name': get_detail_info.team_name,
'file_name': common_controller.get_model_name(team=get_detail_info.team_name,
dict_key=get_detail_info.file_name),
'class_name': get_data_info.class_name,
'method_name': get_data_info.method_name,
'method_detail': get_detail_info.method_detail,
'method_function_detail': get_detail_info.method_function_detail,
'creator': get_detail_info.creator,
# 'request_parameter':unescape(str(_edit.request_parameter)),
'request_parameter': self.get_request_parameter(get_data_info.request_parameter),
'created_time': get_data_info.created_time,
'modified_time': get_data_info.modified_time}
return _data
def run_keyword_data(self):
"""
执行造数
:return:
"""
create_info_service = CreateInfoService()
common_controller = commonController.CommonController()
data_type = 1
# creator = dict_data["creator"]
creator = common_controller.get_login_creator(self.email)
time.sleep(2)
# 查询请求参数的表用于判断传入的类名与方法名是否正确
get_data_info = create_info_service.get_create_data_info_by_id(session=self.session,
sid=self.create_data_info_id)
chushi_name = get_data_info.class_name
try:
get_parameter = json.loads(self.request_parameter)
except:
return {"code": 40009, "message": "请求参数格式不正确"}
create_data_result_id = commonController.get_uuid()
created_time = commonController.get_time()
modified_time = commonController.get_time()
get_result_info = common_controller.handle_result_data(create_data_detail_id=self.create_data_detail_id,
create_data_info_id=self.create_data_info_id)
req_json = {"create_data_detail_id": self.create_data_detail_id,
"method_name": get_result_info.get("method_name")}
create_number_controller = CreateDataNumberController(req_json=req_json, token=self.token)
req_json = {"create_data_result_id": create_data_result_id,
"create_data_info_id": self.create_data_info_id,
"create_data_detail_id": self.create_data_detail_id,
"team_name": get_result_info.get("team_name"),
"file_name": get_result_info.get("file_name"),
"module_name": get_result_info.get("module_name"),
"class_name": get_result_info.get("class_name"),
"method_name": get_result_info.get("method_name"),
"tag": self.get_tag,
"status": 0,
"method_function_detail": get_result_info.get("method_function_detail"),
"request_parameter": get_parameter, "result_info": "",
"creator": creator, "created_time": created_time, "modified_time": modified_time}
add_result_controller = CreateDataResultController(req_json=req_json, token=self.token)
add_result_id = add_result_controller.create_result_data(req_json)
try:
if get_data_info:
dict_key = self.dict_key
get_dict_info = common_controller.handle_dict_data(create_data_detail_id=self.create_data_detail_id,
data_type=data_type, dict_key=dict_key.upper())
if get_dict_info is False:
return {"code": 500, "message": "字典中不存在该信息"}
method_info = {"methodName": get_data_info.method_name,
"requestParameter": get_data_info.request_parameter}
class_name = get_data_info.class_name
print("get_new_path:", get_dict_info.get("get_new_path"))
test = importlib.import_module(get_dict_info.get("get_new_path"))
get_data_info.class_name = getattr(test, get_dict_info.get("class_name")) # 实例化case
result_data = commonController.call_method(class_name=get_data_info.class_name,
method_info=method_info) # 返回造数结果
try:
if isinstance(result_data, str):
is_json = False
else:
is_json = True
get_result = json.dumps(result_data, ensure_ascii=False)
except:
is_json = False
get_result = result_data
add_result_controller.update_result_data(sid=add_result_id, status=1, result_info=str(result_data))
get_data_info.class_name = class_name
create_number_controller.update_number_data(is_right=True)
data = {"message": "造数成功", "data": {"create_data_result_id": create_data_result_id, "data": get_result,
"is_json": is_json}}
else:
data = {"message": "传入请求id未查询到相应信息"}
return data
except:
get_data_info.class_name = chushi_name
s = sys.exc_info()
create_number_controller.update_number_data(is_right=False)
add_result_controller.update_result_data(sid=add_result_id, status=2, result_info=str(s[1]))
logger.info('Error "%s" happend on line %d' % (s[1], s[2].tb_lineno))
data = {"message": "造数出现异常,异常为:{}".format(str(s[1]))}
return data

View File

@@ -1,180 +0,0 @@
# encoding: UTF-8
from datetime import datetime
from ....common.sqlSession import SqlSession
from ..controller import commonController
from ..service.createDataDictService import CreateDictService
from ..service.createDataGroupService import CreateGroupService
from ..model.createDictInfo import CreateDict
from ..controller.commonController import CommonController
from logger import logger
class CreateDataDictController(object):
def __init__(self, req_json, token):
self.session = SqlSession()
self.pageNo = req_json.get('pageNo')
self.pageSize = req_json.get('pageSize')
self.create_dict_data_id = req_json.get('create_dict_data_id')
self.team_name = req_json.get('team_name')
self.data_type = req_json.get('data_type')
self.dict_key = req_json.get('dict_key')
self.dict_value = req_json.get('dict_value')
self.email = req_json.get('email')
self.token = token
self.del_flag = 0
self.req_json = req_json
def create_dict_data(self):
"""
对数据字典进行新增
:return:
"""
common_controller = commonController.CommonController()
# 获取抓取的方法名称,描述等
create_dict_id = commonController.get_uuid()
created_time = commonController.get_time()
modified_time = commonController.get_time()
create_dict_service = CreateDictService()
filter_list = list()
filter_list.append(CreateDict.dict_value == self.team_name)
filter_list.append(CreateDict.data_type == 2)
# 获取抓取的方法名称,描述等
get_dict_value_data = create_dict_service.get_dict_simple_data_by_filters(self.session, filter_list)
if get_dict_value_data:
dict_keys = get_dict_value_data.dict_key
else:
dict_keys = self.dict_key
filter_list_data = list()
filter_list_data.append(CreateDict.dict_key == self.dict_key)
filter_list_data.append(CreateDict.data_type == self.data_type)
filter_list_data.append(CreateDict.team_name == dict_keys)
filter_list_data.append(CreateDict.data_type == 2)
get_dict_data = create_dict_service.get_dict_simple_data_by_filters(self.session, filter_list_data)
add_data = {
"create_dict_data_id": create_dict_id,
"data_type": self.data_type,
"team_name": self.team_name,
"dict_key": self.dict_key,
"dict_value": self.dict_value,
"del_flag": 0,
"created_time": created_time,
"modified_time": modified_time
}
create_data_info_id, err_msg = create_dict_service.create_service_dict_data(session=self.session,
create_info=add_data)
return err_msg
def update_dict_data(self):
"""
对数据字典进行修改
:return:
"""
create_dict_service = CreateDictService()
filter_list = list()
filter_list.append(CreateDict.dict_value == self.team_name)
filter_list.append(CreateDict.data_type == 2)
# 获取抓取的方法名称,描述等
get_dict_value_data = create_dict_service.get_dict_simple_data_by_filters(self.session, filter_list)
if get_dict_value_data:
dict_keys = get_dict_value_data.dict_key
else:
dict_keys = self.dict_key
filter_data_list = list()
filter_data_list.append(CreateDict.team_name == dict_keys)
filter_data_list.append(CreateDict.data_type == self.data_type)
filter_data_list.append(CreateDict.dict_key == self.dict_key)
get_dict_data = create_dict_service.get_dict_simple_data_by_filters(self.session, filter_data_list)
if get_dict_data:
edit_dict_id = self.create_dict_data_id
filter_edit_list = list()
filter_edit_list.append(CreateDict.create_dict_data_id == edit_dict_id)
get_edit_data = create_dict_service.get_dict_simple_data_by_filters(self.session, filter_edit_list)
edit_data = {'dict_value': self.dict_value, 'team_name': get_edit_data.team_name,
'dict_key': get_edit_data.dict_key}
err_msg = create_dict_service.update_service_dict_data(session=self.session, update_info=edit_data,
create_dict_data_id=edit_dict_id)
if err_msg:
return err_msg
else:
add_data = {
'data_type': self.data_type,
'team_name': self.team_name,
'dict_key': self.dict_key,
'dict_value': self.dict_value,
}
create_data_info_id, err_msg = create_dict_service.create_service_dict_data(session=self.session,
create_info=add_data)
if err_msg:
return err_msg
def get_dict_list_data(self):
"""
数据字典列表页查询
:return:
"""
if self.pageNo is None:
self.pageNo = 1
if self.pageSize is None:
self.pageSize = 10
create_dict_service = CreateDictService()
common_controller = CommonController()
create_group_service = CreateGroupService()
get_group_data = create_group_service.get_service_group_info_data_by_email(self.session, email=self.email)
list_group_user = ["ALL"]
filter_list = []
if self.team_name:
filter_list.append(CreateDict.team_name == self.team_name)
if self.dict_value:
filter_list.append(CreateDict.dict_value.like('%' + self.dict_value + '%'))
filter_list.append(CreateDict.data_type == 3)
if get_group_data:
list_group_user.append(get_group_data.team_name)
dict_list, total = create_dict_service.get_dict_list_by_team_filters_page(self.session, filter_list,
list_group_user,
self.pageNo, self.pageSize)
ret_ls = []
for obj in dict_list:
ret_ls.append({
'create_dict_data_id': obj.create_dict_data_id,
'team_name': common_controller.get_team_name(obj.team_name),
'data_type': obj.data_type,
'dict_key': obj.dict_key,
'dict_value': obj.dict_value,
'created_time': obj.created_time,
'modified_time': obj.modified_time,
})
return {"list": ret_ls, "total": total}
def get_team_name(self):
"""
获取各个业务线的数据字典,用于查询
:return:
"""
create_dict_service = CreateDictService()
create_group_service = CreateGroupService()
get_group_data = create_group_service.get_service_group_info_data_by_email(self.session, email=self.email)
list_group_user = ["ALL"]
filter_list = list()
filter_list.append(CreateDict.data_type == self.data_type)
if self.team_name:
filter_list.append(CreateDict.team_name == self.team_name)
if get_group_data:
list_group_user.append(get_group_data.team_name)
get_dict_data = create_dict_service.get_dict_list_by_team_filters_page(self.session, filter_list,
list_group_user, page=1,
limit=10)
list_data = []
if get_dict_data:
for value in get_dict_data[0]:
dict_value = {}
get_data_key = value.dict_key
get_data_value = value.dict_value
dict_value["value"] = get_data_key
dict_value["label"] = get_data_value
list_data.append(dict_value)
return list_data
else:
return get_dict_data

View File

@@ -1,94 +0,0 @@
# encoding: UTF-8
from ....common.sqlSession import SqlSession
from ..service.createDataInfoService import CreateInfoService
from ..controller import commonController
from ..model.createDataInfo import CreateInfo
from logger import logger
import json
class CreateDataInfoController(object):
def __init__(self, req_json, token):
self.session = SqlSession()
self.create_data_info_id = req_json.get('create_data_info_id')
self.create_data_detail_id = req_json.get('create_data_detail_id')
self.className = req_json.get('className')
self.methodName = req_json.get('methodName')
self.request_parameter = req_json.get('request_parameter')
self.token = token
self.del_flag = 0
self.req_json = req_json
def create_info_data(self):
"""
对造数详情进行新增
:return:
"""
get_time = commonController.get_time()
get_request_parameter = json.loads(self.request_parameter)
request_parameter = self.get_method_request_parameter(create_data_info_id=self.create_data_info_id,
request_param=get_request_parameter)
get_uuid = commonController.get_uuid()
add_data = {
'create_data_info_id': get_uuid,
'create_data_detail_id': self.create_data_detail_id,
'class_name': self.className,
'method_name': self.methodName,
'request_parameter': request_parameter,
'del_flag': self.del_flag,
'created_time': get_time,
'modified_time': get_time
}
create_info_service = CreateInfoService()
create_data_info_id, err_msg = create_info_service.create_service_info_data(session=self.session,
create_info=add_data)
if err_msg:
return err_msg
def update_info_data(self):
"""
编辑请求参数信息表
:return:
"""
get_time = commonController.get_time()
get_request_parameter = json.loads(self.request_parameter)
request_parameter = self.get_method_request_parameter(create_data_info_id=self.create_data_info_id,
request_param=get_request_parameter)
edit_data_id = self.create_data_info_id
edit_data = {'class_name': self.className, 'method_name': self.methodName,
'request_parameter': request_parameter,'modified_time':get_time}
create_info_service = CreateInfoService()
err_msg = create_info_service.update_service_info_data(session=self.session, update_info=edit_data,
create_data_info_id=edit_data_id)
if err_msg:
return err_msg
def get_method_request_parameter(self, create_data_info_id, request_param):
"""
组装方法的请求参数
:param parameter:
:return:
"""
# 定义请求的json
json_data = {}
# 查询抓取的请求参数信息
create_info_service = CreateInfoService()
get_data_info = create_info_service.get_create_data_info_by_id(session=self.session, sid=create_data_info_id)
get_db_parameter = get_data_info.request_parameter
# 判断如果请求参数里面含有**kwargs组装请求
if "is_kwargs" in get_db_parameter:
json_data = request_param
else:
# 定义请求的json如果是json格式的参数则组装json
post_data_input = {}
for key, value in request_param.items():
if key in get_db_parameter.keys():
json_data[key] = value
else:
post_data_input[key] = value
if "post_data_input" in get_db_parameter:
json_data["post_data_input"] = post_data_input
return json_data

View File

@@ -1,134 +0,0 @@
# encoding: UTF-8
from ....common.sqlSession import SqlSession
from ..service.createDataNumberService import CreateNumberService
from ..service.createDataDetailService import CreateDetailService
from ..service.createDataInfoService import CreateInfoService
from ..controller import commonController
class CreateDataNumberController(object):
def __init__(self, req_json, token):
self.session = SqlSession()
self.create_data_detail_id = req_json.get('create_data_detail_id')
self.method_name = req_json.get('method_name')
self.token = token
self.del_flag = 0
self.req_json = req_json
def get_number_data(self, create_data_detail_id):
"""
根据id查询对应的次数信息
:return:
"""
create_number_service = CreateNumberService()
get_query_info = create_number_service.get_service_number_by_id(session=self.session,
create_data_detail_id=create_data_detail_id)
def create_result_data(self, add_data):
"""
对造数结果数据进行统计
:return:
"""
create_number_service = CreateNumberService()
create_data_info_id = create_number_service.create_service_number_data(session=self.session,
create_info=add_data)
return create_data_info_id
def update_number_data(self, is_right):
"""
更新造数使用次数表
"""
create_number_service = CreateNumberService()
try:
get_db_data_number, success = create_number_service.get_service_number_by_id(session=self.session,
create_data_detail_id=self.create_data_detail_id)
if success:
if get_db_data_number:
total_number = get_db_data_number.total_number
error_number = get_db_data_number.error_number
right_number = get_db_data_number.right_number
month_number = get_db_data_number.month_number
update_total_number = total_number + 1
update_data = {"total_number": update_total_number}
if is_right:
update_right_number = right_number + 1
update_month_number = month_number + 1
update_data["right_number"] = update_right_number
update_data["month_number"] = update_month_number
else:
update_error_number = error_number + 1
update_data["error_number"] = update_error_number
create_number_service = CreateNumberService()
update_data_info_id = create_number_service.update_service_number_data(
create_data_detail_id=self.create_data_detail_id, session=self.session,
update_info=update_data)
return "更新数据成功"
else:
get_uuid = commonController.get_uuid()
get_time = commonController.get_time()
if is_right:
right_number = 1
error_number = 0
month_number = 1
else:
right_number = 0
error_number = 1
month_number = 0
add_data = {
'id': get_uuid,
'create_data_detail_id': self.create_data_detail_id,
'method_name': self.method_name,
'total_number': 1,
'error_number': error_number,
'right_number': right_number,
'month_number': month_number,
'del_flag': self.del_flag,
'created_time': get_time,
'modified_time': get_time,
}
self.create_result_data(add_data=add_data)
else:
return "更新数据失败"
except:
return "更新数据失败"
def do_history_data(self):
"""
处理历史数据
:return:
"""
create_detail_service = CreateDetailService()
create_number_service = CreateNumberService()
create_data_number_id = commonController.get_uuid()
created_time = commonController.get_time()
modified_time = commonController.get_time()
get_data_detail = create_detail_service.get_all_detail_list_no_filters_page(session=self.session)
list_update_data = []
for detail_info in get_data_detail:
get_create_number = create_number_service.get_service_number_by_id(session=self.session,
create_data_detail_id=detail_info.create_data_detail_id)
if get_create_number:
list_update_data.append(detail_info.create_data_detail_id)
create_number_service.update_service_number_data(session=self.session,
update_info={"method_name": detail_info.method_name},
create_data_detail_id=detail_info.create_data_detail_id)
else:
add_data = {
"id": create_data_number_id,
"create_data_detail_id": detail_info.create_data_detail_id,
"method_name": detail_info.method_name,
"total_number": 0,
"error_number": 0,
"right_number": 0,
"del_flag": 0,
"created_time": created_time,
"modified_time": modified_time,
}
create_number_service.create_service_number_data(session=self.session, create_info=add_data)
list_update_data.append(detail_info.create_data_detail_id)
return list_update_data

View File

@@ -1,186 +0,0 @@
# encoding: UTF-8
from ....common.sqlSession import SqlSession
from ..service.createDataResultService import CreateResultService
from ..service.createDataInfoService import CreateInfoService
from ..service.createDataDetailService import CreateDetailService
from ..service.createDataGroupService import CreateGroupService
from ..controller import commonController
from ..model.createResultInfo import CreateResult
from logger import logger
import json
class CreateDataResultController(object):
def __init__(self, req_json, token):
self.session = SqlSession()
self.page = req_json.get('pageNo')
self.limit = req_json.get('pageSize')
self.create_data_result_id = req_json.get('create_data_result_id')
self.create_data_info_id = req_json.get('create_data_info_id')
self.create_data_detail_id = req_json.get('create_data_detail_id')
self.team_name = req_json.get('team_name')
self.file_name = req_json.get('file_name')
self.module_name = req_json.get('module_name')
self.class_name = req_json.get('class_name')
self.method_name = req_json.get('method_name')
self.tag = req_json.get('get_tag')
self.status = req_json.get('status')
self.method_function_detail = req_json.get('method_function_detail')
self.detail_name = req_json.get('detail_name')
self.request_parameter = req_json.get('request_parameter')
self.result_info = req_json.get('result_info')
self.creator = req_json.get('creator')
self.email = req_json.get('email')
self.token = token
self.del_flag = 0
self.req_json = req_json
def create_result_data(self, add_data):
"""
对造数结果进行新增
:return:
"""
add_data["del_flag"] = self.del_flag
create_result_service = CreateResultService()
create_data_info_id = create_result_service.create_result_data(session=self.session,
create_info=add_data)
return create_data_info_id
def update_result_data(self, sid, status, result_info):
"""
对返回结果进行编辑
"""
edit_data = {'result_info': result_info, 'status': status}
create_result_service = CreateResultService()
err_msg = create_result_service.update_service_result_data(session=self.session, update_info=edit_data,
sid=sid)
if err_msg:
return err_msg
def get_method_request_parameter(self, create_data_info_id, request_param):
"""
组装方法的请求参数
:param parameter:
:return:
"""
# 定义请求的json
json_data = {}
# 查询抓取的请求参数信息
create_info_service = CreateInfoService()
get_data_info = create_info_service.get_create_data_info_by_id(session=self.session, sid=create_data_info_id)
get_db_parameter = get_data_info.request_parameter
# 判断如果请求参数里面含有**kwargs组装请求
if "is_kwargs" in get_db_parameter:
json_data = request_param
else:
# 定义请求的json如果是json格式的参数则组装json
post_data_input = {}
for key, value in request_param.items():
if key in get_db_parameter.keys():
json_data[key] = value
else:
post_data_input[key] = value
if "post_data_input" in get_db_parameter:
json_data["post_data_input"] = post_data_input
return json_data
def get_result_query_list(self):
"""
结果列表页查询
:return:
"""
create_group_service = CreateGroupService()
if self.page is None:
self.page = 1
if self.limit is None:
self.limit = 10
create_result_service = CreateResultService()
common_controller = commonController.CommonController()
get_group_data = create_group_service.get_service_group_info_data_by_email(self.session, email=self.email)
filter_list = []
team_name = self.team_name
get_tag = self.tag
detail_name = self.detail_name
list_group_user = ["ALL"]
if team_name:
filter_list.append(CreateResult.team_name == team_name)
if detail_name:
filter_list.append(CreateResult.method_function_detail.like('%' + detail_name + '%'))
if get_tag:
filter_list.append(CreateResult.tag.like('%' + get_tag + '%'))
if filter_list:
if get_group_data:
list_group_user.append(get_group_data.team_name)
detail_list, total = create_result_service.get_result_list_by_team_filters_page(self.session, filter_list,
list_group_user,
self.page, self.limit)
else:
if get_group_data:
list_group_user.append(get_group_data.team_name)
detail_list, total = create_result_service.get_result_list_no_team_filters_page(self.session,
list_group_user, self.page,
self.limit)
ret_ls = []
for obj in detail_list:
ret_ls.append({
'create_data_result_id': obj.create_data_result_id,
'create_data_info_id': obj.create_data_info_id,
'create_data_detail_id': obj.create_data_detail_id,
'team_name': common_controller.get_team_name(obj.team_name),
'request_parameter': json.dumps(obj.request_parameter),
'result_info': obj.result_info,
'tag': obj.tag,
'class_name': obj.class_name,
'module_name': obj.module_name,
'method_name': obj.method_name,
'method_function_detail': obj.method_function_detail,
'creator': obj.creator,
'created_time': obj.created_time,
'modified_time': obj.modified_time
})
return {"list": ret_ls, "total": total}
def get_result_advance(self):
"""
关键字造数结果详情页查询
:return:
"""
create_result_service = CreateResultService()
get_data_result = create_result_service.get_create_result_by_id(session=self.session,
create_data_result_id=self.create_data_result_id)
create_detail_service = CreateDetailService()
get_detail_info = create_detail_service.get_create_detail_info_by_id(session=self.session,
create_data_detail_id=get_data_result.create_data_detail_id)
common_controller = commonController.CommonController()
try:
is_json = True
get_result = json.dumps(eval(get_data_result.result_info), ensure_ascii=False)
except:
is_json = False
get_result = get_data_result.result_info
_data = {'create_data_result_id': get_data_result.create_data_result_id,
'create_data_detail_id': get_data_result.create_data_detail_id,
'team_name': get_detail_info.team_name,
'file_name': common_controller.get_model_name(team=get_detail_info.team_name,
dict_key=get_detail_info.file_name),
'module_name': get_data_result.module_name,
'class_name': get_data_result.class_name,
'method_name': get_data_result.method_name,
'method_detail': get_detail_info.method_detail,
'request_parameter': get_data_result.request_parameter,
# 'method_function_detail': CreateDictData.query.filter_by(del_flag=0, data_type=2,
# dict_key=get_detail_info.method_name).first().dict_value,
'method_function_detail': get_detail_info.method_function_detail,
'result_info': get_result,
'creator': get_data_result.creator,
'get_tag': get_data_result.tag,
'is_json': is_json,
'created_time': get_data_result.created_time,
'modified_time': get_data_result.modified_time}
return _data

View File

@@ -1,112 +0,0 @@
# encoding: UTF-8
from ....common.sqlSession import SqlSession
from ..service.createDataDictService import CreateDictService
from ..controller import commonController
from logger import logger
from ..model.createDictInfo import CreateDict
import os
from base_framework.public_tools.eureka_api import EurekaAPI
import configparser
class ScrapyController(object):
def __init__(self, req_json, token):
self.session = SqlSession()
self.file_name = req_json.get('fileName')
self.get_team = req_json.get('team')
self.team_name = self.get_team.upper()
self.username = req_json.get('username')
self.password = req_json.get('password')
self.token = token
self.del_flag = 0
self.req_json = req_json
def scrapy_enter_db(self):
"""
对抓取的数据进行入库
:return:
"""
get_common_controller = commonController.CommonController()
create_dict_service = CreateDictService()
filter_list = list()
filter_list.append(CreateDict.dict_key == self.team_name)
filter_list.append(CreateDict.data_type == 1)
get_team_data = create_dict_service.get_dict_simple_data_by_filters(self.session, filter_list)
if get_team_data:
get_path = get_common_controller.get_keyword_path(team=self.team_name, file_name=self.file_name) # 获取路径值
print("get_path:", get_path)
team_name = self.team_name
get_team = team_name.upper()
if get_team == "ALL":
get_list_data = commonController.run(files_path=get_path, end_file="_public_business.py",
remove_file="common")
else:
get_list_data = commonController.run(files_path=get_path, end_file=".py", remove_file="")
get_scrapy_info = get_common_controller.create_all_info(team_name=self.team_name, list_detail=get_list_data)
if get_scrapy_info:
err_msg = "抓取成功"
else:
err_msg = "未成功抓取数据,请重试"
else:
err_msg = "请检查数据字典,输入正确的组名"
return err_msg
def get_git_pull(self):
"""
拉取git上的代码到本地
:return:
"""
create_dict_service = CreateDictService()
filter_list = list()
filter_list.append(CreateDict.team_name == self.team_name)
filter_list.append(CreateDict.data_type == 4)
get_dict_data = create_dict_service.get_dict_simple_data_by_filters(self.session, filter_list)
if get_dict_data:
base = get_dict_data.dict_value
else:
base = self.team_name
username = self.username
password = self.password
print(base,"----base----")
basic_path = os.path.dirname(os.path.abspath(__file__))
base_path = os.path.abspath(os.path.join(basic_path, '../../../../{}'.format("base_framework")))
team_path = os.path.abspath(os.path.join(basic_path, '../../../../{}'.format(base)))
try:
os.system(f"cd " + base_path + "&& git stash drop")
os.system(f"cd " + base_path + "&& git pull")
os.system(f"cd " + team_path + "&& git stash drop")
os.system(f"cd " + team_path + "&& git pull")
err_msg = ""
except:
err_msg = "拉取代码失败"
return err_msg
def get_eureka_ip(self):
"""
重新获取eureka_ip地址重写下ip
:return:
"""
create_dict_service = CreateDictService()
filter_list = list()
filter_list.append(CreateDict.team_name == self.team_name)
filter_list.append(CreateDict.data_type == 4)
get_dict_data = create_dict_service.get_dict_simple_data_by_filters(self.session, filter_list)
if get_dict_data:
team = get_dict_data.dict_value
else:
team = self.team_name
get_eureka = EurekaAPI()
get_eureka.team = team
upper_team = team.upper()
get_eureka.get_all_server_ip_from_eureka()
get_eureka.get_all_server_ip_from_eureka(eureka="EC")
file_path = os.path.dirname(os.path.abspath(__file__))
env_choose_path = os.path.join(file_path, "../../../../../base_config/env_choose.ini")
cof = configparser.ConfigParser()
cof.read(env_choose_path, encoding='utf-8')
cof.set(section="run_evn_name", option="current_team", value=upper_team)
with open(env_choose_path, 'w') as fw: # 循环写入
cof.write(fw)
test_vi_path = os.path.join(file_path, "test_vi.py")
os.system(f"echo 1 >> {test_vi_path}")
return True

View File

@@ -1,28 +0,0 @@
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1

View File

@@ -1,38 +0,0 @@
# encoding: UTF-8
from ....common.sqlSession import SqlSession
import requests
from base_framework.public_tools.sqlhelper import MySqLHelper
sql = MySqLHelper()
class UserController(object):
def __init__(self, req_json, token):
self.session = SqlSession()
self.username = req_json.get('username')
self.password = req_json.get('password')
self.token = token
self.del_flag = 0
self.req_json = req_json
def get_user_email(self):
"""
获取用户邮箱信息
:return:
"""
username = self.username
password = self.password
if "@" not in username:
username = username + "@sparkedu.com"
header = {"Authorization": "Basic c3BhcmtsZS13ZWI6c3BhcmtsZS13ZWI="}
session = requests.session()
session.headers.update(header)
url = "https://sso.qa.huohua.cn/uim/oauth/token/pwd?username=%s&password=%s" % (
username, password)
resp = session.post(url).json()
if resp["code"] == 200:
# user_id = resp.get("data").get('userId')
# name_dict = sql.select_one(sql='select * from emp.employee where id = "%s"' % user_id, choose_db="huohua")
return {"code": 20000, "data": resp.get("data")}
else:
return {"code": 50012, "message": "用户名密码错误"}

View File

@@ -1,139 +0,0 @@
# encoding: UTF-8
from ..model.createDetailInfo import CreateDetail
from ..model.createDataNumber import CreateDataNumber
from sqlalchemy.exc import NoResultFound
from sqlalchemy import desc
from logger import logger
class CreateDetailDao(object):
@staticmethod
def get_all_detail_list_no_filters(session):
rets = session.query(CreateDetail) \
.filter(CreateDetail.del_flag == 0) \
.order_by(CreateDetail.modified_time.desc()) \
.all()
total = session.query(CreateDetail).filter(CreateDetail.del_flag == 0).count()
return rets, total
@staticmethod
def get_detail_list_by_filters(session, filter_list, page=1, limit=20):
rets = session.query(CreateDetail) \
.filter(*filter_list).filter(CreateDetail.del_flag == 0) \
.offset((int(page) - 1) * int(limit)) \
.limit(limit) \
.all()
total = session.query(CreateDetail).filter(*filter_list).filter(CreateDetail.del_flag == 0).count()
return rets, total
@staticmethod
def get_detail_list_by_filters_by_team(session, filter_list, list_team_name, page=1, limit=10):
# rets = session.query(CreateDetail) \
# .filter(*filter_list).filter(CreateDetail.del_flag == 0) \
# .filter(CreateDetail.team_name.in_(list_team_name)) \
# .offset((int(page) - 1) * int(limit)) \
# .limit(limit) \
# .all()
rets = session.query(CreateDetail) \
.outerjoin(CreateDataNumber,
CreateDetail.create_data_detail_id == CreateDataNumber.create_data_detail_id) \
.filter(*filter_list).filter(CreateDetail.del_flag == 0) \
.order_by(desc(CreateDataNumber.month_number)) \
.offset((int(page) - 1) * int(limit)) \
.limit(limit) \
.all()
# total = session.query(CreateDetail).filter(*filter_list).filter(CreateDetail.del_flag == 0).filter(
# CreateDetail.team_name.in_(list_team_name)).count()
total = session.query(CreateDetail).filter(*filter_list).filter(CreateDetail.del_flag == 0).count()
return rets, total
@staticmethod
def get_detail_list_no_filters_by_team(session, list_team_name, page=1, limit=10):
# rets = session.query(CreateDetail) \
# .join(CreateDataNumber,
# CreateDetail.create_data_detail_id == CreateDataNumber.create_data_detail_id) \
# .filter(CreateDetail.del_flag == 0) \
# .order_by(desc(CreateDataNumber.month_number)) \
# .offset((int(page) - 1) * int(limit)) \
# .limit(limit) \
# .all()
rets = session.query(CreateDetail) \
.filter(CreateDetail.del_flag == 0) \
.order_by(CreateDetail.modified_time.desc()) \
.offset((int(page) - 1) * int(limit)) \
.limit(limit) \
.all()
total = session.query(CreateDetail).filter(CreateDetail.del_flag == 0).count()
return rets, total
@staticmethod
def get_detail_list_no_filters(session, page=1, limit=20):
rets = session.query(CreateDetail) \
.filter(CreateDetail.del_flag == 0) \
.order_by(CreateDetail.modified_time.desc()) \
.offset((int(page) - 1) * int(limit)) \
.limit(limit) \
.all()
total = session.query(CreateDetail).filter(CreateDetail.del_flag == 0).count()
return rets, total
@staticmethod
def get_detail_simple_by_filters(session, filter_list):
rets = session.query(CreateDetail) \
.filter(*filter_list).filter(CreateDetail.del_flag == 0) \
.first()
return rets
@staticmethod
def get_create_detail_info_by_id(session, sid):
try:
ret = session.query(CreateDetail).filter(CreateDetail.create_data_detail_id == sid).one()
except Exception as e:
logger.warning(f'获取造数基础信息失败: id{sid}, {e}')
return None, f'获取造数基础信息失败: id{sid}'
return ret
@staticmethod
def save_detail_info_record(session, create_info):
if not isinstance(create_info, dict):
logger.error('只支持dict类型。build_info type: {}'.format(type(create_info)))
create_detail_info = CreateDetail(**create_info)
session.add(create_detail_info)
# session.flush()
err = session.done(close=False)
create_info_id = create_detail_info.create_data_detail_id
if err:
logger.error(f'新增失败!{err}')
return 0
if not create_info_id:
logger.error(f'{create_detail_info}获取关键字id失败')
return 0
# session.commit()
return create_info_id
@staticmethod
def update_detail_info_record(session, update_info, create_data_detail_id):
create_info = session.query(CreateDetail).filter(
CreateDetail.create_data_detail_id == create_data_detail_id).update(
update_info)
err_msg = session.commit()
session.done()
if err_msg:
return '修改场景失败!'
return ""
@staticmethod
def delete_detail_info_record(session, create_data_detail_id):
build_info = session.query(CreateDetail).filter(
CreateDetail.create_data_detail_id == create_data_detail_id).all()
if build_info:
del_info = session.query(CreateDetail).filter(
CreateDetail.create_data_detail_id == create_data_detail_id).update({'del_flag': 1})
session.commit()
if not del_info:
logger.error(f'删除记录失败res: {del_info}')
return del_info
else:
logger.error(f'id{create_data_detail_id} 不存在记录!')
return f'id{create_data_detail_id} 不存在记录!'

View File

@@ -1,83 +0,0 @@
# encoding: UTF-8
from ..model.createDictInfo import CreateDict
from sqlalchemy.exc import NoResultFound
from logger import logger
class CreateDictDao(object):
@staticmethod
def get_dict_list_by_filters(session, filter_list, page=1, limit=20):
rets = session.query(CreateDict) \
.filter(*filter_list).filter(CreateDict.del_flag == 0) \
.offset((int(page) - 1) * int(limit)) \
.limit(limit) \
.all()
total = session.query(CreateDict).filter(*filter_list).filter(CreateDict.del_flag == 0).count()
return rets, total
@staticmethod
def get_dict_list_by_team_filters(session, filter_list, list_team_name, page=1, limit=20):
# rets = session.query(CreateDict) \
# .filter(*filter_list).filter(CreateDict.del_flag == 0) \
# .filter(CreateDict.team_name.in_(list_team_name)) \
# .offset((int(page) - 1) * int(limit)) \
# .limit(limit) \
# .all()
# total = session.query(CreateDict).filter(*filter_list).filter(CreateDict.del_flag == 0).filter(
# CreateDict.team_name.in_(list_team_name)).count()
rets = session.query(CreateDict) \
.filter(*filter_list).filter(CreateDict.del_flag == 0) \
.offset((int(page) - 1) * int(limit)) \
.limit(limit) \
.all()
total = session.query(CreateDict).filter(*filter_list).filter(CreateDict.del_flag == 0).count()
return rets, total
@staticmethod
def get_dict_list_no_filters(session, page=1, limit=20):
rets = session.query(CreateDict) \
.filter(CreateDict.del_flag == 0) \
.order_by(CreateDict.modified_time.desc()) \
.offset((int(page) - 1) * int(limit)) \
.limit(limit) \
.all()
total = session.query(CreateDict).filter(CreateDict.del_flag == 0).count()
return rets, total
@staticmethod
def get_dict_simple_by_filters(session, filter_list):
rets = session.query(CreateDict) \
.filter(*filter_list).filter(CreateDict.del_flag == 0) \
.first()
return rets
@staticmethod
def save_dict_info_record(session, create_info):
if not isinstance(create_info, dict):
logger.error('只支持dict类型。build_info type: {}'.format(type(create_info)))
create_dict_info = CreateDict(**create_info)
session.add(create_dict_info)
# session.flush()
err = session.done(close=False)
create_info_id = create_dict_info.create_dict_data_id
if err:
logger.error(f'新增失败!{err}')
return 0
if not create_info_id:
logger.error(f'{create_dict_info}获取关键字id失败')
return 0
# session.commit()
return create_info_id
@staticmethod
def update_dict_info_record(session, update_info, create_dict_data_id):
create_info = session.query(CreateDict).filter(
CreateDict.create_dict_data_id == create_dict_data_id).one()
create_info.team_name = update_info["team_name"]
create_info.dict_key = update_info["dict_key"]
create_info.dict_value = update_info["dict_value"]
err_msg = session.done()
if err_msg:
return '修改失败!'
return ''

View File

@@ -1,71 +0,0 @@
# encoding: UTF-8
from ..model.createDataInfo import CreateInfo
from sqlalchemy.exc import NoResultFound
from logger import logger
class CreateInfoDao(object):
@staticmethod
def get_data_info(session, filter_list):
try:
ls = session.query(CreateInfo).filter(*filter_list).filter(CreateInfo.del_flag == 0).first()
total = session.query(CreateInfo).filter(*filter_list).filter(CreateInfo.del_flag == 0).count()
except Exception as e:
logger.warning(e)
return [], '获取基础信息失败!'
return ls, total
@staticmethod
def get_data_simple_by_filters(session, filter_list):
rets = session.query(CreateInfo) \
.filter(*filter_list).filter(CreateInfo.del_flag == 0) \
.first()
return rets
@staticmethod
def get_create_data_info_by_id(session, sid):
try:
ret = session.query(CreateInfo).filter(CreateInfo.create_data_info_id == sid).one()
except Exception as e:
logger.warning(f'获取造数信息失败: id{sid}, {e}')
return None, f'获取造数信息失败: id{sid}'
return ret
@staticmethod
def get_create_data_info_by_detail_id(session, detail_id):
try:
ret = session.query(CreateInfo).filter(CreateInfo.create_data_detail_id == detail_id).one()
except Exception as e:
logger.warning(f'获取造数信息失败: id{detail_id}, {e}')
return None, f'获取造数信息失败: id{detail_id}'
return ret
@staticmethod
def save_data_info_record(session, create_info):
if not isinstance(create_info, dict):
logger.error('只支持dict类型。build_info type: {}'.format(type(create_info)))
create_data_info = CreateInfo(**create_info)
session.add(create_data_info)
# session.flush()
err = session.done(close=False)
create_info_id = create_data_info.create_data_info_id
if err:
logger.error(f'新增失败!{err}')
return 0
if not create_info_id:
logger.error(f'{create_data_info}获取关键字id失败')
return 0
# session.commit()
return create_info_id
@staticmethod
def update_data_info_record(session, update_info, create_data_info_id):
create_info = session.query(CreateInfo).filter(CreateInfo.create_data_info_id == create_data_info_id).one()
create_info.class_name = update_info['class_name']
create_info.method_name = update_info['method_name']
create_info.request_parameter = update_info['request_parameter']
err_msg = session.done()
if err_msg:
return '修改失败!'
return ''

View File

@@ -1,60 +0,0 @@
# encoding: UTF-8
from ..model.createDataNumber import CreateDataNumber
from logger import logger
class CreateNumberDao(object):
@staticmethod
def get_number_no_filters(session):
rets = session.query(CreateDataNumber) \
.filter(CreateDataNumber.del_flag == 0) \
.all()
return rets
@staticmethod
def get_number_simple_by_filters(session, filter_list):
rets = session.query(CreateDataNumber) \
.filter(*filter_list).filter(CreateDataNumber.del_flag == 0) \
.first()
return rets
@staticmethod
def get_number_info_by_id(session, create_data_detail_id):
try:
ret = session.query(CreateDataNumber).filter(
CreateDataNumber.create_data_detail_id == create_data_detail_id).first()
except Exception as e:
logger.warning(f'获取造数使用次数失败: id{create_data_detail_id}, {e}')
return f'获取造数使用次数失败: id{create_data_detail_id}', False
return ret, True
@staticmethod
def save_number_info(session, create_info):
if not isinstance(create_info, dict):
logger.error('只支持dict类型。build_info type: {}'.format(type(create_info)))
create_detail_info = CreateDataNumber(**create_info)
session.add(create_detail_info)
# session.flush()
err = session.done(close=False)
create_info_id = create_detail_info.id
if err:
logger.error(f'新增失败!{err}')
return 0
if not create_info_id:
logger.error(f'{create_detail_info}获取关键字id失败')
return 0
# session.commit()
return create_info_id
@staticmethod
def update_number_info(session, update_info, create_data_detail_id):
update_res = session.query(CreateDataNumber).filter(
CreateDataNumber.create_data_detail_id == create_data_detail_id).update(
update_info)
print(update_res, "update_res")
err_msg = session.commit()
# session.done()
if err_msg:
return '基础信息修改失败!'
return update_res

View File

@@ -1,125 +0,0 @@
# encoding: UTF-8
from sqlalchemy import func
from ..model.createResultInfo import CreateResult
from sqlalchemy.exc import NoResultFound
from logger import logger
class CreateResultDao(object):
@staticmethod
def get_result_list_by_filters(session, filter_list, page=1, limit=20):
rets = session.query(CreateResult) \
.filter(*filter_list).filter(CreateResult.del_flag == 0, CreateResult.status == 1) \
.offset((int(page) - 1) * int(limit)) \
.limit(limit) \
.all()
total = session.query(CreateResult).filter(*filter_list).filter(CreateResult.del_flag == 0,
CreateResult.status == 1).count()
return rets, total
@staticmethod
def get_result_list_by_team_filters(session, filter_list, list_team_name, page=1, limit=20):
# rets = session.query(CreateResult) \
# .filter(*filter_list).filter(CreateResult.del_flag == 0, CreateResult.status == 1) \
# .filter(CreateResult.team_name.in_(list_team_name)) \
# .offset((int(page) - 1) * int(limit)) \
# .limit(limit) \
# .all()
# total = session.query(CreateResult).filter(*filter_list).filter(CreateResult.del_flag == 0,
# CreateResult.status == 1).filter(
# CreateResult.team_name.in_(list_team_name)).count()
rets = session.query(CreateResult) \
.filter(*filter_list).filter(CreateResult.del_flag == 0, CreateResult.status == 1) \
.offset((int(page) - 1) * int(limit)) \
.limit(limit) \
.all()
total = session.query(CreateResult).filter(*filter_list).filter(CreateResult.del_flag == 0,
CreateResult.status == 1).count()
return rets, total
@staticmethod
def get_result_list_no_filters(session, page=1, limit=20):
rets = session.query(CreateResult) \
.filter(CreateResult.del_flag == 0, CreateResult.status == 1) \
.order_by(CreateResult.modified_time.desc()) \
.offset((int(page) - 1) * int(limit)) \
.limit(limit) \
.all()
total = session.query(CreateResult).filter(CreateResult.del_flag == 0, CreateResult.status == 1).count()
return rets, total
@staticmethod
def get_result_list_no_team_filters(session, list_team_name, page=1, limit=20):
# rets = session.query(CreateResult) \
# .filter(CreateResult.del_flag == 0, CreateResult.status == 1) \
# .filter(CreateResult.team_name.in_(list_team_name)) \
# .order_by(CreateResult.modified_time.desc()) \
# .offset((int(page) - 1) * int(limit)) \
# .limit(limit) \
# .all()
# total = session.query(CreateResult).filter(CreateResult.del_flag == 0, CreateResult.status == 1).filter(
# CreateResult.team_name.in_(list_team_name)).count()
rets = session.query(CreateResult) \
.filter(CreateResult.del_flag == 0, CreateResult.status == 1) \
.order_by(CreateResult.modified_time.desc()) \
.offset((int(page) - 1) * int(limit)) \
.limit(limit) \
.all()
total = session.query(CreateResult).filter(CreateResult.del_flag == 0, CreateResult.status == 1).count()
return rets, total
@staticmethod
def get_result_simple_by_filters(session, filter_list):
rets = session.query(CreateResult) \
.filter(*filter_list).filter(CreateResult.del_flag == 0) \
.first()
return rets
@staticmethod
def get_result_detail_info_by_id(session, sid):
try:
ret = session.query(CreateResult).filter(CreateResult.create_data_result_id == sid).one()
except Exception as e:
logger.warning(f'获取造数基础信息失败: id{sid}, {e}')
return None, f'获取造数基础信息失败: id{sid}'
return ret
@staticmethod
def save_result_info_record(session, create_info):
if not isinstance(create_info, dict):
logger.error('只支持dict类型。build_info type: {}'.format(type(create_info)))
create_result_info = CreateResult(**create_info)
session.add(create_result_info)
# session.flush()
err = session.done(close=False)
create_info_id = create_result_info.create_data_result_id
if err:
logger.error(f'新增失败!{err}')
return 0
if not create_info_id:
logger.error(f'{create_result_info}获取造数结果id失败')
return 0
# session.commit()
return create_info_id
@staticmethod
def update_result_record(session, update_info, sid):
create_info = session.query(CreateResult).filter(
CreateResult.create_data_result_id == sid).one()
create_info.status = update_info["status"]
create_info.result_info = update_info["result_info"]
err_msg = session.done()
if err_msg:
return '修改结果失败!'
return ''
@staticmethod
def get_result_numbers_by_month(session, create_data_detail_id, one_month_ago_str):
ret = session.query(func.count(CreateResult.create_data_detail_id).label('count')).filter(
CreateResult.created_time >= one_month_ago_str,
CreateResult.create_data_detail_id == create_data_detail_id, CreateResult.status == 1).group_by(
CreateResult.method_function_detail
).first()
return ret

View File

@@ -1,42 +0,0 @@
# encoding: UTF-8
from ..model.createGroupUser import CreateGroupUser
from logger import logger
class CreateGroupDao(object):
@staticmethod
def get_group_list_by_filters(session, filter_list, page=1, limit=20):
rets = session.query(CreateGroupUser) \
.filter(*filter_list).filter(CreateGroupUser.del_flag == 0) \
.offset((int(page) - 1) * int(limit)) \
.limit(limit) \
.all()
total = session.query(CreateGroupUser).filter(*filter_list).filter(CreateGroupUser.del_flag == 0).count()
return rets, total
@staticmethod
def get_group_list_no_filters(session, page=1, limit=20):
rets = session.query(CreateGroupUser) \
.filter(CreateGroupUser.del_flag == 0) \
.offset((int(page) - 1) * int(limit)) \
.limit(limit) \
.all()
total = session.query(CreateGroupUser).filter(CreateGroupUser.del_flag == 0).count()
return rets, total
@staticmethod
def get_group_all_data(session):
rets = session.query(CreateGroupUser).filter(CreateGroupUser.del_flag == 0).all()
return rets
@staticmethod
def get_group_detail_info_by_email(session, email):
try:
if email is not None:
ret = session.query(CreateGroupUser).filter(CreateGroupUser.email == email).one()
else:
return None
except Exception as e:
logger.warning(f'获取组名失败: id{email}, {e}')
return None
return ret

View File

@@ -1,23 +0,0 @@
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, TIMESTAMP, text, JSON
from ....common.sqlSession import to_dict
Base = declarative_base()
Base.to_dict = to_dict
class CreateInfo(Base):
__tablename__ = 'create_data_info'
create_data_info_id = Column(String(120), primary_key=True, comment='传入参数的id')
create_data_detail_id = Column(String(120), unique=True, comment='基础信息的id')
class_name = Column(String(120), unique=True, comment='类名称')
method_name = Column(String(120), unique=True, comment='方法名称')
request_parameter = Column(JSON, unique=True, comment='请求参数')
del_flag = Column(Integer, unique=True, comment='0未删除1已删除')
created_time = Column(TIMESTAMP, server_default=text('CURRENT_TIMESTAMP'), comment='创建时间')
modified_time = Column(TIMESTAMP, server_default=text('CURRENT_TIMESTAMP'),
server_onupdate=text('CURRENT_TIMESTAMP'), comment='更新时间')
def __repr__(self):
return '<create_data_info %r>' % self.create_data_info_id

View File

@@ -1,23 +0,0 @@
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, TIMESTAMP, text
from ....common.sqlSession import to_dict
Base = declarative_base()
Base.to_dict = to_dict
class CreateDataNumber(Base):
__tablename__ = 'create_data_number'
id = Column(String(100), primary_key=True, comment='次数的id')
create_data_detail_id = Column(String(100), primary_key=True, comment='数据字典的id')
method_name = Column(String(120), unique=True, comment='方法名称')
total_number = Column(Integer, unique=True, comment='方法总使用次数')
error_number = Column(Integer, unique=True, comment='方法使用的错误次数')
right_number = Column(Integer, unique=True, comment='方法使用的正确次数')
month_number = Column(Integer, unique=True, comment='方法使用的最近一个月次数')
del_flag = Column(Integer, unique=True, comment='0未删除1已删除')
created_time = Column(String(100), unique=True, comment='创建时间')
modified_time = Column(String(100), unique=True, comment='更新时间')
def __repr__(self):
return '<id %r>' % self.id

View File

@@ -1,28 +0,0 @@
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, TIMESTAMP, text
from ....common.sqlSession import to_dict
Base = declarative_base()
Base.to_dict = to_dict
class CreateDetail(Base):
__tablename__ = 'create_data_detail'
create_data_detail_id = Column(String(120), primary_key=True, comment='基础信息的id')
team_name = Column(String(100), unique=True, comment='组名(项目名)')
file_name = Column(String(100), unique=True, comment='文件夹名称')
module_name = Column(String(100), unique=True, comment='模块名称')
class_name = Column(String(120), unique=True, comment='类名称')
method_name = Column(String(120), unique=True, comment='方法名称')
method_function_detail = Column(String(5000), unique=True, comment='方法简单说明')
method_detail = Column(String(5000), unique=True, comment='方法描述')
creator = Column(String(100), unique=True, comment='责任人')
status = Column(Integer, unique=True, comment='状态:0未审核1创建失败')
del_flag = Column(Integer, unique=True, comment='0未删除1已删除')
created_time = Column(TIMESTAMP, server_default=text('CURRENT_TIMESTAMP'), comment='创建时间')
modified_time = Column(TIMESTAMP, server_default=text('CURRENT_TIMESTAMP'),
server_onupdate=text('CURRENT_TIMESTAMP'), comment='更新时间')
def __repr__(self):
return '<create_data_detail_id %r>' % self.create_data_detail_id

View File

@@ -1,23 +0,0 @@
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, TIMESTAMP, text
from ....common.sqlSession import to_dict
Base = declarative_base()
Base.to_dict = to_dict
class CreateDict(Base):
__tablename__ = 'create_dict_data'
create_dict_data_id = Column(String(120), primary_key=True, comment='数据字典的id')
data_type = Column(Integer, unique=True, comment='1路径 2对应名称')
team_name = Column(String(100), unique=True, comment='业务线名称')
dict_key = Column(String(100), unique=True, comment='字典的key')
dict_value = Column(String(255), unique=True, comment='字典的value')
del_flag = Column(Integer, unique=True, comment='0未删除1已删除')
created_time = Column(TIMESTAMP, server_default=text('CURRENT_TIMESTAMP'), comment='创建时间')
modified_time = Column(TIMESTAMP, server_default=text('CURRENT_TIMESTAMP'),
server_onupdate=text('CURRENT_TIMESTAMP'), comment='更新时间')
def __repr__(self):
return '<create_dict_data_id %r>' % self.create_dict_data_id

View File

@@ -1,19 +0,0 @@
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, TIMESTAMP, text
from ....common.sqlSession import to_dict
Base = declarative_base()
Base.to_dict = to_dict
class CreateGroupUser(Base):
__tablename__ = 'create_group_user'
id = Column(Integer, primary_key=True, comment='用户的id')
email = Column(String(100), unique=True, comment='邮箱')
team_name = Column(String(100), unique=True, comment='组名')
name = Column(String(100), unique=True, comment='用户名称')
del_flag = Column(Integer, unique=True, comment='0未删除1已删除')
def __repr__(self):
return '<id %r>' % self.id

View File

@@ -1,31 +0,0 @@
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, TIMESTAMP, text, JSON
from ....common.sqlSession import to_dict
Base = declarative_base()
Base.to_dict = to_dict
class CreateResult(Base):
__tablename__ = 'create_data_result'
create_data_result_id = Column(String(120), primary_key=True, comment='执行结果的id')
create_data_info_id = Column(String(120), unique=True, comment='传入参数的id')
create_data_detail_id = Column(String(120), unique=True, comment='基础信息的id')
request_parameter = Column(JSON, unique=True, comment='请求参数')
result_info = Column(JSON, unique=True, comment='造数结果')
team_name = Column(String(100), unique=True, comment='组名(项目名)')
module_name = Column(String(100), unique=True, comment='模块名称')
class_name = Column(String(120), unique=True, comment='类名称')
file_name = Column(String(255), unique=True, comment='文件名称')
method_name = Column(String(120), unique=True, comment='方法名称')
tag = Column(String(1000), unique=True, comment='标签')
status = Column(Integer, unique=True, comment='状态')
method_function_detail = Column(String(5000), unique=True, comment='方法描述')
del_flag = Column(Integer, unique=True, comment='0未删除1已删除')
creator = Column(String(100), unique=True, comment='创建人')
created_time = Column(TIMESTAMP, server_default=text('CURRENT_TIMESTAMP'), comment='创建时间')
modified_time = Column(TIMESTAMP, server_default=text('CURRENT_TIMESTAMP'),
server_onupdate=text('CURRENT_TIMESTAMP'), comment='更新时间')
def __repr__(self):
return '<create_data_result_id %r>' % self.create_data_result_id

View File

@@ -1,61 +0,0 @@
# encoding: UTF-8
from ..dao.createDataDetailDao import CreateDetailDao
class CreateDetailService(object):
def __init__(self):
pass
@staticmethod
def get_all_detail_list_no_filters_page(session):
scene_list, total = CreateDetailDao.get_all_detail_list_no_filters(session)
return scene_list, total
@staticmethod
def get_detail_list_no_filters_page(session, page, limit):
scene_list, total = CreateDetailDao.get_detail_list_no_filters(session, page=page, limit=limit)
return scene_list, total
@staticmethod
def get_detail_list_by_filters_page(session, filter_list, page, limit):
ret, err_msg = CreateDetailDao.get_detail_list_by_filters(session, filter_list, page=page, limit=limit)
return ret, err_msg
@staticmethod
def get_detail_list_by_filters_team_page(session, filter_list, list_team_name, page, limit):
ret, err_msg = CreateDetailDao.get_detail_list_by_filters_by_team(session, filter_list,
list_team_name=list_team_name,
page=page, limit=limit)
return ret, err_msg
@staticmethod
def get_detail_list_no_filters_team_page(session, list_team_name, page, limit):
scene_list, total = CreateDetailDao.get_detail_list_no_filters_by_team(session, list_team_name=list_team_name,
page=page, limit=limit)
return scene_list, total
@staticmethod
def get_detail_simple_data_by_filters(session, filter_list):
ret = CreateDetailDao.get_detail_simple_by_filters(session, filter_list)
return ret
@staticmethod
def get_create_detail_info_by_id(session, create_data_detail_id):
err_msg = CreateDetailDao.get_create_detail_info_by_id(session, create_data_detail_id)
return err_msg
@staticmethod
def create_service_detail_data(session, create_info):
ret = CreateDetailDao.save_detail_info_record(session, create_info)
return ret
@staticmethod
def update_service_detail_data(session, update_info, create_data_detail_id):
err_msg = CreateDetailDao.update_detail_info_record(session, update_info, create_data_detail_id)
return err_msg
@staticmethod
def delete_service_detail_data(session, create_data_detail_id):
bf_dao = CreateDetailDao()
del_info = bf_dao.delete_detail_info_record(session, create_data_detail_id)
return del_info

View File

@@ -1,38 +0,0 @@
# encoding: UTF-8
from ..dao.createDataDictDao import CreateDictDao
class CreateDictService(object):
def __init__(self):
pass
@staticmethod
def get_dict_list_no_filters_page(session, page, limit):
scene_list, total = CreateDictDao.get_dict_list_no_filters(session, page=page, limit=limit)
return scene_list, total
@staticmethod
def get_dict_list_by_filters_page(session, filter_list, page, limit):
ret, total = CreateDictDao.get_dict_list_by_filters(session, filter_list, page=page, limit=limit)
return ret, total
@staticmethod
def get_dict_list_by_team_filters_page(session, filter_list, list_team_name, page, limit):
ret, total = CreateDictDao.get_dict_list_by_team_filters(session, filter_list, list_team_name, page=page,
limit=limit)
return ret, total
@staticmethod
def get_dict_simple_data_by_filters(session, filter_list):
ret = CreateDictDao.get_dict_simple_by_filters(session, filter_list)
return ret
@staticmethod
def create_service_dict_data(session, create_info):
ret = CreateDictDao.save_dict_info_record(session, create_info)
return ret
@staticmethod
def update_service_dict_data(session, update_info, create_dict_data_id):
err_msg = CreateDictDao.update_dict_info_record(session, update_info, create_dict_data_id)
return err_msg

View File

@@ -1,22 +0,0 @@
# encoding: UTF-8
from ..dao.createGroupUserDao import CreateGroupDao
class CreateGroupService(object):
def __init__(self):
pass
@staticmethod
def get_service_group_list_no_filters_page(session, page, limit):
scene_list, total = CreateGroupDao.get_group_list_no_filters(session, page=page, limit=limit)
return scene_list, total
@staticmethod
def get_service_group_list_all_data(session):
scene_list = CreateGroupDao.get_group_all_data(session)
return scene_list
@staticmethod
def get_service_group_info_data_by_email(session, email):
scene_list = CreateGroupDao.get_group_detail_info_by_email(session, email)
return scene_list

View File

@@ -1,37 +0,0 @@
# encoding: UTF-8
from ..dao.createDataInfoDao import CreateInfoDao
class CreateInfoService(object):
def __init__(self):
pass
@staticmethod
def get_service_info_data(session,filter_list):
ret, err_msg = CreateInfoDao.get_data_info(session,filter_list)
return ret, err_msg
@staticmethod
def get_data_simple_data_by_filters(session, filter_list):
ret = CreateInfoDao.get_data_simple_by_filters(session, filter_list)
return ret
@staticmethod
def get_create_data_info_by_id(session, sid):
scene_obj = CreateInfoDao.get_create_data_info_by_id(session, sid)
return scene_obj
@staticmethod
def get_create_data_info_by_detail_id(session, detail_id):
scene_obj = CreateInfoDao.get_create_data_info_by_detail_id(session, detail_id)
return scene_obj
@staticmethod
def create_service_info_data(session, create_info):
ret = CreateInfoDao.save_data_info_record(session, create_info)
return ret
@staticmethod
def update_service_info_data(session, update_info,create_data_info_id):
err_msg = CreateInfoDao.update_data_info_record(session,update_info,create_data_info_id)
return err_msg

View File

@@ -1,32 +0,0 @@
# encoding: UTF-8
from ..dao.createDataNumberDao import CreateNumberDao
class CreateNumberService(object):
def __init__(self):
pass
@staticmethod
def get_service_number_all_no_filters(session):
ret = CreateNumberDao.get_number_no_filters(session)
return ret
@staticmethod
def get_service_number_simple_by_filters(session, filter_list):
ret = CreateNumberDao.get_number_simple_by_filters(session, filter_list)
return ret
@staticmethod
def get_service_number_by_id(session, create_data_detail_id):
err_msg, success = CreateNumberDao.get_number_info_by_id(session, create_data_detail_id)
return err_msg, success
@staticmethod
def create_service_number_data(session, create_info):
ret = CreateNumberDao.save_number_info(session, create_info)
return ret
@staticmethod
def update_service_number_data(session, update_info, create_data_detail_id):
err_msg = CreateNumberDao.update_number_info(session, update_info, create_data_detail_id)
return err_msg

View File

@@ -1,55 +0,0 @@
# encoding: UTF-8
from ..dao.createDataResultDao import CreateResultDao
class CreateResultService(object):
def __init__(self):
pass
@staticmethod
def get_result_list_no_filters_page(session, page, limit):
scene_list, total = CreateResultDao.get_result_list_no_filters(session, page=page, limit=limit)
return scene_list, total
@staticmethod
def get_result_list_no_team_filters_page(session, list_team_name, page, limit):
scene_list, total = CreateResultDao.get_result_list_no_team_filters(session, list_team_name, page=page,
limit=limit)
return scene_list, total
@staticmethod
def get_result_list_by_filters_page(session, filter_list, page, limit):
ret, err_msg = CreateResultDao.get_result_list_by_filters(session, filter_list, page=page, limit=limit)
return ret, err_msg
@staticmethod
def get_result_list_by_team_filters_page(session, filter_list, list_team_name, page, limit):
ret, err_msg = CreateResultDao.get_result_list_by_team_filters(session, filter_list,
list_team_name=list_team_name,
page=page, limit=limit)
return ret, err_msg
@staticmethod
def get_result_simple_data_by_filters(session, filter_list):
ret = CreateResultDao.get_result_simple_by_filters(session, filter_list)
return ret
@staticmethod
def get_create_result_by_id(session, create_data_result_id):
err_msg = CreateResultDao.get_result_detail_info_by_id(session, create_data_result_id)
return err_msg
@staticmethod
def create_result_data(session, create_info):
ret = CreateResultDao.save_result_info_record(session, create_info)
return ret
@staticmethod
def update_service_result_data(session, update_info, sid):
err_msg = CreateResultDao.update_result_record(session, update_info, sid)
return err_msg
@staticmethod
def get_service_result_numbers_by_month(session, create_data_detail_id, one_month_ago_str):
err_msg = CreateResultDao.get_result_numbers_by_month(session, create_data_detail_id, one_month_ago_str)
return err_msg

View File

@@ -1,593 +0,0 @@
# encoding: UTF-8
from flask import Blueprint, request
from ...common.apiResponse import ApiResponse
from .controller.createDataInfoController import CreateDataInfoController
from .controller.createDataDetailController import CreateDataDetailController
from .controller.createDataDictController import CreateDataDictController
from .controller.createDataResultController import CreateDataResultController
from .controller.commonController import CommonController
from .controller.scrapyController import ScrapyController
from .controller.userController import UserController
api = Blueprint('api', __name__)
@api.route('/add/info/data', methods=['POST'])
def add_info_data():
"""新增造数请求参数数据
@@@
### 参数
| 参数名 | 是否必传 | 请求类型 |参数类型 | 参数描述 |
|-------|---------|--------|--------|----------|
| create_data_info_id | true | query | int | 基本信息的id |
| create_data_detail_id | true | query | int | 详细信息的id |
| className | true | query | string | 类名 |
| methodName | true | query | string | 方法名 |
| request_parameter | true | query | string | 请求参数 |
### 请求
```json
{"create_data_info_id":"","create_data_detail_id":102222,"className":"","methodName":"","request_parameter":{}}
```
### 响应
```json
{"code": x, "message": "x", "data":true,"success":}
```
@@@
"""
req_json = request.get_json()
access_token = request.headers['accesstoken']
controller = CreateDataInfoController(req_json, access_token)
ret = controller.create_info_data()
if ret:
return ApiResponse.build_failure(5000, data=ret)
return ApiResponse.build_success(20000, data=True)
@api.route('/edit/info/data', methods=['POST'])
def edit_info_data():
"""编辑造数请求参数数据
@@@
### 参数
| 参数名 | 是否必传 | 请求类型 |参数类型 | 参数描述 |
|-------|---------|--------|--------|----------|
| create_data_info_id | true | query | int | 基本信息的id |
| create_data_detail_id | true | query | int | 详细信息的id |
| className | true | query | string | 类名 |
| methodName | true | query | string | 方法名 |
| request_parameter | true | query | string | 请求参数 |
### 请求
```json
{"create_data_info_id":"","create_data_detail_id":102222,"className":"","methodName":"","request_parameter":{}}
```
### 响应
```json
{"code": x, "message": "x ", "data":true,"success":}
```
@@@
"""
req_json = request.get_json()
access_token = request.headers['accesstoken']
controller = CreateDataInfoController(req_json, access_token)
ret = controller.update_info_data()
if ret:
return ApiResponse.build_failure(5000, data=ret)
return ApiResponse.build_success(20000, data=True)
@api.route('/delete/detail/data', methods=['POST'])
def delete_detail_data():
"""删除造数详情数据
@@@
### 参数
| 参数名 | 是否必传 | 请求类型 |参数类型 | 参数描述 |
|-------|---------|--------|--------|----------|
| create_data_detail_id | true | query | int | 详细信息的id |
### 请求
```json
{"create_data_detail_id":102222}
```
### 响应
```json
{"code": x, "message": "删除成功", "data":true,"success":}
```
@@@
"""
req_json = request.get_json()
access_token = request.headers['accesstoken']
controller = CreateDataDetailController(req_json, access_token)
ret = controller.delete_detail_data()
return ApiResponse.build_success(20000, data=ret)
@api.route('/create/data/detail/list', methods=['POST'])
def get_keywors_detail_list():
"""查询造数关键字基本信息列表页数据
@@@
### 参数
| 参数名 | 是否必传 | 请求类型 |参数类型 | 参数描述 |
|-------|---------|--------|--------|----------|
| pageNo | true | query | int | 基本信息的id |
| pageSize | true | query | int | 详细信息的id |
| detail_name | true | query | string | 基本描述信息 |
| team_name | true | query | string | 业务线 |
| file_name | true | query | string | 业务对应业务线名称 |
| module_name | true | query | string | 模块名称 |
### 请求
```json
{"pageNo":1,"pageSize":10,"dict_value":"","team_name":""}
```
### 响应
```json
{"code": x, "message": "x", "data":list[{},{}],"success":}
```
@@@
"""
req_json = request.get_json()
accesstoken = request.headers['accesstoken']
controller = CreateDataDetailController(req_json, accesstoken)
ret = controller.get_detail_query_advance()
return ApiResponse.build_success(20000, data=ret)
@api.route('/create/data/detail/advance', methods=['POST'])
def get_keywors_detail_advance():
"""查询造数关键字基本信息详情页数据
@@@
### 参数
| 参数名 | 是否必传 | 请求类型 |参数类型 | 参数描述 |
|-------|---------|--------|--------|----------|
| create_data_detail_id | true | query | int | 基本信息的id |
### 请求
```json
{"create_data_detail_id":123}
```
### 响应
```json
{"code": x, "message": "x", "data":{},"success":True}
```
@@@
"""
req_json = request.get_json()
accesstoken = request.headers['accesstoken']
controller = CreateDataDetailController(req_json, accesstoken)
ret = controller.get_detail_advance()
return ApiResponse.build_success(20000, data=ret)
@api.route('/keyword/run', methods=['POST'])
def run_keywords():
"""执行造数
@@@
### 参数
| 参数名 | 是否必传 | 请求类型 |参数类型 | 参数描述 |
|-------|---------|--------|--------|----------|
| create_data_info_id | true | query | string | 基本信息的id |
| create_data_detail_id | true | query | string | 详细信息的id |
| dict_key | true | query | string | 组名 |
| get_tag | true | query | string | 标签,备注说明 |
| request_parameter | true | query | string | 请求参数 |
### 请求
```json
{"create_data_info_id":"12","create_data_detail_id":"13","dict_key":"StudentEvent","get_tag":"get_student_classroom","request_parameter":""}
```
### 响应
```json
{"code": x, "message": "x", "success":}
```
@@@
"""
req_json = request.get_json()
access_token = request.headers['accesstoken']
controller = CreateDataDetailController(req_json, access_token)
data = controller.run_keyword_data()
if data.get("message") == "造数成功":
return ApiResponse.build_success(20000, message="造数成功", data=data.get("data"))
return ApiResponse.build_failure(40012, msg=data.get("message"))
@api.route('/create/data/result/list', methods=['POST'])
def get_keywors_result_list():
"""查询造数关键字造数结果列表页数据
@@@
### 参数
| 参数名 | 是否必传 | 请求类型 |参数类型 | 参数描述 |
|-------|---------|--------|--------|----------|
| pageNo | true | query | int | 页码 |
| pageSize | true | query | int | 页码规格 |
| detail_name | true | query | string | 详细描述信息 |
| team_name | true | query | string | 业务线 |
| get_tag | true | query | string | 标签,备注 |
### 请求
```json
{"pageNo":1,"pageSize":10,"detail_name":"","team_name":"","get_tag":""}
```
### 响应
```json
{"code": x, "message": "x", "data":list[{},{}],"success":}
```
@@@
"""
req_json = request.get_json()
accesstoken = request.headers['accesstoken']
controller = CreateDataResultController(req_json, accesstoken)
ret = controller.get_result_query_list()
return ApiResponse.build_success(20000, data=ret)
@api.route('/create/data/result/advance', methods=['POST'])
def get_keywors_result_advance():
"""查询造数结果的详情信息
@@@
### 参数
| 参数名 | 是否必传 | 请求类型 |参数类型 | 参数描述 |
|-------|---------|--------|--------|----------|
| create_data_result_id | true | query | int | 基本信息的id |
### 请求
```json
{"create_data_result_id":123}
```
### 响应
```json
{"code": x, "message": "x", "data":{},"success":True}
```
@@@
"""
req_json = request.get_json()
accesstoken = request.headers['accesstoken']
controller = CreateDataResultController(req_json, accesstoken)
ret = controller.get_result_advance()
return ApiResponse.build_success(20000, data=ret)
@api.route('/add/dict/data', methods=['POST'])
def edit_dict_data():
"""编辑造数关键字进行的映射
@@@
### 参数
| 参数名 | 是否必传 | 请求类型 |参数类型 | 参数描述 |
|-------|---------|--------|--------|----------|
| create_dict_data_id | true | query | int | 基本信息的id |
| data_type | true | query | int | 详细信息的id |
| dict_key | true | query | string | 映射的key |
| dict_value | true | query | string | 字段映射对应的名称 |
| team_name | true | query | string | 组名 |
| created_time | true | query | string | 创建时间 |
| modified_time | true | query | string | 修改时间 |
### 请求
```json
{"create_dict_data_id":"e757b5cd-cec5-11ed-ae4a-c8b29bebcb51","team_name":"用户","data_type":3,"dict_key":"common","dict_value":"公共","created_time":"202303301440","modified_time":"202304111341"}
```
### 响应
```json
{"code": x, "message": "x", "data":list[{},{}],"success":}
```
@@@
"""
req_json = request.get_json()
accesstoken = request.headers['accesstoken']
controller = CreateDataDictController(req_json, accesstoken)
ret = controller.update_dict_data()
return ApiResponse.build_success(20000, data=ret)
@api.route('/dict/data/page', methods=['POST'])
def get_dict_data_list():
"""查询造数关键字配置列表
@@@
### 参数
| 参数名 | 是否必传 | 请求类型 |参数类型 | 参数描述 |
|-------|---------|--------|--------|----------|
| pageNo | true | query | int | 基本信息的id |
| pageSize | true | query | int | 详细信息的id |
| dict_value | true | query | string | 配置值 |
| team_name | true | query | string | 业务线 |
### 请求
```json
{"pageNo":1,"pageSize":10,"detail_name":"","team_name":"","file_name":"","module_name":""}
```
### 响应
```json
{"code": x, "message": "x", "data":list[{},{}],"success":}
```
@@@
"""
req_json = request.get_json()
accesstoken = request.headers['accesstoken']
controller = CreateDataDictController(req_json, accesstoken)
ret = controller.get_dict_list_data()
return ApiResponse.build_success(20000, data=ret)
@api.route('/get/pull/git', methods=['POST'])
def get_new_git_info():
"""获取git上的最新代码到本地
@@@
### 参数
| 参数名 | 是否必传 | 请求类型 |参数类型 | 参数描述 |
|-------|---------|--------|--------|----------|
| fileName | true | query | string | 传入需要抓取的文件名称 |
| team | true | query | string | 业务线名称 |
| username | true | query | string | git地址用户名 |
| password | true | query | string | git地址密码 |
### 请求
```json
{"team":"USER","fileName":"","username":"","password":""}
```
### 响应
```json
{"code": x, "message": "x", "success":}
```
@@@
"""
req_json = request.get_json()
# accesstoken = request.headers['accesstoken']
accesstoken = "22233"
controller = ScrapyController(req_json, accesstoken)
ret = controller.get_git_pull()
return ApiResponse.build_success(20000, data=ret)
@api.route('/get/eureka', methods=['POST'])
def get_eureka_ip():
"""更新eureka上的ip地址
@@@
### 参数
| 参数名 | 是否必传 | 请求类型 |参数类型 | 参数描述 |
|-------|---------|--------|--------|----------|
| team | true | query | string | 业务线名称 |
### 请求
```json
{"team":"USER"}
```
### 响应
```json
{"code": x, "message": "x", "success":}
```
@@@
"""
req_json = request.get_json()
accesstoken = request.headers['accesstoken']
controller = ScrapyController(req_json, accesstoken)
ret = controller.get_eureka_ip()
return ApiResponse.build_success(20000, data=ret)
@api.route('/create/data/detail/scrapy', methods=['POST'])
def scrapy_entery_db():
"""查找出全部的可用方法与描述进行录库
@@@
### 参数
| 参数名 | 是否必传 | 请求类型 |参数类型 | 参数描述 |
|-------|---------|--------|--------|----------|
| fileName | true | query | string | 传入需要抓取的文件名称 |
| team | true | query | string | 业务线名称 |
| username | true | query | string | git地址用户名 |
| password | true | query | string | git地址密码 |
### 请求
```json
{"team":"USER","fileName":"","username":"","password":""}
```
### 响应
```json
{"code": x, "message": "x", "success":}
```
@@@
"""
req_json = request.get_json()
# accesstoken = request.headers['accesstoken']
accesstoken = "123"
controller = ScrapyController(req_json, accesstoken)
ret = controller.scrapy_enter_db()
if ret != "抓取成功":
return ApiResponse.build_failure(40012, msg=ret)
return ApiResponse.build_success(20000, message=ret)
@api.route('/get/team/name', methods=['POST'])
def get_team_name():
"""获取各个业务线的数据字典,用于查询
@@@
### 参数
| 参数名 | 是否必传 | 请求类型 |参数类型 | 参数描述 |
|-------|---------|--------|--------|----------|
| data_type | true | query | int | 类型 |
| team_name | true | query | string | 组名 |
### 请求
```json
{"data_type":2,"team_name":""}
```
### 响应
```json
{"code": x, "message": "x", "data":"","success":}
```
@@@
"""
req_json = request.get_json()
accesstoken = request.headers['accesstoken']
controller = CreateDataDictController(req_json, accesstoken)
ret = controller.get_team_name()
return ApiResponse.build_success(20000, data=ret)
@api.route('/create/data/detail/delete', methods=['POST'])
def delete_data_detail():
"""删除造数关键字基本信息
@@@
### 参数
| 参数名 | 是否必传 | 请求类型 |参数类型 | 参数描述 |
|-------|---------|--------|--------|----------|
| create_data_detail_id | true | query | int | 基本信息的id |
### 请求
```json
{"create_data_detail_id":""}
```
### 响应
```json
{"code": x, "message": "x", "data":true,"success":}
```
@@@
"""
req_json = request.get_json()
accesstoken = request.headers['accesstoken']
controller = CreateDataDetailController(req_json, accesstoken)
ret = controller.delete_detail_data()
return ApiResponse.build_success(20000, data=ret)
@api.route('/create/data/info/add', methods=['POST'])
def add_keywors_data():
"""增加造数关键字的请求参数
@@@
### 参数
| 参数名 | 是否必传 | 请求类型 |参数类型 | 参数描述 |
|-------|---------|--------|--------|----------|
| create_data_info_id | true | query | string | 基本信息的id |
| create_data_detail_id | true | query | string | 详细信息的id |
| className | true | query | string | 类名 |
| methodName | true | query | string | 方法名 |
| request_parameter | true | query | string | 请求参数 |
### 请求
```json
{"create_data_info_id":"12","create_data_detail_id":"13","className":"StudentEvent","methodName":"get_student_classroom","request_parameter":""}
```
### 响应
```json
{"code": x, "message": "x", "success":}
```
@@@
"""
req_json = request.get_json()
accesstoken = request.headers['accesstoken']
controller = CreateDataInfoController(req_json, accesstoken)
err_msg = controller.create_info_data()
if err_msg:
return ApiResponse.build_failure(40012, msg=err_msg)
return ApiResponse.build_success(20000)
@api.route('/create/data/info/list', methods=['POST'])
def get_keywors_data_list():
"""查询造数关键字请求列表页数据
@@@
### 参数
| 参数名 | 是否必传 | 请求类型 |参数类型 | 参数描述 |
|-------|---------|--------|--------|----------|
| create_data_info_id | true | query | string | 基本信息的id |
| create_data_detail_id | true | query | string | 详细信息的id |
| className | true | query | string | 类名 |
| methodName | true | query | string | 方法名 |
| request_parameter | true | query | string | 请求参数 |
### 请求
```json
{"create_data_info_id":"12","create_data_detail_id":"13","className":"StudentEvent","methodName":"get_student_classroom","request_parameter":""}
```
### 响应
```json
{"code": x, "message": "x", "success":}
```
@@@
"""
req_json = request.get_json()
accesstoken = request.headers['accesstoken']
controller = CreateDataInfoController(req_json, accesstoken)
ret = controller.create_info_data()
return ApiResponse.build_success(20000, data=ret)
@api.route('/Login', methods=['POST'])
def get_user_login():
"""判断登录,根据登录信息获取邮箱
@@@
### 参数
| 参数名 | 是否必传 | 请求类型 |参数类型 | 参数描述 |
|-------|---------|--------|--------|----------|
| username | true | query | string | 用户名 |
| password | true | query | string | 密码 |
### 请求
```json
{"username":2,"password":""}
```
### 响应
```json
{"code": x, "message": "x", "data":"","success":}
```
@@@
"""
req_json = request.get_json()
accesstoken = request.headers['accesstoken']
controller = UserController(req_json, accesstoken)
ret = controller.get_user_email()
if ret.get("code") != 20000:
return ApiResponse.build_failure(40012, msg=ret.get("message"))
return ApiResponse.build_success(20000, data=ret.get("data"))
@api.route('/create/data/detail/approve', methods=['POST'])
def approve_detail_info():
"""对关键字进行审核
@@@
### 参数
| 参数名 | 是否必传 | 请求类型 |参数类型 | 参数描述 |
|-------|---------|--------|--------|----------|
| create_data_detail_id | true | query | int | 基本信息的id |
### 请求
```json
{"create_data_detail_id":123}
```
### 响应
```json
{"code": x, "message": "x", "data":{},"success":True}
```
@@@
"""
req_json = request.get_json()
accesstoken = request.headers['accesstoken']
controller = CreateDataDetailController(req_json, accesstoken)
ret = controller.approve_detail_status()
if ret.get("code") != 20000:
return ApiResponse.build_failure(40012, msg=ret.get("message"))
return ApiResponse.build_success(20000, data=ret)
@api.route('/update/month/use/number', methods=['GET'])
def update_month_use_number():
"""每月使用次数更新,定时任务
@@@
### 参数
| 参数名 | 是否必传 | 请求类型 |参数类型 | 参数描述 |
|-------|---------|--------|--------|----------|
### 请求
```json
```
### 响应
```json
{"code": x, "message": "x", "data":{},"success":True}
```
@@@
"""
controller = CommonController()
ret = controller.daily_task_update_month_number()
if ret.get("code") != 20000:
return ApiResponse.build_failure(40012, msg=ret.get("message"))
return ApiResponse.build_success(20000, data=ret)

View File

@@ -1,54 +0,0 @@
# encoding: UTF-8
from flask import make_response
import json
from ..const import RES_CODE
class ApiResponse(object):
def __init__(self):
self.success = False
self.code = ''
self.message = ''
self.data = {}
@staticmethod
def build_success(code=20000, message='', data=None):
if data is None:
data = {}
response = ApiResponse()
response.success = True
response.code = code
response.message = message
response.data = data
return response.cors_response(make_response(json.dumps(response, default=obj_2_json)))
@staticmethod
def build_failure(code, msg='', data=None):
response = ApiResponse()
if data is None:
data = {}
if not msg:
response.message = RES_CODE[code]
else:
response.message = msg
response.success = False
response.code = code
response.data = data
return response.cors_response(make_response(json.dumps(response, default=obj_2_json)))
@staticmethod
def cors_response(res):
res.headers['Access-Control-Allow-Origin'] = '*'
res.headers['Access-Control-Allow-Methods'] = 'POST'
res.headers['Access-Control-Allow-Headers'] = 'x-requested-with,content-type'
return res
def obj_2_json(obj):
return {
'success': obj.success,
'code': obj.code,
'message': obj.message,
'data': obj.data
}

View File

@@ -1,35 +0,0 @@
from ..const import CREATE_URI
from ..common.getRequest import Request
class CronRequest(object):
def __init__(self, token):
self.stress_api = CREATE_URI
self.headers = {'accesstoken': token, 'Accept': '*/*', 'content-type': 'application/json;charset=UTF-8'}
def create(self, params):
url = self.stress_api + '/back-end/stress/schedule/save'
ret = Request.go('post', url, params, self.headers)
if not ret:
return
return ret.get('id')
def pause(self, jid):
url = self.stress_api + '/back-end/stress/schedule/pause'
params = [jid]
Request.go('post', url, params, self.headers)
def resume(self, jid):
url = self.stress_api + '/back-end/stress/schedule/resume'
params = [jid]
Request.go('post', url, params, self.headers)
def remove(self, jid):
url = self.stress_api + '/back-end/stress/schedule/delete'
params = [jid]
Request.go('post', url, params, self.headers)
def update(self, req_params):
url = self.stress_api + '/back-end/stress/schedule/update'
Request.go('post', url, req_params, self.headers)

View File

@@ -1,16 +0,0 @@
import requests
class FeiShuMessage:
def __init__(self):
self.headers = {'Content-Type': 'application/json; charset=utf-8'}
self.webhook = "https://open.feishu.cn/open-apis/bot/v2/hook/180fa48e-1474-448e-a3d5-1a530f6ca689"
def send_message(self, msg, url=None):
url = url if url else self.webhook
res = requests.post(url, headers=self.headers, json=msg, verify=False)
if res.status_code == 200:
return True
else:
return False

View File

@@ -1,41 +0,0 @@
# -*- coding: utf-8 -*-
import requests
import json
from requests.exceptions import ConnectionError
from logger import logger
class Request(object):
@classmethod
def go(cls, method, url, params, headers=None, noFormat=False):
# logger.info(f'发送{method}请求到: {url}, 参数: {params}')
try:
if method == 'get':
response = requests.get(url=url, params=params, headers=headers, timeout=20)
elif method == 'post':
response = requests.post(url=url, data=json.dumps(params), headers=headers, timeout=20)
else:
logger.error(f'暂不支持{method}方法')
return
except ConnectionRefusedError:
logger.error(f'服务请求失败:{url}')
return
except ConnectionError:
logger.error(f'服务无法链接: {url}')
return
if response.status_code != 200:
logger.error(f'返回码不等于200请检查服务{response.status_code}, {response.text}')
else:
resp_json = response.json()
# logger.info(f'返回内容:{resp_json}')
# noFormat: 不需要对返回内容进行校验直接返回整个response
if noFormat:
return resp_json
# 对response做校验返回体为qe平台的通用格式
if resp_json.get('success') or resp_json.get('code') == 20000:
return resp_json.get('data')
else:
logger.error(resp_json)
return

View File

@@ -1,24 +0,0 @@
from ..common.getRequest import Request
from ..const import STRESS_URI
class UserInfo(object):
@staticmethod
def get_user_info(access_token, url_prefix=None, info='userId'):
stress_uri = STRESS_URI
url = "/back-end/stress/user/info"
result = Request.go(method="get",
url=stress_uri + url if not url_prefix else url_prefix + url,
params=None,
headers={"accessToken": access_token})
return None if not result else result.get(info)
@staticmethod
def get_user_info_by_user_id(access_token, user_id, info):
stress_uri = STRESS_URI
url = "/back-end/stress/user/infoFromId"
result = Request.go(method="get", url=stress_uri+url, params={'userId': user_id},
headers={"accessToken": access_token})
return None if not result else result.get(info)

View File

@@ -1,83 +0,0 @@
# 创建连接相关
from sqlalchemy import create_engine, text
from sqlalchemy.orm import sessionmaker
from base_framework.platform_tools.IDF.const import create_sql_url
from logger import logger
"""
sql操作
排序order_by(ChartsName.column.desc()/asc())
limit: .offset(n)过滤前面n条数据 .limit(n)
count: .count()计数
是否存在is_exist = session.query(exists().where(Book.id > 10)).scalar()
or: .filter(or_(Chart.column == x, Chart.column > y)).all()
one: .one()只获取一条,如不存在或存在多条都会报错
first: 通过主键获取记录 filter(**).first()
"""
class SqlSession:
def __init__(self, sql_uri=create_sql_url):
self.sql_uri = sql_uri
self._session = self.get_session()
# 创建连接对象,使用 pymsql 引擎
def get_session(self):
engine = create_engine(self.sql_uri, max_overflow=5, connect_args={'connect_timeout': 10})
Session = sessionmaker(bind=engine)
session = Session()
return session
def query(self, obj):
return self._session.query(obj)
def add(self, added):
self._session.add(added)
def add_all(self, added_list):
if isinstance(added_list, list):
self._session.add_all(added_list)
else:
logger.warning('只能传递list')
def flush(self):
self._session.flush()
def commit(self):
self._session.commit()
def close(self):
self._session.close()
def rollback(self):
self._session.rollback()
def object_session(self, instance):
self._session.object_session(instance)
def execute(self, sql):
return self._session.execute(text(sql))
def done(self, close=True):
"""
执行完插入、删除、修改等操作后执行done如报错回滚本次事务的sql操作
:return:
"""
try:
self.commit()
if close:
self.close()
except Exception as e:
logger.warning(e)
self._session.rollback()
return e
@property
def session(self):
return self._session
def to_dict(self):
return {c.name: getattr(self, c.name, None) for c in self.__table__.columns}

View File

@@ -1,37 +0,0 @@
# encoding: UTF-8
import os
from urllib.parse import quote_plus as urlquote
from urllib.parse import quote
# dev环境
# BE_URL = '127.0.0.1:6080'
# online环境
BE_URL = '127.0.0.1:6080'
BASEDIR = os.path.dirname(os.path.abspath(__file__))
# PROJDIR = os.path.dirname(BASEDIR)
LOG_DIR = os.path.join(BASEDIR, 'logs')
# 返回码
RES_CODE = {
40001: 'URL不正确请检查',
40002: '不支持该请求方法!',
40003: '参数有误!',
40004: 'header错误',
40005: 'user_id不能为空! ',
40006: '获取下拉框列表失败!',
40007: '获取接口列表失败!',
}
# sqlalchemy链接
password = urlquote("peppa@test")
create_sql_url = 'mysql+pymysql://root:{}@10.250.200.53/tools-dev?charset=utf8mb4'.format(password) #测试库
PASSWORD = quote('AcUVeRb8lN')
REDIS_URL = "redis://:{}@redis.qa.huohua.cn:6379/30".format(PASSWORD)
STRESS_URI = 'https://qe.bg.huohua.cn'
CREATE_URI = '172.19.24.100'
# dev环境 qe domain
# QE_DOMAIN = 'http://qe.qa.huohua.cn'
# prod环境 qe domain
QE_DOMAIN = 'https://qe.bg.huohua.cn'

View File

@@ -1,15 +0,0 @@
# encoding: UTF-8
from .const import BE_URL
workers = 1 # 定义同时开启的处理请求的进程数量,根据网站流量适当调整
bind = BE_URL
threads = 2 # 多线程2个暂时就够用
debug = False
reload = False
loglevel = 'debug'
pidfile = "logs/gunicorn.pid"
accesslog = "logs/access.log" # 每个接口调用会展示在access.log中
errorlog = "logs/debug.log" # 未处理的报错会在debug.log日志中展示
timeout = 300 # 每个接口的超时时间
daemon = False # 是否开启守护进程。不开启可直接在idea或命令行中查看日志在服务器上需要修改为True来开启守护进程

View File

@@ -1,39 +0,0 @@
import logging
import os
from logging.handlers import TimedRotatingFileHandler
from base_framework.platform_tools.IDF.const import LOG_DIR
class FunctionalTestsLogger(logging.Logger):
def critical(self, msg, *args, **kwargs):
super(FunctionalTestsLogger, self).critical(msg, *args, **kwargs)
raise Exception(msg)
logging.setLoggerClass(FunctionalTestsLogger)
logger = logging.getLogger(FunctionalTestsLogger.__name__)
logger.setLevel(logging.DEBUG)
LOG_FMT = logging.Formatter("%(asctime)s %(filename)-24s[:%(lineno)-4d] %(levelname)-8s %(message)s")
# log by day
# fh = TimedRotatingFileHandler(
# filename=os.path.join(LOG_DIR, f'{datetime.datetime.now().strftime("%Y%m%d")}.log'),
# when="MIDNIGHT",
# encoding='utf-8')
fh = TimedRotatingFileHandler(
filename=os.path.join(LOG_DIR, 'it-log'),
when="MIDNIGHT",
encoding='utf-8')
fh.setLevel(logging.DEBUG)
fh.setFormatter(LOG_FMT)
logger.addHandler(fh)
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
ch.setFormatter(LOG_FMT)
logger.addHandler(ch)
logging.basicConfig()

View File

@@ -1,64 +0,0 @@
# encoding: UTF-8
from flask_cors import CORS
from flask import make_response, jsonify, request, redirect
import os, sys
import configparser
import argparse
from apscheduler.schedulers.background import BackgroundScheduler
BASIC_PATH = os.path.dirname(os.path.abspath(__file__))
BASE_PATH = os.path.abspath(os.path.join(BASIC_PATH, '../../../{}'.format("base_framework")))
sys.path.append(BASE_PATH)
PROJECT_PATH = os.path.abspath(os.path.join(BASIC_PATH, '../../..'))
sys.path.append(PROJECT_PATH)
env_choose_path = os.path.join(BASE_PATH, 'base_config', 'env_choose.ini')
team_names = ["UBRD","TMO","H2R","CC","LaLive","SCM","TO"]
for team in team_names:
TEAM_PATH = os.path.abspath(os.path.join(BASIC_PATH, '../../../{}'.format(team)))
sys.path.append(TEAM_PATH)
from base_framework.platform_tools.IDF.app import create_app
from base_framework.platform_tools.IDF.app.api.controller.commonController import CommonController
def start_env():
parser = argparse.ArgumentParser(description="Choose current environment")
parser.add_argument("-e", dest='env', help="ST or PRE", default='QA')
args = parser.parse_args()
choose_env = args.env
return choose_env
get_env = start_env()
cof = configparser.ConfigParser()
cof.read(env_choose_path, encoding='utf-8')
cof.set(section="is_ip_from_ini", option="is_ip_from_ini", value="false")
cof.set(section="run_evn_name", option="current_evn", value=get_env.upper())
with open(env_choose_path, 'w') as fw: # 循环写入
cof.write(fw)
app = create_app()
CORS(app, resources=r'/*')
create_common_controll = CommonController()
# 初始化调度器
scheduler = BackgroundScheduler()
# 添加每日任务每天凌晨0点执行
scheduler.add_job(create_common_controll.daily_task_update_month_number, 'cron', hour=0, minute=0)
# 启动调度器
scheduler.start()
if get_env == "SIM":
app.run(host="0.0.0.0", port=int("5112"), debug=True, use_reloader=False)
else:
app.run(host="0.0.0.0", port=int("5113"), debug=True, use_reloader=False)
def cors_response(res):
response = make_response(jsonify(res))
response.headers['Access-Control-Allow-Origin'] = '*'
response.headers['Access-Control-Allow-Methods'] = '*'
response.headers['Access-Control-Allow-Headers'] = 'x-requested-with,content-type'
return response

View File

@@ -1,175 +0,0 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?><project>
<actions/>
<description>调度任务公共job</description>
<keepDependencies>false</keepDependencies>
<properties>
<jenkins.model.BuildDiscarderProperty>
<strategy class="hudson.tasks.LogRotator">
<daysToKeep>30</daysToKeep>
<numToKeep>100</numToKeep>
<artifactDaysToKeep>-1</artifactDaysToKeep>
<artifactNumToKeep>-1</artifactNumToKeep>
</strategy>
</jenkins.model.BuildDiscarderProperty>
<com.sonyericsson.jenkins.plugins.bfa.model.ScannerJobProperty plugin="build-failure-analyzer@2.0.0">
<doNotScan>false</doNotScan>
</com.sonyericsson.jenkins.plugins.bfa.model.ScannerJobProperty>
<com.chikli.hudson.plugin.naginator.NaginatorOptOutProperty plugin="naginator@1.18.1">
<optOut>false</optOut>
</com.chikli.hudson.plugin.naginator.NaginatorOptOutProperty>
<com.sonyericsson.rebuild.RebuildSettings plugin="rebuild@1.32">
<autoRebuild>false</autoRebuild>
<rebuildDisabled>false</rebuildDisabled>
</com.sonyericsson.rebuild.RebuildSettings>
<hudson.model.ParametersDefinitionProperty>
<parameterDefinitions>
<hudson.model.StringParameterDefinition>
<name>special_env</name>
<description>独立环境</description>
<defaultValue>qa</defaultValue>
<trim>false</trim>
</hudson.model.StringParameterDefinition>
<hudson.model.StringParameterDefinition>
<name>test_case_path</name>
<description>目录和robot都可以</description>
<trim>false</trim>
</hudson.model.StringParameterDefinition>
<hudson.model.StringParameterDefinition>
<name>test_case_id</name>
<description>需要构建的用例编号多个用逗号隔开默认空构建所有。例query_classroom-1001-正常请求有数据,query_classroom-1002-正常请求无数据</description>
<trim>false</trim>
</hudson.model.StringParameterDefinition>
<hudson.model.StringParameterDefinition>
<name>inculde</name>
<description>需要构建的用例tag多个用逗号隔开默认空构建所有。例p0,p1备注tag中不能出现关键字大写AND、OR、NOT可用小写platform-27418</description>
<trim>false</trim>
</hudson.model.StringParameterDefinition>
<hudson.model.StringParameterDefinition>
<name>exculde</name>
<description>不需要构建的用例tag多个用逗号隔开默认空不过滤。例norun,del</description>
<defaultValue>norun</defaultValue>
<trim>false</trim>
</hudson.model.StringParameterDefinition>
<hudson.model.StringParameterDefinition>
<name>rerun</name>
<description>是否需要二次构建失败用例。true/false</description>
<defaultValue>true</defaultValue>
<trim>false</trim>
</hudson.model.StringParameterDefinition>
<hudson.model.StringParameterDefinition>
<name>git_path</name>
<description>构建代码地址</description>
<trim>false</trim>
</hudson.model.StringParameterDefinition>
<hudson.model.StringParameterDefinition>
<name>team</name>
<description>组名</description>
<trim>false</trim>
</hudson.model.StringParameterDefinition>
<hudson.model.StringParameterDefinition>
<name>team_code_path</name>
<description>代码分支</description>
<trim>false</trim>
</hudson.model.StringParameterDefinition>
<hudson.model.StringParameterDefinition>
<name>build_info_id</name>
<description>本次构建对应数据库id</description>
<trim>false</trim>
</hudson.model.StringParameterDefinition>
<hudson.model.StringParameterDefinition>
<name>is_use_db</name>
<description>使用数据库中参数构建qe平台使用</description>
<defaultValue>0</defaultValue>
<trim>false</trim>
</hudson.model.StringParameterDefinition>
</parameterDefinitions>
</hudson.model.ParametersDefinitionProperty>
</properties>
<scm class="org.jenkinsci.plugins.multiplescms.MultiSCM" plugin="multiple-scms@0.8">
<scms>
<hudson.plugins.git.GitSCM plugin="git@4.3.0">
<configVersion>2</configVersion>
<userRemoteConfigs>
<hudson.plugins.git.UserRemoteConfig>
<url>${git_path}</url>
<credentialsId>a670722b-96ec-449f-a2dc-6e6676bf8dbc</credentialsId>
</hudson.plugins.git.UserRemoteConfig>
</userRemoteConfigs>
<branches>
<hudson.plugins.git.BranchSpec>
<name>*/${team_code_path}</name>
</hudson.plugins.git.BranchSpec>
</branches>
<doGenerateSubmoduleConfigurations>false</doGenerateSubmoduleConfigurations>
<gitTool> git-1.8.3.1</gitTool>
<submoduleCfg class="list"/>
<extensions>
<hudson.plugins.git.extensions.impl.RelativeTargetDirectory>
<relativeTargetDir>./${team}</relativeTargetDir>
</hudson.plugins.git.extensions.impl.RelativeTargetDirectory>
</extensions>
</hudson.plugins.git.GitSCM>
<hudson.plugins.git.GitSCM plugin="git@4.3.0">
<configVersion>2</configVersion>
<userRemoteConfigs>
<hudson.plugins.git.UserRemoteConfig>
<url>https://git.bg.huohua.cn/h2asatp/base_framework.git</url>
<credentialsId>a670722b-96ec-449f-a2dc-6e6676bf8dbc</credentialsId>
</hudson.plugins.git.UserRemoteConfig>
</userRemoteConfigs>
<branches>
<hudson.plugins.git.BranchSpec>
<name>*/master</name>
</hudson.plugins.git.BranchSpec>
</branches>
<doGenerateSubmoduleConfigurations>false</doGenerateSubmoduleConfigurations>
<gitTool> git-1.8.3.1</gitTool>
<submoduleCfg class="list"/>
<extensions>
<hudson.plugins.git.extensions.impl.RelativeTargetDirectory>
<relativeTargetDir>./base_framework</relativeTargetDir>
</hudson.plugins.git.extensions.impl.RelativeTargetDirectory>
</extensions>
</hudson.plugins.git.GitSCM>
</scms>
</scm>
<assignedNode>SparkATP</assignedNode>
<canRoam>false</canRoam>
<disabled>false</disabled>
<blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
<blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
<triggers/>
<concurrentBuild>false</concurrentBuild>
<builders>
<hudson.tasks.Shell>
<command>python3 $WORKSPACE/../sparkatp-scripts/case_runner10.py -w $WORKSPACE -c $WORKSPACE/$test_case_path -t "$test_case_id" -i "$inculde" -e "$exculde" -r "$rerun" -env "$special_env" -team "$team" -b_id "$build_info_id" -b_url "$BUILD_URL" -is_db "$is_use_db"</command>
<configuredLocalRules/>
</hudson.tasks.Shell>
</builders>
<publishers>
<hudson.plugins.robot.RobotPublisher plugin="robot@2.1.2">
<outputPath>$WORKSPACE/Report/ci_out/out</outputPath>
<reportFileName>report.html</reportFileName>
<logFileName>log.html</logFileName>
<outputFileName>output.xml</outputFileName>
<disableArchiveOutput>false</disableArchiveOutput>
<passThreshold>100.0</passThreshold>
<unstableThreshold>90.0</unstableThreshold>
<otherFiles>
<string/>
</otherFiles>
<enableCache>true</enableCache>
<onlyCritical>true</onlyCritical>
</hudson.plugins.robot.RobotPublisher>
</publishers>
<buildWrappers>
<hudson.plugins.ws__cleanup.PreBuildCleanup plugin="ws-cleanup@0.38">
<deleteDirs>false</deleteDirs>
<cleanupParameter/>
<externalDelete/>
<disableDeferredWipeout>false</disableDeferredWipeout>
</hudson.plugins.ws__cleanup.PreBuildCleanup>
<hudson.plugins.timestamper.TimestamperBuildWrapper plugin="timestamper@1.11.3"/>
</buildWrappers>
</project>

View File

@@ -1,32 +0,0 @@
from playwright.sync_api import sync_playwright
def click_email_link():
url = "https://switch4.best-envision.com/activity/form-review?userLanguage=jp&webKey=JyOJY1HaUWBQ00oooiNOEjTEwMDg3ODA3LCJ1c2VyTmFtZSI6InRveTFrbHNOeTExMSIsImVtYWlsIjoidG8xQGpveWh1Yi5uZXQiLCJwdXNoX2lkIjoxMDc4LCJwdXNoX3R5cGUiOjgsInByb2R1Y3RzIjoiXHU3MmVlXHU1YjUwXHU5OGRlXHU2NzNhXHU2NzZmIiwiYnJhbmRfdWlkIjoyMTA1LCJjaGFuIjoiaW0iLCJwcm9kdWN0X2lkIjo3fQO0O0OO0O0O"
with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
page = browser.new_page()
page.goto(url)
# 等待页面加载完成
page.wait_for_load_state('networkidle')
# 查找并点击邮箱超链接
# 邮箱链接通常包含 mailto: 协议
email_links = page.query_selector_all('a[href^="mailto:"]')
if email_links:
print(f"找到 {len(email_links)} 个邮箱链接")
# 点击第一个邮箱链接
email_links[0].click()
print("已点击第一个邮箱链接")
else:
print("未找到邮箱链接")
# 等待一段时间以便查看结果
page.wait_for_timeout(3000)
browser.close()
if __name__ == "__main__":
click_email_link()

View File

@@ -0,0 +1,75 @@
# -*- coding: utf-8 -*-
import allure
import logging
from zhyy.library.BusinessKw.SZPurchase.PurchaseOrderManage import PurchaseOrder
@allure.feature('深圳采购工作台采购订单页面')
class Test_purchase_order(object):
test_case = PurchaseOrder()
def teardown_method(self):
logging.info("-----------------------------End-------------------------------")
@allure.story("验证采购工作台采购订单页面列表查询")
def test_check_purchase_order_page(self):
purchase_order_code = 'PO251209048' # 采购单号 必填
supplier_company_ids = ['334'] # 供应商id 非必填
payment_status = '0' # 付款状态 非必填
status = '0' # 采购单状态 非必填
page_no = 1 # 页码 必填
page_size = 10 # 每页条数 必填
response_data = self.test_case.kw_zhyy_get_purchase_page_post(
note="采购工作台采购订单页面列表查询",
user='purchase',
order_sn=purchase_order_code,
supplier_company_ids=supplier_company_ids,
payment_status=payment_status,
status=status,
page_no=page_no,
page_size=page_size
)
# 断言检查
assert response_data is not None, "响应数据不能为空"
assert 'code' in response_data, "响应数据中缺少code字段"
assert response_data['code'] == 0, "接口调用失败code: {}, msg: {}".format(
response_data.get('code'), response_data.get('msg', '未知错误'))
assert 'data' in response_data, "响应数据中缺少data字段"
assert response_data['data'] is not None, "响应数据中的data字段不能为空"
# 如果传入了采购单号,检查返回的数据中是否包含该采购单号
if purchase_order_code:
data = response_data.get('data', {})
order_found = False
# 检查返回的数据结构,可能包含列表或其他结构
if isinstance(data, dict):
# 如果data是字典可能包含records、list、data等字段
records = data.get('records') or data.get('list') or data.get('data') or []
if isinstance(records, list) and len(records) > 0:
# 检查列表中是否包含指定的采购单号
for item in records:
if isinstance(item, dict):
order_sn = item.get('order_sn') or item.get('orderSn') or item.get('orderSn')
if order_sn == purchase_order_code:
order_found = True
break
elif isinstance(data, list):
# 如果data本身就是列表
for item in data:
if isinstance(item, dict):
order_sn = item.get('order_sn') or item.get('orderSn') or item.get('orderSn')
if order_sn == purchase_order_code:
order_found = True
break
if order_found:
logging.info("✓ 断言通过:返回的数据中包含采购单号 {}".format(purchase_order_code))
else:
logging.warning("⚠ 警告:返回的数据中未找到采购单号: {},但接口调用成功".format(purchase_order_code))
logging.info("✓ 所有断言检查通过")
print("✓ 查询成功,响应数据: {}".format(response_data))

View File

@@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
import allure
import logging
from zhyy.library.BusinessKw.SZPurchase.index import PurchaseIndex
@allure.feature('深圳采购工作台首页')
class Test_purchase_index(object):
# config = ReadConfig.ReadConfig() # 调用读取配置文件的方法类
test_case = PurchaseIndex()
def teardown_method(self):
logging.info("-----------------------------End-------------------------------")
@allure.story("验证采购工作台待办任务与在办任务功能")
def test_check_todo(self):
get_purchase_data = self.test_case.kw_zhyy_get_todo(note="采购工作台首页待办任务PO与在办任务PO", user='purchase')

View File

@@ -0,0 +1,11 @@
# -*- coding: utf-8 -*-
from joyhub_backend.library.functional_case_converter import (
ApiContextItem,
ApiMatcher,
FunctionalCaseInput,
FunctionalCaseParser,
FunctionalCaseToApiAutomationService,
FunctionalStep,
LLMApiCaseConverter,
convert_functional_case,
)

View File

@@ -0,0 +1,148 @@
# -*- coding: utf-8 -*-
import json
import logging
import os
import allure
import requests
CAPTCHA_URL = os.getenv(
"JOYHUB_CAPTCHA_URL",
"http://test-manager-api.best-envision.com/admin/login/captcha",
)
LOGIN_BASE_URL = os.getenv(
"JOYHUB_LOGIN_BASE_URL",
"http://test-manager-api.best-envision.com",
)
LOGIN_PATH = os.getenv("JOYHUB_LOGIN_PATH", "/admin/login/login")
USERNAME = os.getenv("JOYHUB_USERNAME", "guojiabao")
PASSWORD = os.getenv("JOYHUB_PASSWORD", "gjb123456")
CAPTCHA = os.getenv("JOYHUB_CAPTCHA", "1111")
TIMEOUT = int(os.getenv("JOYHUB_TIMEOUT", "20"))
TENANT_ID = os.getenv("JOYHUB_TENANT_ID", "126")
class JoyhubAuth(object):
def __init__(self):
self.session = requests.Session()
self._token = None
@property
def login_url(self):
return LOGIN_BASE_URL.rstrip("/") + LOGIN_PATH
def get_captcha_key(self):
with allure.step("前置:获取登录验证码 key"):
logging.info("GET %s", CAPTCHA_URL)
response = self.session.get(CAPTCHA_URL, timeout=TIMEOUT)
self._attach_response("captcha", response)
response.raise_for_status()
data = response.json()
key = self._extract_key(data)
assert key, "验证码接口未返回 key响应{}".format(data)
return key
def login(self):
if self._token:
return self._token
key = self.get_captcha_key()
body = {
"key": key,
"username": USERNAME,
"password": PASSWORD,
"captcha": CAPTCHA,
}
headers = {"Content-Type": "application/json", "tenant-id": TENANT_ID}
with allure.step("前置:登录并获取 token"):
logging.info("POST %s", self.login_url)
logging.info("request headers: %s", headers)
logging.info("request body: %s", self._safe_body(body))
response = self.session.post(self.login_url, json=body, headers=headers, timeout=TIMEOUT)
self._attach_request(self.login_url, "POST", headers, self._safe_body(body))
self._attach_response("login", response)
response.raise_for_status()
data = response.json()
token = self._extract_token(data)
assert token, "登录接口未返回 token响应{}".format(data)
self._token = token if token.startswith("Bearer ") else "Bearer " + token
return self._token
def auth_headers(self):
return {
"Authorization": self.login(),
"Content-Type": "application/json",
"tenant-id": TENANT_ID,
}
@staticmethod
def _extract_key(data):
if isinstance(data, dict):
for field in ("key", "captchaKey", "captcha_key", "uuid"):
if data.get(field):
return data.get(field)
nested = data.get("data")
if isinstance(nested, dict):
for field in ("key", "captchaKey", "captcha_key", "uuid"):
if nested.get(field):
return nested.get(field)
if isinstance(nested, str):
return nested
return None
@staticmethod
def _extract_token(data):
token_fields = (
"token",
"access_token",
"accessToken",
"Authorization",
"authorization",
"userToken",
"user_token",
"jwt",
)
if isinstance(data, dict):
for field in token_fields:
token = data.get(field)
if JoyhubAuth._looks_like_token(token):
return token
nested = data.get("data")
if isinstance(nested, dict):
for field in token_fields:
token = nested.get(field)
if JoyhubAuth._looks_like_token(token):
return token
return None
@staticmethod
def _looks_like_token(value):
if not isinstance(value, str):
return False
value = value.strip()
if not value:
return False
if any(ord(char) > 127 for char in value):
return False
return len(value) >= 16 or value.startswith("Bearer ")
@staticmethod
def _safe_body(body):
safe = dict(body)
if "password" in safe:
safe["password"] = "******"
return safe
@staticmethod
def _attach_request(url, method, headers, body):
allure.attach(str(url), "请求url", allure.attachment_type.TEXT)
allure.attach(str(method), "请求方式", allure.attachment_type.TEXT)
allure.attach(json.dumps(headers, ensure_ascii=False, indent=2), "请求头", allure.attachment_type.JSON)
allure.attach(json.dumps(body, ensure_ascii=False, indent=2), "请求体", allure.attachment_type.JSON)
@staticmethod
def _attach_response(name, response):
logging.info("%s response status: %s", name, response.status_code)
logging.info("%s response body: %s", name, response.text)
allure.attach(str(response.status_code), "{} 响应状态码".format(name), allure.attachment_type.TEXT)
allure.attach(response.text, "{} 响应体".format(name), allure.attachment_type.JSON)

View File

@@ -0,0 +1,62 @@
# -*- coding: utf-8 -*-
import logging
from joyhub_backend.library.joyhub_interface import JoyhubInterface
class JoyhubBusiness(JoyhubInterface):
def get_video_label_list(self):
logging.info("==========获取视频标签列表==========")
body = {
"page": 1,
"limit": 10,
"sort": "id",
"label_name": "",
"category_id": 0,
"video_type": 0,
"video_num": 0,
"created_at": [],
"order": "descending",
}
return self.request("获取视频标签列表", "POST", "admin/video/getVideoLabelList", body=body)
def get_video_category_list(self):
logging.info("==========获取视频分类列表==========")
body = {
"page": 1,
"limit": 10,
"sort": "id",
"category_name": "",
"order": "descending",
}
return self.request("获取视频分类列表", "POST", "admin/video/getVideoCategoryList", body=body)
def get_exchange_record_list(self):
logging.info("==========兑换记录列表==========")
body = {
"page": 1,
"limit": 10,
"status": "",
"goods_type": "",
"created_at": [],
}
return self.request("兑换记录列表", "POST", "admin/exchange/recordList", body=body)
def get_app_feedback_list(self):
logging.info("==========app反馈意见列表==========")
body = {
"page": 1,
"limit": 10,
"status": "",
"keyword": "",
}
return self.request("app反馈意见列表", "POST", "admin/feedback/list", body=body)
def get_sensitive_word_list(self):
logging.info("==========敏感词列表==========")
body = {
"page": 1,
"limit": 10,
"keyword": "",
}
return self.request("敏感词列表", "POST", "admin/sensitiveWord/list", body=body)

View File

@@ -0,0 +1,917 @@
# -*- coding: utf-8 -*-
import argparse
import copy
import json
import os
import re
from dataclasses import asdict, dataclass, field
from difflib import SequenceMatcher
from typing import Any, Callable, Dict, Iterable, List, Optional, Union
COMMON_CN_KEYWORDS = [
"登录",
"查询",
"搜索",
"筛选",
"列表",
"详情",
"新增",
"创建",
"添加",
"修改",
"编辑",
"更新",
"删除",
"导出",
"导入",
"上传",
"下载",
"提交",
"审核",
"确认",
"保存",
"分页",
"分页查询",
"性能",
"响应时间",
"超时",
"返回",
"结果",
"成功",
"失败",
"校验",
"重置",
"启用",
"停用",
"开关",
"状态",
"排序",
"标签",
"分类",
"关键字",
"关键字搜索",
"模糊搜索",
]
METHOD_INTENT_KEYWORDS = {
"GET": ["查询", "搜索", "筛选", "列表", "详情", "获取", "查看", "分页", "返回"],
"POST": ["新增", "创建", "添加", "登录", "提交", "导入", "上传", "确认", "审核", "保存"],
"PUT": ["修改", "编辑", "更新", "重置"],
"PATCH": ["修改", "编辑", "更新", "状态", "启用", "停用", "开关"],
"DELETE": ["删除", "移除"],
}
DEFAULT_PLACEHOLDER_URL = "/api/need-confirm"
DEFAULT_PAGE_SIZE = 10
DEFAULT_RESPONSE_TIME_MS = 1000
@dataclass
class FunctionalStep:
stepNo: int
action: str
expectedResult: str = ""
@dataclass
class ApiContextItem:
apiName: str = ""
method: str = ""
url: str = ""
description: str = ""
headers: Dict[str, Any] = field(default_factory=dict)
queryParams: Dict[str, Any] = field(default_factory=dict)
requestBody: Any = None
responseExample: Any = None
tags: List[str] = field(default_factory=list)
@dataclass
class FunctionalCaseInput:
caseId: str = ""
caseKey: str = ""
caseName: str = ""
projectName: str = ""
moduleName: str = ""
priority: str = ""
preconditions: str = ""
steps: List[FunctionalStep] = field(default_factory=list)
expectedResults: List[str] = field(default_factory=list)
apiContext: Optional[List[ApiContextItem]] = None
generateOptions: Dict[str, Any] = field(default_factory=dict)
extra: Dict[str, Any] = field(default_factory=dict)
class FunctionalCaseParser:
@classmethod
def parse(cls, payload: Union[str, Dict[str, Any], FunctionalCaseInput]) -> FunctionalCaseInput:
if isinstance(payload, FunctionalCaseInput):
return payload
if isinstance(payload, str):
try:
payload = json.loads(payload)
except Exception:
payload = {
"caseName": "手工输入功能用例",
"steps": [payload],
"expectedResults": [],
}
if not isinstance(payload, dict):
raise TypeError("functional case payload must be dict, json string or FunctionalCaseInput")
steps = cls._normalize_steps(payload.get("steps") or payload.get("step") or [])
expected_results = cls._normalize_text_list(
payload.get("expectedResults")
or payload.get("expectedResult")
or payload.get("expectations")
or []
)
api_context = cls._normalize_api_context(payload.get("apiContext") or payload.get("apis") or payload.get("apiInfo"))
generate_options = payload.get("generateOptions") or payload.get("options") or {}
known_keys = {
"caseId",
"caseKey",
"caseName",
"projectName",
"moduleName",
"priority",
"preconditions",
"steps",
"step",
"expectedResults",
"expectedResult",
"expectations",
"apiContext",
"apis",
"apiInfo",
"generateOptions",
"options",
}
extra = {key: value for key, value in payload.items() if key not in known_keys}
return FunctionalCaseInput(
caseId=str(payload.get("caseId", "") or ""),
caseKey=str(payload.get("caseKey", "") or ""),
caseName=str(payload.get("caseName", "") or payload.get("name", "") or ""),
projectName=str(payload.get("projectName", "") or ""),
moduleName=str(payload.get("moduleName", "") or ""),
priority=str(payload.get("priority", "") or ""),
preconditions=str(payload.get("preconditions", "") or payload.get("precondition", "") or ""),
steps=steps,
expectedResults=expected_results,
apiContext=api_context,
generateOptions=generate_options if isinstance(generate_options, dict) else {},
extra=extra,
)
@staticmethod
def _normalize_steps(value: Any) -> List[FunctionalStep]:
if not value:
return []
if isinstance(value, str):
raw_items = [item.strip() for item in re.split(r"[\n\r]+", value) if item.strip()]
if len(raw_items) <= 1:
raw_items = [item.strip() for item in re.split(r"(?<=[。;;])", value) if item.strip()]
items = raw_items
elif isinstance(value, list):
items = value
else:
items = [value]
normalized: List[FunctionalStep] = []
for index, item in enumerate(items, start=1):
if isinstance(item, dict):
step_no = int(item.get("stepNo") or item.get("step_no") or item.get("no") or index)
action = str(item.get("action") or item.get("step") or item.get("content") or item.get("description") or "")
expected_result = str(item.get("expectedResult") or item.get("expected") or "")
else:
raw_text = str(item).strip()
step_no = index
action = re.sub(r"^\s*\d+[\.、\)]\s*", "", raw_text)
expected_result = ""
if action:
normalized.append(FunctionalStep(stepNo=step_no, action=action, expectedResult=expected_result))
return normalized
@staticmethod
def _normalize_text_list(value: Any) -> List[str]:
if not value:
return []
if isinstance(value, str):
parts = [item.strip() for item in re.split(r"[\n\r]+", value) if item.strip()]
if len(parts) <= 1:
parts = [item.strip() for item in re.split(r"[。;;]\s*", value) if item.strip()]
return [item for item in parts if item]
if isinstance(value, list):
result = []
for item in value:
if isinstance(item, dict):
text = str(item.get("text") or item.get("content") or item.get("expected") or "").strip()
else:
text = str(item).strip()
if text:
result.append(text)
return result
return [str(value).strip()] if str(value).strip() else []
@staticmethod
def _normalize_api_context(value: Any) -> Optional[List[ApiContextItem]]:
if not value:
return None
if isinstance(value, dict):
if "apis" in value and isinstance(value["apis"], list):
value = value["apis"]
elif "items" in value and isinstance(value["items"], list):
value = value["items"]
else:
value = [value]
if isinstance(value, str):
value = value.strip()
if not value:
return None
try:
parsed = json.loads(value)
return FunctionalCaseParser._normalize_api_context(parsed)
except Exception:
return FunctionalCaseParser._parse_markdown_api_context(value)
if not isinstance(value, list):
return None
apis: List[ApiContextItem] = []
for item in value:
if isinstance(item, ApiContextItem):
apis.append(item)
continue
if not isinstance(item, dict):
continue
headers = item.get("headers") or item.get("header") or {}
query_params = item.get("queryParams") or item.get("query") or item.get("params") or {}
tags = item.get("tags") or []
if isinstance(tags, str):
tags = [tag.strip() for tag in re.split(r"[\s,/|]+", tags) if tag.strip()]
apis.append(
ApiContextItem(
apiName=str(item.get("apiName") or item.get("name") or ""),
method=str(item.get("method") or item.get("httpMethod") or "").upper(),
url=str(item.get("url") or item.get("path") or ""),
description=str(item.get("description") or item.get("desc") or ""),
headers=headers if isinstance(headers, dict) else {},
queryParams=query_params if isinstance(query_params, dict) else {},
requestBody=item.get("requestBody") if "requestBody" in item else item.get("body"),
responseExample=item.get("responseExample") or item.get("response") or item.get("example"),
tags=tags if isinstance(tags, list) else [],
)
)
return apis or None
@staticmethod
def _parse_markdown_api_context(text: str) -> Optional[List[ApiContextItem]]:
lines = text.splitlines()
apis: List[ApiContextItem] = []
current: Dict[str, Any] = {}
in_body = False
body_lines: List[str] = []
def flush_current():
nonlocal current, body_lines, in_body
if not current:
return
body_text = "\n".join(body_lines).strip()
request_body = FunctionalCaseParser._safe_json_load(body_text)
apis.append(
ApiContextItem(
apiName=current.get("apiName", ""),
method=current.get("method", ""),
url=current.get("url", ""),
description=current.get("description", ""),
headers=current.get("headers", {}),
queryParams=current.get("queryParams", {}),
requestBody=request_body if request_body is not None else body_text,
responseExample=current.get("responseExample"),
tags=current.get("tags", []),
)
)
current = {}
body_lines = []
in_body = False
for line in lines:
stripped = line.strip()
if stripped.startswith("## "):
flush_current()
current["apiName"] = stripped[3:].strip()
continue
if stripped == "**接口URL**":
continue
if stripped.startswith("> ") and not current.get("url"):
value = stripped[2:].strip()
if value and value != "暂无参数":
current["url"] = value
continue
if stripped == "**请求方式**":
continue
if stripped == "**请求Body参数**":
in_body = True
body_lines = []
continue
if stripped == "**响应示例**":
in_body = False
continue
if in_body:
if stripped.startswith("```"):
continue
body_lines.append(line)
flush_current()
return apis or None
@staticmethod
def _safe_json_load(text: str) -> Any:
if not text:
return None
cleaned = text.strip()
if cleaned.startswith("```"):
cleaned = re.sub(r"^```[a-zA-Z0-9_-]*\s*", "", cleaned)
cleaned = re.sub(r"\s*```$", "", cleaned)
try:
return json.loads(cleaned)
except Exception:
return None
class ApiMatcher:
def match(self, functional_case: FunctionalCaseInput, candidates: List[ApiContextItem], top_k: int = 3) -> List[Dict[str, Any]]:
matched: List[Dict[str, Any]] = []
keywords = self.extract_keywords(functional_case)
intent = self.detect_intent(functional_case)
for api in candidates:
score = self._score_api(api, keywords, intent, functional_case)
if score <= 0:
continue
matched.append(
{
"score": round(score, 4),
"api": api,
"reason": self._build_reason(api, keywords, intent),
}
)
matched.sort(key=lambda item: item["score"], reverse=True)
return matched[:top_k]
def extract_keywords(self, functional_case: FunctionalCaseInput) -> List[str]:
texts = [functional_case.caseName, functional_case.moduleName, functional_case.preconditions]
texts.extend(step.action for step in functional_case.steps)
texts.extend(step.expectedResult for step in functional_case.steps if step.expectedResult)
texts.extend(functional_case.expectedResults)
texts.extend(str(value) for value in functional_case.extra.values() if value is not None)
full_text = " \n ".join(texts)
keywords: List[str] = []
for keyword in COMMON_CN_KEYWORDS:
if keyword in full_text and keyword not in keywords:
keywords.append(keyword)
english_tokens = re.findall(r"[A-Za-z_][A-Za-z0-9_]{1,}", full_text)
for token in english_tokens:
if token not in keywords:
keywords.append(token)
generic_tokens = re.findall(r"[\u4e00-\u9fa5]{2,}", full_text)
for token in generic_tokens:
if len(token) <= 2:
if token not in keywords:
keywords.append(token)
continue
if token not in keywords:
keywords.append(token)
return self._dedupe(keywords)
def detect_intent(self, functional_case: FunctionalCaseInput) -> str:
text = self._all_text(functional_case)
for method, keywords in METHOD_INTENT_KEYWORDS.items():
if any(keyword in text for keyword in keywords):
return method
return "GET"
def _score_api(self, api: ApiContextItem, keywords: List[str], intent: str, functional_case: FunctionalCaseInput) -> float:
score = 0.0
api_text = " ".join(
[
api.apiName or "",
api.method or "",
api.url or "",
api.description or "",
" ".join(api.tags or []),
" ".join(api.headers.keys()),
" ".join(api.queryParams.keys()),
]
)
if api.method and api.method.upper() == intent:
score += 1.2
elif api.method and api.method.upper() in ("GET", "POST", "PUT", "PATCH", "DELETE"):
score += 0.2
for keyword in keywords:
if keyword and keyword in api_text:
score += 0.8
for token in self._url_tokens(api.url):
if token and any(keyword in token or token in keyword for keyword in keywords):
score += 0.6
if functional_case.moduleName and functional_case.moduleName in api_text:
score += 0.8
if functional_case.caseName and functional_case.caseName in api_text:
score += 0.5
ratio = SequenceMatcher(None, self._all_text(functional_case), api_text).ratio()
score += ratio * 0.8
return score
@staticmethod
def _build_reason(api: ApiContextItem, keywords: List[str], intent: str) -> str:
matched_keywords = [keyword for keyword in keywords if keyword and keyword in (api.apiName + " " + api.description + " " + api.url)]
parts = []
if api.method and api.method.upper() == intent:
parts.append("方法匹配")
if matched_keywords:
parts.append("关键词命中:{}".format("".join(matched_keywords[:5])))
return "; ".join(parts) or "模糊匹配"
@staticmethod
def _url_tokens(url: str) -> List[str]:
if not url:
return []
return [token for token in re.split(r"[/?&=_\-\.]+", url) if token]
@staticmethod
def _dedupe(items: Iterable[str]) -> List[str]:
seen = set()
result = []
for item in items:
if item and item not in seen:
seen.add(item)
result.append(item)
return result
@staticmethod
def _all_text(functional_case: FunctionalCaseInput) -> str:
texts = [functional_case.caseName, functional_case.moduleName, functional_case.preconditions]
texts.extend(step.action for step in functional_case.steps)
texts.extend(step.expectedResult for step in functional_case.steps if step.expectedResult)
texts.extend(functional_case.expectedResults)
return " \n ".join(filter(None, texts))
class LLMApiCaseConverter:
def convert(self, prompt: str, llm_client: Any = None) -> Optional[Dict[str, Any]]:
if llm_client is None:
return None
raw = self._invoke_client(llm_client, prompt)
if raw is None:
return None
if isinstance(raw, dict):
return raw
if hasattr(raw, "content"):
raw = raw.content
elif hasattr(raw, "text"):
raw = raw.text
elif hasattr(raw, "data"):
raw = raw.data
if isinstance(raw, dict):
return raw
if not isinstance(raw, str):
raw = str(raw)
return self._extract_json(raw)
@staticmethod
def _invoke_client(llm_client: Any, prompt: str) -> Any:
if callable(llm_client):
try:
return llm_client(prompt=prompt)
except TypeError:
try:
return llm_client(prompt)
except TypeError:
return llm_client({"prompt": prompt})
if hasattr(llm_client, "generate") and callable(llm_client.generate):
return llm_client.generate(prompt)
if hasattr(llm_client, "chat") and callable(llm_client.chat):
return llm_client.chat(prompt)
raise TypeError("llm_client must be callable or expose generate/chat")
@staticmethod
def _extract_json(text: str) -> Optional[Dict[str, Any]]:
if not text:
return None
cleaned = text.strip()
match = re.search(r"```json\s*(\{.*?\})\s*```", cleaned, flags=re.S)
if match:
cleaned = match.group(1)
else:
first = cleaned.find("{")
last = cleaned.rfind("}")
if first >= 0 and last > first:
cleaned = cleaned[first : last + 1]
try:
parsed = json.loads(cleaned)
return parsed if isinstance(parsed, dict) else {"data": parsed}
except Exception:
return None
class FunctionalCaseToApiAutomationService:
def __init__(self, matcher: Optional[ApiMatcher] = None):
self.matcher = matcher or ApiMatcher()
self.llm_converter = LLMApiCaseConverter()
def convert(self, payload: Union[str, Dict[str, Any], FunctionalCaseInput], llm_client: Any = None) -> Dict[str, Any]:
functional_case = FunctionalCaseParser.parse(payload)
options = self._build_options(functional_case)
candidates = functional_case.apiContext or []
matched = self.matcher.match(functional_case, candidates, top_k=int(options.get("topK", 3))) if candidates else []
llm_result = None
if options.get("useLLM", True) and llm_client is not None:
prompt = self.build_prompt(functional_case, matched, options)
llm_result = self.llm_converter.convert(prompt, llm_client)
if llm_result:
return self._finalize_llm_result(functional_case, matched, llm_result, options)
return self._build_rule_result(functional_case, matched, options)
def build_prompt(self, functional_case: FunctionalCaseInput, matched: List[Dict[str, Any]], options: Dict[str, Any]) -> str:
payload = {
"functionalCase": asdict(functional_case),
"matchedApis": [
{
"score": item["score"],
"reason": item["reason"],
"api": asdict(item["api"]),
}
for item in matched
],
"options": options,
}
return (
"你是接口自动化测试用例生成专家。\n"
"请把功能测试用例转换成接口自动化测试用例。\n"
"要求:\n"
"1. 只输出严格 JSON。\n"
"2. 如果给了候选接口信息,优先使用候选接口。\n"
"3. 无法确认的接口信息写入 missingInfo。\n"
"4. 需要包含 method、url、headers、queryParams、body、assertions、performanceAssertions。\n"
"5. 如果涉及性能要求,生成 responseTime 断言。\n"
"6. 如果涉及登录态,使用 ${token}\n\n"
"输入数据:\n"
f"{json.dumps(payload, ensure_ascii=False, indent=2)}\n\n"
"输出 JSON 结构:\n"
"{\n"
' "caseId": "",\n'
' "caseKey": "",\n'
' "caseName": "",\n'
' "automationType": "api",\n'
' "convertStatus": "SUCCESS",\n'
' "apiTestCases": [],\n'
' "missingInfo": [],\n'
' "warnings": []\n'
"}"
)
def _build_options(self, functional_case: FunctionalCaseInput) -> Dict[str, Any]:
options = copy.deepcopy(functional_case.generateOptions or {})
options.setdefault("useLLM", True)
options.setdefault("outputFormat", "json")
options.setdefault("targetFramework", "pytest")
options.setdefault("allowMissingInfo", True)
options.setdefault("topK", 3)
return options
def _build_rule_result(self, functional_case: FunctionalCaseInput, matched: List[Dict[str, Any]], options: Dict[str, Any]) -> Dict[str, Any]:
api_test_cases: List[Dict[str, Any]] = []
missing_info: List[str] = []
warnings: List[str] = []
if matched:
for index, item in enumerate(matched, start=1):
api_test_cases.append(self._build_api_test_case(functional_case, item["api"], index, item["score"], options))
else:
api_test_cases.append(self._build_fallback_test_case(functional_case, options))
missing_info.extend(self._collect_missing_info(functional_case))
warnings.append("未匹配到真实接口信息,已生成占位自动化用例")
missing_info = self._dedupe_text(missing_info)
warnings = self._dedupe_text(warnings)
convert_status = "SUCCESS"
if missing_info:
convert_status = "SUCCESS_WITH_MISSING_INFO"
if warnings and not matched:
convert_status = "DRAFT"
return {
"caseId": functional_case.caseId,
"caseKey": functional_case.caseKey,
"caseName": functional_case.caseName,
"projectName": functional_case.projectName,
"moduleName": functional_case.moduleName,
"automationType": "api",
"convertStatus": convert_status,
"apiTestCases": api_test_cases,
"missingInfo": missing_info,
"warnings": warnings,
}
def _finalize_llm_result(self, functional_case: FunctionalCaseInput, matched: List[Dict[str, Any]], llm_result: Dict[str, Any], options: Dict[str, Any]) -> Dict[str, Any]:
result = copy.deepcopy(llm_result)
result.setdefault("caseId", functional_case.caseId)
result.setdefault("caseKey", functional_case.caseKey)
result.setdefault("caseName", functional_case.caseName)
result.setdefault("projectName", functional_case.projectName)
result.setdefault("moduleName", functional_case.moduleName)
result.setdefault("automationType", "api")
result.setdefault("convertStatus", "SUCCESS")
result.setdefault("apiTestCases", [])
result.setdefault("missingInfo", [])
result.setdefault("warnings", [])
if not result.get("apiTestCases"):
rule_result = self._build_rule_result(functional_case, matched, options)
result["apiTestCases"] = rule_result["apiTestCases"]
if not result.get("missingInfo"):
result["missingInfo"] = rule_result["missingInfo"]
if not result.get("warnings"):
result["warnings"] = rule_result["warnings"]
result["convertStatus"] = rule_result["convertStatus"]
result["missingInfo"] = self._dedupe_text(result.get("missingInfo", []))
result["warnings"] = self._dedupe_text(result.get("warnings", []))
return result
def _build_api_test_case(self, functional_case: FunctionalCaseInput, api: ApiContextItem, index: int, score: float, options: Dict[str, Any]) -> Dict[str, Any]:
method = (api.method or self.matcher.detect_intent(functional_case)).upper()
query_params = copy.deepcopy(api.queryParams or {})
body = copy.deepcopy(api.requestBody)
headers = copy.deepcopy(api.headers or {})
if not headers:
headers = {"Content-Type": "application/json"}
if not any(key.lower() == "authorization" for key in headers):
headers["Authorization"] = "Bearer ${token}"
variables = self._build_variables(functional_case, api, query_params, body)
query_params = self._fill_placeholders(query_params, variables)
body = self._fill_placeholders(body, variables)
assertions = self._build_assertions(functional_case, api, method)
performance_assertions = self._build_performance_assertions(functional_case)
step_name = api.apiName or functional_case.caseName or "接口自动化步骤"
return {
"stepNo": index,
"name": step_name,
"apiName": api.apiName or step_name,
"method": method,
"url": api.url or self._infer_placeholder_url(functional_case),
"headers": headers,
"queryParams": query_params,
"body": body,
"extractVariables": [],
"assertions": assertions,
"performanceAssertions": performance_assertions,
"variables": variables,
"matchedApi": {
"apiName": api.apiName,
"method": method,
"url": api.url,
"matchScore": round(score, 4),
},
}
def _build_fallback_test_case(self, functional_case: FunctionalCaseInput, options: Dict[str, Any]) -> Dict[str, Any]:
method = self.matcher.detect_intent(functional_case)
url = self._infer_placeholder_url(functional_case)
variables = self._build_variables(functional_case, None, {}, None)
return {
"stepNo": 1,
"name": functional_case.caseName or "功能用例转接口自动化",
"apiName": functional_case.caseName or "待确认接口",
"method": method,
"url": url,
"headers": {
"Content-Type": "application/json",
"Authorization": "Bearer ${token}",
},
"queryParams": {},
"body": None,
"extractVariables": [],
"assertions": self._build_assertions(functional_case, None, method),
"performanceAssertions": self._build_performance_assertions(functional_case),
"variables": variables,
"matchedApi": {
"apiName": "",
"method": method,
"url": url,
"matchScore": 0,
},
}
def _build_variables(self, functional_case: FunctionalCaseInput, api: Optional[ApiContextItem], query_params: Dict[str, Any], body: Any) -> Dict[str, Any]:
variables: Dict[str, Any] = {}
text = self.matcher._all_text(functional_case)
for keyword in self.matcher.extract_keywords(functional_case):
if keyword in ("搜索", "查询", "列表", "筛选", "关键字", "模糊搜索"):
variables.setdefault("keyword", "测试")
if keyword in ("分页", "分页查询"):
variables.setdefault("page", 1)
variables.setdefault("limit", DEFAULT_PAGE_SIZE)
if keyword in ("登录",):
variables.setdefault("token", "${token}")
if not variables and text:
variables["keyword"] = "测试"
if query_params:
for key in query_params.keys():
if key not in variables and any(token in key.lower() for token in ["keyword", "name", "id", "page", "limit", "status", "type"]):
variables[key] = query_params[key]
if isinstance(body, dict):
for key in body.keys():
if key not in variables and any(token in key.lower() for token in ["keyword", "name", "id", "page", "limit", "status", "type"]):
variables[key] = body[key]
return variables
def _build_assertions(self, functional_case: FunctionalCaseInput, api: Optional[ApiContextItem], method: str) -> List[Dict[str, Any]]:
assertions = [
{
"type": "statusCode",
"actual": "$.code" if api or method != "DELETE" else "$.status",
"operator": "==",
"expected": 200,
}
]
text = self.matcher._all_text(functional_case)
if api and isinstance(api.responseExample, dict):
example = api.responseExample
if "code" in example:
assertions.append(
{
"type": "jsonPath",
"actual": "$.code",
"operator": "==",
"expected": example.get("code", 0),
}
)
if "msg" in example:
assertions.append(
{
"type": "jsonPath",
"actual": "$.msg",
"operator": "notEmpty",
"expected": True,
}
)
if any(keyword in text for keyword in ["搜索", "查询", "列表", "筛选", "返回"]):
assertions.append(
{
"type": "jsonPath",
"actual": "$.data",
"operator": "notEmpty",
"expected": True,
}
)
return assertions
def _build_performance_assertions(self, functional_case: FunctionalCaseInput) -> List[Dict[str, Any]]:
text = self.matcher._all_text(functional_case)
expected_ms = self._extract_response_time_ms(text)
if expected_ms is None:
return []
return [
{
"type": "responseTime",
"operator": "<=",
"expected": expected_ms,
"unit": "ms",
}
]
def _collect_missing_info(self, functional_case: FunctionalCaseInput) -> List[str]:
missing = []
if not functional_case.steps:
missing.append("缺少步骤信息")
if not functional_case.caseName:
missing.append("缺少用例名称")
if not functional_case.apiContext:
missing.append("未传入真实接口信息,已使用占位接口生成")
if self._extract_response_time_ms(self.matcher._all_text(functional_case)) is None and any(k in self.matcher._all_text(functional_case) for k in ["性能", "响应时间", "超时"]):
missing.append("性能阈值未明确,默认使用 1000ms")
return missing
@staticmethod
def _extract_response_time_ms(text: str) -> Optional[int]:
if not text:
return None
patterns = [
r"(\d+)\s*毫秒",
r"(\d+)\s*ms",
r"(\d+)\s*秒",
r"不超过\s*(\d+)\s*秒",
r"<=\s*(\d+)\s*秒",
r"小于等于\s*(\d+)\s*秒",
]
for pattern in patterns:
match = re.search(pattern, text, flags=re.I)
if match:
value = int(match.group(1))
if "" in pattern:
return value * 1000
return value
if any(keyword in text for keyword in ["响应时间", "超时", "性能"]):
return DEFAULT_RESPONSE_TIME_MS
return None
@staticmethod
def _infer_placeholder_url(functional_case: FunctionalCaseInput) -> str:
text = " ".join([functional_case.caseName, functional_case.moduleName] + [step.action for step in functional_case.steps])
if any(keyword in text for keyword in ["登录"]):
return "/api/login"
if any(keyword in text for keyword in ["搜索", "查询", "列表", "筛选"]):
return "/api/list/query"
if any(keyword in text for keyword in ["新增", "创建", "添加"]):
return "/api/create"
if any(keyword in text for keyword in ["修改", "编辑", "更新"]):
return "/api/update"
if any(keyword in text for keyword in ["删除", "移除"]):
return "/api/delete"
return DEFAULT_PLACEHOLDER_URL
@staticmethod
def _fill_placeholders(value: Any, variables: Dict[str, Any]) -> Any:
if isinstance(value, dict):
return {key: FunctionalCaseToApiAutomationService._fill_placeholders(item, variables) for key, item in value.items()}
if isinstance(value, list):
return [FunctionalCaseToApiAutomationService._fill_placeholders(item, variables) for item in value]
if isinstance(value, str):
result = value
for key, variable in variables.items():
result = result.replace("${" + key + "}", str(variable))
return result
return value
@staticmethod
def _dedupe_text(items: Iterable[str]) -> List[str]:
seen = set()
result = []
for item in items:
text = str(item).strip()
if not text or text in seen:
continue
seen.add(text)
result.append(text)
return result
def convert_functional_case(payload: Union[str, Dict[str, Any], FunctionalCaseInput], llm_client: Any = None) -> Dict[str, Any]:
return FunctionalCaseToApiAutomationService().convert(payload, llm_client=llm_client)
def load_payload_from_file(file_path: str) -> Dict[str, Any]:
with open(file_path, "r", encoding="utf-8") as file:
return json.load(file)
def main():
parser = argparse.ArgumentParser(description="功能测试用例转接口自动化用例")
parser.add_argument("--input", type=str, help="输入JSON文件路径未指定则从stdin读取")
parser.add_argument("--output", type=str, help="输出JSON文件路径未指定则打印到stdout")
args = parser.parse_args()
if args.input:
payload = load_payload_from_file(args.input)
else:
payload = json.load(os.sys.stdin)
result = convert_functional_case(payload)
output = json.dumps(result, ensure_ascii=False, indent=2)
if args.output:
with open(args.output, "w", encoding="utf-8") as file:
file.write(output)
else:
print(output)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,189 @@
# -*- coding: utf-8 -*-
import ast
import json
import os
import re
PROJECT_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
DEFAULT_HUBOPS_PATH = os.path.join(PROJECT_ROOT, "HubOps.md")
class HubOpsParser(object):
def __init__(self, file_path=None):
self.file_path = file_path or os.getenv("JOYHUB_DOC_PATH", DEFAULT_HUBOPS_PATH)
def parse(self):
with open(self.file_path, "r", encoding="utf-8") as file:
lines = file.read().splitlines()
cases = []
headings = []
for index, line in enumerate(lines):
heading = self._parse_heading(line)
if heading:
level, title = heading
headings = [item for item in headings if item[0] < level]
headings.append((level, title))
continue
if line.strip() != "**接口URL**":
continue
case = self._parse_case(lines, index, headings)
if case.get("url"):
case["case_id"] = "joyhub_{:04d}".format(len(cases) + 1)
cases.append(case)
return cases
def _parse_case(self, lines, url_index, headings):
title = self._case_title(headings, url_index)
url = self._next_quote_value(lines, url_index)
method = self._find_section_quote(lines, url_index, "**请求方式**") or "POST"
content_type = self._find_section_quote(lines, url_index, "**Content-Type**") or "json"
body_text = self._find_code_block(lines, url_index, "**请求Body参数**")
query = self._find_param_table(lines, url_index, "**请求Query参数**")
headers = self._find_headers(lines, url_index)
body = self._parse_body(body_text)
return {
"name": title,
"method": method.upper(),
"url": url,
"content_type": content_type,
"headers": headers,
"query": query,
"body": body,
"raw_body": body_text,
}
@staticmethod
def _parse_heading(line):
match = re.match(r"^(#{2,6})\s+(.+?)\s*$", line)
if not match:
return None
return len(match.group(1)), match.group(2).strip()
@staticmethod
def _case_title(headings, url_index):
if headings:
return " / ".join(title for _, title in headings[-3:])
return "HubOps接口{}".format(url_index + 1)
@staticmethod
def _next_quote_value(lines, start):
for index in range(start + 1, min(start + 8, len(lines))):
line = lines[index].strip()
if line.startswith(">"):
value = line[1:].strip()
if value and value != "暂无参数":
return value
return ""
@staticmethod
def _section_end(lines, start):
for index in range(start + 1, len(lines)):
line = lines[index].strip()
if line.startswith("## ") or line.startswith("### ") or line == "**接口URL**":
return index
return len(lines)
def _find_section_quote(self, lines, url_index, section_name):
start = max(0, url_index - 80)
end = self._section_end(lines, url_index)
for index in range(start, min(end, len(lines))):
if lines[index].strip() == section_name:
return self._next_quote_value(lines, index)
return None
def _find_code_block(self, lines, url_index, section_name):
end = self._section_end(lines, url_index)
for index in range(url_index, end):
if lines[index].strip() != section_name:
continue
for code_start in range(index + 1, end):
if lines[code_start].strip().startswith("```"):
block = []
for code_end in range(code_start + 1, end):
if lines[code_end].strip().startswith("```"):
return "\n".join(block).strip()
block.append(lines[code_end])
return ""
def _find_param_table(self, lines, url_index, section_name):
end = self._section_end(lines, url_index)
for index in range(url_index, end):
if lines[index].strip() != section_name:
continue
params = {}
for row_index in range(index + 1, end):
row = lines[row_index].strip()
if not row.startswith("|"):
if params:
break
continue
if "---" in row or "参数名" in row or "暂无参数" in row:
continue
columns = [column.strip() for column in row.strip("|").split("|")]
if len(columns) >= 2 and columns[0]:
params[columns[0]] = self._coerce_value(columns[1])
return params
return {}
def _find_headers(self, lines, url_index):
headers = {}
end = self._section_end(lines, url_index)
for index in range(url_index, end):
if lines[index].strip() != "**请求Header参数**":
continue
table_started = False
for row_index in range(index + 1, end):
row = lines[row_index].strip()
if row.startswith("**") or row.startswith("#") or row.startswith("*"):
break
if not row.startswith("|"):
if table_started:
break
continue
table_started = True
if "---" in row or "参数名" in row or "暂无参数" in row:
continue
columns = [column.strip() for column in row.strip("|").split("|")]
if len(columns) >= 2 and columns[0] and columns[0] != "Authorization":
headers[columns[0]] = columns[1]
return headers
return headers
@classmethod
def _parse_body(cls, body_text):
if not body_text or body_text == "暂无数据":
return {}
text = cls._clean_body(body_text)
for loader in (json.loads, ast.literal_eval):
try:
value = loader(text)
return value if isinstance(value, (dict, list)) else {}
except Exception:
pass
return {}
@staticmethod
def _clean_body(text):
text = re.sub(r"//.*", "", text)
text = re.sub(r"/\*.*?\*/", "", text, flags=re.S)
text = text.replace("{{token}}", "")
text = re.sub(r",\s*([}\]])", r"\1", text)
return text.strip()
@staticmethod
def _coerce_value(value):
if value in ("-", "暂无参数", ""):
return ""
if value.isdigit():
return int(value)
if value.lower() in ("true", "false"):
return value.lower() == "true"
return value
def load_hubops_cases():
return HubOpsParser().parse()

View File

@@ -0,0 +1,131 @@
# -*- coding: utf-8 -*-
import json
import logging
import os
from urllib.parse import urljoin
import allure
import requests
from joyhub_backend.library.auth import JoyhubAuth, TIMEOUT
MANAGER_BASE_URL = os.getenv(
"JOYHUB_MANAGER_BASE_URL",
"http://test-manager-api.best-envision.com",
)
class JoyhubInterface(object):
def __init__(self):
self.auth = JoyhubAuth()
self.session = requests.Session()
self.base_url = MANAGER_BASE_URL.rstrip("/") + "/"
def request(self, case_name, method, path, body=None, query=None, headers=None, expected_code=0):
url = path if path.startswith("http") else urljoin(self.base_url, path.lstrip("/"))
request_headers = self.auth.auth_headers()
if headers:
request_headers.update({key: value for key, value in headers.items() if key.lower() != "authorization"})
with allure.step("操作步骤:{}".format(case_name)):
self._attach_request(url, method, request_headers, body, query)
logging.info("case: %s", case_name)
logging.info("request url: %s", url)
logging.info("request method: %s", method)
logging.info("request headers: %s", request_headers)
logging.info("request body: %s", body)
logging.info("request query: %s", query)
request_kwargs = {
"method": method,
"url": url,
"params": query,
"headers": request_headers,
"timeout": TIMEOUT,
}
if method.upper() in ("POST", "PUT", "PATCH"):
request_kwargs["json"] = body
elif body:
request_kwargs["params"] = dict(query or {}, **body) if isinstance(body, dict) else query
response = self.session.request(**request_kwargs)
self._attach_response(response)
self._attach_log(case_name, url, method, request_headers, body, query, response)
logging.info("response status: %s", response.status_code)
logging.info("response body: %s", response.text)
is_business_api = self._is_business_api(url)
assertion_text = "HTTP状态码为200且业务code为{}".format(expected_code) if is_business_api else "HTTP状态码为2xx兼容非JSON/SSE响应"
allure.attach(assertion_text, "断言内容", allure.attachment_type.TEXT)
with allure.step("断言内容:{}".format(assertion_text)):
try:
if is_business_api:
assert response.status_code == 200, "HTTP状态码期望200实际{},响应{}".format(
response.status_code, response.text
)
data = self._safe_json(response)
assert isinstance(data, dict), "业务接口响应不是JSON对象响应{}".format(response.text)
assert "code" in data, "响应缺少 code 字段,响应{}".format(data)
assert data.get("code") == expected_code, "业务code期望{},实际{}msg={},响应{}".format(
expected_code, data.get("code"), data.get("msg"), data
)
else:
assert 200 <= response.status_code < 300, "HTTP状态码期望2xx实际{},响应{}".format(
response.status_code, response.text
)
data = self._non_json_result(response)
allure.attach("", "断言失败原因", allure.attachment_type.TEXT)
return data
except AssertionError as error:
allure.attach(str(error), "断言失败原因", allure.attachment_type.TEXT)
raise AssertionError("断言失败原因:{}".format(error))
@staticmethod
def _attach_request(url, method, headers, body, query):
allure.attach(str(url), "请求url", allure.attachment_type.TEXT)
allure.attach(str(method), "请求方式", allure.attachment_type.TEXT)
allure.attach(json.dumps(headers, ensure_ascii=False, indent=2), "请求头", allure.attachment_type.JSON)
allure.attach(json.dumps(query or {}, ensure_ascii=False, indent=2), "请求query", allure.attachment_type.JSON)
allure.attach(json.dumps(body or {}, ensure_ascii=False, indent=2), "请求体", allure.attachment_type.JSON)
@staticmethod
def _attach_response(response):
allure.attach(str(response.status_code), "响应状态码", allure.attachment_type.TEXT)
content_type = response.headers.get("Content-Type", "")
attachment_type = allure.attachment_type.JSON if "json" in content_type.lower() else allure.attachment_type.TEXT
allure.attach(response.text, "响应体/日志", attachment_type)
def _is_business_api(self, url):
return url.startswith(self.base_url)
@staticmethod
def _safe_json(response):
if not response.text.strip():
return None
return response.json()
@staticmethod
def _non_json_result(response):
try:
data = response.json()
except ValueError:
data = {
"status_code": response.status_code,
"content_type": response.headers.get("Content-Type", ""),
"text": response.text,
}
return data
@staticmethod
def _attach_log(case_name, url, method, headers, body, query, response):
log_text = "\n".join([
"case: {}".format(case_name),
"request url: {}".format(url),
"request method: {}".format(method),
"request headers: {}".format(headers),
"request query: {}".format(query or {}),
"request body: {}".format(body or {}),
"response status: {}".format(response.status_code),
"response body: {}".format(response.text),
])
allure.attach(log_text, "日志", allure.attachment_type.TEXT)

View File

@@ -0,0 +1,33 @@
# -*- coding: utf-8 -*-
import os
import sys
current_file_path = os.path.abspath(__file__)
project_root = os.path.abspath(os.path.join(os.path.dirname(current_file_path), '../../../..'))
if project_root not in sys.path:
sys.path.insert(0, project_root)
try:
import allure_pytest.listener
except ImportError:
allure_pytest = None
def _allure_test_fixtures_compatible(item):
fixturemanager = item.session._fixturemanager
fixturedefs = []
if hasattr(item, "_request") and hasattr(item._request, "fixturenames"):
for name in item._request.fixturenames:
try:
fixturedefs_pytest = fixturemanager.getfixturedefs(name, item)
except AttributeError:
fixturedefs_pytest = fixturemanager.getfixturedefs(name, item.nodeid)
if fixturedefs_pytest:
fixturedefs.extend(fixturedefs_pytest)
return fixturedefs
if allure_pytest is not None:
allure_pytest.listener._test_fixtures = _allure_test_fixtures_compatible

View File

@@ -0,0 +1,57 @@
# -*- coding: utf-8 -*-
import logging
import re
from urllib.parse import urljoin
import allure
import pytest
from joyhub_backend.library.hubops_parser import load_hubops_cases
from joyhub_backend.library.joyhub_interface import JoyhubInterface
ALL_CASES = load_hubops_cases()
def case_id(case):
raw_id = "{}-{}".format(case.get("case_id"), case.get("name"))
safe_id = re.sub(r"[^0-9A-Za-z_\u4e00-\u9fa5-]+", "_", raw_id)
return safe_id[:120]
@allure.feature("JoyHub Backend 接口自动化")
class TestHubOps(object):
test_case = JoyhubInterface()
def teardown_method(self):
with allure.step("后置:记录用例结束日志"):
logging.info("-----------------------------End-------------------------------")
@pytest.mark.parametrize("case", ALL_CASES, ids=case_id)
def test_hub_ops_api(self, case):
allure.dynamic.title("{} {}".format(case.get("case_id"), case.get("name")))
allure.dynamic.story(case.get("name"))
with allure.step("前置:初始化接口客户端并准备鉴权 token"):
headers = case.get("headers") or {}
query = case.get("query") or {}
body = case.get("body") or {}
response_data = self.test_case.request(
case.get("name"),
case.get("method"),
case.get("url"),
body=body,
query=query,
headers=headers,
)
with allure.step("断言内容:校验响应基础字段"):
request_url = case.get("url") or ""
full_url = request_url if request_url.startswith("http") else urljoin(self.test_case.base_url, request_url.lstrip("/"))
if full_url.startswith(self.test_case.base_url):
assert isinstance(response_data, dict), "断言失败原因响应不是JSON对象响应{}".format(response_data)
assert "code" in response_data, "断言失败原因响应缺少code字段响应{}".format(response_data)
assert response_data.get("msg") is not None, "断言失败原因msg字段不能为空响应{}".format(response_data)
else:
assert response_data is not None, "断言失败原因:非业务接口响应为空"
logging.info("断言通过:%s", case.get("name"))

View File

@@ -0,0 +1,170 @@
# -*- coding: utf-8 -*-
import argparse
import os
import shutil
import subprocess
import sys
current_file_path = os.path.abspath(__file__)
project_root = os.path.abspath(os.path.join(os.path.dirname(current_file_path), '../../'))
if project_root not in sys.path:
sys.path.insert(0, project_root)
TEST_CASE_DIR = 'joyhub_backend/test_case/TestCase'
case_dir = os.path.join(project_root, TEST_CASE_DIR)
ALLURE_RESULTS_DIR = os.path.join(project_root, 'joyhub_backend', 'test_case', 'reports', 'allure-results')
ALLURE_REPORT_DIR = os.path.join(project_root, 'joyhub_backend', 'test_case', 'reports', 'allure-report')
def ensure_dirs():
os.makedirs(ALLURE_RESULTS_DIR, exist_ok=True)
os.makedirs(ALLURE_REPORT_DIR, exist_ok=True)
def clean_allure_results():
if os.path.exists(ALLURE_RESULTS_DIR):
shutil.rmtree(ALLURE_RESULTS_DIR)
os.makedirs(ALLURE_RESULTS_DIR, exist_ok=True)
def find_test_files(directory):
test_files = []
for root, dirs, files in os.walk(directory):
for file in files:
if file.endswith('.py') and not file.startswith('__') and file != 'conftest.py':
test_files.append(os.path.join(root, file))
return test_files
def run_pytest(args_list):
env = os.environ.copy()
env['PYTHONPATH'] = project_root + (os.pathsep + env['PYTHONPATH'] if 'PYTHONPATH' in env else '')
cmd = ['python', '-m', 'pytest'] + args_list
print("开始执行pytest...")
print("执行命令: {}".format(' '.join('"{}"'.format(item) if ' ' in item else item for item in cmd)), flush=True)
result = subprocess.run(cmd, cwd=project_root, env=env)
print("pytest执行结束退出码: {}".format(result.returncode), flush=True)
return result.returncode
def run_tests(target=None, test_type='all'):
base_args = ['-v', '--tb=short', '--alluredir={}'.format(ALLURE_RESULTS_DIR)]
if test_type == 'all':
print("运行所有测试用例...")
test_files = find_test_files(case_dir)
if not test_files:
print("错误: 未找到测试文件")
return 1
args = test_files + base_args
elif test_type == 'dir':
full_path = os.path.join(case_dir, target.replace('/', os.sep).replace('\\', os.sep))
if not os.path.exists(full_path):
print("错误: 目录不存在: {}".format(full_path))
return 1
print("按目录运行: {}".format(target))
test_files = find_test_files(full_path)
if not test_files:
print("错误: 未找到测试文件")
return 1
args = test_files + base_args
elif test_type == 'file':
full_path = os.path.join(case_dir, target.replace('/', os.sep).replace('\\', os.sep))
if not os.path.exists(full_path):
print("错误: 文件不存在: {}".format(full_path))
return 1
print("按文件运行: {}".format(target))
args = [full_path] + base_args
elif test_type == 'keyword':
print("按关键字运行: {}".format(target))
test_files = find_test_files(case_dir)
args = test_files + ['-k={}'.format(target)] + base_args
elif test_type == 'marker':
print("按pytest标记运行: {}".format(target))
test_files = find_test_files(case_dir)
args = test_files + ['-m={}'.format(target)] + base_args
elif test_type == 'feature':
print("按Allure feature运行: {}".format(target))
test_files = find_test_files(case_dir)
args = test_files + ['--allure-features={}'.format(target)] + base_args
elif test_type == 'story':
print("按Allure story运行: {}".format(target))
test_files = find_test_files(case_dir)
args = test_files + ['--allure-stories={}'.format(target)] + base_args
else:
print("错误: 未知的测试类型: {}".format(test_type))
return 1
return run_pytest(args)
def generate_allure_report():
print("开始生成Allure报告...", flush=True)
if os.path.exists(ALLURE_REPORT_DIR):
shutil.rmtree(ALLURE_REPORT_DIR)
cmd = 'allure generate "{}" --output "{}"'.format(ALLURE_RESULTS_DIR, ALLURE_REPORT_DIR)
print("执行命令: {}".format(cmd), flush=True)
try:
subprocess.run(cmd, check=True, shell=True)
print("Allure报告生成成功: {}".format(ALLURE_REPORT_DIR))
print("打开报告命令: allure open \"{}\"".format(ALLURE_REPORT_DIR))
return 0
except (subprocess.CalledProcessError, FileNotFoundError, OSError) as error:
print("生成Allure报告失败: {}".format(error))
print("手动执行: {}".format(cmd))
return 1
def open_allure_report():
cmd = 'allure open "{}"'.format(ALLURE_REPORT_DIR)
try:
subprocess.Popen(cmd, shell=True)
print("Allure报告已打开: {}".format(ALLURE_REPORT_DIR))
return 0
except (FileNotFoundError, OSError) as error:
print("打开Allure报告失败: {}".format(error))
return 1
def main():
parser = argparse.ArgumentParser(description='JoyHub Backend 接口自动化测试执行工具')
run_group = parser.add_mutually_exclusive_group(required=False)
run_group.add_argument('--feature', type=str, help='按Allure feature运行')
run_group.add_argument('--story', type=str, help='按Allure story运行')
run_group.add_argument('--dir', type=str, help='按目录运行相对于TestCase目录')
run_group.add_argument('--file', type=str, help='按文件运行相对于TestCase目录')
run_group.add_argument('--keyword', type=str, help='按关键字运行')
run_group.add_argument('--marker', type=str, help='按pytest标记运行')
parser.add_argument('--report', action='store_true', help='生成Allure报告')
parser.add_argument('--open', action='store_true', help='打开Allure报告')
parser.add_argument('--no-report', action='store_true', help='不生成Allure报告')
args = parser.parse_args()
ensure_dirs()
clean_allure_results()
if args.feature:
exit_code = run_tests(args.feature, 'feature')
elif args.story:
exit_code = run_tests(args.story, 'story')
elif args.dir:
exit_code = run_tests(args.dir, 'dir')
elif args.file:
exit_code = run_tests(args.file, 'file')
elif args.keyword:
exit_code = run_tests(args.keyword, 'keyword')
elif args.marker:
exit_code = run_tests(args.marker, 'marker')
else:
exit_code = run_tests()
if args.report or not args.no_report:
generate_allure_report()
if args.open:
open_allure_report()
print("=" * 80)
print("测试执行完成" if exit_code == 0 else "测试执行失败,退出码: {}".format(exit_code))
print("=" * 80)
sys.exit(exit_code)
if __name__ == '__main__':
main()

16
node_modules/.bin/acorn generated vendored
View File

@@ -1,16 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../acorn/bin/acorn" "$@"
else
exec node "$basedir/../acorn/bin/acorn" "$@"
fi

17
node_modules/.bin/acorn.cmd generated vendored
View File

@@ -1,17 +0,0 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\acorn\bin\acorn" %*

28
node_modules/.bin/acorn.ps1 generated vendored
View File

@@ -1,28 +0,0 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../acorn/bin/acorn" $args
} else {
& "$basedir/node$exe" "$basedir/../acorn/bin/acorn" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../acorn/bin/acorn" $args
} else {
& "node$exe" "$basedir/../acorn/bin/acorn" $args
}
$ret=$LASTEXITCODE
}
exit $ret

16
node_modules/.bin/esbuild generated vendored
View File

@@ -1,16 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../esbuild/bin/esbuild" "$@"
else
exec node "$basedir/../esbuild/bin/esbuild" "$@"
fi

17
node_modules/.bin/esbuild.cmd generated vendored
View File

@@ -1,17 +0,0 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\esbuild\bin\esbuild" %*

28
node_modules/.bin/esbuild.ps1 generated vendored
View File

@@ -1,28 +0,0 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../esbuild/bin/esbuild" $args
} else {
& "$basedir/node$exe" "$basedir/../esbuild/bin/esbuild" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../esbuild/bin/esbuild" $args
} else {
& "node$exe" "$basedir/../esbuild/bin/esbuild" $args
}
$ret=$LASTEXITCODE
}
exit $ret

16
node_modules/.bin/js-yaml generated vendored
View File

@@ -1,16 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../js-yaml/bin/js-yaml.js" "$@"
else
exec node "$basedir/../js-yaml/bin/js-yaml.js" "$@"
fi

17
node_modules/.bin/js-yaml.cmd generated vendored
View File

@@ -1,17 +0,0 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\js-yaml\bin\js-yaml.js" %*

28
node_modules/.bin/js-yaml.ps1 generated vendored
View File

@@ -1,28 +0,0 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../js-yaml/bin/js-yaml.js" $args
} else {
& "$basedir/node$exe" "$basedir/../js-yaml/bin/js-yaml.js" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../js-yaml/bin/js-yaml.js" $args
} else {
& "node$exe" "$basedir/../js-yaml/bin/js-yaml.js" $args
}
$ret=$LASTEXITCODE
}
exit $ret

16
node_modules/.bin/jsondiffpatch generated vendored
View File

@@ -1,16 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../jsondiffpatch/bin/jsondiffpatch.js" "$@"
else
exec node "$basedir/../jsondiffpatch/bin/jsondiffpatch.js" "$@"
fi

17
node_modules/.bin/jsondiffpatch.cmd generated vendored
View File

@@ -1,17 +0,0 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\jsondiffpatch\bin\jsondiffpatch.js" %*

28
node_modules/.bin/jsondiffpatch.ps1 generated vendored
View File

@@ -1,28 +0,0 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../jsondiffpatch/bin/jsondiffpatch.js" $args
} else {
& "$basedir/node$exe" "$basedir/../jsondiffpatch/bin/jsondiffpatch.js" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../jsondiffpatch/bin/jsondiffpatch.js" $args
} else {
& "node$exe" "$basedir/../jsondiffpatch/bin/jsondiffpatch.js" $args
}
$ret=$LASTEXITCODE
}
exit $ret

16
node_modules/.bin/mcp-eval generated vendored
View File

@@ -1,16 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../mcp-evals/dist/cli.js" "$@"
else
exec node "$basedir/../mcp-evals/dist/cli.js" "$@"
fi

17
node_modules/.bin/mcp-eval.cmd generated vendored
View File

@@ -1,17 +0,0 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\mcp-evals\dist\cli.js" %*

28
node_modules/.bin/mcp-eval.ps1 generated vendored
View File

@@ -1,28 +0,0 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../mcp-evals/dist/cli.js" $args
} else {
& "$basedir/node$exe" "$basedir/../mcp-evals/dist/cli.js" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../mcp-evals/dist/cli.js" $args
} else {
& "node$exe" "$basedir/../mcp-evals/dist/cli.js" $args
}
$ret=$LASTEXITCODE
}
exit $ret

16
node_modules/.bin/mime generated vendored
View File

@@ -1,16 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../mime/cli.js" "$@"
else
exec node "$basedir/../mime/cli.js" "$@"
fi

17
node_modules/.bin/mime.cmd generated vendored
View File

@@ -1,17 +0,0 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\mime\cli.js" %*

28
node_modules/.bin/mime.ps1 generated vendored
View File

@@ -1,28 +0,0 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../mime/cli.js" $args
} else {
& "$basedir/node$exe" "$basedir/../mime/cli.js" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../mime/cli.js" $args
} else {
& "node$exe" "$basedir/../mime/cli.js" $args
}
$ret=$LASTEXITCODE
}
exit $ret

16
node_modules/.bin/nanoid generated vendored
View File

@@ -1,16 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../nanoid/bin/nanoid.cjs" "$@"
else
exec node "$basedir/../nanoid/bin/nanoid.cjs" "$@"
fi

17
node_modules/.bin/nanoid.cmd generated vendored
View File

@@ -1,17 +0,0 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\nanoid\bin\nanoid.cjs" %*

28
node_modules/.bin/nanoid.ps1 generated vendored
View File

@@ -1,28 +0,0 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../nanoid/bin/nanoid.cjs" $args
} else {
& "$basedir/node$exe" "$basedir/../nanoid/bin/nanoid.cjs" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../nanoid/bin/nanoid.cjs" $args
} else {
& "node$exe" "$basedir/../nanoid/bin/nanoid.cjs" $args
}
$ret=$LASTEXITCODE
}
exit $ret

16
node_modules/.bin/node-which generated vendored
View File

@@ -1,16 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../which/bin/node-which" "$@"
else
exec node "$basedir/../which/bin/node-which" "$@"
fi

17
node_modules/.bin/node-which.cmd generated vendored
View File

@@ -1,17 +0,0 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\which\bin\node-which" %*

28
node_modules/.bin/node-which.ps1 generated vendored
View File

@@ -1,28 +0,0 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../which/bin/node-which" $args
} else {
& "$basedir/node$exe" "$basedir/../which/bin/node-which" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../which/bin/node-which" $args
} else {
& "node$exe" "$basedir/../which/bin/node-which" $args
}
$ret=$LASTEXITCODE
}
exit $ret

16
node_modules/.bin/openai generated vendored
View File

@@ -1,16 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../openai/bin/cli" "$@"
else
exec node "$basedir/../openai/bin/cli" "$@"
fi

17
node_modules/.bin/openai.cmd generated vendored
View File

@@ -1,17 +0,0 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\openai\bin\cli" %*

28
node_modules/.bin/openai.ps1 generated vendored
View File

@@ -1,28 +0,0 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../openai/bin/cli" $args
} else {
& "$basedir/node$exe" "$basedir/../openai/bin/cli" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../openai/bin/cli" $args
} else {
& "node$exe" "$basedir/../openai/bin/cli" $args
}
$ret=$LASTEXITCODE
}
exit $ret

16
node_modules/.bin/playwright generated vendored
View File

@@ -1,16 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../@playwright/test/cli.js" "$@"
else
exec node "$basedir/../@playwright/test/cli.js" "$@"
fi

16
node_modules/.bin/playwright-core generated vendored
View File

@@ -1,16 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../playwright-core/cli.js" "$@"
else
exec node "$basedir/../playwright-core/cli.js" "$@"
fi

View File

@@ -1,17 +0,0 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\playwright-core\cli.js" %*

View File

@@ -1,28 +0,0 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../playwright-core/cli.js" $args
} else {
& "$basedir/node$exe" "$basedir/../playwright-core/cli.js" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../playwright-core/cli.js" $args
} else {
& "node$exe" "$basedir/../playwright-core/cli.js" $args
}
$ret=$LASTEXITCODE
}
exit $ret

View File

@@ -1,16 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../@executeautomation/playwright-mcp-server/dist/index.js" "$@"
else
exec node "$basedir/../@executeautomation/playwright-mcp-server/dist/index.js" "$@"
fi

View File

@@ -1,17 +0,0 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\@executeautomation\playwright-mcp-server\dist\index.js" %*

Some files were not shown because too many files have changed in this diff Show More