135 lines
3.9 KiB
JavaScript
135 lines
3.9 KiB
JavaScript
const crypto = require('crypto')
|
|
const mongoose = require('mongoose')
|
|
const UserModel = require('../models/UserModel')
|
|
const DeletedAccountTombstoneModel = require('../models/DeletedAccountTombstoneModel')
|
|
const PostModel = require('../models/PostModel')
|
|
const MessageModel = require('../models/MessageModel')
|
|
const PostBookmarkModel = require('../models/PostBookmarkModel')
|
|
const StoryModel = require('../models/StoryModel')
|
|
const NotificationModel = require('../models/NotificationModel')
|
|
const ExploreInteractionModel = require('../models/ExploreInteractionModel')
|
|
const CourseModel = require('../models/CourseModel')
|
|
const AdvertisingModel = require('../models/AdvertisingModel')
|
|
const AcademyModel = require('../models/AcademyModel')
|
|
|
|
const DEACTIVATION_LOCK_DAYS = 7
|
|
const DEACTIVATION_PURGE_MONTHS = 6
|
|
const DELETION_TOMBSTONE_DAYS = 30
|
|
|
|
const MS_DAY = 24 * 60 * 60 * 1000
|
|
|
|
function hashValue (value) {
|
|
if (!value) return null
|
|
return crypto
|
|
.createHash('sha256')
|
|
.update(String(value).trim().toLowerCase() + (process.env.APP_SECRET || 'modstagram'))
|
|
.digest('hex')
|
|
}
|
|
|
|
function isDeactivated (user) {
|
|
return user?.account_status === 'deactivated'
|
|
}
|
|
|
|
function isHiddenFromPublic (user) {
|
|
return isDeactivated(user)
|
|
}
|
|
|
|
function formatChatUserLabel (user) {
|
|
const name =
|
|
`${user?.first_name || ''} ${user?.last_name || ''}`.trim() ||
|
|
user?.user_name ||
|
|
'کاربر'
|
|
if (isDeactivated(user)) {
|
|
return `${name} (کاربر غیرفعال)`
|
|
}
|
|
return name
|
|
}
|
|
|
|
async function getHiddenUserIds () {
|
|
return UserModel.find({ account_status: 'deactivated' }).distinct('_id')
|
|
}
|
|
|
|
async function isMobileBlockedByTombstone (mobile) {
|
|
const hash = hashValue(mobile)
|
|
if (!hash) return false
|
|
const hit = await DeletedAccountTombstoneModel.findOne({
|
|
mobile_hash: hash,
|
|
expires_at: { $gt: new Date() }
|
|
}).lean()
|
|
return Boolean(hit)
|
|
}
|
|
|
|
async function isUsernameBlockedByTombstone (userName) {
|
|
const hash = hashValue(userName)
|
|
if (!hash) return false
|
|
const hit = await DeletedAccountTombstoneModel.findOne({
|
|
user_name_hash: hash,
|
|
expires_at: { $gt: new Date() }
|
|
}).lean()
|
|
return Boolean(hit)
|
|
}
|
|
|
|
async function createDeletionTombstone ({ mobile, userName }) {
|
|
const expiresAt = new Date(Date.now() + DELETION_TOMBSTONE_DAYS * MS_DAY)
|
|
await DeletedAccountTombstoneModel.create({
|
|
mobile_hash: hashValue(mobile),
|
|
user_name_hash: hashValue(userName),
|
|
expires_at: expiresAt
|
|
})
|
|
}
|
|
|
|
async function purgeUserData (userId) {
|
|
const uid = new mongoose.Types.ObjectId(String(userId))
|
|
await Promise.all([
|
|
PostModel.deleteMany({ user_id: uid }),
|
|
MessageModel.deleteMany({ $or: [{ senderId: uid }, { receiverId: uid }] }),
|
|
PostBookmarkModel.deleteMany({ userId: uid }),
|
|
StoryModel.deleteMany({ user_id: uid }),
|
|
NotificationModel.deleteMany({ user_id: uid }),
|
|
ExploreInteractionModel.deleteMany({
|
|
$or: [{ viewerId: uid }, { authorId: uid }]
|
|
}),
|
|
CourseModel.deleteMany({ user_id: uid }),
|
|
AdvertisingModel.deleteMany({ userId: uid }),
|
|
AcademyModel.deleteMany({ userId: uid })
|
|
])
|
|
}
|
|
|
|
async function purgeExpiredDeactivatedAccounts () {
|
|
const now = new Date()
|
|
const due = await UserModel.find({
|
|
account_status: 'deactivated',
|
|
scheduled_purge_at: { $lte: now }
|
|
}).select('_id mobile user_name').lean()
|
|
|
|
for (const user of due) {
|
|
await purgeUserData(user._id)
|
|
await UserModel.deleteOne({ _id: user._id })
|
|
}
|
|
return due.length
|
|
}
|
|
|
|
async function purgeExpiredTombstones () {
|
|
await DeletedAccountTombstoneModel.deleteMany({
|
|
expires_at: { $lte: new Date() }
|
|
})
|
|
}
|
|
|
|
module.exports = {
|
|
DEACTIVATION_LOCK_DAYS,
|
|
DEACTIVATION_PURGE_MONTHS,
|
|
DELETION_TOMBSTONE_DAYS,
|
|
MS_DAY,
|
|
hashValue,
|
|
isDeactivated,
|
|
isHiddenFromPublic,
|
|
formatChatUserLabel,
|
|
getHiddenUserIds,
|
|
isMobileBlockedByTombstone,
|
|
isUsernameBlockedByTombstone,
|
|
createDeletionTombstone,
|
|
purgeUserData,
|
|
purgeExpiredDeactivatedAccounts,
|
|
purgeExpiredTombstones
|
|
}
|