* feat: team permission refine (#4402) * chore: team permission extend * feat: manage team permission * chore: api auth * fix: i18n * feat: add initv493 * fix: test, org auth manager * test: app test for refined permission * update init sh * fix: add/remove manage permission (#4427) * fix: add/remove manage permission * fix: github action fastgpt-test * fix: mock create model * fix: team write permission * fix: ts * account permission --------- Co-authored-by: Finley Ge <32237950+FinleyGe@users.noreply.github.com>
This commit is contained in:
@@ -1,20 +1,24 @@
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { Box, Checkbox, HStack, VStack } from '@chakra-ui/react';
|
||||
import Avatar from '@fastgpt/web/components/common/Avatar';
|
||||
import PermissionTags from './PermissionTags';
|
||||
import { PermissionValueType } from '@fastgpt/global/support/permission/type';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import OrgTags from '../../user/team/OrgTags';
|
||||
import Tag from '@fastgpt/web/components/common/Tag';
|
||||
|
||||
function MemberItemCard({
|
||||
avatar,
|
||||
key,
|
||||
onChange,
|
||||
onChange: _onChange,
|
||||
isChecked,
|
||||
onDelete,
|
||||
name,
|
||||
permission,
|
||||
orgs
|
||||
orgs,
|
||||
addOnly,
|
||||
rightSlot
|
||||
}: {
|
||||
avatar: string;
|
||||
key: string;
|
||||
@@ -23,44 +27,66 @@ function MemberItemCard({
|
||||
onDelete?: () => void;
|
||||
name: string;
|
||||
permission?: PermissionValueType;
|
||||
addOnly?: boolean;
|
||||
orgs?: string[];
|
||||
rightSlot?: React.ReactNode;
|
||||
}) {
|
||||
const isAdded = addOnly && !!permission;
|
||||
const onChange = () => {
|
||||
if (!isAdded) _onChange();
|
||||
};
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<>
|
||||
<HStack
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
key={key}
|
||||
px="3"
|
||||
py="2"
|
||||
borderRadius="sm"
|
||||
_hover={{
|
||||
bgColor: 'myGray.50',
|
||||
cursor: 'pointer'
|
||||
}}
|
||||
onClick={onChange}
|
||||
>
|
||||
{isChecked !== undefined && <Checkbox isChecked={isChecked} pointerEvents="none" />}
|
||||
<Avatar src={avatar} w="1.5rem" borderRadius={'50%'} />
|
||||
<HStack
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
key={key}
|
||||
px="3"
|
||||
py="2"
|
||||
borderRadius="sm"
|
||||
_hover={{
|
||||
bgColor: 'myGray.50',
|
||||
cursor: 'pointer'
|
||||
}}
|
||||
onClick={onChange}
|
||||
>
|
||||
{isChecked !== undefined && (
|
||||
<Checkbox isChecked={isChecked} pointerEvents="none" disabled={isAdded} />
|
||||
)}
|
||||
<Avatar src={avatar} w="1.5rem" borderRadius={'50%'} />
|
||||
|
||||
<Box w="full">
|
||||
<Box fontSize={'sm'}>{name}</Box>
|
||||
<Box lineHeight={1}>{orgs && orgs.length > 0 && <OrgTags orgs={orgs} />}</Box>
|
||||
<Box w="full">
|
||||
<Box fontSize={'sm'} className="textEllipsis" maxW="300px">
|
||||
{name}
|
||||
</Box>
|
||||
{permission && <PermissionTags permission={permission} />}
|
||||
{onDelete !== undefined && (
|
||||
<MyIcon
|
||||
name="common/closeLight"
|
||||
w="1rem"
|
||||
cursor={'pointer'}
|
||||
_hover={{
|
||||
color: 'red.600'
|
||||
}}
|
||||
onClick={onDelete}
|
||||
/>
|
||||
)}
|
||||
</HStack>
|
||||
</>
|
||||
<Box lineHeight={1}>{orgs && orgs.length > 0 && <OrgTags orgs={orgs} />}</Box>
|
||||
</Box>
|
||||
{!isAdded && permission && <PermissionTags permission={permission} />}
|
||||
{isAdded && (
|
||||
<Tag
|
||||
mixBlendMode={'multiply'}
|
||||
colorSchema="blue"
|
||||
border="none"
|
||||
py={2}
|
||||
px={3}
|
||||
fontSize={'xs'}
|
||||
>
|
||||
{t('user:team.collaborator.added')}
|
||||
</Tag>
|
||||
)}
|
||||
{onDelete !== undefined && (
|
||||
<MyIcon
|
||||
name="common/closeLight"
|
||||
w="1rem"
|
||||
cursor={'pointer'}
|
||||
_hover={{
|
||||
color: 'red.600'
|
||||
}}
|
||||
onClick={onDelete}
|
||||
/>
|
||||
)}
|
||||
{rightSlot}
|
||||
</HStack>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,17 +1,6 @@
|
||||
import { useUserStore } from '@/web/support/user/useUserStore';
|
||||
import { ChevronDownIcon } from '@chakra-ui/icons';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Checkbox,
|
||||
Flex,
|
||||
Grid,
|
||||
HStack,
|
||||
ModalBody,
|
||||
ModalFooter,
|
||||
Tag,
|
||||
Text
|
||||
} from '@chakra-ui/react';
|
||||
import { Box, Button, Flex, Grid, HStack, ModalBody, ModalFooter, Text } from '@chakra-ui/react';
|
||||
import { DefaultGroupName } from '@fastgpt/global/support/user/team/group/constant';
|
||||
import MyAvatar from '@fastgpt/web/components/common/Avatar';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
@@ -19,27 +8,26 @@ import SearchInput from '@fastgpt/web/components/common/Input/SearchInput';
|
||||
import MyModal from '@fastgpt/web/components/common/MyModal';
|
||||
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useMemo, useRef, useState } from 'react';
|
||||
import PermissionSelect from './PermissionSelect';
|
||||
import PermissionTags from './PermissionTags';
|
||||
import {
|
||||
DEFAULT_ORG_AVATAR,
|
||||
DEFAULT_TEAM_AVATAR,
|
||||
DEFAULT_USER_AVATAR
|
||||
} from '@fastgpt/global/common/system/constants';
|
||||
import Path from '@/components/common/folder/Path';
|
||||
import { OrgListItemType, OrgType } from '@fastgpt/global/support/user/team/org/type';
|
||||
import { OrgListItemType } from '@fastgpt/global/support/user/team/org/type';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { CollaboratorContext } from './context';
|
||||
import { getTeamMembers } from '@/web/support/user/team/api';
|
||||
import { getGroupList } from '@/web/support/user/team/group/api';
|
||||
import { useScrollPagination } from '@fastgpt/web/hooks/useScrollPagination';
|
||||
import MemberItemCard from './MemberItemCard';
|
||||
import { GetSearchUserGroupOrg } from '@/web/support/user/api';
|
||||
import useOrg from '@/web/support/user/team/org/hooks/useOrg';
|
||||
import { TeamMemberItemType } from '@fastgpt/global/support/user/team/type';
|
||||
import { MemberGroupListItemType } from '@fastgpt/global/support/permission/memberGroup/type';
|
||||
import _ from 'lodash';
|
||||
import { UpdateClbPermissionProps } from '@fastgpt/global/support/permission/collaborator';
|
||||
import { ValueOf } from 'next/dist/shared/lib/constants';
|
||||
|
||||
const HoverBoxStyle = {
|
||||
bgColor: 'myGray.50',
|
||||
@@ -131,8 +119,8 @@ function MemberModal({
|
||||
members: selectedMemberList.map((item) => item.tmbId),
|
||||
groups: selectedGroupList.map((item) => item._id),
|
||||
orgs: selectedOrgList.map((item) => item._id),
|
||||
permission: selectedPermission!
|
||||
}),
|
||||
permission: addOnly ? undefined : selectedPermission!
|
||||
} as UpdateClbPermissionProps<ValueOf<typeof addOnly>>),
|
||||
{
|
||||
successToast: t('common:common.Add Success'),
|
||||
onSuccess() {
|
||||
@@ -285,6 +273,7 @@ function MemberModal({
|
||||
const collaborator = collaboratorList?.find((v) => v.tmbId === member.tmbId);
|
||||
return (
|
||||
<MemberItemCard
|
||||
addOnly={addOnly}
|
||||
avatar={member.avatar}
|
||||
key={member.tmbId}
|
||||
name={member.memberName}
|
||||
@@ -321,49 +310,33 @@ function MemberModal({
|
||||
};
|
||||
const collaborator = collaboratorList?.find((v) => v.orgId === org._id);
|
||||
return (
|
||||
<HStack
|
||||
justifyContent="space-between"
|
||||
<MemberItemCard
|
||||
avatar={org.avatar}
|
||||
key={org._id}
|
||||
py="2"
|
||||
px="3"
|
||||
borderRadius="sm"
|
||||
alignItems="center"
|
||||
_hover={HoverBoxStyle}
|
||||
onClick={onChange}
|
||||
>
|
||||
<Checkbox
|
||||
isChecked={!!selectedOrgList.find((v) => v._id === org._id)}
|
||||
pointerEvents="none"
|
||||
/>
|
||||
<MyAvatar src={org.avatar} w="1.5rem" borderRadius={'50%'} />
|
||||
<HStack w="full">
|
||||
<Text>{org.name}</Text>
|
||||
{org.total && (
|
||||
<>
|
||||
<Tag size="sm" my="auto">
|
||||
{org.total}
|
||||
</Tag>
|
||||
</>
|
||||
)}
|
||||
</HStack>
|
||||
<PermissionTags permission={collaborator?.permission.value} />
|
||||
{org.total && (
|
||||
<MyIcon
|
||||
name="core/chat/chevronRight"
|
||||
w="16px"
|
||||
p="4px"
|
||||
rounded={'6px'}
|
||||
_hover={{
|
||||
bgColor: 'myGray.200'
|
||||
}}
|
||||
onClick={(e) => {
|
||||
onClickOrg(org);
|
||||
// setPath(getOrgChildrenPath(org));
|
||||
e.stopPropagation();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</HStack>
|
||||
name={org.name}
|
||||
onChange={onChange}
|
||||
addOnly={addOnly}
|
||||
permission={collaborator?.permission.value}
|
||||
isChecked={!!selectedOrgList.find((v) => String(v._id) === String(org._id))}
|
||||
rightSlot={
|
||||
org.total && (
|
||||
<MyIcon
|
||||
name="core/chat/chevronRight"
|
||||
w="16px"
|
||||
p="4px"
|
||||
rounded={'6px'}
|
||||
_hover={{
|
||||
bgColor: 'myGray.200'
|
||||
}}
|
||||
onClick={(e) => {
|
||||
onClickOrg(org);
|
||||
// setPath(getOrgChildrenPath(org));
|
||||
e.stopPropagation();
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
/>
|
||||
);
|
||||
});
|
||||
return searchKey ? (
|
||||
@@ -372,6 +345,9 @@ function MemberModal({
|
||||
<OrgMemberScrollData>
|
||||
{Orgs}
|
||||
{orgMembers.map((member) => {
|
||||
const isChecked = !!selectedMemberList.find(
|
||||
(v) => v.tmbId === member.tmbId
|
||||
);
|
||||
return (
|
||||
<MemberItemCard
|
||||
avatar={member.avatar}
|
||||
@@ -385,7 +361,9 @@ function MemberModal({
|
||||
return [...state, member];
|
||||
});
|
||||
}}
|
||||
isChecked={!!selectedMemberList.find((v) => v.tmbId === member.tmbId)}
|
||||
isChecked={isChecked}
|
||||
permission={member.permission.value}
|
||||
addOnly={addOnly && !!member.permission.value}
|
||||
orgs={member.orgs}
|
||||
/>
|
||||
);
|
||||
@@ -414,6 +392,7 @@ function MemberModal({
|
||||
permission={collaborator?.permission.value}
|
||||
onChange={onChange}
|
||||
isChecked={!!selectedGroupList.find((v) => v._id === group._id)}
|
||||
addOnly={addOnly}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -110,7 +110,15 @@ const CollaboratorContextProvider = ({
|
||||
} = useRequest2(
|
||||
async () => {
|
||||
if (feConfigs.isPlus) {
|
||||
return onGetCollaboratorList();
|
||||
const data = await onGetCollaboratorList();
|
||||
return data.map((item) => {
|
||||
return {
|
||||
...item,
|
||||
permission: new Permission({
|
||||
per: item.permission.value
|
||||
})
|
||||
};
|
||||
});
|
||||
}
|
||||
return [];
|
||||
},
|
||||
|
||||
@@ -10,7 +10,14 @@ function OrgTags({ orgs, type = 'simple' }: { orgs?: string[]; type?: 'simple' |
|
||||
label={
|
||||
<VStack gap="1" alignItems={'start'}>
|
||||
{orgs.map((org, index) => (
|
||||
<Box key={index} fontSize="sm" fontWeight={400} color="myGray.500">
|
||||
<Box
|
||||
key={index}
|
||||
fontSize="sm"
|
||||
fontWeight={400}
|
||||
color="myGray.500"
|
||||
maxW={'300px'}
|
||||
className="textEllipsis"
|
||||
>
|
||||
{org.slice(1)}
|
||||
</Box>
|
||||
))}
|
||||
|
||||
@@ -91,7 +91,7 @@ const AccountContainer = ({
|
||||
}
|
||||
]
|
||||
: []),
|
||||
...(userInfo?.team?.permission.hasManagePer
|
||||
...(userInfo?.team?.permission.hasApikeyCreatePer
|
||||
? [
|
||||
{
|
||||
icon: 'key',
|
||||
|
||||
@@ -27,6 +27,9 @@ import Avatar from '@fastgpt/web/components/common/Avatar';
|
||||
import MemberTag from '../../../../components/support/user/team/Info/MemberTag';
|
||||
import { DefaultGroupName } from '@fastgpt/global/support/user/team/group/constant';
|
||||
import {
|
||||
TeamApikeyCreatePermissionVal,
|
||||
TeamAppCreatePermissionVal,
|
||||
TeamDatasetCreatePermissionVal,
|
||||
TeamManagePermissionVal,
|
||||
TeamPermissionList,
|
||||
TeamWritePermissionVal
|
||||
@@ -42,6 +45,9 @@ import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import SearchInput from '@fastgpt/web/components/common/Input/SearchInput';
|
||||
import { GetSearchUserGroupOrg } from '@/web/support/user/api';
|
||||
import { PermissionValueType } from '@fastgpt/global/support/permission/type';
|
||||
import { CollaboratorItemType } from '@fastgpt/global/support/permission/collaborator';
|
||||
import { Permission } from '@fastgpt/global/support/permission/controller';
|
||||
|
||||
function PermissionManage({
|
||||
Tabs,
|
||||
@@ -104,19 +110,18 @@ function PermissionManage({
|
||||
}, [collaboratorList, searchResult, searchKey]);
|
||||
|
||||
const { runAsync: onUpdatePermission, loading: addLoading } = useRequest2(
|
||||
async ({ id, type, per }: { id: string; type: 'add' | 'remove'; per: 'write' | 'manage' }) => {
|
||||
async ({ id, type, per }: { id: string; type: 'add' | 'remove'; per: PermissionValueType }) => {
|
||||
const clb = collaboratorList.find(
|
||||
(clb) => clb.tmbId === id || clb.groupId === id || clb.orgId === id
|
||||
);
|
||||
|
||||
if (!clb) return;
|
||||
|
||||
const updatePer = per === 'write' ? TeamWritePermissionVal : TeamManagePermissionVal;
|
||||
const permission = new TeamPermission({ per: clb.permission.value });
|
||||
if (type === 'add') {
|
||||
permission.addPer(updatePer);
|
||||
permission.addPer(per);
|
||||
} else {
|
||||
permission.removePer(updatePer);
|
||||
permission.removePer(per);
|
||||
}
|
||||
|
||||
return onUpdateCollaborators({
|
||||
@@ -132,12 +137,48 @@ function PermissionManage({
|
||||
useRequest2(onDelOneCollaborator);
|
||||
|
||||
const userManage = userInfo?.permission.hasManagePer;
|
||||
const hasDeletePer = (per: TeamPermission) => {
|
||||
const hasDeletePer = (per: Permission) => {
|
||||
if (userInfo?.permission.isOwner) return true;
|
||||
if (userManage && !per.hasManagePer) return true;
|
||||
return false;
|
||||
};
|
||||
|
||||
function PermissionCheckBox({
|
||||
isDisabled,
|
||||
per,
|
||||
clbPer,
|
||||
id
|
||||
}: {
|
||||
isDisabled: boolean;
|
||||
per: PermissionValueType;
|
||||
clbPer: Permission;
|
||||
id: string;
|
||||
}) {
|
||||
return (
|
||||
<Td>
|
||||
<Box mx="auto" w="fit-content">
|
||||
<Checkbox
|
||||
isDisabled={isDisabled}
|
||||
isChecked={clbPer.checkPer(per)}
|
||||
onChange={(e) =>
|
||||
e.target.checked
|
||||
? onUpdatePermission({
|
||||
id,
|
||||
type: 'add',
|
||||
per
|
||||
})
|
||||
: onUpdatePermission({
|
||||
id,
|
||||
type: 'remove',
|
||||
per
|
||||
})
|
||||
}
|
||||
/>
|
||||
</Box>
|
||||
</Td>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Flex justify={'space-between'} align={'center'} pb={'1rem'}>
|
||||
@@ -174,13 +215,26 @@ function PermissionManage({
|
||||
</Th>
|
||||
<Th bg="myGray.100">
|
||||
<Box mx="auto" w="fit-content">
|
||||
{t('user:team.group.permission.write')}
|
||||
{t('account_team:permission_appCreate')}
|
||||
<QuestionTip ml="1" label={t('account_team:permission_appCreate_tip')} />
|
||||
</Box>
|
||||
</Th>
|
||||
<Th bg="myGray.100">
|
||||
<Box mx="auto" w="fit-content">
|
||||
{t('user:team.group.permission.manage')}
|
||||
<QuestionTip ml="1" label={t('user:team.group.manage_tip')} />
|
||||
{t('account_team:permission_datasetCreate')}
|
||||
<QuestionTip ml="1" label={t('account_team:permission_datasetCreate_Tip')} />
|
||||
</Box>
|
||||
</Th>
|
||||
<Th bg="myGray.100">
|
||||
<Box mx="auto" w="fit-content">
|
||||
{t('account_team:permission_apikeyCreate')}
|
||||
<QuestionTip ml="1" label={t('account_team:permission_apikeyCreate_Tip')} />
|
||||
</Box>
|
||||
</Th>
|
||||
<Th bg="myGray.100">
|
||||
<Box mx="auto" w="fit-content">
|
||||
{t('account_team:permission_manage')}
|
||||
<QuestionTip ml="1" label={t('account_team:permission_manage_tip')} />
|
||||
</Box>
|
||||
</Th>
|
||||
<Th bg="myGray.100" borderRightRadius="md">
|
||||
@@ -210,48 +264,30 @@ function PermissionManage({
|
||||
<Box>{member.name}</Box>
|
||||
</HStack>
|
||||
</Td>
|
||||
<Td>
|
||||
<Box mx="auto" w="fit-content">
|
||||
<Checkbox
|
||||
isDisabled={member.permission.isOwner || !userManage}
|
||||
isChecked={member.permission.hasWritePer}
|
||||
onChange={(e) =>
|
||||
e.target.checked
|
||||
? onUpdatePermission({
|
||||
id: member.tmbId!,
|
||||
type: 'add',
|
||||
per: 'write'
|
||||
})
|
||||
: onUpdatePermission({
|
||||
id: member.tmbId!,
|
||||
type: 'remove',
|
||||
per: 'write'
|
||||
})
|
||||
}
|
||||
/>
|
||||
</Box>
|
||||
</Td>
|
||||
<Td>
|
||||
<Box mx="auto" w="fit-content">
|
||||
<Checkbox
|
||||
isDisabled={member.permission.isOwner || !userInfo?.permission.isOwner}
|
||||
isChecked={member.permission.hasManagePer}
|
||||
onChange={(e) =>
|
||||
e.target.checked
|
||||
? onUpdatePermission({
|
||||
id: member.tmbId!,
|
||||
type: 'add',
|
||||
per: 'manage'
|
||||
})
|
||||
: onUpdatePermission({
|
||||
id: member.tmbId!,
|
||||
type: 'remove',
|
||||
per: 'manage'
|
||||
})
|
||||
}
|
||||
/>
|
||||
</Box>
|
||||
</Td>
|
||||
<PermissionCheckBox
|
||||
isDisabled={member.permission.isOwner || !userManage}
|
||||
per={TeamAppCreatePermissionVal}
|
||||
clbPer={member.permission}
|
||||
id={member.tmbId!}
|
||||
/>
|
||||
<PermissionCheckBox
|
||||
isDisabled={member.permission.isOwner || !userManage}
|
||||
per={TeamDatasetCreatePermissionVal}
|
||||
clbPer={member.permission}
|
||||
id={member.tmbId!}
|
||||
/>
|
||||
<PermissionCheckBox
|
||||
isDisabled={member.permission.isOwner || !userManage}
|
||||
per={TeamApikeyCreatePermissionVal}
|
||||
clbPer={member.permission}
|
||||
id={member.tmbId!}
|
||||
/>
|
||||
<PermissionCheckBox
|
||||
isDisabled={member.permission.isOwner || !userInfo?.permission.isOwner}
|
||||
per={TeamManagePermissionVal}
|
||||
clbPer={member.permission}
|
||||
id={member.tmbId!}
|
||||
/>
|
||||
<Td>
|
||||
{hasDeletePer(member.permission) &&
|
||||
userInfo?.team.tmbId !== member.tmbId && (
|
||||
@@ -268,7 +304,6 @@ function PermissionManage({
|
||||
</Tr>
|
||||
))}
|
||||
</>
|
||||
|
||||
<>
|
||||
<Tr borderBottom={'1px solid'} borderColor={'myGray.200'} />
|
||||
<Tr userSelect={'none'}>
|
||||
@@ -286,40 +321,30 @@ function PermissionManage({
|
||||
<Td pl={10}>
|
||||
<MemberTag name={org.name} avatar={org.avatar} />
|
||||
</Td>
|
||||
<Td>
|
||||
<Box mx="auto" w="fit-content">
|
||||
<Checkbox
|
||||
isDisabled={!userManage}
|
||||
isChecked={org.permission.hasWritePer}
|
||||
onChange={(e) =>
|
||||
e.target.checked
|
||||
? onUpdatePermission({ id: org.orgId!, type: 'add', per: 'write' })
|
||||
: onUpdatePermission({
|
||||
id: org.orgId!,
|
||||
type: 'remove',
|
||||
per: 'write'
|
||||
})
|
||||
}
|
||||
/>
|
||||
</Box>
|
||||
</Td>
|
||||
<Td>
|
||||
<Box mx="auto" w="fit-content">
|
||||
<Checkbox
|
||||
isDisabled={!userInfo?.permission.isOwner}
|
||||
isChecked={org.permission.hasManagePer}
|
||||
onChange={(e) =>
|
||||
e.target.checked
|
||||
? onUpdatePermission({ id: org.orgId!, type: 'add', per: 'manage' })
|
||||
: onUpdatePermission({
|
||||
id: org.orgId!,
|
||||
type: 'remove',
|
||||
per: 'manage'
|
||||
})
|
||||
}
|
||||
/>
|
||||
</Box>
|
||||
</Td>
|
||||
<PermissionCheckBox
|
||||
isDisabled={org.permission.isOwner || !userManage}
|
||||
per={TeamAppCreatePermissionVal}
|
||||
clbPer={org.permission}
|
||||
id={org.orgId!}
|
||||
/>
|
||||
<PermissionCheckBox
|
||||
isDisabled={org.permission.isOwner || !userManage}
|
||||
per={TeamDatasetCreatePermissionVal}
|
||||
clbPer={org.permission}
|
||||
id={org.orgId!}
|
||||
/>
|
||||
<PermissionCheckBox
|
||||
isDisabled={org.permission.isOwner || !userManage}
|
||||
per={TeamApikeyCreatePermissionVal}
|
||||
clbPer={org.permission}
|
||||
id={org.orgId!}
|
||||
/>
|
||||
<PermissionCheckBox
|
||||
isDisabled={org.permission.isOwner || !userInfo?.permission.isOwner}
|
||||
per={TeamManagePermissionVal}
|
||||
clbPer={org.permission}
|
||||
id={org.orgId!}
|
||||
/>
|
||||
<Td>
|
||||
{hasDeletePer(org.permission) && (
|
||||
<Box mx="auto" w="fit-content">
|
||||
@@ -358,48 +383,30 @@ function PermissionManage({
|
||||
avatar={group.avatar}
|
||||
/>
|
||||
</Td>
|
||||
<Td>
|
||||
<Box mx="auto" w="fit-content">
|
||||
<Checkbox
|
||||
isDisabled={!userManage}
|
||||
isChecked={group.permission.hasWritePer}
|
||||
onChange={(e) =>
|
||||
e.target.checked
|
||||
? onUpdatePermission({
|
||||
id: group.groupId!,
|
||||
type: 'add',
|
||||
per: 'write'
|
||||
})
|
||||
: onUpdatePermission({
|
||||
id: group.groupId!,
|
||||
type: 'remove',
|
||||
per: 'write'
|
||||
})
|
||||
}
|
||||
/>
|
||||
</Box>
|
||||
</Td>
|
||||
<Td>
|
||||
<Box mx="auto" w="fit-content">
|
||||
<Checkbox
|
||||
isDisabled={!userInfo?.permission.isOwner}
|
||||
isChecked={group.permission.hasManagePer}
|
||||
onChange={(e) =>
|
||||
e.target.checked
|
||||
? onUpdatePermission({
|
||||
id: group.groupId!,
|
||||
type: 'add',
|
||||
per: 'manage'
|
||||
})
|
||||
: onUpdatePermission({
|
||||
id: group.groupId!,
|
||||
type: 'remove',
|
||||
per: 'manage'
|
||||
})
|
||||
}
|
||||
/>
|
||||
</Box>
|
||||
</Td>
|
||||
<PermissionCheckBox
|
||||
isDisabled={group.permission.isOwner || !userManage}
|
||||
per={TeamAppCreatePermissionVal}
|
||||
clbPer={group.permission}
|
||||
id={group.groupId!}
|
||||
/>
|
||||
<PermissionCheckBox
|
||||
isDisabled={group.permission.isOwner || !userManage}
|
||||
per={TeamDatasetCreatePermissionVal}
|
||||
clbPer={group.permission}
|
||||
id={group.groupId!}
|
||||
/>
|
||||
<PermissionCheckBox
|
||||
isDisabled={group.permission.isOwner || !userManage}
|
||||
per={TeamApikeyCreatePermissionVal}
|
||||
clbPer={group.permission}
|
||||
id={group.groupId!}
|
||||
/>
|
||||
<PermissionCheckBox
|
||||
isDisabled={group.permission.isOwner || !userInfo?.permission.isOwner}
|
||||
per={TeamManagePermissionVal}
|
||||
clbPer={group.permission}
|
||||
id={group.groupId!}
|
||||
/>
|
||||
<Td>
|
||||
{hasDeletePer(group.permission) && (
|
||||
<Box mx="auto" w="fit-content">
|
||||
|
||||
@@ -36,6 +36,7 @@ import { useSystem } from '@fastgpt/web/hooks/useSystem';
|
||||
import { useChatStore } from '@/web/core/chat/context/useChatStore';
|
||||
import { RequireOnlyOne } from '@fastgpt/global/common/type/utils';
|
||||
import UserBox from '@fastgpt/web/components/common/UserBox';
|
||||
import { PermissionValueType } from '@fastgpt/global/support/permission/type';
|
||||
const HttpEditModal = dynamic(() => import('./HttpPluginEditModal'));
|
||||
|
||||
const ListItem = () => {
|
||||
@@ -429,7 +430,7 @@ const ListItem = () => {
|
||||
members?: string[];
|
||||
groups?: string[];
|
||||
orgs?: string[];
|
||||
permission: number;
|
||||
permission: PermissionValueType;
|
||||
}) =>
|
||||
postUpdateAppCollaborators({
|
||||
...props,
|
||||
|
||||
@@ -4,6 +4,7 @@ import { authApp } from '@fastgpt/service/support/permission/app/auth';
|
||||
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
|
||||
import { authUserPer } from '@fastgpt/service/support/permission/user/auth';
|
||||
import { onCreateApp } from './create';
|
||||
import { TeamAppCreatePermissionVal } from '@fastgpt/global/support/permission/user/constant';
|
||||
|
||||
export type copyAppQuery = {};
|
||||
|
||||
@@ -17,19 +18,16 @@ async function handler(
|
||||
req: ApiRequestProps<copyAppBody, copyAppQuery>,
|
||||
res: ApiResponseType<any>
|
||||
): Promise<copyAppResponse> {
|
||||
const [{ app, tmbId }] = await Promise.all([
|
||||
authApp({
|
||||
req,
|
||||
authToken: true,
|
||||
per: WritePermissionVal,
|
||||
appId: req.body.appId
|
||||
}),
|
||||
authUserPer({
|
||||
req,
|
||||
authToken: true,
|
||||
per: WritePermissionVal
|
||||
})
|
||||
]);
|
||||
const { app } = await authApp({
|
||||
req,
|
||||
authToken: true,
|
||||
per: WritePermissionVal,
|
||||
appId: req.body.appId
|
||||
});
|
||||
|
||||
const { tmbId } = app.parentId
|
||||
? await authApp({ req, appId: app.parentId, per: TeamAppCreatePermissionVal, authToken: true })
|
||||
: await authUserPer({ req, authToken: true, per: TeamAppCreatePermissionVal });
|
||||
|
||||
const appId = await onCreateApp({
|
||||
parentId: app.parentId,
|
||||
|
||||
@@ -17,6 +17,7 @@ import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
|
||||
import { MongoTeamMember } from '@fastgpt/service/support/user/team/teamMemberSchema';
|
||||
import { pushTrack } from '@fastgpt/service/common/middle/tracks/utils';
|
||||
import { refreshSourceAvatar } from '@fastgpt/service/common/file/image/controller';
|
||||
import { TeamAppCreatePermissionVal } from '@fastgpt/global/support/permission/user/constant';
|
||||
|
||||
export type CreateAppBody = {
|
||||
parentId?: ParentIdType;
|
||||
@@ -36,18 +37,15 @@ async function handler(req: ApiRequestProps<CreateAppBody>) {
|
||||
}
|
||||
|
||||
// 凭证校验
|
||||
const [{ teamId, tmbId, userId }] = await Promise.all([
|
||||
authUserPer({ req, authToken: true, per: WritePermissionVal }),
|
||||
...(parentId
|
||||
? [authApp({ req, appId: parentId, per: WritePermissionVal, authToken: true })]
|
||||
: [])
|
||||
]);
|
||||
const { teamId, tmbId, userId } = parentId
|
||||
? await authApp({ req, appId: parentId, per: TeamAppCreatePermissionVal, authToken: true })
|
||||
: await authUserPer({ req, authToken: true, per: TeamAppCreatePermissionVal });
|
||||
|
||||
// 上限校验
|
||||
await checkTeamAppLimit(teamId);
|
||||
const tmb = await MongoTeamMember.findById({ _id: tmbId }, 'userId').populate<{
|
||||
user: { avatar: string; username: string };
|
||||
}>('user', 'avatar username');
|
||||
user: { username: string };
|
||||
}>('user', 'username');
|
||||
|
||||
// 创建app
|
||||
const appId = await onCreateApp({
|
||||
@@ -60,7 +58,7 @@ async function handler(req: ApiRequestProps<CreateAppBody>) {
|
||||
chatConfig,
|
||||
teamId,
|
||||
tmbId,
|
||||
userAvatar: tmb?.user?.avatar,
|
||||
userAvatar: tmb?.avatar,
|
||||
username: tmb?.user?.username
|
||||
});
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
|
||||
import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
|
||||
import { syncCollaborators } from '@fastgpt/service/support/permission/inheritPermission';
|
||||
import { getResourceClbsAndGroups } from '@fastgpt/service/support/permission/controller';
|
||||
import { TeamWritePermissionVal } from '@fastgpt/global/support/permission/user/constant';
|
||||
import { TeamAppCreatePermissionVal } from '@fastgpt/global/support/permission/user/constant';
|
||||
import { MongoResourcePermission } from '@fastgpt/service/support/permission/schema';
|
||||
|
||||
export type CreateAppFolderBody = {
|
||||
@@ -33,21 +33,9 @@ async function handler(req: ApiRequestProps<CreateAppFolderBody>) {
|
||||
}
|
||||
|
||||
// 凭证校验
|
||||
const { teamId, tmbId } = await authUserPer({
|
||||
req,
|
||||
authToken: true,
|
||||
per: TeamWritePermissionVal
|
||||
});
|
||||
|
||||
if (parentId) {
|
||||
// if it is not a root folder
|
||||
await authApp({
|
||||
req,
|
||||
appId: parentId,
|
||||
per: WritePermissionVal,
|
||||
authToken: true
|
||||
});
|
||||
}
|
||||
const { teamId, tmbId } = parentId
|
||||
? await authApp({ req, appId: parentId, per: TeamAppCreatePermissionVal, authToken: true })
|
||||
: await authUserPer({ req, authToken: true, per: TeamAppCreatePermissionVal });
|
||||
|
||||
// Create app
|
||||
await mongoSessionRun(async (session) => {
|
||||
|
||||
@@ -9,6 +9,8 @@ import { onCreateApp, type CreateAppBody } from '../create';
|
||||
import { AppSchema } from '@fastgpt/global/core/app/type';
|
||||
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
|
||||
import { pushTrack } from '@fastgpt/service/common/middle/tracks/utils';
|
||||
import { authApp } from '@fastgpt/service/support/permission/app/auth';
|
||||
import { TeamAppCreatePermissionVal } from '@fastgpt/global/support/permission/user/constant';
|
||||
|
||||
export type createHttpPluginQuery = {};
|
||||
|
||||
@@ -29,11 +31,9 @@ async function handler(
|
||||
return Promise.reject('缺少参数');
|
||||
}
|
||||
|
||||
const { teamId, tmbId, userId } = await authUserPer({
|
||||
req,
|
||||
authToken: true,
|
||||
per: WritePermissionVal
|
||||
});
|
||||
const { teamId, tmbId, userId } = parentId
|
||||
? await authApp({ req, appId: parentId, per: TeamAppCreatePermissionVal, authToken: true })
|
||||
: await authUserPer({ req, authToken: true, per: TeamAppCreatePermissionVal });
|
||||
|
||||
await mongoSessionRun(async (session) => {
|
||||
// create http plugin folder
|
||||
|
||||
@@ -20,7 +20,7 @@ import { ClientSession } from 'mongoose';
|
||||
import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
|
||||
import { getResourceClbsAndGroups } from '@fastgpt/service/support/permission/controller';
|
||||
import { authUserPer } from '@fastgpt/service/support/permission/user/auth';
|
||||
import { TeamWritePermissionVal } from '@fastgpt/global/support/permission/user/constant';
|
||||
import { TeamAppCreatePermissionVal } from '@fastgpt/global/support/permission/user/constant';
|
||||
import { AppErrEnum } from '@fastgpt/global/common/error/code/app';
|
||||
import { refreshSourceAvatar } from '@fastgpt/service/common/file/image/controller';
|
||||
import { MongoResourcePermission } from '@fastgpt/service/support/permission/schema';
|
||||
@@ -79,7 +79,7 @@ async function handler(req: ApiRequestProps<AppUpdateBody, AppUpdateQuery>) {
|
||||
await authUserPer({
|
||||
req,
|
||||
authToken: true,
|
||||
per: TeamWritePermissionVal
|
||||
per: TeamAppCreatePermissionVal
|
||||
});
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -6,11 +6,9 @@ import {
|
||||
getLLMModel,
|
||||
getEmbeddingModel,
|
||||
getDatasetModel,
|
||||
getDefaultEmbeddingModel,
|
||||
getVlmModel
|
||||
getDefaultEmbeddingModel
|
||||
} from '@fastgpt/service/core/ai/model';
|
||||
import { checkTeamDatasetLimit } from '@fastgpt/service/support/permission/teamLimit';
|
||||
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
|
||||
import { NextAPI } from '@/service/middleware/entry';
|
||||
import type { ApiRequestProps } from '@fastgpt/service/type/next';
|
||||
import { parseParentIdInMongo } from '@fastgpt/global/common/parentFolder/utils';
|
||||
@@ -18,6 +16,7 @@ import { authDataset } from '@fastgpt/service/support/permission/dataset/auth';
|
||||
import { pushTrack } from '@fastgpt/service/common/middle/tracks/utils';
|
||||
import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
|
||||
import { refreshSourceAvatar } from '@fastgpt/service/common/file/image/controller';
|
||||
import { TeamDatasetCreatePermissionVal } from '@fastgpt/global/support/permission/user/constant';
|
||||
|
||||
export type DatasetCreateQuery = {};
|
||||
export type DatasetCreateBody = CreateDatasetParams;
|
||||
@@ -41,25 +40,20 @@ async function handler(
|
||||
} = req.body;
|
||||
|
||||
// auth
|
||||
const [{ teamId, tmbId, userId }] = await Promise.all([
|
||||
authUserPer({
|
||||
req,
|
||||
authToken: true,
|
||||
authApiKey: true,
|
||||
per: WritePermissionVal
|
||||
}),
|
||||
...(parentId
|
||||
? [
|
||||
authDataset({
|
||||
req,
|
||||
datasetId: parentId,
|
||||
authToken: true,
|
||||
authApiKey: true,
|
||||
per: WritePermissionVal
|
||||
})
|
||||
]
|
||||
: [])
|
||||
]);
|
||||
const { teamId, tmbId, userId } = parentId
|
||||
? await authDataset({
|
||||
req,
|
||||
datasetId: parentId,
|
||||
authToken: true,
|
||||
authApiKey: true,
|
||||
per: TeamDatasetCreatePermissionVal
|
||||
})
|
||||
: await authUserPer({
|
||||
req,
|
||||
authToken: true,
|
||||
authApiKey: true,
|
||||
per: TeamDatasetCreatePermissionVal
|
||||
});
|
||||
|
||||
// check model valid
|
||||
const vectorModelStore = getEmbeddingModel(vectorModel);
|
||||
|
||||
@@ -5,8 +5,7 @@ import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
|
||||
import { authUserPer } from '@fastgpt/service/support/permission/user/auth';
|
||||
import {
|
||||
OwnerPermissionVal,
|
||||
PerResourceTypeEnum,
|
||||
WritePermissionVal
|
||||
PerResourceTypeEnum
|
||||
} from '@fastgpt/global/support/permission/constant';
|
||||
import { authDataset } from '@fastgpt/service/support/permission/dataset/auth';
|
||||
import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
|
||||
@@ -16,6 +15,7 @@ import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants';
|
||||
import { getResourceClbsAndGroups } from '@fastgpt/service/support/permission/controller';
|
||||
import { syncCollaborators } from '@fastgpt/service/support/permission/inheritPermission';
|
||||
import { MongoResourcePermission } from '@fastgpt/service/support/permission/schema';
|
||||
import { TeamDatasetCreatePermissionVal } from '@fastgpt/global/support/permission/user/constant';
|
||||
export type DatasetFolderCreateQuery = {};
|
||||
export type DatasetFolderCreateBody = {
|
||||
parentId?: string;
|
||||
@@ -33,20 +33,20 @@ async function handler(
|
||||
return Promise.reject(CommonErrEnum.missingParams);
|
||||
}
|
||||
|
||||
const { tmbId, teamId } = await authUserPer({
|
||||
req,
|
||||
per: WritePermissionVal,
|
||||
authToken: true
|
||||
});
|
||||
|
||||
if (parentId) {
|
||||
await authDataset({
|
||||
datasetId: parentId,
|
||||
per: WritePermissionVal,
|
||||
req,
|
||||
authToken: true
|
||||
});
|
||||
}
|
||||
const { teamId, tmbId } = parentId
|
||||
? await authDataset({
|
||||
req,
|
||||
datasetId: parentId,
|
||||
authToken: true,
|
||||
authApiKey: true,
|
||||
per: TeamDatasetCreatePermissionVal
|
||||
})
|
||||
: await authUserPer({
|
||||
req,
|
||||
authToken: true,
|
||||
authApiKey: true,
|
||||
per: TeamDatasetCreatePermissionVal
|
||||
});
|
||||
|
||||
await mongoSessionRun(async (session) => {
|
||||
const dataset = await MongoDataset.create({
|
||||
|
||||
@@ -23,7 +23,7 @@ import {
|
||||
syncCollaborators
|
||||
} from '@fastgpt/service/support/permission/inheritPermission';
|
||||
import { authUserPer } from '@fastgpt/service/support/permission/user/auth';
|
||||
import { TeamWritePermissionVal } from '@fastgpt/global/support/permission/user/constant';
|
||||
import { TeamDatasetCreatePermissionVal } from '@fastgpt/global/support/permission/user/constant';
|
||||
import { DatasetErrEnum } from '@fastgpt/global/common/error/code/dataset';
|
||||
import { MongoDatasetTraining } from '@fastgpt/service/core/dataset/training/schema';
|
||||
import { MongoDatasetCollection } from '@fastgpt/service/core/dataset/collection/schema';
|
||||
@@ -104,7 +104,7 @@ async function handler(
|
||||
await authUserPer({
|
||||
req,
|
||||
authToken: true,
|
||||
per: TeamWritePermissionVal
|
||||
per: TeamDatasetCreatePermissionVal
|
||||
});
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -4,12 +4,10 @@ import { authUserPer } from '@fastgpt/service/support/permission/user/auth';
|
||||
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
||||
import type { ApiRequestProps } from '@fastgpt/service/type/next';
|
||||
import { NextAPI } from '@/service/middleware/entry';
|
||||
import {
|
||||
ManagePermissionVal,
|
||||
WritePermissionVal
|
||||
} from '@fastgpt/global/support/permission/constant';
|
||||
import { ManagePermissionVal } from '@fastgpt/global/support/permission/constant';
|
||||
import { authApp } from '@fastgpt/service/support/permission/app/auth';
|
||||
import { OpenApiErrEnum } from '@fastgpt/global/common/error/code/openapi';
|
||||
import { TeamApikeyCreatePermissionVal } from '@fastgpt/global/support/permission/user/constant';
|
||||
|
||||
async function handler(req: ApiRequestProps<EditApiKeyProps>): Promise<string> {
|
||||
const { appId, name, limit } = req.body;
|
||||
@@ -19,7 +17,7 @@ async function handler(req: ApiRequestProps<EditApiKeyProps>): Promise<string> {
|
||||
const { teamId, tmbId } = await authUserPer({
|
||||
req,
|
||||
authToken: true,
|
||||
per: WritePermissionVal
|
||||
per: TeamApikeyCreatePermissionVal
|
||||
});
|
||||
return { teamId, tmbId };
|
||||
} else {
|
||||
|
||||
@@ -31,6 +31,7 @@ import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import TemplateMarketModal from '@/pageComponents/app/list/TemplateMarketModal';
|
||||
import MyImage from '@fastgpt/web/components/common/Image/MyImage';
|
||||
import JsonImportModal from '@/pageComponents/app/list/JsonImportModal';
|
||||
import { PermissionValueType } from '@fastgpt/global/support/permission/type';
|
||||
|
||||
const CreateModal = dynamic(() => import('@/pageComponents/app/list/CreateModal'));
|
||||
const EditFolderModal = dynamic(
|
||||
@@ -213,7 +214,7 @@ const MyApps = () => {
|
||||
|
||||
{(folderDetail
|
||||
? folderDetail.permission.hasWritePer && folderDetail?.type !== AppTypeEnum.httpPlugin
|
||||
: userInfo?.team.permission.hasWritePer) && (
|
||||
: userInfo?.team.permission.hasAppCreatePer) && (
|
||||
<MyMenu
|
||||
size="md"
|
||||
Button={
|
||||
@@ -327,7 +328,7 @@ const MyApps = () => {
|
||||
}: {
|
||||
members?: string[];
|
||||
groups?: string[];
|
||||
permission: number;
|
||||
permission: PermissionValueType;
|
||||
}) => {
|
||||
return postUpdateAppCollaborators({
|
||||
members,
|
||||
|
||||
@@ -29,6 +29,7 @@ import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants';
|
||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
import MyBox from '@fastgpt/web/components/common/MyBox';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import { PermissionValueType } from '@fastgpt/global/support/permission/type';
|
||||
|
||||
const EditFolderModal = dynamic(
|
||||
() => import('@fastgpt/web/components/common/MyModal/EditFolderModal')
|
||||
@@ -138,7 +139,7 @@ const Dataset = () => {
|
||||
|
||||
{(folderDetail
|
||||
? folderDetail.permission.hasWritePer
|
||||
: userInfo?.team?.permission.hasWritePer) && (
|
||||
: userInfo?.team?.permission.hasDatasetCreatePer) && (
|
||||
<Box pl={[0, 4]}>
|
||||
<MyMenu
|
||||
size="md"
|
||||
@@ -248,7 +249,7 @@ const Dataset = () => {
|
||||
}: {
|
||||
members?: string[];
|
||||
groups?: string[];
|
||||
permission: number;
|
||||
permission: PermissionValueType;
|
||||
}) =>
|
||||
postUpdateDatasetCollaborators({
|
||||
members,
|
||||
|
||||
Reference in New Issue
Block a user