|
|
|
|
@ -1,310 +0,0 @@
|
|
|
|
|
const express = require('express');
|
|
|
|
|
const cors = require('cors');
|
|
|
|
|
const bodyParser = require('body-parser');
|
|
|
|
|
const fs = require('fs');
|
|
|
|
|
const path = require('path');
|
|
|
|
|
const crypto = require('crypto');
|
|
|
|
|
|
|
|
|
|
// 导入工具类
|
|
|
|
|
const UserManager = require('./utils/user-manager');
|
|
|
|
|
const MultiEmailService = require('./utils/multi-email-service');
|
|
|
|
|
const MathQuestionGenerator = require('./utils/question-generator');
|
|
|
|
|
|
|
|
|
|
// 创建Express应用实例
|
|
|
|
|
const app = express();
|
|
|
|
|
const PORT = 8080;
|
|
|
|
|
|
|
|
|
|
// 配置中间件
|
|
|
|
|
app.use(cors());
|
|
|
|
|
app.use(bodyParser.json());
|
|
|
|
|
app.use(express.static(path.join(__dirname, '../project4')));
|
|
|
|
|
|
|
|
|
|
// 实例化管理器
|
|
|
|
|
const userManager = new UserManager();
|
|
|
|
|
const emailService = new MultiEmailService();
|
|
|
|
|
|
|
|
|
|
// 存储验证码(内存存储,重启后失效)
|
|
|
|
|
const verificationCodes = new Map();
|
|
|
|
|
|
|
|
|
|
// 生成6位数字验证码
|
|
|
|
|
function generateVerificationCode() {
|
|
|
|
|
return Math.floor(100000 + Math.random() * 900000).toString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 验证邮箱格式是否正确
|
|
|
|
|
function validateEmail(email) {
|
|
|
|
|
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// API路由
|
|
|
|
|
|
|
|
|
|
// 检查服务器健康状态
|
|
|
|
|
app.get('/api/health', (req, res) => {
|
|
|
|
|
res.json({
|
|
|
|
|
ok: true,
|
|
|
|
|
message: '服务正常运行',
|
|
|
|
|
emailService: emailService.transporter ? '已配置' : '测试模式'
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 发送邮箱验证码
|
|
|
|
|
app.post('/api/send-code', async (req, res) => {
|
|
|
|
|
try {
|
|
|
|
|
const {email, username} = req.body;
|
|
|
|
|
|
|
|
|
|
console.log('收到发送验证码请求:', {email, username});
|
|
|
|
|
|
|
|
|
|
if (!email || !username) {
|
|
|
|
|
return res.json({ok: false, message: '邮箱和用户名不能为空'});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 验证邮箱格式
|
|
|
|
|
if (!validateEmail(email)) {
|
|
|
|
|
return res.json({ok: false, message: '邮箱格式不正确'});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 限制邮箱域名,只允许QQ邮箱和163邮箱
|
|
|
|
|
if (!email.includes('@qq.com') && !email.includes('@163.com')) {
|
|
|
|
|
return res.json({ok: false, message: '只支持QQ邮箱和163邮箱'});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查用户名是否已存在
|
|
|
|
|
if (userManager.findUserByUsername(username)) {
|
|
|
|
|
return res.json({ok: false, message: '用户名已存在'});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查邮箱是否已注册
|
|
|
|
|
if (userManager.findUserByEmail(email)) {
|
|
|
|
|
return res.json({ok: false, message: '邮箱已被注册'});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const code = generateVerificationCode();
|
|
|
|
|
verificationCodes.set(email, {
|
|
|
|
|
code,
|
|
|
|
|
username,
|
|
|
|
|
timestamp: Date.now(),
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
console.log(`为邮箱 ${email} 生成验证码: ${code}`);
|
|
|
|
|
|
|
|
|
|
// 发送邮件
|
|
|
|
|
const emailResult = await emailService.sendVerificationCode(email, code, username);
|
|
|
|
|
|
|
|
|
|
if (emailResult.success) {
|
|
|
|
|
res.json({ok: true, message: emailResult.message});
|
|
|
|
|
} else {
|
|
|
|
|
// 如果邮件发送失败,但在开发模式下提供了验证码,仍然算成功
|
|
|
|
|
if (emailResult.debug) {
|
|
|
|
|
res.json({ok: true, message: emailResult.message + ' ' + emailResult.debug});
|
|
|
|
|
} else {
|
|
|
|
|
res.json({ok: false, message: emailResult.message});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('发送验证码错误:', error);
|
|
|
|
|
res.json({ok: false, message: '服务器内部错误'});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 验证码验证
|
|
|
|
|
app.post('/api/verify-code', (req, res) => {
|
|
|
|
|
try {
|
|
|
|
|
const {email, username, code} = req.body;
|
|
|
|
|
|
|
|
|
|
console.log('收到验证码验证请求:', {email, username, code});
|
|
|
|
|
|
|
|
|
|
if (!email || !username || !code) {
|
|
|
|
|
return res.json({ok: false, message: '请填写完整信息'});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const storedData = verificationCodes.get(email);
|
|
|
|
|
|
|
|
|
|
if (!storedData) {
|
|
|
|
|
return res.json({ok: false, message: '请先获取验证码'});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 验证码10分钟过期
|
|
|
|
|
if (Date.now() - storedData.timestamp > 10 * 60 * 1000) {
|
|
|
|
|
verificationCodes.delete(email);
|
|
|
|
|
return res.json({ok: false, message: '验证码已过期,请重新获取'});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (storedData.code !== code) {
|
|
|
|
|
return res.json({ok: false, message: '验证码不正确'});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (storedData.username !== username) {
|
|
|
|
|
return res.json({ok: false, message: '用户名与验证时不一致'});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 清除验证码
|
|
|
|
|
verificationCodes.delete(email);
|
|
|
|
|
|
|
|
|
|
res.json({ok: true, message: '验证成功,请设置密码'});
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('验证码验证错误:', error);
|
|
|
|
|
res.json({ok: false, message: error.message});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 注册(创建用户 + 设置密码)
|
|
|
|
|
app.post('/api/register', (req, res) => {
|
|
|
|
|
try {
|
|
|
|
|
const {email, username, password} = req.body;
|
|
|
|
|
|
|
|
|
|
console.log('收到注册请求:', {email, username});
|
|
|
|
|
|
|
|
|
|
if (!email || !username || !password) {
|
|
|
|
|
return res.json({ok: false, message: '请填写完整信息'});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 创建用户并设置密码
|
|
|
|
|
userManager.createUser(email, username);
|
|
|
|
|
userManager.setPassword(email, password);
|
|
|
|
|
|
|
|
|
|
res.json({ok: true, message: '注册成功'});
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('注册错误:', error);
|
|
|
|
|
res.json({ok: false, message: error.message});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 登录
|
|
|
|
|
app.post('/api/login', (req, res) => {
|
|
|
|
|
try {
|
|
|
|
|
const {account, password} = req.body;
|
|
|
|
|
|
|
|
|
|
if (!account || !password) {
|
|
|
|
|
return res.json({ok: false, message: '请填写账号和密码'});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 通过邮箱或用户名查找用户
|
|
|
|
|
let user = userManager.findUserByEmail(account);
|
|
|
|
|
if (!user) {
|
|
|
|
|
user = userManager.findUserByUsername(account);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!user || !user.password) {
|
|
|
|
|
return res.json({ok: false, message: '用户不存在'});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!userManager.verifyPassword(user.email, password)) {
|
|
|
|
|
return res.json({ok: false, message: '密码不正确'});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
res.json({
|
|
|
|
|
ok: true,
|
|
|
|
|
message: '登录成功',
|
|
|
|
|
data: {
|
|
|
|
|
email: user.email,
|
|
|
|
|
username: user.username,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('登录错误:', error);
|
|
|
|
|
res.json({ok: false, message: error.message});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 修改密码
|
|
|
|
|
app.post('/api/change-password', (req, res) => {
|
|
|
|
|
try {
|
|
|
|
|
const {email, oldPassword, newPassword} = req.body;
|
|
|
|
|
|
|
|
|
|
if (!email || !oldPassword || !newPassword) {
|
|
|
|
|
return res.json({ok: false, message: '请填写完整信息'});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
userManager.changePassword(email, oldPassword, newPassword);
|
|
|
|
|
res.json({ok: true, message: '密码修改成功'});
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('修改密码错误:', error);
|
|
|
|
|
res.json({ok: false, message: error.message});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 修改用户名
|
|
|
|
|
app.post('/api/change-username', (req, res) => {
|
|
|
|
|
try {
|
|
|
|
|
const {email, username} = req.body;
|
|
|
|
|
|
|
|
|
|
if (!email || !username) {
|
|
|
|
|
return res.json({ok: false, message: '请填写完整信息'});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
userManager.changeUsername(email, username);
|
|
|
|
|
res.json({ok: true, message: '用户名修改成功'});
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('修改用户名错误:', error);
|
|
|
|
|
res.json({ok: false, message: error.message});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 删除账号
|
|
|
|
|
app.post('/api/delete-account', (req, res) => {
|
|
|
|
|
try {
|
|
|
|
|
const {email, password} = req.body;
|
|
|
|
|
|
|
|
|
|
if (!email || !password) {
|
|
|
|
|
return res.json({ok: false, message: '请填写完整信息'});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 验证密码
|
|
|
|
|
if (!userManager.verifyPassword(email, password)) {
|
|
|
|
|
return res.json({ok: false, message: '密码不正确'});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
userManager.deleteUser(email);
|
|
|
|
|
res.json({ok: true, message: '账号删除成功'});
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('删除账号错误:', error);
|
|
|
|
|
res.json({ok: false, message: error.message});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 获取题目
|
|
|
|
|
app.get('/api/questions', (req, res) => {
|
|
|
|
|
try {
|
|
|
|
|
const {grade, count} = req.query;
|
|
|
|
|
|
|
|
|
|
if (!grade || !count) {
|
|
|
|
|
return res.json({ok: false, message: '请选择年级和题目数量'});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const countNum = parseInt(count);
|
|
|
|
|
if (isNaN(countNum) || countNum < 10 || countNum > 30) {
|
|
|
|
|
return res.json({ok: false, message: '题目数量需在10-30之间'});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const generator = new MathQuestionGenerator();
|
|
|
|
|
const questions = generator.generateQuestions(grade, countNum);
|
|
|
|
|
res.json({
|
|
|
|
|
ok: true,
|
|
|
|
|
data: questions,
|
|
|
|
|
message: '题目生成成功',
|
|
|
|
|
});
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('生成题目失败:', error);
|
|
|
|
|
res.json({ok: false, message: '生成题目失败'});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 提供前端页面
|
|
|
|
|
app.get('/', (req, res) => {
|
|
|
|
|
res.sendFile(path.join(__dirname, '../project4/index.html'));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 启动服务器
|
|
|
|
|
app.listen(PORT, () => {
|
|
|
|
|
console.log(`========================================`);
|
|
|
|
|
console.log(`🎓 数学学习软件后端服务已启动`);
|
|
|
|
|
console.log(`📍 服务地址: http://localhost:${PORT}`);
|
|
|
|
|
console.log(`🌐 前端页面: http://localhost:${PORT}/`);
|
|
|
|
|
console.log(`🔧 API文档: http://localhost:${PORT}/api/health`);
|
|
|
|
|
console.log(`📧 邮箱服务: ${emailService.transporter ? '已配置' : '测试模式'}`);
|
|
|
|
|
console.log(`========================================`);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
module.exports = app;
|
|
|
|
|
|