From b71c4a66e19d93a3a71f6c46651a0c37191663d2 Mon Sep 17 00:00:00 2001 From: qiaoxinjiu Date: Mon, 18 May 2026 10:04:56 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0module=E8=A1=A8status?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=E5=8F=8A=E7=9B=B8=E5=85=B3=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 在module表新增status字段(0:待确认;1:正常;2:弃用) 2. 修改/document/generate-cases接口,创建模块时设置status=0 3. 修改/case/restore接口,恢复用例时同步更新模块及其父模块的status为1 4. 修改/case/list接口,支持module_status参数过滤,默认只显示status=1的模块 5. 修改/case/list接口,返回module_path字段 6. 修改/plan/case/list接口,返回module_path字段 7. 修改/module/tree接口,默认筛选status=1的数据 8. 优化数据库连接池配置,添加连接验证和自动重试机制 --- __pycache__/const.cpython-38.pyc | Bin 2006 -> 2006 bytes app/api/__pycache__/views.cpython-38.pyc | Bin 43314 -> 50891 bytes .../__pycache__/caseController.cpython-38.pyc | Bin 13057 -> 15926 bytes .../__pycache__/planController.cpython-38.pyc | Bin 7663 -> 7755 bytes app/api/controller/caseController.py | 111 +++++- app/api/controller/planController.py | 7 +- .../__pycache__/caseModel.cpython-38.pyc | Bin 3246 -> 3379 bytes app/api/model/caseModel.py | 2 + app/api/views.py | 327 +++++++++++++++++- check_permission_table.py | 36 -- common/__pycache__/sqlSession.cpython-38.pyc | Bin 3614 -> 4320 bytes common/sqlSession.py | 73 ++-- const.py | 8 +- generate_automation_menus.py | 75 ---- 14 files changed, 489 insertions(+), 150 deletions(-) delete mode 100644 check_permission_table.py delete mode 100644 generate_automation_menus.py diff --git a/__pycache__/const.cpython-38.pyc b/__pycache__/const.cpython-38.pyc index d8989899ef076c1aa9b94b177ab70fd8dec3faed..eccf79f239840bab95cd1c5d00b28752981b1f16 100644 GIT binary patch delta 27 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 Y!hCDio0k1<$7}fq(=lqWPPeT853*i7uK)l5 literal 43314 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 Xd$!_ve_ioX2xE>;-%U#Er1}2=_^k6% diff --git a/app/api/controller/__pycache__/caseController.cpython-38.pyc b/app/api/controller/__pycache__/caseController.cpython-38.pyc index 92c9c249a7344c110a167259d8e2ba0d4344fe78..e3e5e3a0b086a713f80c6d5034b0d393ef7102ec 100644 GIT binary patch delta 7340 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 YL{v&8*}L4o;qB;RgYK*HpKloXUqsO35dZ)H delta 4703 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 Sx3Jgw!TrDd;*r7!hW-cYCObI* diff --git a/app/api/controller/__pycache__/planController.cpython-38.pyc b/app/api/controller/__pycache__/planController.cpython-38.pyc index 362c35419892391159d7ae9a48eef3f3964d39fd..3368fc4c3a610b1d5f4ca794535a3e1b6f81b8ea 100644 GIT binary patch delta 517 zcmX|8ze^)Q6rML1_rjW8_hPcUiHVA!N94FpR7`1MWg{X8hXyBVVm7*y95xdI=O3W( zT9Kr&5$+V5bhdI=h}A**!&0uc@y+^U;ChGunY^2)w+ zppQ4sf7r&WPd{M?HhsWwt%bw^}hx)JNjc$5tnS;XmAru}adD$yBG zb{Bx1K=@T9)PTsH@)cIdFH1a6Nn@KHCC9MidN`B*HMpl`O+$c>=?f#!X`R}$O9rJY z6pc}W3RCQx+X4kuMxmJtcFK{5F>;3jmtSbCA3G>DcMBin0*R<1LyUV9YX_tcDH__< zV4TI6d_Q~L+$uH78_i0yR+iBXBCo+e8s Fch9C%g+BlQ delta 412 zcmX|*K}!Nb7>4ItL`B=xblqJo3nCDq4h2!7L=n*s5DA1Z$*t5?aWn!MsUOfG_^uIl zEegdSV9+7KAUbsM&|ip-6+|-<&G5bNGkh@bJ4n38m6R;I2tRM1Kl#nsj?(r*8hhRk zFtIa!2m83|%Sl7Pmoc?F^o3!%)s&gs@?DXp!sLSg9O$)h<|x_)qo&4UE#_g)(YwW* z%o8L`$>|AFcIJ#fGDhT2kdX)eT*tN=a0D-;B#DObNv-o1>w$s0zzfo%5DRtf#%>8L zVP9KbuyIWCscBsDgpnPk2@DE^51>@FB?+D4tEfcd+~^!`=`(8;j>mjzb}n`z5gVcZ zA!*lMwq|DP`MPCN5jAv|D!C)e%#^bwlZqg`*Dc;{-iX2hZW}4E@YaaHD!v*^iXyor xCy1*^jWAYawYwO61Yr0T>cbg6Onk#7_9pAzL;e+Q2ssgQiW}h-h#(6;{{sC%Y}5b% diff --git a/app/api/controller/caseController.py b/app/api/controller/caseController.py index b5f361f..aef146a 100644 --- a/app/api/controller/caseController.py +++ b/app/api/controller/caseController.py @@ -31,6 +31,8 @@ class CaseController(BaseCrudController): if hasattr(Module, 'is_delete'): query = query.filter(Module.is_delete == 0) + if hasattr(Module, 'status'): + query = query.filter(Module.status == 1) total = query.count() @@ -90,11 +92,18 @@ class CaseController(BaseCrudController): filters.append(Module.name.like('%{}%'.format(module_name))) for req_key, column in [('moduleId', TestCase.module_id), ('priority', TestCase.priority), - ('caseType', TestCase.case_type), ('status', TestCase.status), - ('isAuto', TestCase.is_auto)]: + ('caseType', TestCase.case_type), ('isAuto', TestCase.is_auto)]: value = self._get(self.req_data, req_key) if value not in (None, ''): filters.append(column == int(value)) + is_ai_generated = self._get(self.req_data, 'isAiGenerated', 'is_ai_generated') + if is_ai_generated not in (None, ''): + filters.append(TestCase.is_ai_generated == int(is_ai_generated)) + status = self._get(self.req_data, 'status') + if status not in (None, ''): + filters.append(TestCase.status == int(status)) + else: + filters.append(TestCase.status != 0) keyword = self._get(self.req_data, 'keyword') if keyword: @@ -108,7 +117,7 @@ class CaseController(BaseCrudController): if created_by_name: filters.append(User.real_name.like('%{}%'.format(created_by_name))) - query = self.session.query(TestCase, Project.name.label('project_name'), Module.name.label('module_name'), User.real_name.label('created_by_name')).\ + query = self.session.query(TestCase, Project.name.label('project_name'), Module.name.label('module_name'), Module.path.label('module_path'), User.real_name.label('created_by_name')).\ join(Project, TestCase.project_id == Project.id, isouter=True).\ join(Module, TestCase.module_id == Module.id, isouter=True).\ join(User, TestCase.created_by == User.id, isouter=True).\ @@ -120,6 +129,14 @@ class CaseController(BaseCrudController): query = query.filter(Project.is_delete == 0) if hasattr(Module, 'is_delete'): query = query.filter(or_(Module.is_delete == 0, Module.is_delete.is_(None))) + if hasattr(Module, 'status'): + module_status = self._get(self.req_data, 'moduleStatus', 'module_status') + if module_status not in (None, ''): + # 如果传入了module_status参数,按指定状态过滤 + query = query.filter(Module.status == int(module_status)) + else: + # 默认只查询状态为1的模块 + query = query.filter(or_(Module.status == 1, Module.status.is_(None))) if hasattr(User, 'is_delete'): query = query.filter(or_(User.is_delete == 0, User.is_delete.is_(None))) @@ -132,10 +149,11 @@ class CaseController(BaseCrudController): items = query.offset((page_num - 1) * page_size).limit(page_size).all() result_list = [] - for case, project_name, module_name, created_by_name in items: + for case, project_name, module_name, module_path, created_by_name in items: case_dict = self.serialize(case, ['is_delete']) case_dict['project_name'] = project_name or '' case_dict['module_name'] = module_name or '' + case_dict['module_path'] = module_path or '' case_dict['case_key'] = case_dict.get('case_key', '') case_dict['created_by_name'] = created_by_name or '' if not case_dict.get('steps'): @@ -184,6 +202,7 @@ class CaseController(BaseCrudController): 'tags': self._get(self.req_data, 'tags', default=[]), 'status': int(self._get(self.req_data, 'status', default=1)), 'is_auto': int(self._get(self.req_data, 'isAuto', default=0)), + 'is_ai_generated': int(self._get(self.req_data, 'isAiGenerated', default=0)), 'created_by': getattr(g, 'current_user_id', None), 'is_delete': 0 } @@ -195,7 +214,7 @@ class CaseController(BaseCrudController): if not case_id: return 0, 'caseId 为必传参数' update_info = {} - mapping = [('moduleId', 'module_id'), ('caseKey', 'case_key'), ('title', 'title'), ('preconditions', 'preconditions'), ('expectedResults', 'expected_results'), ('priority', 'priority'), ('caseType', 'case_type'), ('tags', 'tags'), ('status', 'status'), ('isAuto', 'is_auto')] + mapping = [('moduleId', 'module_id'), ('caseKey', 'case_key'), ('title', 'title'), ('preconditions', 'preconditions'), ('expectedResults', 'expected_results'), ('priority', 'priority'), ('caseType', 'case_type'), ('tags', 'tags'), ('status', 'status'), ('isAuto', 'is_auto'), ('isAiGenerated', 'is_ai_generated')] for req_key, column_key in mapping: value = self._get(self.req_data, req_key) if value is not None: @@ -208,10 +227,83 @@ class CaseController(BaseCrudController): return CaseService.update_by_id(self.session, TestCase, case_id, update_info) def case_delete(self): - case_id = self._get(self.req_data, 'caseId', 'id') - if not case_id: - return 0, 'caseId 为必传参数' - return CaseService.delete_by_id(self.session, TestCase, case_id) + case_ids = self._get(self.req_data, 'caseIds', 'caseId', 'ids', 'id') + if not case_ids: + return {}, 'caseIds 为必传参数' + if isinstance(case_ids, str): + case_ids = [case_id.strip() for case_id in case_ids.split(',') if case_id.strip()] + elif not isinstance(case_ids, list): + case_ids = [case_ids] + try: + case_ids = list({int(case_id) for case_id in case_ids if str(case_id).strip()}) + except ValueError: + return {}, 'caseIds 必须为数字数组或英文逗号分隔的数字字符串' + if not case_ids: + return {}, 'caseIds 为必传参数' + delete_count = self.session.query(TestCase).filter( + TestCase.id.in_(case_ids), + TestCase.is_delete == 0 + ).update({'is_delete': 1}, synchronize_session=False) + err = self.session.done(close=False) + if err: + return {}, f'删除失败!{err}' + return {'caseIds': case_ids, 'deletedCount': delete_count}, '' + + def case_restore(self): + case_ids = self._get(self.req_data, 'caseIds', 'caseId', 'ids', 'id') + if not case_ids: + return {}, 'caseIds 为必传参数' + if isinstance(case_ids, str): + case_ids = [case_id.strip() for case_id in case_ids.split(',') if case_id.strip()] + elif not isinstance(case_ids, list): + case_ids = [case_ids] + try: + case_ids = list({int(case_id) for case_id in case_ids if str(case_id).strip()}) + except ValueError: + return {}, 'caseIds 必须为数字数组或英文逗号分隔的数字字符串' + if not case_ids: + return {}, 'caseIds 为必传参数' + # 先获取需要恢复的用例对应的模块ID + cases = self.session.query(TestCase).filter( + TestCase.id.in_(case_ids), + TestCase.status == 0, + TestCase.is_delete == 0 + ).all() + module_ids = list({case.module_id for case in cases if case.module_id}) + # 更新用例状态 + update_count = self.session.query(TestCase).filter( + TestCase.id.in_(case_ids), + TestCase.status == 0, + TestCase.is_delete == 0 + ).update({'status': 1}, synchronize_session=False) + # 更新模块状态为1,同时更新父模块状态 + if module_ids: + # 获取所有需要更新的模块ID(包括父模块) + all_module_ids = set(module_ids) + current_ids = module_ids.copy() + + # 递归获取所有父模块ID + while current_ids: + parents = self.session.query(Module.parent_id).filter( + Module.id.in_(current_ids), + Module.parent_id != 0, + Module.is_delete == 0 + ).all() + parent_ids = [p[0] for p in parents if p[0] not in all_module_ids] + if not parent_ids: + break + all_module_ids.update(parent_ids) + current_ids = parent_ids + + # 更新所有模块(包括父模块)的状态为1 + self.session.query(Module).filter( + Module.id.in_(list(all_module_ids)), + Module.is_delete == 0 + ).update({'status': 1}, synchronize_session=False) + err = self.session.done(close=False) + if err: + return {}, f'恢复失败!{err}' + return {'caseIds': case_ids, 'updatedCount': update_count}, '' def snapshot_create(self): case_id = self._get(self.req_data, 'caseId') @@ -374,6 +466,7 @@ class CaseController(BaseCrudController): tags=tags, status=1, is_auto=0, + is_ai_generated=0, created_by=getattr(g, 'current_user_id', None), is_delete=0 ) diff --git a/app/api/controller/planController.py b/app/api/controller/planController.py index b7ee195..e85c849 100644 --- a/app/api/controller/planController.py +++ b/app/api/controller/planController.py @@ -116,7 +116,7 @@ class PlanController(BaseCrudController): module_ids = [case.module_id for case in cases if case.module_id] if module_ids: modules = self.session.query(Module).filter(Module.id.in_(module_ids), Module.is_delete == 0).all() - module_info_map = {module.id: module.name for module in modules} + module_info_map = {module.id: {'name': module.name, 'path': module.path} for module in modules} result_list = [] for item in items: @@ -126,13 +126,16 @@ class PlanController(BaseCrudController): case_dict['case_title'] = case_info_map[item.case_id]['title'] module_id = case_info_map[item.case_id].get('module_id') if module_id and module_id in module_info_map: - case_dict['module_name'] = module_info_map[module_id] + case_dict['module_name'] = module_info_map[module_id]['name'] + case_dict['module_path'] = module_info_map[module_id].get('path', '') else: case_dict['module_name'] = '' + case_dict['module_path'] = '' else: case_dict['case_key'] = '' case_dict['case_title'] = '' case_dict['module_name'] = '' + case_dict['module_path'] = '' result_list.append(case_dict) return {'list': result_list, 'total': total} diff --git a/app/api/model/__pycache__/caseModel.cpython-38.pyc b/app/api/model/__pycache__/caseModel.cpython-38.pyc index 58bf4b7945497c3360da851767ca6534283123bc..f0611cfb44ec50573cedd0bff338455b08d80771 100644 GIT binary patch delta 692 zcmZ1{xmk)Yl$V!_0SM%4*s_xNHuA+VGImTp&uKJyE~C3hDoZMN3P*}i3Rf?46n~0v zFoUMZ+^-{UaVX4e$Q+}AphCg#ZPza0CJ2#l6#t;Pg&uo zDKPmgQ=8x|w&Ie+lG5Up3`H71-9;LcW0;*pg@8;BMixc^Mm``E0%9O*@0Q6i<;#kx3B-IzkfYB-Rw!6wY3zC@CNtBqIlwkp}W)Qbkhan;BD>QWR1Y zds(7n5n^x|r4;2})+o6Y6`*HSH-BbnXH+hggZk#>+>HWLL7*T)h7RESLEVj|U5R);hpGZo*zb#PYsO z9ADu0FOr8K{30dNRke`#x%-Z^i;k*RXcL{(y6bjcI|h6Tj6py4>g~i8Jq<}L z>8FjgfLGoqS3IfGJT=|*iW`;kHVy`d7d|F@ACu9;$PgMyy)Hr!REUBF5r~mQ-o+x{ zCgocT>Op4kGI-xGz>ixQgNz}@FrI~SeN$}ej1Xg*@n7dz3S==EZc^F89N3r-U&9=# zM#=bH^uQQzo~M+WA)Ou9*>z;m6;k86lXz!jm$*gE{0xd>*)2K$c3h;qQBp5P_}cYj evj}gth_jLN6#t0iktFB;DTIdEsTt9RX!s3@hHTdW diff --git a/app/api/model/caseModel.py b/app/api/model/caseModel.py index e798739..96915d0 100644 --- a/app/api/model/caseModel.py +++ b/app/api/model/caseModel.py @@ -17,6 +17,7 @@ class Module(Base): sort_order = Column(Integer, default=0, comment='排序') path = Column(String(512), comment='模块路径') is_delete = Column(Integer, default=0, comment='0:未删除;1:已删除') + status = Column(Integer, default=0, comment='0:待确认;1:正常;2:弃用') class TestCase(Base): @@ -34,6 +35,7 @@ class TestCase(Base): tags = Column(ARRAY(String(64)), server_default=text("'{}'::varchar[]"), comment='标签') status = Column(SmallInteger, default=1, comment='1:正常 2:已废弃 3:评审中 4:评审通过') is_auto = Column(Integer, default=0, comment='0:未实现自动化;1:已实现自动化') + is_ai_generated = Column(Integer, default=0, comment='0:非AI生成;1:AI生成') created_by = Column(BigInteger, comment='创建人') is_delete = Column(Integer, default=0, comment='0:未删除;1:已删除') created_time = Column(TIMESTAMP, server_default=text('CURRENT_TIMESTAMP'), nullable=True, comment='创建时间') diff --git a/app/api/views.py b/app/api/views.py index 3cf7147..6a23381 100644 --- a/app/api/views.py +++ b/app/api/views.py @@ -18,6 +18,8 @@ from .controller.userController import UserController from .controller.bugController import BugController, BugUploadController from .controller.projectHookController import ProjectHookController from .controller.automationController import AutomationController +from .controller.skillController import SkillController +from .controller.documentSourceController import DocumentSourceController api = Blueprint('api', __name__) @@ -514,16 +516,31 @@ def case_update(): @permission_required('case:delete') def case_delete(): try: - delete_id, err_msg = CaseController(request.get_json() or {}).case_delete() + ret, err_msg = CaseController(request.get_json() or {}).case_delete() if err_msg: logger.warning(f'case_delete失败:{err_msg}, 请求参数:{request.get_json()}') return ApiResponse.build_failure(40012, msg=err_msg) - return ApiResponse.build_success(20000, data={'id': delete_id}) + return ApiResponse.build_success(20000, data=ret) except Exception as e: logger.error(f'case_delete异常:{str(e)}, 请求参数:{request.get_json()}, 堆栈:{traceback.format_exc()}') return ApiResponse.build_failure(40012, msg=f'删除失败:{str(e)[:100]}') +@api.route('/case/restore', methods=['POST']) +@login_required +@permission_required('case:update') +def case_restore(): + try: + ret, err_msg = CaseController(request.get_json() or {}).case_restore() + if err_msg: + logger.warning(f'case_restore失败:{err_msg}, 请求参数:{request.get_json()}') + return ApiResponse.build_failure(40012, msg=err_msg) + return ApiResponse.build_success(20000, data=ret) + except Exception as e: + logger.error(f'case_restore异常:{str(e)}, 请求参数:{request.get_json()}, 堆栈:{traceback.format_exc()}') + return ApiResponse.build_failure(40012, msg=f'恢复失败:{str(e)[:100]}') + + @api.route('/case/import', methods=['POST']) @login_required @permission_required('case:create') @@ -922,6 +939,159 @@ def automation_execution_abort(): controller.close_session() +# ========================= +# 测试 Skills 与业务规则接口 +# ========================= + + +@api.route('/skill/create', methods=['POST']) +@login_required +@permission_required('skill:create') +def skill_create(): + controller = SkillController(request.get_json() or {}) + try: + create_id, err_msg = controller.skill_create() + if err_msg: + return ApiResponse.build_failure(40009, msg=err_msg) + return ApiResponse.build_success(20000, data={'id': create_id}) + finally: + controller.close_session() + + +@api.route('/skill/update', methods=['POST']) +@login_required +@permission_required('skill:update') +def skill_update(): + controller = SkillController(request.get_json() or {}) + try: + update_id, err_msg = controller.skill_update() + if err_msg: + return ApiResponse.build_failure(40012, msg=err_msg) + return ApiResponse.build_success(20000, data={'id': update_id}) + finally: + controller.close_session() + + +@api.route('/skill/delete', methods=['POST']) +@login_required +@permission_required('skill:delete') +def skill_delete(): + controller = SkillController(request.get_json() or {}) + try: + delete_id, err_msg = controller.skill_delete() + if err_msg: + return ApiResponse.build_failure(40012, msg=err_msg) + return ApiResponse.build_success(20000, data={'id': delete_id}) + finally: + controller.close_session() + + +@api.route('/skill/detail', methods=['GET']) +@login_required +@permission_required('skill:detail') +def skill_detail(): + controller = SkillController(request.args) + try: + ret, err_msg = controller.skill_detail() + if err_msg: + return ApiResponse.build_failure(40011, msg=err_msg) + return ApiResponse.build_success(20000, data=ret) + finally: + controller.close_session() + + +@api.route('/skill/list', methods=['GET']) +@login_required +@permission_required('skill:list') +def skill_list(): + controller = SkillController(request.args) + try: + return ApiResponse.build_success(20000, data=controller.skill_list()) + finally: + controller.close_session() + + +@api.route('/skill-rule/list', methods=['GET']) +@login_required +@permission_required('skill:list') +def skill_rule_list(): + controller = SkillController(request.args) + try: + ret, err_msg = controller.skill_rule_list() + if err_msg: + return ApiResponse.build_failure(40011, msg=err_msg) + return ApiResponse.build_success(20000, data=ret) + finally: + controller.close_session() + + +@api.route('/business-rule/create', methods=['POST']) +@login_required +@permission_required('business-rule:create') +def business_rule_create(): + controller = SkillController(request.get_json() or {}) + try: + create_id, err_msg = controller.business_rule_create() + if err_msg: + return ApiResponse.build_failure(40009, msg=err_msg) + return ApiResponse.build_success(20000, data={'id': create_id}) + finally: + controller.close_session() + + +@api.route('/business-rule/update', methods=['POST']) +@login_required +@permission_required('business-rule:update') +def business_rule_update(): + controller = SkillController(request.get_json() or {}) + try: + update_id, err_msg = controller.business_rule_update() + if err_msg: + return ApiResponse.build_failure(40012, msg=err_msg) + return ApiResponse.build_success(20000, data={'id': update_id}) + finally: + controller.close_session() + + +@api.route('/business-rule/delete', methods=['POST']) +@login_required +@permission_required('business-rule:delete') +def business_rule_delete(): + controller = SkillController(request.get_json() or {}) + try: + delete_id, err_msg = controller.business_rule_delete() + if err_msg: + return ApiResponse.build_failure(40012, msg=err_msg) + return ApiResponse.build_success(20000, data={'id': delete_id}) + finally: + controller.close_session() + + +@api.route('/business-rule/detail', methods=['GET']) +@login_required +@permission_required('business-rule:detail') +def business_rule_detail(): + controller = SkillController(request.args) + try: + ret, err_msg = controller.business_rule_detail() + if err_msg: + return ApiResponse.build_failure(40011, msg=err_msg) + return ApiResponse.build_success(20000, data=ret) + finally: + controller.close_session() + + +@api.route('/business-rule/list', methods=['GET']) +@login_required +@permission_required('business-rule:list') +def business_rule_list(): + controller = SkillController(request.args) + try: + return ApiResponse.build_success(20000, data=controller.business_rule_list()) + finally: + controller.close_session() + + # ========================= # 报告接口 # ========================= @@ -1600,3 +1770,156 @@ def bug_upload(): finally: controller.close_session() + +# ========================= +# 文档源接口 (PRD文档/飞书链接) +# ========================= + +@api.route('/document/list', methods=['GET']) +@login_required +@permission_required('document:list') +def document_list(): + controller = DocumentSourceController(request.args) + try: + return ApiResponse.build_success(20000, data=controller.document_list()) + finally: + controller.close_session() + + +@api.route('/document/detail', methods=['GET']) +@login_required +@permission_required('document:detail') +def document_detail(): + controller = DocumentSourceController(request.args) + try: + ret, err_msg = controller.document_detail() + if err_msg: + return ApiResponse.build_failure(40011, msg=err_msg) + return ApiResponse.build_success(20000, data=ret) + finally: + controller.close_session() + + +@api.route('/document/create', methods=['POST']) +@login_required +@permission_required('document:create') +def document_create(): + controller = DocumentSourceController(request.get_json() or {}) + try: + create_id, err_msg = controller.document_create() + if err_msg: + return ApiResponse.build_failure(40009, msg=err_msg) + return ApiResponse.build_success(20000, data={'id': create_id}) + finally: + controller.close_session() + + +@api.route('/document/update', methods=['POST']) +@login_required +@permission_required('document:update') +def document_update(): + controller = DocumentSourceController(request.get_json() or {}) + try: + update_id, err_msg = controller.document_update() + if err_msg: + return ApiResponse.build_failure(40012, msg=err_msg) + return ApiResponse.build_success(20000, data={'id': update_id}) + finally: + controller.close_session() + + +@api.route('/document/delete', methods=['POST']) +@login_required +@permission_required('document:delete') +def document_delete(): + controller = DocumentSourceController(request.get_json() or {}) + try: + delete_id, err_msg = controller.document_delete() + if err_msg: + return ApiResponse.build_failure(40012, msg=err_msg) + return ApiResponse.build_success(20000, data={'id': delete_id}) + finally: + controller.close_session() + + +@api.route('/document/refresh', methods=['POST']) +@login_required +@permission_required('document:update') +def document_refresh(): + controller = DocumentSourceController(request.get_json() or {}) + try: + success, err_msg = controller.document_refresh() + if err_msg: + return ApiResponse.build_failure(40009, msg=err_msg) + return ApiResponse.build_success(20000, data={'success': success}) + finally: + controller.close_session() + + +@api.route('/document/generate-cases', methods=['POST']) +@login_required +@permission_required('document:generate') +def document_generate_cases(): + controller = DocumentSourceController(request.get_json() or {}) + try: + ret, err_msg = controller.document_generate_cases() + if err_msg: + return ApiResponse.build_failure(40009, msg=err_msg) + return ApiResponse.build_success(20000, data=ret) + finally: + controller.close_session() + + +@api.route('/document/match-modules', methods=['POST']) +@login_required +@permission_required('document:generate') +def document_match_modules(): + controller = DocumentSourceController(request.get_json() or {}) + try: + ret = controller.document_match_modules() + return ApiResponse.build_success(20000, data=ret) + finally: + controller.close_session() + + +@api.route('/document/import-cases', methods=['POST']) +@login_required +@permission_required('document:import') +def document_import_cases(): + controller = DocumentSourceController(request.get_json() or {}) + try: + success_count, err_msg = controller.document_import_cases() + if err_msg: + return ApiResponse.build_failure(40009, msg=err_msg) + return ApiResponse.build_success(20000, data={'successCount': success_count}) + finally: + controller.close_session() + + +@api.route('/document/batch-create-modules', methods=['POST']) +@login_required +@permission_required('module:create') +def document_batch_create_modules(): + controller = DocumentSourceController(request.get_json() or {}) + try: + ret, err_msg = controller.document_batch_create_modules() + if err_msg: + return ApiResponse.build_failure(40009, msg=err_msg) + return ApiResponse.build_success(20000, data=ret) + finally: + controller.close_session() + + +@api.route('/document/upload', methods=['POST']) +@login_required +@permission_required('document:create') +def document_upload(): + controller = DocumentSourceController(request) + try: + ret, err_msg = controller.document_upload() + if err_msg: + return ApiResponse.build_failure(40009, msg=err_msg) + return ApiResponse.build_success(20000, data=ret) + finally: + controller.close_session() + diff --git a/check_permission_table.py b/check_permission_table.py deleted file mode 100644 index a5c9e7d..0000000 --- a/check_permission_table.py +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env python -# encoding: UTF-8 - -import psycopg2 - -def check_permission_table(): - try: - conn = psycopg2.connect( - host="39.170.26.156", - port=8366, - dbname="test", - user="postgres", - password="difyai123456" - ) - cursor = conn.cursor() - - cursor.execute(""" - SELECT column_name, data_type, is_nullable - FROM information_schema.columns - WHERE table_name = 'permission' - ORDER BY ordinal_position; - """) - - print("Permission 表结构:") - print("-" * 60) - print(f"{'字段名':<20} {'类型':<20} {'是否可空'}") - print("-" * 60) - for row in cursor.fetchall(): - print(f"{row[0]:<20} {row[1]:<20} {row[2]}") - - conn.close() - except Exception as e: - print("Error: " + str(e)) - -if __name__ == "__main__": - check_permission_table() \ No newline at end of file diff --git a/common/__pycache__/sqlSession.cpython-38.pyc b/common/__pycache__/sqlSession.cpython-38.pyc index d2a95ab1f4c84c861d71d2e85767aea9fc1f4012..c728a5e438119df05ffba941c5a588d6108f7b86 100644 GIT binary patch delta 2304 zcmZ`)-ES0C6u)=Ac6N65v!xAC%3?6GQCkXym|DKX1yQJk*3eEuHtXIgT{^q7+?fU1 zY+bcgVr;=O!V7|}kp~PBR1y-S;n5fWf{72jw6^iVSM|Yo?wvw6O`XX-_ndpq@7&+L z=iZsyZBMqv-ibyv1W$cNIrn99Hr9se?2BDT43!`vTj7#sXc&R6Sdmi1h+tGih7K)C zLPm_JM*JuuVWLeTqD=}$f<%Zug^VPT`cWo2d#wle&HmaRSr%c6WelP)o7{+}JQ;5{ z+lfL#Q`iU*m4pGL5{*Ql4-=h4q1Q-^#G#Ln1W7`#lN4!!K1!O&2Iym?g|tE+CtJxz zvI#OJ%p}=N+NRJXHd15@P)K{z*ivl zt7R*N9@hDVLiCx?1VpZnG2j3#7^#&@~lIgKQ0@=bIL=wSp@Bb)@97r+u5tq&o?9;obu{GL3BhEQ1; ztfQKA8ugPwGrFJ8H`{LS>z{SOwt{%+~voj-q?UU+b8>HhWQ z%QK5N9xPpXv~cxC5Z05fKF2V8Xz}`k#hGsxe)Iz0Gw|>C?xm~j?57v+%|i~z1h^e5 zxUQ=={tvkD==&f%U1b-5!F$q~l=rjLj&<)hsjcpZ%u8mW3fshPwja)3DwuqiX^7dO zi+NgRs}?JE#ZR3$G?+V;9XK_VJ2WtmJ#liN-@*SHO=ursGL+GjIUSfy(;W4DNDpp#i~@u!TB(AP^R?j#b_SEP=K1 z3ePkw{3HFXBs3hu8dgLBr*Hx%gc#V(f&!L?H-T&sTJU&F|9Pt)IGFOQ-4V#15h(ja z`11LxNyorqoP8-z&pK;q?FY|k?^dYQ`$O*D-3S)*ggk}HpqpeZ_8?#l@09ZC0X|y@ zf^vDw;u}tPgL4ILXdIriijKQB$LkPw#!H9Z?r5A_9=58^$X(2duZ3g*QUJ=wUT%aa z1-n!#y7UNm*CLL>*s#~6zS-G`P^oQM@8%1m>tfyjOwpTGkH6H2kqegXnCk+L0l?xr zxjEdumxDxJ2HM3au~YeUJ4NTbwU#3bvVZs_yaOL&bSX^{%mP2>kyjv`kOn1a4 zbPJn>-2}>x3_ZvMD;{O#pqw&e7VzdPehW-rtx&sSQg@89c^YW0-VF9F-3rZN-%Pj@ zlCT+TqSmR3@G4v~P1IrnrkZy~zt|I$#Fxr>xU!+MCJ=RLM(~A>ojxu!lqU%(eXW-i z3oe|G%KneNSoF1y)otJ!4+^<68{!%`*S>ca;>(BYM^BtnbFhW`U$1}>Zc delta 1629 zcmZuxJ!~9B6yBNLz5Thpy|ZzgA3KI9DZEPT1hA4|oCJ~pN)&7qlY(nb=Y3;)lfB#X z>>RcuN0zWVl){=8AxP&AiIy6=P|&S}M1>R~A<Es>FdvE5w@4Yu~-s~Ue zz8w!ARVu!L-xq)WlS~GC;W$~^yZH9imRI+P0S4Hq-}37|F%qL*#uNJ2MP7xoa0*WEl6s8|!5J9aHFijS7{)Q^gxn{otIn`*@KBzm zb7V}`=`ZI)+~S&4Q7VR)x=9L+PL_)m&hkc=CvVETX0#m>R3CmO3T2#kaONE(!uXDC z8IS4r%bEPk zo}p1m{#u$KzWlp1z8#sog7J%L&hi|?G?tsO$oOVaV(pcr&3ZL{U1+Y#cOGXxiNqiQ zarLCcBJ^lbl>f8-EmeFH5}!OBU0h2SdjY0bm}ndXi;0|eqZto9MU)4~3VW@~_$ID& zR#ua*r-bc&>d8_>3Qa{Fy(=2Dl0#x@c=xV+!&&+C& z*}DpdZLqj27+25cu&idjmJa551N9GoydF%FPgTlXxh%YoHe#kbR~MIGQyNutu2MW` zyPhc-?6Sgwtj!+D{mOi#Ga^0YF-0nz!(Ni(;W>FXoZ7Cb@Ifw`B8gi}tY*N+R9w}% zTs03@UBJ~9a&;+OC#|y5>2P%%{vndW?eMI_xY*>k)!xxR=jc7Ss5pZ&R}UKBf