const Event = require('../Models/Event'); const User = require('../Models/User'); const { notifyUser } = require('../Services/notification'); const { logger } = require('../Middleware/errorHandler'); const { cacheService } = require('../Services/cacheService'); /** * Get all pending certificate verifications */ async function getPendingVerifications(req, res) { try { const { page = 1, limit = 10, eventType } = req.query; const skip = (parseInt(page) - 1) * parseInt(limit); // Build query const query = { 'certificateSettings.verificationStatus': 'pending', 'features.certificateEnabled': true, }; if (eventType) { query.type = eventType; } // Get pending events const events = await Event.find(query) .populate('hostUserId', 'name email') .populate('institutionId', 'name') .populate('certificateSettings.submittedBy', 'name email') .sort({ 'certificateSettings.submittedAt': 1 }) // Oldest first .skip(skip) .limit(parseInt(limit)) .lean(); const totalPending = await Event.countDocuments(query); // Format response const pending = events.map((event) => ({ eventId: event._id, eventTitle: event.title, eventDate: event.date, eventType: event.type, hostName: event.hostUserId?.name, hostEmail: event.hostUserId?.email, institutionName: event.institutionId?.name, certificateConfig: { selectedTemplateId: event.certificateSettings.selectedTemplateId, certificateType: event.certificateSettings.certificateType, awardText: event.certificateSettings.awardText, leftSignatory: event.certificateSettings.leftSignatory, rightSignatory: event.certificateSettings.rightSignatory, uploadedAssets: event.certificateSettings.uploadedAssets, }, submittedAt: event.certificateSettings.submittedAt, submittedBy: event.certificateSettings.submittedBy, })); return res.json({ pending, pagination: { page: parseInt(page), limit: parseInt(limit), total: totalPending, pages: Math.ceil(totalPending / parseInt(limit)), }, }); } catch (error) { logger.error('Get pending verifications error:', error); return res .status(500) .json({ error: 'Error fetching pending verifications' }); } } /** * Get verification statistics */ async function getVerificationStats(req, res) { try { const stats = await Event.aggregate([ { $match: { 'features.certificateEnabled': true, }, }, { $group: { _id: '$certificateSettings.verificationStatus', count: { $sum: 1 }, }, }, ]); const statsObj = { total: 0, pending: 0, approved: 0, rejected: 0, not_configured: 0, }; stats.forEach((stat) => { statsObj[stat._id || 'not_configured'] = stat.count; statsObj.total += stat.count; }); return res.json(statsObj); } catch (error) { logger.error('Get verification stats error:', error); return res .status(500) .json({ error: 'Error fetching verification statistics' }); } } /** * Get specific verification details */ async function getVerificationById(req, res) { try { const { eventId } = req.params; const event = await Event.findById(eventId) .populate('hostUserId', 'name email') .populate('institutionId', 'name') .populate('certificateSettings.submittedBy', 'name email') .populate('certificateSettings.verifiedBy', 'name email') .lean(); if (!event) { return res.status(404).json({ error: 'Event not found' }); } if (!event.features.certificateEnabled) { return res .status(400) .json({ error: 'Certificates not enabled for this event' }); } return res.json({ eventId: event._id, eventTitle: event.title, eventDescription: event.description, eventDate: event.date, eventType: event.type, hostName: event.hostUserId?.name, hostEmail: event.hostUserId?.email, institutionName: event.institutionId?.name, certificateConfig: { selectedTemplateId: event.certificateSettings.selectedTemplateId, certificateType: event.certificateSettings.certificateType, awardText: event.certificateSettings.awardText, leftSignatory: event.certificateSettings.leftSignatory, rightSignatory: event.certificateSettings.rightSignatory, uploadedAssets: event.certificateSettings.uploadedAssets, }, verificationStatus: event.certificateSettings.verificationStatus, submittedAt: event.certificateSettings.submittedAt, submittedBy: event.certificateSettings.submittedBy, verifiedAt: event.certificateSettings.verifiedAt, verifiedBy: event.certificateSettings.verifiedBy, rejectionReason: event.certificateSettings.rejectionReason, }); } catch (error) { logger.error('Get verification by ID error:', error); return res .status(500) .json({ error: 'Error fetching verification details' }); } } /** * Approve certificate configuration */ async function approveCertificateConfig(req, res) { try { const { eventId } = req.params; const verifierId = req.user.id; const event = await Event.findById(eventId).populate( 'hostUserId', 'name email' ); if (!event) { return res.status(404).json({ error: 'Event not found' }); } if (!event.features.certificateEnabled) { return res .status(400) .json({ error: 'Certificates not enabled for this event' }); } if (event.certificateSettings.verificationStatus !== 'pending') { return res.status(400).json({ error: `Certificate configuration is not pending (current status: ${event.certificateSettings.verificationStatus})`, }); } // Check if all required assets are uploaded const assets = event.certificateSettings.uploadedAssets; if ( !assets?.organizationLogo || !assets?.leftSignature || !assets?.rightSignature ) { return res.status(400).json({ error: 'Cannot approve: Missing required assets (organization logo, left signature, or right signature)', }); } // Update verification status and potentially the template const { selectedTemplateId } = req.body; if (selectedTemplateId) { event.certificateSettings.selectedTemplateId = selectedTemplateId; } event.certificateSettings.verificationStatus = 'approved'; event.certificateSettings.verifiedBy = verifierId; event.certificateSettings.verifiedAt = new Date(); await event.save(); // Invalidate cache so verifier dashboard shows updated data await cacheService.invalidateCertificateVerification(eventId); await cacheService.invalidateVerifierCache(); // Notify host const host = event.hostUserId; if (host) { await notifyUser({ userId: host._id, type: 'certificate_verification', message: `Your certificate configuration for "${event.title}" has been approved!`, data: { eventId: event._id, eventTitle: event.title, status: 'approved', }, emailOptions: { to: host.email, subject: `Certificate Configuration Approved: ${event.title}`, html: `

🎉 Certificate Configuration Approved!

Dear ${host.name},

Your certificate configuration for ${event.title} has been approved by a verifier.

You can now generate certificates for all attended participants.

Next Steps:


Best regards,
CampVerse Team

`, }, }); } return res.json({ success: true, message: 'Certificate configuration approved successfully', eventId: event._id, verificationStatus: 'approved', approvedBy: verifierId, approvedAt: event.certificateSettings.verifiedAt, }); } catch (error) { logger.error('Approve certificate config error:', error); return res .status(500) .json({ error: 'Error approving certificate configuration' }); } } /** * Reject certificate configuration */ async function rejectCertificateConfig(req, res) { try { const { eventId } = req.params; const { reason, specificIssues } = req.body; const verifierId = req.user.id; if (!reason) { return res.status(400).json({ error: 'Rejection reason is required' }); } const event = await Event.findById(eventId).populate( 'hostUserId', 'name email' ); if (!event) { return res.status(404).json({ error: 'Event not found' }); } if (!event.features.certificateEnabled) { return res .status(400) .json({ error: 'Certificates not enabled for this event' }); } if (event.certificateSettings.verificationStatus !== 'pending') { return res.status(400).json({ error: `Certificate configuration is not pending (current status: ${event.certificateSettings.verificationStatus})`, }); } // Update verification status event.certificateSettings.verificationStatus = 'rejected'; event.certificateSettings.verifiedBy = verifierId; event.certificateSettings.verifiedAt = new Date(); event.certificateSettings.rejectionReason = reason; if (specificIssues && Array.isArray(specificIssues)) { event.certificateSettings.specificIssues = specificIssues; } await event.save(); // Invalidate cache so verifier dashboard shows updated data await cacheService.invalidateCertificateVerification(eventId); await cacheService.invalidateVerifierCache(); // Notify host with detailed feedback const host = event.hostUserId; if (host) { const issuesList = specificIssues && specificIssues.length > 0 ? `` : ''; await notifyUser({ userId: host._id, type: 'certificate_verification', message: `Your certificate configuration for "${event.title}" was rejected. Please review and resubmit.`, data: { eventId: event._id, eventTitle: event.title, status: 'rejected', reason: reason, specificIssues: specificIssues, }, emailOptions: { to: host.email, subject: `Certificate Configuration Rejected: ${event.title}`, html: `

⚠️ Certificate Configuration Rejected

Dear ${host.name},

Your certificate configuration for ${event.title} has been rejected by a verifier.

Reason: ${reason}

${issuesList ? `

Specific Issues:

${issuesList}` : ''}

Next Steps:


If you have questions, please contact support.


Best regards,
CampVerse Team

`, }, }); } return res.json({ success: true, message: 'Certificate configuration rejected', eventId: event._id, verificationStatus: 'rejected', rejectedBy: verifierId, rejectedAt: event.certificateSettings.verifiedAt, rejectionReason: reason, specificIssues: specificIssues, }); } catch (error) { logger.error('Reject certificate config error:', error); return res .status(500) .json({ error: 'Error rejecting certificate configuration' }); } } /** * Request changes to certificate configuration */ async function requestConfigChanges(req, res) { try { const { eventId } = req.params; const { requestedChanges } = req.body; const verifierId = req.user.id; if (!requestedChanges || !Array.isArray(requestedChanges) || requestedChanges.length === 0) { return res.status(400).json({ error: 'Requested changes are required' }); } const event = await Event.findById(eventId).populate( 'hostUserId', 'name email' ); if (!event) { return res.status(404).json({ error: 'Event not found' }); } if (!event.features.certificateEnabled) { return res .status(400) .json({ error: 'Certificates not enabled for this event' }); } if (event.certificateSettings.verificationStatus !== 'pending') { return res.status(400).json({ error: `Certificate configuration is not pending (current status: ${event.certificateSettings.verificationStatus})`, }); } // Store requested changes (status remains pending) event.certificateSettings.requestedChanges = requestedChanges; event.certificateSettings.changesRequestedBy = verifierId; event.certificateSettings.changesRequestedAt = new Date(); await event.save(); // Notify host with requested changes const host = event.hostUserId; if (host) { const changesList = ``; await notifyUser({ userId: host._id, type: 'certificate_verification', message: `Changes requested for your certificate configuration for "${event.title}"`, data: { eventId: event._id, eventTitle: event.title, status: 'pending', requestedChanges: requestedChanges, }, emailOptions: { to: host.email, subject: `Changes Requested: Certificate Configuration for ${event.title}`, html: `

📝 Changes Requested

Dear ${host.name},

A verifier has reviewed your certificate configuration for ${event.title} and is requesting the following changes:

${changesList}

Next Steps:


Best regards,
CampVerse Team

`, }, }); } return res.json({ success: true, message: 'Changes requested successfully', eventId: event._id, verificationStatus: 'pending', requestedChanges: requestedChanges, requestedBy: verifierId, requestedAt: event.certificateSettings.changesRequestedAt, }); } catch (error) { logger.error('Request config changes error:', error); return res .status(500) .json({ error: 'Error requesting configuration changes' }); } } module.exports = { getPendingVerifications, getVerificationStats, getVerificationById, approveCertificateConfig, rejectCertificateConfig, requestConfigChanges, };