diff --git a/app.js b/app.js index fe10396..75bcf7a 100644 --- a/app.js +++ b/app.js @@ -1,35 +1,20 @@ import createError from 'http-errors' - import express from 'express' - import path from 'path' - import logger from 'morgan' - import cors from 'cors' - import session from 'express-session' - import { RedisStore } from 'connect-redis' - import Redis from 'ioredis' - +import { fileURLToPath } from 'url' import cookieParser from 'cookie-parser' - -import indexRouter from './routes/index' - -import userRouter from './routes/userRouter' - -import accountRouter from './routes/accountRouter' - +import indexRouter from './routes/index.js' +import userRouter from './routes/userRouter.js' +import accountRouter from './routes/accountRouter.js' import { config } from 'dotenv' - -// mongodb数据库连接 -import { connectMongoDB } from './config/mongodbConfig' - -import { HTTP_STATUS } from './common/constant/httpStatus' - -import loginUtil from './utils/loginUtil' +import { connectMongoDB } from './config/mongodbConfig.js' +import { HTTP_STATUS } from './common/constant/httpStatus.js' +import { authenticateSession } from './utils/loginUtil.js' config() // 初始化 Redis 客户端 @@ -42,6 +27,9 @@ const redisClient = new Redis({ const app = express() +const __filename = fileURLToPath(import.meta.url) +const __dirname = path.dirname(__filename) + app.use(logger('dev')) app.use(express.json()) app.use(express.urlencoded({ extended: false })) @@ -81,7 +69,7 @@ async function startServer() { startServer().then((r) => logger(r)) app.use('/', indexRouter) -app.use('/user', loginUtil.authenticateSession, userRouter) +app.use('/user', authenticateSession, userRouter) app.use('/account', accountRouter) // catch 404 and forward to error handler @@ -105,4 +93,4 @@ app.use(function (err, req, res) { }) }) -module.exports = app +export default app diff --git a/bin/www b/bin/www index 62e99f5..944e23f 100644 --- a/bin/www +++ b/bin/www @@ -3,9 +3,9 @@ /** * Module dependencies. */ -const app = require('../app') -const debug = require('debug')('express:server') -const http = require('http') +import app from '../app.js' +import debug from 'debug' +import http from 'http' /** * Get port from environment and store in Express. diff --git a/controllers/userController.js b/controllers/userController.js index ac2dc82..94672fb 100644 --- a/controllers/userController.js +++ b/controllers/userController.js @@ -1,12 +1,12 @@ import { body, validationResult } from 'express-validator' import logger from 'morgan' -import userService from '../services/userService' -import FetchResult from '../common/web/fetchResult' -import messages from '../config/messages' -import { HTTP_STATUS } from '../common/constant/httpStatus' -import { SearchQuery } from '../models/search' +import userService from '../services/userService.js' +import FetchResult from '../common/web/fetchResult.js' +import messages from '../config/messages.js' +import { HTTP_STATUS } from '../common/constant/httpStatus.js' +import { SearchQuery } from '../models/search.js' -export default UserController = { +const UserController = { async getAllUsers(res) { try { const users = await userService.getUserList() @@ -128,3 +128,5 @@ export default UserController = { } } } + +export default UserController diff --git a/models/userModel.js b/models/userModel.js index cd9fdea..65682f9 100644 --- a/models/userModel.js +++ b/models/userModel.js @@ -1,5 +1,5 @@ import { Schema as _Schema, model } from 'mongoose' -import { hashPassword } from '../utils/hashUtils' +import { hashPassword } from '../utils/hashUtils.js' const Schema = _Schema const UserSchema = new Schema({ @@ -7,12 +7,12 @@ const UserSchema = new Schema({ gender: { type: String, enum: ['male', 'female', 'other'], maxlength: 20 }, birth: { type: Date }, avatar: { type: String, maxlength: 100 }, - account: { type: String, required: true, unique: true, maxlength: 100, index: true }, + account: { type: String, required: true, unique: true, maxlength: 100 }, password: { type: String, required: true, maxlength: 100 }, - email: { type: String, maxlength: 255, index: true }, - phone: { type: String, maxlength: 11 }, + email: { type: String, match: /^\S+@\S+\.\S+$/, maxlength: 255, index: true }, + phone: { type: String, match: /^1[3-9]\d{9}$/, maxlength: 11 }, registerDate: { type: Date, default: Date.now }, - lastLoginDate: { type: Date, default: Date.now }, + lastLoginDate: { type: Date }, status: { type: String, enum: ['active', 'inactive', 'pending'], default: 'pending' } }) @@ -20,13 +20,18 @@ UserSchema.pre('save', async function (next) { const user = this if (!user.isModified('password')) return next() try { - console.log(user.password) - user.password = await hashPassword(user.password) next() } catch (error) { - next(error) + // 记录错误日志,避免泄露敏感信息 + console.error('Error hashing password:', error.message) + next(new Error('Failed to hash password')) } }) +// 更新 lastLoginDate 在用户登录时 +UserSchema.methods.updateLastLoginDate = function () { + this.lastLoginDate = new Date() +} + export default model('User', UserSchema) diff --git a/repositories/userRepository.js b/repositories/userRepository.js index 3d0d084..29724cf 100644 --- a/repositories/userRepository.js +++ b/repositories/userRepository.js @@ -1,19 +1,27 @@ -import { - startSession, - find, - aggregate, - findById, - findOne, - exists, - create, - findByIdAndUpdate, - findByIdAndDelete, - deleteMany -} from '../models/userModel' -import { SearchResult } from '../models/search' +import User from '../models/userModel.js' +import { SearchResult } from '../models/search.js' + +const userRepository = { + startTransaction, + commitTransaction, + rollbackTransaction, + selectAllUser, + selectUserList, + selectUserById, + selectUserByAccount, + selectUserByEmail, + selectUserByUsername, + selectUserByPhone, + selectUserByAccountExist, + createUser, + updateUserById, + updateUserByLoginDate, + deleteUserById, + deleteAllUser +} export async function startTransaction() { - const session = await startSession() + const session = await User.startSession() session.startTransaction() return session } @@ -27,7 +35,7 @@ export async function rollbackTransaction(session) { } export async function selectAllUser() { - return find() + return User.find() } export async function selectUserList(search = {}) { @@ -43,7 +51,7 @@ export async function selectUserList(search = {}) { const matchFilters = filters ? { ...filters } : {} const sortObj = sort && typeof sort === 'object' ? sort : { _id: 1 } // 默认按 _id 升序排序 - const result = await aggregate([ + const result = await User.aggregate([ // 应用过滤条件,确保filters存在时才传入 { $match: matchFilters }, { @@ -69,46 +77,48 @@ export async function selectUserList(search = {}) { } export async function selectUserById(id) { - return findById(id) + return User.findById(id) } export async function selectUserByAccount(account) { - return findOne({ account: account }) + return User.findOne({ account: account }) } export async function selectUserByEmail(email) { - return findOne({ email: email }) + return User.findOne({ email: email }) } export async function selectUserByUsername(username) { - return findOne({ username: username }) + return User.findOne({ username: username }) } export async function selectUserByPhone(phone) { - return findOne({ phone: phone }) + return User.findOne({ phone: phone }) } export async function selectUserByAccountExist(account) { - const exist = await exists({ account: account }) + const exist = await User.exists({ account: account }) return exist !== null } export async function createUser(user) { - return create(user) + return User.create(user) } export async function updateUserById(id, user) { - return findByIdAndUpdate(id, user) + return User.findByIdAndUpdate(id, user) } export async function updateUserByLoginDate(id, loginDate) { - return findByIdAndUpdate(id, { last_login_date: loginDate }) + return User.findByIdAndUpdate(id, { lastLoginDate: loginDate }) } export async function deleteUserById(id) { - return findByIdAndDelete(id) + return User.findByIdAndDelete(id) } export async function deleteAllUser() { - return deleteMany() + return User.deleteMany() } + +export default userRepository diff --git a/routes/accountRouter.js b/routes/accountRouter.js index 726d098..5e0c7f5 100644 --- a/routes/accountRouter.js +++ b/routes/accountRouter.js @@ -1,9 +1,9 @@ // routes/userRoutes.js import express from 'express' -const userController = import('../controllers/userController') +import userController from '../controllers/userController.js' const router = express.Router() -router.get('/', getUserExists) +router.get('/', userController.getUserExists) export default router diff --git a/routes/index.js b/routes/index.js index 9f39dd0..e33df05 100644 --- a/routes/index.js +++ b/routes/index.js @@ -1,6 +1,6 @@ import express from 'express' -import userController from '../controllers/userController' +import userController from '../controllers/userController.js' const router = express.Router() router.get('/', function (req, res) { diff --git a/routes/userRouter.js b/routes/userRouter.js index 7fbe640..fef1151 100644 --- a/routes/userRouter.js +++ b/routes/userRouter.js @@ -1,7 +1,5 @@ -// routes/userRoutes.js -import userController from '../controllers/userController' - import express from 'express' +import userController from '../controllers/userController.js' const router = express.Router() diff --git a/services/userService.js b/services/userService.js index 8bc1f96..61d423c 100644 --- a/services/userService.js +++ b/services/userService.js @@ -1,9 +1,9 @@ -import userMapper from '../repositories/userRepository' +import userRepository from '../repositories/userRepository.js' import logger from 'morgan' -import messages from '../config/messages' -import { comparePassword } from '../utils/hashUtils' +import messages from '../config/messages.js' +import { comparePassword } from '../utils/hashUtils.js' -export default userServeice = { +const userService = { /** * 用户登录 * @param {string} account - 用户账号 @@ -12,7 +12,7 @@ export default userServeice = { * @throws {Error} - 如果用户不存在或密码不正确 */ async login(account, password) { - const user = await userMapper.selectUserByAccount(account) + const user = await userRepository.selectUserByAccount(account) // 用户不存在 if (!user) { @@ -27,7 +27,7 @@ export default userServeice = { // 更新用户的最后登录时间 user.lastLoginDate = new Date() - await userMapper.updateUserByLoginDate(user.id, user.lastLoginDate) + await userRepository.updateUserByLoginDate(user.id, user.lastLoginDate) return user }, @@ -38,16 +38,16 @@ export default userServeice = { * @returns {Promise} */ async getUserExists(account) { - return userMapper.selectUserByAccountExist(account) + return userRepository.selectUserByAccountExist(account) }, // Removed the unnecessary try-catch block and simplified the function async getAllUser() { - return await userMapper.selectAllUser() + return await userRepository.selectAllUser() }, async getUserList(searchQuery) { - return userMapper.selectUserList(searchQuery) + return userRepository.selectUserList(searchQuery) }, /** @@ -58,27 +58,29 @@ export default userServeice = { */ async createUser(user) { const { account } = user - const session = await userMapper.startTransaction() + const session = await userRepository.startTransaction() try { // 检查用户是否已存在 - const existingUser = await userMapper.selectUserByAccount(account) + const existingUser = await userRepository.selectUserByAccount(account) if (existingUser) { return new Error(messages.user.alreadyExists) } // 创建新用户 - const result = await userMapper.createUser(user) + const result = await userRepository.createUser(user) // 提交事务 - await userMapper.commitTransaction(session) + await userRepository.commitTransaction(session) return result } catch (err) { // 回滚事务 - await userMapper.rollbackTransaction(session).catch((rollbackErr) => { + await userRepository.rollbackTransaction(session).catch((rollbackErr) => { logger('Error rolling back transaction: ', rollbackErr) }) throw err // 将错误抛给调用方(Controller 层) } } } + +export default userService diff --git a/utils/hashUtils.js b/utils/hashUtils.js index 15aa4e7..329bfd5 100644 --- a/utils/hashUtils.js +++ b/utils/hashUtils.js @@ -5,7 +5,7 @@ import bcrypt from 'bcrypt' * @param {string} password 密码 * @returns password 加密后的密码 */ -async function hashPassword(password) { +export async function hashPassword(password) { return bcrypt.hash(password, 10) } @@ -18,5 +18,3 @@ async function hashPassword(password) { export async function comparePassword(password, hashedPassword) { return bcrypt.compare(password, hashedPassword) } - -export default { hashPassword, comparePassword }