-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
a460156
commit a935823
Showing
7 changed files
with
202 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
'use server' | ||
|
||
import { MongoClient } from 'mongodb' | ||
import sha256 from 'crypto-js/sha256' | ||
|
||
// 连接 MongoDB | ||
const client = new MongoClient(process.env.MONGODB_URI!) | ||
const db = client.db('mailbox') | ||
const user = db.collection('user') | ||
|
||
export async function registry( | ||
username: string, | ||
email: string, | ||
password: string, | ||
authCode: string = '' | ||
): Promise<string> { | ||
const fullEmail = `${email}@${process.env.NEXT_PUBLIC_MAIL_SERVER}` | ||
try { | ||
// 验证 authCode | ||
if (process.env.REGISTRY_KEY && authCode !== process.env.REGISTRY_KEY) { | ||
return '注册码错误' | ||
} | ||
// 查询是否已存在 | ||
const result = await user.findOne({ email: fullEmail }) | ||
if (result) { | ||
return '邮箱已注册' | ||
} | ||
// 插入数据 | ||
await user.insertOne({ | ||
username, | ||
email: fullEmail, | ||
password: sha256(password).toString(), | ||
role: 'user', | ||
active: true, | ||
createTime: Date.now(), | ||
updateTime: Date.now() | ||
}) | ||
return '200' | ||
} catch (err) { | ||
throw new Error(err instanceof Error ? err.message : '未知错误') | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,155 @@ | ||
'use client' | ||
|
||
import { Button } from 'antd' | ||
import { Button, Input, Form, Flex, message } from 'antd' | ||
import { UserOutlined, KeyOutlined, MailOutlined, CodeOutlined } from '@ant-design/icons' | ||
import { useRouter } from 'next/navigation' | ||
import { useState, useOptimistic } from 'react' | ||
import { registry } from './action' | ||
|
||
type FieldType = { | ||
username: string | ||
email: string // without '@' and domain | ||
password: string // before encryption | ||
confirm: string // should be the same as password | ||
authCode?: string // registration code | ||
} | ||
|
||
export default function Login() { | ||
|
||
export default function Register() { | ||
const router = useRouter() | ||
const [messageAPI, contextHolder] = message.useMessage() | ||
const [disableForm] = useState(false) | ||
const [disableState, setDisableState] = useOptimistic( | ||
disableForm, | ||
(_, value: boolean) => value | ||
) | ||
|
||
const handleSubmit = async (values: FieldType) => { | ||
setDisableState(true) | ||
messageAPI.open({ | ||
type: 'loading', | ||
content: '正在注册...', | ||
duration: 0, | ||
key: 'registering' | ||
}) | ||
await registry(values.username, values.email, values.password, values.authCode ?? '') | ||
.then(res => { | ||
if (res === '200') { | ||
messageAPI.destroy() | ||
messageAPI.open({ | ||
type: 'success', | ||
content: '注册成功 (2秒后自动跳转至登录页面)', | ||
duration: 2, | ||
key: 'success' | ||
}) | ||
setTimeout(() => { | ||
router.push('/login') | ||
}, 2000) | ||
} else { | ||
messageAPI.destroy() | ||
messageAPI.open({ | ||
type: 'error', | ||
content: `注册失败: ${res}`, | ||
duration: 3, | ||
key: 'error' | ||
}) | ||
} | ||
}).catch(() => { | ||
messageAPI.destroy() | ||
messageAPI.open({ | ||
type: 'error', | ||
content: '注册失败, 未知错误', | ||
duration: 3, | ||
key: 'error' | ||
}) | ||
}) | ||
} | ||
|
||
return ( | ||
<div className='flex flex-col items-center justify-center h-full w-full'> | ||
<div className="text-center text-lg font-bold my-4">开发中...</div> | ||
<Button type='primary' onClick={() => router.push('/login')}>返回登录</Button> | ||
<div className='relative w-full h-full flex flex-col items-center justify-center'> | ||
{contextHolder} | ||
<Form<FieldType> | ||
name='registry' | ||
className='w-11/12' | ||
onFinish={handleSubmit} | ||
disabled={disableState} | ||
> | ||
<Form.Item> | ||
<p className='mb-2 text-2xl font-bold text-center'>注册</p> | ||
</Form.Item> | ||
|
||
<Form.Item | ||
name='username' | ||
rules={[{ required: true, message: '请输入用户名' }, | ||
() => ({ | ||
validator(_, value) { | ||
if (!value || value.length <= 20 && !/\s/.test(value)) { | ||
return Promise.resolve() | ||
} | ||
return Promise.reject(new Error('用户名最长20个字符且不能有空格')) | ||
}, | ||
}) | ||
]} | ||
> | ||
<Input prefix={<UserOutlined />} placeholder='用户名 (支持中文)' /> | ||
</Form.Item> | ||
|
||
<Form.Item | ||
name='email' | ||
rules={[{ required: true, message: '请输入邮箱地址', }, | ||
() => ({ | ||
validator(_, value) { | ||
if (!value || /^[a-z0-9]{1,20}$/.test(value)) { | ||
return Promise.resolve() | ||
} | ||
return Promise.reject(new Error('请输入20个字符以内的小写字母或数字')) | ||
}, | ||
}) | ||
]} | ||
> | ||
<Input addonAfter={`@${process.env.NEXT_PUBLIC_MAIL_SERVER}`} prefix={<MailOutlined />} placeholder='邮箱地址' type='text' /> | ||
</Form.Item> | ||
|
||
<Form.Item | ||
name='password' | ||
rules={[{ required: true, message: '请输入密码' }]} | ||
> | ||
<Input prefix={<KeyOutlined />} type="password" placeholder='密码' /> | ||
</Form.Item> | ||
|
||
<Form.Item | ||
name='confirm' | ||
dependencies={['password']} | ||
rules={[{ required: true, message: '请再次输入密码' }, | ||
({ getFieldValue }) => ({ | ||
validator(_, value) { | ||
if (!value || getFieldValue('password') === value) { | ||
return Promise.resolve() | ||
} | ||
return Promise.reject(new Error('两次输入的密码不一致')) | ||
}, | ||
})]} | ||
> | ||
<Input prefix={<KeyOutlined />} type="password" placeholder='确认密码' /> | ||
</Form.Item> | ||
|
||
{ | ||
process.env.NEXT_PUBLIC_REGISTRY_SET === 'true' && | ||
<Form.Item | ||
name='authCode' | ||
rules={[{ required: true, message: '请输入注册码' }]} | ||
> | ||
<Input prefix={<CodeOutlined />} placeholder='注册码' /> | ||
</Form.Item> | ||
} | ||
|
||
<Form.Item> | ||
<Flex justify="space-between" align="center" className='mt-2'> | ||
<Button type='default' htmlType='button' className='w-[48%]' onClick={() => router.push('/login')}>返回登录</Button> | ||
<Button type='primary' htmlType='submit' className='w-[48%]'>立即注册</Button> | ||
</Flex> | ||
</Form.Item> | ||
</Form> | ||
</div> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters