Add Pinterest tag/filter for shop products

- New is_pinterest boolean on ShopProductListingModel, settable via the
  existing create/update product endpoints (multipart form field)
- /shop-products/discover accepts ?pinterest=true to show only
  Pinterest-tagged products across shops; skips the tagged-posts merge
  under this filter since those posts aren't Pinterest-tagged themselves

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
payacom
2026-09-16 10:22:37 +03:30
parent e1abb40cc6
commit 2e14db1ccd
2 changed files with 30 additions and 13 deletions

View File

@@ -103,7 +103,7 @@ function parseVariants (rawVariants) {
const createShopProduct = async (req, res, next) => {
try {
const { shopId, catalogProductId, name, description, primaryImageIndex, cloneFromListingId } = req.body
const { shopId, catalogProductId, name, description, primaryImageIndex, cloneFromListingId, is_pinterest: isPinterest } = req.body
if (!shopId) {
return productError(res, 422, 'فروشگاه مشخص نشده است')
}
@@ -175,6 +175,7 @@ const createShopProduct = async (req, res, next) => {
category: clonedFields.category || null,
sub_category: clonedFields.sub_category || null,
sub_sub_category: clonedFields.sub_sub_category || null,
is_pinterest: ['true', '1', true].includes(isPinterest),
// قبلاً اگه خودِ فروشگاه active بود، کالای تازه‌ساخته (همین قدمِ اول، فقط نام — بدون
// واریانت/تصویر/دسته‌بندی) بلافاصله status:'active' می‌گرفت و توی فیدِ دیسکاور عمومی
// نمایش داده می‌شد، با اینکه هنوز کاربر ویزارد رو تموم نکرده بود (کالاهای نیمه‌کاره/
@@ -198,7 +199,7 @@ const updateShopProduct = async (req, res, next) => {
if (error === 'FORBIDDEN') return productError(res, 403, 'شما مالک این فروشگاه نیستید')
if (error === 'NOT_FOUND' || !shop) return productError(res, 404, 'فروشگاه یافت نشد')
const { title, description, category, sub_category: subCategory, sub_sub_category: subSubCategory, status } = req.body
const { title, description, category, sub_category: subCategory, sub_sub_category: subSubCategory, status, is_pinterest: isPinterest } = req.body
if (title) listing.title = title
if (description !== undefined) listing.description = maskPhoneNumbers(description)
if (category) listing.category = category
@@ -207,6 +208,9 @@ const updateShopProduct = async (req, res, next) => {
if (status && ['active', 'inactive'].includes(status)) {
listing.status = status
}
if (isPinterest !== undefined) {
listing.is_pinterest = ['true', '1', true].includes(isPinterest)
}
if (req.body.variants) {
const variants = parseVariants(req.body.variants)
@@ -411,6 +415,7 @@ const getDiscoverFeed = async (req, res, next) => {
const page = Number(req.query.page) || 1
const q = String(req.query.q || '').trim()
const category = String(req.query.category || '').trim()
const pinterestOnly = ['true', '1'].includes(String(req.query.pinterest || '').trim())
const [preferredCategories, interestCategories] = await Promise.all([
getPreferredCategories(currentUserId),
@@ -423,6 +428,9 @@ const getDiscoverFeed = async (req, res, next) => {
if (category) {
matchStage.category = category
}
if (pinterestOnly) {
matchStage.is_pinterest = true
}
const [docs, totalDocs] = await Promise.all([
ShopProductListingModel.aggregate([
@@ -442,17 +450,21 @@ const getDiscoverFeed = async (req, res, next) => {
// پست‌های عادی که کالای یکی از فروشگاه‌های فعال رو تگ کرده‌اند هم اینجا نمایش داده بشن —
// این پست‌ها دیگه توی گرید اکسپلور نمایش داده نمی‌شن (getUserController.js: gridMode filter)
const taggedPosts = await PostModel.find({
linked_shop_id: { $in: activeShopIds },
linked_shop_product_id: { $ne: null },
status: 'accept',
is_archived: false,
report_hidden: false
})
.sort({ createdAt: -1 })
.limit(limit)
.populate('linked_shop_product_id')
.lean()
// زیرِ فیلترِ پینترستی این پست‌ها نمایش داده نمی‌شن چون خودِ پست تگِ پینترستی نداره،
// فقط کالای لینک‌شده‌اش ممکنه داشته باشه — نمایششون گیج‌کننده می‌شد
const taggedPosts = pinterestOnly
? []
: await PostModel.find({
linked_shop_id: { $in: activeShopIds },
linked_shop_product_id: { $ne: null },
status: 'accept',
is_archived: false,
report_hidden: false
})
.sort({ createdAt: -1 })
.limit(limit)
.populate('linked_shop_product_id')
.lean()
const validTaggedPosts = taggedPosts.filter(
(post) => post.linked_shop_product_id && post.linked_shop_product_id.status === 'active'