diff --git a/app-builder/plugins/aipp-custom-model-center/src/main/resources/sql/data/tr_t_model_import.sql b/app-builder/plugins/aipp-custom-model-center/src/main/resources/sql/data/tr_t_model_import.sql index bc2a373d12..8d8099edeb 100644 --- a/app-builder/plugins/aipp-custom-model-center/src/main/resources/sql/data/tr_t_model_import.sql +++ b/app-builder/plugins/aipp-custom-model-center/src/main/resources/sql/data/tr_t_model_import.sql @@ -17,16 +17,16 @@ INSERT INTO "public"."store_tag" ("tool_unique_name", "name") VALUES ('f76205df- INSERT INTO "public"."store_tag" ("tool_unique_name", "name") VALUES ('77ee3e02-5870-4338-a8be-52c8ed42f3c7', 'MODEL') ON CONFLICT ("tool_unique_name", "name") DO NOTHING; INSERT INTO "public"."store_tag" ("tool_unique_name", "name") VALUES ('16816279-411b-48e1-b754-191abd61dcd0', 'MODEL') ON CONFLICT ("tool_unique_name", "name") DO NOTHING; -INSERT INTO "public"."store_plugin_tool" ("like_count", "download_count", "tool_name", "plugin_id", "tool_unique_name", "source", "icon") VALUES (0, 0, '切换默认模型', 'f231f908d0f0959acbc1df7b2f4b8f76b05219e3fa82fcb715def9f8858139e5', 'f76205df-1814-49b9-a473-c03ee99770b7', '', NULL) ON CONFLICT ("plugin_id", "tool_unique_name") DO NOTHING; -INSERT INTO "public"."store_plugin_tool" ("like_count", "download_count", "tool_name", "plugin_id", "tool_unique_name", "source", "icon") VALUES (0, 0, '删除模型', 'f231f908d0f0959acbc1df7b2f4b8f76b05219e3fa82fcb715def9f8858139e5', 'ff0a4b59-0be7-436f-8931-6a599ed9f8f3', '', NULL) ON CONFLICT ("plugin_id", "tool_unique_name") DO NOTHING; -INSERT INTO "public"."store_plugin_tool" ("like_count", "download_count", "tool_name", "plugin_id", "tool_unique_name", "source", "icon") VALUES (0, 0, '添加模型', 'f231f908d0f0959acbc1df7b2f4b8f76b05219e3fa82fcb715def9f8858139e5', '77ee3e02-5870-4338-a8be-52c8ed42f3c7', '', NULL) ON CONFLICT ("plugin_id", "tool_unique_name") DO NOTHING; -INSERT INTO "public"."store_plugin_tool" ("like_count", "download_count", "tool_name", "plugin_id", "tool_unique_name", "source", "icon") VALUES (0, 0, '获取用户模型列表', 'f231f908d0f0959acbc1df7b2f4b8f76b05219e3fa82fcb715def9f8858139e5', '16816279-411b-48e1-b754-191abd61dcd0', '', NULL) ON CONFLICT ("plugin_id", "tool_unique_name") DO NOTHING; +INSERT INTO "public"."store_plugin_tool" ("like_count", "download_count", "tool_name", "plugin_id", "tool_unique_name", "source", "icon", "user_group_id") VALUES (0, 0, '切换默认模型', 'f231f908d0f0959acbc1df7b2f4b8f76b05219e3fa82fcb715def9f8858139e5', 'f76205df-1814-49b9-a473-c03ee99770b7', '', NULL, '*') ON CONFLICT ("plugin_id", "tool_unique_name") DO NOTHING; +INSERT INTO "public"."store_plugin_tool" ("like_count", "download_count", "tool_name", "plugin_id", "tool_unique_name", "source", "icon", "user_group_id") VALUES (0, 0, '删除模型', 'f231f908d0f0959acbc1df7b2f4b8f76b05219e3fa82fcb715def9f8858139e5', 'ff0a4b59-0be7-436f-8931-6a599ed9f8f3', '', NULL, '*') ON CONFLICT ("plugin_id", "tool_unique_name") DO NOTHING; +INSERT INTO "public"."store_plugin_tool" ("like_count", "download_count", "tool_name", "plugin_id", "tool_unique_name", "source", "icon", "user_group_id") VALUES (0, 0, '添加模型', 'f231f908d0f0959acbc1df7b2f4b8f76b05219e3fa82fcb715def9f8858139e5', '77ee3e02-5870-4338-a8be-52c8ed42f3c7', '', NULL, '*') ON CONFLICT ("plugin_id", "tool_unique_name") DO NOTHING; +INSERT INTO "public"."store_plugin_tool" ("like_count", "download_count", "tool_name", "plugin_id", "tool_unique_name", "source", "icon", "user_group_id") VALUES (0, 0, '获取用户模型列表', 'f231f908d0f0959acbc1df7b2f4b8f76b05219e3fa82fcb715def9f8858139e5', '16816279-411b-48e1-b754-191abd61dcd0', '', NULL, '*') ON CONFLICT ("plugin_id", "tool_unique_name") DO NOTHING; -INSERT INTO "public"."store_plugin" ("plugin_id", "plugin_name", "extension", "deploy_status", "is_builtin", "source", "icon") VALUES ('f231f908d0f0959acbc1df7b2f4b8f76b05219e3fa82fcb715def9f8858139e5', '用戶查询模型工具', '{"uniqueness.groupId":"user-model-edit-groupId","pluginFullName":"aipp-custom-model-center-1.0.0-SNAPSHOT_1744769471992.jar","checksum":"77679d190769b46a8da7e2c08a1f2ce2680647e430514e7da1d39be3f3d17925","name":"用戶查询模型工具","description":"这是一个用戶查询模型工具","uniqueness.artifactId":"user-model-edit-artifactId","type":"java"}', 'DEPLOYED', TRUE, '', NULL) ON CONFLICT ("plugin_id") DO NOTHING; +INSERT INTO "public"."store_plugin" ("plugin_id", "plugin_name", "extension", "deploy_status", "is_builtin", "source", "icon", "user_group_id") VALUES ('f231f908d0f0959acbc1df7b2f4b8f76b05219e3fa82fcb715def9f8858139e5', '用戶查询模型工具', '{"uniqueness.groupId":"user-model-edit-groupId","pluginFullName":"aipp-custom-model-center-1.0.0-SNAPSHOT_1744769471992.jar","checksum":"77679d190769b46a8da7e2c08a1f2ce2680647e430514e7da1d39be3f3d17925","name":"用戶查询模型工具","description":"这是一个用戶查询模型工具","uniqueness.artifactId":"user-model-edit-artifactId","type":"java"}', 'DEPLOYED', TRUE, '', NULL, '*') ON CONFLICT ("plugin_id") DO NOTHING; -INSERT INTO "public"."app_builder_form" ("id", "name", "tenant_id", "appearance", "type", "create_by", "create_at", "update_by", "update_at", "is_deleted", "form_suite_id", "version") VALUES ('1568509614c245a39ce53bda9c3c2ec1', '模型管理表单', '31f20efc7e0848deab6a6bc10fc3021e', '{"imgUrl": "smart_form/6befc536-7e6d-48b5-8dcb-1c4d04ca4e92/form.png", "schema": {"name": "模型管理表单", "return": {"type": "object", "required": ["action", "info"], "properties": {"info": {"type": "object", "required": ["modelName", "modelId", "baseUrl", "isDefault", "userId", "apiKey"], "properties": {"apiKey": {"type": "string"}, "userId": {"type": "string"}, "baseUrl": {"type": "string"}, "modelId": {"type": "string"}, "isDefault": {"type": "integer"}, "modelName": {"type": "string"}, "type": {"type": "string"}}}, "action": {"enum": ["add", "delete", "switch", "quit"], "type": "string"}}}, "parameters": {"type": "object", "required": ["models"], "properties": {"models": {"type": "array", "items": {"type": "object", "required": ["modelId", "isDefault", "userId"], "properties": {"userId": {"type": "string"}, "baseUrl": {"type": "string"}, "modelId": {"type": "string"}, "createdAt": {"type": "string"}, "isDefault": {"type": "integer"}, "modelName": {"type": "string"}, "type": {"type": "string"}}}}}}}, "fileName": "模型管理表单.zip", "fileSize": 352510, "fileUuid": "7e9db4c01d8f482596fc1ddc78625496", "iframeUrl": "smart_form/6befc536-7e6d-48b5-8dcb-1c4d04ca4e92/build/index.html", "description": "这是一个模型管理表单"}', 'runtime', 'system', '2025-04-18 12:09:28.732006', 'system', '2025-04-18 12:09:28.73202', 0, '07b7ebd306944de683c2d060944da579', '1.0.0') ON CONFLICT ("id") DO NOTHING; +INSERT INTO "public"."app_builder_form" ("id", "name", "tenant_id", "appearance", "type", "create_by", "create_at", "update_by", "update_at", "is_deleted", "form_suite_id", "version", "user_group_id") VALUES ('1568509614c245a39ce53bda9c3c2ec1', '模型管理表单', '31f20efc7e0848deab6a6bc10fc3021e', '{"imgUrl": "smart_form/6befc536-7e6d-48b5-8dcb-1c4d04ca4e92/form.png", "schema": {"name": "模型管理表单", "return": {"type": "object", "required": ["action", "info"], "properties": {"info": {"type": "object", "required": ["modelName", "modelId", "baseUrl", "isDefault", "userId", "apiKey"], "properties": {"apiKey": {"type": "string"}, "userId": {"type": "string"}, "baseUrl": {"type": "string"}, "modelId": {"type": "string"}, "isDefault": {"type": "integer"}, "modelName": {"type": "string"}, "type": {"type": "string"}}}, "action": {"enum": ["add", "delete", "switch", "quit"], "type": "string"}}}, "parameters": {"type": "object", "required": ["models"], "properties": {"models": {"type": "array", "items": {"type": "object", "required": ["modelId", "isDefault", "userId"], "properties": {"userId": {"type": "string"}, "baseUrl": {"type": "string"}, "modelId": {"type": "string"}, "createdAt": {"type": "string"}, "isDefault": {"type": "integer"}, "modelName": {"type": "string"}, "type": {"type": "string"}}}}}}}, "fileName": "模型管理表单.zip", "fileSize": 352510, "fileUuid": "7e9db4c01d8f482596fc1ddc78625496", "iframeUrl": "smart_form/6befc536-7e6d-48b5-8dcb-1c4d04ca4e92/build/index.html", "description": "这是一个模型管理表单"}', 'runtime', 'system', '2025-04-18 12:09:28.732006', 'system', '2025-04-18 12:09:28.73202', 0, '07b7ebd306944de683c2d060944da579', '1.0.0', '*') ON CONFLICT ("id") DO NOTHING; -INSERT INTO "public"."app_builder_app" ("id", "name", "create_by", "create_at", "update_by", "update_at", "config_id", "flow_graph_id", "tenant_id", "type", "version", "attributes", "state", "app_built_type", "app_category", "collection_usr_cnt", "is_deleted", "path", "app_type", "app_suite_id", "is_active", "status", "unique_name", "publish_at", "app_id") VALUES ('cec6bfe7cb3a444f8a26a97ea513e501', '模型配置应用', 'system', '2025-07-25 03:33:56.014633', 'system', '2025-07-25 03:34:46.694847', '99bc4eda890041878bc0e4fe13114956', 'df3c7df760964d08b092f7c9d0eb9513', '31f20efc7e0848deab6a6bc10fc3021e', 'app', '1.0.0', '{"icon": "", "app_type": "b653edb7eb5a49be91abcd2c5877c6ad", "greeting": "", "store_id": "7a76cbd2-881d-469b-b2df-76abed7d0b61", "is_update": true, "description": "当你想要配置模型的时候,请使用我!", "latest_version": "1.0.0", "publishedUpdateLog": "", "publishedDescription": ""}', 'active', 'workflow', 'chatbot', 0, 0, 'P920UNZY2JkYoWhl', 'b653edb7eb5a49be91abcd2c5877c6ad', '0b4fe5a430104edfbe0dc6cff0ebea19', 't', 'published', '7a76cbd2-881d-469b-b2df-76abed7d0b61', '2025-07-25 03:34:46.69485', 'cec6bfe7cb3a444f8a26a97ea513e501') ON CONFLICT (id) DO NOTHING; +INSERT INTO "public"."app_builder_app" ("id", "name", "create_by", "create_at", "update_by", "update_at", "config_id", "flow_graph_id", "tenant_id", "type", "version", "attributes", "state", "app_built_type", "app_category", "collection_usr_cnt", "is_deleted", "path", "app_type", "app_suite_id", "is_active", "status", "unique_name", "publish_at", "app_id", "user_group_id") VALUES ('cec6bfe7cb3a444f8a26a97ea513e501', '模型配置应用', 'system', '2025-07-25 03:33:56.014633', 'system', '2025-07-25 03:34:46.694847', '99bc4eda890041878bc0e4fe13114956', 'df3c7df760964d08b092f7c9d0eb9513', '31f20efc7e0848deab6a6bc10fc3021e', 'app', '1.0.0', '{"icon": "", "app_type": "b653edb7eb5a49be91abcd2c5877c6ad", "greeting": "", "store_id": "7a76cbd2-881d-469b-b2df-76abed7d0b61", "is_update": true, "description": "当你想要配置模型的时候,请使用我!", "latest_version": "1.0.0", "publishedUpdateLog": "", "publishedDescription": ""}', 'active', 'workflow', 'chatbot', 0, 0, 'P920UNZY2JkYoWhl', 'b653edb7eb5a49be91abcd2c5877c6ad', '0b4fe5a430104edfbe0dc6cff0ebea19', 't', 'published', '7a76cbd2-881d-469b-b2df-76abed7d0b61', '2025-07-25 03:34:46.69485', 'cec6bfe7cb3a444f8a26a97ea513e501', '*') ON CONFLICT (id) DO NOTHING; INSERT INTO "public"."app_builder_config" ("id", "form_id", "app_id", "tenant_id", "create_by", "create_at", "update_by", "update_at", "is_deleted") VALUES ('99bc4eda890041878bc0e4fe13114956', 'b8986770a6ffef44bbf2a9f26d6fc1be', 'cec6bfe7cb3a444f8a26a97ea513e501', '31f20efc7e0848deab6a6bc10fc3021e', 'system', '2025-04-18 11:54:33.515505', 'system', '2025-04-18 12:12:12.847078', 0) ON CONFLICT (id) DO NOTHING; @@ -58,7 +58,7 @@ INSERT INTO "public"."flow_definition" ("definition_id", "meta_id", "name", "ten INSERT INTO "public"."flow_graph" ("id", "version", "tenant", "status", "name", "data", "created_by", "created_at", "updated_by", "updated_at", "previous", "is_deleted") VALUES ('df3c7df760964d08b092f7c9d0eb9513', '1.0.0', '31f20efc7e0848deab6a6bc10fc3021e', 'active', 'df3c7df760964d08b092f7c9d0eb9513', '{"id":"df3c7df760964d08b092f7c9d0eb9513","title":"df3c7df760964d08b092f7c9d0eb9513","source":"elsa","type":"jadeFlowGraph","tenant":"31f20efc7e0848deab6a6bc10fc3021e","setting":{"borderColor":"#047bfc","backColor":"whitesmoke","headColor":"steelblue","fontColor":"steelblue","captionfontColor":"whitesmoke","fontFace":"arial","captionfontFace":"arial black","fontSize":12,"captionfontSize":14,"fontStyle":"normal","captionfontStyle":"normal","fontWeight":"lighter","captionfontWeight":"lighter","hAlign":"center","vAlign":"top","captionhAlign":"center","lineHeight":1.5,"lineWidth":2,"captionlineHeight":1,"focusMargin":0,"focusBorderColor":"#047bfc","focusFontColor":"darkorange","focusBackColor":"whitesmoke","mouseInColor":"orange","mouseInBorderColor":"#047bfc","mouseInFontColor":"orange","mouseInBackColor":"whitesmoke","borderWidth":1,"focusBorderWidth":1,"globalAlpha":1,"backAlpha":0.15,"cornerRadius":4,"dashWidth":0,"autoText":false,"autoHeight":false,"autoWidth":false,"margin":25,"pad":10,"code":"","rotateDegree":0,"shadow":"","focusShadow":"","shadowData":"2px 2px 4px","outstanding":false,"pDock":"none","dockMode":"none","priority":0,"infoType":{"name":"none","next":"INFORMATION"},"progressStatus":{"name":"NONE","next":"UNKNOWN","color":"gray"},"progressPercent":0.65,"showedProgress":false,"itemPad":[5,5,5,5],"itemScroll":{"x":0,"y":0},"scrollLock":{"x":false,"y":false},"resizeable":true,"selectable":true,"rotateAble":true,"editable":true,"moveable":true,"dragable":true,"visible":true,"deletable":true,"allowLink":true,"shared":false,"strikethrough":false,"underline":false,"numberedList":false,"bulletedList":false,"enableAnimation":false,"enableSocial":true,"emphasized":false,"bulletSpeed":1,"tag":{},"allNodeNumLimit":99,"sameTypeNodeNumLimit":19,"outlineColor":"rgba(74,147,255,0.12)","outlineWidth":10},"pages":[{"x":-1169.9755830393424,"y":539.4722222222223,"id":"elsa-page:tvp1s6","bold":false,"mode":"configuration","text":"newFlowPage","type":"jadeFlowPage","dirty":true,"index":0,"width":1600,"hAlign":"left","height":800,"isPage":true,"italic":false,"scaleX":0.7000000000000001,"scaleY":0.7000000000000001,"vAlign":"top","itemPad":[0,0,0,0],"division":-1,"dockMode":"none","fontFace":"arial","fontSize":18,"hideText":true,"moveable":true,"shapesAs":{},"backColor":"#fbfbfc","container":"elsa-page:tvp1s6","dockAlign":"top","fontColor":"#ECD0A7","fontStyle":"normal","itemSpace":5,"namespace":"jadeFlow","fontWeight":"bold","itemScroll":{"x":0,"y":0},"borderColor":"white","focusBackColor":"#fbfbfc","shapes":[{"x":-170.8928571428571,"y":31.071428571428555,"id":"jade6qm5eg","pad":6,"bold":false,"text":"开始","type":"startNodeStart","dirty":false,"index":0,"width":360,"height":271,"italic":false,"shadow":"0 2px 4px 0 rgba(0,0,0,.1)","flowMeta":{"inputParams":[{"id":"91138f09-b635-43df-95c6-1fe3d1745829","from":"Expand","name":"input","type":"Object","value":[{"id":"input_ae2ffd6e-2b9e-4e73-9d7f-0e661ec3dbdb","from":"Input","name":"Question","type":"String","value":"","isVisible":true,"isRequired":true,"description":"这是用户输入的问题。","displayName":"用户问题","disableModifiable":true}],"config":[{"allowAdd":true}]},{"id":"4a770dc6-e3c9-475d-84c7-48dacc74a5b6","from":"Expand","name":"memory","type":"Object","value":[{"id":"a7675623-7fc7-468c-8910-e73c70e5e468","from":"Input","name":"memorySwitch","type":"Boolean","value":false},{"id":"cee9a31b-781c-4835-a616-ceed73be22f2","from":"Input","name":"type","type":"String","value":"ByConversationTurn"},{"id":"69592622-4291-409d-9d65-9faea83db657","from":"Input","name":"value","type":"Integer","value":"3"}]},{"id":"91138f09-b635-43df-95c6-1fe3d1745830","from":"Expand","name":"appConfig","type":"Object","value":[{"id":"input_ae2ffd6e-2b9e-4e73-9d7f-0e661ec3dadf","from":"Input","name":"appChatStyle","type":"String","value":"default"}]}],"triggerMode":"auto"},"hideText":true,"moveable":true,"runnable":true,"backColor":"white","container":"elsa-page:tvp1s6","dashWidth":0,"deletable":false,"namespace":"flowable","autoHeight":true,"emphasized":false,"rotateAble":false,"borderColor":"rgba(28,31,35,.08)","borderWidth":1,"focusShadow":"0 0 1px rgba(0,0,0,.3),0 4px 14px rgba(0,0,0,.1)","runningTask":0,"triggerMode":"auto","warningTask":0,"cornerRadius":8,"outlineColor":"rgba(74,147,255,0.12)","outlineWidth":10,"completedTask":0,"componentName":"startComponent","focusBackColor":"white","sourcePlatform":"official","enableAnimation":false,"mouseInBorderColor":"rgba(28,31,35,.08)"},{"x":2564.107142857142,"y":-146.60714285714283,"id":"jadesoux5i","pad":6,"bold":false,"text":"添加模型结束","type":"endNodeEnd","dirty":false,"index":1,"width":360,"height":181,"italic":false,"shadow":"0 2px 4px 0 rgba(0,0,0,.1)","flowMeta":{"callback":{"name":"通知回调","type":"general_callback","fitables":["modelengine.fit.jober.aipp.fitable.AippFlowEndCallback"],"converter":{"type":"mapping_converter","entity":{"inputParams":[{"id":"54dab89c-5693-4082-baa7-12c648d812f7","from":"Expand","name":"finalOutput","type":"Object","value":[{"id":"ffad80c2-3f60-4d57-93b2-c2362a5dab9c","from":"Reference","name":"finalOutput","type":"String","value":["output"],"editable":true,"isRequired":true,"description":"","referenceId":"output_bf03f587-05e6-47f6-b4b2-baf8017415bd","referenceKey":"output","referenceNode":"jadenavqab"}],"editable":false,"isRequired":false,"referenceId":"","referenceKey":"","referenceNode":""},{"id":"c26bf2ca-75b3-4a6f-bc47-132c2e170895","from":"Input","name":"enableLog","type":"Boolean","value":true}],"outputParams":[{}]}}},"triggerMode":"auto"},"hasError":false,"hideText":true,"moveable":true,"runnable":true,"backColor":"white","container":"elsa-page:tvp1s6","dashWidth":0,"deletable":true,"namespace":"flowable","autoHeight":true,"emphasized":false,"rotateAble":false,"borderColor":"rgba(28, 31, 35, 0.08)","borderWidth":1,"focusShadow":"0 0 1px rgba(0,0,0,.3),0 4px 14px rgba(0,0,0,.1)","runningTask":0,"triggerMode":"auto","warningTask":0,"cornerRadius":8,"outlineColor":"rgba(74, 147, 255, 0.12)","outlineWidth":10,"completedTask":0,"componentName":"endComponent","focusBackColor":"white","sourcePlatform":"official","enableAnimation":false,"focusBorderColor":"rgb(4, 123, 252)","mouseInBorderColor":"rgb(4, 123, 252)"},{"x":278.02238424402026,"y":428.19444444444423,"id":"jadevpescp","pad":6,"bold":false,"text":"获取用户模型列表","type":"toolInvokeNodeState","dirty":false,"index":2,"width":360,"height":185,"italic":false,"flowMeta":{"jober":{"name":"","type":"STORE_JOBER","entity":{"params":[{"name":"userId"}],"return":{"type":"array"},"uniqueName":"16816279-411b-48e1-b754-191abd61dcd0"},"fitables":[],"converter":{"type":"mapping_converter","entity":{"inputParams":[{"id":"userId_f4725c4a-ac63-4b51-ae86-8c0baca9b71d","from":"Reference","name":"userId","type":"String","value":["userId"],"isRequired":true,"description":"用户id","referenceId":"userId","referenceKey":"userId","referenceNode":"_systemEnv"}],"outputParams":[{"id":"output_78982629-c58c-4211-9f4b-369bdcfef31f","name":"output","type":"Array","value":[]}]}}},"joberFilter":{"type":"MINIMUM_SIZE_FILTER","threshold":1},"triggerMode":"auto"},"hasError":false,"hideText":true,"moveable":true,"runnable":true,"backColor":"white","container":"elsa-page:tvp1s6","dashWidth":0,"namespace":"jadeFlow","autoHeight":true,"emphasized":false,"enableMask":false,"rotateAble":false,"borderColor":"rgba(28, 31, 35, 0.08)","borderWidth":1,"runningTask":0,"triggerMode":"auto","warningTask":0,"cornerRadius":8,"outlineColor":"rgba(74, 147, 255, 0.12)","outlineWidth":10,"completedTask":0,"componentName":"toolInvokeComponent","focusBackColor":"white","sourcePlatform":"","enableAnimation":false,"focusBorderColor":"rgb(4, 123, 252)","focusBorderWidth":1,"mouseInBorderColor":"rgb(4, 123, 252)"},{"x":189.1071428571429,"y":166.57142857142856,"id":"jadexixl9n","pad":0,"bold":false,"text":"","type":"jadeEvent","dirty":true,"index":3,"textX":0,"textY":0,"width":88.91524138687737,"hAlign":"center","height":354.1230158730157,"italic":false,"margin":20,"toShape":"jadevpescp","endArrow":true,"hideText":true,"lineMode":{"type":"auto_curve"},"runnable":true,"allowLink":false,"backColor":"white","container":"elsa-page:tvp1s6","fromShape":"jade6qm5eg","lineWidth":2,"namespace":"elsa","beginArrow":false,"borderColor":"#B1B1B7","borderWidth":1,"curvePoint1":{"x":0,"y":0},"curvePoint2":{"x":0,"y":0},"brokenPoints":[],"endArrowSize":4,"arrowEndPoint":{"x":0,"y":0},"endArrowEmpty":false,"beginArrowSize":4,"arrowBeginPoint":{"x":0,"y":0},"beginArrowEmpty":false,"definedToConnector":"W","mouseInBorderColor":"#B1B1B7","allowSwitchLineMode":false,"definedFromConnector":"E"},{"x":638.0223842440203,"y":520.6944444444442,"id":"jade419ps4","pad":0,"bold":false,"text":"","type":"jadeEvent","dirty":true,"index":4,"textX":0,"textY":0,"width":51.85768072422525,"hAlign":"center","height":-75.52380952380997,"italic":false,"margin":20,"toShape":"jadedyz9lx","endArrow":true,"hideText":true,"lineMode":{"type":"auto_curve"},"runnable":true,"allowLink":false,"backColor":"white","container":"elsa-page:tvp1s6","fromShape":"jadevpescp","lineWidth":2,"namespace":"elsa","beginArrow":false,"borderColor":"#B1B1B7","borderWidth":1,"curvePoint1":{"x":0,"y":0},"curvePoint2":{"x":0,"y":0},"brokenPoints":[],"endArrowSize":4,"arrowEndPoint":{"x":0,"y":0},"endArrowEmpty":false,"beginArrowSize":4,"arrowBeginPoint":{"x":0,"y":0},"beginArrowEmpty":false,"definedToConnector":"W","mouseInBorderColor":"#B1B1B7","allowSwitchLineMode":false,"definedFromConnector":"E"},{"x":1170.885717539451,"y":175.33730158730177,"id":"jade0305an","pad":6,"bold":false,"text":"条件","type":"conditionNodeCondition","dirty":false,"index":5,"width":600,"height":339,"italic":false,"flowMeta":{"joberFilter":{"type":"MINIMUM_SIZE_FILTER","threshold":1},"triggerMode":"auto","conditionParams":{"branches":[{"id":"20e8e83b-31f2-4ba5-93b7-0920b2b7cc2e","type":"if","disabled":false,"runnable":true,"conditions":[{"id":"eaa48316-b65d-49f4-a9c2-0d1261cb4efe","value":[{"id":"3288e216-4f89-473c-b6b9-e9d80e66fe0c","from":"Reference","name":"left","type":"String","value":["output","action"],"referenceId":"15ee5d6e-03f7-4abc-8966-73d420997048","referenceKey":"action","referenceNode":"jadedyz9lx"},{"id":"e63c3cba-9edc-4d94-af84-e8ad0c319aa8","from":"Input","name":"right","type":"String","value":"add","referenceId":"","referenceKey":"","referenceNode":""}],"condition":"equal"}],"conditionRelation":"and"},{"id":"42754fab-4274-4e32-9811-9088eb80f691","type":"if","disabled":false,"runnable":true,"conditions":[{"id":"7122796c-36ce-41ea-96be-0ce69cfe704b","value":[{"id":"b9a64d7a-1ebc-40e1-a02b-2a793154b5fa","from":"Reference","name":"left","type":"String","value":["output","action"],"referenceId":"15ee5d6e-03f7-4abc-8966-73d420997048","referenceKey":"action","referenceNode":"jadedyz9lx"},{"id":"51b80568-1f7a-4cca-8c31-c42f41d5b63d","from":"Input","name":"right","type":"String","value":"delete","referenceId":"","referenceKey":"","referenceNode":""}],"condition":"equal"}],"conditionRelation":"and"},{"id":"79592b84-07fd-4212-9f50-71479aa86b22","type":"if","disabled":false,"runnable":true,"conditions":[{"id":"42692336-de84-4023-864e-3ee666da5d93","value":[{"id":"14a9b304-09dd-45ce-a421-6aa91703a1f4","from":"Reference","name":"left","type":"String","value":["output","action"],"referenceId":"15ee5d6e-03f7-4abc-8966-73d420997048","referenceKey":"action","referenceNode":"jadedyz9lx"},{"id":"557856d5-18c8-4a67-91d4-0cf4faec4060","from":"Input","name":"right","type":"String","value":"switch","referenceId":"","referenceKey":"","referenceNode":""}],"condition":"equal"}],"conditionRelation":"and"},{"id":"50b171e2-b8b6-46cb-89a3-a6e0883ae710","type":"else","disabled":false,"runnable":true,"conditions":[{"id":"90303c25-9b1b-4e87-8af8-e3c997331c38","value":[],"condition":"true"}],"conditionRelation":"and"}],"jadeNodeConfigChangeIgnored":true}},"hasError":false,"hideText":true,"moveable":true,"runnable":true,"backColor":"white","container":"elsa-page:tvp1s6","dashWidth":0,"namespace":"jadeFlow","autoHeight":true,"emphasized":false,"enableMask":false,"rotateAble":false,"borderColor":"rgba(28, 31, 35, 0.08)","borderWidth":1,"runningTask":0,"triggerMode":"auto","warningTask":0,"cornerRadius":8,"outlineColor":"rgba(74, 147, 255, 0.12)","outlineWidth":10,"completedTask":0,"componentName":"conditionComponent","focusBackColor":"white","sourcePlatform":"official","enableAnimation":false,"focusBorderColor":"rgb(4, 123, 252)","focusBorderWidth":1,"mouseInBorderColor":"rgb(4, 123, 252)"},{"x":1973.736669958303,"y":369.623015873016,"id":"jadeas9z1s","pad":6,"bold":false,"text":"删除模型","type":"toolInvokeNodeState","dirty":false,"index":6,"width":360,"height":185,"italic":false,"flowMeta":{"jober":{"name":"","type":"STORE_JOBER","entity":{"params":[{"name":"modelId"},{"name":"userId"}],"return":{"type":"string"},"uniqueName":"ff0a4b59-0be7-436f-8931-6a599ed9f8f3"},"fitables":[],"converter":{"type":"mapping_converter","entity":{"inputParams":[{"id":"modelId_e329ead9-4485-453a-8973-9047c1e06a9a","from":"Reference","name":"modelId","type":"String","value":["output","info","modelId"],"isRequired":true,"description":"模型id","referenceId":"0c0bab50-cb34-4c38-869d-68edcd24d107","referenceKey":"modelId","referenceNode":"jadedyz9lx"},{"id":"userId_47ee255d-9eeb-418c-aabc-8eb7871d0be5","from":"Reference","name":"userId","type":"String","value":["output","info","userId"],"isRequired":true,"description":"用户id","referenceId":"6a81539b-30ee-4a4c-92e0-958772550106","referenceKey":"userId","referenceNode":"jadedyz9lx"}],"outputParams":[{"id":"output_786cf758-f9af-4959-83e7-251a01e04fb0","name":"output","type":"String","value":[]}]}}},"joberFilter":{"type":"MINIMUM_SIZE_FILTER","threshold":1},"triggerMode":"auto"},"hasError":false,"hideText":true,"moveable":true,"runnable":true,"backColor":"white","container":"elsa-page:tvp1s6","dashWidth":0,"namespace":"jadeFlow","autoHeight":true,"emphasized":false,"enableMask":false,"rotateAble":false,"borderColor":"rgba(28, 31, 35, 0.08)","borderWidth":1,"runningTask":0,"triggerMode":"auto","warningTask":0,"cornerRadius":8,"outlineColor":"rgba(74, 147, 255, 0.12)","outlineWidth":10,"completedTask":0,"componentName":"toolInvokeComponent","focusBackColor":"white","sourcePlatform":"","enableAnimation":false,"focusBorderColor":"rgb(4, 123, 252)","focusBorderWidth":1,"mouseInBorderColor":"rgb(4, 123, 252)"},{"x":1759.93337291752,"y":296.003996228415,"id":"jade2cfmdw","pad":0,"bold":false,"text":"","type":"jadeEvent","dirty":true,"index":7,"textX":0,"textY":0,"width":220.20339686679063,"hAlign":"center","height":-367.2619327363504,"italic":false,"margin":20,"toShape":"jadenavqab","endArrow":true,"hideText":true,"lineMode":{"type":"auto_curve"},"runnable":true,"allowLink":false,"backColor":"white","container":"elsa-page:tvp1s6","fromShape":"jade0305an","lineWidth":2,"namespace":"elsa","beginArrow":false,"borderColor":"#B1B1B7","borderWidth":1,"curvePoint1":{"x":0,"y":0},"curvePoint2":{"x":0,"y":0},"brokenPoints":[],"endArrowSize":4,"arrowEndPoint":{"x":0,"y":0},"endArrowEmpty":false,"beginArrowSize":4,"arrowBeginPoint":{"x":0,"y":0},"beginArrowEmpty":false,"definedToConnector":"W","mouseInBorderColor":"#B1B1B7","allowSwitchLineMode":false,"definedFromConnector":"dynamic-0|20e8e83b-31f2-4ba5-93b7-0920b2b7cc2e"},{"x":1759.93337291752,"y":352.00397007049094,"id":"jade31ntj1","pad":0,"bold":false,"text":"","type":"jadeEvent","dirty":true,"index":8,"textX":0,"textY":0,"width":213.80329704078304,"hAlign":"center","height":110.11904580252508,"italic":false,"margin":20,"toShape":"jadeas9z1s","endArrow":true,"hideText":true,"lineMode":{"type":"auto_curve"},"runnable":true,"allowLink":false,"backColor":"white","container":"elsa-page:tvp1s6","fromShape":"jade0305an","lineWidth":2,"namespace":"elsa","beginArrow":false,"borderColor":"#B1B1B7","borderWidth":1,"curvePoint1":{"x":0,"y":0},"curvePoint2":{"x":0,"y":0},"brokenPoints":[],"endArrowSize":4,"arrowEndPoint":{"x":0,"y":0},"endArrowEmpty":false,"beginArrowSize":4,"arrowBeginPoint":{"x":0,"y":0},"beginArrowEmpty":false,"definedToConnector":"W","mouseInBorderColor":"#B1B1B7","allowSwitchLineMode":false,"definedFromConnector":"dynamic-1|42754fab-4274-4e32-9811-9088eb80f691"},{"x":1759.93337291752,"y":408.00397116040443,"id":"jadedmxi6l","pad":0,"bold":false,"text":"","type":"jadeEvent","dirty":true,"index":9,"textX":0,"textY":0,"width":227.34767540951998,"hAlign":"center","height":485.0238066173741,"italic":false,"margin":20,"toShape":"jade9gdgwb","endArrow":true,"hideText":true,"lineMode":{"type":"auto_curve"},"runnable":true,"allowLink":false,"backColor":"white","container":"elsa-page:tvp1s6","fromShape":"jade0305an","lineWidth":2,"namespace":"elsa","beginArrow":false,"borderColor":"#B1B1B7","borderWidth":1,"curvePoint1":{"x":0,"y":0},"curvePoint2":{"x":0,"y":0},"brokenPoints":[],"endArrowSize":4,"arrowEndPoint":{"x":0,"y":0},"endArrowEmpty":false,"beginArrowSize":4,"arrowBeginPoint":{"x":0,"y":0},"beginArrowEmpty":false,"definedToConnector":"W","mouseInBorderColor":"#B1B1B7","allowSwitchLineMode":false,"definedFromConnector":"dynamic-2|79592b84-07fd-4212-9f50-71479aa86b22"},{"x":2632.3078142497616,"y":322.4801587301588,"id":"jade7dv633","pad":6,"bold":false,"text":"删除模型结束","type":"endNodeEnd","dirty":false,"index":10,"width":360,"height":181,"italic":false,"flowMeta":{"callback":{"name":"通知回调","type":"general_callback","fitables":["modelengine.fit.jober.aipp.fitable.AippFlowEndCallback"],"converter":{"type":"mapping_converter","entity":{"inputParams":[{"id":"104c12c3-804b-419f-a1c7-24b66516ed42","from":"Expand","name":"finalOutput","type":"Object","value":[{"id":"020da94c-e511-4ee9-8e2b-0ce5eb3103cb","from":"Reference","name":"finalOutput","type":"String","value":["output"],"editable":true,"isRequired":true,"description":"","referenceId":"output_786cf758-f9af-4959-83e7-251a01e04fb0","referenceKey":"output","referenceNode":"jadeas9z1s"}],"editable":false,"isRequired":false,"referenceId":"","referenceKey":"","referenceNode":""},{"id":"0367a295-adad-4a19-a08e-ab04c37db3ac","from":"Input","name":"enableLog","type":"Boolean","value":true}],"outputParams":[{}]}}},"triggerMode":"auto"},"hasError":false,"hideText":true,"moveable":true,"runnable":true,"backColor":"white","container":"elsa-page:tvp1s6","dashWidth":0,"deletable":true,"namespace":"jadeFlow","autoHeight":true,"emphasized":false,"enableMask":false,"rotateAble":false,"borderColor":"rgba(28, 31, 35, 0.08)","borderWidth":1,"runningTask":0,"triggerMode":"auto","warningTask":0,"cornerRadius":8,"outlineColor":"rgba(74, 147, 255, 0.12)","outlineWidth":10,"completedTask":0,"componentName":"endComponent","focusBackColor":"white","sourcePlatform":"official","enableAnimation":false,"focusBorderColor":"rgb(4, 123, 252)","focusBorderWidth":1,"mouseInBorderColor":"rgb(4, 123, 252)"},{"x":2602.308098529733,"y":732.4801587301587,"id":"jade1thrs1","pad":6,"bold":false,"text":"结束_2","type":"endNodeEnd","dirty":false,"index":11,"width":360,"height":181,"italic":false,"flowMeta":{"callback":{"name":"通知回调","type":"general_callback","fitables":["modelengine.fit.jober.aipp.fitable.AippFlowEndCallback"],"converter":{"type":"mapping_converter","entity":{"inputParams":[{"id":"9f2d49d0-240d-46bb-80cb-a4391ac0de69","from":"Expand","name":"finalOutput","type":"Object","value":[{"id":"0f777bfd-06e5-452a-b80e-509057551d72","from":"Reference","name":"finalOutput","type":"String","value":["output"],"editable":true,"isRequired":true,"description":"","referenceId":"output_3f586ce1-6a98-4823-abeb-3e4783782b52","referenceKey":"output","referenceNode":"jade9gdgwb"}],"editable":false,"isRequired":false,"referenceId":"","referenceKey":"","referenceNode":""},{"id":"fac8c254-46c4-42b2-92f0-32990dcd0086","from":"Input","name":"enableLog","type":"Boolean","value":true}],"outputParams":[{}]}}},"triggerMode":"auto"},"hasError":false,"hideText":true,"moveable":true,"runnable":true,"backColor":"white","container":"elsa-page:tvp1s6","dashWidth":0,"deletable":true,"namespace":"jadeFlow","autoHeight":true,"emphasized":false,"enableMask":false,"rotateAble":false,"borderColor":"rgba(28, 31, 35, 0.08)","borderWidth":1,"runningTask":0,"triggerMode":"auto","warningTask":0,"cornerRadius":8,"outlineColor":"rgba(74, 147, 255, 0.12)","outlineWidth":10,"completedTask":0,"componentName":"endComponent","focusBackColor":"white","sourcePlatform":"official","enableAnimation":false,"focusBorderColor":"rgb(4, 123, 252)","focusBorderWidth":1,"mouseInBorderColor":"rgb(4, 123, 252)"},{"x":2038.0570664007846,"y":1301.051587301588,"id":"jadeifaftx","pad":6,"bold":false,"text":"退出表单结束","type":"endNodeEnd","dirty":false,"index":12,"width":360,"height":181,"italic":false,"flowMeta":{"callback":{"name":"通知回调","type":"general_callback","fitables":["modelengine.fit.jober.aipp.fitable.AippFlowEndCallback"],"converter":{"type":"mapping_converter","entity":{"inputParams":[{"id":"59007e69-9047-42d4-bfcd-3150e78f0215","from":"Expand","name":"finalOutput","type":"Object","value":[{"id":"cffd1f94-832a-4f23-b8d5-b72db4d521c1","from":"Input","name":"finalOutput","type":"String","value":"已退出,请重新开始对话来发起新的模型配置请求。","editable":true,"isRequired":true,"description":""}],"editable":false,"isRequired":false,"referenceId":"","referenceKey":"","referenceNode":""},{"id":"6f7d0c10-fe39-4dbe-8e72-0d5202e42a22","from":"Input","name":"enableLog","type":"Boolean","value":true}],"outputParams":[{}]}}},"triggerMode":"auto"},"hasError":false,"hideText":true,"moveable":true,"runnable":true,"backColor":"white","container":"elsa-page:tvp1s6","dashWidth":0,"deletable":true,"namespace":"jadeFlow","autoHeight":true,"emphasized":false,"enableMask":false,"rotateAble":false,"borderColor":"rgba(28, 31, 35, 0.08)","borderWidth":1,"runningTask":0,"triggerMode":"auto","warningTask":0,"cornerRadius":8,"outlineColor":"rgba(74, 147, 255, 0.12)","outlineWidth":10,"completedTask":0,"componentName":"endComponent","focusBackColor":"white","sourcePlatform":"official","enableAnimation":false,"focusBorderColor":"rgb(4, 123, 252)","focusBorderWidth":1,"mouseInBorderColor":"rgb(4, 123, 252)"},{"x":2333.736669958303,"y":462.123015873016,"id":"jadei8jdd4","pad":0,"bold":false,"text":"","type":"jadeEvent","dirty":true,"index":13,"textX":0,"textY":0,"width":298.5711442914585,"hAlign":"center","height":-49.142857142857224,"italic":false,"margin":20,"toShape":"jade7dv633","endArrow":true,"hideText":true,"lineMode":{"type":"auto_curve"},"runnable":true,"allowLink":false,"backColor":"white","container":"elsa-page:tvp1s6","fromShape":"jadeas9z1s","lineWidth":2,"namespace":"elsa","beginArrow":false,"borderColor":"#B1B1B7","borderWidth":1,"curvePoint1":{"x":0,"y":0},"curvePoint2":{"x":0,"y":0},"brokenPoints":[],"endArrowSize":4,"arrowEndPoint":{"x":0,"y":0},"endArrowEmpty":false,"beginArrowSize":4,"arrowBeginPoint":{"x":0,"y":0},"beginArrowEmpty":false,"definedToConnector":"W","mouseInBorderColor":"#B1B1B7","allowSwitchLineMode":false,"definedFromConnector":"E"},{"x":1759.93337291752,"y":455.0039624410964,"id":"jadecg9j3o","pad":0,"bold":false,"text":"","type":"jadeEvent","dirty":true,"index":14,"textX":0,"textY":0,"width":278.12369348326456,"hAlign":"center","height":936.5476248604915,"italic":false,"margin":20,"toShape":"jadeifaftx","endArrow":true,"hideText":true,"lineMode":{"type":"auto_curve"},"runnable":true,"allowLink":false,"backColor":"white","container":"elsa-page:tvp1s6","fromShape":"jade0305an","lineWidth":2,"namespace":"elsa","beginArrow":false,"borderColor":"#B1B1B7","borderWidth":1,"curvePoint1":{"x":0,"y":0},"curvePoint2":{"x":0,"y":0},"brokenPoints":[],"endArrowSize":4,"arrowEndPoint":{"x":0,"y":0},"endArrowEmpty":false,"beginArrowSize":4,"arrowBeginPoint":{"x":0,"y":0},"beginArrowEmpty":false,"definedToConnector":"W","mouseInBorderColor":"#B1B1B7","allowSwitchLineMode":false,"definedFromConnector":"dynamic-999"},{"x":1980.1367697843107,"y":-163.75793650793537,"id":"jadenavqab","pad":6,"bold":false,"text":"添加模型_1","type":"toolInvokeNodeState","dirty":false,"index":15,"width":360,"height":185,"italic":false,"flowMeta":{"jober":{"name":"","type":"STORE_JOBER","entity":{"params":[{"name":"modelName"},{"name":"baseUrl"},{"name":"apiKey"},{"name":"userId"},{"name":"type"}],"return":{"type":"string"},"uniqueName":"77ee3e02-5870-4338-a8be-52c8ed42f3c7"},"fitables":[],"converter":{"type":"mapping_converter","entity":{"inputParams":[{"id":"modelName_ca6789f3-8f17-4316-8d51-78e106c3b820","from":"Reference","name":"modelName","type":"String","value":["output","info","modelName"],"isRequired":true,"description":"模型名称","referenceId":"26ce7895-ee30-489d-83fa-672a03d72189","referenceKey":"modelName","referenceNode":"jadedyz9lx"},{"id":"baseUrl_898c544a-c71b-442d-8125-052b5d596c0c","from":"Reference","name":"baseUrl","type":"String","value":["output","info","baseUrl"],"isRequired":true,"description":"模型访问地址","referenceId":"4c2b64ed-87b1-4377-9692-3da748f2594e","referenceKey":"baseUrl","referenceNode":"jadedyz9lx"},{"id":"apiKey_11d4820e-b92c-4d00-80b2-6536b438b489","from":"Reference","name":"apiKey","type":"String","value":["output","info","apiKey"],"isRequired":true,"description":"模型访问的 API Key","referenceId":"cd52297d-5041-4b07-8dc9-a023df691e38","referenceKey":"apiKey","referenceNode":"jadedyz9lx"},{"id":"userId_42394f8d-92d8-491e-ac5c-5c4bca29c529","from":"Reference","name":"userId","type":"String","value":["output","info","userId"],"isRequired":true,"description":"用户id","referenceId":"6a81539b-30ee-4a4c-92e0-958772550106","referenceKey":"userId","referenceNode":"jadedyz9lx"},{"id":"type_e8af982b-3ac3-4197-8581-27eea2ed947f","from":"Reference","name":"type","type":"String","value":["output","info","type"],"isRequired":true,"description":"模型类型","referenceId":"adaa5c88-d336-498a-8054-b7a3ed043efc","referenceKey":"type","referenceNode":"jadedyz9lx"}],"outputParams":[{"id":"output_bf03f587-05e6-47f6-b4b2-baf8017415bd","name":"output","type":"String","value":[]}]}}},"joberFilter":{"type":"MINIMUM_SIZE_FILTER","threshold":1},"triggerMode":"auto"},"hasError":false,"hideText":true,"moveable":true,"runnable":true,"backColor":"white","container":"elsa-page:tvp1s6","dashWidth":0,"namespace":"jadeFlow","autoHeight":true,"emphasized":false,"enableMask":false,"rotateAble":false,"borderColor":"rgba(28, 31, 35, 0.08)","borderWidth":1,"runningTask":0,"triggerMode":"auto","warningTask":0,"cornerRadius":8,"outlineColor":"rgba(74, 147, 255, 0.12)","outlineWidth":10,"completedTask":0,"componentName":"toolInvokeComponent","focusBackColor":"white","sourcePlatform":"","enableAnimation":false,"focusBorderColor":"rgb(4, 123, 252)","focusBorderWidth":1,"mouseInBorderColor":"rgb(4, 123, 252)"},{"x":689.8800649682455,"y":307.67063492063426,"id":"jadedyz9lx","pad":6,"bold":false,"text":"表单","type":"intelligentFormNodeState","dirty":false,"index":16,"width":360,"height":275,"italic":false,"flowMeta":{"task":{"type":"AIPP_SMART_FORM","imgUrl":"http://localhost:8001/api/jober/static/smart_form/6befc536-7e6d-48b5-8dcb-1c4d04ca4e92/form.png","taskId":"1568509614c245a39ce53bda9c3c2ec1","formName":"模型管理表单","formType":"manual","converter":{"type":"mapping_converter","entity":{"inputParams":[{"id":"models_4e385aa6-5270-44ef-8e19-5210d91a0966","from":"Reference","name":"models","type":"Array","value":["output"],"isRequired":true,"referenceId":"output_78982629-c58c-4211-9f4b-369bdcfef31f","referenceKey":"output","referenceNode":"jadevpescp"}],"outputParams":[{"id":"output_cac0efc4-edc6-4b7d-84c0-f4489f707642","name":"output","type":"Object","value":[{"id":"output_f23cfc74-a38f-4928-ba85-b62023e5b212","name":"info","type":"Object","value":[{"id":"cd52297d-5041-4b07-8dc9-a023df691e38","name":"apiKey","type":"String","value":"String"},{"id":"6a81539b-30ee-4a4c-92e0-958772550106","name":"userId","type":"String","value":"String"},{"id":"4c2b64ed-87b1-4377-9692-3da748f2594e","name":"baseUrl","type":"String","value":"String"},{"id":"0c0bab50-cb34-4c38-869d-68edcd24d107","name":"modelId","type":"String","value":"String"},{"id":"d7c3a06d-dcfe-4b4b-8b3d-51095b36d23a","name":"isDefault","type":"Integer","value":"Integer"},{"id":"26ce7895-ee30-489d-83fa-672a03d72189","name":"modelName","type":"String","value":"String"},{"id":"adaa5c88-d336-498a-8054-b7a3ed043efc","name":"type","type":"String","value":"String"}]},{"id":"15ee5d6e-03f7-4abc-8966-73d420997048","name":"action","type":"String","value":"String"}]}]}}},"joberFilter":{"type":"MINIMUM_SIZE_FILTER","threshold":1},"triggerMode":"manual"},"hasError":false,"hideText":true,"moveable":true,"runnable":true,"backColor":"white","container":"elsa-page:tvp1s6","dashWidth":0,"namespace":"jadeFlow","autoHeight":true,"emphasized":false,"enableMask":false,"rotateAble":false,"borderColor":"rgba(28, 31, 35, 0.08)","borderWidth":1,"runningTask":0,"triggerMode":"auto","warningTask":0,"cornerRadius":8,"outlineColor":"rgba(74, 147, 255, 0.12)","outlineWidth":10,"completedTask":0,"componentName":"intelligentFormComponent","focusBackColor":"white","sourcePlatform":"official","enableAnimation":false,"focusBorderColor":"rgb(4, 123, 252)","focusBorderWidth":1,"mouseInBorderColor":"rgb(4, 123, 252)"},{"x":2340.1367697843107,"y":-71.25793650793537,"id":"jadev8f0bf","pad":0,"bold":false,"text":"","type":"jadeEvent","dirty":true,"index":17,"textX":0,"textY":0,"width":223.97037307283153,"hAlign":"center","height":15.150793650792536,"italic":false,"margin":20,"toShape":"jadesoux5i","endArrow":true,"hideText":true,"lineMode":{"type":"auto_curve"},"runnable":true,"allowLink":false,"backColor":"white","container":"elsa-page:tvp1s6","fromShape":"jadenavqab","lineWidth":2,"namespace":"elsa","beginArrow":false,"borderColor":"#B1B1B7","borderWidth":1,"curvePoint1":{"x":0,"y":0},"curvePoint2":{"x":0,"y":0},"brokenPoints":[],"endArrowSize":4,"arrowEndPoint":{"x":0,"y":0},"endArrowEmpty":false,"beginArrowSize":4,"arrowBeginPoint":{"x":0,"y":0},"beginArrowEmpty":false,"definedToConnector":"W","mouseInBorderColor":"#B1B1B7","allowSwitchLineMode":false,"definedFromConnector":"E"},{"x":1987.28104832704,"y":800.5277777777785,"id":"jade9gdgwb","pad":6,"bold":false,"text":"切换默认模型_1","type":"toolInvokeNodeState","dirty":false,"index":18,"width":360,"height":185,"italic":false,"flowMeta":{"jober":{"name":"","type":"STORE_JOBER","entity":{"params":[{"name":"modelId"},{"name":"userId"}],"return":{"type":"string"},"uniqueName":"f76205df-1814-49b9-a473-c03ee99770b7"},"fitables":[],"converter":{"type":"mapping_converter","entity":{"inputParams":[{"id":"modelId_63072515-1c67-42d2-bffa-7b553b054d66","from":"Reference","name":"modelId","type":"String","value":["output","info","modelId"],"isRequired":true,"description":"默认模型id","referenceId":"0c0bab50-cb34-4c38-869d-68edcd24d107","referenceKey":"modelId","referenceNode":"jadedyz9lx"},{"id":"userId_7af974a1-d3bf-481c-a83f-b761c7e9ca85","from":"Reference","name":"userId","type":"String","value":["output","info","userId"],"isRequired":true,"description":"用户id","referenceId":"6a81539b-30ee-4a4c-92e0-958772550106","referenceKey":"userId","referenceNode":"jadedyz9lx"}],"outputParams":[{"id":"output_3f586ce1-6a98-4823-abeb-3e4783782b52","name":"output","type":"String","value":[]}]}}},"joberFilter":{"type":"MINIMUM_SIZE_FILTER","threshold":1},"triggerMode":"auto"},"hasError":false,"hideText":true,"moveable":true,"runnable":true,"backColor":"white","container":"elsa-page:tvp1s6","dashWidth":0,"namespace":"jadeFlow","autoHeight":true,"emphasized":false,"enableMask":false,"rotateAble":false,"borderColor":"rgba(28, 31, 35, 0.08)","borderWidth":1,"runningTask":0,"triggerMode":"auto","warningTask":0,"cornerRadius":8,"outlineColor":"rgba(74, 147, 255, 0.12)","outlineWidth":10,"completedTask":0,"componentName":"toolInvokeComponent","focusBackColor":"white","sourcePlatform":"","enableAnimation":false,"focusBorderColor":"rgb(4, 123, 252)","focusBorderWidth":1,"mouseInBorderColor":"rgb(4, 123, 252)"},{"x":2347.28104832704,"y":893.0277777777785,"id":"jadeo437e0","pad":0,"bold":false,"text":"","type":"jadeEvent","dirty":true,"index":19,"textX":0,"textY":0,"width":255.02705020269286,"hAlign":"center","height":-70.04761904761983,"italic":false,"margin":20,"toShape":"jade1thrs1","endArrow":true,"hideText":true,"lineMode":{"type":"auto_curve"},"runnable":true,"allowLink":false,"backColor":"white","container":"elsa-page:tvp1s6","fromShape":"jade9gdgwb","lineWidth":2,"namespace":"elsa","beginArrow":false,"borderColor":"#B1B1B7","borderWidth":1,"curvePoint1":{"x":0,"y":0},"curvePoint2":{"x":0,"y":0},"brokenPoints":[],"endArrowSize":4,"arrowEndPoint":{"x":0,"y":0},"endArrowEmpty":false,"beginArrowSize":4,"arrowBeginPoint":{"x":0,"y":0},"beginArrowEmpty":false,"definedToConnector":"W","mouseInBorderColor":"#B1B1B7","allowSwitchLineMode":false,"definedFromConnector":"E"},{"x":1049.8800649682455,"y":445.17063492063426,"id":"jadey40slx","pad":0,"bold":false,"text":"","type":"jadeEvent","dirty":true,"index":20,"textX":0,"textY":0,"width":121.00565257120547,"hAlign":"center","height":-100.33333333333246,"italic":false,"margin":20,"toShape":"jade0305an","endArrow":true,"hideText":true,"lineMode":{"type":"auto_curve"},"runnable":true,"allowLink":false,"backColor":"white","container":"elsa-page:tvp1s6","fromShape":"jadedyz9lx","lineWidth":2,"namespace":"elsa","beginArrow":false,"borderColor":"#B1B1B7","borderWidth":1,"curvePoint1":{"x":0,"y":0},"curvePoint2":{"x":0,"y":0},"brokenPoints":[],"endArrowSize":4,"arrowEndPoint":{"x":0,"y":0},"endArrowEmpty":false,"beginArrowSize":4,"arrowBeginPoint":{"x":0,"y":0},"beginArrowEmpty":false,"definedToConnector":"W","mouseInBorderColor":"#B1B1B7","allowSwitchLineMode":false,"definedFromConnector":"E"}]}],"enableText":false,"flowMeta":{"callback":{"name":"通知回调","type":"general_callback","fitables":["modelengine.fit.jober.fitable.FlowInfoCallback"]},"enableOutputScope":true,"exceptionFitables":["modelengine.fit.jober.aipp.fitable.AippFlowExceptionHandler","modelengine.fit.jober.fitable.FlowInfoException"]},"version":"1.0.0"}', 'system', '2025-07-25 03:34:45.147236', 'system', '2025-07-25 03:34:45.639138', NULL, 'f') ON CONFLICT (id, version) DO NOTHING; -INSERT INTO "public"."store_app" ("like_count", "download_count", "source", "icon", "app_category", "tool_name", "tool_unique_name") VALUES (0, 0, 'system', '', 'chatbot', '模型配置应用', '7a76cbd2-881d-469b-b2df-76abed7d0b61') ON CONFLICT ("tool_unique_name") DO NOTHING; +INSERT INTO "public"."store_app" ("like_count", "download_count", "source", "icon", "app_category", "tool_name", "tool_unique_name", "user_group_id") VALUES (0, 0, 'system', '', 'chatbot', '模型配置应用', '7a76cbd2-881d-469b-b2df-76abed7d0b61', '*') ON CONFLICT ("tool_unique_name") DO NOTHING; INSERT INTO "public"."store_tool" ("name", "schema", "runnables", "extensions", "unique_name", "version", "is_latest", "group_name", "definition_name", "definition_group_name") VALUES ('模型配置应用', '{"name":"模型配置应用","description":"当你想要配置模型的时候,请使用我!","manualIntervention":false,"parameters":{"type":"object","properties":{"aippId":{"description":"the aipp id of the waterFlow tool","default":"0b4fe5a430104edfbe0dc6cff0ebea19","type":"string"},"tenantId":{"description":"the tenant id of the waterFlow tool","default":"31f20efc7e0848deab6a6bc10fc3021e","type":"string"},"inputParams":{"type":"object","properties":{"Question":{"type":"string","description":"这是用户输入的问题。"}},"required":["Question"],"order":["Question"]},"version":{"description":"the aipp version of the waterFlow tool","default":"1.0.0","type":"string"}},"required":["tenantId","aippId","version","inputParams"]},"return":{"type":"object","properties":{}},"order":["tenantId","aippId","version","inputParams"]}', '{"FIT":{"fitableId":"water.flow.invoke","genericableId":"07b51bd246594c159d403164369ce1db"},"APP":{"aippId":"0b4fe5a430104edfbe0dc6cff0ebea19","appCategory":"chatbot","version":"1.0.0","appId":"cec6bfe7cb3a444f8a26a97ea513e501"}}', 'null', '7a76cbd2-881d-469b-b2df-76abed7d0b61', '1.0.0', 't', '7a76cbd2-881d-469b-b2df-76abed7d0b61', '7a76cbd2-881d-469b-b2df-76abed7d0b61', '7a76cbd2-881d-469b-b2df-76abed7d0b61') ON CONFLICT ("unique_name", "version") DO NOTHING; diff --git a/app-builder/plugins/aipp-domain-division/pom.xml b/app-builder/plugins/aipp-domain-division/pom.xml new file mode 100644 index 0000000000..2b4950f671 --- /dev/null +++ b/app-builder/plugins/aipp-domain-division/pom.xml @@ -0,0 +1,150 @@ + + + 4.0.0 + + + modelengine.fit.jade + app-builder-plugin-parent + 1.0.0-SNAPSHOT + + + modelengine.fit.jade.plugin + aipp-domain-division + + + + + org.fitframework + fit-api + + + org.fitframework.service + fit-http-classic + + + org.fitframework + fit-util + + + + + modelengine.jade.service + aipp-domain-division-service + 1.0.0-SNAPSHOT + + + modelengine.fit.jade.service + authentication-service + + + modelengine.fit.jade.service + common-service + 1.0.0-SNAPSHOT + + + + + org.projectlombok + lombok + + + org.fitframework.integration + fit-mybatis + + + org.postgresql + postgresql + + + org.mybatis + mybatis + + + com.alibaba + druid + + + org.fitframework.integration + fit-druid + + + com.fasterxml.jackson.core + jackson-databind + + + + + org.junit.jupiter + junit-jupiter + test + + + org.mockito + mockito-inline + test + + + org.assertj + assertj-core + test + + + org.fitframework + fit-test-framework + test + + + com.h2database + h2 + test + + + + + + + org.fitframework + fit-build-maven-plugin + ${fit.version} + + user + 3 + + + + build-plugin + + build-plugin + + + + package-plugin + + package-plugin + + + + + + org.apache.maven.plugins + maven-antrun-plugin + ${maven.antrun.version} + + + install + + + + + + + run + + + + + + + \ No newline at end of file diff --git a/app-builder/plugins/aipp-domain-division/src/main/java/modelengine/fit/jade/aipp/domain/division/aop/CreateSourceAspect.java b/app-builder/plugins/aipp-domain-division/src/main/java/modelengine/fit/jade/aipp/domain/division/aop/CreateSourceAspect.java new file mode 100644 index 0000000000..119539352d --- /dev/null +++ b/app-builder/plugins/aipp-domain-division/src/main/java/modelengine/fit/jade/aipp/domain/division/aop/CreateSourceAspect.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + */ + +package modelengine.fit.jade.aipp.domain.division.aop; + +import modelengine.fit.http.client.HttpClassicClientFactory; +import modelengine.fit.jade.aipp.domain.division.UserGroup; +import modelengine.fit.jade.aipp.domain.division.entity.UserInfo; +import modelengine.fit.jade.aipp.domain.division.entity.UserInfoHolder; +import modelengine.fitframework.annotation.Component; +import modelengine.fitframework.annotation.Scope; +import modelengine.fitframework.annotation.Value; +import modelengine.fitframework.aop.JoinPoint; +import modelengine.fitframework.aop.annotation.After; +import modelengine.fitframework.aop.annotation.AfterThrowing; +import modelengine.fitframework.aop.annotation.Aspect; +import modelengine.fitframework.aop.annotation.Before; +import modelengine.fitframework.util.StringUtils; + +/** + * 表示创建资源的切面 + * + * @author 邬涨财 + * @since 2025-08-12 + */ +@Aspect(scope = Scope.GLOBAL) +@Component +public class CreateSourceAspect extends SourceAspect { + private final String allGroupId; + private final String allGroupAliasId; + private final boolean isEnableDomainDivision; + + public CreateSourceAspect(@Value("${domain-division.all-group.id}") final String allGroupId, + @Value("${domain-division.all-group.alias.id}") final String allGroupAliasId, + HttpClassicClientFactory httpClientFactory, + @Value("${domain-division.host}") final String allGroupHost, + @Value("${domain-division.path}") final String allGroupPath, + @Value("${domain-division.isEnable}") boolean isEnableDomainDivision) { + super(httpClientFactory, allGroupHost + allGroupPath); + this.allGroupId = allGroupId; + this.allGroupAliasId = allGroupAliasId; + this.isEnableDomainDivision = isEnableDomainDivision; + } + + private UserInfo buildUserInfo(String username, String userGroupId) { + return UserInfo.builder().username(username).userGroupId(userGroupId).build(); + } + + /** + * 资源创建前的切面处理。 + * + * @param joinPoint 表示连接点的 {@link JoinPoint}。 + */ + @Before("@annotation(modelengine.fit.jade.aipp.domain.division.annotation.CreateSource)") + public void beforeCreate(JoinPoint joinPoint) { + if (!this.isEnableDomainDivision) { + return; + } + String username = this.getUserName(); + UserGroup userGroup = this.getUserGroup(username); + String id = userGroup.getId(); + if (StringUtils.equals(this.allGroupAliasId, id)) { + id = this.allGroupId; + } + UserInfo userInfo = this.buildUserInfo(username, id); + UserInfoHolder.set(userInfo); + } + + /** + * 资源创建后的切面处理。 + * + * @param joinPoint 表示连接点的 {@link JoinPoint}。 + */ + @After("@annotation(modelengine.fit.jade.aipp.domain.division.annotation.CreateSource)") + public void afterCreate(JoinPoint joinPoint) { + this.clear(); + } + + /** + * 资源创建出现异常后的切面处理。 + * + * @param joinPoint 表示连接点的 {@link JoinPoint}。 + */ + @AfterThrowing("@annotation(modelengine.fit.jade.aipp.domain.division.annotation.CreateSource)") + public void afterCreateThrowing(JoinPoint joinPoint) { + this.clear(); + } +} diff --git a/app-builder/plugins/aipp-domain-division/src/main/java/modelengine/fit/jade/aipp/domain/division/aop/GetSourceAspect.java b/app-builder/plugins/aipp-domain-division/src/main/java/modelengine/fit/jade/aipp/domain/division/aop/GetSourceAspect.java new file mode 100644 index 0000000000..d4080c7104 --- /dev/null +++ b/app-builder/plugins/aipp-domain-division/src/main/java/modelengine/fit/jade/aipp/domain/division/aop/GetSourceAspect.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + */ + +package modelengine.fit.jade.aipp.domain.division.aop; + +import modelengine.fit.http.client.HttpClassicClientFactory; +import modelengine.fit.jade.aipp.domain.division.UserGroup; +import modelengine.fit.jade.aipp.domain.division.entity.UserInfo; +import modelengine.fit.jade.aipp.domain.division.entity.UserInfoHolder; +import modelengine.fitframework.annotation.Component; +import modelengine.fitframework.annotation.Scope; +import modelengine.fitframework.annotation.Value; +import modelengine.fitframework.aop.JoinPoint; +import modelengine.fitframework.aop.annotation.After; +import modelengine.fitframework.aop.annotation.AfterThrowing; +import modelengine.fitframework.aop.annotation.Aspect; +import modelengine.fitframework.aop.annotation.Before; + +import java.util.List; + +/** + * 表示获取资源的切面 + * + * @author 邬涨财 + * @since 2025-08-12 + */ +@Aspect(scope = Scope.GLOBAL) +@Component +public class GetSourceAspect extends SourceAspect { + private final List allGroupUsers; + private final boolean isEnableDomainDivision; + + public GetSourceAspect(@Value("${domain-division.all-group.users}") final List allGroupUsers, + HttpClassicClientFactory httpClientFactory, + @Value("${domain-division.host}") final String allGroupHost, + @Value("${domain-division.path}") final String allGroupPath, + @Value("${domain-division.isEnable}") boolean isEnableDomainDivision) { + super(httpClientFactory, allGroupHost + allGroupPath); + this.allGroupUsers = allGroupUsers; + this.isEnableDomainDivision = isEnableDomainDivision; + } + + private UserInfo buildUserInfo(String username, String userGroupId) { + return UserInfo.builder().username(username).userGroupId(userGroupId).build(); + } + + /** + * 获取资源前的切面处理。 + * + * @param joinPoint 表示连接点的 {@link JoinPoint}。 + */ + @Before("@annotation(modelengine.fit.jade.aipp.domain.division.annotation.GetSource)") + public void beforeGet(JoinPoint joinPoint) { + if (!this.isEnableDomainDivision) { + return; + } + String username = this.getUserName(); + if (this.allGroupUsers != null && this.allGroupUsers.contains(username)) { + return; + } + UserGroup userGroup = this.getUserGroup(username); + UserInfo userInfo = this.buildUserInfo(username, userGroup.getId()); + UserInfoHolder.set(userInfo); + } + + /** + * 获取资源后的切面处理。 + * + * @param joinPoint 表示连接点的 {@link JoinPoint}。 + */ + @After("@annotation(modelengine.fit.jade.aipp.domain.division.annotation.GetSource)") + public void afterGet(JoinPoint joinPoint) { + this.clear(); + } + + /** + * 获取资源异常后的切面处理。 + * + * @param joinPoint 表示连接点的 {@link JoinPoint}。 + */ + @AfterThrowing("@annotation(modelengine.fit.jade.aipp.domain.division.annotation.GetSource)") + public void afterGetThrowing(JoinPoint joinPoint) { + this.clear(); + } +} diff --git a/app-builder/plugins/aipp-domain-division/src/main/java/modelengine/fit/jade/aipp/domain/division/aop/SourceAspect.java b/app-builder/plugins/aipp-domain-division/src/main/java/modelengine/fit/jade/aipp/domain/division/aop/SourceAspect.java new file mode 100644 index 0000000000..f30f49da20 --- /dev/null +++ b/app-builder/plugins/aipp-domain-division/src/main/java/modelengine/fit/jade/aipp/domain/division/aop/SourceAspect.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + */ + +package modelengine.fit.jade.aipp.domain.division.aop; + +import static modelengine.fit.jade.aipp.domain.division.code.DomainDivisionRetCode.USER_GROUP_EXCHANGE_ERROR; +import static modelengine.fit.jade.aipp.domain.division.code.DomainDivisionRetCode.USER_GROUP_NOT_EXIST; + +import modelengine.fit.http.client.HttpClassicClient; +import modelengine.fit.http.client.HttpClassicClientFactory; +import modelengine.fit.http.client.HttpClassicClientRequest; +import modelengine.fit.http.client.HttpClientException; +import modelengine.fit.http.protocol.HttpRequestMethod; +import modelengine.fit.jade.aipp.domain.division.UserGroup; +import modelengine.fit.jade.aipp.domain.division.entity.UserInfo; +import modelengine.fit.jade.aipp.domain.division.entity.UserInfoHolder; +import modelengine.fitframework.exception.ClientException; +import modelengine.fitframework.util.CollectionUtils; +import modelengine.fitframework.util.LazyLoader; +import modelengine.fitframework.util.MapBuilder; +import modelengine.fitframework.util.ObjectUtils; +import modelengine.fitframework.util.StringUtils; +import modelengine.fitframework.util.TypeUtils; +import modelengine.jade.authentication.context.UserContext; +import modelengine.jade.authentication.context.UserContextHolder; +import modelengine.jade.common.exception.ModelEngineException; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.List; +import java.util.Map; + +/** + * 表示资源的切面 + * + * @author 邬涨财 + * @since 2025-08-15 + */ +public abstract class SourceAspect { + private final HttpClassicClientFactory httpClientFactory; + private final LazyLoader httpClient; + private final String allGroupUrl; + + public SourceAspect(HttpClassicClientFactory httpClientFactory, + String allGroupUrl) { + this.httpClientFactory = httpClientFactory; + this.httpClient = new LazyLoader<>(this::getHttpClient); + this.allGroupUrl = allGroupUrl; + } + + private HttpClassicClient getHttpClient() { + Map custom = MapBuilder.get() + .put("client.http.secure.ignore-trust", true) + .put("client.http.secure.ignore-hostname", true) + .build(); + return this.httpClientFactory.create(HttpClassicClientFactory.Config.builder().custom(custom).build()); + } + + /** + * 用户信息清理。 + */ + protected void clear() { + UserInfo userInfo = UserInfoHolder.get(); + if (userInfo != null) { + UserInfoHolder.remove(); + } + } + + /** + * 获取用户名。 + * + * @return 表示用户名的 {@link String}。 + */ + public String getUserName() { + UserContext userContext = UserContextHolder.get(); + if (userContext == null) { + throw new ModelEngineException(USER_GROUP_NOT_EXIST); + } + return userContext.getName(); + } + + /** + * 获取用户组。 + * + * @return 表示用户组的 {@link UserGroup}。 + */ + public UserGroup getUserGroup(String username) { + String fullUrl = StringUtils.format(this.allGroupUrl, username); + HttpClassicClientRequest request = + this.httpClient.get().createRequest(HttpRequestMethod.GET, fullUrl); + try { + Object response = this.httpClient.get().exchangeForEntity(request, Object.class); + ParameterizedType parameterizedType = TypeUtils.parameterized(List.class, new Type[] {UserGroup.class}); + List userGroups = ObjectUtils.toCustomObject(response, parameterizedType); + if (CollectionUtils.isEmpty(userGroups)) { + throw new ModelEngineException(USER_GROUP_NOT_EXIST); + } + return userGroups.get(0); + } catch (HttpClientException | ClientException ex) { + throw new ModelEngineException(USER_GROUP_EXCHANGE_ERROR, ex); + } + } +} diff --git a/app-builder/plugins/aipp-domain-division/src/main/java/modelengine/fit/jade/aipp/domain/division/code/DomainDivisionRetCode.java b/app-builder/plugins/aipp-domain-division/src/main/java/modelengine/fit/jade/aipp/domain/division/code/DomainDivisionRetCode.java new file mode 100644 index 0000000000..30b07ade8a --- /dev/null +++ b/app-builder/plugins/aipp-domain-division/src/main/java/modelengine/fit/jade/aipp/domain/division/code/DomainDivisionRetCode.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + */ +package modelengine.fit.jade.aipp.domain.division.code; + +import modelengine.jade.common.code.RetCode; + +/** + * 分域错误码 + * + * @author 邬涨财 + * @since 2025-08-14 + */ +public enum DomainDivisionRetCode implements RetCode { + /** + * 用户组不存在 + */ + USER_GROUP_NOT_EXIST(131200001, + "The current user does not belong to any resource group and has no permission to access the resource."), + /** + * 用户名不存在 + */ + USER_NAME_NOT_EXIST(131200002,"The current user not exist and has no permission to access the resource."), + + /** + * 用户组服务调用失败 + */ + USER_GROUP_EXCHANGE_ERROR(131200003,"Unable to exchange with user group service."); + + private final int code; + + private final String msg; + + DomainDivisionRetCode(int code, String msg) { + this.code = code; + this.msg = msg; + } + + @Override + public int getCode() { + return this.code; + } + + @Override + public String getMsg() { + return this.msg; + } +} diff --git a/app-builder/plugins/aipp-domain-division/src/main/java/modelengine/fit/jade/aipp/domain/division/entity/UserInfo.java b/app-builder/plugins/aipp-domain-division/src/main/java/modelengine/fit/jade/aipp/domain/division/entity/UserInfo.java new file mode 100644 index 0000000000..8529b14994 --- /dev/null +++ b/app-builder/plugins/aipp-domain-division/src/main/java/modelengine/fit/jade/aipp/domain/division/entity/UserInfo.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + */ + +package modelengine.fit.jade.aipp.domain.division.entity; + +import lombok.Builder; +import lombok.Data; + +/** + * 用户信息 + * + * @author 邬涨财 + * @since 2025-08-12 + */ +@Data +@Builder +public class UserInfo { + private String username; + private String userGroupId; +} diff --git a/app-builder/plugins/aipp-domain-division/src/main/java/modelengine/fit/jade/aipp/domain/division/entity/UserInfoHolder.java b/app-builder/plugins/aipp-domain-division/src/main/java/modelengine/fit/jade/aipp/domain/division/entity/UserInfoHolder.java new file mode 100644 index 0000000000..35a298bbae --- /dev/null +++ b/app-builder/plugins/aipp-domain-division/src/main/java/modelengine/fit/jade/aipp/domain/division/entity/UserInfoHolder.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + */ + +package modelengine.fit.jade.aipp.domain.division.entity; + +import modelengine.jade.authentication.context.UserContext; + +/** + * 表示当前线程持有的用户信息。 + * + * @author 邬涨财 + * @since 2025-08-12 + */ +public class UserInfoHolder { + private static final ThreadLocal USER_INFO_THREAD_LOCAL = new ThreadLocal<>(); + + /** + * 获取本地线程变量的用户信息。 + * + * @return 表示当前用户信息的 {@link UserContext}。 + */ + public static UserInfo get() { + return USER_INFO_THREAD_LOCAL.get(); + } + + /** + * 设置本地线程变量的用户信息。 + * + * @param userInfo 表示当前用户信息的 {@link UserContext}。 + */ + public static void set(UserInfo userInfo) { + USER_INFO_THREAD_LOCAL.set(userInfo); + } + + /** + * 移除本地线程变量的用户信息。 + * + */ + public static void remove() { + USER_INFO_THREAD_LOCAL.remove(); + } +} diff --git a/app-builder/plugins/aipp-domain-division/src/main/java/modelengine/fit/jade/aipp/domain/division/impl/DomainDivisionServiceImpl.java b/app-builder/plugins/aipp-domain-division/src/main/java/modelengine/fit/jade/aipp/domain/division/impl/DomainDivisionServiceImpl.java new file mode 100644 index 0000000000..813931f944 --- /dev/null +++ b/app-builder/plugins/aipp-domain-division/src/main/java/modelengine/fit/jade/aipp/domain/division/impl/DomainDivisionServiceImpl.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + */ +package modelengine.fit.jade.aipp.domain.division.impl; + +import modelengine.fit.http.client.HttpClassicClientFactory; +import modelengine.fit.jade.aipp.domain.division.UserGroup; +import modelengine.fit.jade.aipp.domain.division.aop.SourceAspect; +import modelengine.fit.jade.aipp.domain.division.entity.UserInfoHolder; +import modelengine.fit.jade.aipp.domain.division.service.DomainDivisionService; +import modelengine.fitframework.annotation.Component; +import modelengine.fitframework.annotation.Fitable; +import modelengine.fitframework.annotation.Value; +import modelengine.fitframework.util.StringUtils; + +import java.util.List; + +/** + * 分域服务的实现类 + * + * @author 邬涨财 + * @since 2025-08-13 + */ +@Component +public class DomainDivisionServiceImpl extends SourceAspect implements DomainDivisionService { + private final List allGroupUsers; + + public DomainDivisionServiceImpl(@Value("${domain-division.all-group.users}") final List allGroupUsers, + HttpClassicClientFactory httpClientFactory, + @Value("${domain-division.host}") final String allGroupHost, + @Value("${domain-division.path}") final String allGroupPath) { + super(httpClientFactory, allGroupHost + allGroupPath); + this.allGroupUsers = allGroupUsers; + } + + @Override + @Fitable + public String getUserGroupId() { + if (UserInfoHolder.get() == null) { + return null; + } + return UserInfoHolder.get().getUserGroupId(); + } + + @Override + public boolean validate(List toBeVerifiedIds) { + String username = this.getUserName(); + if (this.allGroupUsers != null && this.allGroupUsers.contains(username)) { + return true; + } + UserGroup userGroup = this.getUserGroup(username); + String currUserGroupId = userGroup.getId(); + for(String toBeVerifiedId : toBeVerifiedIds) { + if (!(StringUtils.equals(toBeVerifiedId, "*") || StringUtils.equals(toBeVerifiedId, currUserGroupId))) { + return false; + } + } + return true; + } +} diff --git a/app-builder/plugins/aipp-domain-division/src/main/resources/application.yml b/app-builder/plugins/aipp-domain-division/src/main/resources/application.yml new file mode 100644 index 0000000000..e428b1e768 --- /dev/null +++ b/app-builder/plugins/aipp-domain-division/src/main/resources/application.yml @@ -0,0 +1,37 @@ +fit: + beans: + packages: + - 'modelengine.fit.jade.aipp.domain.division' + messages: + basename: i18n/messages, i18n/ui + datasource: + primary: 'app-engine' + instances: + app-engine: + mode: 'shared' + url: '' + username: '' + password: '' + druid: + driver-class-name: 'org.postgresql.Driver' + initialSize: 5 + minIdle: 5 + maxActive: 32 + maxWait: 60000 + timeBetweenEvictionRunsMillis: 60000 + minEvictableIdleTimeMillis: 300000 + validationQuery: 'SELECT 1' + testWhileIdle: true + testOnBorrow: false + testOnReturn: false +domain-division: + host: 'http:////127.0.0.1:8004' + path: '//rpc//v1//{0}//user-resource-groups' + all-group: + users: + - 'admin' + id: '*' + alias: + id: '*' + isEnable: false + diff --git a/app-builder/plugins/aipp-domain-division/src/test/java/modelengine/fit/jade/aipp/domain/division/aop/CreateSourceAspectTest.java b/app-builder/plugins/aipp-domain-division/src/test/java/modelengine/fit/jade/aipp/domain/division/aop/CreateSourceAspectTest.java new file mode 100644 index 0000000000..57395ffc77 --- /dev/null +++ b/app-builder/plugins/aipp-domain-division/src/test/java/modelengine/fit/jade/aipp/domain/division/aop/CreateSourceAspectTest.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + */ + +package modelengine.fit.jade.aipp.domain.division.aop; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import modelengine.fit.http.client.HttpClassicClient; +import modelengine.fit.http.client.HttpClassicClientFactory; +import modelengine.fit.http.client.HttpClassicClientRequest; +import modelengine.fit.jade.aipp.domain.division.UserGroup; +import modelengine.fit.jade.aipp.domain.division.entity.UserInfo; +import modelengine.fit.jade.aipp.domain.division.entity.UserInfoHolder; +import modelengine.fitframework.aop.JoinPoint; +import modelengine.fitframework.test.adapter.north.junit5.FitExtension; +import modelengine.fitframework.test.annotation.Mock; +import modelengine.jade.authentication.context.UserContext; +import modelengine.jade.authentication.context.UserContextHolder; +import modelengine.jade.common.exception.ModelEngineException; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import java.util.Collections; + +/** + * 设置资源的切面单测类 + * + * @author 邬涨财 + * @since 2025-09-02 + */ +@ExtendWith(FitExtension.class) +public class CreateSourceAspectTest { + @Mock + private HttpClassicClientFactory httpClientFactory; + + @Mock + private JoinPoint joinPoint; + + @Mock + private CreateSourceAspect createSourceAspect; + + @Mock + private HttpClassicClient client; + + @BeforeEach + void setUp() { + when(this.httpClientFactory.create(any())).thenReturn(this.client); + HttpClassicClientRequest request = mock(HttpClassicClientRequest.class); + when(this.client.createRequest(any(), eq("http://localhost//user3"))).thenReturn(request); + when(this.client.createRequest(any(), eq("http://localhost//admin1"))).thenReturn(request); + when(this.client.createRequest(any(), eq("http://localhost//admin2"))).thenReturn(request); + UserGroup userGroup = UserGroup.builder().id("001").build(); + Object response = Collections.singletonList(userGroup); + when(this.client.exchangeForEntity(eq(request), any())).thenReturn(response); + when(this.client.exchangeForEntity(eq(request), any())).thenReturn(response); + this.createSourceAspect = + new CreateSourceAspect("*", "001", this.httpClientFactory, "http:////localhost////{0}", "", true); + } + + @Test + void testBeforeGetUserInGroupUsers() { + UserContext context = new UserContext("user3", "localhost", "en"); + UserContextHolder.apply(context, () -> { + this.createSourceAspect.beforeCreate(this.joinPoint); + UserInfo userInfoHolder = UserInfoHolder.get(); + assertEquals("user3", userInfoHolder.getUsername()); + assertEquals("*", userInfoHolder.getUserGroupId()); + this.createSourceAspect.afterCreate(this.joinPoint); + assertNull(UserInfoHolder.get()); + }); + } + + @Test + void testBeforeGetUserNotInGroupUsers() { + UserContext context = new UserContext("user2", "localhost", "en"); + UserContextHolder.apply(context, () -> { + assertThatThrownBy(() -> this.createSourceAspect.beforeCreate(this.joinPoint)).isInstanceOf( + ModelEngineException.class); + assertNull(UserInfoHolder.get()); + }); + } + + @Test + void testAfterThrowing() { + this.createSourceAspect.afterCreateThrowing(this.joinPoint); + assertNull(UserInfoHolder.get()); + } +} diff --git a/app-builder/plugins/aipp-domain-division/src/test/java/modelengine/fit/jade/aipp/domain/division/aop/GetSourceAspectTest.java b/app-builder/plugins/aipp-domain-division/src/test/java/modelengine/fit/jade/aipp/domain/division/aop/GetSourceAspectTest.java new file mode 100644 index 0000000000..51a78d6843 --- /dev/null +++ b/app-builder/plugins/aipp-domain-division/src/test/java/modelengine/fit/jade/aipp/domain/division/aop/GetSourceAspectTest.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + */ + +package modelengine.fit.jade.aipp.domain.division.aop; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import modelengine.fit.http.client.HttpClassicClient; +import modelengine.fit.http.client.HttpClassicClientFactory; +import modelengine.fit.http.client.HttpClassicClientRequest; +import modelengine.fit.jade.aipp.domain.division.UserGroup; +import modelengine.fit.jade.aipp.domain.division.entity.UserInfo; +import modelengine.fit.jade.aipp.domain.division.entity.UserInfoHolder; +import modelengine.fitframework.aop.JoinPoint; +import modelengine.fitframework.test.adapter.north.junit5.FitExtension; +import modelengine.fitframework.test.annotation.Mock; +import modelengine.jade.authentication.context.UserContext; +import modelengine.jade.authentication.context.UserContextHolder; +import modelengine.jade.common.exception.ModelEngineException; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import java.util.Arrays; +import java.util.Collections; + +/** + * 获取资源的切面单测类 + * + * @author 邬涨财 + * @since 2025-09-01 + */ +@ExtendWith(FitExtension.class) +public class GetSourceAspectTest { + @Mock + private HttpClassicClientFactory httpClientFactory; + + @Mock + private JoinPoint joinPoint; + + @Mock + private GetSourceAspect getSourceAspect; + + @Mock + private HttpClassicClient client; + + @BeforeEach + void setUp() { + when(this.httpClientFactory.create(any())).thenReturn(this.client); + HttpClassicClientRequest request = mock(HttpClassicClientRequest.class); + when(this.client.createRequest(any(), eq("http://localhost//user3"))).thenReturn(request); + when(this.client.createRequest(any(), eq("http://localhost//admin1"))).thenReturn(request); + when(this.client.createRequest(any(), eq("http://localhost//admin2"))).thenReturn(request); + UserGroup userGroup = UserGroup.builder().id("g_user3").build(); + Object response = Collections.singletonList(userGroup); + when(this.client.exchangeForEntity(eq(request), any())).thenReturn(response); + this.getSourceAspect = new GetSourceAspect(Arrays.asList("admin1", "admin2"), + this.httpClientFactory, + "http:////localhost////{0}", + "", + true); + } + + @Test + void testBeforeGetUserInGroupUsers() { + UserContext context = new UserContext("user3", "localhost", "en"); + UserContextHolder.apply(context, () -> { + this.getSourceAspect.beforeGet(this.joinPoint); + UserInfo userInfoHolder = UserInfoHolder.get(); + assertEquals("user3", userInfoHolder.getUsername()); + this.getSourceAspect.afterGet(this.joinPoint); + assertNull(UserInfoHolder.get()); + }); + } + + @Test + void testBeforeGetUserNotInGroupUsers() { + UserContext context = new UserContext("user2", "localhost", "en"); + UserContextHolder.apply(context, () -> { + assertThatThrownBy(() -> this.getSourceAspect.beforeGet(this.joinPoint)).isInstanceOf(ModelEngineException.class); + assertNull(UserInfoHolder.get()); + }); + } + + @Test + void testBeforeGetUserInAllGroupUsers() { + UserContext context = new UserContext("admin1", "localhost", "en"); + UserContextHolder.apply(context, () -> { + this.getSourceAspect.beforeGet(this.joinPoint); + assertNull(UserInfoHolder.get()); + }); + } + + @Test + void testAfterThrowing() { + this.getSourceAspect.afterGetThrowing(this.joinPoint); + assertNull(UserInfoHolder.get()); + } +} diff --git a/app-builder/plugins/aipp-northbound/pom.xml b/app-builder/plugins/aipp-northbound/pom.xml index 812058b203..898ad3c085 100644 --- a/app-builder/plugins/aipp-northbound/pom.xml +++ b/app-builder/plugins/aipp-northbound/pom.xml @@ -61,6 +61,10 @@ modelengine.jade.service app-engine-base-service + + modelengine.jade.service + aipp-domain-division-service + diff --git a/app-builder/plugins/aipp-northbound/src/main/java/modelengine/fit/jade/aipp/northbound/controller/AppBuilderAppController.java b/app-builder/plugins/aipp-northbound/src/main/java/modelengine/fit/jade/aipp/northbound/controller/AppBuilderAppController.java index 3ec6933fa1..f875190ad6 100644 --- a/app-builder/plugins/aipp-northbound/src/main/java/modelengine/fit/jade/aipp/northbound/controller/AppBuilderAppController.java +++ b/app-builder/plugins/aipp-northbound/src/main/java/modelengine/fit/jade/aipp/northbound/controller/AppBuilderAppController.java @@ -8,15 +8,15 @@ import static modelengine.fitframework.inspection.Validation.notNull; -import modelengine.fit.jane.task.gateway.Authenticator; - import modelengine.fit.http.annotation.GetMapping; import modelengine.fit.http.annotation.PathVariable; import modelengine.fit.http.annotation.RequestBean; import modelengine.fit.http.annotation.RequestMapping; import modelengine.fit.http.server.HttpClassicServerRequest; +import modelengine.fit.jade.aipp.domain.division.annotation.GetSource; import modelengine.fit.jane.common.controller.AbstractController; import modelengine.fit.jane.common.response.Rsp; +import modelengine.fit.jane.task.gateway.Authenticator; import modelengine.fit.jober.aipp.dto.AppBuilderAppDto; import modelengine.fit.jober.aipp.dto.chat.AppMetadata; import modelengine.fit.jober.aipp.dto.chat.AppQueryParams; @@ -74,6 +74,7 @@ private static List replaceAsterisks(List excludeNames) { */ @GetMapping(summary = "查询用户应用列表", description = "该接口可以使用指定条件筛选用户应用列表,如应用id、查询的应用名字和状态等.") + @GetSource public Rsp> list(HttpClassicServerRequest httpRequest, @PathVariable("tenantId") @Property(description = "租户的唯一标识符") String tenantId, @RequestBean AppQueryParams cond) { diff --git a/app-builder/plugins/aipp-parallel-tool/src/main/resources/sql/data/aipp_parallel_tool.sql b/app-builder/plugins/aipp-parallel-tool/src/main/resources/sql/data/aipp_parallel_tool.sql index bb970ae169..083fa02bf4 100644 --- a/app-builder/plugins/aipp-parallel-tool/src/main/resources/sql/data/aipp_parallel_tool.sql +++ b/app-builder/plugins/aipp-parallel-tool/src/main/resources/sql/data/aipp_parallel_tool.sql @@ -1,6 +1,6 @@ -INSERT INTO "public"."store_plugin" ("plugin_id", "plugin_name", "extension", "deploy_status", "is_builtin", "source", "icon") VALUES ('d44a239ed854ef94af0f032a526907e20ba8a56ebb4f851cc6956c0172a144e7', '并行', '{"uniqueness.groupId":"modelengine.fit.jade.plugin","pluginFullName":"aipp-parallel-tool-1.0.0-SNAPSHOT_1745841582889.jar","checksum":"42266c0ada1415feb0b689f288b4063b9406506ff7da16eca0332b91a01df20e","name":"并行","description":"并行执行工具","uniqueness.artifactId":"aipp-parallel-tool","type":"java"}', 'DEPLOYED', 't', '', NULL) ON CONFLICT ("plugin_id") DO NOTHING; +INSERT INTO "public"."store_plugin" ("plugin_id", "plugin_name", "extension", "deploy_status", "is_builtin", "source", "icon", "user_group_id") VALUES ('d44a239ed854ef94af0f032a526907e20ba8a56ebb4f851cc6956c0172a144e7', '并行', '{"uniqueness.groupId":"modelengine.fit.jade.plugin","pluginFullName":"aipp-parallel-tool-1.0.0-SNAPSHOT_1745841582889.jar","checksum":"42266c0ada1415feb0b689f288b4063b9406506ff7da16eca0332b91a01df20e","name":"并行","description":"并行执行工具","uniqueness.artifactId":"aipp-parallel-tool","type":"java"}', 'DEPLOYED', 't', '', NULL, '*') ON CONFLICT ("plugin_id") DO NOTHING; -INSERT INTO "public"."store_plugin_tool" ("tool_name", "plugin_id", "tool_unique_name") VALUES ('parallelToolDefault', 'd44a239ed854ef94af0f032a526907e20ba8a56ebb4f851cc6956c0172a144e7', '1d0c8164-1aea-4264-879f-2c7898d13fb9') ON CONFLICT ("plugin_id", "tool_unique_name") DO NOTHING; +INSERT INTO "public"."store_plugin_tool" ("tool_name", "plugin_id", "tool_unique_name", "user_group_id") VALUES ('parallelToolDefault', 'd44a239ed854ef94af0f032a526907e20ba8a56ebb4f851cc6956c0172a144e7', '1d0c8164-1aea-4264-879f-2c7898d13fb9', '*') ON CONFLICT ("plugin_id", "tool_unique_name") DO NOTHING; INSERT INTO "public"."store_definition" ("name", "schema", "definition_group_name") VALUES ('parallelTool', '{"name":"parallelTool","description":"用于并行执行工具","parameters":{"type":"object","properties":{"toolCalls":{"default":"","description":"并行调用的工具列表","name":"toolCalls","type":"array","items":{"type":"object","properties":{"uniqueName":{"type":"string"},"args":{"type":"object"},"outputName":{"type":"string"}}},"required":[]},"config":{"default":"","description":"并行调用的配置","name":"config","type":"object","properties":{"concurrency":{"type":"integer"}},"required":[]},"context":{"default":"","description":"调用时的上下文信息","name":"context","type":"object","required":[]}},"required":["toolCalls"]},"order":["toolCalls","config","context"],"parameterExtensions":null,"return":{"type":"object","convertor":""}}', 'ParallelTool') ON CONFLICT ("definition_group_name", "name") DO NOTHING; diff --git a/app-builder/plugins/aipp-plugin/pom.xml b/app-builder/plugins/aipp-plugin/pom.xml index 09668c0065..f3e52b69ac 100644 --- a/app-builder/plugins/aipp-plugin/pom.xml +++ b/app-builder/plugins/aipp-plugin/pom.xml @@ -229,6 +229,10 @@ common-service 1.0.0-SNAPSHOT + + modelengine.jade.service + aipp-domain-division-service + diff --git a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/aop/AppValidation.java b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/aop/AppValidation.java new file mode 100644 index 0000000000..0780156156 --- /dev/null +++ b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/aop/AppValidation.java @@ -0,0 +1,23 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fit.jober.aipp.aop; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/** + * 应用校验注解 + * + * @author 邬涨财 + * @since 2025-08-25 + */ +@Target(METHOD) +@Retention(RUNTIME) +public @interface AppValidation {} diff --git a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/aop/AppValidationAspect.java b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/aop/AppValidationAspect.java new file mode 100644 index 0000000000..e463f3c2fb --- /dev/null +++ b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/aop/AppValidationAspect.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + */ + +package modelengine.fit.jober.aipp.aop; + +import modelengine.fit.jade.aipp.domain.division.service.DomainDivisionService; +import modelengine.fit.jober.aipp.common.exception.AippErrCode; +import modelengine.fit.jober.aipp.common.exception.AippException; +import modelengine.fit.jober.aipp.domains.appversion.AppVersion; +import modelengine.fit.jober.aipp.domains.appversion.service.AppVersionService; +import modelengine.fitframework.annotation.Component; +import modelengine.fitframework.annotation.Value; +import modelengine.fitframework.aop.JoinPoint; +import modelengine.fitframework.aop.annotation.Aspect; +import modelengine.fitframework.aop.annotation.Before; + +import java.util.Optional; + +/** + * 应用校验切面 + * + * @author 邬涨财 + * @since 2025-08-25 + */ +@Aspect +@Component +public class AppValidationAspect extends ValidationAspect { + private final AppVersionService appVersionService; + + public AppValidationAspect(AppVersionService appVersionService, + DomainDivisionService domainDivisionService, + @Value("${domain-division.isEnable}") boolean isEnableDomainDivision) { + super(domainDivisionService, isEnableDomainDivision); + this.appVersionService = appVersionService; + } + + @Before("@annotation(modelengine.fit.jober.aipp.aop.AppValidation)") + public void appValidation(JoinPoint joinPoint) { + this.validate(joinPoint, "appId"); + } + + @Override + protected String getUserGroupId(String id) { + Optional appVersionOptional = this.appVersionService.getByAppId(String.valueOf(id)); + if (appVersionOptional.isEmpty()) { + throw new AippException(AippErrCode.APP_NOT_FOUND); + } + AppVersion appVersion = appVersionOptional.get(); + return appVersion.getData().getUserGroupId(); + } + + @Override + protected void throwNoPermissionException() { + throw new AippException(AippErrCode.NO_PERMISSION_OPERATE_APP); + } +} diff --git a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/aop/FormValidation.java b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/aop/FormValidation.java new file mode 100644 index 0000000000..8cfd6715d0 --- /dev/null +++ b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/aop/FormValidation.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + */ + +package modelengine.fit.jober.aipp.aop; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/** + * 表单校验注解 + * + * @author 邬涨财 + * @since 2025-08-26 + */ +@Target(METHOD) +@Retention(RUNTIME) +public @interface FormValidation {} diff --git a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/aop/FormValidationAspect.java b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/aop/FormValidationAspect.java new file mode 100644 index 0000000000..7c86827ee6 --- /dev/null +++ b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/aop/FormValidationAspect.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + */ + +package modelengine.fit.jober.aipp.aop; + +import modelengine.fit.jade.aipp.domain.division.service.DomainDivisionService; +import modelengine.fit.jober.aipp.common.exception.AippErrCode; +import modelengine.fit.jober.aipp.common.exception.AippException; +import modelengine.fit.jober.aipp.domain.AppBuilderForm; +import modelengine.fit.jober.aipp.service.AppBuilderFormService; +import modelengine.fitframework.annotation.Component; +import modelengine.fitframework.annotation.Value; +import modelengine.fitframework.aop.JoinPoint; +import modelengine.fitframework.aop.annotation.Aspect; +import modelengine.fitframework.aop.annotation.Before; + +/** + * 表单校验切面 + * + * @author 邬涨财 + * @since 2025-08-26 + */ +@Aspect +@Component +public class FormValidationAspect extends ValidationAspect { + private final AppBuilderFormService appBuilderFormService; + + public FormValidationAspect(DomainDivisionService domainDivisionService, + AppBuilderFormService appBuilderFormService, + @Value("${domain-division.isEnable}") boolean isEnableDomainDivision) { + super(domainDivisionService, isEnableDomainDivision); + this.appBuilderFormService = appBuilderFormService; + } + + @Before("@annotation(modelengine.fit.jober.aipp.aop.FormValidation)") + public void appValidation(JoinPoint joinPoint) { + this.validate(joinPoint, "formId"); + } + + @Override + protected void throwNoPermissionException() { + throw new AippException(AippErrCode.NO_PERMISSION_OPERATE_FORM); + } + + @Override + protected String getUserGroupId(String id) { + AppBuilderForm appBuilderForm = this.appBuilderFormService.selectWithId(id); + if (appBuilderForm == null) { + throw new AippException(AippErrCode.FORM_NOT_EXIST); + } + return appBuilderForm.getUserGroupId(); + } +} diff --git a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/aop/ValidationAspect.java b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/aop/ValidationAspect.java new file mode 100644 index 0000000000..faee455b16 --- /dev/null +++ b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/aop/ValidationAspect.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + */ + +package modelengine.fit.jober.aipp.aop; + +import modelengine.fit.jade.aipp.domain.division.service.DomainDivisionService; +import modelengine.fitframework.annotation.Value; +import modelengine.fitframework.aop.JoinPoint; +import modelengine.fitframework.aop.MethodSignature; + +import java.util.Collections; + +/** + * 校验切面 + * + * @author 邬涨财 + * @since 2025-08-26 + */ +public abstract class ValidationAspect { + private final DomainDivisionService domainDivisionService; + private final boolean isEnableDomainDivision; + + public ValidationAspect(DomainDivisionService domainDivisionService, + @Value("${domain-division.isEnable}") boolean isEnableDomainDivision) { + this.domainDivisionService = domainDivisionService; + this.isEnableDomainDivision = isEnableDomainDivision; + } + + /** + * 资源校验 + * + * @param joinPoint 表示连接点的 {@link JoinPoint}。 + * @param idKey 表示变量键的 {@link String}。 + */ + protected void validate(JoinPoint joinPoint, String idKey) { + MethodSignature signature = (MethodSignature) joinPoint.getSignature(); + String[] paramNames = signature.getParameterNames(); + Object[] paramValues = joinPoint.getArgs(); + Object id = null; + for (int i = 0; i < paramNames.length; i++) { + if (paramNames[i].equals(idKey)) { + id = paramValues[i]; + break; + } + } + if (id == null) { + return; + } + if (!this.isEnableDomainDivision) { + return; + } + String appUserGroupId = this.getUserGroupId(String.valueOf(id)); + if (!this.domainDivisionService.validate(Collections.singletonList(appUserGroupId))) { + throwNoPermissionException(); + } + } + + /** + * 抛出没有权限的异常。 + */ + protected abstract void throwNoPermissionException(); + + /** + * 获取资源的用户组唯一标识。 + * + * @param id 表示资源唯一标识的 {@link String}。 + * @return 表示用户组唯一标识的 {@link String} + */ + protected abstract String getUserGroupId(String id); +} diff --git a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/common/exception/AippErrCode.java b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/common/exception/AippErrCode.java index ecd511011d..7c83c5ce98 100644 --- a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/common/exception/AippErrCode.java +++ b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/common/exception/AippErrCode.java @@ -761,6 +761,21 @@ public enum AippErrCode implements ErrorCode, RetCode { */ GENERATE_CONTENT_FAILED(90002140, "大模型生成{0}失败,请尝试更换默认模型,失败原因:{1}。"), + /** + * 没有权限操作该应用。 + */ + NO_PERMISSION_OPERATE_APP(90002141, "没有权限操作该应用。"), + + /** + * 表单不存在。 + */ + FORM_NOT_EXIST(90002142, "表单不存在。"), + + /** + * 没有权限操作该表单。 + */ + NO_PERMISSION_OPERATE_FORM(90002143, "没有权限操作该表单。"), + /** * 应用模板不存在。 */ diff --git a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/condition/AppQueryCondition.java b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/condition/AppQueryCondition.java index b548ff772f..ba4370732f 100644 --- a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/condition/AppQueryCondition.java +++ b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/condition/AppQueryCondition.java @@ -49,4 +49,5 @@ public class AppQueryCondition { @RequestParam(name = "app_type", required = false) private String appType; private String createBy; + private String userGroupId; } diff --git a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/condition/FormQueryCondition.java b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/condition/FormQueryCondition.java index 960e19b4d2..8e0d204bc3 100644 --- a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/condition/FormQueryCondition.java +++ b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/condition/FormQueryCondition.java @@ -32,4 +32,5 @@ public class FormQueryCondition { private String id; private String createBy; private List excludeNames; + private String userGroupId; } diff --git a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/controller/AppBuilderAppController.java b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/controller/AppBuilderAppController.java index fb11f09c95..34d75b489e 100644 --- a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/controller/AppBuilderAppController.java +++ b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/controller/AppBuilderAppController.java @@ -22,10 +22,13 @@ import modelengine.fit.http.entity.PartitionedEntity; import modelengine.fit.http.server.HttpClassicServerRequest; import modelengine.fit.http.server.HttpClassicServerResponse; +import modelengine.fit.jade.aipp.domain.division.annotation.CreateSource; +import modelengine.fit.jade.aipp.domain.division.annotation.GetSource; import modelengine.fit.jane.common.controller.AbstractController; import modelengine.fit.jane.common.entity.OperationContext; import modelengine.fit.jane.common.response.Rsp; import modelengine.fit.jane.task.gateway.Authenticator; +import modelengine.fit.jober.aipp.aop.AppValidation; import modelengine.fit.jober.aipp.common.exception.AippErrCode; import modelengine.fit.jober.aipp.common.exception.AippException; import modelengine.fit.jober.aipp.condition.AppQueryCondition; @@ -139,6 +142,7 @@ private static List replaceAsterisks(List excludeNames) { * @return 查询结果列表。 */ @GetMapping(description = "查询 app 列表") + @GetSource public Rsp> list(HttpClassicServerRequest httpRequest, @PathVariable("tenant_id") String tenantId, @RequestParam(value = "offset", defaultValue = "0") long offset, @RequestParam(value = "limit", defaultValue = "10") int limit, @RequestBean AppQueryCondition cond, @@ -155,6 +159,7 @@ public Rsp> list(HttpClassicServerRequ * @return 表示查询app的最新可编排版本的DTO {@link Rsp}{@code <}{@link AppBuilderAppDto}{@code >}。 */ @GetMapping(value = "/{app_id}", description = "查询 app ") + @AppValidation public Rsp query(HttpClassicServerRequest httpRequest, @PathVariable("tenant_id") String tenantId, @PathVariable("app_id") String appId) { return Rsp.ok(this.appGenericable.query(appId, this.contextOf(httpRequest, tenantId))); @@ -169,6 +174,7 @@ public Rsp query(HttpClassicServerRequest httpRequest, * @return 表示查询app的最新可编排版本的DTO {@link Rsp}{@code <}{@link AppBuilderAppDto}{@code >}。 */ @GetMapping(value = "/{app_id}/latest_orchestration", description = "查询 app 最新可编排的版本") + @AppValidation public Rsp queryLatestOrchestration(HttpClassicServerRequest httpRequest, @PathVariable("tenant_id") String tenantId, @PathVariable("app_id") String appId) { return Rsp.ok(this.appGenericable.queryLatestOrchestration(appId, this.contextOf(httpRequest, tenantId))); @@ -222,6 +228,7 @@ public Rsp published(HttpClassicServerRequest httpRequest, */ @CarverSpan(value = "operation.appBuilderApp.template") @PostMapping(value = "/{app_id}", description = "根据模板创建aipp") + @CreateSource public Rsp create(HttpClassicServerRequest request, @PathVariable("app_id") String appId, @PathVariable("tenant_id") String tenantId, @RequestBody @Validated @SpanAttr("name:$.name") AppBuilderAppCreateDto dto) { @@ -248,6 +255,7 @@ public Rsp create(HttpClassicServerRequest request, @PathVaria */ @CarverSpan(value = "operation.appBuilderApp.config") @PutMapping(value = "/{app_id}/config", description = "通过config更新aipp") + @AppValidation public Rsp saveConfig(HttpClassicServerRequest httpRequest, @PathVariable("tenant_id") String tenantId, @PathVariable("app_id") String appId, @RequestBody @Validated AppBuilderSaveConfigDto appBuilderSaveConfigDto) { @@ -265,6 +273,7 @@ public Rsp saveConfig(HttpClassicServerRequest httpRequest, */ @CarverSpan(value = "operation.appBuilderApp.graph") @PutMapping(value = "/{app_id}/graph", description = "根据graph更新aipp") + @AppValidation public Rsp updateByGraph(HttpClassicServerRequest httpRequest, @PathVariable("tenant_id") String tenantId, @PathVariable("app_id") String appId, @RequestBody @Validated AppBuilderFlowGraphDto flowGraphDto) { @@ -282,6 +291,7 @@ public Rsp updateByGraph(HttpClassicServerRequest httpRequest, */ @CarverSpan(value = "operation.appBuilderApp.update") @PutMapping(value = "/{app_id}", description = "更新 app") + @AppValidation public Rsp update(HttpClassicServerRequest httpRequest, @PathVariable("tenant_id") String tenantId, @PathVariable("app_id") String appId, @RequestBody @Validated @SpanAttr("name:$.name") AppBuilderAppDto appDto) { @@ -298,7 +308,10 @@ public Rsp update(HttpClassicServerRequest httpRequest, */ @CarverSpan(value = "operation.appBuilderApp.publish") @PostMapping(path = "/{app_id}/publish", description = "发布 app ") + @CreateSource + @AppValidation public Rsp publish(HttpClassicServerRequest httpRequest, @PathVariable("tenant_id") String tenantId, + @PathVariable("app_id") String appId, @RequestBody @Validated @SpanAttr("name:$.name, version:$.version") AppBuilderAppDto appDto) { return this.appService.publish(appDto, this.contextOf(httpRequest, tenantId)); } @@ -313,7 +326,9 @@ public Rsp publish(HttpClassicServerRequest httpRequest, @PathVar */ @CarverSpan(value = "operation.appBuilderApp.debug") @PostMapping(path = "/{app_id}/debug", description = "调试 app ") + @AppValidation public Rsp debug(HttpClassicServerRequest httpRequest, @PathVariable("tenant_id") String tenantId, + @PathVariable("app_id") String appId, @RequestBody @Validated @SpanAttr("name:$.name") AppBuilderAppDto appDto) { return Rsp.ok(ConvertUtils.toAippCreateDto(this.appGenericable.debug(appDto, this.contextOf(httpRequest, tenantId)))); @@ -328,6 +343,7 @@ public Rsp debug(HttpClassicServerRequest httpRequest, @PathVaria * @return 返回结果。 */ @GetMapping(path = "/{app_id}/latest_published", description = "获取 app 最新发布版本信息") + @AppValidation public Rsp latestPublished(HttpClassicServerRequest httpRequest, @PathVariable("tenant_id") String tenantId, @PathVariable("app_id") String appId) { return Rsp.ok(ConvertUtils.toAippCreateDto(this.appGenericable.queryLatestPublished(appId, @@ -344,7 +360,9 @@ public Rsp latestPublished(HttpClassicServerRequest httpRequest, */ @CarverSpan(value = "operation.appBuilderApp.idea") @PostMapping(path = "/{app_id}/inspiration/department", description = "获取灵感大全的部门信息") + @AppValidation public Rsp inspirations(HttpClassicServerRequest httpRequest, + @PathVariable("app_id") String appId, @PathVariable("tenant_id") String tenantId, @RequestBody @Validated AppBuilderAppDto appDto) { throw new UnsupportedOperationException(); } @@ -359,6 +377,7 @@ public Rsp inspirations(HttpClassicServerRequest httpRequest, */ @CarverSpan(value = "operation.appBuilderApp.delete") @DeleteMapping(path = "/{app_id}", description = "删除 app") + @AppValidation public Rsp delete(HttpClassicServerRequest httpRequest, @PathVariable("tenant_id") String tenantId, @PathVariable("app_id") @SpanAttr("app_id") String appId) { this.appService.delete(appId, this.contextOf(httpRequest, tenantId)); @@ -376,6 +395,7 @@ public Rsp delete(HttpClassicServerRequest httpRequest, @PathVariable("ten */ @CarverSpan(value = "operation.appBuilderApp.export") @GetMapping(path = "/export/{app_id}", description = "导出应用配置") + @AppValidation public FileEntity export(HttpClassicServerRequest httpRequest, @PathVariable("tenant_id") String tenantId, @PathVariable("app_id") String appId, HttpClassicServerResponse response) { AppExportDto configDto = this.appDomainService.exportApp(appId, this.exportMeta, @@ -414,6 +434,7 @@ public Rsp> checkAvailable(HttpClassicServerRequest httpReques */ @CarverSpan(value = "operation.appBuilderApp.import") @PostMapping(path = "/import", description = "导入应用配置") + @CreateSource public Rsp importApp(HttpClassicServerRequest httpRequest, @PathVariable("tenant_id") String tenantId, PartitionedEntity appConfig) { this.fitRuntime.publisherOfEvents().publishEvent(new AppCreatingEvent(this)); @@ -449,6 +470,7 @@ public Rsp importApp(HttpClassicServerRequest httpRequest, */ @CarverSpan(value = "operation.appBuilderApp.recoverApp") @PostMapping(path = "/{app_id}/recover") + @AppValidation public Rsp recoverApp(HttpClassicServerRequest httpRequest, @PathVariable("tenant_id") String tenantId, @PathVariable("app_id") String appId, @RequestBody String recoverAppId) { diff --git a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/controller/AppBuilderFormController.java b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/controller/AppBuilderFormController.java index afd613aee9..69167f0785 100644 --- a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/controller/AppBuilderFormController.java +++ b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/controller/AppBuilderFormController.java @@ -6,9 +6,12 @@ package modelengine.fit.jober.aipp.controller; +import modelengine.fit.jade.aipp.domain.division.annotation.CreateSource; +import modelengine.fit.jade.aipp.domain.division.annotation.GetSource; import modelengine.fit.jane.common.controller.AbstractController; import modelengine.fit.jane.common.response.Rsp; import modelengine.fit.jane.task.gateway.Authenticator; +import modelengine.fit.jober.aipp.aop.FormValidation; import modelengine.fit.jober.aipp.dto.AppBuilderFormDto; import modelengine.fit.jober.aipp.service.AppBuilderFormService; import modelengine.fit.jober.common.RangedResultSet; @@ -74,6 +77,7 @@ public Rsp> queryByType(HttpClassicServerRequest httpReq */ @PostMapping(value = "/smart_form", description = "创建智能表单") @CarverSpan(value = "operation.create.smart.form") + @CreateSource public Rsp create(HttpClassicServerRequest httpRequest, @PathVariable("tenant_id") String tenantId, @RequestBody AppBuilderFormDto appBuilderFormDto) { return Rsp.ok(this.formService.create(appBuilderFormDto, this.contextOf(httpRequest, tenantId))); @@ -90,6 +94,7 @@ public Rsp create(HttpClassicServerRequest httpRequest, */ @PutMapping(value = "/smart_form/{form_id}", description = "更新智能表单") @CarverSpan(value = "operation.update.smart.form") + @FormValidation public Rsp update(HttpClassicServerRequest httpRequest, @PathVariable("tenant_id") String tenantId, @RequestBody AppBuilderFormDto appBuilderFormDto, @PathVariable("form_id") @SpanAttr("form_id") String formId) { @@ -107,6 +112,7 @@ public Rsp update(HttpClassicServerRequest httpRequest, * @return 表示查询结果的的 {@link RangedResultSet}{@code <}{@link AppBuilderFormDto}{@code >}。 */ @GetMapping(value = "/smart_form/", description = "查询智能表单") + @GetSource public Rsp> query(HttpClassicServerRequest httpRequest, @PathVariable("tenant_id") String tenantId, @RequestParam(value = "pageNum", defaultValue = "0") long pageNum, @@ -125,6 +131,7 @@ public Rsp> query(HttpClassicServerRequest ht */ @DeleteMapping(value = "/smart_form/{form_id}", description = "删除智能表单") @CarverSpan(value = "operation.delete.smart.form") + @FormValidation public Rsp delete(HttpClassicServerRequest httpRequest, @PathVariable("tenant_id") String tenantId, @PathVariable("form_id") @SpanAttr("form_id") String formId) { return Rsp.ok(this.formService.delete(formId, this.contextOf(httpRequest, tenantId))); diff --git a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/controller/AppBuilderPromptController.java b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/controller/AppBuilderPromptController.java index 06054dc55d..eb8de5d7ca 100644 --- a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/controller/AppBuilderPromptController.java +++ b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/controller/AppBuilderPromptController.java @@ -9,6 +9,7 @@ import modelengine.fit.jane.common.controller.AbstractController; import modelengine.fit.jane.common.response.Rsp; import modelengine.fit.jane.task.gateway.Authenticator; +import modelengine.fit.jober.aipp.aop.AppValidation; import modelengine.fit.jober.aipp.dto.AppBuilderPromptCategoryDto; import modelengine.fit.jober.aipp.dto.AppBuilderPromptDto; import modelengine.fit.jober.aipp.service.AppBuilderPromptService; @@ -60,6 +61,7 @@ public AppBuilderPromptController(Authenticator authenticator, AppBuilderPromptS * @return 返回所有的灵感类别。 */ @GetMapping + @AppValidation public Rsp> listCategories(HttpClassicServerRequest httpRequest, @PathVariable("tenant_id") String tenantId, @PathVariable("app_id") String appId, @RequestParam(value = "isDebug", defaultValue = "true", required = false) boolean isDebug) { @@ -77,6 +79,7 @@ public Rsp> listCategories(HttpClassicServerRe * @return 返回指定类别的所有灵感 {@link Rsp}{@code <}{@link AppBuilderPromptDto}{@code >}。 */ @GetMapping("/{category_id}") + @AppValidation public Rsp queryInspirations(HttpClassicServerRequest httpRequest, @PathVariable("tenant_id") String tenantId, @PathVariable("app_id") String appId, @PathVariable("category_id") String categoryId, @@ -96,6 +99,7 @@ public Rsp queryInspirations(HttpClassicServerRequest httpR */ @CarverSpan(value = "operation.inspiration.addMy") @PostMapping("/{parent_id}") + @AppValidation public Rsp addMyInspiration(HttpClassicServerRequest httpRequest, @PathVariable("tenant_id") String tenantId, @PathVariable("parent_id") String parentId, @SpanAttr("app_id") @PathVariable("app_id") String appId, @RequestBody AppBuilderPromptDto.AppBuilderInspirationDto inspirationDto) { @@ -116,6 +120,7 @@ public Rsp addMyInspiration(HttpClassicServerRequest httpRequest, @PathVar */ @CarverSpan(value = "operation.inspiration.updateMy") @PutMapping("/{category_id}/inspiration/{inspiration_id}") + @AppValidation public Rsp updateMyInspiration(HttpClassicServerRequest httpRequest, @PathVariable("tenant_id") String tenantId, @PathVariable("category_id") String categoryId, @SpanAttr("app_id") @PathVariable("app_id") String appId, @@ -141,6 +146,7 @@ public Rsp updateMyInspiration(HttpClassicServerRequest httpRequest, */ @CarverSpan(value = "operation.inspiration.delete") @DeleteMapping("/{category_id}/inspiration/{inspiration_id}") + @AppValidation public Rsp deleteMyInspiration(HttpClassicServerRequest httpRequest, @PathVariable("tenant_id") String tenantId, @PathVariable("category_id") String categoryId, @SpanAttr("app_id") @PathVariable("app_id") String appId, diff --git a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/controller/AppTemplateController.java b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/controller/AppTemplateController.java index 529ddf6cdb..8900187167 100644 --- a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/controller/AppTemplateController.java +++ b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/controller/AppTemplateController.java @@ -6,6 +6,7 @@ package modelengine.fit.jober.aipp.controller; +import modelengine.fit.jade.aipp.domain.division.annotation.CreateSource; import modelengine.fit.jane.common.controller.AbstractController; import modelengine.fit.jane.common.response.Rsp; import modelengine.fit.jane.task.gateway.Authenticator; @@ -83,6 +84,7 @@ public Rsp publish(HttpClassicServerRequest request, @PathVaria */ @PostMapping(value = "/create", description = "根据应用模板创建应用") @CarverSpan(value = "operation.appTemplate.create") + @CreateSource public Rsp create(HttpClassicServerRequest request, @PathVariable("tenant_id") String tenantId, @RequestBody @SpanAttr("name:$.name") TemplateAppCreateDto createDto) { return Rsp.ok(this.appTemplateService.createAppByTemplate(createDto, this.contextOf(request, tenantId))); diff --git a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/domain/AppBuilderForm.java b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/domain/AppBuilderForm.java index 28dfcf7b3f..38030fe265 100644 --- a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/domain/AppBuilderForm.java +++ b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/domain/AppBuilderForm.java @@ -36,6 +36,7 @@ public class AppBuilderForm extends BaseDomain { private String version; private String formSuiteId; private AppBuilderFormPropertyRepository formPropertyRepository; + private String userGroupId; public AppBuilderForm(AppBuilderFormPropertyRepository formPropertyRepository) { this.formPropertyRepository = formPropertyRepository; diff --git a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/domains/app/App.java b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/domains/app/App.java index 01d7e7f78f..77aa8945f7 100644 --- a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/domains/app/App.java +++ b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/domains/app/App.java @@ -6,6 +6,7 @@ package modelengine.fit.jober.aipp.domains.app; +import modelengine.fit.jade.aipp.domain.division.service.DomainDivisionService; import modelengine.fit.jane.common.entity.OperationContext; import modelengine.fit.jober.aipp.common.exception.AippErrCode; import modelengine.fit.jober.aipp.common.exception.AippException; @@ -63,6 +64,8 @@ public class App { private final Map exportMeta; private final PluginToolService pluginToolService; private final PluginService pluginService; + private final DomainDivisionService domainDivisionService; + private final boolean isEnableDomainDivision; // 懒加载数据. private List appVersionList; @@ -71,7 +74,8 @@ public class App { AppBuilderFlowGraphRepository flowGraphRepository, AppBuilderFormPropertyRepository formPropertyRepository, AippLogMapper aippLogMapper, AppService appService, AippChatMapper aippChatMapper, AppVersionRepository appVersionRepository, AppVersionFactory appVersionFactory, - Map exportMeta, PluginToolService pluginToolService, PluginService pluginService) { + Map exportMeta, PluginToolService pluginToolService, PluginService pluginService, + DomainDivisionService domainDivisionService, boolean isEnableDomainDivision) { this.appSuiteId = appSuiteId; this.appVersionService = appVersionService; this.configRepository = configRepository; @@ -85,6 +89,8 @@ public class App { this.exportMeta = exportMeta; this.pluginToolService = pluginToolService; this.pluginService = pluginService; + this.domainDivisionService = domainDivisionService; + this.isEnableDomainDivision = isEnableDomainDivision; } /** @@ -126,6 +132,9 @@ public AppExportDto export(OperationContext context) { public AppVersion importData(AppExportDto appDto, String contextRoot, OperationContext context) { AppVersion appVersion = this.appVersionFactory.create(new AppBuilderAppPo(), this.appVersionRepository); appVersion.importData(appDto, this.appSuiteId, contextRoot, context, this.exportMeta); + if (this.isEnableDomainDivision) { + appVersion.getData().setUserGroupId(this.domainDivisionService.getUserGroupId()); + } this.appVersionService.validateAppName(appVersion.getData().getName(), context); this.appVersionService.save(appVersion); return appVersion; diff --git a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/domains/app/AppFactory.java b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/domains/app/AppFactory.java index 2a1d648679..bee0730db1 100644 --- a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/domains/app/AppFactory.java +++ b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/domains/app/AppFactory.java @@ -6,6 +6,7 @@ package modelengine.fit.jober.aipp.domains.app; +import modelengine.fit.jade.aipp.domain.division.service.DomainDivisionService; import modelengine.fit.jober.aipp.domains.appversion.AppVersion; import modelengine.fit.jober.aipp.domains.appversion.AppVersionFactory; import modelengine.fit.jober.aipp.domains.appversion.repository.AppVersionRepository; @@ -44,13 +45,16 @@ public class AppFactory { private final Map exportMeta; private final PluginToolService pluginToolService; private final PluginService pluginService; + private final DomainDivisionService domainDivisionService; + private final boolean isEnableDomainDivision; public AppFactory(AppVersionService appVersionService, AppBuilderConfigRepository configRepository, AppBuilderFlowGraphRepository flowGraphRepository, AppBuilderFormPropertyRepository formPropertyRepository, AippLogMapper aippLogMapper, AppService appService, AippChatMapper aippChatMapper, AppVersionRepository appVersionRepository, AppVersionFactory appVersionFactory, @Value("${export-meta}") Map exportMeta, PluginToolService pluginToolService, - PluginService pluginService) { + PluginService pluginService, DomainDivisionService domainDivisionService, + @Value("${domain-division.isEnable}") boolean isEnableDomainDivision) { this.appVersionService = appVersionService; this.configRepository = configRepository; this.flowGraphRepository = flowGraphRepository; @@ -63,6 +67,8 @@ public AppFactory(AppVersionService appVersionService, AppBuilderConfigRepositor this.exportMeta = exportMeta; this.pluginToolService = pluginToolService; this.pluginService = pluginService; + this.domainDivisionService = domainDivisionService; + this.isEnableDomainDivision = isEnableDomainDivision; } /** @@ -84,6 +90,8 @@ public App create(String appSuiteId) { this.appVersionFactory, this.exportMeta, this.pluginToolService, - this.pluginService); + this.pluginService, + this.domainDivisionService, + this.isEnableDomainDivision); } } diff --git a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/domains/appversion/publish/StorePublisher.java b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/domains/appversion/publish/StorePublisher.java index 887da000ef..117dbcddcf 100644 --- a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/domains/appversion/publish/StorePublisher.java +++ b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/domains/appversion/publish/StorePublisher.java @@ -86,6 +86,7 @@ private AppPublishData buildItemData(PublishContext context, AppVersion appVersi itemData.setSource(appCategory.getSource()); itemData.setTags(Set.of(appCategory.getTag())); itemData.setRunnables(this.buildRunnables(context, appVersion)); + itemData.setUserGroupId(context.getPublishData().getUserGroupId()); return itemData; } @@ -114,9 +115,11 @@ private PluginData buildPluginData(AppData appData) { pluginData.setExtension(new HashMap<>()); pluginData.setPluginId(Entities.generateId() + Entities.generateId()); PluginToolData pluginToolData = this.buildPluginToolData(appData, pluginData); + pluginToolData.setUserGroupId(appData.getUserGroupId()); pluginData.setPluginToolDataList(Collections.singletonList(pluginToolData)); pluginData.setDefinitionGroupDataList(List.of(AppData.toDefGroup(appData))); pluginData.setToolGroupDataList(List.of(AppData.toToolGroup(appData))); + pluginData.setUserGroupId(appData.getUserGroupId()); return pluginData; } diff --git a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/domains/appversion/service/impl/AppVersionServiceImpl.java b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/domains/appversion/service/impl/AppVersionServiceImpl.java index c1d3a55b7b..e383628165 100644 --- a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/domains/appversion/service/impl/AppVersionServiceImpl.java +++ b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/domains/appversion/service/impl/AppVersionServiceImpl.java @@ -9,6 +9,10 @@ import static modelengine.fit.jober.aipp.service.impl.UploadedFileMangeServiceImpl.IRREMOVABLE; import static modelengine.fit.jober.aipp.service.impl.UploadedFileMangeServiceImpl.REMOVABLE; +import com.alibaba.fastjson.JSONObject; + +import io.opentelemetry.api.trace.Span; +import modelengine.fit.jade.aipp.domain.division.service.DomainDivisionService; import modelengine.fit.jane.common.entity.OperationContext; import modelengine.fit.jane.common.enums.DirectionEnum; import modelengine.fit.jober.aipp.common.exception.AippErrCode; @@ -48,11 +52,6 @@ import modelengine.fit.jober.aipp.util.AippFileUtils; import modelengine.fit.jober.aipp.util.TemplateUtils; import modelengine.fit.jober.common.RangedResultSet; -import modelengine.jade.common.locale.LocaleUtil; - -import com.alibaba.fastjson.JSONObject; - -import io.opentelemetry.api.trace.Span; import modelengine.fitframework.annotation.Component; import modelengine.fitframework.annotation.Value; import modelengine.fitframework.flowable.Choir; @@ -60,6 +59,7 @@ import modelengine.fitframework.transaction.Transactional; import modelengine.fitframework.util.CollectionUtils; import modelengine.fitframework.util.StringUtils; +import modelengine.jade.common.locale.LocaleUtil; import java.time.LocalDateTime; import java.util.HashMap; @@ -90,6 +90,8 @@ public class AppVersionServiceImpl implements AppVersionService { private final AppBuilderConfigPropertyRepository configPropertyRepository; private final AppTaskService appTaskService; private final AppVersionFactory appVersionFactory; + private final DomainDivisionService domainDivisionService; + private final boolean isEnableDomainDivision; private final int nameLengthMaximum; public AppVersionServiceImpl(AppVersionRepository repository, AppChatRepository appChatRepository, @@ -97,8 +99,9 @@ public AppVersionServiceImpl(AppVersionRepository repository, AppChatRepository AppBuilderConfigRepository configRepository, AppBuilderFlowGraphRepository flowGraphRepository, AppBuilderFormPropertyRepository formPropertyRepository, AppBuilderConfigPropertyRepository configPropertyRepository, AppTaskService appTaskService, - AppVersionFactory appVersionFactory, - @Value("${validation.task.name.length.maximum:64}") int nameLengthMaximum) { + AppVersionFactory appVersionFactory, DomainDivisionService domainDivisionService, + @Value("${validation.task.name.length.maximum:64}") int nameLengthMaximum, + @Value("${domain-division.isEnable}") boolean isEnableDomainDivision) { this.repository = repository; this.appChatRepository = appChatRepository; this.appTaskInstanceService = appTaskInstanceService; @@ -110,6 +113,8 @@ public AppVersionServiceImpl(AppVersionRepository repository, AppChatRepository this.appTaskService = appTaskService; this.appVersionFactory = appVersionFactory; this.nameLengthMaximum = nameLengthMaximum; + this.domainDivisionService = domainDivisionService; + this.isEnableDomainDivision = isEnableDomainDivision; } @Override @@ -210,6 +215,9 @@ public AppVersion create(String templateId, AppBuilderAppCreateDto dto, Operatio AppVersion template = this.retrieval(templateId); template.create(); template.cloneVersion(dto, DEFAULT_APP_VERSION, AppTypeEnum.APP.name(), context); + if (this.isEnableDomainDivision) { + template.getData().setUserGroupId(this.domainDivisionService.getUserGroupId()); + } this.save(template); return template; } @@ -245,6 +253,9 @@ public AppVersion createByTemplate(AppTemplate template, OperationContext contex appVersion.cloneVersion(TemplateUtils.toAppCreateDTO(template), DEFAULT_APP_VERSION, AppTypeEnum.APP.name(), context); appVersion.getData().setState(AppState.INACTIVE.getName()); + if (this.isEnableDomainDivision) { + appVersion.getData().setUserGroupId(this.domainDivisionService.getUserGroupId()); + } this.save(appVersion); return appVersion; } diff --git a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/fitable/LlmComponent.java b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/fitable/LlmComponent.java index 07509d7f53..03230a6ebb 100644 --- a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/fitable/LlmComponent.java +++ b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/fitable/LlmComponent.java @@ -424,6 +424,8 @@ private ChatOption buildChatOptions(Map businessData) { OperationContext opContext = DataUtils.getOpContext(businessData); ModelAccessInfo modelAccessInfo = this.aippModelCenter.getModelAccessInfo(accessInfo.get("tag"), accessInfo.get("serviceName"), opContext); + Map extensions = new HashMap<>(); + extensions.put(AippConst.CONTEXT_USER_ID, businessData.getOrDefault(AippConst.CONTEXT_USER_ID, null)); return ChatOption.custom() .model(accessInfo.get("serviceName")) .baseUrl(modelAccessInfo.getBaseUrl()) @@ -432,6 +434,7 @@ private ChatOption buildChatOptions(Map businessData) { .apiKey(modelAccessInfo.getAccessKey()) .temperature(ObjectUtils.cast(businessData.get("temperature"))) .tools(this.buildToolInfos(businessData)) + .extensions(extensions) .build(); } diff --git a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/po/AppBuilderAppPo.java b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/po/AppBuilderAppPo.java index 7981821fec..2bdc72ed76 100644 --- a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/po/AppBuilderAppPo.java +++ b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/po/AppBuilderAppPo.java @@ -53,4 +53,5 @@ public class AppBuilderAppPo { private String status; private String uniqueName; private LocalDateTime publishAt; + private String userGroupId; } diff --git a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/po/AppBuilderFormPo.java b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/po/AppBuilderFormPo.java index a5c2647c76..7f56ed2341 100644 --- a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/po/AppBuilderFormPo.java +++ b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/po/AppBuilderFormPo.java @@ -35,4 +35,5 @@ public class AppBuilderFormPo { private LocalDateTime updateAt; private String version; private String formSuiteId; + private String userGroupId; } diff --git a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/serializer/impl/AppBuilderFormSerializer.java b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/serializer/impl/AppBuilderFormSerializer.java index b75620ce54..bf08372eb0 100644 --- a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/serializer/impl/AppBuilderFormSerializer.java +++ b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/serializer/impl/AppBuilderFormSerializer.java @@ -37,6 +37,7 @@ public AppBuilderFormPo serialize(AppBuilderForm appBuilderForm) { .updateBy(appBuilderForm.getUpdateBy()) .version(appBuilderForm.getVersion()) .formSuiteId(appBuilderForm.getFormSuiteId()) + .userGroupId(appBuilderForm.getUserGroupId()) .build(); } @@ -58,6 +59,7 @@ public AppBuilderForm deserialize(AppBuilderFormPo appBuilderFormPO) { .updateBy(appBuilderFormPO.getUpdateBy()) .version(appBuilderFormPO.getVersion()) .formSuiteId(appBuilderFormPO.getFormSuiteId()) + .userGroupId(appBuilderFormPO.getUserGroupId()) .build(); } } diff --git a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/service/impl/AppBuilderAppServiceImpl.java b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/service/impl/AppBuilderAppServiceImpl.java index 245d3b8458..f40fdc161f 100644 --- a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/service/impl/AppBuilderAppServiceImpl.java +++ b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/service/impl/AppBuilderAppServiceImpl.java @@ -11,7 +11,7 @@ import static modelengine.fit.jober.aipp.common.exception.AippErrCode.QUERY_PUBLICATION_HISTORY_FAILED; import io.opentelemetry.api.trace.Span; -import lombok.RequiredArgsConstructor; +import modelengine.fit.jade.aipp.domain.division.service.DomainDivisionService; import modelengine.fit.jane.common.entity.OperationContext; import modelengine.fit.jane.common.response.Rsp; import modelengine.fit.jober.aipp.common.exception.AippErrCode; @@ -55,6 +55,7 @@ import modelengine.fit.jober.common.RangedResultSet; import modelengine.fitframework.annotation.Component; import modelengine.fitframework.annotation.Fitable; +import modelengine.fitframework.annotation.Value; import modelengine.fitframework.log.Logger; import modelengine.fitframework.transaction.Transactional; import modelengine.fitframework.util.StringUtils; @@ -78,7 +79,6 @@ * @since 2024-04-17 */ @Component -@RequiredArgsConstructor public class AppBuilderAppServiceImpl implements AppBuilderAppService, modelengine.fit.jober.aipp.genericable.AppBuilderAppService { private static final Logger log = Logger.get(AppBuilderAppServiceImpl.class); @@ -93,6 +93,26 @@ public class AppBuilderAppServiceImpl private final AppFactory appDomainFactory; private final ConverterFactory converterFactory; private final KnowledgeCenterService knowledgeCenterService; + private final DomainDivisionService domainDivisionService; + private final boolean isEnableDomainDivision; + + public AppBuilderAppServiceImpl(AppTemplateFactory templateFactory, + UploadedFileManageService uploadedFileManageService, AppTaskService appTaskService, + AppVersionService appVersionService, AppDomainService appDomainService, AppFactory appDomainFactory, + ConverterFactory converterFactory, KnowledgeCenterService knowledgeCenterService, + DomainDivisionService domainDivisionService, + @Value("${domain-division.isEnable}") boolean isEnableDomainDivision) { + this.templateFactory = templateFactory; + this.uploadedFileManageService = uploadedFileManageService; + this.appTaskService = appTaskService; + this.appVersionService = appVersionService; + this.appDomainService = appDomainService; + this.appDomainFactory = appDomainFactory; + this.converterFactory = converterFactory; + this.knowledgeCenterService = knowledgeCenterService; + this.domainDivisionService = domainDivisionService; + this.isEnableDomainDivision = isEnableDomainDivision; + } @Override @Fitable(id = "default") @@ -129,6 +149,9 @@ public Rsp publish(AppBuilderAppDto appDto, OperationContext cont if (appVersion.isPublished()) { throw new AippException(AippErrCode.APP_HAS_PUBLISHED); } + if (this.isEnableDomainDivision) { + appDto.setUserGroupId(this.domainDivisionService.getUserGroupId()); + } appVersion.publish(new PublishContext(appDto, contextOf)); return Rsp.ok(AippCreateDto.builder() .aippId(appVersion.getData().getAppSuiteId()) @@ -201,7 +224,9 @@ public Rsp> list(AppQueryCondition con if (cond == null) { cond = new AppQueryCondition(); } - cond.setCreateBy(context.getOperator()); + if (this.isEnableDomainDivision) { + cond.setUserGroupId(this.domainDivisionService.getUserGroupId()); + } RangedResultSet result = this.appVersionService.pageListByTenantId(cond, context.getTenantId(), offset, limit); List metaDtoList = result.getResults() diff --git a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/service/impl/AppBuilderFormServiceImpl.java b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/service/impl/AppBuilderFormServiceImpl.java index e990c05cb6..86bce7d2ee 100644 --- a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/service/impl/AppBuilderFormServiceImpl.java +++ b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/service/impl/AppBuilderFormServiceImpl.java @@ -8,6 +8,7 @@ import static modelengine.fitframework.util.ObjectUtils.cast; +import modelengine.fit.jade.aipp.domain.division.service.DomainDivisionService; import modelengine.fit.jane.common.entity.OperationContext; import modelengine.fit.jane.common.response.Rsp; import modelengine.fit.jane.task.util.Entities; @@ -61,14 +62,19 @@ public class AppBuilderFormServiceImpl implements AppBuilderFormService { private final AippFormCreateConfig aippFormCreateConfig; private final UploadedFileManageService uploadedFileManageService; private final List excludeNames; + private final DomainDivisionService domainDivisionService; + private final boolean isEnableDomainDivision; public AppBuilderFormServiceImpl(AppBuilderFormRepository formRepository, AippFormCreateConfig aippFormCreateConfig, - UploadedFileManageService uploadedFileManageService, - @Value("${app-engine.form.exclude-names}") List excludeNames) { + UploadedFileManageService uploadedFileManageService, DomainDivisionService domainDivisionService, + @Value("${app-engine.form.exclude-names}") List excludeNames, + @Value("${domain-division.isEnable}") boolean isEnableDomainDivision) { this.formRepository = formRepository; this.aippFormCreateConfig = aippFormCreateConfig; this.uploadedFileManageService = uploadedFileManageService; + this.domainDivisionService = domainDivisionService; this.excludeNames = excludeNames; + this.isEnableDomainDivision = isEnableDomainDivision; } @Override @@ -109,6 +115,7 @@ public AppBuilderFormDto create(AppBuilderFormDto dto, OperationContext context) .updateAt(LocalDateTime.now()) .version(VERSION) .formSuiteId(Entities.generateId()) + .userGroupId(this.isEnableDomainDivision ? this.domainDivisionService.getUserGroupId() : null) .build(); this.updateFile(dto.getAppearance(), IRREMOVABLE); this.formRepository.insertOne(appBuilderForm); @@ -161,6 +168,7 @@ public RangedResultSet query(long pageNum, int pageSize, Stri .limit(pageSize) .name(name) .excludeNames(excludeNames) + .userGroupId(this.isEnableDomainDivision ? this.domainDivisionService.getUserGroupId() : null) .build(); long total = this.formRepository.countWithCondition(cond); List result = this.formRepository.selectWithCondition(cond) diff --git a/app-builder/plugins/aipp-plugin/src/main/resources/i18n/messages_en.properties b/app-builder/plugins/aipp-plugin/src/main/resources/i18n/messages_en.properties index 47e9ddb33e..2401a43b40 100644 --- a/app-builder/plugins/aipp-plugin/src/main/resources/i18n/messages_en.properties +++ b/app-builder/plugins/aipp-plugin/src/main/resources/i18n/messages_en.properties @@ -141,4 +141,7 @@ 90002137=System error. Failed to obtain form configuration information. Please contact the administrator. 90002138=Failed to run. The form does not exist or has been deleted. 90002139=Failed to call the large model service, {0}. -90002140=Failed to generate {0} by model, please change default model. reason: {1}. \ No newline at end of file +90002140=Failed to generate {0} by model, please change default model. reason: {1}. +90002141=No permission to operate this app. +90002142=Form not exist. +90002143=No permission to operate this form. \ No newline at end of file diff --git a/app-builder/plugins/aipp-plugin/src/main/resources/i18n/messages_zh.properties b/app-builder/plugins/aipp-plugin/src/main/resources/i18n/messages_zh.properties index 3c51155780..15c355f829 100644 --- a/app-builder/plugins/aipp-plugin/src/main/resources/i18n/messages_zh.properties +++ b/app-builder/plugins/aipp-plugin/src/main/resources/i18n/messages_zh.properties @@ -142,4 +142,7 @@ 90002137=系统错误,获取表单配置信息失败,请联系管理员。 90002138=运行失败,表单不存在或已经被删除。 90002139=调用大模型服务失败,{0}。 -90002140=大模型生成{0}失败,请尝试更换默认模型,失败原因:{1}。 \ No newline at end of file +90002140=大模型生成{0}失败,请尝试更换默认模型,失败原因:{1}。 +90002141=没有权限操作该应用。 +90002142=表单不存在。 +90002143=没有权限操作该表单。 \ No newline at end of file diff --git a/app-builder/plugins/aipp-plugin/src/main/resources/mapper/AppBuilderAppMapper.xml b/app-builder/plugins/aipp-plugin/src/main/resources/mapper/AppBuilderAppMapper.xml index f5e02df5f8..9bf78b0b85 100644 --- a/app-builder/plugins/aipp-plugin/src/main/resources/mapper/AppBuilderAppMapper.xml +++ b/app-builder/plugins/aipp-plugin/src/main/resources/mapper/AppBuilderAppMapper.xml @@ -24,10 +24,12 @@ + - id, name, app_id, app_suite_id, config_id, flow_graph_id, tenant_id, type, version, attributes, path, state, app_built_type, app_category, create_by, create_at, update_by, update_at, is_active, status, unique_name, publish_at, app_type + id + , name, app_id, app_suite_id, config_id, flow_graph_id, tenant_id, type, version, attributes, path, state, app_built_type, app_category, create_by, create_at, update_by, update_at, is_active, status, unique_name, publish_at, app_type, user_group_id @@ -121,8 +123,8 @@ #{excludeName} - - and create_by = #{cond.createBy} + + and (user_group_id = #{cond.userGroupId} or user_group_id = '*') ORDER BY "name", update_at DESC @@ -200,8 +202,8 @@ and app_category = #{cond.appCategory} - - and create_by = #{cond.createBy} + + and (user_group_id = #{cond.userGroupId} or user_group_id = '*') ) as latest_records WHERE ; @@ -211,7 +213,7 @@ ) values (#{id}, #{name}, #{appId}, #{appSuiteId}, #{configId}, #{flowGraphId}, #{tenantId}, #{type}, #{version}, #{attributes}::jsonb, - #{path}, #{state}, #{appBuiltType}, #{appCategory}, #{createBy}, #{createAt}, #{updateBy}, #{updateAt}, #{isActive}, #{status}, #{uniqueName}, #{publishAt}, #{appType}) + #{path}, #{state}, #{appBuiltType}, #{appCategory}, #{createBy}, #{createAt}, #{updateBy}, #{updateAt}, #{isActive}, #{status}, #{uniqueName}, #{publishAt}, #{appType}, #{userGroupId}) diff --git a/app-builder/plugins/aipp-plugin/src/main/resources/mapper/AppBuilderFormMapper.xml b/app-builder/plugins/aipp-plugin/src/main/resources/mapper/AppBuilderFormMapper.xml index 3c5d8f8fc5..2a16a11ba1 100644 --- a/app-builder/plugins/aipp-plugin/src/main/resources/mapper/AppBuilderFormMapper.xml +++ b/app-builder/plugins/aipp-plugin/src/main/resources/mapper/AppBuilderFormMapper.xml @@ -13,10 +13,11 @@ + - id, name, tenant_id, appearance, type, create_by, create_at, update_by, update_at, version, form_suite_id + id, name, tenant_id, appearance, type, create_by, create_at, update_by, update_at, version, form_suite_id, user_group_id @@ -113,6 +118,9 @@ and i."app_category" ilike '%\' || #{appCategory} || '%' ESCAPE '\' + + and (i."user_group_id" = #{userGroupId} or i."user_group_id" = '*') + diff --git a/store/plugins/store-repository-postgresql/src/main/resources/mapper/PluginMapper.xml b/store/plugins/store-repository-postgresql/src/main/resources/mapper/PluginMapper.xml index c601065d51..d878f584b6 100644 --- a/store/plugins/store-repository-postgresql/src/main/resources/mapper/PluginMapper.xml +++ b/store/plugins/store-repository-postgresql/src/main/resources/mapper/PluginMapper.xml @@ -14,6 +14,7 @@ + insert into store_plugin @@ -26,6 +27,7 @@ "deploy_status", "source", "icon", + "user_group_id", values @@ -37,6 +39,7 @@ #{deployStatus}, #{source}, #{icon}, + #{userGroupId}, @@ -84,16 +87,16 @@ - select count("plugin_id") from "store_plugin" where "deploy_status" = #{deployStatus} @@ -108,13 +111,25 @@ + + and (i."is_builtin" = true or i."user_group_id" = #{userGroupId} or i."user_group_id" = '*') + + + and (i."is_builtin" = false and i."user_group_id" = #{userGroupId} or i."user_group_id" = '*') + + + and i."is_builtin" = #{isBuiltin} + + + and (i."user_group_id" = #{userGroupId} or i."user_group_id" = '*') + and (i."is_builtin" = true or i."creator" ilike '%\' || #{creator} || '%' ESCAPE '\') diff --git a/store/plugins/store-repository-postgresql/src/main/resources/mapper/PluginToolMapper.xml b/store/plugins/store-repository-postgresql/src/main/resources/mapper/PluginToolMapper.xml index 901dae1c32..d76eb05321 100644 --- a/store/plugins/store-repository-postgresql/src/main/resources/mapper/PluginToolMapper.xml +++ b/store/plugins/store-repository-postgresql/src/main/resources/mapper/PluginToolMapper.xml @@ -14,6 +14,7 @@ + insert into store_plugin_tool @@ -26,6 +27,7 @@ "plugin_id", "source", "icon", + "user_group_id", "tool_unique_name", values @@ -38,6 +40,7 @@ #{pluginId}, #{source}, #{icon}, + #{userGroupId}, #{toolUniqueName}, @@ -53,6 +56,7 @@ "plugin_id", "source", "icon", + "user_group_id", "tool_unique_name", values @@ -65,6 +69,7 @@ #{pluginToolDo.pluginId}, #{pluginToolDo.source}, #{pluginToolDo.icon}, + #{pluginToolDo.userGroupId}, #{pluginToolDo.toolUniqueName}, @@ -120,7 +125,8 @@