Spaces:
Paused
Paused
Download Controller/support.js from imkrish/campverse-backend: direct link, hf CLI and curl.
- Browser
- Download file 8.51 kB
-
https://huggingface.co/spaces/imkrish/campverse-backend/resolve/main/Controller/support.js
- Command line
-
hf download hf://spaces/imkrish/campverse-backend/Controller/support.js
-
curl -L -o support.js https://huggingface.co/spaces/imkrish/campverse-backend/resolve/main/Controller/support.js
8.51 kB
| const SupportTicket = require('../Models/SupportTicket'); | |
| const { uploadUserDocument } = require('../Services/firebaseStorageService'); | |
| const { logger } = require('../Middleware/errorHandler'); | |
| // Submit support ticket (user) | |
| async function submitTicket(req, res) { | |
| try { | |
| const { topic, subject, message, name, email } = req.body; | |
| const userId = req.user.id; | |
| // Validate required fields | |
| if (!topic || !subject || !message || !name || !email) { | |
| return res.status(400).json({ | |
| error: 'All fields are required: topic, subject, message, name, email', | |
| }); | |
| } | |
| // Handle file attachment if present | |
| let attachment = null; | |
| if (req.file) { | |
| try { | |
| const url = await uploadUserDocument( | |
| req.file.buffer, | |
| req.file.originalname, | |
| 'support', | |
| userId, | |
| req.file.mimetype, | |
| ); | |
| attachment = { | |
| filename: req.file.originalname, | |
| url, | |
| mimetype: req.file.mimetype, | |
| size: req.file.size, | |
| }; | |
| } catch (uploadError) { | |
| logger.error('File upload failed:', uploadError); | |
| return res.status(500).json({ error: 'Failed to upload attachment' }); | |
| } | |
| } | |
| // Create support ticket | |
| const ticket = new SupportTicket({ | |
| userId, | |
| topic, | |
| subject: subject.trim(), | |
| message: message.trim(), | |
| name: name.trim(), | |
| email: email.trim(), | |
| attachment, | |
| }); | |
| await ticket.save(); | |
| res.status(201).json({ | |
| message: 'Support ticket submitted successfully', | |
| ticket: { | |
| ticketId: ticket.ticketId, | |
| topic: ticket.topic, | |
| subject: ticket.subject, | |
| status: ticket.status, | |
| priority: ticket.priority, | |
| createdAt: ticket.createdAt, | |
| }, | |
| }); | |
| } catch (err) { | |
| logger.error('Submit ticket error:', err); | |
| res.status(500).json({ error: 'Failed to submit support ticket' }); | |
| } | |
| } | |
| // Get user's tickets (user) | |
| async function getMyTickets(req, res) { | |
| try { | |
| const userId = req.user.id; | |
| const tickets = await SupportTicket.find({ userId }) | |
| .sort({ createdAt: -1 }) | |
| .select('-adminNotes -assignedTo'); | |
| res.json(tickets); | |
| } catch (err) { | |
| logger.error('Get tickets error:', err); | |
| res.status(500).json({ error: 'Failed to fetch tickets' }); | |
| } | |
| } | |
| // Get ticket by ID (user or admin) | |
| async function getTicketById(req, res) { | |
| try { | |
| const { id } = req.params; | |
| const userId = req.user.id; | |
| const ticket = await SupportTicket.findById(id) | |
| .populate('userId', 'name email') | |
| .populate('assignedTo', 'name') | |
| .populate('adminNotes.addedBy', 'name'); | |
| if (!ticket) { | |
| return res.status(404).json({ error: 'Ticket not found' }); | |
| } | |
| // Users can only see their own tickets, admins can see all | |
| if ( | |
| !req.user.roles.includes('platformAdmin') && | |
| !req.user.roles.includes('verifier') | |
| ) { | |
| if (ticket.userId._id.toString() !== userId) { | |
| return res.status(403).json({ error: 'Access denied' }); | |
| } | |
| } | |
| res.json(ticket); | |
| } catch (err) { | |
| logger.error('Get ticket error:', err); | |
| res.status(500).json({ error: 'Failed to fetch ticket' }); | |
| } | |
| } | |
| // Get all tickets (admin/verifier only) | |
| async function getAllTickets(req, res) { | |
| try { | |
| if ( | |
| !req.user.roles.includes('platformAdmin') && | |
| !req.user.roles.includes('verifier') | |
| ) { | |
| return res.status(403).json({ error: 'Access denied' }); | |
| } | |
| const { status, topic, priority, page = 1, limit = 20 } = req.query; | |
| const skip = (page - 1) * limit; | |
| // Build filter | |
| const filter = {}; | |
| if (status) filter.status = status; | |
| if (topic) filter.topic = topic; | |
| if (priority) filter.priority = priority; | |
| const tickets = await SupportTicket.find(filter) | |
| .populate('userId', 'name email') | |
| .populate('assignedTo', 'name') | |
| .sort({ createdAt: -1 }) | |
| .skip(skip) | |
| .limit(parseInt(limit)); | |
| const total = await SupportTicket.countDocuments(filter); | |
| res.json({ | |
| tickets, | |
| pagination: { | |
| page: parseInt(page), | |
| limit: parseInt(limit), | |
| total, | |
| pages: Math.ceil(total / limit), | |
| }, | |
| }); | |
| } catch (err) { | |
| logger.error('Get all tickets error:', err); | |
| res.status(500).json({ error: 'Failed to fetch tickets' }); | |
| } | |
| } | |
| // Update ticket (admin/verifier only) | |
| async function updateTicket(req, res) { | |
| try { | |
| if ( | |
| !req.user.roles.includes('platformAdmin') && | |
| !req.user.roles.includes('verifier') | |
| ) { | |
| return res.status(403).json({ error: 'Access denied' }); | |
| } | |
| const { id } = req.params; | |
| const { status, priority, assignedTo, adminNotes } = req.body; | |
| const ticket = await SupportTicket.findById(id); | |
| if (!ticket) { | |
| return res.status(404).json({ error: 'Ticket not found' }); | |
| } | |
| // Update fields | |
| if (status && status !== ticket.status) { | |
| ticket.status = status; | |
| if (status === 'resolved') { | |
| ticket.resolvedAt = new Date(); | |
| } else if (status === 'closed') { | |
| ticket.closedAt = new Date(); | |
| } | |
| } | |
| if (priority) ticket.priority = priority; | |
| if (assignedTo) ticket.assignedTo = assignedTo; | |
| // Add admin notes | |
| if (adminNotes && adminNotes.trim()) { | |
| ticket.adminNotes = ticket.adminNotes || []; | |
| ticket.adminNotes.push({ | |
| note: adminNotes.trim(), | |
| addedBy: req.user.id, | |
| }); | |
| } | |
| await ticket.save(); | |
| res.json({ | |
| message: 'Ticket updated successfully', | |
| ticket: { | |
| id: ticket._id, | |
| ticketId: ticket.ticketId, | |
| status: ticket.status, | |
| priority: ticket.priority, | |
| assignedTo: ticket.assignedTo, | |
| adminNotes: ticket.adminNotes, | |
| }, | |
| }); | |
| } catch (err) { | |
| logger.error('Update ticket error:', err); | |
| res.status(500).json({ error: 'Failed to update ticket' }); | |
| } | |
| } | |
| // Get support analytics (admin only) | |
| async function getSupportAnalytics(req, res) { | |
| try { | |
| if (!req.user.roles.includes('platformAdmin')) { | |
| return res.status(403).json({ error: 'Access denied' }); | |
| } | |
| const totalTickets = await SupportTicket.countDocuments(); | |
| const openTickets = await SupportTicket.countDocuments({ status: 'open' }); | |
| const resolvedTickets = await SupportTicket.countDocuments({ | |
| status: 'resolved', | |
| }); | |
| // Topic distribution | |
| const topicStats = await SupportTicket.aggregate([ | |
| { $group: { _id: '$topic', count: { $sum: 1 } } }, | |
| { $sort: { count: -1 } }, | |
| ]); | |
| // Priority distribution | |
| const priorityStats = await SupportTicket.aggregate([ | |
| { $group: { _id: '$priority', count: { $sum: 1 } } }, | |
| { $sort: { count: -1 } }, | |
| ]); | |
| // Status distribution | |
| const statusStats = await SupportTicket.aggregate([ | |
| { $group: { _id: '$status', count: { $sum: 1 } } }, | |
| { $sort: { count: -1 } }, | |
| ]); | |
| // Monthly trend (last 6 months) | |
| const sixMonthsAgo = new Date(); | |
| sixMonthsAgo.setMonth(sixMonthsAgo.getMonth() - 6); | |
| const monthlyTrend = await SupportTicket.aggregate([ | |
| { $match: { createdAt: { $gte: sixMonthsAgo } } }, | |
| { | |
| $group: { | |
| _id: { | |
| year: { $year: '$createdAt' }, | |
| month: { $month: '$createdAt' }, | |
| }, | |
| count: { $sum: 1 }, | |
| }, | |
| }, | |
| { $sort: { '_id.year': 1, '_id.month': 1 } }, | |
| ]); | |
| // Average resolution time | |
| const resolvedTicketsWithTime = await SupportTicket.find({ | |
| status: 'resolved', | |
| resolvedAt: { $exists: true }, | |
| }); | |
| let totalResolutionTime = 0; | |
| let resolvedCount = 0; | |
| resolvedTicketsWithTime.forEach((ticket) => { | |
| if (ticket.resolvedAt && ticket.createdAt) { | |
| totalResolutionTime += ticket.resolvedAt - ticket.createdAt; | |
| resolvedCount++; | |
| } | |
| }); | |
| const avgResolutionTime = | |
| resolvedCount > 0 ? totalResolutionTime / resolvedCount : 0; | |
| res.json({ | |
| totalTickets, | |
| openTickets, | |
| resolvedTickets, | |
| topicStats, | |
| priorityStats, | |
| statusStats, | |
| monthlyTrend, | |
| avgResolutionTime: Math.round(avgResolutionTime / (1000 * 60 * 60 * 24)), // in days | |
| }); | |
| } catch (err) { | |
| logger.error('Get support analytics error:', err); | |
| res.status(500).json({ error: 'Failed to fetch analytics' }); | |
| } | |
| } | |
| module.exports = { | |
| submitTicket, | |
| getMyTickets, | |
| getTicketById, | |
| getAllTickets, | |
| updateTicket, | |
| getSupportAnalytics, | |
| }; | |