142 lines
5.8 KiB
JavaScript
142 lines
5.8 KiB
JavaScript
const UnitOfWork = require('../../database/UnitOfWork');
|
|
const ReferralService = require('../../services/referral/ReferralService'); // <-- use unified service
|
|
const { logger } = require('../../middleware/logger');
|
|
|
|
// Helper to get frontend URL without trailing slash, no localhost fallback
|
|
function getFrontendUrl() {
|
|
let url = process.env.FRONTEND_URL || '';
|
|
if (url.endsWith('/')) {
|
|
url = url.slice(0, -1);
|
|
}
|
|
return url;
|
|
}
|
|
|
|
class ReferralTokenController {
|
|
static async create(req, res) {
|
|
const userId = req.user.userId;
|
|
const userRole = req.user.role;
|
|
const { expiresInDays, maxUses } = req.body;
|
|
// Normalize unlimited expiry from frontend (0 or -1) to -1 sentinel
|
|
let normalizedExpiresInDays = (expiresInDays === 0) ? -1 : expiresInDays;
|
|
logger.info('ReferralTokenController:createReferralToken:start', { userId, normalizedExpiresInDays, maxUses });
|
|
const unitOfWork = new UnitOfWork();
|
|
await unitOfWork.start();
|
|
try {
|
|
let maxActiveLinks = 5;
|
|
if (userRole === 'admin' || userRole === 'super_admin') {
|
|
maxActiveLinks = 15;
|
|
}
|
|
const activeCount = await ReferralService.countActiveReferralTokens(userId, unitOfWork);
|
|
if (activeCount >= maxActiveLinks) {
|
|
await unitOfWork.rollback();
|
|
return res.status(403).json({
|
|
success: false,
|
|
message: `Maximum active referral links reached (${maxActiveLinks}) for your role (${userRole}).`
|
|
});
|
|
}
|
|
const token = await ReferralService.createReferralToken({
|
|
userId,
|
|
expiresInDays: normalizedExpiresInDays,
|
|
maxUses,
|
|
unitOfWork
|
|
});
|
|
if (normalizedExpiresInDays === -1) {
|
|
logger.info('ReferralTokenController:createReferralToken:unlimited_expiry', { userId });
|
|
}
|
|
await unitOfWork.commit();
|
|
logger.info('ReferralTokenController:createReferralToken:success', { token });
|
|
const link = `${getFrontendUrl()}/register?ref=${token.token}`;
|
|
res.json({ success: true, token: token.token, link, expiresAt: token.expiresAt, maxUses: token.maxUses });
|
|
} catch (error) {
|
|
await unitOfWork.rollback(error);
|
|
logger.error('ReferralTokenController:createReferralToken:error', { userId, error });
|
|
res.status(400).json({ success: false, message: error.message });
|
|
}
|
|
}
|
|
|
|
static async list(req, res) {
|
|
const userId = req.user.userId;
|
|
logger.info('ReferralTokenController:getUserReferralTokens:start', { userId });
|
|
const unitOfWork = new UnitOfWork();
|
|
await unitOfWork.start();
|
|
try {
|
|
const tokens = await ReferralService.getUserReferralTokens(userId, unitOfWork);
|
|
await unitOfWork.commit();
|
|
logger.info('ReferralTokenController:getUserReferralTokens:success', { count: tokens.length });
|
|
const frontendUrl = getFrontendUrl();
|
|
|
|
// FIX: tokens already transformed by service; use provided fields instead of raw DB column names
|
|
const result = tokens.map(t => {
|
|
const isUnlimitedExpiry = t.isUnlimited || !t.expires;
|
|
const usage = t.usage || (t.isUnlimited ? `${t.used}/∞` : `${t.used}/${t.maxUses}`);
|
|
return {
|
|
id: t.id,
|
|
status: t.status,
|
|
created: t.created,
|
|
created_at: t.created, // legacy alias
|
|
expires: isUnlimitedExpiry ? '∞' : t.expires,
|
|
expires_at: t.expires, // legacy alias
|
|
link: t.link || `${frontendUrl}/register?ref=${t.token}`,
|
|
token: t.token,
|
|
// normalized usage fields
|
|
used: t.used,
|
|
maxUses: t.maxUses,
|
|
isUnlimited: t.isUnlimited,
|
|
usage,
|
|
usageDisplay: usage,
|
|
// backward compatibility (old FE expected these)
|
|
max_uses: t.isUnlimited ? -1 : t.maxUses,
|
|
usage_count: t.used
|
|
};
|
|
});
|
|
|
|
return res.json({ success: true, tokens: result });
|
|
} catch (error) {
|
|
await unitOfWork.rollback(error);
|
|
logger.error('ReferralTokenController:getUserReferralTokens:error', { userId, error });
|
|
res.status(500).json({ success: false, message: error.message });
|
|
}
|
|
}
|
|
|
|
static async stats(req, res) {
|
|
const userId = req.user.userId;
|
|
logger.info('ReferralTokenController:getUserReferralStats:start', { userId });
|
|
const unitOfWork = new UnitOfWork();
|
|
await unitOfWork.start();
|
|
try {
|
|
const stats = await ReferralService.getUserReferralStats(userId, unitOfWork);
|
|
await unitOfWork.commit();
|
|
logger.info('ReferralTokenController:getUserReferralStats:success', { stats });
|
|
// Response now includes companyUsersReferred and personalUsersReferred
|
|
res.json({ success: true, stats });
|
|
} catch (error) {
|
|
await unitOfWork.rollback(error);
|
|
logger.error('ReferralTokenController:getUserReferralStats:error', { userId, error });
|
|
res.status(500).json({ success: false, message: error.message });
|
|
}
|
|
}
|
|
|
|
static async deactivate(req, res) {
|
|
const userId = req.user.userId;
|
|
const { tokenId } = req.body;
|
|
logger.info('ReferralTokenController:deactivateReferralToken:start', { userId, tokenId });
|
|
if (!tokenId) {
|
|
return res.status(400).json({ success: false, message: 'tokenId is required' });
|
|
}
|
|
const unitOfWork = new UnitOfWork();
|
|
await unitOfWork.start();
|
|
try {
|
|
await ReferralService.deactivateReferralToken(userId, tokenId, unitOfWork);
|
|
await unitOfWork.commit();
|
|
logger.info('ReferralTokenController:deactivateReferralToken:success', { userId, tokenId });
|
|
res.json({ success: true, message: 'Referral link deactivated' });
|
|
} catch (error) {
|
|
await unitOfWork.rollback(error);
|
|
logger.error('ReferralTokenController:deactivateReferralToken:error', { userId, tokenId, error });
|
|
res.status(500).json({ success: false, message: error.message });
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = ReferralTokenController;
|