// API endpoint to process email user actions - urls we send in emails to users import { getToken } from "next-auth/jwt"; import type { NextApiRequest, NextApiResponse } from 'next'; import { createRouter, expressWrapper } from "next-connect"; const common = require('../../src/helpers/common'); const data = require('../../src/helpers/data'); const emailHelper = require('../../src/helpers/email'); const { v4: uuidv4 } = require('uuid'); const CON = require("../../src/helpers/const"); import { EventLogType } from "@prisma/client"; import fs from 'fs'; import path from 'path'; const handlebars = require("handlebars"); const router = createRouter(); //action to accept coverme request from email /** * * @param req import { NextApiRequest, NextApiResponse } from 'next' * @param res import { NextApiRequest, NextApiResponse } from 'next' */ export default async function handler(req, res) { const prisma = common.getPrismaClient(); const action = req.query.action; const emailaction = req.query.emailaction; // Retrieve and validate the JWT token //response is a special action that does not require a token if (action == "email_response") { switch (emailaction) { case "coverMeAccept": //validate shiftId and assignmentId let shiftId = req.query.shiftId; let userId = req.query.userId; let publisher = await prisma.publisher.findUnique({ where: { id: userId } }); // Update the user status to accepted console.log("User: " + publisher.firstName + " " + publisher.lastName + " accepted the CoverMe request"); let assignmentPID = req.query.assignmentPID; if (!shiftId) { return res.status(400).json({ message: "Shift ID is not provided" }); } if (!assignmentPID) { return res.status(400).json({ message: "Assignment PID is not provided" }); } //check if the assignment request is still open const assignment = await prisma.assignment.findFirst({ where: { publicGuid: assignmentPID, shiftId: parseInt(shiftId), isConfirmed: false }, include: { shift: { include: { cartEvent: { include: { location: true } }, assignments: { include: { publisher: true // { // include: { // email: true, // firstName: true, // lastName: true // } // } } } } }, publisher: true } }); if (!assignment) { const messagePageUrl = `/message?message=${encodeURIComponent('Благодаря за желанието, но някой е отговорил на тази заявка за заместване и тя вече е неактивна')}&type=info&caption=${encodeURIComponent('Някой вече те изпревари. Заявката е вече обработена')}`; res.redirect(messagePageUrl); return; } let to = assignment.shift.assignments.map(a => a.publisher.email); to.push(publisher.email); // update the assignment. clear the guid, isConfirmed to true await prisma.assignment.update({ where: { id: assignment.id }, data: { publisherId: userId, publicGuid: null, // if this exists, we consider the request open isConfirmed: true } }); const newAssignment = await prisma.assignment.findFirst({ where: { shiftId: parseInt(shiftId), isConfirmed: true }, include: { shift: { include: { cartEvent: { include: { location: true } }, assignments: { include: { publisher: true } } } } } }); await prisma.eventLog.create({ data: { date: new Date(), publisher: { connect: { id: publisher.id } }, shift: { connect: { id: assignment.shiftId } }, type: EventLogType.AssignmentReplacementAccepted, content: "Заявка за заместване приета от " + publisher.firstName + " " + publisher.lastName } }); const shiftStr = `${CON.weekdaysBG[assignment.shift.startTime.getDay()]} ${CON.GetDateFormat(assignment.shift.startTime)} at ${assignment.shift.cartEvent.location.name} from ${CON.GetTimeFormat(assignment.shift.startTime)} to ${CON.GetTimeFormat(assignment.shift.endTime)}`; const newPubs = newAssignment.shift.assignments.map(a => ({ name: `${a.publisher.firstName} ${a.publisher.lastName}`, phone: a.publisher.phone })); let model = { user: publisher, shiftStr: shiftStr, shiftId: assignment.shiftId, prefix: publisher.isMale ? "Брат" : "Сестра", oldPubName: assignment.publisher.firstName + " " + assignment.publisher.lastName, firstName: publisher.firstName, lastName: publisher.lastName, newPubs: newPubs, placeName: assignment.shift.cartEvent.location.name, dateStr: common.getDateFormated(assignment.shift.startTime), time: common.formatTimeHHmm(assignment.shift.startTime), sentDate: common.getDateFormated(new Date()) }; emailHelper.SendEmailHandlebars(to, "coverMeAccepted", model); const messagePageUrl = `/message?message=${encodeURIComponent('Вашата заявка за замстване е обработена успешно')}&type=info&caption=${encodeURIComponent('Благодаря!')}`; res.redirect(messagePageUrl); break; //POST case "send_report": //we can send report form in the emails to the user. process the POSTED data here // Send report form to the user //get from POST data: locationId, date, placementCount, videoCount, returnVisitInfoCount, conversationCount let locationId = req.body.locationId; let date = req.body.date; let placementCount = req.body.placementCount; let videoCount = req.body.videoCount; let returnVisitInfoCount = req.body.returnVisitInfoCount; let conversationCount = req.body.conversationCount; console.log("User: " + user.email + " sent a report: " + locationId + " " + date + " " + placementCount + " " + videoCount + " " + returnVisitInfoCount + " " + conversationCount); //save the report in the database await prisma.report.create({ data: { userId: parseInt(userId), locationId: parseInt(locationId), date: date, placementCount: parseInt(placementCount), videoCount: parseInt(videoCount), returnVisitInfoCount: parseInt(returnVisitInfoCount), conversationCount: parseInt(conversationCount) } }); break; } // //send email response to the user // const emailResponse = await common.sendEmail(user.email, "Email Action Processed", // "Your email action was processed successfully"); } else { const token = await getToken({ req: req }); if (!token) { // If no token or invalid token, return unauthorized status return res.status(401).json({ message: "Unauthorized to call this API endpoint" }); } const publisher = await prisma.publisher.findUnique({ where: { email: token.email } }); switch (action) { case "sendCoverMeRequestByEmail": // Send CoverMe request to the users //get from POST data: shiftId, assignmentId, date //let shiftId = req.body.shiftId; let assignmentId = req.body.assignmentId; let toSubscribed = req.body.toSubscribed; let toAvailable = req.body.toAvailable; let assignment = await prisma.assignment.findUnique({ where: { id: parseInt(assignmentId) }, include: { shift: { include: { cartEvent: { include: { location: true } } } } } }); console.log("User: " + publisher.email + " sent a 'CoverMe' request for his assignment " + assignmentId + " - " + assignment.shift.cartEvent.location.name + " " + assignment.shift.startTime.toISOString()); // update the assignment. generate new publicGuid, isConfirmed to false let newPublicGuid = uuidv4(); await prisma.assignment.update({ where: { id: parseInt(assignmentId) }, data: { publicGuid: newPublicGuid, // if this exists, we consider the request open isConfirmed: false } }); let subscribedPublishers = [], availablePublishers = []; if (toSubscribed) { //get all subscribed publisers subscribedPublishers = await prisma.publisher.findMany({ where: { isSubscribedToCoverMe: true } }); } if (toAvailable) { availablePublishers = await data.filterPublishersNew("id,firstName,lastName,email", new Date(assignment.shift.startTime), true, false); } //concat and remove duplicate emails let pubsToSend = subscribedPublishers.concat(availablePublishers). filter((item, index, self) => index === self.findIndex((t) => ( t.email === item.email //and exclude the user himself )) //&& item.email !== publisher.email ); console.log("Sending CoverMe request to " + pubsToSend.length + " publishers"); await prisma.eventLog.create({ data: { date: new Date(), publisher: { connect: { id: publisher.id } }, shift: { connect: { id: assignment.shiftId } }, type: EventLogType.AssignmentReplacementRequested, content: "Заявка за заместване от " + publisher.firstName + " " + publisher.lastName + "до: " + pubsToSend.map(p => p.firstName + " " + p.lastName + "<" + p.email + ">").join(", "), } }); //send email to all subscribed publishers for (let i = 0; i < pubsToSend.length; i++) { //send email to subscribed publisher let acceptUrl = process.env.NEXTAUTH_URL + "/api/email?action=email_response&emailaction=coverMeAccept&userId=" + pubsToSend[i].id + "&shiftId=" + assignment.shiftId + "&assignmentPID=" + newPublicGuid; let model = { user: publisher, shiftId: assignment.shiftId, acceptUrl: acceptUrl, prefix: publisher.isMale ? "Брат" : "Сестра", firstName: pubsToSend[i].firstName, lastName: pubsToSend[i].lastName, email: pubsToSend[i].email, placeName: assignment.shift.cartEvent.location.name, dateStr: common.getDateFormated(assignment.shift.startTime), time: common.formatTimeHHmm(assignment.shift.startTime), sentDate: common.getDateFormated(new Date()) }; let results = emailHelper.SendEmailHandlebars( { name: pubsToSend[i].firstName + " " + pubsToSend[i].lastName, email: pubsToSend[i].email }, "coverMe", model); // if (results) { // console.log("Error sending email: " + error); // return res.status(500).json({ message: "Error sending email:" + error }); //} if (results) { console.log("Email sent to: " + pubsToSend[i].email); } } res.status(200).json({ message: "CoverMe request sent" }); break; default: return res.status(400).json({ message: "Invalid action" }); } return res.status(200).json({ message: "User action processed" }); } } router.use(expressWrapper(handler));