4.1.3
This commit is contained in:
59
controllers/application/analytics/analyticsController.js
Normal file
59
controllers/application/analytics/analyticsController.js
Normal file
@@ -0,0 +1,59 @@
|
||||
const jwt = require('jsonwebtoken')
|
||||
const AnalyticsEvent = require('../../../models/AnalyticsEventModel')
|
||||
|
||||
const MAX_BATCH_SIZE = 50
|
||||
const VALID_TYPES = new Set(['session_start', 'page_view', 'click'])
|
||||
const VALID_PLATFORMS = new Set(['web', 'android', 'ios'])
|
||||
|
||||
function decodeUserId(req) {
|
||||
const token = req.header('Authorization')?.split(' ')[1]
|
||||
if (!token) return null
|
||||
try {
|
||||
const decoded = jwt.verify(token, process.env.APP_SECRET)
|
||||
return decoded?.id || null
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
// ورودیِ خام و کوتاه (بدون توکن الزامی — کاربر مهمون هم ردیابی میشه)؛ از هر دو کلاینت
|
||||
// وب (sendBeacon موقع بستن تب) و اپلیکیشن اندروید/iOS بهصورت دستهای ارسال میشه
|
||||
const trackEvents = async (req, res, next) => {
|
||||
try {
|
||||
const userId = decodeUserId(req)
|
||||
const events = Array.isArray(req.body?.events) ? req.body.events : []
|
||||
if (!events.length) return res.status(204).end()
|
||||
|
||||
const docs = events.slice(0, MAX_BATCH_SIZE).reduce((acc, e) => {
|
||||
if (!e || !VALID_TYPES.has(e.type) || !VALID_PLATFORMS.has(e.platform)) {
|
||||
return acc
|
||||
}
|
||||
if (!e.sessionId || typeof e.sessionId !== 'string') return acc
|
||||
|
||||
acc.push({
|
||||
userId,
|
||||
sessionId: e.sessionId,
|
||||
type: e.type,
|
||||
path: typeof e.path === 'string' ? e.path.slice(0, 500) : null,
|
||||
durationMs:
|
||||
typeof e.durationMs === 'number' && e.durationMs >= 0
|
||||
? Math.min(e.durationMs, 24 * 60 * 60 * 1000)
|
||||
: null,
|
||||
label: typeof e.label === 'string' ? e.label.slice(0, 200) : null,
|
||||
platform: e.platform,
|
||||
device: typeof e.device === 'string' ? e.device.slice(0, 100) : null,
|
||||
browser: typeof e.browser === 'string' ? e.browser.slice(0, 100) : null,
|
||||
os: typeof e.os === 'string' ? e.os.slice(0, 100) : null
|
||||
})
|
||||
return acc
|
||||
}, [])
|
||||
|
||||
if (docs.length) await AnalyticsEvent.insertMany(docs, { ordered: false })
|
||||
|
||||
res.status(204).end()
|
||||
} catch (error) {
|
||||
next(error)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { trackEvents }
|
||||
Reference in New Issue
Block a user