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

perf: captcha code #2620

Merged
merged 2 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
7 changes: 5 additions & 2 deletions packages/web/i18n/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -647,7 +647,8 @@
"success": "Start syncing"
}
},
"training": {}
"training": {
}
},
"data": {
"Auxiliary Data": "Auxiliary data",
Expand Down Expand Up @@ -1084,13 +1085,15 @@
"default_reply": "Default reply",
"error": {
"Create failed": "Create failed",
"code_error": "Code error",
"fileNotFound": "File not found~",
"inheritPermissionError": "Inherit permission Error",
"missingParams": "Insufficient parameters",
"team": {
"overSize": "Team members exceed the limit"
},
"upload_file_error_filename": "{{name}} upload failed"
"upload_file_error_filename": "{{name}} upload failed",
"username_empty": "Account cannot be empty"
},
"extraction_results": "Extract results",
"field_name": "Name",
Expand Down
9 changes: 6 additions & 3 deletions packages/web/i18n/zh/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -647,7 +647,8 @@
"success": "开始同步"
}
},
"training": {}
"training": {
}
},
"data": {
"Auxiliary Data": "辅助数据",
Expand Down Expand Up @@ -1084,13 +1085,15 @@
"default_reply": "默认回复",
"error": {
"Create failed": "创建失败",
"code_error": "验证码错误",
"fileNotFound": "文件找不到了~",
"inheritPermissionError": "权限继承错误",
"missingParams": "参数缺失",
"team": {
"overSize": "团队成员超出上限"
},
"upload_file_error_filename": "{{name}} 上传失败"
"upload_file_error_filename": "{{name}} 上传失败",
"username_empty": "账号不能为空"
},
"extraction_results": "提取结果",
"field_name": "字段名",
Expand Down Expand Up @@ -1247,7 +1250,6 @@
},
"user": {
"Avatar": "头像",
"captcha_placeholder": "请输入验证码",
"Go laf env": "点击前往 {{env}} 获取 PAT 凭证。",
"Laf account course": "查看绑定 laf 账号教程。",
"Laf account intro": "绑定你的 laf 账号后,你将可以在工作流中使用 laf 模块,实现在线编写代码。",
Expand All @@ -1257,6 +1259,7 @@
"auth": {
"Sending Code": "正在发送"
},
"captcha_placeholder": "请输入验证码",
"inform": {
"System message": "系统消息"
},
Expand Down
4 changes: 2 additions & 2 deletions projects/app/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ COPY ./projects/app/data /app/data

RUN chown -R nextjs:nodejs /app/data

ENV NODE_ENV production
ENV NEXT_TELEMETRY_DISABLED 1
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
ENV PORT=3000

EXPOSE 3000
Expand Down
76 changes: 45 additions & 31 deletions projects/app/src/components/support/user/safe/SendCodeAuthModal.tsx
Original file line number Diff line number Diff line change
@@ -1,58 +1,72 @@
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 { Button, Input, Image, ModalBody, ModalFooter, Skeleton } from '@chakra-ui/react';
import MyModal from '@fastgpt/web/components/common/MyModal';
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
import { useTranslation } from 'next-i18next';
import { useState } from 'react';
import { useForm } from 'react-hook-form';

const SendCodeAuthModal = ({
username,
type,
onClose
onClose,
onSending,
onSendCode
}: {
username: string;
type: UserAuthTypeEnum;
onClose: () => void;

onSending: boolean;
onSendCode: (params_0: { username: string; captcha: string }) => Promise<void>;
}) => {
const { t } = useTranslation();
const [captchaInput, setCaptchaInput] = useState('');
const { codeSending, sendCode } = useSendCode();

const { register, handleSubmit } = useForm({
defaultValues: {
code: ''
}
});

const {
data,
loading,
runAsync: getCaptcha
} = useRequest2(() => getCaptchaPic(username), { manual: false });

return (
<MyModal isOpen={true} isLoading={loading}>
<MyModal isOpen={true}>
<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)}
/>
<Skeleton
minH="200px"
isLoaded={!loading}
fadeDuration={2}
display={'flex'}
justifyContent={'center'}
my={1}
>
<Image
borderRadius={'md'}
w={'100%'}
h={'200px'}
_hover={{ cursor: 'pointer' }}
mb={8}
onClick={getCaptcha}
src={data?.captchaImage}
alt=""
/>
</Skeleton>

<Input placeholder={t('common:support.user.captcha_placeholder')} {...register('code')} />
</ModalBody>
<ModalFooter gap={2}>
<Button isLoading={codeSending} variant={'whiteBase'} onClick={onClose}>
<Button isLoading={onSending} variant={'whiteBase'} onClick={onClose}>
{t('common:common.Cancel')}
</Button>
<Button
isLoading={codeSending}
onClick={async () => {
await sendCode({ username, type, captcha: captchaInput });
onClose();
}}
isLoading={onSending}
onClick={handleSubmit(({ code }) => {
return onSendCode({ username, captcha: code }).then(() => {
onClose();
});
})}
>
{t('common:common.Confirm')}
</Button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ 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 @@ -30,19 +28,16 @@ const UpdateNotificationModal = ({ onClose }: { onClose: () => void }) => {
const { t } = useTranslation();
const { initUserInfo } = useUserStore();
const { feConfigs } = useSystemStore();
const { register, handleSubmit, trigger, getValues, watch } = useForm<FormType>({

const { register, handleSubmit, watch } = useForm<FormType>({
defaultValues: {
account: '',
verifyCode: ''
}
});
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 @@ -57,13 +52,7 @@ const UpdateNotificationModal = ({ onClose }: { onClose: () => void }) => {
}
);

const { sendCodeText, codeCountDown } = useSendCode();

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

const placeholder = feConfigs?.bind_notification_method
?.map((item) => {
Expand Down Expand Up @@ -107,23 +96,7 @@ const UpdateNotificationModal = ({ onClose }: { onClose: () => void }) => {
{...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>
<SendCodeBox username={account} />
</Flex>
</Flex>
</ModalBody>
Expand All @@ -140,13 +113,6 @@ const UpdateNotificationModal = ({ onClose }: { onClose: () => void }) => {
</Button>
</ModalFooter>
</MyModal>
{openCodeAuthModal && (
<SendCodeAuthModal
onClose={onCloseCodeAuthModal}
username={getValues('account')}
type={UserAuthTypeEnum.bindNotification}
/>
)}
</>
);
};
Expand Down
82 changes: 21 additions & 61 deletions projects/app/src/pages/login/components/ForgetPasswordForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +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';
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';

interface Props {
setPageType: Dispatch<`${LoginPageTypeEnum}`>;
loginSuccess: (e: ResLogin) => void;
Expand All @@ -30,25 +30,15 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
register,
handleSubmit,
getValues,
trigger,
watch,
formState: { errors }
} = useForm<RegisterType>({
mode: 'onBlur'
});
const username = watch('username');

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

const [requesting, setRequesting] = useState(false);
const placeholder = feConfigs?.find_password_method
?.map((item) => {
switch (item) {
Expand All @@ -62,30 +52,23 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
})
.join('/');

const onclickFindPassword = useCallback(
const { runAsync: onclickFindPassword, loading: requesting } = useRequest2(
async ({ username, code, password }: RegisterType) => {
setRequesting(true);
try {
loginSuccess(
await postFindPassword({
username,
code,
password
})
);
toast({
title: t('user:password.retrieved'),
status: 'success'
});
} catch (error: any) {
toast({
title: error.message || t('user:password.change_error'),
status: 'error'
});
}
setRequesting(false);
loginSuccess(
await postFindPassword({
username,
code,
password
})
);
toast({
status: 'success',
title: t('user:password.retrieved')
});
},
[loginSuccess, toast]
{
refreshDeps: [loginSuccess, t, toast]
}
);

return (
Expand Down Expand Up @@ -131,23 +114,7 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
required: t('user:password.code_required')
})}
></Input>
<Box
position={'absolute'}
right={3}
zIndex={1}
fontSize={'sm'}
{...(codeCountDown > 0
? {
color: 'myGray.500'
}
: {
color: 'primary.700',
cursor: 'pointer',
onClick: onclickSendCode
})}
>
{sendCodeText}
</Box>
<SendCodeBox username={username} />
</FormControl>
<FormControl mt={6} isInvalid={!!errors.password}>
<Input
Expand Down Expand Up @@ -203,13 +170,6 @@ 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