mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-22 20:37:48 +00:00
fix: invite link (#4229)
* fix: invite link * feat: create invite link and copy it directly
This commit is contained in:
@@ -1,15 +1,18 @@
|
||||
import {
|
||||
TeamCollectionName,
|
||||
TeamMemberCollectionName
|
||||
} from '@fastgpt/global/support/user/team/constant';
|
||||
import { TeamCollectionName } from '@fastgpt/global/support/user/team/constant';
|
||||
import { connectionMongo, getMongoModel } from '../../../../common/mongo';
|
||||
import { InvitationSchemaType } from './type';
|
||||
import addDays from 'date-fns/esm/fp/addDays/index.js';
|
||||
import { randomUUID } from 'crypto';
|
||||
const { Schema } = connectionMongo;
|
||||
|
||||
export const InvitationCollectionName = 'team_invitation_links';
|
||||
|
||||
const InvitationSchema = new Schema({
|
||||
linkId: {
|
||||
type: String,
|
||||
required: true,
|
||||
unique: true,
|
||||
default: () => randomUUID()
|
||||
},
|
||||
teamId: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: TeamCollectionName,
|
||||
|
@@ -2,6 +2,7 @@ import { TeamMemberSchema } from '@fastgpt/global/support/user/team/type';
|
||||
|
||||
export type InvitationSchemaType = {
|
||||
_id: string;
|
||||
linkId: string;
|
||||
teamId: string;
|
||||
usedTimesLimit?: number;
|
||||
forbidden?: boolean;
|
||||
@@ -25,11 +26,10 @@ export type InvitationLinkCreateType = {
|
||||
expires: InvitationLinkExpiresType;
|
||||
usedTimesLimit: 1 | -1;
|
||||
};
|
||||
export type InvitationLinkUpdateType = Partial<
|
||||
Omit<InvitationSchemaType, 'members' | 'teamId' | '_id'>
|
||||
> & {
|
||||
linkId: string;
|
||||
};
|
||||
|
||||
// export type InvitationLinkUpdateType = Partial<
|
||||
// Omit<InvitationSchemaType, 'members' | 'teamId' | '_id'>
|
||||
// >;
|
||||
|
||||
export type InvitationInfoType = InvitationSchemaType & {
|
||||
teamAvatar: string;
|
||||
|
@@ -22,7 +22,7 @@ import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useForm } from 'react-hook-form';
|
||||
|
||||
function CreateInvitationModal({ onClose }: { onClose: () => void }) {
|
||||
function CreateInvitationModal({ onClose }: { onClose: (linkId?: string) => void }) {
|
||||
const { t } = useTranslation();
|
||||
const expiresOptions: Array<{ label: string; value: InvitationLinkExpiresType }> = [
|
||||
{ label: t('account_team:30mins'), value: '30m' }, // 30 mins
|
||||
@@ -45,6 +45,9 @@ function CreateInvitationModal({ onClose }: { onClose: () => void }) {
|
||||
manual: true,
|
||||
successToast: t('common:common.Create Success'),
|
||||
errorToast: t('common:common.Create Failed'),
|
||||
onSuccess: (data) => {
|
||||
onClose(data);
|
||||
},
|
||||
onFinally: () => onClose()
|
||||
});
|
||||
|
||||
@@ -55,7 +58,7 @@ function CreateInvitationModal({ onClose }: { onClose: () => void }) {
|
||||
iconColor="primary.500"
|
||||
title={<Box>{t('account_team:create_invitation_link')}</Box>}
|
||||
>
|
||||
<ModalCloseButton onClick={onClose} />
|
||||
<ModalCloseButton onClick={() => onClose()} />
|
||||
<ModalBody>
|
||||
<Grid gap={6} templateColumns="max-content 1fr" alignItems="center">
|
||||
<>
|
||||
@@ -91,7 +94,7 @@ function CreateInvitationModal({ onClose }: { onClose: () => void }) {
|
||||
</Grid>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button isLoading={loading} onClick={onClose} variant="outline">
|
||||
<Button isLoading={loading} onClick={() => onClose()} variant="outline">
|
||||
{t('common:common.Cancel')}
|
||||
</Button>
|
||||
<Button isLoading={loading} onClick={handleSubmit(createInvitationLink)} ml="4">
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import MemberTag from '@/components/support/user/team/Info/MemberTag';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import { getInvitationLinkList, putUpdateInvitationInfo } from '@/web/support/user/team/api';
|
||||
import { getInvitationLinkList, putForbidInvitationLink } from '@/web/support/user/team/api';
|
||||
import { useUserStore } from '@/web/support/user/useUserStore';
|
||||
import {
|
||||
Box,
|
||||
@@ -79,18 +79,11 @@ const InviteModal = ({
|
||||
[copyData]
|
||||
);
|
||||
|
||||
const { runAsync: onForbid, loading: forbiding } = useRequest2(
|
||||
(linkId: string) =>
|
||||
putUpdateInvitationInfo({
|
||||
linkId,
|
||||
forbidden: true
|
||||
}),
|
||||
{
|
||||
manual: true,
|
||||
onSuccess: refetchInvitationLinkList,
|
||||
successToast: t('account_team:forbid_success')
|
||||
}
|
||||
);
|
||||
const { runAsync: onForbid, loading: forbiding } = useRequest2(putForbidInvitationLink, {
|
||||
manual: true,
|
||||
onSuccess: refetchInvitationLinkList,
|
||||
successToast: t('account_team:forbid_success')
|
||||
});
|
||||
|
||||
return (
|
||||
<MyModal
|
||||
@@ -134,7 +127,7 @@ const InviteModal = ({
|
||||
{invitationLinkList?.map((item) => {
|
||||
const isForbidden = item.forbidden || new Date(item.expires) < new Date();
|
||||
return (
|
||||
<Tr key={item._id} overflow={'unset'}>
|
||||
<Tr key={item.linkId} overflow={'unset'}>
|
||||
<Td maxW="200px" minW="100px">
|
||||
{item.description}
|
||||
</Td>
|
||||
@@ -209,7 +202,7 @@ const InviteModal = ({
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
onClick={() => onCopy(item._id)}
|
||||
onClick={() => onCopy(item.linkId)}
|
||||
color="myGray.900"
|
||||
>
|
||||
<Icon name="common/link" w="16px" mr="1" />
|
||||
@@ -239,7 +232,7 @@ const InviteModal = ({
|
||||
variant="outline"
|
||||
colorScheme="red"
|
||||
onClick={() => {
|
||||
onForbid(item._id);
|
||||
onForbid(item.linkId);
|
||||
onClosePopover();
|
||||
}}
|
||||
>
|
||||
@@ -268,7 +261,17 @@ const InviteModal = ({
|
||||
</ModalFooter>
|
||||
{isOpenCreate && (
|
||||
<CreateInvitationModal
|
||||
onClose={() => Promise.all([onCloseCreate(), refetchInvitationLinkList()])}
|
||||
onClose={(linkId?: string) =>
|
||||
Promise.all([
|
||||
onCloseCreate(),
|
||||
refetchInvitationLinkList(),
|
||||
(() => {
|
||||
if (linkId) {
|
||||
onCopy(linkId);
|
||||
}
|
||||
})()
|
||||
])
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</MyModal>
|
||||
|
@@ -21,7 +21,6 @@ import type { PaginationProps, PaginationResponse } from '@fastgpt/web/common/fe
|
||||
import type {
|
||||
InvitationInfoType,
|
||||
InvitationLinkCreateType,
|
||||
InvitationLinkUpdateType,
|
||||
InvitationType
|
||||
} from '@fastgpt/service/support/user/team/invitationLink/type';
|
||||
|
||||
@@ -66,9 +65,8 @@ export const postAcceptInvitationLink = (linkId: string) =>
|
||||
|
||||
export const getInvitationInfo = (linkId: string) =>
|
||||
GET<InvitationInfoType>(`/proApi/support/user/team/invitationLink/info`, { linkId });
|
||||
|
||||
export const putUpdateInvitationInfo = (data: InvitationLinkUpdateType) =>
|
||||
PUT('/proApi/support/user/team/invitationLink/update', data);
|
||||
export const putForbidInvitationLink = (linkId: string) =>
|
||||
PUT<string>(`/proApi/support/user/team/invitationLink/forbid`, { linkId });
|
||||
|
||||
/* -------------- team collaborator -------------------- */
|
||||
export const getTeamClbs = () =>
|
||||
|
@@ -32,3 +32,32 @@ export async function getRootUser(): Promise<parseHeaderCertRet> {
|
||||
tmbId: tmb?._id
|
||||
};
|
||||
}
|
||||
|
||||
export async function getUser(username: string): Promise<parseHeaderCertRet> {
|
||||
const user = await MongoUser.create({
|
||||
username,
|
||||
password: '123456'
|
||||
});
|
||||
|
||||
const team = await MongoTeam.create({
|
||||
name: 'test team',
|
||||
ownerId: user._id
|
||||
});
|
||||
|
||||
const tmb = await MongoTeamMember.create({
|
||||
teamId: team._id,
|
||||
userId: user._id,
|
||||
status: 'active'
|
||||
});
|
||||
|
||||
return {
|
||||
userId: user._id,
|
||||
apikey: '',
|
||||
appId: '',
|
||||
authType: AuthUserTypeEnum.token,
|
||||
isRoot: false,
|
||||
sourceName: undefined,
|
||||
teamId: tmb?.teamId,
|
||||
tmbId: tmb?._id
|
||||
};
|
||||
}
|
||||
|
Reference in New Issue
Block a user