112 lines
3.5 KiB
JavaScript
112 lines
3.5 KiB
JavaScript
|
|
const { TrackingToken, ClickLog, Company } = require('../models');
|
||
|
|
const { getGeoLocation } = require('../utils/geoip');
|
||
|
|
const { parseUserAgent } = require('../utils/userAgentParser');
|
||
|
|
const telegramService = require('../services/telegram.service');
|
||
|
|
const tokenService = require('../services/token.service');
|
||
|
|
const logger = require('../config/logger');
|
||
|
|
|
||
|
|
exports.trackClick = async (req, res, next) => {
|
||
|
|
try {
|
||
|
|
const { token } = req.params;
|
||
|
|
|
||
|
|
// Find token
|
||
|
|
const trackingToken = await TrackingToken.findOne({
|
||
|
|
where: { token },
|
||
|
|
include: [{ model: Company, as: 'company' }],
|
||
|
|
});
|
||
|
|
|
||
|
|
if (!trackingToken) {
|
||
|
|
logger.warn(`Invalid token accessed: ${token}`);
|
||
|
|
return res.redirect(process.env.BASE_URL || 'https://google.com');
|
||
|
|
}
|
||
|
|
|
||
|
|
// Get IP address
|
||
|
|
const ipAddress = req.headers['x-forwarded-for']?.split(',')[0].trim()
|
||
|
|
|| req.connection.remoteAddress
|
||
|
|
|| req.socket.remoteAddress
|
||
|
|
|| req.ip;
|
||
|
|
|
||
|
|
// Get user agent
|
||
|
|
const userAgent = req.headers['user-agent'] || '';
|
||
|
|
const referer = req.headers['referer'] || req.headers['referrer'] || null;
|
||
|
|
|
||
|
|
// Parse geo location
|
||
|
|
const geoData = getGeoLocation(ipAddress);
|
||
|
|
|
||
|
|
// Parse user agent
|
||
|
|
const uaData = parseUserAgent(userAgent);
|
||
|
|
|
||
|
|
// Create click log
|
||
|
|
const clickLog = await ClickLog.create({
|
||
|
|
token_id: trackingToken.id,
|
||
|
|
ip_address: ipAddress,
|
||
|
|
country: geoData.country,
|
||
|
|
city: geoData.city,
|
||
|
|
latitude: geoData.latitude,
|
||
|
|
longitude: geoData.longitude,
|
||
|
|
user_agent: userAgent,
|
||
|
|
browser: uaData.browser,
|
||
|
|
os: uaData.os,
|
||
|
|
device: uaData.device,
|
||
|
|
referer,
|
||
|
|
});
|
||
|
|
|
||
|
|
// Update token stats
|
||
|
|
const isFirstClick = !trackingToken.clicked;
|
||
|
|
await trackingToken.update({
|
||
|
|
clicked: true,
|
||
|
|
click_count: trackingToken.click_count + 1,
|
||
|
|
first_click_at: isFirstClick ? new Date() : trackingToken.first_click_at,
|
||
|
|
last_click_at: new Date(),
|
||
|
|
});
|
||
|
|
|
||
|
|
// Update company stats
|
||
|
|
await tokenService.updateCompanyStats(trackingToken.company_id);
|
||
|
|
|
||
|
|
// Get updated company for Telegram notification
|
||
|
|
const company = await Company.findByPk(trackingToken.company_id);
|
||
|
|
|
||
|
|
// Send Telegram notification
|
||
|
|
try {
|
||
|
|
const timestamp = new Date().toLocaleString('tr-TR', {
|
||
|
|
year: 'numeric',
|
||
|
|
month: 'long',
|
||
|
|
day: 'numeric',
|
||
|
|
hour: '2-digit',
|
||
|
|
minute: '2-digit',
|
||
|
|
second: '2-digit',
|
||
|
|
});
|
||
|
|
|
||
|
|
await telegramService.sendNotification({
|
||
|
|
companyName: company.name,
|
||
|
|
targetEmail: trackingToken.target_email,
|
||
|
|
employeeName: trackingToken.employee_name,
|
||
|
|
ipAddress,
|
||
|
|
country: geoData.country,
|
||
|
|
city: geoData.city,
|
||
|
|
browser: uaData.browser,
|
||
|
|
os: uaData.os,
|
||
|
|
timestamp,
|
||
|
|
clickCount: trackingToken.click_count + 1,
|
||
|
|
companyTotalClicks: company.total_clicks,
|
||
|
|
companyTotalTokens: company.total_tokens,
|
||
|
|
});
|
||
|
|
|
||
|
|
await clickLog.update({ telegram_sent: true });
|
||
|
|
} catch (telegramError) {
|
||
|
|
logger.error('Telegram notification failed:', telegramError);
|
||
|
|
// Don't fail the request if Telegram fails
|
||
|
|
}
|
||
|
|
|
||
|
|
logger.info(`Click tracked: ${token} from ${ipAddress} (${geoData.city}, ${geoData.country})`);
|
||
|
|
|
||
|
|
// Redirect to landing page
|
||
|
|
res.redirect('/landing.html');
|
||
|
|
} catch (error) {
|
||
|
|
logger.error('Tracking error:', error);
|
||
|
|
// Even on error, redirect to something
|
||
|
|
res.redirect(process.env.BASE_URL || 'https://google.com');
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|