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

114
utils/postEngagement.js Normal file
View File

@@ -0,0 +1,114 @@
const PostBookmarkModel = require('../models/PostBookmarkModel')
const PostSendModel = require('../models/PostSendModel')
const PostShareModel = require('../models/PostShareModel')
const UserFollowModel = require('../models/UserFollowModel')
const ExploreInteractionModel = require('../models/ExploreInteractionModel')
const UserModel = require('../models/UserModel')
const StoryModel = require('../models/StoryModel')
async function attachPostEngagementFields(posts, viewerId) {
if (!posts?.length) return posts
const postIds = posts.map((p) => p._id)
const authorIds = [...new Set(posts.map((p) => String(p.user_id)))]
const [bookmarkAgg, sendAgg, shareAgg, viewAgg, authorDocs, userBookmarks, userFollows, activeStories] = await Promise.all([
PostBookmarkModel.aggregate([
{ $match: { postId: { $in: postIds } } },
{ $group: { _id: '$postId', count: { $sum: 1 } } },
]),
PostSendModel.aggregate([
{ $match: { postId: { $in: postIds } } },
{ $group: { _id: '$postId', count: { $sum: 1 } } },
]),
PostShareModel.aggregate([
{ $match: { postId: { $in: postIds } } },
{ $group: { _id: '$postId', count: { $sum: 1 } } },
]),
ExploreInteractionModel.aggregate([
{
$match: {
targetType: 'post',
targetId: { $in: postIds },
action: 'view',
},
},
{ $group: { _id: '$targetId', count: { $sum: 1 } } },
]),
UserModel.find({ _id: { $in: authorIds } })
.select('_id allow_save_posts')
.lean(),
viewerId
? PostBookmarkModel.find({ userId: viewerId, postId: { $in: postIds } })
.select('postId')
.lean()
: [],
viewerId
? UserFollowModel.find({
followerId: viewerId,
followingId: { $in: authorIds },
})
.select('followingId')
.lean()
: [],
StoryModel.find({ user_id: { $in: authorIds }, expires_at: { $gt: new Date() } })
.select('user_id viewers')
.lean(),
])
const savesMap = Object.fromEntries(
bookmarkAgg.map((b) => [String(b._id), b.count])
)
const sendsMap = Object.fromEntries(
sendAgg.map((s) => [String(s._id), s.count])
)
const sharesMap = Object.fromEntries(
shareAgg.map((s) => [String(s._id), s.count])
)
const viewsMap = Object.fromEntries(
viewAgg.map((v) => [String(v._id), v.count])
)
const allowSaveMap = Object.fromEntries(
authorDocs.map((u) => [String(u._id), u.allow_save_posts !== false])
)
const savedSet = new Set(userBookmarks.map((b) => String(b.postId)))
const followSet = new Set(userFollows.map((f) => String(f.followingId)))
const storiesByAuthor = {}
activeStories.forEach((s) => {
const key = String(s.user_id)
if (!storiesByAuthor[key]) storiesByAuthor[key] = []
storiesByAuthor[key].push(s)
})
const hasStorySet = new Set(Object.keys(storiesByAuthor))
const unviewedStorySet = new Set(
Object.keys(storiesByAuthor).filter((authorId) =>
storiesByAuthor[authorId].some(
(s) => !s.viewers?.some((v) => String(v.user_id) === String(viewerId))
)
)
)
return posts.map((post) => ({
...post,
savesCount: savesMap[String(post._id)] || 0,
sendsCount: sendsMap[String(post._id)] || 0,
sharesCount: sharesMap[String(post._id)] || 0,
viewsCount: viewsMap[String(post._id)] || 0,
author_allow_save: allowSaveMap[String(post.user_id)] !== false,
is_saved: savedSet.has(String(post._id)),
is_following: followSet.has(String(post.user_id)),
has_story: hasStorySet.has(String(post.user_id)),
has_unviewed_story: viewerId ? unviewedStorySet.has(String(post.user_id)) : hasStorySet.has(String(post.user_id)),
}))
}
async function attachSinglePostEngagement(post, viewerId) {
const [enriched] = await attachPostEngagementFields([post], viewerId)
return enriched
}
module.exports = {
attachPostEngagementFields,
attachSinglePostEngagement,
}