This commit is contained in:
payacom
2026-10-09 15:44:47 +03:30
parent 367416d419
commit e5dcd0f1b2
14 changed files with 282 additions and 197 deletions

View File

@@ -74,18 +74,19 @@ router.get("/", academyController.findAcademy);
// یافتن آکادمی با شناسه
router.post("/findAcademyById", academyController.findAcademyById);
// تکمیل پروفایل آکادمی
router.post("/academy/profile", academyController.academyProfile);
// تکمیل پروفایل آکادمی — همون باگِ req.files که توی verify/* پیدا شد (middlewareِ
// global قدیمی که req.files رو پر می‌کرد حذف شده بود، این روت بدونِ جایگزین مونده بود)
router.post("/academy/profile", upload.single("profile_image"), academyController.academyProfile);
// ==========================================
// 📚 مسیرهای مدیریت دوره‌ها (Courses)
// ==========================================
// ایجاد دوره جدید
router.post("/academy/creat/course", [auth, blockCheck, requireSubUserPermission('academy_packages')], academyController.creatCourse);
// ایجاد دوره جدید — همون باگِ req.files بالا
router.post("/academy/creat/course", [auth, blockCheck, requireSubUserPermission('academy_packages')], upload.single("course_image"), academyController.creatCourse);
// ویرایش دوره
router.patch("/academy/update/course", [auth, blockCheck, requireSubUserPermission('academy_packages')], academyController.updateCourse);
// ویرایش دوره — همون باگِ req.files بالا
router.patch("/academy/update/course", [auth, blockCheck, requireSubUserPermission('academy_packages')], upload.single("course_image"), academyController.updateCourse);
// حذف دوره (تغییر وضعیت به reject)
router.delete("/academy/delete/course", academyController.deleteCourse);

View File

@@ -1,4 +1,7 @@
const express = require('express')
const multer = require('multer')
const fs = require('fs')
const path = require('path')
const blockCheck = require('../../../middlewares/blockCheck')
const { createAdvertisingValidationRules, createAdvertising, getAdvertisingTypes, getAdvertisingCategory, getSingleAdvertising, getAdvertisingFeatures, getAdvertisings, toggleLike, addComment, getComments, rateAdvertising, getUserAdvertisings, getAdvertisingAnalytics, editAdvertising, getUserSingleAdvertising, getUserAdvertisingProfile, updateUserAdvertisingProfile, getAdvertisingsWeb, getSingleAdvertisingWeb, getUserAdvertisingProfileWeb, recordAdvertisingView, getUserLikedAdvertisings, getUserAdvertisingComments } = require('../../../controllers/application/advertising/advertisingController')
const auth = require('../../../middlewares/auth')
@@ -6,16 +9,38 @@ const requireSubUserPermission = require('../../../middlewares/requireSubUserPer
const { initiateAdvertisingPayment, handleAdvertisingPaymentCallback, handleAdvertisingRepublishPaymentCallback, republishAdvertisingPayment } = require('../../../controllers/application/payment/paymentController')
const { initiateAdvertisingPaymentWeb, handleAdvertisingPaymentCallbackWeb, republishAdvertisingPaymentWeb, handleAdvertisingRepublishPaymentCallbackWeb } = require('../../../controllers/application/payment/paymentControllerWeb')
const router = express.Router()
// قبلاً express-form-data به‌صورتِ global این فیلدها رو تویِ req.files پر می‌کرد؛
// وقتی اون middleware حذف شد (تداخل با multer توی posts/chat)، این روت‌ها بدونِ هیچ
// parserِ جایگزینی موندن — یعنی آپلودِ عکسِ بیلبورد/خدمات/پروفایلِ ویترین همیشه
// خاموش بودن (createAdvertising حتی بدون خطا، فقط عکس‌ها رو نادیده می‌گرفت)
const advertisingTmpDir = '/tmp/modstagram-uploads'
if (!fs.existsSync(advertisingTmpDir)) {
fs.mkdirSync(advertisingTmpDir, { recursive: true })
}
const advertisingTmpUpload = multer({
storage: multer.diskStorage({
destination: (req, file, cb) => cb(null, advertisingTmpDir),
filename: (req, file, cb) => {
cb(null, `${Date.now()}-${Math.round(Math.random() * 1e9)}${path.extname(file.originalname || '')}`)
}
}),
limits: { fileSize: 50 * 1024 * 1024 }
})
// اسمِ فیلدِ عکسِ هر خدمت پویاست (serviceImages[id])، پس .any() به‌جای .fields()
// با لیستِ ثابت — کنترلر با file.fieldname تشخیص می‌ده مالِ کدوم خدمت/بخشه
const advertisingImagesUpload = advertisingTmpUpload.any()
const advertisingProfileImageUpload = advertisingTmpUpload.single('profile_image')
router.get('/', [auth], getAdvertisings)
router.get('/web', getAdvertisingsWeb)
router.get('/profile', [auth], getUserAdvertisingProfile)
router.get('/profile-web', getUserAdvertisingProfileWeb)
router.patch('/profile', [auth], [blockCheck], updateUserAdvertisingProfile)
router.patch('/profile', [auth], [blockCheck], advertisingProfileImageUpload, updateUserAdvertisingProfile)
router.get('/user-advertising', [auth], getUserAdvertisings)
router.get('/analytics', [auth], getAdvertisingAnalytics)
router.get('/user-liked', [auth], getUserLikedAdvertisings)
router.get('/user-comments', [auth], getUserAdvertisingComments)
router.post('/create', [auth], [blockCheck], requireSubUserPermission('billboards'), createAdvertisingValidationRules(), createAdvertising)
router.post('/create', [auth], [blockCheck], requireSubUserPermission('billboards'), advertisingImagesUpload, createAdvertisingValidationRules(), createAdvertising)
router.get('/types', [auth], getAdvertisingTypes)
router.get('/categories', getAdvertisingCategory)
router.get('/features', [auth], getAdvertisingFeatures)
@@ -35,6 +60,6 @@ router.post('/like', [blockCheck], [auth], toggleLike)
router.post('/comment', [blockCheck], [auth], addComment)
router.get('/comments', getComments)
router.post('/rate', [blockCheck], [auth], rateAdvertising)
router.post('/edit/:id', [blockCheck], [auth], requireSubUserPermission('billboards'), editAdvertising)
router.post('/edit/:id', [blockCheck], [auth], requireSubUserPermission('billboards'), advertisingImagesUpload, editAdvertising)
module.exports = router

View File

@@ -1,6 +1,26 @@
const express = require('express')
const multer = require('multer')
const fs = require('fs')
const path = require('path')
const blockCheck = require('../../../middlewares/blockCheck')
const requireSubUserPermission = require('../../../middlewares/requireSubUserPermission')
// قبلاً express-form-data به‌صورتِ global این فیلد رو تویِ req.files پر می‌کرد؛ وقتی
// اون middleware حذف شد (تداخل با multer توی posts/chat)، این روت‌ها بدونِ هیچ parserِ
// جایگزینی موندن — یعنی آپلودِ عکسِ محصول همیشه خاموش بود
const shopProductsTmpDir = '/tmp/modstagram-uploads'
if (!fs.existsSync(shopProductsTmpDir)) {
fs.mkdirSync(shopProductsTmpDir, { recursive: true })
}
const shopProductImagesUpload = multer({
storage: multer.diskStorage({
destination: (req, file, cb) => cb(null, shopProductsTmpDir),
filename: (req, file, cb) => {
cb(null, `${Date.now()}-${Math.round(Math.random() * 1e9)}${path.extname(file.originalname || '')}`)
}
}),
limits: { fileSize: 50 * 1024 * 1024 }
}).array('images', 10)
const {
searchCatalog,
createShopProduct,
@@ -25,8 +45,8 @@ router.get('/:id', getShopProductById)
router.get('/:id/comments', getShopProductComments)
// Seller-only
router.post('/', [blockCheck], requireSubUserPermission('shop_products'), createShopProduct)
router.patch('/:id', [blockCheck], requireSubUserPermission('shop_products'), updateShopProduct)
router.post('/', [blockCheck], requireSubUserPermission('shop_products'), shopProductImagesUpload, createShopProduct)
router.patch('/:id', [blockCheck], requireSubUserPermission('shop_products'), shopProductImagesUpload, updateShopProduct)
// Authenticated buyer actions
router.post('/:id/comments', [blockCheck], createShopProductComment)

View File

@@ -1,8 +1,28 @@
const express = require('express')
const multer = require('multer')
const fs = require('fs')
const path = require('path')
const router = express.Router()
const auth = require('../../../middlewares/auth')
const blockCheck = require('../../../middlewares/blockCheck')
// قبلاً express-form-data به‌صورتِ global این فیلد رو تویِ req.files پر می‌کرد؛ وقتی
// اون middleware حذف شد (تداخل با multer توی posts/chat)، این روت‌ها بدونِ هیچ parserِ
// جایگزینی موندن — یعنی آپلودِ آواتارِ کاربرِ زیرمجموعه همیشه خاموش بود
const subUserTmpDir = '/tmp/modstagram-uploads'
if (!fs.existsSync(subUserTmpDir)) {
fs.mkdirSync(subUserTmpDir, { recursive: true })
}
const subUserAvatarUpload = multer({
storage: multer.diskStorage({
destination: (req, file, cb) => cb(null, subUserTmpDir),
filename: (req, file, cb) => {
cb(null, `${Date.now()}-${Math.round(Math.random() * 1e9)}${path.extname(file.originalname || '')}`)
}
}),
limits: { fileSize: 20 * 1024 * 1024 }
}).single('profile_image')
const {
createSubUser,
listSubUsers,
@@ -23,10 +43,10 @@ function ownerOnly (req, res, next) {
next()
}
router.post('/', [auth, blockCheck, ownerOnly], createSubUser)
router.post('/', [auth, blockCheck, ownerOnly], subUserAvatarUpload, createSubUser)
router.get('/', [auth, blockCheck, ownerOnly], listSubUsers)
router.get('/:id', [auth, blockCheck, ownerOnly], getSubUser)
router.patch('/:id', [auth, blockCheck, ownerOnly], updateSubUser)
router.patch('/:id', [auth, blockCheck, ownerOnly], subUserAvatarUpload, updateSubUser)
router.patch('/:id/active', [auth, blockCheck, ownerOnly], setSubUserActive)
module.exports = router

View File

@@ -1,9 +1,30 @@
const express = require('express')
const multer = require('multer')
const fs = require('fs')
const path = require('path')
const { getUserTickets, createTicket, addUserMessageToTicket, getTicketMessages } = require('../../../controllers/application/tickets/ticketsController')
const router = express.Router()
// قبلاً express-form-data به‌صورتِ global این فیلد رو تویِ req.files پر می‌کرد؛ وقتی
// اون middleware حذف شد (تداخل با multer توی posts/chat)، این روت بدونِ هیچ parserِ
// جایگزینی مونده بود — یعنی پیوستِ فایلِ پیامِ تیکت همیشه خاموش بود
const ticketTmpDir = '/tmp/modstagram-uploads'
if (!fs.existsSync(ticketTmpDir)) {
fs.mkdirSync(ticketTmpDir, { recursive: true })
}
const ticketFileUpload = multer({
storage: multer.diskStorage({
destination: (req, file, cb) => cb(null, ticketTmpDir),
filename: (req, file, cb) => {
cb(null, `${Date.now()}-${Math.round(Math.random() * 1e9)}${path.extname(file.originalname || '')}`)
}
}),
limits: { fileSize: 50 * 1024 * 1024 }
}).single('file')
router.get('/', getUserTickets)
router.get('/messages', getTicketMessages)
router.post('/create', createTicket)
router.post('/message', addUserMessageToTicket)
router.post('/message', ticketFileUpload, addUserMessageToTicket)
module.exports = router

View File

@@ -1,4 +1,8 @@
const express = require('express')
const multer = require('multer')
const crypto = require('crypto')
const fs = require('fs')
const path = require('path')
const { setProfileImage, updateProfileImage } = require('../../../controllers/application/verify/setProfileImageController')
const { setExpertise, updateExpertise } = require('../../../controllers/application/verify/expertiseController')
const { setGender, updateGender } = require('../../../controllers/application/verify/genderController')
@@ -16,16 +20,54 @@ const { setServices, updateServices } = require('../../../controllers/applicatio
const { setPersonalDetails, updatePersonalDetails } = require('../../../controllers/application/verify/personalDetailsController')
const router = express.Router()
router.post('/profile_image', setProfileImage)
router.patch('/profile_image', [blockCheck], [auth], updateProfileImage)
// قبلاً express-form-data به‌صورتِ global این فیلدها رو تویِ req.files پر می‌کرد؛
// وقتی اون middleware حذف شد (تداخل با multer توی posts/chat)، این روت بدونِ هیچ
// parserِ جایگزینی موند — یعنی req.files همیشه undefined بود و هر آپلودِ عکسِ
// پروفایل با «خطایی رخ داده است» شکست می‌خورد (همون الگویی که قبلاً برای
// /api/v1/chat/file پیدا و با multer.diskStorage رفع شد — نگاه کن به index.js)
const profileImageDir = path.join(__dirname, '../../../storage/profiles')
if (!fs.existsSync(profileImageDir)) {
fs.mkdirSync(profileImageDir, { recursive: true })
}
const profileImageUpload = multer({
storage: multer.diskStorage({
destination: (req, file, cb) => cb(null, profileImageDir),
filename: (req, file, cb) => {
cb(null, `${Date.now()}-${crypto.randomUUID()}${path.extname(file.originalname || '')}`)
}
}),
limits: { fileSize: 20 * 1024 * 1024 }
}).single('profile_image')
router.post('/profile_image', profileImageUpload, setProfileImage)
router.patch('/profile_image', [blockCheck], [auth], profileImageUpload, updateProfileImage)
router.post('/expertise', setExpertise)
router.patch('/expertise', [blockCheck], [auth], updateExpertise)
router.post('/gender', setGender)
router.patch('/gender', [blockCheck], [auth], updateGender)
router.post('/sizes', setSizes)
router.patch('/sizes', [blockCheck], [auth], updateSizes)
router.post('/services', setServices)
router.patch('/services', [blockCheck], [auth], updateServices)
// همون باگِ req.files (نگاه کن به کامنتِ profileImageUpload بالا) اینجا هم بود؛
// فرق با بقیه اینه که اسمِ فیلدِ عکسِ هر خدمت پویاست (serviceImages[serviceId]،
// یه آیدی متفاوت برای هر خدمت) پس به‌جای .single()/.fields() با اسمِ ثابت، از
// .any() استفاده می‌شه — همه‌ی فایل‌ها با هر اسمی قبول می‌شه، بعد توی کنترلر با
// file.fieldname تطبیق داده می‌شه
const servicesImagesDir = path.join(__dirname, '../../../storage/services')
if (!fs.existsSync(servicesImagesDir)) {
fs.mkdirSync(servicesImagesDir, { recursive: true })
}
const servicesUpload = multer({
storage: multer.diskStorage({
destination: (req, file, cb) => cb(null, servicesImagesDir),
filename: (req, file, cb) => {
cb(null, `${Date.now()}-${crypto.randomUUID()}${path.extname(file.originalname || '')}`)
}
}),
limits: { fileSize: 20 * 1024 * 1024 }
}).any()
router.post('/services', servicesUpload, setServices)
router.patch('/services', [blockCheck], [auth], servicesUpload, updateServices)
router.post('/colors', setColors)
router.patch('/colors', [blockCheck], [auth], updateColors)
router.post('/personal_details', [blockCheck], [auth], setPersonalDetails)
@@ -38,7 +80,22 @@ router.post('/auth', saveAuthValidationRules(), saveAuth)
router.patch('/shaba', [blockCheck], [auth], updateShaba)
router.post('/address', setAddress)
router.patch('/address', [blockCheck], [auth], updateAddress)
router.post('/national_card_image', setNationalCardImage)
// همون باگِ req.files (نگاه کن به کامنتِ profileImageUpload بالا) اینجا هم بود
const nationalCardDir = path.join(__dirname, '../../../storage/carts')
if (!fs.existsSync(nationalCardDir)) {
fs.mkdirSync(nationalCardDir, { recursive: true })
}
const nationalCardUpload = multer({
storage: multer.diskStorage({
destination: (req, file, cb) => cb(null, nationalCardDir),
filename: (req, file, cb) => {
cb(null, `${Date.now()}-${crypto.randomUUID()}${path.extname(file.originalname || '')}`)
}
}),
limits: { fileSize: 20 * 1024 * 1024 }
}).single('national_card_image')
router.post('/national_card_image', nationalCardUpload, setNationalCardImage)
router.post('/complete', completeRegistration)
module.exports = router