Compare commits
4 Commits
main
...
29d5830d54
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
29d5830d54 | ||
|
|
2c6d8a4434 | ||
|
|
a7e4f68495 | ||
|
|
5719818b9d |
@@ -28,7 +28,6 @@ module.exports = async (req, res, next) => {
|
||||
const user = await UserModel.findById(decodedToken.id)
|
||||
if (!user.user_name ||
|
||||
!user.first_name ||
|
||||
!user.last_name ||
|
||||
!user.user_type ||
|
||||
!user.password) {
|
||||
return res.status(403).send({
|
||||
|
||||
@@ -26,7 +26,6 @@ module.exports = async (req, res, next) => {
|
||||
const user = await UserModel.findById(decodedToken.id)
|
||||
if (!user.user_name ||
|
||||
!user.first_name ||
|
||||
!user.last_name ||
|
||||
!user.password) {
|
||||
return res.status(403).send({
|
||||
status: 'error',
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
const UserModel = require('../../../models/UserModel')
|
||||
const { check, validationResult } = require('express-validator')
|
||||
const { default: axios } = require('axios')
|
||||
const { OTP_VALID_MS } = require('../../../utils/otpExpiry')
|
||||
const loginValidationRules = () => {
|
||||
return [
|
||||
check('mobile')
|
||||
@@ -34,18 +35,22 @@ const loginUser = async (req, res, next) => {
|
||||
}
|
||||
|
||||
const otp = generateOTP()
|
||||
const otpSentAt = new Date()
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const user = await UserModel.findOneAndUpdate(
|
||||
{ mobile },
|
||||
{ $set: { mobile, otp } },
|
||||
{ $set: { mobile, otp: String(otp), otpSentAt } },
|
||||
{ upsert: true, new: true, lean: true }
|
||||
)
|
||||
// زمانبندی تنظیم مقدار otp به null پس از 10 دقیقه
|
||||
setTimeout(() => {
|
||||
UserModel.findOneAndUpdate({ mobile }, { $set: { otp: null } }, { new: true })
|
||||
UserModel.findOneAndUpdate(
|
||||
{ mobile },
|
||||
{ $set: { otp: null, otpSentAt: null } },
|
||||
{ new: true }
|
||||
)
|
||||
.then(() => {})
|
||||
.catch(error => console.error('Error setting OTP to null:', error))
|
||||
}, 5 * 60 * 1000)
|
||||
}, OTP_VALID_MS)
|
||||
const data = JSON.stringify({
|
||||
mobile,
|
||||
templateId: '930719',
|
||||
|
||||
@@ -64,7 +64,7 @@ const loginWithUserName = async (req, res, next) => {
|
||||
(!user.password) { step = 'password' } else if
|
||||
(!user.first_name) { step = 'first_name' } else if
|
||||
(!user.user_type) { step = 'user_type' }
|
||||
if (!user.user_type || user.user_name === null || !user.first_name || !user.last_name) {
|
||||
if (!user.user_type || user.user_name === null || !user.first_name) {
|
||||
return res.json({
|
||||
message: 'کد تایید صحیح بود',
|
||||
token,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
const UserModel = require('../../../models/UserModel')
|
||||
const TokenService = require('../../../services/TokenService')
|
||||
const { isOtpExpired } = require('../../../utils/otpExpiry')
|
||||
// const jwt = require('jsonwebtoken')
|
||||
|
||||
const verifyUser = async (req, res, next) => {
|
||||
@@ -20,7 +21,15 @@ const verifyUser = async (req, res, next) => {
|
||||
})
|
||||
}
|
||||
const token = TokenService.sign({ id: user._id })
|
||||
if (user.otp === otp) {
|
||||
|
||||
if (!user.otp || isOtpExpired(user)) {
|
||||
return res.status(422).json({
|
||||
error: true,
|
||||
message: 'کد تایید منقضی شده است. لطفاً دوباره درخواست ارسال کد دهید'
|
||||
})
|
||||
}
|
||||
|
||||
if (String(user.otp) === String(otp)) {
|
||||
// if (user.user_name === null) {
|
||||
// return res.json({
|
||||
// message: 'کد تایید صحیح بود',
|
||||
@@ -55,7 +64,7 @@ const verifyUser = async (req, res, next) => {
|
||||
(!user.password) { step = 'password' } else if
|
||||
(!user.first_name) { step = 'first_name' } else if
|
||||
(!user.user_type) { step = 'user_type' } else { step = 'profile_image' }
|
||||
if (!user.user_type || user.user_name === null || !user.first_name || !user.last_name) {
|
||||
if (!user.user_type || user.user_name === null || !user.first_name) {
|
||||
return res.json({
|
||||
message: 'کد تایید صحیح بود',
|
||||
token,
|
||||
|
||||
@@ -81,7 +81,6 @@ const getProfile = async (req, res, next) => {
|
||||
let isRegister = true
|
||||
if (!user.user_name ||
|
||||
!user.first_name ||
|
||||
!user.last_name ||
|
||||
!user.user_type ||
|
||||
!user.national_card_image ||
|
||||
!user.password ||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
const { default: axios } = require('axios')
|
||||
const UserModel = require('../../../models/UserModel')
|
||||
const { check, validationResult } = require('express-validator')
|
||||
const { OTP_VALID_MS } = require('../../../utils/otpExpiry')
|
||||
// const { Token, VerificationCode } = require('sms-ir')
|
||||
|
||||
const registerValidationRules = () => {
|
||||
@@ -36,17 +37,22 @@ const registerUser = async (req, res, next) => {
|
||||
}
|
||||
|
||||
const otp = generateOTP()
|
||||
const otpSentAt = new Date()
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const user = await UserModel.findOneAndUpdate(
|
||||
{ mobile },
|
||||
{ $set: { mobile, otp } },
|
||||
{ $set: { mobile, otp: String(otp), otpSentAt } },
|
||||
{ upsert: true, new: true, lean: true }
|
||||
)
|
||||
setTimeout(() => {
|
||||
UserModel.findOneAndUpdate({ mobile }, { $set: { otp: null } }, { new: true })
|
||||
UserModel.findOneAndUpdate(
|
||||
{ mobile },
|
||||
{ $set: { otp: null, otpSentAt: null } },
|
||||
{ new: true }
|
||||
)
|
||||
.then(() => {})
|
||||
.catch(error => console.error('Error setting OTP to null:', error))
|
||||
}, 5 * 60 * 1000)
|
||||
}, OTP_VALID_MS)
|
||||
const data = JSON.stringify({
|
||||
mobile,
|
||||
templateId: '930719',
|
||||
|
||||
@@ -7,8 +7,6 @@ const setUserFullNameValidationRules = () => {
|
||||
return [
|
||||
check('first_name')
|
||||
.notEmpty().withMessage('نام نمیتواند خالی باشد'),
|
||||
check('last_name')
|
||||
.notEmpty().withMessage('نام خانوادگی نمیتواند خالی باشد')
|
||||
]
|
||||
}
|
||||
|
||||
@@ -34,8 +32,8 @@ const setUserFullName = async (req, res, next) => {
|
||||
}
|
||||
|
||||
// آپدیت نام کاربری به صورت lowercase
|
||||
user.first_name = first_name.toLowerCase()
|
||||
user.last_name = last_name.toLowerCase()
|
||||
user.first_name = first_name.trim().toLowerCase()
|
||||
user.last_name = last_name?.trim() ? last_name.trim().toLowerCase() : null
|
||||
await user.save()
|
||||
|
||||
return res.json({
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/* eslint-disable camelcase */
|
||||
const UserModel = require('../../../models/UserModel')
|
||||
const jwt = require('jsonwebtoken')
|
||||
const { validateUsername } = require('../../../utils/usernameValidation')
|
||||
const { generateUsernameSuggestions } = require('../../../utils/usernameSuggestions')
|
||||
|
||||
const setUserName = async (req, res, next) => {
|
||||
try {
|
||||
@@ -20,32 +22,33 @@ const setUserName = async (req, res, next) => {
|
||||
message: 'کاربری با این شماره موبایل یافت نشد'
|
||||
})
|
||||
}
|
||||
// بررسی حداقل طول نام کاربری
|
||||
if (user_name.length < 5) {
|
||||
const validationError = validateUsername(user_name)
|
||||
if (validationError) {
|
||||
return res.status(422).json({
|
||||
error: true,
|
||||
message: 'نام کاربری باید حداقل 5 کاراکتر باشد'
|
||||
message: validationError
|
||||
})
|
||||
}
|
||||
// بررسی محدودیتهای مجاز در نام کاربری
|
||||
// const usernameRegex = /^[a-zA-Z0-9_]+$/
|
||||
// if (!usernameRegex.test(user_name)) {
|
||||
// return res.status(422).json({
|
||||
// error: true,
|
||||
// message: 'نام کاربری فقط میتواند شامل حروف الفبای انگلیسی، اعداد و کاراکتر _ باشد'
|
||||
// })
|
||||
// }
|
||||
|
||||
const normalizedUserName = user_name.trim().toLowerCase()
|
||||
|
||||
// بررسی تکراری بودن user_name
|
||||
const existingUser = await UserModel.findOne({ user_name: { $regex: new RegExp('^' + user_name + '$', 'i') } })
|
||||
const existingUser = await UserModel.findOne({ user_name: { $regex: new RegExp('^' + normalizedUserName + '$', 'i') } })
|
||||
if (existingUser && existingUser._id.toString() !== user._id.toString()) {
|
||||
const suggestions = await generateUsernameSuggestions(
|
||||
UserModel,
|
||||
normalizedUserName,
|
||||
user._id.toString()
|
||||
)
|
||||
return res.status(422).json({
|
||||
error: true,
|
||||
message: 'نام کاربری تکراری است'
|
||||
message: 'نام کاربری تکراری است',
|
||||
suggestions
|
||||
})
|
||||
}
|
||||
|
||||
// آپدیت نام کاربری به صورت lowercase
|
||||
user.user_name = user_name.toLowerCase()
|
||||
user.user_name = normalizedUserName
|
||||
await user.save()
|
||||
|
||||
return res.json({
|
||||
@@ -73,7 +76,37 @@ const updateUserName = async (req, res, next) => {
|
||||
})
|
||||
}
|
||||
|
||||
const user = await UserModel.findByIdAndUpdate(userId, { user_name }, { new: true })
|
||||
const validationError = validateUsername(user_name)
|
||||
if (validationError) {
|
||||
return res.status(422).json({
|
||||
error: true,
|
||||
message: validationError
|
||||
})
|
||||
}
|
||||
|
||||
const normalizedUserName = user_name.trim().toLowerCase()
|
||||
|
||||
const existingUser = await UserModel.findOne({
|
||||
user_name: { $regex: new RegExp('^' + normalizedUserName + '$', 'i') }
|
||||
})
|
||||
if (existingUser && existingUser._id.toString() !== userId) {
|
||||
const suggestions = await generateUsernameSuggestions(
|
||||
UserModel,
|
||||
normalizedUserName,
|
||||
userId
|
||||
)
|
||||
return res.status(422).json({
|
||||
error: true,
|
||||
message: 'نام کاربری تکراری است',
|
||||
suggestions
|
||||
})
|
||||
}
|
||||
|
||||
const user = await UserModel.findByIdAndUpdate(
|
||||
userId,
|
||||
{ user_name: normalizedUserName },
|
||||
{ new: true }
|
||||
)
|
||||
|
||||
if (!user) {
|
||||
return res.status(404).json({
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
const UserModel = require('../../../models/UserModel')
|
||||
const TokenService = require('../../../services/TokenService')
|
||||
const { isOtpExpired } = require('../../../utils/otpExpiry')
|
||||
// const jwt = require('jsonwebtoken')
|
||||
|
||||
const verifyUser = async (req, res, next) => {
|
||||
@@ -25,7 +26,14 @@ const verifyUser = async (req, res, next) => {
|
||||
(!user.password) { step = 'password' } else if
|
||||
(!user.first_name) { step = 'first_name' } else if
|
||||
(!user.user_type) { step = 'user_type' } else { step = 'profile_image' }
|
||||
if (user.otp === otp) {
|
||||
if (!user.otp || isOtpExpired(user)) {
|
||||
return res.status(422).json({
|
||||
error: true,
|
||||
message: 'کد تایید منقضی شده است. لطفاً دوباره درخواست ارسال کد دهید'
|
||||
})
|
||||
}
|
||||
|
||||
if (String(user.otp) === String(otp)) {
|
||||
return res.json({
|
||||
message: 'کد تایید صحیح بود',
|
||||
token,
|
||||
|
||||
@@ -33,7 +33,7 @@ const setProfileImage = async (req, res, next) => {
|
||||
}
|
||||
|
||||
// ذخیره فایل عکس پروفایل
|
||||
const uploadDir = path.join(__dirname, '../../../../storage/profiles')
|
||||
const uploadDir = path.join(__dirname, '../../../storage/profiles')
|
||||
if (!fs.existsSync(uploadDir)) {
|
||||
fs.mkdirSync(uploadDir, { recursive: true })
|
||||
}
|
||||
@@ -78,7 +78,7 @@ const updateProfileImage = async (req, res, next) => {
|
||||
})
|
||||
}
|
||||
|
||||
const uploadDir = path.join(__dirname, '../../../../storage/profiles')
|
||||
const uploadDir = path.join(__dirname, '../../../storage/profiles')
|
||||
|
||||
if (!fs.existsSync(uploadDir)) {
|
||||
fs.mkdirSync(uploadDir, { recursive: true })
|
||||
|
||||
10
index.js
@@ -98,14 +98,22 @@ const io = require('socket.io')(http, {
|
||||
app.use(express.json({ limit: '1000mb' }));
|
||||
app.use(express.urlencoded({ limit: '1000mb', extended: true }));
|
||||
|
||||
app.use('/storage', express.static(path.join(__dirname, 'storage')));
|
||||
// مسیرهای مشخص قبل از /storage عمومی — پروفایل از هر دو محل (قدیم و جدید) سرو میشود
|
||||
app.use('/storage/profiles', express.static(path.join(__dirname, '../storage/profiles')));
|
||||
app.use('/storage/profiles', express.static(path.join(__dirname, 'storage/profiles')));
|
||||
app.use('/storage/carts', express.static(path.join(__dirname, '../storage/carts')));
|
||||
app.use('/storage/carts', express.static(path.join(__dirname, 'storage/carts')));
|
||||
app.use('/storage/posts', express.static(path.join(__dirname, 'storage/posts')));
|
||||
app.use('/storage/posts', express.static(path.join(__dirname, '../storage/posts')));
|
||||
app.use('/storage/messages', express.static(path.join(__dirname, '../storage/messages')));
|
||||
app.use('/storage/messages', express.static(path.join(__dirname, 'storage/messages')));
|
||||
app.use('/storage/tickets', express.static(path.join(__dirname, '../storage/tickets')));
|
||||
app.use('/storage/tickets', express.static(path.join(__dirname, 'storage/tickets')));
|
||||
app.use('/storage/advertising', express.static(path.join(__dirname, '../storage/advertising')));
|
||||
app.use('/storage/advertising', express.static(path.join(__dirname, 'storage/advertising')));
|
||||
app.use('/storage/services', express.static(path.join(__dirname, '../storage/services')));
|
||||
app.use('/storage/services', express.static(path.join(__dirname, 'storage/services')));
|
||||
app.use('/storage', express.static(path.join(__dirname, 'storage')));
|
||||
|
||||
require('./boot');
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@ module.exports = async (req, res, next) => {
|
||||
const user = await UserModel.findById(decodedToken.id)
|
||||
if (!user.user_name ||
|
||||
!user.first_name ||
|
||||
!user.last_name ||
|
||||
!user.user_type ||
|
||||
!user.password) {
|
||||
return res.status(403).send({
|
||||
|
||||
@@ -26,7 +26,6 @@ module.exports = async (req, res, next) => {
|
||||
const user = await UserModel.findById(decodedToken.id)
|
||||
if (!user.user_name ||
|
||||
!user.first_name ||
|
||||
!user.last_name ||
|
||||
!user.password) {
|
||||
return res.status(403).send({
|
||||
status: 'error',
|
||||
|
||||
@@ -16,6 +16,11 @@ const userSchema = new mongoose.Schema({
|
||||
maxLength: 6,
|
||||
default: null
|
||||
},
|
||||
otpSentAt: {
|
||||
type: Date,
|
||||
required: false,
|
||||
default: null
|
||||
},
|
||||
user_name: {
|
||||
type: String,
|
||||
required: false,
|
||||
|
||||
|
Before Width: | Height: | Size: 192 KiB |
|
Before Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 488 KiB |
|
Before Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 494 KiB |
|
Before Width: | Height: | Size: 144 KiB |
|
Before Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 76 KiB |
|
Before Width: | Height: | Size: 51 KiB |
|
Before Width: | Height: | Size: 69 KiB |
|
Before Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 216 KiB |
|
Before Width: | Height: | Size: 83 KiB |
|
Before Width: | Height: | Size: 192 KiB |
|
Before Width: | Height: | Size: 192 KiB |
|
Before Width: | Height: | Size: 192 KiB |
|
Before Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 76 KiB |
|
Before Width: | Height: | Size: 69 KiB |
|
Before Width: | Height: | Size: 80 KiB |
|
Before Width: | Height: | Size: 192 KiB |
|
Before Width: | Height: | Size: 487 KiB |
|
Before Width: | Height: | Size: 490 KiB |
|
Before Width: | Height: | Size: 637 KiB |
|
Before Width: | Height: | Size: 525 KiB |
|
Before Width: | Height: | Size: 420 KiB |
|
Before Width: | Height: | Size: 487 KiB |
|
Before Width: | Height: | Size: 134 KiB |
|
Before Width: | Height: | Size: 448 KiB |
|
Before Width: | Height: | Size: 132 KiB |
|
Before Width: | Height: | Size: 105 KiB |
|
Before Width: | Height: | Size: 132 KiB |
|
Before Width: | Height: | Size: 132 KiB |
|
Before Width: | Height: | Size: 209 KiB |
|
Before Width: | Height: | Size: 118 KiB |
|
Before Width: | Height: | Size: 143 KiB |
|
Before Width: | Height: | Size: 142 KiB |
|
Before Width: | Height: | Size: 80 KiB |
|
Before Width: | Height: | Size: 60 KiB |
|
Before Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 69 KiB |
|
Before Width: | Height: | Size: 150 KiB |
|
Before Width: | Height: | Size: 81 KiB |
|
Before Width: | Height: | Size: 151 KiB |
|
Before Width: | Height: | Size: 106 KiB |
|
Before Width: | Height: | Size: 93 KiB |
|
Before Width: | Height: | Size: 92 KiB |
|
Before Width: | Height: | Size: 94 KiB |
|
Before Width: | Height: | Size: 108 KiB |
|
Before Width: | Height: | Size: 78 KiB |
|
Before Width: | Height: | Size: 124 KiB |
|
Before Width: | Height: | Size: 97 KiB |
|
Before Width: | Height: | Size: 99 KiB |
|
Before Width: | Height: | Size: 69 KiB |
|
Before Width: | Height: | Size: 63 KiB |
|
Before Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 81 KiB |
|
Before Width: | Height: | Size: 72 KiB |
|
Before Width: | Height: | Size: 78 KiB |
|
Before Width: | Height: | Size: 76 KiB |
|
Before Width: | Height: | Size: 67 KiB |
|
Before Width: | Height: | Size: 78 KiB |
|
Before Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 114 KiB |
|
Before Width: | Height: | Size: 91 KiB |
|
Before Width: | Height: | Size: 90 KiB |
|
Before Width: | Height: | Size: 107 KiB |
|
Before Width: | Height: | Size: 118 KiB |
|
Before Width: | Height: | Size: 131 KiB |
|
Before Width: | Height: | Size: 112 KiB |
|
Before Width: | Height: | Size: 550 KiB |
|
Before Width: | Height: | Size: 471 KiB |
|
Before Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 77 KiB |