mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-27 00:17:31 +00:00
feat: 手机验证码作为用户凭证
This commit is contained in:
@@ -1,50 +1,55 @@
|
||||
import { GET, POST, PUT } from './request';
|
||||
import { createHashPassword, Obj2Query } from '@/utils/tools';
|
||||
import { ResLogin } from './response/user';
|
||||
import { EmailTypeEnum } from '@/constants/common';
|
||||
import { UserAuthTypeEnum } from '@/constants/common';
|
||||
import { UserType, UserUpdateParams } from '@/types/user';
|
||||
import type { PagingData, RequestPaging } from '@/types';
|
||||
import { BillSchema, PaySchema } from '@/types/mongoSchema';
|
||||
import { adaptBill } from '@/utils/adapt';
|
||||
|
||||
export const sendCodeToEmail = ({ email, type }: { email: string; type: `${EmailTypeEnum}` }) =>
|
||||
GET('/user/sendEmail', { email, type });
|
||||
export const sendAuthCode = ({
|
||||
username,
|
||||
type
|
||||
}: {
|
||||
username: string;
|
||||
type: `${UserAuthTypeEnum}`;
|
||||
}) => GET('/user/sendAuthCode', { username, type });
|
||||
|
||||
export const getTokenLogin = () => GET<UserType>('/user/tokenLogin');
|
||||
|
||||
export const postRegister = ({
|
||||
email,
|
||||
phone,
|
||||
password,
|
||||
code
|
||||
}: {
|
||||
email: string;
|
||||
phone: string;
|
||||
code: string;
|
||||
password: string;
|
||||
}) =>
|
||||
POST<ResLogin>('/user/register', {
|
||||
email,
|
||||
phone,
|
||||
code,
|
||||
password: createHashPassword(password)
|
||||
});
|
||||
|
||||
export const postFindPassword = ({
|
||||
email,
|
||||
username,
|
||||
code,
|
||||
password
|
||||
}: {
|
||||
email: string;
|
||||
username: string;
|
||||
code: string;
|
||||
password: string;
|
||||
}) =>
|
||||
POST<ResLogin>('/user/updatePasswordByCode', {
|
||||
email,
|
||||
username,
|
||||
code,
|
||||
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', {
|
||||
email,
|
||||
username,
|
||||
password: createHashPassword(password)
|
||||
});
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
export enum EmailTypeEnum {
|
||||
export enum UserAuthTypeEnum {
|
||||
register = 'register',
|
||||
findPassword = 'findPassword'
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { useState, useMemo, useCallback } from 'react';
|
||||
import { sendCodeToEmail } from '@/api/user';
|
||||
import { EmailTypeEnum } from '@/constants/common';
|
||||
import { sendAuthCode } from '@/api/user';
|
||||
import { UserAuthTypeEnum } from '@/constants/common';
|
||||
let timer: any;
|
||||
import { useToast } from './useToast';
|
||||
|
||||
@@ -19,11 +19,11 @@ export const useSendCode = () => {
|
||||
}, [codeCountDown]);
|
||||
|
||||
const sendCode = useCallback(
|
||||
async ({ email, type }: { email: string; type: `${EmailTypeEnum}` }) => {
|
||||
async ({ username, type }: { username: string; type: `${UserAuthTypeEnum}` }) => {
|
||||
setCodeSending(true);
|
||||
try {
|
||||
await sendCodeToEmail({
|
||||
email,
|
||||
await sendAuthCode({
|
||||
username,
|
||||
type
|
||||
});
|
||||
setCodeCountDown(60);
|
||||
|
@@ -7,24 +7,24 @@ import { generateToken } from '@/service/utils/tools';
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
try {
|
||||
const { email, password } = req.body;
|
||||
const { username, password } = req.body;
|
||||
|
||||
if (!email || !password) {
|
||||
if (!username || !password) {
|
||||
throw new Error('缺少参数');
|
||||
}
|
||||
|
||||
await connectToDatabase();
|
||||
|
||||
// 检测邮箱是否存在
|
||||
const authEmail = await User.findOne({
|
||||
email
|
||||
// 检测用户是否存在
|
||||
const authUser = await User.findOne({
|
||||
username
|
||||
});
|
||||
if (!authEmail) {
|
||||
throw new Error('邮箱未注册');
|
||||
if (!authUser) {
|
||||
throw new Error('用户未注册');
|
||||
}
|
||||
|
||||
const user = await User.findOne({
|
||||
email,
|
||||
username,
|
||||
password
|
||||
});
|
||||
|
||||
|
@@ -5,23 +5,29 @@ import { User } from '@/service/models/user';
|
||||
import { AuthCode } from '@/service/models/authCode';
|
||||
import { connectToDatabase } from '@/service/mongo';
|
||||
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>) {
|
||||
try {
|
||||
const { email, code, password } = req.body;
|
||||
const { phone, code, password } = req.body;
|
||||
|
||||
if (!email || !code || !password) {
|
||||
if (!phone || !code || !password) {
|
||||
throw new Error('缺少参数');
|
||||
}
|
||||
|
||||
const reg = /^1[3456789]\d{9}$/;
|
||||
|
||||
if (!reg.test(phone)) {
|
||||
throw new Error('手机号格式错误');
|
||||
}
|
||||
|
||||
await connectToDatabase();
|
||||
|
||||
// 验证码校验
|
||||
// 验证码校验. 注册只接收手机号
|
||||
const authCode = await AuthCode.findOne({
|
||||
email,
|
||||
username: phone,
|
||||
code,
|
||||
type: EmailTypeEnum.register,
|
||||
type: UserAuthTypeEnum.register,
|
||||
expiredTime: { $gte: Date.now() }
|
||||
});
|
||||
|
||||
@@ -31,15 +37,15 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
||||
|
||||
// 重名校验
|
||||
const authRepeat = await User.findOne({
|
||||
email
|
||||
username: phone
|
||||
});
|
||||
|
||||
if (authRepeat) {
|
||||
throw new Error('邮箱已被注册');
|
||||
throw new Error('手机号已被注册');
|
||||
}
|
||||
|
||||
const response = await User.create({
|
||||
email,
|
||||
username: phone,
|
||||
password
|
||||
});
|
||||
|
||||
@@ -50,6 +56,11 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
||||
throw new Error('获取用户信息异常');
|
||||
}
|
||||
|
||||
// 删除验证码记录
|
||||
await AuthCode.deleteMany({
|
||||
username: phone
|
||||
});
|
||||
|
||||
jsonRes(res, {
|
||||
data: {
|
||||
token: generateToken(user._id),
|
||||
|
@@ -2,28 +2,27 @@
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@/service/response';
|
||||
import { AuthCode } from '@/service/models/authCode';
|
||||
import { connectToDatabase, User } from '@/service/mongo';
|
||||
import { sendCode } from '@/service/utils/sendEmail';
|
||||
import { EmailTypeEnum } from '@/constants/common';
|
||||
import { connectToDatabase } from '@/service/mongo';
|
||||
import { sendPhoneCode, sendEmailCode } from '@/service/utils/sendNote';
|
||||
import { UserAuthTypeEnum } from '@/constants/common';
|
||||
import { customAlphabet } from 'nanoid';
|
||||
const nanoid = customAlphabet('1234567890', 6);
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
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('缺少参数');
|
||||
}
|
||||
|
||||
await connectToDatabase();
|
||||
|
||||
let code = '';
|
||||
for (let i = 0; i < 6; i++) {
|
||||
code += Math.floor(Math.random() * 10);
|
||||
}
|
||||
let code = nanoid();
|
||||
|
||||
// 判断 1 分钟内是否有重复数据
|
||||
const authCode = await AuthCode.findOne({
|
||||
email,
|
||||
username,
|
||||
type,
|
||||
expiredTime: { $gte: Date.now() + 4 * 60 * 1000 } // 如果有一个记录的过期时间,大于当前+4分钟,说明距离上次发送还没到1分钟。(因为默认创建时,过期时间是未来5分钟)
|
||||
});
|
||||
@@ -34,13 +33,17 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
|
||||
// 创建 auth 记录
|
||||
await AuthCode.create({
|
||||
email,
|
||||
username,
|
||||
type,
|
||||
code
|
||||
});
|
||||
|
||||
// 发送验证码
|
||||
await sendCode(email as string, code, type as `${EmailTypeEnum}`);
|
||||
if (username.includes('@')) {
|
||||
await sendEmailCode(username, code, type);
|
||||
} else {
|
||||
// 发送验证码
|
||||
await sendPhoneCode(username, code);
|
||||
}
|
||||
|
||||
jsonRes(res, {
|
||||
message: '发送验证码成功'
|
@@ -5,13 +5,13 @@ import { User } from '@/service/models/user';
|
||||
import { AuthCode } from '@/service/models/authCode';
|
||||
import { connectToDatabase } from '@/service/mongo';
|
||||
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>) {
|
||||
try {
|
||||
const { email, code, password } = req.body;
|
||||
const { username, code, password } = req.body;
|
||||
|
||||
if (!email || !code || !password) {
|
||||
if (!username || !code || !password) {
|
||||
throw new Error('缺少参数');
|
||||
}
|
||||
|
||||
@@ -19,9 +19,9 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
||||
|
||||
// 验证码校验
|
||||
const authCode = await AuthCode.findOne({
|
||||
email,
|
||||
username,
|
||||
code,
|
||||
type: EmailTypeEnum.findPassword,
|
||||
type: UserAuthTypeEnum.findPassword,
|
||||
expiredTime: { $gte: Date.now() }
|
||||
});
|
||||
|
||||
@@ -32,16 +32,16 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
||||
// 更新对应的记录
|
||||
await User.updateOne(
|
||||
{
|
||||
email
|
||||
username
|
||||
},
|
||||
{
|
||||
password
|
||||
}
|
||||
);
|
||||
|
||||
// 根据 email 获取用户信息
|
||||
// 根据 username 获取用户信息
|
||||
const user = await User.findOne({
|
||||
email
|
||||
username
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
|
@@ -14,7 +14,7 @@ interface Props {
|
||||
}
|
||||
|
||||
interface RegisterType {
|
||||
email: string;
|
||||
username: string;
|
||||
code: string;
|
||||
password: string;
|
||||
password2: string;
|
||||
@@ -36,10 +36,10 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
|
||||
const { codeSending, sendCodeText, sendCode, codeCountDown } = useSendCode();
|
||||
|
||||
const onclickSendCode = useCallback(async () => {
|
||||
const check = await trigger('email');
|
||||
const check = await trigger('username');
|
||||
if (!check) return;
|
||||
sendCode({
|
||||
email: getValues('email'),
|
||||
username: getValues('username'),
|
||||
type: 'findPassword'
|
||||
});
|
||||
}, [getValues, sendCode, trigger]);
|
||||
@@ -47,12 +47,12 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
|
||||
const [requesting, setRequesting] = useState(false);
|
||||
|
||||
const onclickFindPassword = useCallback(
|
||||
async ({ email, code, password }: RegisterType) => {
|
||||
async ({ username, code, password }: RegisterType) => {
|
||||
setRequesting(true);
|
||||
try {
|
||||
loginSuccess(
|
||||
await postFindPassword({
|
||||
email,
|
||||
username,
|
||||
code,
|
||||
password
|
||||
})
|
||||
@@ -78,23 +78,24 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
|
||||
找回 FastGPT 账号
|
||||
</Box>
|
||||
<form onSubmit={handleSubmit(onclickFindPassword)}>
|
||||
<FormControl mt={8} isInvalid={!!errors.email}>
|
||||
<FormControl mt={8} isInvalid={!!errors.username}>
|
||||
<Input
|
||||
placeholder="邮箱"
|
||||
placeholder="邮箱/手机号"
|
||||
size={mediaLgMd}
|
||||
{...register('email', {
|
||||
required: '邮箱不能为空',
|
||||
{...register('username', {
|
||||
required: '邮箱/手机号不能为空',
|
||||
pattern: {
|
||||
value: /^[A-Za-z0-9]+([_\.][A-Za-z0-9]+)*@([A-Za-z0-9\-]+\.)+[A-Za-z]{2,6}$/,
|
||||
message: '邮箱错误'
|
||||
value:
|
||||
/(^1[3456789]\d{9}$)|(^[A-Za-z0-9]+([_\.][A-Za-z0-9]+)*@([A-Za-z0-9\-]+\.)+[A-Za-z]{2,6}$)/,
|
||||
message: '邮箱/手机号格式错误'
|
||||
}
|
||||
})}
|
||||
></Input>
|
||||
<FormErrorMessage position={'absolute'} fontSize="xs">
|
||||
{!!errors.email && errors.email.message}
|
||||
{!!errors.username && errors.username.message}
|
||||
</FormErrorMessage>
|
||||
</FormControl>
|
||||
<FormControl mt={8} isInvalid={!!errors.email}>
|
||||
<FormControl mt={8} isInvalid={!!errors.username}>
|
||||
<Flex>
|
||||
<Input
|
||||
flex={1}
|
||||
|
@@ -13,7 +13,7 @@ interface Props {
|
||||
}
|
||||
|
||||
interface LoginFormType {
|
||||
email: string;
|
||||
username: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
@@ -29,12 +29,12 @@ const LoginForm = ({ setPageType, loginSuccess }: Props) => {
|
||||
const [requesting, setRequesting] = useState(false);
|
||||
|
||||
const onclickLogin = useCallback(
|
||||
async ({ email, password }: LoginFormType) => {
|
||||
async ({ username, password }: LoginFormType) => {
|
||||
setRequesting(true);
|
||||
try {
|
||||
loginSuccess(
|
||||
await postLogin({
|
||||
email,
|
||||
username,
|
||||
password
|
||||
})
|
||||
);
|
||||
@@ -59,20 +59,21 @@ const LoginForm = ({ setPageType, loginSuccess }: Props) => {
|
||||
登录 FastGPT
|
||||
</Box>
|
||||
<form onSubmit={handleSubmit(onclickLogin)}>
|
||||
<FormControl mt={8} isInvalid={!!errors.email}>
|
||||
<FormControl mt={8} isInvalid={!!errors.username}>
|
||||
<Input
|
||||
placeholder="邮箱"
|
||||
placeholder="邮箱/手机号"
|
||||
size={mediaLgMd}
|
||||
{...register('email', {
|
||||
required: '邮箱不能为空',
|
||||
{...register('username', {
|
||||
required: '邮箱/手机号不能为空',
|
||||
pattern: {
|
||||
value: /^[A-Za-z0-9]+([_\.][A-Za-z0-9]+)*@([A-Za-z0-9\-]+\.)+[A-Za-z]{2,6}$/,
|
||||
message: '邮箱错误'
|
||||
value:
|
||||
/(^1[3456789]\d{9}$)|(^[A-Za-z0-9]+([_\.][A-Za-z0-9]+)*@([A-Za-z0-9\-]+\.)+[A-Za-z]{2,6}$)/,
|
||||
message: '邮箱/手机号格式错误'
|
||||
}
|
||||
})}
|
||||
></Input>
|
||||
<FormErrorMessage position={'absolute'} fontSize="xs">
|
||||
{!!errors.email && errors.email.message}
|
||||
{!!errors.username && errors.username.message}
|
||||
</FormErrorMessage>
|
||||
</FormControl>
|
||||
<FormControl mt={8} isInvalid={!!errors.password}>
|
||||
|
@@ -14,7 +14,7 @@ interface Props {
|
||||
}
|
||||
|
||||
interface RegisterType {
|
||||
email: string;
|
||||
phone: string;
|
||||
password: string;
|
||||
password2: string;
|
||||
code: string;
|
||||
@@ -36,10 +36,10 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
|
||||
const { codeSending, sendCodeText, sendCode, codeCountDown } = useSendCode();
|
||||
|
||||
const onclickSendCode = useCallback(async () => {
|
||||
const check = await trigger('email');
|
||||
const check = await trigger('phone');
|
||||
if (!check) return;
|
||||
sendCode({
|
||||
email: getValues('email'),
|
||||
username: getValues('phone'),
|
||||
type: 'register'
|
||||
});
|
||||
}, [getValues, sendCode, trigger]);
|
||||
@@ -47,12 +47,12 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
|
||||
const [requesting, setRequesting] = useState(false);
|
||||
|
||||
const onclickRegister = useCallback(
|
||||
async ({ email, password, code }: RegisterType) => {
|
||||
async ({ phone, password, code }: RegisterType) => {
|
||||
setRequesting(true);
|
||||
try {
|
||||
loginSuccess(
|
||||
await postRegister({
|
||||
email,
|
||||
phone,
|
||||
code,
|
||||
password
|
||||
})
|
||||
@@ -78,23 +78,23 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
|
||||
注册 FastGPT 账号
|
||||
</Box>
|
||||
<form onSubmit={handleSubmit(onclickRegister)}>
|
||||
<FormControl mt={8} isInvalid={!!errors.email}>
|
||||
<FormControl mt={8} isInvalid={!!errors.phone}>
|
||||
<Input
|
||||
placeholder="邮箱"
|
||||
placeholder="手机号"
|
||||
size={mediaLgMd}
|
||||
{...register('email', {
|
||||
required: '邮箱不能为空',
|
||||
{...register('phone', {
|
||||
required: '手机号不能为空',
|
||||
pattern: {
|
||||
value: /^[A-Za-z0-9]+([_\.][A-Za-z0-9]+)*@([A-Za-z0-9\-]+\.)+[A-Za-z]{2,6}$/,
|
||||
message: '邮箱错误'
|
||||
value: /^1[3456789]\d{9}$/,
|
||||
message: '手机号格式错误'
|
||||
}
|
||||
})}
|
||||
></Input>
|
||||
<FormErrorMessage position={'absolute'} fontSize="xs">
|
||||
{!!errors.email && errors.email.message}
|
||||
{!!errors.phone && errors.phone.message}
|
||||
</FormErrorMessage>
|
||||
</FormControl>
|
||||
<FormControl mt={8} isInvalid={!!errors.email}>
|
||||
<FormControl mt={8} isInvalid={!!errors.phone}>
|
||||
<Flex>
|
||||
<Input
|
||||
flex={1}
|
||||
|
@@ -51,8 +51,8 @@ const NumberSetting = () => {
|
||||
账号信息
|
||||
</Box>
|
||||
<Flex mt={6} alignItems={'center'}>
|
||||
<Box flex={'0 0 60px'}>邮箱:</Box>
|
||||
<Box>{userInfo?.email}</Box>
|
||||
<Box flex={'0 0 60px'}>用户账号:</Box>
|
||||
<Box>{userInfo?.username}</Box>
|
||||
</Flex>
|
||||
<Box mt={6}>
|
||||
<Flex alignItems={'center'}>
|
||||
|
@@ -2,7 +2,7 @@ import { Schema, model, models, Model } from 'mongoose';
|
||||
import { AuthCodeSchema as AuthCodeType } from '@/types/mongoSchema';
|
||||
|
||||
const AuthCodeSchema = new Schema({
|
||||
email: {
|
||||
username: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
|
@@ -3,7 +3,8 @@ import { hashPassword } from '@/service/utils/tools';
|
||||
import { PRICE_SCALE } from '@/constants/common';
|
||||
import { UserModelSchema } from '@/types/mongoSchema';
|
||||
const UserSchema = new Schema({
|
||||
email: {
|
||||
username: {
|
||||
// 可以是手机/邮箱,新的验证都只用手机
|
||||
type: String,
|
||||
required: true,
|
||||
unique: true // 唯一
|
||||
|
@@ -1,63 +0,0 @@
|
||||
import * as nodemailer from 'nodemailer';
|
||||
import { EmailTypeEnum } from '@/constants/common';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
const myEmail = process.env.MY_MAIL;
|
||||
let mailTransport = nodemailer.createTransport({
|
||||
// host: 'smtp.qq.email',
|
||||
service: 'qq',
|
||||
secure: true, //安全方式发送,建议都加上
|
||||
auth: {
|
||||
user: myEmail,
|
||||
pass: process.env.MAILE_CODE
|
||||
}
|
||||
});
|
||||
|
||||
const emailMap: { [key: string]: any } = {
|
||||
[EmailTypeEnum.register]: {
|
||||
subject: '注册 FastGPT 账号',
|
||||
html: (code: string) => `<div>您正在注册 FastGPT 账号,验证码为:${code}</div>`
|
||||
},
|
||||
[EmailTypeEnum.findPassword]: {
|
||||
subject: '修改 FastGPT 密码',
|
||||
html: (code: string) => `<div>您正在修改 FastGPT 账号密码,验证码为:${code}</div>`
|
||||
}
|
||||
};
|
||||
|
||||
export const sendCode = (email: string, code: string, type: `${EmailTypeEnum}`) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const options = {
|
||||
from: `"FastGPT" ${myEmail}`,
|
||||
to: email,
|
||||
subject: emailMap[type]?.subject,
|
||||
html: emailMap[type]?.html(code)
|
||||
};
|
||||
mailTransport.sendMail(options, function (err, msg) {
|
||||
if (err) {
|
||||
console.log('send email error->', err);
|
||||
reject('邮箱异常');
|
||||
} else {
|
||||
resolve('');
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export const sendTrainSucceed = (email: string, modelName: string) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const options = {
|
||||
from: `"FastGPT" ${myEmail}`,
|
||||
to: email,
|
||||
subject: '模型训练完成通知',
|
||||
html: `你的模型 ${modelName} 已于 ${dayjs().format('YYYY-MM-DD HH:mm')} 训练完成!`
|
||||
};
|
||||
mailTransport.sendMail(options, function (err, msg) {
|
||||
if (err) {
|
||||
console.log('send email error->', err);
|
||||
reject('邮箱异常');
|
||||
} else {
|
||||
resolve('');
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
72
src/service/utils/sendNote.ts
Normal file
72
src/service/utils/sendNote.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import * as nodemailer from 'nodemailer';
|
||||
import { UserAuthTypeEnum } from '@/constants/common';
|
||||
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 mailTransport = nodemailer.createTransport({
|
||||
// host: 'smtp.qq.phone',
|
||||
service: 'qq',
|
||||
secure: true, //安全方式发送,建议都加上
|
||||
auth: {
|
||||
user: myEmail,
|
||||
pass: process.env.MAILE_CODE
|
||||
}
|
||||
});
|
||||
|
||||
const emailMap: { [key: string]: any } = {
|
||||
[UserAuthTypeEnum.register]: {
|
||||
subject: '注册 FastGPT 账号',
|
||||
html: (code: string) => `<div>您正在注册 FastGPT 账号,验证码为:${code}</div>`
|
||||
},
|
||||
[UserAuthTypeEnum.findPassword]: {
|
||||
subject: '修改 FastGPT 密码',
|
||||
html: (code: string) => `<div>您正在修改 FastGPT 账号密码,验证码为:${code}</div>`
|
||||
}
|
||||
};
|
||||
|
||||
export const sendEmailCode = (email: string, code: string, type: `${UserAuthTypeEnum}`) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const options = {
|
||||
from: `"FastGPT" ${myEmail}`,
|
||||
to: email,
|
||||
subject: emailMap[type]?.subject,
|
||||
html: emailMap[type]?.html(code)
|
||||
};
|
||||
mailTransport.sendMail(options, function (err, msg) {
|
||||
if (err) {
|
||||
console.log('send email error->', err);
|
||||
reject('发生邮件异常');
|
||||
} else {
|
||||
resolve('');
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export const sendPhoneCode = async (phone: string, code: string) => {
|
||||
const accessKeyId = process.env.aliAccessKeyId;
|
||||
const accessKeySecret = process.env.aliAccessKeySecret;
|
||||
const signName = process.env.aliSignName;
|
||||
const templateCode = process.env.aliTemplateCode;
|
||||
const endpoint = 'dysmsapi.aliyuncs.com';
|
||||
|
||||
const sendSmsRequest = new dysmsapi.SendSmsRequest({
|
||||
phoneNumbers: phone,
|
||||
signName,
|
||||
templateCode,
|
||||
templateParam: `{"code":${code}}`
|
||||
});
|
||||
|
||||
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 || '发送短信失败');
|
||||
}
|
||||
};
|
4
src/types/mongoSchema.d.ts
vendored
4
src/types/mongoSchema.d.ts
vendored
@@ -11,7 +11,7 @@ export type ServiceName = 'openai';
|
||||
|
||||
export interface UserModelSchema {
|
||||
_id: string;
|
||||
email: string;
|
||||
username: string;
|
||||
password: string;
|
||||
balance: number;
|
||||
openaiKey: string;
|
||||
@@ -20,7 +20,7 @@ export interface UserModelSchema {
|
||||
|
||||
export interface AuthCodeSchema {
|
||||
_id: string;
|
||||
email: string;
|
||||
username: string;
|
||||
code: string;
|
||||
type: 'register' | 'findPassword';
|
||||
expiredTime: number;
|
||||
|
7
src/types/user.d.ts
vendored
7
src/types/user.d.ts
vendored
@@ -1,11 +1,6 @@
|
||||
export enum UserNumberEnum {
|
||||
phone = 'phone',
|
||||
wx = 'wx'
|
||||
}
|
||||
|
||||
export interface UserType {
|
||||
_id: string;
|
||||
email: string;
|
||||
username: string;
|
||||
openaiKey: string;
|
||||
balance: number;
|
||||
}
|
||||
|
Reference in New Issue
Block a user