Commit faf722fa by archer

feat: 手机验证码作为用户凭证

parent 36dad6df
...@@ -11,6 +11,9 @@ ...@@ -11,6 +11,9 @@
"format": "prettier --config \"./.prettierrc.js\" --write \"./src/**/*.{ts,tsx,scss}\"" "format": "prettier --config \"./.prettierrc.js\" --write \"./src/**/*.{ts,tsx,scss}\""
}, },
"dependencies": { "dependencies": {
"@alicloud/dysmsapi20170525": "^2.0.23",
"@alicloud/openapi-client": "^0.4.5",
"@alicloud/tea-util": "^1.4.5",
"@chakra-ui/icons": "^2.0.17", "@chakra-ui/icons": "^2.0.17",
"@chakra-ui/react": "^2.5.1", "@chakra-ui/react": "^2.5.1",
"@emotion/react": "^11.10.6", "@emotion/react": "^11.10.6",
......
...@@ -9,7 +9,7 @@ wx号: fastgpt123 ...@@ -9,7 +9,7 @@ wx号: fastgpt123
### 快速开始 ### 快速开始
1. 使用邮箱注册账号。 1. 使用手机号注册账号。
2. 进入账号页面,添加关联账号,目前只有 openai 的账号可以添加,直接去 openai 官网,把 API Key 粘贴过来。 2. 进入账号页面,添加关联账号,目前只有 openai 的账号可以添加,直接去 openai 官网,把 API Key 粘贴过来。
3. 如果填写了自己的 openai 账号,使用时会直接用你的账号。如果没有填写,需要付费使用平台的账号。 3. 如果填写了自己的 openai 账号,使用时会直接用你的账号。如果没有填写,需要付费使用平台的账号。
4. 进入模型页,创建一个模型,建议直接用 ChatGPT。 4. 进入模型页,创建一个模型,建议直接用 ChatGPT。
......
import { GET, POST, PUT } from './request'; import { GET, POST, PUT } from './request';
import { createHashPassword, Obj2Query } from '@/utils/tools'; import { createHashPassword, Obj2Query } from '@/utils/tools';
import { ResLogin } from './response/user'; import { ResLogin } from './response/user';
import { EmailTypeEnum } from '@/constants/common'; import { UserAuthTypeEnum } from '@/constants/common';
import { UserType, UserUpdateParams } from '@/types/user'; import { UserType, UserUpdateParams } from '@/types/user';
import type { PagingData, RequestPaging } from '@/types'; import type { PagingData, RequestPaging } from '@/types';
import { BillSchema, PaySchema } from '@/types/mongoSchema'; import { BillSchema, PaySchema } from '@/types/mongoSchema';
import { adaptBill } from '@/utils/adapt'; import { adaptBill } from '@/utils/adapt';
export const sendCodeToEmail = ({ email, type }: { email: string; type: `${EmailTypeEnum}` }) => export const sendAuthCode = ({
GET('/user/sendEmail', { email, type }); username,
type
}: {
username: string;
type: `${UserAuthTypeEnum}`;
}) => GET('/user/sendAuthCode', { username, type });
export const getTokenLogin = () => GET<UserType>('/user/tokenLogin'); export const getTokenLogin = () => GET<UserType>('/user/tokenLogin');
export const postRegister = ({ export const postRegister = ({
email, phone,
password, password,
code code
}: { }: {
email: string; phone: string;
code: string; code: string;
password: string; password: string;
}) => }) =>
POST<ResLogin>('/user/register', { POST<ResLogin>('/user/register', {
email, phone,
code, code,
password: createHashPassword(password) password: createHashPassword(password)
}); });
export const postFindPassword = ({ export const postFindPassword = ({
email, username,
code, code,
password password
}: { }: {
email: string; username: string;
code: string; code: string;
password: string; password: string;
}) => }) =>
POST<ResLogin>('/user/updatePasswordByCode', { POST<ResLogin>('/user/updatePasswordByCode', {
email, username,
code, code,
password: createHashPassword(password) password: createHashPassword(password)
}); });
export const postLogin = ({ email, password }: { email: string; password: string }) => export const postLogin = ({ username, password }: { username: string; password: string }) =>
POST<ResLogin>('/user/loginByPassword', { POST<ResLogin>('/user/loginByPassword', {
email, username,
password: createHashPassword(password) password: createHashPassword(password)
}); });
......
export enum EmailTypeEnum { export enum UserAuthTypeEnum {
register = 'register', register = 'register',
findPassword = 'findPassword' findPassword = 'findPassword'
} }
......
import { useState, useMemo, useCallback } from 'react'; import { useState, useMemo, useCallback } from 'react';
import { sendCodeToEmail } from '@/api/user'; import { sendAuthCode } from '@/api/user';
import { EmailTypeEnum } from '@/constants/common'; import { UserAuthTypeEnum } from '@/constants/common';
let timer: any; let timer: any;
import { useToast } from './useToast'; import { useToast } from './useToast';
...@@ -19,11 +19,11 @@ export const useSendCode = () => { ...@@ -19,11 +19,11 @@ export const useSendCode = () => {
}, [codeCountDown]); }, [codeCountDown]);
const sendCode = useCallback( const sendCode = useCallback(
async ({ email, type }: { email: string; type: `${EmailTypeEnum}` }) => { async ({ username, type }: { username: string; type: `${UserAuthTypeEnum}` }) => {
setCodeSending(true); setCodeSending(true);
try { try {
await sendCodeToEmail({ await sendAuthCode({
email, username,
type type
}); });
setCodeCountDown(60); setCodeCountDown(60);
......
...@@ -7,24 +7,24 @@ import { generateToken } from '@/service/utils/tools'; ...@@ -7,24 +7,24 @@ import { generateToken } from '@/service/utils/tools';
export default async function handler(req: NextApiRequest, res: NextApiResponse) { export default async function handler(req: NextApiRequest, res: NextApiResponse) {
try { try {
const { email, password } = req.body; const { username, password } = req.body;
if (!email || !password) { if (!username || !password) {
throw new Error('缺少参数'); throw new Error('缺少参数');
} }
await connectToDatabase(); await connectToDatabase();
// 检测邮箱是否存在 // 检测用户是否存在
const authEmail = await User.findOne({ const authUser = await User.findOne({
email username
}); });
if (!authEmail) { if (!authUser) {
throw new Error('邮箱未注册'); throw new Error('用户未注册');
} }
const user = await User.findOne({ const user = await User.findOne({
email, username,
password password
}); });
......
...@@ -5,23 +5,29 @@ import { User } from '@/service/models/user'; ...@@ -5,23 +5,29 @@ import { User } from '@/service/models/user';
import { AuthCode } from '@/service/models/authCode'; import { AuthCode } from '@/service/models/authCode';
import { connectToDatabase } from '@/service/mongo'; import { connectToDatabase } from '@/service/mongo';
import { generateToken } from '@/service/utils/tools'; import { generateToken } from '@/service/utils/tools';
import { EmailTypeEnum } from '@/constants/common'; import { UserAuthTypeEnum } from '@/constants/common';
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) { export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try { try {
const { email, code, password } = req.body; const { phone, code, password } = req.body;
if (!email || !code || !password) { if (!phone || !code || !password) {
throw new Error('缺少参数'); throw new Error('缺少参数');
} }
const reg = /^1[3456789]\d{9}$/;
if (!reg.test(phone)) {
throw new Error('手机号格式错误');
}
await connectToDatabase(); await connectToDatabase();
// 验证码校验 // 验证码校验. 注册只接收手机号
const authCode = await AuthCode.findOne({ const authCode = await AuthCode.findOne({
email, username: phone,
code, code,
type: EmailTypeEnum.register, type: UserAuthTypeEnum.register,
expiredTime: { $gte: Date.now() } expiredTime: { $gte: Date.now() }
}); });
...@@ -31,15 +37,15 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse< ...@@ -31,15 +37,15 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
// 重名校验 // 重名校验
const authRepeat = await User.findOne({ const authRepeat = await User.findOne({
email username: phone
}); });
if (authRepeat) { if (authRepeat) {
throw new Error('邮箱已被注册'); throw new Error('手机号已被注册');
} }
const response = await User.create({ const response = await User.create({
email, username: phone,
password password
}); });
...@@ -50,6 +56,11 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse< ...@@ -50,6 +56,11 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
throw new Error('获取用户信息异常'); throw new Error('获取用户信息异常');
} }
// 删除验证码记录
await AuthCode.deleteMany({
username: phone
});
jsonRes(res, { jsonRes(res, {
data: { data: {
token: generateToken(user._id), token: generateToken(user._id),
......
...@@ -2,28 +2,27 @@ ...@@ -2,28 +2,27 @@
import type { NextApiRequest, NextApiResponse } from 'next'; import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@/service/response'; import { jsonRes } from '@/service/response';
import { AuthCode } from '@/service/models/authCode'; import { AuthCode } from '@/service/models/authCode';
import { connectToDatabase, User } from '@/service/mongo'; import { connectToDatabase } from '@/service/mongo';
import { sendCode } from '@/service/utils/sendEmail'; import { sendPhoneCode, sendEmailCode } from '@/service/utils/sendNote';
import { EmailTypeEnum } from '@/constants/common'; import { UserAuthTypeEnum } from '@/constants/common';
import { customAlphabet } from 'nanoid';
const nanoid = customAlphabet('1234567890', 6);
export default async function handler(req: NextApiRequest, res: NextApiResponse) { export default async function handler(req: NextApiRequest, res: NextApiResponse) {
try { try {
const { email, type } = req.query as { email: string; type: `${EmailTypeEnum}` }; const { username, type } = req.query as { username: string; type: `${UserAuthTypeEnum}` };
if (!email || !type) { if (!username || !type) {
throw new Error('缺少参数'); throw new Error('缺少参数');
} }
await connectToDatabase(); await connectToDatabase();
let code = ''; let code = nanoid();
for (let i = 0; i < 6; i++) {
code += Math.floor(Math.random() * 10);
}
// 判断 1 分钟内是否有重复数据 // 判断 1 分钟内是否有重复数据
const authCode = await AuthCode.findOne({ const authCode = await AuthCode.findOne({
email, username,
type, type,
expiredTime: { $gte: Date.now() + 4 * 60 * 1000 } // 如果有一个记录的过期时间,大于当前+4分钟,说明距离上次发送还没到1分钟。(因为默认创建时,过期时间是未来5分钟) expiredTime: { $gte: Date.now() + 4 * 60 * 1000 } // 如果有一个记录的过期时间,大于当前+4分钟,说明距离上次发送还没到1分钟。(因为默认创建时,过期时间是未来5分钟)
}); });
...@@ -34,13 +33,17 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) ...@@ -34,13 +33,17 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
// 创建 auth 记录 // 创建 auth 记录
await AuthCode.create({ await AuthCode.create({
email, username,
type, type,
code code
}); });
// 发送验证码 if (username.includes('@')) {
await sendCode(email as string, code, type as `${EmailTypeEnum}`); await sendEmailCode(username, code, type);
} else {
// 发送验证码
await sendPhoneCode(username, code);
}
jsonRes(res, { jsonRes(res, {
message: '发送验证码成功' message: '发送验证码成功'
......
...@@ -5,13 +5,13 @@ import { User } from '@/service/models/user'; ...@@ -5,13 +5,13 @@ import { User } from '@/service/models/user';
import { AuthCode } from '@/service/models/authCode'; import { AuthCode } from '@/service/models/authCode';
import { connectToDatabase } from '@/service/mongo'; import { connectToDatabase } from '@/service/mongo';
import { generateToken } from '@/service/utils/tools'; import { generateToken } from '@/service/utils/tools';
import { EmailTypeEnum } from '@/constants/common'; import { UserAuthTypeEnum } from '@/constants/common';
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) { export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try { try {
const { email, code, password } = req.body; const { username, code, password } = req.body;
if (!email || !code || !password) { if (!username || !code || !password) {
throw new Error('缺少参数'); throw new Error('缺少参数');
} }
...@@ -19,9 +19,9 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse< ...@@ -19,9 +19,9 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
// 验证码校验 // 验证码校验
const authCode = await AuthCode.findOne({ const authCode = await AuthCode.findOne({
email, username,
code, code,
type: EmailTypeEnum.findPassword, type: UserAuthTypeEnum.findPassword,
expiredTime: { $gte: Date.now() } expiredTime: { $gte: Date.now() }
}); });
...@@ -32,16 +32,16 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse< ...@@ -32,16 +32,16 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
// 更新对应的记录 // 更新对应的记录
await User.updateOne( await User.updateOne(
{ {
email username
}, },
{ {
password password
} }
); );
// 根据 email 获取用户信息 // 根据 username 获取用户信息
const user = await User.findOne({ const user = await User.findOne({
email username
}); });
if (!user) { if (!user) {
......
...@@ -14,7 +14,7 @@ interface Props { ...@@ -14,7 +14,7 @@ interface Props {
} }
interface RegisterType { interface RegisterType {
email: string; username: string;
code: string; code: string;
password: string; password: string;
password2: string; password2: string;
...@@ -36,10 +36,10 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => { ...@@ -36,10 +36,10 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
const { codeSending, sendCodeText, sendCode, codeCountDown } = useSendCode(); const { codeSending, sendCodeText, sendCode, codeCountDown } = useSendCode();
const onclickSendCode = useCallback(async () => { const onclickSendCode = useCallback(async () => {
const check = await trigger('email'); const check = await trigger('username');
if (!check) return; if (!check) return;
sendCode({ sendCode({
email: getValues('email'), username: getValues('username'),
type: 'findPassword' type: 'findPassword'
}); });
}, [getValues, sendCode, trigger]); }, [getValues, sendCode, trigger]);
...@@ -47,12 +47,12 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => { ...@@ -47,12 +47,12 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
const [requesting, setRequesting] = useState(false); const [requesting, setRequesting] = useState(false);
const onclickFindPassword = useCallback( const onclickFindPassword = useCallback(
async ({ email, code, password }: RegisterType) => { async ({ username, code, password }: RegisterType) => {
setRequesting(true); setRequesting(true);
try { try {
loginSuccess( loginSuccess(
await postFindPassword({ await postFindPassword({
email, username,
code, code,
password password
}) })
...@@ -78,23 +78,24 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => { ...@@ -78,23 +78,24 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
找回 FastGPT 账号 找回 FastGPT 账号
</Box> </Box>
<form onSubmit={handleSubmit(onclickFindPassword)}> <form onSubmit={handleSubmit(onclickFindPassword)}>
<FormControl mt={8} isInvalid={!!errors.email}> <FormControl mt={8} isInvalid={!!errors.username}>
<Input <Input
placeholder="邮箱" placeholder="邮箱/手机号"
size={mediaLgMd} size={mediaLgMd}
{...register('email', { {...register('username', {
required: '邮箱不能为空', required: '邮箱/手机号不能为空',
pattern: { pattern: {
value: /^[A-Za-z0-9]+([_\.][A-Za-z0-9]+)*@([A-Za-z0-9\-]+\.)+[A-Za-z]{2,6}$/, value:
message: '邮箱错误' /(^1[3456789]\d{9}$)|(^[A-Za-z0-9]+([_\.][A-Za-z0-9]+)*@([A-Za-z0-9\-]+\.)+[A-Za-z]{2,6}$)/,
message: '邮箱/手机号格式错误'
} }
})} })}
></Input> ></Input>
<FormErrorMessage position={'absolute'} fontSize="xs"> <FormErrorMessage position={'absolute'} fontSize="xs">
{!!errors.email && errors.email.message} {!!errors.username && errors.username.message}
</FormErrorMessage> </FormErrorMessage>
</FormControl> </FormControl>
<FormControl mt={8} isInvalid={!!errors.email}> <FormControl mt={8} isInvalid={!!errors.username}>
<Flex> <Flex>
<Input <Input
flex={1} flex={1}
......
...@@ -13,7 +13,7 @@ interface Props { ...@@ -13,7 +13,7 @@ interface Props {
} }
interface LoginFormType { interface LoginFormType {
email: string; username: string;
password: string; password: string;
} }
...@@ -29,12 +29,12 @@ const LoginForm = ({ setPageType, loginSuccess }: Props) => { ...@@ -29,12 +29,12 @@ const LoginForm = ({ setPageType, loginSuccess }: Props) => {
const [requesting, setRequesting] = useState(false); const [requesting, setRequesting] = useState(false);
const onclickLogin = useCallback( const onclickLogin = useCallback(
async ({ email, password }: LoginFormType) => { async ({ username, password }: LoginFormType) => {
setRequesting(true); setRequesting(true);
try { try {
loginSuccess( loginSuccess(
await postLogin({ await postLogin({
email, username,
password password
}) })
); );
...@@ -59,20 +59,21 @@ const LoginForm = ({ setPageType, loginSuccess }: Props) => { ...@@ -59,20 +59,21 @@ const LoginForm = ({ setPageType, loginSuccess }: Props) => {
登录 FastGPT 登录 FastGPT
</Box> </Box>
<form onSubmit={handleSubmit(onclickLogin)}> <form onSubmit={handleSubmit(onclickLogin)}>
<FormControl mt={8} isInvalid={!!errors.email}> <FormControl mt={8} isInvalid={!!errors.username}>
<Input <Input
placeholder="邮箱" placeholder="邮箱/手机号"
size={mediaLgMd} size={mediaLgMd}
{...register('email', { {...register('username', {
required: '邮箱不能为空', required: '邮箱/手机号不能为空',
pattern: { pattern: {
value: /^[A-Za-z0-9]+([_\.][A-Za-z0-9]+)*@([A-Za-z0-9\-]+\.)+[A-Za-z]{2,6}$/, value:
message: '邮箱错误' /(^1[3456789]\d{9}$)|(^[A-Za-z0-9]+([_\.][A-Za-z0-9]+)*@([A-Za-z0-9\-]+\.)+[A-Za-z]{2,6}$)/,
message: '邮箱/手机号格式错误'
} }
})} })}
></Input> ></Input>
<FormErrorMessage position={'absolute'} fontSize="xs"> <FormErrorMessage position={'absolute'} fontSize="xs">
{!!errors.email && errors.email.message} {!!errors.username && errors.username.message}
</FormErrorMessage> </FormErrorMessage>
</FormControl> </FormControl>
<FormControl mt={8} isInvalid={!!errors.password}> <FormControl mt={8} isInvalid={!!errors.password}>
......
...@@ -14,7 +14,7 @@ interface Props { ...@@ -14,7 +14,7 @@ interface Props {
} }
interface RegisterType { interface RegisterType {
email: string; phone: string;
password: string; password: string;
password2: string; password2: string;
code: string; code: string;
...@@ -36,10 +36,10 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => { ...@@ -36,10 +36,10 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
const { codeSending, sendCodeText, sendCode, codeCountDown } = useSendCode(); const { codeSending, sendCodeText, sendCode, codeCountDown } = useSendCode();
const onclickSendCode = useCallback(async () => { const onclickSendCode = useCallback(async () => {
const check = await trigger('email'); const check = await trigger('phone');
if (!check) return; if (!check) return;
sendCode({ sendCode({
email: getValues('email'), username: getValues('phone'),
type: 'register' type: 'register'
}); });
}, [getValues, sendCode, trigger]); }, [getValues, sendCode, trigger]);
...@@ -47,12 +47,12 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => { ...@@ -47,12 +47,12 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
const [requesting, setRequesting] = useState(false); const [requesting, setRequesting] = useState(false);
const onclickRegister = useCallback( const onclickRegister = useCallback(
async ({ email, password, code }: RegisterType) => { async ({ phone, password, code }: RegisterType) => {
setRequesting(true); setRequesting(true);
try { try {
loginSuccess( loginSuccess(
await postRegister({ await postRegister({
email, phone,
code, code,
password password
}) })
...@@ -78,23 +78,23 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => { ...@@ -78,23 +78,23 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
注册 FastGPT 账号 注册 FastGPT 账号
</Box> </Box>
<form onSubmit={handleSubmit(onclickRegister)}> <form onSubmit={handleSubmit(onclickRegister)}>
<FormControl mt={8} isInvalid={!!errors.email}> <FormControl mt={8} isInvalid={!!errors.phone}>
<Input <Input
placeholder="邮箱" placeholder="手机号"
size={mediaLgMd} size={mediaLgMd}
{...register('email', { {...register('phone', {
required: '邮箱不能为空', required: '手机号不能为空',
pattern: { pattern: {
value: /^[A-Za-z0-9]+([_\.][A-Za-z0-9]+)*@([A-Za-z0-9\-]+\.)+[A-Za-z]{2,6}$/, value: /^1[3456789]\d{9}$/,
message: '邮箱错误' message: '手机号格式错误'
} }
})} })}
></Input> ></Input>
<FormErrorMessage position={'absolute'} fontSize="xs"> <FormErrorMessage position={'absolute'} fontSize="xs">
{!!errors.email && errors.email.message} {!!errors.phone && errors.phone.message}
</FormErrorMessage> </FormErrorMessage>
</FormControl> </FormControl>
<FormControl mt={8} isInvalid={!!errors.email}> <FormControl mt={8} isInvalid={!!errors.phone}>
<Flex> <Flex>
<Input <Input
flex={1} flex={1}
......
...@@ -51,8 +51,8 @@ const NumberSetting = () => { ...@@ -51,8 +51,8 @@ const NumberSetting = () => {
账号信息 账号信息
</Box> </Box>
<Flex mt={6} alignItems={'center'}> <Flex mt={6} alignItems={'center'}>
<Box flex={'0 0 60px'}>邮箱:</Box> <Box flex={'0 0 60px'}>用户账号:</Box>
<Box>{userInfo?.email}</Box> <Box>{userInfo?.username}</Box>
</Flex> </Flex>
<Box mt={6}> <Box mt={6}>
<Flex alignItems={'center'}> <Flex alignItems={'center'}>
......
...@@ -2,7 +2,7 @@ import { Schema, model, models, Model } from 'mongoose'; ...@@ -2,7 +2,7 @@ import { Schema, model, models, Model } from 'mongoose';
import { AuthCodeSchema as AuthCodeType } from '@/types/mongoSchema'; import { AuthCodeSchema as AuthCodeType } from '@/types/mongoSchema';
const AuthCodeSchema = new Schema({ const AuthCodeSchema = new Schema({
email: { username: {
type: String, type: String,
required: true required: true
}, },
......
...@@ -3,7 +3,8 @@ import { hashPassword } from '@/service/utils/tools'; ...@@ -3,7 +3,8 @@ import { hashPassword } from '@/service/utils/tools';
import { PRICE_SCALE } from '@/constants/common'; import { PRICE_SCALE } from '@/constants/common';
import { UserModelSchema } from '@/types/mongoSchema'; import { UserModelSchema } from '@/types/mongoSchema';
const UserSchema = new Schema({ const UserSchema = new Schema({
email: { username: {
// 可以是手机/邮箱,新的验证都只用手机
type: String, type: String,
required: true, required: true,
unique: true // 唯一 unique: true // 唯一
......
import * as nodemailer from 'nodemailer'; import * as nodemailer from 'nodemailer';
import { EmailTypeEnum } from '@/constants/common'; import { UserAuthTypeEnum } from '@/constants/common';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import Dysmsapi, * as dysmsapi from '@alicloud/dysmsapi20170525';
// @ts-ignore
import * as OpenApi from '@alicloud/openapi-client';
// @ts-ignore
import * as Util from '@alicloud/tea-util';
const myEmail = process.env.MY_MAIL; const myEmail = process.env.MY_MAIL;
let mailTransport = nodemailer.createTransport({ const mailTransport = nodemailer.createTransport({
// host: 'smtp.qq.email', // host: 'smtp.qq.phone',
service: 'qq', service: 'qq',
secure: true, //安全方式发送,建议都加上 secure: true, //安全方式发送,建议都加上
auth: { auth: {
...@@ -14,17 +19,17 @@ let mailTransport = nodemailer.createTransport({ ...@@ -14,17 +19,17 @@ let mailTransport = nodemailer.createTransport({
}); });
const emailMap: { [key: string]: any } = { const emailMap: { [key: string]: any } = {
[EmailTypeEnum.register]: { [UserAuthTypeEnum.register]: {
subject: '注册 FastGPT 账号', subject: '注册 FastGPT 账号',
html: (code: string) => `<div>您正在注册 FastGPT 账号,验证码为:${code}</div>` html: (code: string) => `<div>您正在注册 FastGPT 账号,验证码为:${code}</div>`
}, },
[EmailTypeEnum.findPassword]: { [UserAuthTypeEnum.findPassword]: {
subject: '修改 FastGPT 密码', subject: '修改 FastGPT 密码',
html: (code: string) => `<div>您正在修改 FastGPT 账号密码,验证码为:${code}</div>` html: (code: string) => `<div>您正在修改 FastGPT 账号密码,验证码为:${code}</div>`
} }
}; };
export const sendCode = (email: string, code: string, type: `${EmailTypeEnum}`) => { export const sendEmailCode = (email: string, code: string, type: `${UserAuthTypeEnum}`) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const options = { const options = {
from: `"FastGPT" ${myEmail}`, from: `"FastGPT" ${myEmail}`,
...@@ -35,7 +40,7 @@ export const sendCode = (email: string, code: string, type: `${EmailTypeEnum}`) ...@@ -35,7 +40,7 @@ export const sendCode = (email: string, code: string, type: `${EmailTypeEnum}`)
mailTransport.sendMail(options, function (err, msg) { mailTransport.sendMail(options, function (err, msg) {
if (err) { if (err) {
console.log('send email error->', err); console.log('send email error->', err);
reject('邮箱异常'); reject('发生邮件异常');
} else { } else {
resolve(''); resolve('');
} }
...@@ -43,21 +48,25 @@ export const sendCode = (email: string, code: string, type: `${EmailTypeEnum}`) ...@@ -43,21 +48,25 @@ export const sendCode = (email: string, code: string, type: `${EmailTypeEnum}`)
}); });
}; };
export const sendTrainSucceed = (email: string, modelName: string) => { export const sendPhoneCode = async (phone: string, code: string) => {
return new Promise((resolve, reject) => { const accessKeyId = process.env.aliAccessKeyId;
const options = { const accessKeySecret = process.env.aliAccessKeySecret;
from: `"FastGPT" ${myEmail}`, const signName = process.env.aliSignName;
to: email, const templateCode = process.env.aliTemplateCode;
subject: '模型训练完成通知', const endpoint = 'dysmsapi.aliyuncs.com';
html: `你的模型 ${modelName} 已于 ${dayjs().format('YYYY-MM-DD HH:mm')} 训练完成!`
}; const sendSmsRequest = new dysmsapi.SendSmsRequest({
mailTransport.sendMail(options, function (err, msg) { phoneNumbers: phone,
if (err) { signName,
console.log('send email error->', err); templateCode,
reject('邮箱异常'); templateParam: `{"code":${code}}`
} else {
resolve('');
}
});
}); });
const config = new OpenApi.Config({ accessKeyId, accessKeySecret, endpoint });
const client = new Dysmsapi(config);
const runtime = new Util.RuntimeOptions({});
const res = await client.sendSmsWithOptions(sendSmsRequest, runtime);
if (res.body.code !== 'OK') {
return Promise.reject(res.body.message || '发送短信失败');
}
}; };
...@@ -11,7 +11,7 @@ export type ServiceName = 'openai'; ...@@ -11,7 +11,7 @@ export type ServiceName = 'openai';
export interface UserModelSchema { export interface UserModelSchema {
_id: string; _id: string;
email: string; username: string;
password: string; password: string;
balance: number; balance: number;
openaiKey: string; openaiKey: string;
...@@ -20,7 +20,7 @@ export interface UserModelSchema { ...@@ -20,7 +20,7 @@ export interface UserModelSchema {
export interface AuthCodeSchema { export interface AuthCodeSchema {
_id: string; _id: string;
email: string; username: string;
code: string; code: string;
type: 'register' | 'findPassword'; type: 'register' | 'findPassword';
expiredTime: number; expiredTime: number;
......
export enum UserNumberEnum {
phone = 'phone',
wx = 'wx'
}
export interface UserType { export interface UserType {
_id: string; _id: string;
email: string; username: string;
openaiKey: string; openaiKey: string;
balance: number; balance: number;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment