const { TrackingToken, Company, MailTemplate } = require('../models'); const { generateTrackingToken } = require('../utils/tokenGenerator'); const mailService = require('./mail.service'); const logger = require('../config/logger'); class TokenService { async createToken(data) { const { company_id, target_email, employee_name, template_type, from_name } = data; // Generate unique token let token = generateTrackingToken(); let isUnique = false; let attempts = 0; // Ensure token is unique while (!isUnique && attempts < 5) { const existing = await TrackingToken.findOne({ where: { token } }); if (!existing) { isUnique = true; } else { token = generateTrackingToken(); attempts++; } } if (!isUnique) { throw new Error('Failed to generate unique token'); } // Get company and template const company = await Company.findByPk(company_id); if (!company) { throw new Error('Company not found'); } const template = await MailTemplate.findOne({ where: { template_type } }); if (!template) { throw new Error('Mail template not found'); } // Create tracking token const trackingToken = await TrackingToken.create({ token, company_id, target_email, employee_name, template_type, from_name: from_name || null, mail_subject: template.subject_template.replace('{{company_name}}', company.name), }); // Update company stats await company.increment('total_tokens'); logger.info(`Token created: ${token} for ${target_email}`); return trackingToken; } async sendMail(tokenId) { const token = await TrackingToken.findByPk(tokenId, { include: [{ model: Company, as: 'company' }], }); if (!token) { throw new Error('Token not found'); } if (token.mail_sent) { throw new Error('Mail already sent for this token'); } // Get mail template const template = await MailTemplate.findOne({ where: { template_type: token.template_type }, }); if (!template) { throw new Error('Mail template not found'); } // Get base URL from settings or env const { Settings } = require('../models'); const baseUrlSetting = await Settings.findOne({ where: { key: 'base_url' } }); const baseUrl = baseUrlSetting?.value || process.env.BASE_URL || 'http://localhost:3000'; // Prepare template data const trackingUrl = `${baseUrl}/t/${token.token}`; const currentDate = new Date().toLocaleDateString('tr-TR', { year: 'numeric', month: 'long', day: 'numeric', }); const currentYear = new Date().getFullYear(); const templateData = { company_name: token.company.name, employee_name: token.employee_name, tracking_url: trackingUrl, current_date: currentDate, current_year: currentYear, }; // Render mail body const htmlBody = mailService.renderTemplate(template.body_html, templateData); const subject = mailService.renderTemplate(template.subject_template, templateData); // Send mail with custom from_name if provided await mailService.sendMail(token.target_email, subject, htmlBody, token.from_name); // Update token await token.update({ mail_sent: true, sent_at: new Date(), }); logger.info(`Mail sent for token: ${token.token} to ${token.target_email}`); return token; } async updateCompanyStats(companyId) { const company = await Company.findByPk(companyId); if (!company) return; // Count tokens const totalTokens = await TrackingToken.count({ where: { company_id: companyId }, }); const clickedTokens = await TrackingToken.count({ where: { company_id: companyId, clicked: true }, }); const totalClicks = await TrackingToken.sum('click_count', { where: { company_id: companyId }, }); const clickRate = totalTokens > 0 ? ((clickedTokens / totalTokens) * 100).toFixed(2) : 0; await company.update({ total_tokens: totalTokens, total_clicks: totalClicks || 0, click_rate: clickRate, }); logger.info(`Company stats updated for: ${company.name}`); } } module.exports = new TokenService();