Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add captcha #2613

Merged
merged 3 commits into from
Sep 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions packages/global/support/user/auth/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ export enum UserAuthTypeEnum {
register = 'register',
findPassword = 'findPassword',
wxLogin = 'wxLogin',
bindNotification = 'bindNotification'
bindNotification = 'bindNotification',
captcha = 'captcha'
}

export const userAuthTypeMap = {
[UserAuthTypeEnum.register]: 'register',
[UserAuthTypeEnum.findPassword]: 'findPassword',
[UserAuthTypeEnum.wxLogin]: 'wxLogin',
[UserAuthTypeEnum.bindNotification]: 'bindNotification'
[UserAuthTypeEnum.bindNotification]: 'bindNotification',
[UserAuthTypeEnum.captcha]: 'captcha'
};
4 changes: 2 additions & 2 deletions packages/web/i18n/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -647,8 +647,7 @@
"success": "Start syncing"
}
},
"training": {
}
"training": {}
},
"data": {
"Auxiliary Data": "Auxiliary data",
Expand Down Expand Up @@ -1257,6 +1256,7 @@
"auth": {
"Sending Code": "Sending"
},
"captcha_placeholder": "Please enter the verification code",
"inform": {
"System message": "System message"
},
Expand Down
4 changes: 2 additions & 2 deletions packages/web/i18n/zh/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -647,8 +647,7 @@
"success": "开始同步"
}
},
"training": {
}
"training": {}
},
"data": {
"Auxiliary Data": "辅助数据",
Expand Down Expand Up @@ -1248,6 +1247,7 @@
},
"user": {
"Avatar": "头像",
"captcha_placeholder": "请输入验证码",
"Go laf env": "点击前往 {{env}} 获取 PAT 凭证。",
"Laf account course": "查看绑定 laf 账号教程。",
"Laf account intro": "绑定你的 laf 账号后,你将可以在工作流中使用 laf 模块,实现在线编写代码。",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { getCaptchaPic } from '@/web/support/user/api';
import { useSendCode } from '@/web/support/user/hooks/useSendCode';
import { Box, Button, Input, Image, ModalBody, ModalFooter } from '@chakra-ui/react';
import { UserAuthTypeEnum } from '@fastgpt/global/support/user/auth/constants';
import MyModal from '@fastgpt/web/components/common/MyModal';
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
import { useTranslation } from 'next-i18next';
import { useState } from 'react';

const SendCodeAuthModal = ({
username,
type,
onClose
}: {
username: string;
type: UserAuthTypeEnum;
onClose: () => void;
}) => {
const { t } = useTranslation();
const [captchaInput, setCaptchaInput] = useState('');
const { codeSending, sendCode } = useSendCode();
const {
data,
loading,
runAsync: getCaptcha
} = useRequest2(() => getCaptchaPic(username), { manual: false });
return (
<MyModal isOpen={true} isLoading={loading}>
<ModalBody pt={8}>
<Image
borderRadius={'md'}
w={'100%'}
h={'200px'}
_hover={{ cursor: 'pointer' }}
mb={8}
onClick={getCaptcha}
src={data?.captchaImage}
alt="captcha"
/>
<Input
placeholder={t('common:support.user.captcha_placeholder')}
value={captchaInput}
onChange={(e) => setCaptchaInput(e.target.value)}
/>
</ModalBody>
<ModalFooter gap={2}>
<Button isLoading={codeSending} variant={'whiteBase'} onClick={onClose}>
{t('common:common.Cancel')}
</Button>
<Button
isLoading={codeSending}
onClick={async () => {
await sendCode({ username, type, captcha: captchaInput });
onClose();
}}
>
{t('common:common.Confirm')}
</Button>
</ModalFooter>
</MyModal>
);
};

export default SendCodeAuthModal;
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
import React, { useCallback } from 'react';
import { ModalBody, Box, Flex, Input, ModalFooter, Button, HStack } from '@chakra-ui/react';
import {
ModalBody,
Box,
Flex,
Input,
ModalFooter,
Button,
HStack,
useDisclosure
} from '@chakra-ui/react';
import MyModal from '@fastgpt/web/components/common/MyModal';
import { useTranslation } from 'next-i18next';
import { useForm } from 'react-hook-form';
Expand All @@ -9,6 +18,8 @@ import Icon from '@fastgpt/web/components/common/Icon';
import { useSendCode } from '@/web/support/user/hooks/useSendCode';
import { useUserStore } from '@/web/support/user/useUserStore';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import SendCodeAuthModal from '@/components/support/user/safe/SendCodeAuthModal';
import { UserAuthTypeEnum } from '@fastgpt/global/support/user/auth/constants';

type FormType = {
account: string;
Expand All @@ -27,7 +38,11 @@ const UpdateNotificationModal = ({ onClose }: { onClose: () => void }) => {
});
const account = watch('account');
const verifyCode = watch('verifyCode');

const {
isOpen: openCodeAuthModal,
onOpen: onOpenCodeAuthModal,
onClose: onCloseCodeAuthModal
} = useDisclosure();
const { runAsync: onSubmit, loading: isLoading } = useRequest2(
(data: FormType) => {
return updateNotificationAccount(data);
Expand All @@ -42,16 +57,13 @@ const UpdateNotificationModal = ({ onClose }: { onClose: () => void }) => {
}
);

const { sendCodeText, sendCode, codeCountDown } = useSendCode();
const { sendCodeText, codeCountDown } = useSendCode();

const onclickSendCode = useCallback(async () => {
const check = await trigger('account');
if (!check) return;
sendCode({
username: getValues('account'),
type: 'bindNotification'
});
}, [getValues, sendCode, trigger]);
onOpenCodeAuthModal();
}, [onOpenCodeAuthModal, trigger]);

const placeholder = feConfigs?.bind_notification_method
?.map((item) => {
Expand All @@ -65,68 +77,77 @@ const UpdateNotificationModal = ({ onClose }: { onClose: () => void }) => {
.join('/');

return (
<MyModal
isOpen
iconSrc="common/settingLight"
w={'32rem'}
title={t('common:user.Notification Receive')}
>
<ModalBody px={10}>
<Flex flexDirection="column">
<HStack px="6" py="3" color="primary.600" bgColor="primary.50" borderRadius="md">
<Icon name="common/info" w="1rem" />
<Box fontSize={'sm'}>{t('user:notification.Bind Notification Pipe Hint')}</Box>
</HStack>
<Flex mt="4" alignItems="center">
<Box flex={'0 0 70px'}>{t('common:user.Account')}</Box>
<Input
flex={1}
bg={'myGray.50'}
{...register('account', { required: true })}
placeholder={placeholder}
></Input>
</Flex>
<Flex mt="6" alignItems="center" position={'relative'}>
<Box flex={'0 0 70px'}>{t('user:password.verification_code')}</Box>
<Input
flex={1}
bg={'myGray.50'}
{...register('verifyCode', { required: true })}
placeholder={t('user:password.code_required')}
></Input>
<Box
position={'absolute'}
right={2}
zIndex={1}
fontSize={'sm'}
{...(codeCountDown > 0
? {
color: 'myGray.500'
}
: {
color: 'primary.700',
cursor: 'pointer',
onClick: onclickSendCode
})}
>
{sendCodeText}
</Box>
<>
<MyModal
isOpen
iconSrc="common/settingLight"
w={'32rem'}
title={t('common:user.Notification Receive')}
>
<ModalBody px={10}>
<Flex flexDirection="column">
<HStack px="6" py="3" color="primary.600" bgColor="primary.50" borderRadius="md">
<Icon name="common/info" w="1rem" />
<Box fontSize={'sm'}>{t('user:notification.Bind Notification Pipe Hint')}</Box>
</HStack>
<Flex mt="4" alignItems="center">
<Box flex={'0 0 70px'}>{t('common:user.Account')}</Box>
<Input
flex={1}
bg={'myGray.50'}
{...register('account', { required: true })}
placeholder={placeholder}
></Input>
</Flex>
<Flex mt="6" alignItems="center" position={'relative'}>
<Box flex={'0 0 70px'}>{t('user:password.verification_code')}</Box>
<Input
flex={1}
bg={'myGray.50'}
{...register('verifyCode', { required: true })}
placeholder={t('user:password.code_required')}
></Input>
<Box
position={'absolute'}
right={2}
zIndex={1}
fontSize={'sm'}
{...(codeCountDown > 0
? {
color: 'myGray.500'
}
: {
color: 'primary.700',
cursor: 'pointer',
onClick: onclickSendCode
})}
>
{sendCodeText}
</Box>
</Flex>
</Flex>
</Flex>
</ModalBody>
<ModalFooter>
<Button mr={3} variant={'whiteBase'} onClick={onClose}>
{t('common:common.Cancel')}
</Button>
<Button
isLoading={isLoading}
isDisabled={!account || !verifyCode}
onClick={handleSubmit((data) => onSubmit(data))}
>
{t('common:common.Confirm')}
</Button>
</ModalFooter>
</MyModal>
</ModalBody>
<ModalFooter>
<Button mr={3} variant={'whiteBase'} onClick={onClose}>
{t('common:common.Cancel')}
</Button>
<Button
isLoading={isLoading}
isDisabled={!account || !verifyCode}
onClick={handleSubmit((data) => onSubmit(data))}
>
{t('common:common.Confirm')}
</Button>
</ModalFooter>
</MyModal>
{openCodeAuthModal && (
<SendCodeAuthModal
onClose={onCloseCodeAuthModal}
username={getValues('account')}
type={UserAuthTypeEnum.bindNotification}
/>
)}
</>
);
};

Expand Down
26 changes: 18 additions & 8 deletions projects/app/src/pages/login/components/ForgetPasswordForm.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useState, Dispatch, useCallback } from 'react';
import { FormControl, Box, Input, Button } from '@chakra-ui/react';
import { FormControl, Box, Input, Button, useDisclosure } from '@chakra-ui/react';
import { useForm } from 'react-hook-form';
import { LoginPageTypeEnum } from '@/web/support/user/login/constants';
import { postFindPassword } from '@/web/support/user/api';
Expand All @@ -8,6 +8,8 @@ import type { ResLogin } from '@/global/support/api/userRes.d';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import { useTranslation } from 'next-i18next';
import { UserAuthTypeEnum } from '@fastgpt/global/support/user/auth/constants';
import SendCodeAuthModal from '@/components/support/user/safe/SendCodeAuthModal';
interface Props {
setPageType: Dispatch<`${LoginPageTypeEnum}`>;
loginSuccess: (e: ResLogin) => void;
Expand All @@ -34,16 +36,17 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
mode: 'onBlur'
});

const { codeSending, sendCodeText, sendCode, codeCountDown } = useSendCode();

const { sendCodeText, codeCountDown } = useSendCode();
const {
isOpen: openCodeAuthModal,
onOpen: onOpenCodeAuthModal,
onClose: onCloseCodeAuthModal
} = useDisclosure();
const onclickSendCode = useCallback(async () => {
const check = await trigger('username');
if (!check) return;
sendCode({
username: getValues('username'),
type: 'findPassword'
});
}, [getValues, sendCode, trigger]);
onOpenCodeAuthModal();
}, [onOpenCodeAuthModal, trigger]);

const [requesting, setRequesting] = useState(false);
const placeholder = feConfigs?.find_password_method
Expand Down Expand Up @@ -200,6 +203,13 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
{t('user:password.to_login')}
</Box>
</Box>
{openCodeAuthModal && (
<SendCodeAuthModal
onClose={onCloseCodeAuthModal}
username={getValues('username')}
type={UserAuthTypeEnum.findPassword}
/>
)}
</>
);
};
Expand Down
Loading
Loading