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..8a080e6c22 --- /dev/null +++ b/app-builder/plugins/aipp-domain-division/src/main/java/modelengine/fit/jade/aipp/domain/division/impl/DomainDivisionServiceImpl.java @@ -0,0 +1,58 @@ +/* + * 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(); + return toBeVerifiedIds.stream().allMatch(toBeVerifiedId -> StringUtils.equals(toBeVerifiedId, "*") || + StringUtils.equals(toBeVerifiedId, currUserGroupId)); + } +} 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 6d7c73536d..eb3f00779a 100644 --- a/app-builder/plugins/aipp-plugin/pom.xml +++ b/app-builder/plugins/aipp-plugin/pom.xml @@ -239,6 +239,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..a6438e251e 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,26 @@ 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, "没有权限操作该表单。"), + + /** + * 应用未打开游客模式。 + */ + APP_NOT_IN_GUEST_MODE(90002144, "应用未打开游客模式。"), + /** * 应用模板不存在。 */ 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 b536f4c8cf..3191333a07 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/AppBuilderGuestController.java b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/controller/AppBuilderGuestController.java index d0334563e4..7f7fb30df6 100644 --- a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/controller/AppBuilderGuestController.java +++ b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/controller/AppBuilderGuestController.java @@ -27,6 +27,7 @@ import modelengine.fit.jober.aipp.common.exception.AippException; import modelengine.fit.jober.aipp.common.exception.AippParamException; import modelengine.fit.jober.aipp.common.exception.AippTaskNotFoundException; +import modelengine.fit.jober.aipp.constants.AippConst; import modelengine.fit.jober.aipp.dto.AippCreateDto; import modelengine.fit.jober.aipp.dto.AppBuilderAppDto; import modelengine.fit.jober.aipp.dto.AppBuilderPromptCategoryDto; @@ -38,14 +39,10 @@ import modelengine.fit.jober.aipp.dto.chat.QueryChatRequest; import modelengine.fit.jober.aipp.dto.chat.QueryChatRspDto; import modelengine.fit.jober.aipp.genericable.AppBuilderAppService; -import modelengine.fit.jober.aipp.service.AippChatService; -import modelengine.fit.jober.aipp.service.AippLogService; -import modelengine.fit.jober.aipp.service.AippRunTimeService; -import modelengine.fit.jober.aipp.service.AppBuilderPromptService; -import modelengine.fit.jober.aipp.service.AppChatService; -import modelengine.fit.jober.aipp.service.FileService; +import modelengine.fit.jober.aipp.service.*; import modelengine.fit.jober.aipp.util.AippFileUtils; import modelengine.fit.jober.aipp.util.ConvertUtils; +import modelengine.fit.jober.aipp.validation.GuestValidator; import modelengine.fit.jober.common.RangedResultSet; import modelengine.fitframework.annotation.Component; import modelengine.fitframework.annotation.Property; @@ -84,6 +81,7 @@ public class AppBuilderGuestController extends AbstractController { private final AppBuilderRecommendService recommendService; private final FileService fileService; private final AippChatService aippChatService; + private final GuestValidator guestValidator; /** * 用限校验认的证器对象 {@link Authenticator}, 应用通用服务 {@link AppBuilderAppService},对话服务 {@link AppChatService},实例历史记录服务 @@ -102,12 +100,13 @@ public class AppBuilderGuestController extends AbstractController { * @param recommendService 表示猜你想问服务的 {@link AppBuilderRecommendService}。 * @param fileService 表示文件服务的 {@link FileService}。 * @param aippChatService 表示应用聊天服务的 {@link AippChatService}。 + * @param guestValidator 表示游客模式的校验器的 {@link GuestValidator}。 */ public AppBuilderGuestController(Authenticator authenticator, AppBuilderAppService appGenericable, AppChatService appChatService, AippLogService aippLogService, AppBuilderPromptService appBuilderPromptService, AippRunTimeService aippRunTimeService, UserFeedbackService userFeedbackService, AppBuilderRecommendService recommendService, FileService fileService, - AippChatService aippChatService) { + AippChatService aippChatService, GuestValidator guestValidator) { super(authenticator); this.appGenericable = appGenericable; this.appChatService = appChatService; @@ -118,6 +117,7 @@ public AppBuilderGuestController(Authenticator authenticator, AppBuilderAppServi this.recommendService = recommendService; this.fileService = fileService; this.aippChatService = aippChatService; + this.guestValidator = guestValidator; } /** @@ -158,6 +158,8 @@ public Rsp queryByPath(HttpClassicServerRequest httpRequest, @ public Choir chat(HttpClassicServerRequest httpRequest, @PathVariable("tenant_id") String tenantId, @RequestBody CreateAppChatRequest body) throws AippTaskNotFoundException { this.validateChat(httpRequest, body); + this.guestValidator.validateByAppId(body.getAppId()); + body.getContext().setGuest(true); return this.appChatService.chat(body, this.contextOf(httpRequest, tenantId), false); } @@ -175,6 +177,7 @@ public Choir chat(HttpClassicServerRequest httpRequest, @PathVariable("t public Rsp> queryChatRecentChatLog(HttpClassicServerRequest httpRequest, @PathVariable("tenant_id") String tenantId, @PathVariable("app_id") String appId, @PathVariable("chat_id") String chatId) { + this.guestValidator.validateByAppId(appId); return Rsp.ok(this.aippLogService.queryChatRecentChatLog(chatId, appId, this.contextOf(httpRequest, tenantId))); } @@ -189,6 +192,7 @@ public Rsp> queryChatRecentChatLog(HttpClassicServerReq @GetMapping(path = "/{tenant_id}/app/{app_id}/latest_published", description = "获取 app 最新发布版本信息") public Rsp latestPublished(HttpClassicServerRequest httpRequest, @PathVariable("tenant_id") String tenantId, @PathVariable("app_id") String appId) { + this.guestValidator.validateByAppId(appId); return Rsp.ok(ConvertUtils.toAippCreateDto(this.appGenericable.queryLatestPublished(appId, this.contextOf(httpRequest, tenantId)))); } @@ -204,6 +208,7 @@ public Rsp latestPublished(HttpClassicServerRequest httpRequest, @GetMapping(value = "/{tenant_id}/{app_id}", description = "查询 app ") public Rsp query(HttpClassicServerRequest httpRequest, @PathVariable("tenant_id") String tenantId, @PathVariable("app_id") String appId) { + this.guestValidator.validateByAppId(appId); return Rsp.ok(this.appGenericable.query(appId, this.contextOf(httpRequest, tenantId))); } @@ -220,6 +225,7 @@ public Rsp query(HttpClassicServerRequest httpRequest, @PathVa public Rsp> listCategories(HttpClassicServerRequest httpRequest, @PathVariable("tenant_id") String tenantId, @PathVariable("app_id") String appId, @RequestParam(value = "isDebug", defaultValue = "true", required = false) boolean isDebug) { + this.guestValidator.validateByAppId(appId); return this.appBuilderPromptService.listPromptCategories(appId, this.contextOf(httpRequest, tenantId), isDebug); } @@ -238,6 +244,7 @@ public Rsp queryInspirations(HttpClassicServerRequest httpR @PathVariable("tenant_id") String tenantId, @PathVariable("app_id") String appId, @PathVariable("category_id") String categoryId, @RequestParam(value = "isDebug", defaultValue = "true", required = false) boolean isDebug) { + this.guestValidator.validateByAppId(appId); return this.appBuilderPromptService.queryInspirations(appId, categoryId, this.contextOf(httpRequest, tenantId), @@ -259,6 +266,7 @@ public Rsp queryInspirations(HttpClassicServerRequest httpR 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) { + this.guestValidator.validateByAppId(appId); this.appBuilderPromptService.addCustomInspiration(appId, parentId, inspirationDto, @@ -284,6 +292,7 @@ public Rsp updateMyInspiration(HttpClassicServerRequest httpRequest, @SpanAttr("app_id") @PathVariable("app_id") String appId, @SpanAttr("inspiration_id") @PathVariable("inspiration_id") String inspirationId, @RequestBody AppBuilderPromptDto.AppBuilderInspirationDto inspirationDto) { + this.guestValidator.validateByAppId(appId); this.appBuilderPromptService.updateCustomInspiration(appId, categoryId, inspirationId, @@ -308,6 +317,7 @@ public Rsp deleteMyInspiration(HttpClassicServerRequest httpRequest, @PathVariable("tenant_id") String tenantId, @PathVariable("category_id") String categoryId, @SpanAttr("app_id") @PathVariable("app_id") String appId, @SpanAttr("inspiration_id") @PathVariable("inspiration_id") String inspirationId) { + this.guestValidator.validateByAppId(appId); this.appBuilderPromptService.deleteCustomInspiration(appId, categoryId, inspirationId, @@ -330,6 +340,7 @@ public Rsp terminateAippInstance(HttpClassicServerRequest httpRequest, @PathVariable("tenant_id") String tenantId, @PathVariable("instance_id") @SpanAttr("instance_id") String instanceId, @RequestBody Map msgArgs) { + this.guestValidator.validateByInstanceId(instanceId); return Rsp.ok(this.aippRunTimeService.terminateInstance(instanceId, msgArgs, this.contextOf(httpRequest, tenantId))); @@ -352,6 +363,7 @@ public Rsp terminateAippInstance(HttpClassicServerRequest httpRequest, @PathVariable("tenant_id") String tenantId, @PathVariable("instance_id") @SpanAttr("instance_id") String instanceId, @RequestBody Map msgArgs, @PathVariable("log_id") Long logId) { + this.guestValidator.validateByInstanceId(instanceId); return Rsp.ok(this.aippRunTimeService.terminateInstance(instanceId, msgArgs, logId, @@ -366,7 +378,8 @@ public Rsp terminateAippInstance(HttpClassicServerRequest httpRequest, */ @CarverSpan(value = "operation.aippLog.deleteHistory") @DeleteMapping(path = "/{app_id}/log/logs", description = "删除指定的应用对话记录") - public Rsp deleteLogs(@RequestBody List logIds) { + public Rsp deleteLogs(@RequestBody List logIds, @PathVariable("app_id") String appId) { + this.guestValidator.validateByAppId(appId); Span.current().setAttribute("logIds", logIds.toString()); this.aippLogService.deleteLogs(logIds); return Rsp.ok(); @@ -391,6 +404,7 @@ public void createUserFeedback(@RequestBody UserFeedbackDto userFeedbackDto) { @PatchMapping("/feedback/{instanceId}") public void updateUserFeedback(@PathVariable("instanceId") String instanceId, @RequestBody UserFeedbackDto userFeedbackDto) { + this.guestValidator.validateByInstanceId(instanceId); this.userFeedbackService.updateOne(instanceId, userFeedbackDto); } @@ -401,6 +415,7 @@ public void updateUserFeedback(@PathVariable("instanceId") String instanceId, */ @DeleteMapping("/feedback/{instanceId}") public void deleteByLogId(@PathVariable("instanceId") String instanceId) { + this.guestValidator.validateByInstanceId(instanceId); this.userFeedbackService.deleteByLogId(instanceId); } @@ -422,6 +437,7 @@ public List getAllUserFeedbacks() { */ @GetMapping("/feedback/{instanceId}") public UserFeedbackDto getAllAnswerByInstanceId(@PathVariable("instanceId") String instanceId) { + this.guestValidator.validateByInstanceId(instanceId); return this.userFeedbackService.getUserFeedbackByInstanceId(instanceId); } @@ -440,6 +456,8 @@ public UserFeedbackDto getAllAnswerByInstanceId(@PathVariable("instanceId") Stri public Choir restartChat(HttpClassicServerRequest httpRequest, @PathVariable("tenant_id") String tenantId, @PathVariable("current_instance_id") @SpanAttr("current_instance_id") String currentInstanceId, @RequestBody Map additionalContext) { + this.guestValidator.validateByInstanceId(currentInstanceId); + additionalContext.put(AippConst.CONTEXT_IS_GUEST, true); return this.appChatService.restartChat(currentInstanceId, additionalContext, this.contextOf(httpRequest, tenantId)); @@ -472,6 +490,7 @@ public Rsp> queryRecommends(HttpClassicServerRequest request, public Rsp> batchUploadFile(HttpClassicServerRequest httpRequest, @PathVariable("tenant_id") String tenantId, @RequestParam(value = "app_id", required = false) String appId, PartitionedEntity receivedFiles) { + this.guestValidator.validateByAppId(appId); OperationContext context = this.contextOf(httpRequest, tenantId); List fileRspDtos = AippFileUtils.getFileEntity(receivedFiles).stream().map(fileEntity -> { try { @@ -497,6 +516,7 @@ public Rsp> batchUploadFile(HttpClassicServerRequest httpReques public Rsp deleteChat(HttpClassicServerRequest httpRequest, @PathVariable("tenant_id") String tenantId, @RequestParam(value = "app_id", required = false) String appId, @RequestBody(value = "chat_id", required = false) @SpanAttr("chat_id") String chatIds) { + this.guestValidator.validateByAppId(appId); this.aippChatService.deleteChat(chatIds, appId, this.contextOf(httpRequest, tenantId)); return Rsp.ok(); } @@ -534,11 +554,12 @@ public Choir resumeAndUpdateAippInstance(HttpClassicServerRequest httpRe @RequestBean ResumeAippDto resumeAippDto, @Property(description = "用户填写的表单信息", example = "用户选择的大模型信息") @RequestBody Map formArgs) { + this.guestValidator.validateByInstanceId(resumeAippDto.getInstanceId()); return this.aippRunTimeService.resumeAndUpdateAippInstance(resumeAippDto.getInstanceId(), formArgs, resumeAippDto.getLogId(), this.contextOf(httpRequest, resumeAippDto.getTenantId()), - resumeAippDto.isDebug()); + resumeAippDto.isDebug(), true); } /** @@ -554,6 +575,7 @@ public Choir resumeAndUpdateAippInstance(HttpClassicServerRequest httpRe @DeleteMapping(path = "/{tenant_id}/log/app/{app_id}", description = "清除appId查询实例的全部历史记录") public Rsp deleteInstanceLog(HttpClassicServerRequest httpRequest, @PathVariable("tenant_id") String tenantId, @PathVariable("app_id") @SpanAttr("app_id") String appId, @RequestParam("type") String type) { + this.guestValidator.validateByAppId(appId); this.aippLogService.deleteAippInstLog(appId, type, this.contextOf(httpRequest, tenantId)); return Rsp.ok(); } 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/AppRunTimeController.java b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/controller/AppRunTimeController.java index 1df25c5032..02a2fd055e 100644 --- a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/controller/AppRunTimeController.java +++ b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/controller/AppRunTimeController.java @@ -98,7 +98,7 @@ public Choir resumeAndUpdateAippInstance(HttpClassicServerRequest httpRe formArgs, resumeAippDto.getLogId(), this.contextOf(httpRequest, resumeAippDto.getTenantId()), - resumeAippDto.isDebug()); + resumeAippDto.isDebug(), false); } /** 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/AppVersion.java b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/domains/appversion/AppVersion.java index aa73ae1aa0..112c38019b 100644 --- a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/domains/appversion/AppVersion.java +++ b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/domains/appversion/AppVersion.java @@ -18,6 +18,7 @@ import static modelengine.fit.jober.aipp.constants.AippConst.ATTR_APP_IS_UPDATE; import static modelengine.fit.jober.aipp.constants.AippConst.ATTR_META_STATUS_KEY; import static modelengine.fit.jober.aipp.constants.AippConst.BS_AIPP_QUESTION_KEY; +import static modelengine.fit.jober.aipp.constants.AippConst.CONTEXT_IS_GUEST; import static modelengine.fit.jober.aipp.constants.AippConst.RESTART_MODE; import static modelengine.fit.jober.aipp.enums.AippMetaStatusEnum.ACTIVE; import static modelengine.fit.jober.aipp.enums.AippTypeEnum.NORMAL; @@ -604,6 +605,10 @@ public void restart(AppTaskInstance instance, Map restartParams, runContext.setUserContext(mergedRestartParams); runContext.putAllToBusiness(mergedRestartParams); runContext.setQuestion(this.getQuestion(appLog.getLogData())); + runContext.setIsGuest(ObjectUtils.cast(restartParams.getOrDefault(CONTEXT_IS_GUEST, false))); + AppVersion appVersion = this.appVersionRepository.selectById(mostRecentRsp.getAppId()) + .orElseThrow(() -> new AippException(APP_NOT_FOUND_WHEN_CHAT)); + runContext.setAppCreateBy(appVersion.getData().getCreateBy()); if (chatList.size() == 2) { runContext.setAtChatId(chatList.get(1).getChatId()); } @@ -697,7 +702,7 @@ public boolean isApp() { * @return true/false. */ public boolean isUpdated() { - return ObjectUtils.cast(this.attributes.getOrDefault(AippConst.ATTR_APP_IS_UPDATE, true)); + return ObjectUtils.cast(this.attributes.getOrDefault(ATTR_APP_IS_UPDATE, true)); } /** @@ -974,7 +979,7 @@ public boolean isEqual(AppVersion appVersion) { */ public void putAttributes(Map attributes) { this.attributes.putAll(attributes); - this.attributes.put(AippConst.ATTR_APP_IS_UPDATE, true); + this.attributes.put(ATTR_APP_IS_UPDATE, true); } /** 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..52af22a12b 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 @@ -141,6 +146,8 @@ public Choir run(CreateAppChatRequest request, OperationContext context) AppVersion appVersion = this.retrieval(request.getAppId()); RunContext runContext = RunContext.from(request, context); appVersion.validate(runContext, false); + runContext.setIsGuest(request.getContext().isGuest()); + runContext.setAppCreateBy(appVersion.getData().getCreateBy()); Locale locale = LocaleUtil.getLocale(); return Choir.create(emitter -> { ChatSession session = new ChatSession<>(emitter, request.getAppId(), false, locale); @@ -155,6 +162,8 @@ public Choir debug(CreateAppChatRequest request, OperationContext contex appVersion.updateFlows(context); RunContext runContext = RunContext.from(request, context); appVersion.validate(runContext, true); + runContext.setIsGuest(request.getContext().isGuest()); + runContext.setAppCreateBy(appVersion.getData().getCreateBy()); Locale locale = LocaleUtil.getLocale(); return Choir.create(emitter -> { ChatSession session = new ChatSession<>(emitter, request.getAppId(), true, locale); @@ -210,6 +219,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 +257,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/domains/business/RunContext.java b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/domains/business/RunContext.java index f9b9887158..cc537e0577 100644 --- a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/domains/business/RunContext.java +++ b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/domains/business/RunContext.java @@ -17,6 +17,8 @@ import static modelengine.fit.jober.aipp.constants.AippConst.BS_CHAT_ID; import static modelengine.fit.jober.aipp.constants.AippConst.BS_HTTP_CONTEXT_KEY; import static modelengine.fit.jober.aipp.constants.AippConst.BS_META_VERSION_ID_KEY; +import static modelengine.fit.jober.aipp.constants.AippConst.CONTEXT_APP_CREATE_BY; +import static modelengine.fit.jober.aipp.constants.AippConst.CONTEXT_IS_GUEST; import static modelengine.fit.jober.aipp.constants.AippConst.CONTEXT_USER_ID; import static modelengine.fit.jober.aipp.constants.AippConst.PARENT_CALLBACK_ID; import static modelengine.fit.jober.aipp.constants.AippConst.PARENT_INSTANCE_ID; @@ -175,13 +177,31 @@ public void setAppSuiteId(String appSuiteId) { this.businessData.put(BS_AIPP_ID_KEY, appSuiteId); } + /** + * 设置是否是游客模式。 + * + * @param isGuest 表示是否是游客模式。 + */ + public void setIsGuest(boolean isGuest) { + this.businessData.put(CONTEXT_IS_GUEST, isGuest); + } + + /** + * 设置应用创建者。 + * + * @param appCreateBy 表示应用创建者 + */ + public void setAppCreateBy(String appCreateBy) { + this.businessData.put(CONTEXT_APP_CREATE_BY, appCreateBy); + } + /** * 获取应用id. * * @return 应用id. */ public String getAppSuiteId() { - return ObjectUtils.cast(this.businessData.get(AippConst.ATTR_AIPP_TYPE_KEY)); + return ObjectUtils.cast(this.businessData.get(ATTR_AIPP_TYPE_KEY)); } /** @@ -235,7 +255,7 @@ public void setAippType(String aippType) { * @return aipp类型. */ public String getAippType() { - return ObjectUtils.cast(this.businessData.get(AippConst.ATTR_AIPP_TYPE_KEY)); + return ObjectUtils.cast(this.businessData.get(ATTR_AIPP_TYPE_KEY)); } /** @@ -272,7 +292,7 @@ public void setStartTime(Object startTime) { * @param restartMode restart模式. */ public void setRestartMode(String restartMode) { - this.businessData.put(AippConst.RESTART_MODE, restartMode); + this.businessData.put(RESTART_MODE, restartMode); } /** @@ -290,7 +310,7 @@ public boolean isOverWriteMode() { * @param question 问题. */ public void setQuestion(String question) { - this.businessData.put(AippConst.BS_AIPP_QUESTION_KEY, question); + this.businessData.put(BS_AIPP_QUESTION_KEY, question); } /** @@ -299,7 +319,7 @@ public void setQuestion(String question) { * @return {@link String} 对象 */ public String getRestartMode() { - return ObjectUtils.cast(this.businessData.get(AippConst.RESTART_MODE)); + return ObjectUtils.cast(this.businessData.get(RESTART_MODE)); } /** diff --git a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/domains/task/AppTask.java b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/domains/task/AppTask.java index 67d6ac2b53..1f3daadd79 100644 --- a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/domains/task/AppTask.java +++ b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/domains/task/AppTask.java @@ -120,18 +120,18 @@ public class AppTask implements AppTaskRunnable { } /** - * 作为实体. + * 作为实体。 * - * @return {@link TaskDomainEntity} 对象. + * @return {@link TaskDomainEntity} 对象。 */ public static TaskDomainEntity asEntity() { return new TaskDomainEntity(); } /** - * 作为创建参数. + * 作为创建参数。 * - * @return {@link TaskDomainEntity} 对象 + * @return {@link TaskDomainEntity} 对象。 */ public static TaskDomainEntity asCreateEntity() { TaskDomainEntity entity = new TaskDomainEntity(); @@ -144,10 +144,10 @@ public static TaskDomainEntity asCreateEntity() { } /** - * 作为修改参数. + * 作为修改参数。 * - * @param taskId 任务唯一标识. - * @return {@link TaskDomainEntity} 对象. + * @param taskId 任务唯一标识。 + * @return {@link TaskDomainEntity} 对象。 */ public static TaskDomainEntity asUpdateEntity(String taskId) { TaskDomainEntity entity = new TaskDomainEntity(); @@ -156,21 +156,21 @@ public static TaskDomainEntity asUpdateEntity(String taskId) { } /** - * 作为查询参数. + * 作为查询参数。 * - * @param offset 偏移量. - * @param limit 限制. - * @return {@link TaskQueryEntity} 对象. + * @param offset 偏移量。 + * @param limit 限制。 + * @return {@link TaskQueryEntity} 对象。 */ public static TaskQueryEntity asQueryEntity(long offset, int limit) { return new TaskQueryEntity(offset, limit); } /** - * 将entity转换为特定的Entity类型对象. + * 将entity转换为特定的Entity类型对象。 * - * @param 代表Entity的类型. - * @return 特定的 {@link TaskEntity} 类型. + * @param 代表Entity的类型。 + * @return 特定的 {@link TaskEntity} 类型。 */ public > T getEntity() { return ObjectUtils.cast(this.entity); @@ -312,9 +312,9 @@ private void insertLog(String logType, AippLogData logData, RunContext runContex } /** - * 获取表单配置项集合. + * 获取表单配置项集合。 * - * @return {@link List}{@code <}{@link AppBuilderFormProperty}{@code >} 集合. + * @return {@link List}{@code <}{@link AppBuilderFormProperty}{@code >} 集合。 */ public List getFormProperties() { return UsefulUtils.lazyGet(this.formProperties, @@ -346,9 +346,9 @@ private List> getMemoryConfigs(String flowDefinitionId, Oper } /** - * 是否处于草稿态. + * 是否处于草稿态。 * - * @return true/false. + * @return true/false。 */ public boolean isDraft() { String baseLineVersion = this.entity.getBaseLineVersion(); @@ -357,47 +357,47 @@ public boolean isDraft() { } /** - * 是否是正常类型任务. + * 是否是正常类型任务。 * - * @return true/false. + * @return true/false。 */ public boolean isNormal() { return StringUtils.equalsIgnoreCase(this.entity.getAippType(), NORMAL.name()); } /** - * 是否处于active状态. + * 是否处于active状态。 * - * @return true/false. + * @return true/false。 */ public boolean isActive() { return StringUtils.equals(AippMetaStatusEnum.ACTIVE.getCode(), this.entity.getStatus()); } /** - * 通过最新的版本判断是否是升级. + * 通过最新的版本判断是否是升级。 * - * @param newVersion 最新的版本号. - * @return true/false. + * @param newVersion 最新的版本号。 + * @return true/false。 */ public boolean isUpgrade(String newVersion) { return this.isActive() || !StringUtils.equals(newVersion, this.entity.getVersion()); } /** - * 判断任务是否属于某个app版本. + * 判断任务是否属于某个app版本。 * - * @param appId 应用版本id. - * @return true/false. + * @param appId 应用版本id。 + * @return true/false。 */ public boolean isBelongApp(String appId) { return StringUtils.equals(appId, this.entity.getAppId()); } /** - * 是否已发布. + * 是否已发布。 * - * @return true/false. + * @return true/false。 */ public boolean isPublished() { if (StringUtils.isBlank(this.entity.getAippType()) || StringUtils.isBlank(this.entity.getStatus())) { @@ -408,9 +408,9 @@ public boolean isPublished() { } /** - * 停止所有运行中的实例. + * 停止所有运行中的实例。 * - * @param context 操作人上下文信息. + * @param context 操作人上下文信息。 */ public void terminateAllInstances(OperationContext context) { String taskId = this.entity.getTaskId(); @@ -434,9 +434,9 @@ public void terminateAllInstances(OperationContext context) { } /** - * 清理资源. + * 清理资源。 * - * @param context 操作人上下文信息. + * @param context 操作人上下文信息。 */ public void cleanResource(OperationContext context) { String previewVersion = this.getEntity().getVersion(); @@ -457,10 +457,10 @@ public void cleanResource(OperationContext context) { } /** - * 获取所有实例. + * 获取所有实例。 * * @param context 操作人上下文信息. - * @return {@link AppTaskInstance} 列表. + * @return {@link AppTaskInstance} 列表。 */ public List getInstances(OperationContext context) { return UsefulUtils.lazyGet(this.instances, @@ -469,9 +469,9 @@ public List getInstances(OperationContext context) { } /** - * 删除task,同时删除相关数据. + * 删除task,同时删除相关数据。 * - * @param context 操作人上下文信息. + * @param context 操作人上下文信息。 */ public void delete(OperationContext context) { // 需要先删除instance,再删除task @@ -483,14 +483,16 @@ public void delete(OperationContext context) { } /** - * 恢复执行. + * 恢复执行。 * - * @param instanceId 实例id. - * @param logId 日志id. - * @param formArgs 表单参数. - * @param context 操作人上下文. + * @param instanceId 实例id。 + * @param logId 日志id。 + * @param formArgs 表单参数。 + * @param context 操作人上下文。 + * @param isGuest 是否是游客模式。 */ - public void resume(String instanceId, Long logId, Map formArgs, OperationContext context) { + public void resume(String instanceId, Long logId, Map formArgs, OperationContext context, + boolean isGuest) { AppTaskInstance instance = this.appTaskInstanceService.getInstanceById(instanceId, context) .orElseThrow(() -> new JobberException(ErrorCodes.UN_EXCEPTED_ERROR, StringUtils.format("App task instance[{0}] not found.", instanceId))); @@ -503,6 +505,8 @@ public void resume(String instanceId, Long logId, Map formArgs, runContext.setAippType(Optional.ofNullable(this.getEntity().getAippType()).orElse(NORMAL.name())); runContext.setTaskInstanceId(instanceId); runContext.setHttpContext(JsonUtils.toJsonString(context)); + runContext.setIsGuest(isGuest); + runContext.setAppCreateBy(this.getEntity().getCreator()); // 获取人工节点开始时间戳 [记录人工节点时延] runContext.setResumeDuration( diff --git a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/fitable/AippFlowSmartFormHandle.java b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/fitable/AippFlowSmartFormHandle.java index a24b3deed3..5e2f0e04a0 100644 --- a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/fitable/AippFlowSmartFormHandle.java +++ b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/fitable/AippFlowSmartFormHandle.java @@ -7,7 +7,8 @@ package modelengine.fit.jober.aipp.fitable; import static modelengine.fit.jober.aipp.constants.AippConst.BS_NODE_ID_KEY; -import static modelengine.fit.jober.aipp.constants.AippConst.BUSINESS_DATA_INTERNAL_KEY; +import static modelengine.fit.jober.aipp.constants.AippConst.CONTEXT_IS_GUEST; +import static modelengine.fit.waterflow.common.Constant.BUSINESS_DATA_INTERNAL_KEY; import modelengine.fit.jane.common.entity.OperationContext; import modelengine.fit.jade.waterflow.FlowInstanceService; @@ -111,6 +112,7 @@ public void handleSmartForm(List> contexts, String sheetId) formDataMap.put(BUSINESS_DATA_INTERNAL_KEY, businessData.get(BUSINESS_DATA_INTERNAL_KEY)); } formDataMap.put(BS_NODE_ID_KEY, nodeId); + formDataMap.put(CONTEXT_IS_GUEST, businessData.getOrDefault(CONTEXT_IS_GUEST, false)); String logId = this.insertFormLog(appVersion.getFormProperties(), sheetId, businessData, formDataMap); AppChatRsp appChatRsp = AppChatRsp.builder() .chatId(chatId) 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 083e9dfed9..5f28bb7eaa 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 @@ -7,7 +7,7 @@ package modelengine.fit.jober.aipp.fitable; import static modelengine.fit.jade.aipp.prompt.constant.Constant.PROMPT_METADATA_KEY; -import static modelengine.fit.jober.aipp.constants.AippConst.INST_STATUS_KEY; +import static modelengine.fit.jober.aipp.constants.AippConst.*; import static modelengine.fitframework.inspection.Validation.notNull; import modelengine.fel.core.chat.ChatMessage; @@ -24,6 +24,7 @@ import modelengine.fel.tool.mcp.client.McpClientFactory; import modelengine.fel.tool.mcp.entity.Tool; import modelengine.fel.tool.model.transfer.ToolData; +import modelengine.fit.jober.aipp.domains.appversion.service.AppVersionService; import modelengine.fit.jober.aipp.enums.MetaInstStatusEnum; import modelengine.fit.jober.aipp.util.McpUtils; import modelengine.fitframework.inspection.Validation; @@ -114,6 +115,7 @@ public class LlmComponent implements FlowableService { private final AppTaskInstanceService appTaskInstanceService; private final McpClientFactory mcpClientFactory; private final OutputFormatterChain formatterChain; + private final AppVersionService appVersionService; /** * 大模型节点构造器,内部通过提供的 agent 和 tool 构建智能体工作流。 @@ -139,7 +141,7 @@ public LlmComponent(FlowInstanceService flowInstanceService, PromptBuilderChain promptBuilderChain, AppTaskInstanceService appTaskInstanceService, OutputFormatterChain formatterChain, - McpClientFactory mcpClientFactory) { + McpClientFactory mcpClientFactory, AppVersionService appVersionService) { this.flowInstanceService = flowInstanceService; this.toolService = toolService; this.aippLogService = aippLogService; @@ -157,6 +159,7 @@ public LlmComponent(FlowInstanceService flowInstanceService, this.appTaskInstanceService = appTaskInstanceService; this.mcpClientFactory = notNull(mcpClientFactory, "The mcp client factory cannot be null."); this.formatterChain = formatterChain; + this.appVersionService = appVersionService; } /** @@ -437,6 +440,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<>(); + this.setExtensions(businessData, extensions); return ChatOption.custom() .model(accessInfo.get("serviceName")) .baseUrl(modelAccessInfo.getBaseUrl()) @@ -445,9 +450,20 @@ private ChatOption buildChatOptions(Map businessData) { .apiKey(modelAccessInfo.getAccessKey()) .temperature(ObjectUtils.cast(businessData.get("temperature"))) .tools(this.buildToolInfos(businessData)) + .extensions(extensions) .build(); } + private void setExtensions(Map businessData, Map extensions) { + if (ObjectUtils.cast(businessData.getOrDefault(CONTEXT_IS_GUEST, false))) { + String newUserId = this.appVersionService.getByAppId(ObjectUtils.cast(businessData.get(CONTEXT_APP_ID))) + .map(app -> app.getData().getCreateBy()).orElse(null); + extensions.put(AippConst.CONTEXT_USER_ID, businessData.getOrDefault(newUserId, null)); + } else { + extensions.put(AippConst.CONTEXT_USER_ID, businessData.getOrDefault(AippConst.CONTEXT_USER_ID, null)); + } + } + private List buildToolInfos(Map businessData) { List skillNameList = new ArrayList<>(ObjectUtils.cast(businessData.get("tools"))); if (businessData.containsKey("workflows")) { 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/AippRunTimeServiceImpl.java b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/service/impl/AippRunTimeServiceImpl.java index 1247463edb..91921f303d 100644 --- a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/service/impl/AippRunTimeServiceImpl.java +++ b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/service/impl/AippRunTimeServiceImpl.java @@ -364,7 +364,7 @@ private boolean checkParameter(String formId, String version) { @Override @Transactional public Choir resumeAndUpdateAippInstance(String instanceId, Map formArgs, Long logId, - OperationContext context, boolean isDebug) { + OperationContext context, boolean isDebug, boolean isGuest) { String taskId = this.appTaskInstanceService.getTaskId(instanceId); AppTask appTask = this.appTaskService.getTaskById(taskId, context) .orElseThrow(() -> new JobberException(ErrorCodes.UN_EXCEPTED_ERROR, @@ -374,7 +374,7 @@ public Choir resumeAndUpdateAippInstance(String instanceId, Map { this.appChatSessionService.addSession(instanceId, new ChatSession<>(emitter, appTask.getEntity().getAppId(), isDebug, locale)); - appTask.resume(instanceId, logId, formArgs, context); + appTask.resume(instanceId, logId, formArgs, context, isGuest); }); } 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 03d29a3df4..5bfdd065cb 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; @@ -56,6 +56,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; @@ -79,7 +80,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); @@ -94,8 +94,30 @@ public class AppBuilderAppServiceImpl private final AppFactory appDomainFactory; private final ConverterFactory converterFactory; private final KnowledgeCenterService knowledgeCenterService; + private final DomainDivisionService domainDivisionService; + private final boolean isEnableDomainDivision; private final AppBuilderAppRepository appBuilderAppRepository; + 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, + AppBuilderAppRepository appBuilderAppRepository) { + 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; + this.appBuilderAppRepository = appBuilderAppRepository; + } + @Override @Fitable(id = "default") public AppBuilderAppDto query(String appId, OperationContext context) { @@ -131,6 +153,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()) @@ -203,7 +228,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/java/modelengine/fit/jober/aipp/validation/GuestValidator.java b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/validation/GuestValidator.java new file mode 100644 index 0000000000..1196a01ccd --- /dev/null +++ b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/validation/GuestValidator.java @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * 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.validation; + +/** + * 游客模式校验器 + * + * @author 邬涨财 + * @since 2025/09/22 + */ +public interface GuestValidator { + /** + * 通过应用唯一标识校验游客模式。 + * + * @param appId 表示应用的唯一标识的 {@link String}。 + */ + void validateByAppId(String appId); + + /** + * 通过应用唯一实例标识校验游客模式。 + * + * @param instanceId 表示应用唯一实例标识的 {@link String}。 + */ + void validateByInstanceId(String instanceId); +} diff --git a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/validation/impl/GuestValidatorImpl.java b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/validation/impl/GuestValidatorImpl.java new file mode 100644 index 0000000000..3f58c710b5 --- /dev/null +++ b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/validation/impl/GuestValidatorImpl.java @@ -0,0 +1,58 @@ +/*--------------------------------------------------------------------------------------------- + * 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.validation.impl; + +import modelengine.fit.jober.aipp.common.exception.AippErrCode; +import modelengine.fit.jober.aipp.common.exception.AippException; +import modelengine.fit.jober.aipp.domains.task.AppTask; +import modelengine.fit.jober.aipp.domains.task.service.AppTaskService; +import modelengine.fit.jober.aipp.domains.taskinstance.service.AppTaskInstanceService; +import modelengine.fit.jober.aipp.dto.AppBuilderAppDto; +import modelengine.fit.jober.aipp.validation.GuestValidator; +import modelengine.fitframework.annotation.Component; +import modelengine.fitframework.util.ObjectUtils; + +import static modelengine.fit.jober.aipp.common.exception.AippErrCode.APP_NOT_IN_GUEST_MODE; + +/** + * 游客模式校验器实现类 + * + * @author 邬涨财 + * @since 2025/09/22 + */ +@Component +public class GuestValidatorImpl implements GuestValidator { + private final modelengine.fit.jober.aipp.genericable.AppBuilderAppService appGenericable; + private final AppTaskInstanceService appTaskInstanceService; + private final AppTaskService appTaskService; + + public GuestValidatorImpl(modelengine.fit.jober.aipp.genericable.AppBuilderAppService appGenericable, + AppTaskInstanceService appTaskInstanceService, + AppTaskService appTaskService) { + this.appGenericable = appGenericable; + this.appTaskInstanceService = appTaskInstanceService; + this.appTaskService = appTaskService; + } + + @Override + public void validateByAppId(String appId) { + AppBuilderAppDto appDto = this.appGenericable.query(appId, null); + boolean allow_guest = ObjectUtils.cast(appDto.getAttributes().getOrDefault("allow_guest", false)); + if (!allow_guest) { + throw new AippException(APP_NOT_IN_GUEST_MODE); + } + } + + @Override + public void validateByInstanceId(String instanceId) { + String taskId = this.appTaskInstanceService.getTaskId(instanceId); + AppTask task = this.appTaskService.getTaskById(taskId, null) + .orElseThrow(() -> new AippException(AippErrCode.TASK_NOT_FOUND)); + String appId = task.getEntity().getAppId(); + this.validateByAppId(appId); + } +} diff --git a/app-builder/plugins/aipp-plugin/src/main/resources/application.yml b/app-builder/plugins/aipp-plugin/src/main/resources/application.yml index 345ab5e995..51e5869c64 100644 --- a/app-builder/plugins/aipp-plugin/src/main/resources/application.yml +++ b/app-builder/plugins/aipp-plugin/src/main/resources/application.yml @@ -97,4 +97,6 @@ aipp: chat: session: file: - path: /var/share/backup/chat-session/ \ No newline at end of file + path: /var/share/backup/chat-session/ +domain-division: + isEnable: false \ No newline at end of file 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..5a6045368e 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,8 @@ 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. +90002144=The app is not in guest mode. \ 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..115e0c418a 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,8 @@ 90002137=系统错误,获取表单配置信息失败,请联系管理员。 90002138=运行失败,表单不存在或已经被删除。 90002139=调用大模型服务失败,{0}。 -90002140=大模型生成{0}失败,请尝试更换默认模型,失败原因:{1}。 \ No newline at end of file +90002140=大模型生成{0}失败,请尝试更换默认模型,失败原因:{1}。 +90002141=没有权限操作该应用。 +90002142=表单不存在。 +90002143=没有权限操作该表单。 +90002144=应用未打开游客模式。 \ 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 5b10c78161..1650a996a7 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 @@