This commit is contained in:
payacom
2026-08-31 20:45:41 +03:30
parent fa9f23c61d
commit 3f416a7a60
367 changed files with 621895 additions and 6443 deletions

View File

@@ -4,6 +4,7 @@ const academyController = require("../../../controllers/application/academy/acad
const multer = require("multer");
const path = require("path");
const fs = require("fs");
const adminAuth = require("../../../middlewares/adminAuth");
// const academyCategoryController = require("../../../controllers/application/academy/academyCategoryController");
// ==========================================
@@ -225,6 +226,12 @@ router.get(
academyController.getUserLikedCourses
);
// دریافت لیست کامنت‌های خود کاربر (فعالیت‌های او)
router.get(
"/academy/user/comments",
academyController.getUserComments
);
// ==========================================
// 💬 مسیرهای کامنت و نظرات
// ==========================================
@@ -271,6 +278,7 @@ router.get(
"/course/getAllAcademyPayments",
academyController.getAllAcademyPayments
);
router.get("/analytics", academyController.getAcademyAnalytics);
// بررسی خرید دوره توسط کاربر
router.get(
@@ -283,36 +291,36 @@ router.get(
// ==========================================
// آمار پرداخت‌ها
router.get("/payments/stats", academyController.getPaymentStats);
router.get("/payments/stats", [adminAuth], academyController.getPaymentStats);
// آمار دوره‌ها
router.get("/courses/stats", academyController.getCourseStats);
router.get("/courses/stats", [adminAuth], academyController.getCourseStats);
// آمار دوره‌های خریداری شده
router.get("/purchased/stats", academyController.getPurchasedStats);
router.get("/purchased/stats", [adminAuth], academyController.getPurchasedStats);
// آمار آکادمی‌ها
router.get("/academies/stats", academyController.getAcademyStats);
router.get("/academies/stats", [adminAuth], academyController.getAcademyStats);
// ==========================================
// ⚙️ مسیرهای تنظیمات (Settings)
// ==========================================
// دریافت همه تنظیمات
router.get("/settings/all", academyController.getAllSettings);
router.get("/settings", academyController.getAllSettings);
router.get("/settings/all", [adminAuth], academyController.getAllSettings);
router.get("/settings", [adminAuth], academyController.getAllSettings);
// به‌روزرسانی همه تنظیمات
router.put("/settings/all", academyController.updateAllSettings);
router.put("/settings", academyController.updateAllSettings);
router.put("/settings/all", [adminAuth], academyController.updateAllSettings);
router.put("/settings", [adminAuth], academyController.updateAllSettings);
// دریافت و ویرایش قیمت دوره‌ها
router.get("/settings/course-prices", academyController.getCoursePrices);
router.put("/settings/course-price", academyController.updateCoursePrice);
router.get("/settings/course-prices", [adminAuth], academyController.getCoursePrices);
router.put("/settings/course-price", [adminAuth], academyController.updateCoursePrice);
// دریافت و ویرایش مالیات
router.get("/settings/tax", academyController.getTax);
router.put("/settings/tax", academyController.updateTax);
router.get("/settings/tax", [adminAuth], academyController.getTax);
router.put("/settings/tax", [adminAuth], academyController.updateTax);
// ==========================================
// 🏷️ مسیرهای دسته‌بندی آکادمی (Categories)
@@ -360,27 +368,27 @@ router.post('/categories/:id/increment-count', academyController.incrementCourse
// ==========================================
// ------ مدیریت پرداخت‌ها ------
router.get("/payments", academyController.getAllPayments);
router.put("/payments/status", academyController.updatePaymentStatus);
router.get("/payments", [adminAuth], academyController.getAllPayments);
router.put("/payments/status", [adminAuth], academyController.updatePaymentStatus);
// ------ مدیریت دوره‌ها ------
router.get("/courses", academyController.getAllCourses);
router.get("/courses/:id", academyController.getCourseById);
router.put("/courses/:id", academyController.updateCourse);
router.post("/courses", academyController.createCourse);
router.put("/academy/courses/status", academyController.updateCourseStatus);
router.delete("/courses/:courseId", academyController.admindeleteCourse);
router.get("/courses", [adminAuth], academyController.getAllCourses);
router.put("/courses/status", [adminAuth], academyController.updateCourseStatus);
router.get("/courses/:id", [adminAuth], academyController.getCourseById);
router.put("/courses/:id", [adminAuth], academyController.updateCourse);
router.post("/courses", [adminAuth], academyController.createCourse);
router.delete("/courses/:courseId", [adminAuth], academyController.admindeleteCourse);
// ------ مدیریت دوره‌های خریداری شده ------
router.get("/purchased", academyController.getAllPurchasedCourses);
router.get("/purchased", [adminAuth], academyController.getAllPurchasedCourses);
// ------ مدیریت آکادمی‌ها ------
router.get("/academies", academyController.getAllAcademies);
router.get("/academies/:id", academyController.getAcademyById);
router.put("/academies/:id", academyController.updateAcademy);
router.post("/academies", academyController.createAcademy);
router.put("/academies/status", academyController.updateAcademyStatus);
router.delete("/academies/:id", academyController.deleteAcademy);
router.get("/academies", [adminAuth], academyController.getAllAcademies);
router.get("/academies/:id", [adminAuth], academyController.getAcademyById);
router.put("/academies/:id", [adminAuth], academyController.updateAcademy);
router.post("/academies", [adminAuth], academyController.createAcademy);
router.put("/academies/status", [adminAuth], academyController.updateAcademyStatus);
router.delete("/academies/:id", [adminAuth], academyController.deleteAcademy);
// ==========================================
// 📤 خروجی روت‌ها

View File

@@ -0,0 +1,48 @@
const express = require('express')
const auth = require('../../../middlewares/auth')
const blockCheck = require('../../../middlewares/blockCheck')
const {
deactivateAccount,
reactivateAccount,
deleteAccount,
getAccountStatus,
updatePrivacySettings,
resetAlgorithm,
updateUserRegion,
getProfileVisitors,
pinPost,
toggleArchivePost,
getArchivedPosts,
getAccountAnalytics
} = require('../../../controllers/application/profile/accountController')
const {
putMyPublicKey,
getPublicKeyByUserId,
startDeviceLink,
getDeviceLinkSession,
approveDeviceLink,
pollDeviceLink
} = require('../../../controllers/application/account/e2eeController')
const router = express.Router()
router.get('/status', auth, blockCheck, getAccountStatus)
router.get('/visitors', auth, blockCheck, getProfileVisitors)
router.patch('/privacy', auth, blockCheck, updatePrivacySettings)
router.post('/reset-algorithm', auth, blockCheck, resetAlgorithm)
router.patch('/region', auth, blockCheck, updateUserRegion)
router.post('/pin-post', auth, blockCheck, pinPost)
router.post('/archive-post', auth, blockCheck, toggleArchivePost)
router.get('/archived-posts', auth, blockCheck, getArchivedPosts)
router.get('/analytics', auth, blockCheck, getAccountAnalytics)
router.post('/deactivate', auth, blockCheck, deactivateAccount)
router.post('/reactivate', auth, reactivateAccount)
router.post('/delete', auth, blockCheck, deleteAccount)
router.put('/e2ee/public-key', auth, blockCheck, putMyPublicKey)
router.get('/e2ee/public-key/:userId', auth, blockCheck, getPublicKeyByUserId)
router.post('/e2ee/device-link', auth, blockCheck, startDeviceLink)
router.get('/e2ee/device-link/:linkId', auth, blockCheck, getDeviceLinkSession)
router.post('/e2ee/device-link/:linkId/approve', auth, blockCheck, approveDeviceLink)
router.get('/e2ee/device-link/:linkId/poll', auth, blockCheck, pollDeviceLink)
module.exports = router

View File

@@ -1,6 +1,6 @@
const express = require('express')
const blockCheck = require('../../../middlewares/blockCheck')
const { createAdvertisingValidationRules, createAdvertising, getAdvertisingTypes, getAdvertisingCategory, getSingleAdvertising, getAdvertisingFeatures, getAdvertisings, toggleLike, addComment, getComments, rateAdvertising, getUserAdvertisings, editAdvertising, getUserSingleAdvertising, getUserAdvertisingProfile, updateUserAdvertisingProfile, getAdvertisingsWeb, getSingleAdvertisingWeb, getUserAdvertisingProfileWeb } = require('../../../controllers/application/advertising/advertisingController')
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')
const { initiateAdvertisingPayment, handleAdvertisingPaymentCallback, handleAdvertisingRepublishPaymentCallback, republishAdvertisingPayment, handleSuccessfulAdvertisingPayment, handleFailedAdvertisingPayment, handleFailedAdvertisingRepublishPayment, handleSuccessfulAdvertisingRepublishPayment } = require('../../../controllers/application/payment/paymentController')
const { initiateAdvertisingPaymentWeb, handleAdvertisingPaymentCallbackWeb, republishAdvertisingPaymentWeb, handleAdvertisingRepublishPaymentCallbackWeb } = require('../../../controllers/application/payment/paymentControllerWeb')
@@ -11,12 +11,16 @@ router.get('/profile', [auth], getUserAdvertisingProfile)
router.get('/profile-web', getUserAdvertisingProfileWeb)
router.patch('/profile', [auth], [blockCheck], 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], createAdvertisingValidationRules(), createAdvertising)
router.get('/types', [auth], getAdvertisingTypes)
router.get('/categories', getAdvertisingCategory)
router.get('/features', [auth], getAdvertisingFeatures)
router.get('/get/:advertisingId', [auth], getSingleAdvertising)
router.get('/get/web/:advertisingId', getSingleAdvertisingWeb)
router.post('/view/:advertisingId', recordAdvertisingView)
router.get('/get-detail/:advertisingId', [auth], getUserSingleAdvertising)
router.post('/initiate-payment', [auth], [blockCheck], initiateAdvertisingPayment)
router.post('/initiate-payment-web', [auth], [blockCheck], initiateAdvertisingPaymentWeb)
@@ -42,4 +46,3 @@ router.post('/republish-payment-success', handleSuccessfulAdvertisingRepublishPa
router.post('/republish-payment-failed', handleFailedAdvertisingRepublishPayment)
module.exports = router
module.exports = router

View File

@@ -0,0 +1,80 @@
const express = require('express')
const router = express.Router()
const authRateLimit = require('../../../middlewares/authRateLimit')
const blockCheck = require('../../../middlewares/blockCheck')
const {
googleAuth,
linkGoogleAccount,
getGoogleLinkStatus,
} = require('../../../controllers/application/auth/googleController')
const {
instagramAuth,
linkInstagramAccount,
getInstagramLinkStatus,
disconnectInstagram,
} = require('../../../controllers/application/auth/instagramController')
const {
getInstagramMedia,
importInstagramPosts,
disableAutoImport,
} = require('../../../controllers/application/auth/instagramImportController')
const {
instagramDeauthorize,
instagramDataDeletion,
} = require('../../../controllers/application/auth/instagramComplianceController')
const {
getTotpStatus,
setupTotp,
enableTotp,
disableTotp,
verifyLoginTotp,
} = require('../../../controllers/application/auth/totpController')
function resolveAsyncHandler () {
try {
const mod = require('../../../utils/asyncHandler')
if (typeof mod === 'function') return mod
if (typeof mod?.asyncHandler === 'function') return mod.asyncHandler
} catch (err) {
console.error('[auth] asyncHandler module missing/invalid:', err?.message || err)
}
// fallback محلی تا سرور به خاطر نبودن util بالا نیاید
return (handler) => (req, res, next) => {
Promise.resolve(handler(req, res, next)).catch((error) => {
console.error('[asyncHandler:fallback]', error)
if (res.headersSent) return next(error)
return res.status(error?.status || 500).json({
message: error?.userMessage || 'خطای سرور',
en_message: error?.message || 'internal_error',
})
})
}
}
const asyncHandler = resolveAsyncHandler()
router.post('/google', authRateLimit, asyncHandler(googleAuth))
router.post('/google/link', blockCheck, asyncHandler(linkGoogleAccount))
router.get('/google/status', blockCheck, asyncHandler(getGoogleLinkStatus))
router.post('/instagram/callback', authRateLimit, asyncHandler(instagramAuth))
router.post('/instagram/link', blockCheck, asyncHandler(linkInstagramAccount))
router.get('/instagram/status', blockCheck, asyncHandler(getInstagramLinkStatus))
router.post('/instagram/disconnect', blockCheck, asyncHandler(disconnectInstagram))
router.get('/instagram/media', blockCheck, asyncHandler(getInstagramMedia))
router.post('/instagram/import', blockCheck, asyncHandler(importInstagramPosts))
router.post('/instagram/import/auto-update', blockCheck, asyncHandler(disableAutoImport))
// Called server-to-server by Meta (signed_request, no user session) — registered as the
// "Deauthorize callback URL" / "Data deletion request URL" in Instagram Business Login settings.
router.post('/instagram/deauthorize', authRateLimit, asyncHandler(instagramDeauthorize))
router.post('/instagram/data-deletion', authRateLimit, asyncHandler(instagramDataDeletion))
router.get('/totp/status', blockCheck, asyncHandler(getTotpStatus))
router.post('/totp/setup', blockCheck, asyncHandler(setupTotp))
router.post('/totp/enable', blockCheck, asyncHandler(enableTotp))
router.post('/totp/disable', blockCheck, asyncHandler(disableTotp))
router.post('/totp/verify-login', authRateLimit, asyncHandler(verifyLoginTotp))
module.exports = router

View File

@@ -0,0 +1,50 @@
const express = require('express')
const {
createDraftBookingConfig,
getMyBookingConfigs,
getBookingConfigById,
updateBookingConfigServices,
updateBookingConfigSchedule,
updateBookingConfigStatus,
submitBookingConfig
} = require('../../../controllers/application/bookings/bookingConfigController')
const {
getPublicBookingConfig,
getAvailability,
createBooking,
getMyBookings,
updateBookingStatus,
getBookingAnalytics
} = require('../../../controllers/application/bookings/bookingController')
const {
initiateBookingPayment,
handleBookingPaymentCallback
} = require('../../../controllers/application/bookings/bookingPaymentController')
const blockCheck = require('../../../middlewares/blockCheck')
const router = express.Router()
// --- Booking-config wizard (provider setup) ---
router.post('/draft', [blockCheck], createDraftBookingConfig)
router.get('/mine', [blockCheck], getMyBookingConfigs)
// --- Reservations (buyer booking + provider's received bookings) ---
// Registered before the generic '/:id' route below so these single-segment
// paths aren't swallowed as a booking-config id.
router.get('/public/:userId', getPublicBookingConfig)
router.get('/availability', getAvailability)
router.post('/book', [blockCheck], createBooking)
router.get('/reservations', [blockCheck], getMyBookings)
router.post('/reservations/:id/status', [blockCheck], updateBookingStatus)
router.get('/analytics', [blockCheck], getBookingAnalytics)
router.post('/payment/initiate', [blockCheck], initiateBookingPayment)
router.get('/payment-callback/web', handleBookingPaymentCallback)
// --- Booking-config wizard (continued) ---
router.get('/:id', [blockCheck], getBookingConfigById)
router.patch('/:id/services', [blockCheck], updateBookingConfigServices)
router.patch('/:id/schedule', [blockCheck], updateBookingConfigSchedule)
router.patch('/:id/status', [blockCheck], updateBookingConfigStatus)
router.post('/:id/submit', [blockCheck], submitBookingConfig)
module.exports = router

View File

@@ -0,0 +1,28 @@
const express = require('express')
const {
listRooms,
createRoom,
joinRoom,
getRoomMessages,
sendRoomMessage,
getRoomDetail,
addRoomMembers,
reactToRoomMessage,
getRoomE2eeKeys,
putRoomE2eeKeys
} = require('../../../controllers/application/chatRooms/chatRoomController')
const router = express.Router()
router.get('/', listRooms)
router.post('/', createRoom)
router.get('/:roomId', getRoomDetail)
router.post('/:roomId/join', joinRoom)
router.post('/:roomId/members', addRoomMembers)
router.get('/:roomId/e2ee-keys', getRoomE2eeKeys)
router.put('/:roomId/e2ee-keys', putRoomE2eeKeys)
router.get('/:roomId/messages', getRoomMessages)
router.post('/:roomId/messages', sendRoomMessage)
router.post('/:roomId/messages/reaction', reactToRoomMessage)
module.exports = router

View File

@@ -0,0 +1,7 @@
const express = require('express')
const router = express.Router()
const countriesController = require('../../../controllers/application/countriesController')
router.get('/', countriesController.getCountries)
module.exports = router

View File

@@ -0,0 +1,23 @@
const express = require('express')
const blockCheck = require('../../../middlewares/blockCheck')
const {
initiateGiftPayment,
handleGiftPaymentCallback,
getMyGifts,
replyToGift,
initiateChatGift,
handleChatGiftPaymentCallback,
openGift
} = require('../../../controllers/application/gifts/giftController')
const router = express.Router()
router.post('/initiate', [blockCheck], initiateGiftPayment)
router.get('/payment-callback', handleGiftPaymentCallback)
router.get('/', [blockCheck], getMyGifts)
router.post('/reply', [blockCheck], replyToGift)
router.post('/chat/initiate', [blockCheck], initiateChatGift)
router.get('/chat/payment-callback', handleChatGiftPaymentCallback)
router.post('/:id/open', [blockCheck], openGift)
module.exports = router

View File

@@ -1,14 +1,25 @@
const express = require('express')
const router = express.Router()
const { loginValidationRules, loginUser } = require('../../../controllers/application/login/loginController')
const loginController = require('../../../controllers/application/login/loginController')
const { loginValidationRules, loginUser } = loginController
if (typeof loginValidationRules !== 'function' || typeof loginUser !== 'function') {
throw new Error(
'loginController.js is invalid on server: loginValidationRules/loginUser must be exported'
)
}
const { verifyUser } = require('../../../controllers/application/login/verifyController')
const { changePasswordUser, changePasswordValidationRules, editChangePasswordUser } = require('../../../controllers/application/login/changePasswordController')
const { loginWithUserName } = require('../../../controllers/application/login/loginWithUserName')
const { forgotPassword } = require('../../../controllers/application/login/forgotPasswordController')
const authRateLimit = require('../../../middlewares/authRateLimit')
router.post('/', loginValidationRules(), loginUser)
router.post('/verify', verifyUser)
router.post('/change_password', changePasswordValidationRules(), changePasswordUser)
router.patch('/change_password', changePasswordValidationRules(), editChangePasswordUser)
router.post('/', authRateLimit, loginValidationRules(), loginUser)
router.post('/verify', authRateLimit, verifyUser)
router.post('/forgot_password', authRateLimit, forgotPassword)
router.post('/change_password', authRateLimit, changePasswordValidationRules(), changePasswordUser)
router.patch('/change_password', authRateLimit, changePasswordValidationRules(), editChangePasswordUser)
router.post('/login_username', loginWithUserName)
module.exports = router

View File

@@ -1,6 +1,9 @@
const express = require('express')
const { getNotifications, unreadNotifications } = require('../../../controllers/application/notification/notificationController')
const { getNotifications, unreadNotifications, registerPushToken, markBroadcastSeen, markBroadcastClicked } = require('../../../controllers/application/notification/notificationController')
const router = express.Router()
router.get('/', getNotifications)
router.get('/unread', unreadNotifications)
router.post('/register-token', registerPushToken)
router.post('/broadcast/:id/seen', markBroadcastSeen)
router.post('/broadcast/:id/clicked', markBroadcastClicked)
module.exports = router

View File

@@ -0,0 +1,26 @@
const express = require('express')
const {
createOrderDraft,
getOrders,
updateOrderStatus,
updateTrackingCode,
getOrderById,
confirmReceipt,
rateOrder,
reportOrder,
createReturnRequest
} = require('../../../controllers/application/orders/orderController')
const router = express.Router()
router.post('/draft', createOrderDraft)
router.get('/', getOrders)
router.get('/:id', getOrderById)
router.patch('/:id/status', updateOrderStatus)
router.patch('/:id/tracking-code', updateTrackingCode)
router.patch('/:id/confirm-receipt', confirmReceipt)
router.post('/:id/rate', rateOrder)
router.post('/:id/report', reportOrder)
router.post('/:id/return-request', createReturnRequest)
module.exports = router

View File

@@ -0,0 +1,14 @@
const express = require('express')
const blockCheck = require('../../../../middlewares/blockCheck')
const {
initiateOrderPayment,
handleOrderPaymentCallback
} = require('../../../../controllers/application/payment/shopOrderPaymentController')
const router = express.Router()
router.post('/initiate', [blockCheck], initiateOrderPayment)
// ZarinPal calls this directly (browser redirect) — no Authorization header available
router.get('/callback', handleOrderPaymentCallback)
module.exports = router

View File

@@ -1,12 +1,25 @@
const express = require('express');
const { createPostValidationRules, createPost, getUserPosts, getUserPostsWeb, getPostByIdWeb } = require('../../../controllers/application/posts/postController');
const { createPostValidationRules, createPost, updatePost, getUserPosts, getUserPostsWeb, getPostByIdWeb } = require('../../../controllers/application/posts/postController');
const { toggleLike } = require('../../../controllers/application/posts/likeController');
const {
toggleBookmark,
getBookmarks,
sendPostToUsers,
toggleFollow,
getMyLikedPosts,
getMyCommentedPosts,
sharePost,
} = require('../../../controllers/application/posts/engagementController');
const { getPostAnalytics, getMyPostsAnalyticsList } = require('../../../controllers/application/posts/postAnalyticsController');
const { reportPost } = require('../../../controllers/application/posts/reportController');
const blockCheck = require('../../../middlewares/blockCheck');
const auth = require('../../../middlewares/auth');
const isHalfRegister = require('../../../middlewares/isHalfRegister');
const requirePostExpertise = require('../../../middlewares/requirePostExpertise');
const path = require('path');
const fs = require('fs');
const crypto = require('crypto');
const multer = require('multer');
const { saveBase64PostFiles } = require('../../../utils/postBase64Files');
console.log('DEBUG: Starting to load routes/posts.js');
@@ -36,7 +49,10 @@ const storage = multer.diskStorage({
cb(null, dir);
},
filename: (req, file, cb) => {
const filename = `${Date.now()}-${file.originalname}`;
// اسمِ فایل هیچ‌وقت مستقیم از ورودیِ کاربر (file.originalname) گرفته نمی‌شه — فقط
// پسوندش؛ چون multer هم برای نوشتنِ فایل نهایتاً path.join(destination, filename)
// می‌زنه، یه originalname مثل ../../../etc/passwd می‌تونست از پوشه‌ی مقصد بیرون بزنه
const filename = `${Date.now()}-${crypto.randomUUID()}${path.extname(file.originalname || '')}`;
console.log('DEBUG: Generated filename for', file.originalname, ':', filename);
cb(null, filename);
},
@@ -106,10 +122,10 @@ router.post(
},
blockCheck,
(req, res, next) => {
console.log('DEBUG: reached isHalfRegister');
console.log('DEBUG: reached requirePostExpertise');
next();
},
isHalfRegister,
requirePostExpertise,
(req, res, next) => {
console.log('DEBUG: reached multer');
console.log('DEBUG: Content-Length:', req.headers['content-length']);
@@ -135,67 +151,128 @@ router.post(
// روت جدید برای Base64
router.post(
'/create-base64',
(req, res, next) => {
console.log('DEBUG: reached auth for base64');
console.log('DEBUG: Raw request headers:', JSON.stringify(req.headers, null, 2));
next();
},
auth,
(req, res, next) => {
console.log('DEBUG: reached blockCheck for base64');
next();
},
blockCheck,
(req, res, next) => {
console.log('DEBUG: reached isHalfRegister for base64');
next();
},
isHalfRegister,
(req, res, next) => {
console.log('DEBUG: Request body (base64):', JSON.stringify(req.body, null, 2));
next();
},
requirePostExpertise,
createPostValidationRules(),
async (req, res) => {
try {
const { files, caption } = req.body;
console.log('DEBUG: Received files (base64):', files.length);
console.log('DEBUG: Received caption:', caption);
const {
files,
caption,
tagged_user_ids,
linked_course_id,
linked_project_id,
linked_billboard_id,
linked_shop_id,
linked_shop_product_id,
linked_booking_id,
country_id,
province_id,
city_id,
} = req.body;
// تبدیل Base64 به فایل
const savedFiles = await Promise.all(
files.map(async (file, index) => {
const buffer = Buffer.from(file.data.split(',')[1], 'base64');
const dir = file.type.startsWith('video/') ? videoDir : imageDir;
const filename = `${Date.now()}-${index}-${file.name}`;
const filePath = path.join(dir, filename);
console.log('DEBUG: Saving file:', filePath);
await fs.promises.writeFile(filePath, buffer);
return {
path: filePath,
filename,
mimetype: file.type,
};
})
);
console.log('DEBUG: create-base64', {
filesCount: Array.isArray(files) ? files.length : 0,
captionLen: caption ? String(caption).length : 0,
fileTypes: Array.isArray(files)
? files.map((f) => f?.type).filter(Boolean)
: [],
});
const savedFiles = await saveBase64PostFiles(files, imageDir, videoDir);
// فراخوانی createPost با فرمت مشابه
req.files = savedFiles;
req.body = { caption };
console.log('DEBUG: Prepared files for createPost:', savedFiles);
console.log('DEBUG: Prepared body for createPost:', req.body);
req.body = {
caption,
tagged_user_ids,
linked_course_id,
linked_project_id,
linked_billboard_id,
linked_shop_id,
linked_shop_product_id,
linked_booking_id,
country_id,
province_id,
city_id,
};
await createPost(req, res);
} catch (err) {
console.error('DEBUG: Base64 processing error:', err.message);
if (!res.headersSent) {
res.status(400).json({
error: true,
message: `خطای پردازش فایل‌ها: ${err.message}`,
});
}
}
}
);
async function handleUpdateBase64(req, res) {
try {
const {
postId,
files,
caption,
tagged_user_ids,
keep_files,
media_order,
} = req.body;
console.log('DEBUG: update-base64', {
postId,
filesCount: Array.isArray(files) ? files.length : 0,
keepCount: Array.isArray(keep_files)
? keep_files.length
: keep_files
? 1
: 0,
});
const savedFiles = await saveBase64PostFiles(files, imageDir, videoDir, {
allowEmpty: true,
});
req.files = savedFiles;
req.body = {
postId,
caption,
tagged_user_ids,
keep_files,
media_order,
};
await updatePost(req, res);
} catch (err) {
console.error('DEBUG: update-base64 error:', err.message);
if (!res.headersSent) {
res.status(400).json({
error: true,
message: `خطای پردازش فایل‌ها: ${err.message}`,
});
}
}
);
}
router.post('/update-base64', auth, blockCheck, handleUpdateBase64);
// مسیر جایگزین برای سرورهایی که روت قبلی را کش کرده‌اند
router.put('/update-base64', auth, blockCheck, handleUpdateBase64);
router.post('/:postId/update-base64', auth, blockCheck, (req, res) => {
req.body = { ...(req.body || {}), postId: req.params.postId || req.body?.postId };
return handleUpdateBase64(req, res);
});
router.post('/like', [auth, blockCheck], toggleLike);
router.post('/bookmark', [auth, blockCheck], toggleBookmark);
router.get('/bookmarks', [auth, blockCheck], getBookmarks);
router.get('/my-likes', [auth, blockCheck], getMyLikedPosts);
router.get('/my-comments', [auth, blockCheck], getMyCommentedPosts);
router.post('/send', [auth, blockCheck], sendPostToUsers);
router.post('/share', [auth, blockCheck], sharePost);
router.post('/follow', [auth, blockCheck], toggleFollow);
router.post('/report', [auth, blockCheck], reportPost);
router.get('/analytics/mine', [auth, blockCheck], getMyPostsAnalyticsList)
router.get('/:postId/analytics', [auth, blockCheck], getPostAnalytics);
router.get('/web/:postId', getPostByIdWeb);
router.get('/user-posts', [auth], getUserPosts);
router.get('/user-posts/web', getUserPostsWeb);

View File

@@ -7,8 +7,15 @@ const auth = require('../../../middlewares/auth')
const { requestProjectValidationRules, requestProject, acceptProject, editRequestProject } = require('../../../controllers/application/projects/requestProjectController')
const { editProject, doneProject, cancleProject, editProjectValidationRules, setRateProject, doneProjectWeb } = require('../../../controllers/application/projects/updateProjectController')
const blockCheck = require('../../../middlewares/blockCheck')
const isRegister = require('../../../middlewares/isRegister')
const { initiatePaymentWeb, handlePaymentCallbackWeb, paymentRequestAcceptWeb } = require('../../../controllers/application/payment/paymentControllerWeb')
const isBasicRegister = require('../../../middlewares/isBasicRegister')
const {
initiatePaymentWeb,
handlePaymentCallbackWeb,
paymentRequestAcceptWeb,
paymentRequestAcceptWebCallback,
initiateProjectCompletionPaymentWeb,
handleProjectCompletionPaymentCallbackWeb
} = require('../../../controllers/application/payment/paymentControllerWeb')
const router = express.Router()
router.get('/', getProjects)
router.get('/user-projects', [auth], getUserProjects)
@@ -20,22 +27,25 @@ router.get('/payment', handlePaymentCallback)
router.get('/payment-web', handlePaymentCallbackWeb)
router.post('/create', [blockCheck], [auth], createProjectValidationRules(), createProject)
router.post('/edit', [blockCheck], [auth], editProjectValidationRules(), editProject)
router.post('/rate', [blockCheck], [auth], [isRegister], setRateProject)
router.post('/initiate-payment', [blockCheck], [isRegister], [auth], initiatePayment)
router.post('/initiate-payment-web', [blockCheck], [isRegister], [auth], initiatePaymentWeb)
router.post('/request', [blockCheck], [isRegister], [auth], requestProjectValidationRules(), requestProject)
router.post('/edit-request', [isRegister], [blockCheck], [auth], requestProjectValidationRules(), editRequestProject)
router.post('/payment-request-step-one', [isRegister], [blockCheck], [auth], paymentRequestStepOne)
router.post('/payment-request-step-one/web', [isRegister], [blockCheck], [auth], paymentRequestAcceptWeb)
router.post('/payment-request-step-two', [isRegister], [blockCheck], [auth], paymentRequestStepTwo)
router.post('/payment-request-all', [isRegister], [blockCheck], [auth], paymentRequestStepAll)
router.post('/rate', [blockCheck], [auth], [isBasicRegister], setRateProject)
router.post('/initiate-payment', [blockCheck], [isBasicRegister], [auth], initiatePayment)
router.post('/initiate-payment-web', [blockCheck], [isBasicRegister], [auth], initiatePaymentWeb)
router.post('/request', [blockCheck], [isBasicRegister], [auth], requestProjectValidationRules(), requestProject)
router.post('/edit-request', [isBasicRegister], [blockCheck], [auth], requestProjectValidationRules(), editRequestProject)
router.post('/payment-request-step-one', [isBasicRegister], [blockCheck], [auth], paymentRequestStepOne)
router.post('/payment-request-step-one/web', [isBasicRegister], [blockCheck], [auth], paymentRequestAcceptWeb)
router.post('/payment-request-step-two', [isBasicRegister], [blockCheck], [auth], paymentRequestStepTwo)
router.post('/payment-request-all', [isBasicRegister], [blockCheck], [auth], paymentRequestStepAll)
router.get('/payment-request-step-one-callback', paymentRequestStepOneCallback)
router.get('/payment-request-step-one-callback/web', paymentRequestAcceptWebCallback)
router.get('/payment-request-step-two-callback', paymentRequestStepTwoCallback)
router.get('/payment-request-step-all-callback', paymentRequestStepAllCallback)
router.post('/accept', [isRegister], [blockCheck], [auth], acceptProject)
router.post('/done', [isRegister], [auth], doneProject)
router.post('/done/web', [isRegister], [auth], doneProjectWeb)
router.post('/cancle', [isRegister], [blockCheck], [auth], cancleProject)
router.post('/accept', [isBasicRegister], [blockCheck], [auth], acceptProject)
router.post('/done', [isBasicRegister], [auth], doneProject)
router.post('/done/web', [isBasicRegister], [auth], doneProjectWeb)
router.post('/cancle', [isBasicRegister], [blockCheck], [auth], cancleProject)
router.post('/initiate-completion-payment/web', [isBasicRegister], [blockCheck], [auth], initiateProjectCompletionPaymentWeb)
router.get('/payment-completion-callback/web', handleProjectCompletionPaymentCallbackWeb)
// Route for handling successful payment
router.post('/payment-success', handleSuccessfulPayment)

View File

@@ -5,11 +5,17 @@ const { verifyUser } = require('../../../controllers/application/register/verify
const { setUserName, updateUserName } = require('../../../controllers/application/register/usernameController')
const { setUserFullName, setUserFullNameValidationRules } = require('../../../controllers/application/register/userFullNameController')
const { setUserType } = require('../../../controllers/application/register/userTypeController')
const { setRegisterPassword, setRegisterPasswordValidationRules } = require('../../../controllers/application/register/passwordController')
const { getRegisterStatus } = require('../../../controllers/application/register/statusController')
const auth = require('../../../middlewares/auth')
const authRateLimit = require('../../../middlewares/authRateLimit')
router.post('/', registerValidationRules(), registerUser)
router.post('/verify', verifyUser)
router.post('/', authRateLimit, registerValidationRules(), registerUser)
router.post('/verify', authRateLimit, verifyUser)
router.get('/status', auth, getRegisterStatus)
router.post('/username', setUserName)
router.patch('/username', updateUserName)
router.post('/password', setRegisterPasswordValidationRules(), setRegisterPassword)
router.post('/fullname', setUserFullNameValidationRules(), setUserFullName)
router.post('/user_type', setUserType)

View File

@@ -0,0 +1,6 @@
const express = require('express')
const { getShopCategories } = require('../../../controllers/application/shop-categories/shopCategoryController')
const router = express.Router()
router.get('/', getShopCategories)
module.exports = router

View File

@@ -0,0 +1,17 @@
const express = require('express')
const blockCheck = require('../../../middlewares/blockCheck')
const {
getMyShopChats,
getShopChatMessages,
sendShopChatMessage,
sendShopChatFileMessage
} = require('../../../controllers/application/shop-chat/shopChatController')
const router = express.Router()
router.get('/mine', [blockCheck], getMyShopChats)
router.get('/:shopId/messages', [blockCheck], getShopChatMessages)
router.post('/:shopId/messages', [blockCheck], sendShopChatMessage)
router.post('/:shopId/messages/file', [blockCheck], sendShopChatFileMessage)
module.exports = router

View File

@@ -0,0 +1,34 @@
const express = require('express')
const blockCheck = require('../../../middlewares/blockCheck')
const {
searchCatalog,
createShopProduct,
updateShopProduct,
getShopProducts,
getShopProductById,
getCatalogListings,
getDiscoverFeed,
getShopProductComments,
createShopProductComment,
sendProductToUsers
} = require('../../../controllers/application/shop-products/shopProductController')
const router = express.Router()
// Public browsing
router.get('/catalog/search', searchCatalog)
router.get('/catalog/:catalogId/listings', getCatalogListings)
router.get('/discover', getDiscoverFeed)
router.get('/', getShopProducts)
router.get('/:id', getShopProductById)
router.get('/:id/comments', getShopProductComments)
// Seller-only
router.post('/', [blockCheck], createShopProduct)
router.patch('/:id', [blockCheck], updateShopProduct)
// Authenticated buyer actions
router.post('/:id/comments', [blockCheck], createShopProductComment)
router.post('/:id/send', [blockCheck], sendProductToUsers)
module.exports = router

View File

@@ -0,0 +1,52 @@
const express = require('express')
const {
createDraftShop,
getMyShops,
getShopAnalytics,
getShopById,
getShopPublic,
updateShopBasic,
updateShopLogo,
updateShopShipping,
updateShopLocation,
updateShopContact,
toggleShopFollow,
submitShop
} = require('../../../controllers/application/shops/shopController')
const {
getCart,
addToCart,
updateCartItem,
removeCartItem
} = require('../../../controllers/application/shops/cartController')
const {
getFavorites,
toggleFavorite
} = require('../../../controllers/application/shops/favoriteController')
const blockCheck = require('../../../middlewares/blockCheck')
const router = express.Router()
router.post('/draft', [blockCheck], createDraftShop)
router.get('/mine', [blockCheck], getMyShops)
router.get('/analytics', [blockCheck], getShopAnalytics)
// --- Buyer: cart + favorites (registered before the generic '/:id' below) ---
router.get('/cart', [blockCheck], getCart)
router.post('/cart', [blockCheck], addToCart)
router.patch('/cart/:itemId', [blockCheck], updateCartItem)
router.delete('/cart/:itemId', [blockCheck], removeCartItem)
router.get('/favorites', [blockCheck], getFavorites)
router.post('/favorites/toggle', [blockCheck], toggleFavorite)
router.get('/public/:id', getShopPublic)
router.get('/:id', [blockCheck], getShopById)
router.patch('/:id/basic', [blockCheck], updateShopBasic)
router.patch('/:id/logo', [blockCheck], updateShopLogo)
router.patch('/:id/shipping', [blockCheck], updateShopShipping)
router.patch('/:id/location', [blockCheck], updateShopLocation)
router.patch('/:id/contact', [blockCheck], updateShopContact)
router.post('/:id/follow', [blockCheck], toggleShopFollow)
router.post('/:id/submit', [blockCheck], submitShop)
module.exports = router

View File

@@ -1,20 +1,70 @@
const express = require('express')
const path = require('path')
const fs = require('fs')
const multer = require('multer')
const auth = require('../../../middlewares/auth')
const blockCheck = require('../../../middlewares/blockCheck')
const isHalfRegister = require('../../../middlewares/isHalfRegister')
const {
createStoryBase64,
createStoryMultipart,
createStoryFromPost,
getStoriesFeed,
markStoryViewed,
updateStory,
deleteStory
deleteStory,
likeStory,
commentOnStory,
getStoryViewers,
sendStoryToUsers,
} = require('../../../controllers/application/stories/storyController')
const router = express.Router()
// همون پوشه‌ای که createStoryBase64 توی storyController.js براش استفاده می‌کنه
const storyStorageDir = path.join(__dirname, '../../../storage/stories')
if (!fs.existsSync(storyStorageDir)) {
fs.mkdirSync(storyStorageDir, { recursive: true })
}
const storyUpload = multer({
storage: multer.diskStorage({
destination: (req, file, cb) => cb(null, storyStorageDir),
filename: (req, file, cb) => {
const ext = file.mimetype.startsWith('video/') ? '.mp4' : path.extname(file.originalname) || '.jpg'
cb(null, `${Date.now()}-${req.user?._id || 'story'}${ext}`)
},
}),
limits: { fileSize: 200 * 1024 * 1024 },
fileFilter: (req, file, cb) => {
if (file.mimetype.startsWith('image/') || file.mimetype.startsWith('video/')) return cb(null, true)
cb(new Error('فقط تصویر یا ویدئو مجاز است'), false)
},
}).single('story_file')
router.get('/feed', getStoriesFeed)
router.post('/create-base64', auth, blockCheck, isHalfRegister, createStoryBase64)
// عین /posts/create چندبخشی — برای فایل‌های حجیم (مخصوصاً ویدیو) که تبدیل به base64 توی
// حافظه‌ی JS موبایل باعث خطای OOM می‌شد؛ فایل مستقیم از دیسک استریم می‌شه
router.post(
'/create',
auth,
blockCheck,
isHalfRegister,
(req, res, next) => {
storyUpload(req, res, (err) => {
if (err) return res.status(400).json({ error: true, message: err.message })
next()
})
},
createStoryMultipart
)
router.post('/share-post', auth, blockCheck, isHalfRegister, createStoryFromPost)
router.post('/send', auth, blockCheck, sendStoryToUsers)
router.post('/view', auth, blockCheck, markStoryViewed)
router.post('/like', auth, blockCheck, likeStory)
router.post('/comment', auth, blockCheck, commentOnStory)
router.get('/:storyId/viewers', auth, blockCheck, getStoryViewers)
router.patch('/:storyId', auth, blockCheck, updateStory)
router.delete('/:storyId', auth, blockCheck, deleteStory)

View File

@@ -0,0 +1,12 @@
const express = require('express')
const {
getUserSuggestions,
createSuggestion
} = require('../../../controllers/application/suggestions/suggestionsController')
const router = express.Router()
router.get('/', getUserSuggestions)
router.post('/', createSuggestion)
module.exports = router

View File

@@ -1,23 +1,43 @@
const express = require('express')
const { getUsers, getSingleUser, blockUser, unblockUser, getComments,createLicense, getAllLicenses,updateLicenseConfirmation, getLicenseByUserId, inviteEmployer, getUserContactInfo, getPostsWeb, getSingleUserWeb, createUserComment, recordExploreInteraction } = require('../../../controllers/application/users/getUserController')
const { getUsers, getSingleUser, blockUser, unblockUser, getComments,createLicense, getAllLicenses,updateLicenseConfirmation, getLicenseByUserId, inviteEmployer, getUserContactInfo, getPostsWeb, getSingleUserWeb, createUserComment, toggleCommentLike, recordExploreInteraction, getPublicProfilesForSeo, getTopHashtags } = require('../../../controllers/application/users/getUserController')
const { getFollowStats, getFollowers, getFollowing, getBlockedUsers } = require('../../../controllers/application/users/followController')
const { getNearbyUsers } = require('../../../controllers/application/users/nearbyUsersController')
const {
searchPartners,
getMyPartnerAlert,
createPartnerAlert,
deletePartnerAlert
} = require('../../../controllers/application/users/partnerSearchController')
const blockCheck = require('../../../middlewares/blockCheck')
const isRegister = require('../../../middlewares/isRegister')
const auth = require('../../../middlewares/auth')
const router = express.Router()
router.get('/follow/stats', auth, getFollowStats)
router.get('/follow/followers', auth, getFollowers)
router.get('/follow/following', auth, getFollowing)
router.get('/blocked/list', [auth, blockCheck], getBlockedUsers)
router.get('/nearby', [auth, blockCheck], getNearbyUsers)
router.get('/partner-search', [auth, blockCheck], searchPartners)
router.get('/partner-search/alerts', [auth, blockCheck], getMyPartnerAlert)
router.post('/partner-search/alerts', [auth, blockCheck], createPartnerAlert)
router.delete('/partner-search/alerts/:id', [auth, blockCheck], deletePartnerAlert)
router.get('/', [auth], getUsers)
router.get('/web', getPostsWeb)
router.get('/explore/top-hashtags', getTopHashtags)
router.get('/seo/public-profiles', getPublicProfilesForSeo)
router.get('/get', [auth], getSingleUser)
router.get('/get/web', getSingleUserWeb)
router.post('/block', [auth], [isRegister], [blockCheck], blockUser)
router.post('/unblock', [auth], [isRegister], [blockCheck], unblockUser)
router.get('/comments', [auth], getComments)
router.post('/comments', [auth], [isRegister], [blockCheck], createUserComment)
router.post('/comments/like', [auth], [isRegister], [blockCheck], toggleCommentLike)
router.post('/explore/interaction', [auth], recordExploreInteraction)
router.get('/invite-employer', [auth], [isRegister], [blockCheck], inviteEmployer)
router.get('/contact-info', [auth], getUserContactInfo)
router.get('/License', getAllLicenses)
router.get('/License/:userId', getLicenseByUserId)
router.post('/License', createLicense)
router.put('/License/:userId', updateLicenseConfirmation)
router.get('/License', [auth], getAllLicenses)
router.get('/License/:userId', [auth, blockCheck], getLicenseByUserId)
router.post('/License', [auth, blockCheck], createLicense)
router.put('/License/:userId', [auth], updateLicenseConfirmation)
module.exports = router

View File

@@ -13,6 +13,7 @@ const { completeRegistration } = require('../../../controllers/application/verif
const blockCheck = require('../../../middlewares/blockCheck')
const auth = require('../../../middlewares/auth')
const { setServices, updateServices } = require('../../../controllers/application/verify/servicesController')
const { setPersonalDetails, updatePersonalDetails } = require('../../../controllers/application/verify/personalDetailsController')
const router = express.Router()
router.post('/profile_image', setProfileImage)
@@ -26,6 +27,8 @@ router.post('/services', setServices)
router.patch('/services', [blockCheck], [auth], updateServices)
router.post('/colors', setColors)
router.patch('/colors', [blockCheck], [auth], updateColors)
router.post('/personal_details', [blockCheck], [auth], setPersonalDetails)
router.patch('/personal_details', [blockCheck], [auth], updatePersonalDetails)
router.post('/cooperation_type', setCooperationType)
router.patch('/cooperation_type', [blockCheck], [auth], updateCooperationType)
router.post('/conversation', setConversation)

View File

@@ -0,0 +1,20 @@
const express = require('express')
const blockCheck = require('../../../middlewares/blockCheck')
const {
getWalletSummary,
getWalletTransactions,
requestWithdrawal,
initiateWalletCharge,
handleWalletChargeCallback
} = require('../../../controllers/application/wallet/walletController')
const router = express.Router()
router.get('/summary', [blockCheck], getWalletSummary)
router.get('/transactions', [blockCheck], getWalletTransactions)
router.post('/withdraw', [blockCheck], requestWithdrawal)
router.post('/charge/initiate', [blockCheck], initiateWalletCharge)
// ZarinPal calls this directly (browser redirect) — no Authorization header available
router.get('/charge/callback', handleWalletChargeCallback)
module.exports = router

View File

@@ -1,7 +1,8 @@
const express = require('express')
const { getProjects, getSingleProject, getProjectRequests } = require('../../../controllers/application/workroom/workroomController')
const { getProjects, getSingleProject, getProjectRequests, getProjectAnalytics } = require('../../../controllers/application/workroom/workroomController')
const router = express.Router()
router.get('/', getProjects)
router.get('/analytics', getProjectAnalytics)
router.get('/get', getSingleProject)
router.get('/get-requests/:projectId', getProjectRequests)