Files
modstagram-back/models/AdModel.js
2026-09-24 21:03:27 +03:30

73 lines
4.4 KiB
JavaScript

const mongoose = require('mongoose')
const timestamp = require('mongoose-timestamp')
const mongoosePaginate = require('mongoose-paginate-v2')
// تبلیغِ کاربری — نوعش تعیین می‌کنه محتواش کجا تزریق می‌شه: first_post (اول فید)،
// first_story (اول نوار استوری)، notification (پوش مستقیم به کاربرهای هدف)، project/
// product/shop/billboard (اول لیستِ مربوطه، از utils/adDelivery.js:findActiveAd با همون
// ad_type resolve می‌شه). هدف‌گذاری (لوکیشن/تخصص/جنسیت) روی همون فیلدهایی که
// User/Post/exploreAlgorithm.js از قبل استفاده می‌کنن سوار شده (province.id عددیه، نه
// ObjectId — utils/adPricing.js همین رو resolve می‌کنه)
const AD_TYPES = ['first_post', 'first_story', 'notification', 'project', 'product', 'shop', 'billboard']
const adSchema = new mongoose.Schema({
user_id: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
ad_type: { type: String, enum: AD_TYPES, required: true },
// محتوا — بسته به ad_type فقط یکی از این پر می‌شه
content_post_id: { type: mongoose.Schema.Types.ObjectId, ref: 'Post', default: null },
content_project_id: { type: mongoose.Schema.Types.ObjectId, ref: 'Project', default: null },
content_shop_product_id: { type: mongoose.Schema.Types.ObjectId, ref: 'ShopProductListing', default: null },
content_shop_id: { type: mongoose.Schema.Types.ObjectId, ref: 'Shop', default: null },
content_billboard_id: { type: mongoose.Schema.Types.ObjectId, ref: 'Advertising', default: null },
// استوری‌های واقعی معمولاً ۲۴ساعته منقضی می‌شن (StoryModel: expires_at) و از فیدِ
// استوریِ معمولی حذف می‌شن، ولی یه کمپینِ تبلیغاتی می‌تونه چند روز فعال بمونه — پس
// مدیا/اورلی‌ها رو موقعِ ساختِ تبلیغ اینجا کپی/اسنپ‌شات می‌کنیم تا مستقل از عمرِ
// طبیعیِ خودِ استوری باشه (content_story_id فقط برای رفرنسِ منبع نگه داشته می‌شه)
content_story_id: { type: mongoose.Schema.Types.ObjectId, ref: 'Story', default: null },
content_media_path: { type: String, default: null },
content_media_type: { type: String, default: null },
content_overlays: { type: mongoose.Schema.Types.Mixed, default: null },
notification_title: { type: String, trim: true, default: null },
notification_body: { type: String, trim: true, default: null },
// هدف‌گذاری
target_country_id: { type: Number, default: null },
target_province_id: { type: Number, default: null },
target_city_id: { type: Number, default: null },
target_expertise: { type: String, trim: true, default: null },
target_sub_expertise: { type: [String], default: [] },
target_gender: { type: String, enum: ['female', 'male', 'any'], default: 'any' },
// مالی
price: { type: Number, required: true },
walletAmountUsed: { type: Number, default: 0 },
payment_authority: { type: String, default: null },
status: {
type: String,
enum: ['pending_payment', 'active', 'expired', 'failed'],
default: 'pending_payment'
},
started_at: { type: Date, default: null },
// عین بقیه‌ی کمپین‌های اپ، یه مدت‌زمانِ ثابت (AD_CAMPAIGN_DURATION_DAYS توی
// adsController.js) بعد از فعال‌شدن — بعدش دیگه توی تزریقِ فید/استوری/نوتیف لحاظ نمی‌شه
expires_at: { type: Date, default: null },
views_count: { type: Number, default: 0 },
clicks_count: { type: Number, default: 0 }
})
// تزریق (سرچِ یه تبلیغِ فعالِ منطبق روی فید/استوری) و لیستِ «تبلیغ‌های من» دو مصرفِ
// اصلیِ ایندکسن
adSchema.index({ status: 1, ad_type: 1, expires_at: 1 })
adSchema.index({ user_id: 1, createdAt: -1 })
adSchema.plugin(timestamp)
adSchema.plugin(mongoosePaginate)
const AdModel = mongoose.model('Ad', adSchema)
// روی خودِ مدل به‌عنوان استاتیک — تا adsController.js/adsPanelController.js بدونِ
// require جدا به لیستِ معتبرِ ad_type دسترسی داشته باشن (module.exports همون مدله، نه یه آبجکت)
AdModel.AD_TYPES = AD_TYPES
module.exports = AdModel