Initial commit
This commit is contained in:
77
utils/blockSuspension.js
Normal file
77
utils/blockSuspension.js
Normal file
@@ -0,0 +1,77 @@
|
||||
const moment = require('moment-jalaali')
|
||||
|
||||
const BLOCK_THRESHOLD = 5
|
||||
const BLOCK_DURATION_MS = 7 * 24 * 60 * 60 * 1000
|
||||
|
||||
const applyAutoBlockSuspension = (user) => {
|
||||
if (user.blocked_by.length >= BLOCK_THRESHOLD) {
|
||||
user.block_status = true
|
||||
user.blocked_until = new Date(Date.now() + BLOCK_DURATION_MS)
|
||||
}
|
||||
}
|
||||
|
||||
const clearAutoBlockSuspension = (user) => {
|
||||
if (user.blocked_by.length < BLOCK_THRESHOLD && user.blocked_until) {
|
||||
user.block_status = null
|
||||
user.blocked_until = null
|
||||
}
|
||||
}
|
||||
|
||||
const isUserCurrentlyBlocked = (user) => {
|
||||
if (!user.block_status) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (user.blocked_until) {
|
||||
if (new Date() >= new Date(user.blocked_until)) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
return user.block_status === true
|
||||
}
|
||||
|
||||
const expireBlockSuspensionIfNeeded = async (user) => {
|
||||
if (!user.blocked_until) {
|
||||
return user
|
||||
}
|
||||
|
||||
if (new Date() >= new Date(user.blocked_until)) {
|
||||
user.block_status = null
|
||||
user.blocked_until = null
|
||||
await user.save()
|
||||
}
|
||||
|
||||
return user
|
||||
}
|
||||
|
||||
const getBlockedAccountResponse = (user) => {
|
||||
if (!isUserCurrentlyBlocked(user)) {
|
||||
return null
|
||||
}
|
||||
|
||||
const untilText = user.blocked_until
|
||||
? moment(user.blocked_until).format('jYYYY/jMM/jDD')
|
||||
: null
|
||||
|
||||
return {
|
||||
status: 'error',
|
||||
code: 403,
|
||||
message: untilText
|
||||
? `حساب کاربری شما به دلیل بلاک شدن توسط ${BLOCK_THRESHOLD} کاربر تا تاریخ ${untilText} غیرفعال است.`
|
||||
: 'حساب کاربری شما مسدود شده است، برای اطلاعات بیشتر با پشتیبانی تماس بگیرید!',
|
||||
type: 'block',
|
||||
blocked_until: user.blocked_until || null
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
BLOCK_THRESHOLD,
|
||||
BLOCK_DURATION_MS,
|
||||
applyAutoBlockSuspension,
|
||||
clearAutoBlockSuspension,
|
||||
isUserCurrentlyBlocked,
|
||||
expireBlockSuspensionIfNeeded,
|
||||
getBlockedAccountResponse
|
||||
}
|
||||
30
utils/blockVisibility.js
Normal file
30
utils/blockVisibility.js
Normal file
@@ -0,0 +1,30 @@
|
||||
/** Viewer (blocked person) cannot see profile/posts of user who blocked them */
|
||||
function viewerIsBlockedBy(user, viewerId) {
|
||||
if (!user || !viewerId) return false
|
||||
return user.blocked_users.some((id) => String(id) === String(viewerId))
|
||||
}
|
||||
|
||||
function blockedProfilePayload(user) {
|
||||
return {
|
||||
_id: user._id,
|
||||
user_name: user.user_name,
|
||||
blocked_you: true,
|
||||
is_self: false,
|
||||
user_type: user.user_type,
|
||||
postsCount: 0,
|
||||
allProjectsCount: 0,
|
||||
successfulProjectsCount: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/** User IDs who have blocked the viewer */
|
||||
async function getBlockerUserIds(UserModel, viewerId) {
|
||||
if (!viewerId) return []
|
||||
return UserModel.find({ blocked_users: viewerId }).distinct('_id')
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
viewerIsBlockedBy,
|
||||
blockedProfilePayload,
|
||||
getBlockerUserIds,
|
||||
}
|
||||
57
utils/commentNotification.js
Normal file
57
utils/commentNotification.js
Normal file
@@ -0,0 +1,57 @@
|
||||
const NotificationModel = require('../models/NotificationModel')
|
||||
const { resolveCourseOwnerId } = require('./likeNotification')
|
||||
|
||||
const COMMENT_TITLE = 'یک کامنت برای شما ثبت شد'
|
||||
const COMMENT_DESCRIPTION = 'یک کامنت برای شما ثبت شد'
|
||||
const RATING_TITLE = 'یک امتیاز برای شما ثبت شد'
|
||||
const RATING_DESCRIPTION = 'یک امتیاز برای شما ثبت شد'
|
||||
|
||||
const createCommentNotification = async ({
|
||||
ownerId,
|
||||
commenterId,
|
||||
entityId,
|
||||
type = 'post_comment'
|
||||
}) => {
|
||||
try {
|
||||
if (!ownerId || !commenterId || !entityId) return
|
||||
if (String(ownerId) === String(commenterId)) return
|
||||
|
||||
await NotificationModel.create({
|
||||
user_id: ownerId,
|
||||
project_post_id: entityId,
|
||||
type,
|
||||
title: COMMENT_TITLE,
|
||||
description: COMMENT_DESCRIPTION
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Error creating comment notification:', error)
|
||||
}
|
||||
}
|
||||
|
||||
const createRatingNotification = async ({
|
||||
ownerId,
|
||||
raterId,
|
||||
entityId,
|
||||
type = 'billboard_rating'
|
||||
}) => {
|
||||
try {
|
||||
if (!ownerId || !raterId || !entityId) return
|
||||
if (String(ownerId) === String(raterId)) return
|
||||
|
||||
await NotificationModel.create({
|
||||
user_id: ownerId,
|
||||
project_post_id: entityId,
|
||||
type,
|
||||
title: RATING_TITLE,
|
||||
description: RATING_DESCRIPTION
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Error creating rating notification:', error)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
createCommentNotification,
|
||||
createRatingNotification,
|
||||
resolveCourseOwnerId
|
||||
}
|
||||
84
utils/commentRating.js
Normal file
84
utils/commentRating.js
Normal file
@@ -0,0 +1,84 @@
|
||||
const CommentModel = require('../models/CommentModel')
|
||||
const UserModel = require('../models/UserModel')
|
||||
|
||||
const RATED_FILTER = { $ne: null, $gt: 0 }
|
||||
|
||||
const findExistingUserRating = (creatorId, targetUserId) => {
|
||||
return CommentModel.findOne({
|
||||
creator: creatorId,
|
||||
user: targetUserId,
|
||||
rating: RATED_FILTER
|
||||
})
|
||||
}
|
||||
|
||||
const hasCreatorRatedUser = async (creatorId, targetUserId) => {
|
||||
const existing = await findExistingUserRating(creatorId, targetUserId)
|
||||
return !!existing
|
||||
}
|
||||
|
||||
const resolveRatingForComment = async ({ creatorId, targetUserId, rate }) => {
|
||||
const existingRating = await findExistingUserRating(creatorId, targetUserId)
|
||||
|
||||
if (existingRating) {
|
||||
return { ratingValue: null, isNewRating: false }
|
||||
}
|
||||
|
||||
if (!rate || rate < 1 || rate > 5) {
|
||||
return { ratingValue: null, isNewRating: false, requiresRating: true }
|
||||
}
|
||||
|
||||
return { ratingValue: rate, isNewRating: true }
|
||||
}
|
||||
|
||||
const getUserLevel = (user, totalRating) => {
|
||||
if (user.expertise === 'مدل') {
|
||||
if (totalRating <= 50) return 'تازه وارد'
|
||||
if (totalRating <= 100) return 'استاندارد'
|
||||
if (totalRating <= 300) return 'حرفهای'
|
||||
return 'استاد'
|
||||
}
|
||||
|
||||
if (['زیبایی', 'عکاس'].includes(user.expertise)) {
|
||||
if (totalRating <= 50) return 'تازه وارد'
|
||||
if (totalRating <= 100) return 'استاندارد'
|
||||
if (totalRating <= 300) return 'حرفهای'
|
||||
return 'استاد'
|
||||
}
|
||||
|
||||
return user.user_level
|
||||
}
|
||||
|
||||
const recalculateUserRating = async (targetUserId) => {
|
||||
const user = await UserModel.findById(targetUserId)
|
||||
if (!user) return
|
||||
|
||||
const ratedComments = await CommentModel.find({
|
||||
user: targetUserId,
|
||||
rating: RATED_FILTER
|
||||
}).sort({ createdAt: 1 })
|
||||
|
||||
const uniqueRatingsByCreator = new Map()
|
||||
for (const comment of ratedComments) {
|
||||
const creatorKey = comment.creator.toString()
|
||||
if (!uniqueRatingsByCreator.has(creatorKey)) {
|
||||
uniqueRatingsByCreator.set(creatorKey, comment.rating)
|
||||
}
|
||||
}
|
||||
|
||||
const ratings = Array.from(uniqueRatingsByCreator.values())
|
||||
const totalRating = ratings.reduce((acc, rating) => acc + rating, 0)
|
||||
const ratedCount = ratings.length
|
||||
|
||||
user.user_score = totalRating
|
||||
user.user_level = getUserLevel(user, totalRating)
|
||||
user.rate = ratedCount > 0 ? (totalRating / ratedCount).toFixed(1) : '0'
|
||||
await user.save()
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
RATED_FILTER,
|
||||
findExistingUserRating,
|
||||
hasCreatorRatedUser,
|
||||
resolveRatingForComment,
|
||||
recalculateUserRating
|
||||
}
|
||||
47
utils/likeNotification.js
Normal file
47
utils/likeNotification.js
Normal file
@@ -0,0 +1,47 @@
|
||||
const NotificationModel = require('../models/NotificationModel')
|
||||
const AcademyModel = require('../models/AcademyModel')
|
||||
|
||||
const LIKE_TITLE = 'پست شما لایک شد'
|
||||
const LIKE_DESCRIPTION = 'پست شما لایک شد'
|
||||
|
||||
const createLikeNotification = async ({
|
||||
ownerId,
|
||||
likerId,
|
||||
entityId,
|
||||
type = 'post_like'
|
||||
}) => {
|
||||
try {
|
||||
if (!ownerId || !likerId || !entityId) return
|
||||
if (String(ownerId) === String(likerId)) return
|
||||
|
||||
await NotificationModel.create({
|
||||
user_id: ownerId,
|
||||
project_post_id: entityId,
|
||||
type,
|
||||
title: LIKE_TITLE,
|
||||
description: LIKE_DESCRIPTION
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Error creating like notification:', error)
|
||||
}
|
||||
}
|
||||
|
||||
const resolveCourseOwnerId = async (course) => {
|
||||
if (course?.user_id) {
|
||||
return course.user_id
|
||||
}
|
||||
|
||||
if (course?.academyId) {
|
||||
const academy = await AcademyModel.findById(course.academyId)
|
||||
if (academy?.userId) {
|
||||
return academy.userId
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
createLikeNotification,
|
||||
resolveCourseOwnerId
|
||||
}
|
||||
Reference in New Issue
Block a user