fix: workflow delete error (#2879)
* fix: workflow delete key error * fix: chat auth error
This commit is contained in:
@@ -44,6 +44,7 @@ async function handler(
|
|||||||
per: ReadPermissionVal
|
per: ReadPermissionVal
|
||||||
})
|
})
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (!app) {
|
if (!app) {
|
||||||
return Promise.reject(AppErrEnum.unExist);
|
return Promise.reject(AppErrEnum.unExist);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ async function handler(
|
|||||||
|
|
||||||
// auth chat permission
|
// auth chat permission
|
||||||
if (chat && !app.permission.hasManagePer && String(tmbId) !== String(chat?.tmbId)) {
|
if (chat && !app.permission.hasManagePer && String(tmbId) !== String(chat?.tmbId)) {
|
||||||
throw new Error(ChatErrEnum.unAuthChat);
|
return Promise.reject(ChatErrEnum.unAuthChat);
|
||||||
}
|
}
|
||||||
|
|
||||||
// get app and history
|
// get app and history
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
|
|
||||||
// auth chat permission
|
// auth chat permission
|
||||||
if (chat && chat.outLinkUid !== uid) {
|
if (chat && chat.outLinkUid !== uid) {
|
||||||
throw new Error(ChatErrEnum.unAuthChat);
|
return Promise.reject(ChatErrEnum.unAuthChat);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { nodes, chatConfig } = await getAppLatestVersion(app._id, app);
|
const { nodes, chatConfig } = await getAppLatestVersion(app._id, app);
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
|
|
||||||
// auth chat permission
|
// auth chat permission
|
||||||
if (chat && chat.outLinkUid !== uid) {
|
if (chat && chat.outLinkUid !== uid) {
|
||||||
throw new Error(ChatErrEnum.unAuthChat);
|
return Promise.reject(ChatErrEnum.unAuthChat);
|
||||||
}
|
}
|
||||||
|
|
||||||
// get app and history
|
// get app and history
|
||||||
|
|||||||
@@ -25,12 +25,14 @@ import { useContextSelector } from 'use-context-selector';
|
|||||||
import { WorkflowContext } from '../../context';
|
import { WorkflowContext } from '../../context';
|
||||||
import { THelperLine } from '@fastgpt/global/core/workflow/type';
|
import { THelperLine } from '@fastgpt/global/core/workflow/type';
|
||||||
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||||
import { useKeyPress, useMemoizedFn } from 'ahooks';
|
import { useMemoizedFn } from 'ahooks';
|
||||||
import {
|
import {
|
||||||
Input_Template_Node_Height,
|
Input_Template_Node_Height,
|
||||||
Input_Template_Node_Width
|
Input_Template_Node_Width
|
||||||
} from '@fastgpt/global/core/workflow/template/input';
|
} from '@fastgpt/global/core/workflow/template/input';
|
||||||
import { FlowNodeItemType } from '@fastgpt/global/core/workflow/type/node';
|
import { FlowNodeItemType } from '@fastgpt/global/core/workflow/type/node';
|
||||||
|
import { getHandleId } from '@fastgpt/global/core/workflow/utils';
|
||||||
|
import { IfElseResultEnum } from '@fastgpt/global/core/workflow/template/system/ifElse/constant';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Compute helper lines for snapping nodes to each other
|
Compute helper lines for snapping nodes to each other
|
||||||
@@ -282,8 +284,7 @@ export const useWorkflow = () => {
|
|||||||
onChangeNode,
|
onChangeNode,
|
||||||
onEdgesChange,
|
onEdgesChange,
|
||||||
setHoverEdgeId,
|
setHoverEdgeId,
|
||||||
setMenu,
|
setMenu
|
||||||
mouseInCanvas
|
|
||||||
} = useContextSelector(WorkflowContext, (v) => v);
|
} = useContextSelector(WorkflowContext, (v) => v);
|
||||||
|
|
||||||
const { getIntersectingNodes } = useReactFlow();
|
const { getIntersectingNodes } = useReactFlow();
|
||||||
@@ -413,7 +414,33 @@ export const useWorkflow = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
/* node */
|
/* node */
|
||||||
|
const handleRemoveNode = useMemoizedFn((change: NodeRemoveChange, nodeId: string) => {
|
||||||
|
// If the node has child nodes, remove the child nodes
|
||||||
|
const childNodes = nodes.filter((n) => n.data.parentNodeId === nodeId);
|
||||||
|
if (childNodes.length > 0) {
|
||||||
|
const childNodeIds = childNodes.map((node) => node.id);
|
||||||
|
const childEdges = edges.filter(
|
||||||
|
(edge) => childNodeIds.includes(edge.source) || childNodeIds.includes(edge.target)
|
||||||
|
);
|
||||||
|
|
||||||
|
onNodesChange(
|
||||||
|
childNodes.map<NodeRemoveChange>((node) => ({
|
||||||
|
type: 'remove',
|
||||||
|
id: node.id
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
onEdgesChange(
|
||||||
|
childEdges.map<EdgeRemoveChange>((edge) => ({
|
||||||
|
type: 'remove',
|
||||||
|
id: edge.id
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
onNodesChange([change]);
|
||||||
|
|
||||||
|
return;
|
||||||
|
});
|
||||||
const handleSelectNode = useMemoizedFn((change: NodeSelectionChange) => {
|
const handleSelectNode = useMemoizedFn((change: NodeSelectionChange) => {
|
||||||
// If the node is not selected and the Ctrl key is pressed, select the node
|
// If the node is not selected and the Ctrl key is pressed, select the node
|
||||||
if (change.selected === false && isDowningCtrl) {
|
if (change.selected === false && isDowningCtrl) {
|
||||||
@@ -477,10 +504,25 @@ export const useWorkflow = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleNodesChange = useMemoizedFn((changes: NodeChange[]) => {
|
const handleNodesChange = useMemoizedFn((changes: NodeChange[]) => {
|
||||||
for (const change of changes) {
|
for (const change of changes) {
|
||||||
if (change.type === 'select') {
|
if (change.type === 'remove') {
|
||||||
|
const node = nodes.find((n) => n.id === change.id);
|
||||||
|
if (!node) continue;
|
||||||
|
|
||||||
|
const parentNodeDeleted = changes.find(
|
||||||
|
(c) => c.type === 'remove' && c.id === node?.data.parentNodeId
|
||||||
|
);
|
||||||
|
// Forbidden delete && Parents are not deleted together
|
||||||
|
if (node.data.forbidDelete && !parentNodeDeleted) {
|
||||||
|
toast({
|
||||||
|
status: 'warning',
|
||||||
|
title: t('common:core.workflow.Can not delete node')
|
||||||
|
});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
handleRemoveNode(change, node.id);
|
||||||
|
} else if (change.type === 'select') {
|
||||||
handleSelectNode(change);
|
handleSelectNode(change);
|
||||||
} else if (change.type === 'position') {
|
} else if (change.type === 'position') {
|
||||||
const node = nodes.find((n) => n.id === change.id);
|
const node = nodes.find((n) => n.id === change.id);
|
||||||
@@ -490,7 +532,8 @@ export const useWorkflow = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onNodesChange(changes);
|
// Remove separately
|
||||||
|
onNodesChange(changes.filter((c) => c.type !== 'remove'));
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleEdgeChange = useCallback(
|
const handleEdgeChange = useCallback(
|
||||||
@@ -591,60 +634,6 @@ export const useWorkflow = () => {
|
|||||||
setMenu(null);
|
setMenu(null);
|
||||||
}, [setMenu]);
|
}, [setMenu]);
|
||||||
|
|
||||||
useKeyPress(['Delete', 'Backspace'], (e) => {
|
|
||||||
if (!mouseInCanvas) return;
|
|
||||||
|
|
||||||
const selectedNodes = nodes.filter((node) => node.selected);
|
|
||||||
if (selectedNodes.length > 0) {
|
|
||||||
for (const node of selectedNodes) {
|
|
||||||
if (node.data.forbidDelete) {
|
|
||||||
toast({
|
|
||||||
status: 'warning',
|
|
||||||
title: t('common:core.workflow.Can not delete node')
|
|
||||||
});
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Computed deleted node and its edges
|
|
||||||
const removedNodeId = node.id;
|
|
||||||
const removedNodeEdges = edges.filter(
|
|
||||||
(edge) => edge.source === removedNodeId || edge.target === removedNodeId
|
|
||||||
);
|
|
||||||
|
|
||||||
const childNodes = nodes.filter((n) => n.data.parentNodeId === removedNodeId);
|
|
||||||
const childNodeIds = childNodes.map((node) => node.id);
|
|
||||||
const childEdges = edges.filter(
|
|
||||||
(edge) => childNodeIds.includes(edge.source) || childNodeIds.includes(edge.target)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Delete
|
|
||||||
onNodesChange(
|
|
||||||
[removedNodeId, ...childNodeIds].map((nodeId) => ({
|
|
||||||
type: 'remove',
|
|
||||||
id: nodeId
|
|
||||||
}))
|
|
||||||
);
|
|
||||||
onEdgesChange(
|
|
||||||
[...removedNodeEdges, ...childEdges].map((edge) => ({
|
|
||||||
type: 'remove',
|
|
||||||
id: edge.id
|
|
||||||
}))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete selected edges
|
|
||||||
const selectedEdges = edges.filter((edge) => edge.selected);
|
|
||||||
if (selectedEdges.length > 0) {
|
|
||||||
onEdgesChange(
|
|
||||||
selectedEdges.map((edge) => ({
|
|
||||||
type: 'remove',
|
|
||||||
id: edge.id
|
|
||||||
}))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
handleNodesChange,
|
handleNodesChange,
|
||||||
handleEdgeChange,
|
handleEdgeChange,
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ const Workflow = () => {
|
|||||||
}
|
}
|
||||||
: {})}
|
: {})}
|
||||||
onNodeDragStop={onNodeDragStop}
|
onNodeDragStop={onNodeDragStop}
|
||||||
deleteKeyCode={[]}
|
// deleteKeyCode={[]}
|
||||||
>
|
>
|
||||||
<FlowController />
|
<FlowController />
|
||||||
<HelperLines horizontal={helperLineHorizontal} vertical={helperLineVertical} />
|
<HelperLines horizontal={helperLineHorizontal} vertical={helperLineVertical} />
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import { MongoChat } from '@fastgpt/service/core/chat/chatSchema';
|
|||||||
import { AuthModeType } from '@fastgpt/service/support/permission/type';
|
import { AuthModeType } from '@fastgpt/service/support/permission/type';
|
||||||
import { authOutLink, authOutLinkInit } from './outLink';
|
import { authOutLink, authOutLinkInit } from './outLink';
|
||||||
import { ChatErrEnum } from '@fastgpt/global/common/error/code/chat';
|
import { ChatErrEnum } from '@fastgpt/global/common/error/code/chat';
|
||||||
import { authUserPer } from '@fastgpt/service/support/permission/user/auth';
|
|
||||||
import { TeamMemberRoleEnum } from '@fastgpt/global/support/user/team/constant';
|
import { TeamMemberRoleEnum } from '@fastgpt/global/support/user/team/constant';
|
||||||
import { authTeamSpaceToken } from './team';
|
import { authTeamSpaceToken } from './team';
|
||||||
import { authCert } from '@fastgpt/service/support/permission/auth/common';
|
import { authCert } from '@fastgpt/service/support/permission/auth/common';
|
||||||
@@ -11,12 +10,12 @@ import { authOutLinkValid } from '@fastgpt/service/support/permission/publish/au
|
|||||||
import {
|
import {
|
||||||
AuthUserTypeEnum,
|
AuthUserTypeEnum,
|
||||||
OwnerPermissionVal,
|
OwnerPermissionVal,
|
||||||
ReadPermissionVal,
|
ReadPermissionVal
|
||||||
WritePermissionVal
|
|
||||||
} from '@fastgpt/global/support/permission/constant';
|
} from '@fastgpt/global/support/permission/constant';
|
||||||
import { MongoTeamMember } from '@fastgpt/service/support/user/team/teamMemberSchema';
|
import { MongoTeamMember } from '@fastgpt/service/support/user/team/teamMemberSchema';
|
||||||
import { OutLinkChatAuthProps } from '@fastgpt/global/support/permission/chat';
|
import { OutLinkChatAuthProps } from '@fastgpt/global/support/permission/chat';
|
||||||
import { addLog } from '@fastgpt/service/common/system/log';
|
import { addLog } from '@fastgpt/service/common/system/log';
|
||||||
|
import { authApp } from '@fastgpt/service/support/permission/app/auth';
|
||||||
/*
|
/*
|
||||||
outLink: Must be the owner
|
outLink: Must be the owner
|
||||||
token: team owner and chat owner have all permissions
|
token: team owner and chat owner have all permissions
|
||||||
@@ -71,19 +70,19 @@ export async function authChatCrud({
|
|||||||
if (!chat) return { id: outLinkUid };
|
if (!chat) return { id: outLinkUid };
|
||||||
|
|
||||||
// auth req
|
// auth req
|
||||||
const { teamId, tmbId, permission } = await authUserPer({
|
const { teamId, tmbId, permission } = await authApp({
|
||||||
...props,
|
req: props.req,
|
||||||
|
authToken: true,
|
||||||
|
authApiKey: true,
|
||||||
|
appId,
|
||||||
per: ReadPermissionVal
|
per: ReadPermissionVal
|
||||||
});
|
});
|
||||||
|
|
||||||
if (String(teamId) !== String(chat.teamId)) return Promise.reject(ChatErrEnum.unAuthChat);
|
if (String(teamId) !== String(chat.teamId)) return Promise.reject(ChatErrEnum.unAuthChat);
|
||||||
|
|
||||||
if (permission.isOwner) return { uid: outLinkUid };
|
if (permission.hasManagePer) return { uid: outLinkUid };
|
||||||
if (String(tmbId) === String(chat.tmbId)) return { uid: outLinkUid };
|
if (String(tmbId) === String(chat.tmbId)) return { uid: outLinkUid };
|
||||||
|
|
||||||
// Admin can manage all chat
|
|
||||||
if (per === WritePermissionVal && permission.hasManagePer) return { uid: outLinkUid };
|
|
||||||
|
|
||||||
return Promise.reject(ChatErrEnum.unAuthChat);
|
return Promise.reject(ChatErrEnum.unAuthChat);
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user