Generating commit message...

This commit is contained in:
2025-08-30 14:33:49 +08:00
parent 4d469e95f0
commit 7f9bfbb381
99 changed files with 69225 additions and 35 deletions

View File

@@ -0,0 +1,266 @@
const jwt = require('jsonwebtoken')
const { User } = require('../models/User')
const { AppError } = require('../utils/errors')
const { success } = require('../utils/response')
// 生成JWT Token
const generateToken = (userId) => {
return jwt.sign(
{ userId },
process.env.JWT_SECRET || 'your-secret-key',
{ expiresIn: process.env.JWT_EXPIRE || '7d' }
)
}
// 用户注册
const register = async (req, res, next) => {
try {
const { username, password, nickname, email, phone } = req.body
// 检查用户名是否已存在
const existingUser = await User.findOne({
$or: [
{ username },
{ email: email || null },
{ phone: phone || null }
]
})
if (existingUser) {
if (existingUser.username === username) {
throw new AppError('用户名已存在', 400)
}
if (existingUser.email === email) {
throw new AppError('邮箱已存在', 400)
}
if (existingUser.phone === phone) {
throw new AppError('手机号已存在', 400)
}
}
// 创建新用户
const user = new User({
username,
password,
nickname: nickname || username,
email,
phone
})
await user.save()
// 生成token
const token = generateToken(user._id)
// 更新最后登录时间
user.lastLoginAt = new Date()
await user.save()
res.status(201).json(success({
user: user.toJSON(),
token,
message: '注册成功'
}))
} catch (error) {
next(error)
}
}
// 用户登录
const login = async (req, res, next) => {
try {
const { username, password } = req.body
if (!username || !password) {
throw new AppError('用户名和密码不能为空', 400)
}
// 查找用户(支持用户名、邮箱、手机号登录)
const user = await User.findOne({
$or: [
{ username },
{ email: username },
{ phone: username }
]
})
if (!user) {
throw new AppError('用户不存在', 404)
}
// 检查用户状态
if (!user.isActive()) {
throw new AppError('账户已被禁用', 403)
}
// 验证密码
const isPasswordValid = await user.comparePassword(password)
if (!isPasswordValid) {
throw new AppError('密码错误', 401)
}
// 生成token
const token = generateToken(user._id)
// 更新最后登录时间
user.lastLoginAt = new Date()
await user.save()
res.json(success({
user: user.toJSON(),
token,
message: '登录成功'
}))
} catch (error) {
next(error)
}
}
// 获取当前用户信息
const getCurrentUser = async (req, res, next) => {
try {
const user = await User.findById(req.userId)
if (!user) {
throw new AppError('用户不存在', 404)
}
res.json(success({
user: user.toJSON()
}))
} catch (error) {
next(error)
}
}
// 更新用户信息
const updateProfile = async (req, res, next) => {
try {
const { nickname, avatar, gender, birthday } = req.body
const updates = {}
if (nickname !== undefined) updates.nickname = nickname
if (avatar !== undefined) updates.avatar = avatar
if (gender !== undefined) updates.gender = gender
if (birthday !== undefined) updates.birthday = birthday
const user = await User.findByIdAndUpdate(
req.userId,
updates,
{ new: true, runValidators: true }
)
if (!user) {
throw new AppError('用户不存在', 404)
}
res.json(success({
user: user.toJSON(),
message: '个人信息更新成功'
}))
} catch (error) {
next(error)
}
}
// 修改密码
const changePassword = async (req, res, next) => {
try {
const { currentPassword, newPassword } = req.body
if (!currentPassword || !newPassword) {
throw new AppError('当前密码和新密码不能为空', 400)
}
if (newPassword.length < 6) {
throw new AppError('新密码长度不能少于6位', 400)
}
const user = await User.findById(req.userId)
if (!user) {
throw new AppError('用户不存在', 404)
}
// 验证当前密码
const isCurrentPasswordValid = await user.comparePassword(currentPassword)
if (!isCurrentPasswordValid) {
throw new AppError('当前密码错误', 401)
}
// 更新密码
user.password = newPassword
await user.save()
res.json(success({
message: '密码修改成功'
}))
} catch (error) {
next(error)
}
}
// 微信登录/注册
const wechatLogin = async (req, res, next) => {
try {
const { code, userInfo } = req.body
if (!code) {
throw new AppError('微信授权码不能为空', 400)
}
// 这里应该调用微信API获取openid和unionid
// 模拟获取微信用户信息
const wechatUserInfo = {
openid: `mock_openid_${Date.now()}`,
unionid: `mock_unionid_${Date.now()}`,
nickname: userInfo?.nickName || '微信用户',
avatar: userInfo?.avatarUrl || '',
gender: userInfo?.gender === 1 ? 'male' : userInfo?.gender === 2 ? 'female' : 'unknown'
}
// 查找是否已存在微信用户
let user = await User.findOne({
$or: [
{ wechatOpenid: wechatUserInfo.openid },
{ wechatUnionid: wechatUserInfo.unionid }
]
})
if (user) {
// 更新最后登录时间
user.lastLoginAt = new Date()
await user.save()
} else {
// 创建新用户(微信注册)
user = new User({
username: `wx_${wechatUserInfo.openid.slice(-8)}`,
password: Math.random().toString(36).slice(-8), // 随机密码
nickname: wechatUserInfo.nickname,
avatar: wechatUserInfo.avatar,
gender: wechatUserInfo.gender,
wechatOpenid: wechatUserInfo.openid,
wechatUnionid: wechatUserInfo.unionid
})
await user.save()
}
// 生成token
const token = generateToken(user._id)
res.json(success({
user: user.toJSON(),
token,
message: '微信登录成功'
}))
} catch (error) {
next(error)
}
}
module.exports = {
register,
login,
getCurrentUser,
updateProfile,
changePassword,
wechatLogin
}

View File

@@ -0,0 +1,260 @@
const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs');
const UserMySQL = require('../models/UserMySQL');
const { AppError } = require('../utils/errors');
const { success } = require('../utils/response');
// 生成JWT Token
const generateToken = (userId) => {
return jwt.sign(
{ userId },
process.env.JWT_SECRET || 'your-secret-key',
{ expiresIn: process.env.JWT_EXPIRE || '7d' }
);
};
// 用户注册
const register = async (req, res, next) => {
try {
const { username, password, nickname, email, phone } = req.body;
// 检查用户名是否已存在
if (await UserMySQL.isUsernameExists(username)) {
throw new AppError('用户名已存在', 400);
}
// 检查邮箱是否已存在
if (email && await UserMySQL.isEmailExists(email)) {
throw new AppError('邮箱已存在', 400);
}
// 检查手机号是否已存在
if (phone && await UserMySQL.isPhoneExists(phone)) {
throw new AppError('手机号已存在', 400);
}
// 加密密码
const hashedPassword = await bcrypt.hash(password, 12);
// 创建新用户
const userId = await UserMySQL.create({
username,
password: hashedPassword,
nickname: nickname || username,
email,
phone
});
// 获取用户信息
const user = await UserMySQL.findById(userId);
// 生成token
const token = generateToken(userId);
// 更新最后登录时间
await UserMySQL.updateLastLogin(userId);
res.status(201).json(success({
user: UserMySQL.sanitize(user),
token,
message: '注册成功'
}));
} catch (error) {
next(error);
}
};
// 用户登录
const login = async (req, res, next) => {
try {
const { username, password } = req.body;
if (!username || !password) {
throw new AppError('用户名和密码不能为空', 400);
}
// 查找用户(支持用户名、邮箱、手机号登录)
let user = await UserMySQL.findByUsername(username);
if (!user) {
user = await UserMySQL.findByEmail(username);
}
if (!user) {
user = await UserMySQL.findByPhone(username);
}
if (!user) {
throw new AppError('用户不存在', 404);
}
// 检查用户状态
if (!UserMySQL.isActive(user)) {
throw new AppError('账户已被禁用', 403);
}
// 验证密码
const isPasswordValid = await bcrypt.compare(password, user.password);
if (!isPasswordValid) {
throw new AppError('密码错误', 401);
}
// 生成token
const token = generateToken(user.id);
// 更新最后登录时间
await UserMySQL.updateLastLogin(user.id);
res.json(success({
user: UserMySQL.sanitize(user),
token,
message: '登录成功'
}));
} catch (error) {
next(error);
}
};
// 获取当前用户信息
const getCurrentUser = async (req, res, next) => {
try {
const user = await UserMySQL.findById(req.userId);
if (!user) {
throw new AppError('用户不存在', 404);
}
res.json(success({
user: UserMySQL.sanitize(user)
}));
} catch (error) {
next(error);
}
};
// 更新用户信息
const updateProfile = async (req, res, next) => {
try {
const { nickname, avatar, gender, birthday } = req.body;
const updates = {};
if (nickname !== undefined) updates.nickname = nickname;
if (avatar !== undefined) updates.avatar = avatar;
if (gender !== undefined) updates.gender = gender;
if (birthday !== undefined) updates.birthday = birthday;
const success = await UserMySQL.update(req.userId, updates);
if (!success) {
throw new AppError('更新失败', 400);
}
const user = await UserMySQL.findById(req.userId);
res.json(success({
user: UserMySQL.sanitize(user),
message: '个人信息更新成功'
}));
} catch (error) {
next(error);
}
};
// 修改密码
const changePassword = async (req, res, next) => {
try {
const { currentPassword, newPassword } = req.body;
if (!currentPassword || !newPassword) {
throw new AppError('当前密码和新密码不能为空', 400);
}
if (newPassword.length < 6) {
throw new AppError('新密码长度不能少于6位', 400);
}
const user = await UserMySQL.findById(req.userId);
if (!user) {
throw new AppError('用户不存在', 404);
}
// 验证当前密码
const isCurrentPasswordValid = await bcrypt.compare(currentPassword, user.password);
if (!isCurrentPasswordValid) {
throw new AppError('当前密码错误', 401);
}
// 加密新密码
const hashedPassword = await bcrypt.hash(newPassword, 12);
// 更新密码
await UserMySQL.updatePassword(req.userId, hashedPassword);
res.json(success({
message: '密码修改成功'
}));
} catch (error) {
next(error);
}
};
// 微信登录/注册
const wechatLogin = async (req, res, next) => {
try {
const { code, userInfo } = req.body;
if (!code) {
throw new AppError('微信授权码不能为空', 400);
}
// 这里应该调用微信API获取openid和unionid
// 模拟获取微信用户信息
const wechatUserInfo = {
openid: `mock_openid_${Date.now()}`,
unionid: `mock_unionid_${Date.now()}`,
nickname: userInfo?.nickName || '微信用户',
avatar: userInfo?.avatarUrl || '',
gender: userInfo?.gender === 1 ? 'male' : userInfo?.gender === 2 ? 'female' : 'unknown'
};
// 查找是否已存在微信用户
let user = await UserMySQL.findByWechatOpenid(wechatUserInfo.openid);
if (user) {
// 更新最后登录时间
await UserMySQL.updateLastLogin(user.id);
} else {
// 创建新用户(微信注册)
const randomPassword = Math.random().toString(36).slice(-8);
const hashedPassword = await bcrypt.hash(randomPassword, 12);
const userId = await UserMySQL.create({
username: `wx_${wechatUserInfo.openid.slice(-8)}`,
password: hashedPassword,
nickname: wechatUserInfo.nickname,
avatar: wechatUserInfo.avatar,
gender: wechatUserInfo.gender,
wechatOpenid: wechatUserInfo.openid,
wechatUnionid: wechatUserInfo.unionid
});
user = await UserMySQL.findById(userId);
}
// 生成token
const token = generateToken(user.id);
res.json(success({
user: UserMySQL.sanitize(user),
token,
message: '微信登录成功'
}));
} catch (error) {
next(error);
}
};
module.exports = {
register,
login,
getCurrentUser,
updateProfile,
changePassword,
wechatLogin
};