From 2fd15ac7a82bf1e63090a6f3616e49f1e293d9ab Mon Sep 17 00:00:00 2001 From: JacquelineTuyisenge <109481899+JacquelineTuyisenge@users.noreply.github.com> Date: Mon, 7 Oct 2024 14:32:01 +0200 Subject: [PATCH] #340 Send Email to invitees when an Event is updated (#342) --- src/helpers/sendEventEmails.ts | 187 ++++--- src/resolvers/eventResolver.ts | 494 +++++++++++------- src/resolvers/invitation.resolvers.ts | 105 ++-- src/resolvers/ratingsResolvers.ts | 6 +- .../templates/eventInvitationTemplates.ts | 49 +- 5 files changed, 524 insertions(+), 317 deletions(-) diff --git a/src/helpers/sendEventEmails.ts b/src/helpers/sendEventEmails.ts index ed9e48a2..da7c7a14 100644 --- a/src/helpers/sendEventEmails.ts +++ b/src/helpers/sendEventEmails.ts @@ -1,77 +1,128 @@ -import jwt from "jsonwebtoken" -import { sendEmail } from "../utils/sendEmail" -import { eventCancellationTemplate, eventInvitationTemplate, invitationCancellationTemplate } from "../utils/templates/eventInvitationTemplates"; +import jwt from 'jsonwebtoken' +import { sendEmail } from '../utils/sendEmail' +import { + eventCancellationTemplate, + eventUpdateTemplate, + eventInvitationTemplate, + invitationCancellationTemplate, +} from '../utils/templates/eventInvitationTemplates' export async function sendEventInvitations( - email: string, - eventId: string, - eventTitle: string, - hostName: string, - eventStart: string, - eventEnd: string, - eventTimeToStart: string, - eventTimeToEnd: string, -){ - try{ - const secret = process.env.SECRET! - const acceptedEventToken = jwt.sign({ - email, - eventId, - response: "accepted", - },secret) - const declinedEventToken = jwt.sign({ - email, - eventId, - response: "declined", - },secret) - const content: string = eventInvitationTemplate(eventTitle,hostName,eventStart,eventEnd,eventTimeToStart,eventTimeToEnd, acceptedEventToken, declinedEventToken) - await sendEmail( - email, - 'Event Invitation', - content, - null, - process.env.ADMIN_EMAIL, - process.env.ADMIN_PASS, - ) - }catch(err){ - return err - } + email: string, + eventId: string, + eventTitle: string, + hostName: string, + eventStart: string, + eventEnd: string, + eventTimeToStart: string, + eventTimeToEnd: string +) { + try { + const secret = process.env.SECRET! + const acceptedEventToken = jwt.sign( + { + email, + eventId, + response: 'accepted', + }, + secret + ) + const declinedEventToken = jwt.sign( + { + email, + eventId, + response: 'declined', + }, + secret + ) + const content: string = eventInvitationTemplate( + eventTitle, + hostName, + eventStart, + eventEnd, + eventTimeToStart, + eventTimeToEnd, + acceptedEventToken, + declinedEventToken + ) + await sendEmail( + email, + 'Event Invitation', + content, + null, + process.env.ADMIN_EMAIL, + process.env.ADMIN_PASS + ) + } catch (err) { + return err + } +} + +export async function sendEventUpdates( + email: string, + eventTitle: string, + hostName: string, + eventStart: string, + eventEnd: string, + eventTimeToStart: string, + eventTimeToEnd: string +) { + try { + const content: string = eventUpdateTemplate( + eventTitle, + hostName, + eventStart, + eventEnd, + eventTimeToStart, + eventTimeToEnd + ) + await sendEmail( + email, + 'Event Updated', + content, + null, + process.env.ADMIN_EMAIL, + process.env.ADMIN_PASS + ) + } catch (err) { + return err + } } export async function sendEventCancellations( - email: string, - eventTitle: string, -){ - try{ - const content: string = eventCancellationTemplate(eventTitle) - await sendEmail( - email, - 'Event Cancelled', - content, - null, - process.env.ADMIN_EMAIL, - process.env.ADMIN_PASS, - ) - }catch(err){ - return err - } + email: string, + eventTitle: string +) { + try { + const content: string = eventCancellationTemplate(eventTitle) + await sendEmail( + email, + 'Event Cancelled', + content, + null, + process.env.ADMIN_EMAIL, + process.env.ADMIN_PASS + ) + } catch (err) { + return err + } } export async function sendInvitationCancellations( - email: string, - eventTitle: string, -){ - try{ - const content: string = invitationCancellationTemplate(eventTitle) - await sendEmail( - email, - 'Invitation Cancelled', - content, - null, - process.env.ADMIN_EMAIL, - process.env.ADMIN_PASS, - ) - }catch(err){ - return err - } + email: string, + eventTitle: string +) { + try { + const content: string = invitationCancellationTemplate(eventTitle) + await sendEmail( + email, + 'Invitation Cancelled', + content, + null, + process.env.ADMIN_EMAIL, + process.env.ADMIN_PASS + ) + } catch (err) { + return err + } } diff --git a/src/resolvers/eventResolver.ts b/src/resolvers/eventResolver.ts index a4f0a7ed..fed3f813 100644 --- a/src/resolvers/eventResolver.ts +++ b/src/resolvers/eventResolver.ts @@ -1,192 +1,241 @@ /* eslint-disable quotes */ -import { GraphQLError } from 'graphql'; -import jwt from "jsonwebtoken"; -import { decodeAuthHeader } from '../context'; -import { Event } from '../models/event.model'; -import { User } from '../models/user'; -import { checkLoggedInOrganization } from '../helpers/organization.helper'; -import { sendEventCancellations, sendEventInvitations, sendInvitationCancellations } from '../helpers/sendEventEmails'; +import { GraphQLError } from 'graphql' +import jwt from 'jsonwebtoken' +import { decodeAuthHeader } from '../context' +import { Event } from '../models/event.model' +import { User } from '../models/user' +import { checkLoggedInOrganization } from '../helpers/organization.helper' +import { + sendEventCancellations, + sendEventInvitations, + sendEventUpdates, + sendInvitationCancellations, +} from '../helpers/sendEventEmails' enum INVITEE_STATUS { - PENDING = "pending", - ACCEPTED = "accepted", - DECLINED = "declined", + PENDING = 'pending', + ACCEPTED = 'accepted', + DECLINED = 'declined', } type EventResponse = { - email: string, - eventId: string, - response: "accepted" | "declined" + email: string + eventId: string + response: 'accepted' | 'declined' } -const validateDates = (start: string, end: string): string | null=>{ +const validateDates = (start: string, end: string): string | null => { const startDate = new Date(start) const endDate = new Date(end) - const dateRegex = /^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])T([01]\d|2[0-3]):(00|[0-5]\d):(00|[0-5]\d).\d{3}Z$/ + const dateRegex = + /^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])T([01]\d|2[0-3]):(00|[0-5]\d):(00|[0-5]\d).\d{3}Z$/ - if(!dateRegex.test(start)) return "Invalid start date" - if(!dateRegex.test(end)) return "Invalid end date" - if(startDate > endDate) return "Event should start before it ends" + if (!dateRegex.test(start)) return 'Invalid start date' + if (!dateRegex.test(end)) return 'Invalid end date' + if (startDate > endDate) return 'Event should start before it ends' return null } -const validateTime = (timeToStart: string, timeToEnd: string): string | null=>{ +const validateTime = ( + timeToStart: string, + timeToEnd: string +): string | null => { const timeToStartArr = timeToStart.split(':') const timeToEndArr = timeToEnd.split(':') const timeRegex = /^([01]\d|2[0-3]):([0-5]\d)$/ - if(!timeRegex.test(timeToStart)) return 'Invalid start time' - if(!timeRegex.test(timeToEnd)) return 'Invalid end time' - if(parseInt(timeToStartArr[0]) > parseInt(timeToEndArr[0])) return "Event should start before it ends" + if (!timeRegex.test(timeToStart)) return 'Invalid start time' + if (!timeRegex.test(timeToEnd)) return 'Invalid end time' + if (parseInt(timeToStartArr[0]) > parseInt(timeToEndArr[0])) + return 'Event should start before it ends' - if(parseInt(timeToStartArr[0]) === parseInt(timeToEndArr[0])){ - if(parseInt(timeToStartArr[1]) > parseInt(timeToEndArr[1])) return "Event should start before it ends" + if (parseInt(timeToStartArr[0]) === parseInt(timeToEndArr[0])) { + if (parseInt(timeToStartArr[1]) > parseInt(timeToEndArr[1])) + return 'Event should start before it ends' } return null } -const decodeEventResponseToken = (token: string)=>{ - try{ +const decodeEventResponseToken = (token: string) => { + try { return jwt.verify(token, process.env.SECRET!) as EventResponse - }catch(err: any){ - throw new GraphQLError("Invalid Token",{ - extensions:{ - code: "INVALID_EVENT_TOKEN" - } + } catch (err: any) { + throw new GraphQLError('Invalid Token', { + extensions: { + code: 'INVALID_EVENT_TOKEN', + }, }) } } - const eventResolvers: any = { Query: { getEvents: async (_: any, { authToken }: { authToken: string }) => { - const { userId } = decodeAuthHeader(authToken); + const { userId } = decodeAuthHeader(authToken) const user = await User.findById(userId) - if(!user){ - throw new GraphQLError("No such user found", { + if (!user) { + throw new GraphQLError('No such user found', { extensions: { - code: "USER_NOT_FOUND" - } + code: 'USER_NOT_FOUND', + }, }) } //get all events that belong to the user along with events they accepted - return await Event.find({ $or :[{ user: userId }, { invitees: {$elemMatch: { email: user.email, status: INVITEE_STATUS.ACCEPTED }}}]}); + return await Event.find({ + $or: [ + { user: userId }, + { + invitees: { + $elemMatch: { + email: user.email, + status: INVITEE_STATUS.ACCEPTED, + }, + }, + }, + ], + }) }, getAcceptedEvents: async (_: any, { authToken }: { authToken: string }) => { - const { userId } = decodeAuthHeader(authToken); + const { userId } = decodeAuthHeader(authToken) const user = await User.findById(userId) if (!user) { - throw new GraphQLError("No such user found", { + throw new GraphQLError('No such user found', { extensions: { - code: "USER_NOT_FOUND" - } + code: 'USER_NOT_FOUND', + }, }) } - const events = await Event.find({ invitees: { $elemMatch: { email: user.email, status: INVITEE_STATUS.ACCEPTED } } }) - return events; + const events = await Event.find({ + invitees: { + $elemMatch: { email: user.email, status: INVITEE_STATUS.ACCEPTED }, + }, + }) + return events }, - getEvent: async (_: any, { eventId, authToken }: { eventId: string, authToken: string }) => { - const { userId } = decodeAuthHeader(authToken); + getEvent: async ( + _: any, + { eventId, authToken }: { eventId: string; authToken: string } + ) => { + const { userId } = decodeAuthHeader(authToken) const user = await User.findById(userId) if (!user) { - throw new GraphQLError("No such user found", { + throw new GraphQLError('No such user found', { extensions: { - code: "USER_NOT_FOUND" - } + code: 'USER_NOT_FOUND', + }, }) } const event = await Event.findById(eventId) - if(!event){ - throw new GraphQLError("No such event found",{ + if (!event) { + throw new GraphQLError('No such event found', { extensions: { - code: "EVENT_NOT_FOUND" - } + code: 'EVENT_NOT_FOUND', + }, }) } - return event; + return event }, }, Mutation: { async createEvent( _: any, - { title, hostName, start, end, timeToStart, timeToEnd, authToken, orgToken, invitees = [] }: any + { + title, + hostName, + start, + end, + timeToStart, + timeToEnd, + authToken, + orgToken, + invitees = [], + }: any ) { - const decoded = decodeAuthHeader(authToken); + const decoded = decodeAuthHeader(authToken) const user = await User.findById(decoded.userId) if (!user) { - throw new GraphQLError("No such user found", { + throw new GraphQLError('No such user found', { extensions: { - code: "USER_NOT_FOUND" - } + code: 'USER_NOT_FOUND', + }, }) } - if (user.role === "trainee"){ - throw new GraphQLError("User not authorized",{ + if (user.role === 'trainee') { + throw new GraphQLError('User not authorized', { extensions: { - code: "FORBIDDEN" - } + code: 'FORBIDDEN', + }, }) } - const dateErrorMsg = validateDates(start,end) - if(dateErrorMsg){ - throw new GraphQLError(dateErrorMsg,{ + const dateErrorMsg = validateDates(start, end) + if (dateErrorMsg) { + throw new GraphQLError(dateErrorMsg, { extensions: { - code: "BAD_REQUEST" - } + code: 'BAD_REQUEST', + }, }) } - const timeErrorMsg = validateTime(timeToStart,timeToEnd) - if(timeErrorMsg){ - throw new GraphQLError(timeErrorMsg,{ + const timeErrorMsg = validateTime(timeToStart, timeToEnd) + if (timeErrorMsg) { + throw new GraphQLError(timeErrorMsg, { extensions: { - code: "BAD_REQUEST" - } + code: 'BAD_REQUEST', + }, }) } const org = await checkLoggedInOrganization(orgToken) if (!org) { throw new GraphQLError('Invalid organization token', { extensions: { - code: "FORBIDDEN" - } + code: 'FORBIDDEN', + }, }) } //add the person who invited - invitees = [ - user.email, - ...invitees - ] + invitees = [user.email, ...invitees] //check for non-existing users and users that do not belong to the organization - const validUsers = await User.find({ email: { $in: invitees }, organizations: { $in: [org.name] } }) - const validEmails = validUsers.map((user)=>user.email) - const invalidEmails = invitees.filter((email: string)=> !validEmails.includes(email)) + const validUsers = await User.find({ + email: { $in: invitees }, + organizations: { $in: [org.name] }, + }) + const validEmails = validUsers.map((user) => user.email) + const invalidEmails = invitees.filter( + (email: string) => !validEmails.includes(email) + ) if (invalidEmails.length) { - throw new GraphQLError(`Invitees contain invalid users ${invalidEmails.toString()}`, { - extensions: { - code: "FORBIDDEN" + throw new GraphQLError( + `Invitees contain invalid users ${invalidEmails.toString()}`, + { + extensions: { + code: 'FORBIDDEN', + }, } - }) + ) } - const duplicates = invitees.filter((email: string,index: number)=> invitees.indexOf(email) !== index) + const duplicates = invitees.filter( + (email: string, index: number) => invitees.indexOf(email) !== index + ) if (duplicates.length) { - throw new GraphQLError(`Invitees contain duplicated users ${duplicates.toString()}`, { - extensions: { - code: "FORBIDDEN" + throw new GraphQLError( + `Invitees contain duplicated users ${duplicates.toString()}`, + { + extensions: { + code: 'FORBIDDEN', + }, } - }) + ) } const inviteeArray = invitees.map((email: string) => { return { email: email, - status: INVITEE_STATUS.PENDING + status: INVITEE_STATUS.PENDING, } }) @@ -200,106 +249,142 @@ const eventResolvers: any = { end, timeToStart, timeToEnd, - invitees: inviteeArray - }); + invitees: inviteeArray, + }) - event.invitees.forEach(async invitee => { - await sendEventInvitations(invitee.email, event.id, event.title, event.hostName, event.start, event.end, event.timeToStart, event.timeToEnd) + event.invitees.forEach(async (invitee) => { + await sendEventInvitations( + invitee.email, + event.id, + event.title, + event.hostName, + event.start, + event.end, + event.timeToStart, + event.timeToEnd + ) }) - return event; + return event }, - //fix editEvent async editEvent( _: any, - { eventId, title, hostName, start, end, timeToStart, timeToEnd, authToken, orgToken, invitees = [] }: any + { + eventId, + title, + hostName, + start, + end, + timeToStart, + timeToEnd, + authToken, + orgToken, + invitees = [], + }: any ) { - const decoded = decodeAuthHeader(authToken); + const decoded = decodeAuthHeader(authToken) const user = await User.findById(decoded.userId) if (!user) { - throw new GraphQLError("No such user found", { + throw new GraphQLError('No such user found', { extensions: { - code: "USER_NOT_FOUND" - } + code: 'USER_NOT_FOUND', + }, }) } - if (user.role === "trainee"){ - throw new GraphQLError("User not authorized",{ + if (user.role === 'trainee') { + throw new GraphQLError('User not authorized', { extensions: { - code: "FORBIDDEN" - } + code: 'FORBIDDEN', + }, }) } - const dateErrorMsg = validateDates(start,end) - if(dateErrorMsg){ - throw new GraphQLError(dateErrorMsg,{ + const dateErrorMsg = validateDates(start, end) + if (dateErrorMsg) { + throw new GraphQLError(dateErrorMsg, { extensions: { - code: "BAD_REQUEST" - } + code: 'BAD_REQUEST', + }, }) } - const timeErrMsg = validateTime(timeToStart,timeToEnd) - if(timeErrMsg){ - throw new GraphQLError(timeErrMsg,{ + const timeErrMsg = validateTime(timeToStart, timeToEnd) + if (timeErrMsg) { + throw new GraphQLError(timeErrMsg, { extensions: { - code: "BAD_REQUEST" - } + code: 'BAD_REQUEST', + }, }) } const org = await checkLoggedInOrganization(orgToken) if (!org) { throw new GraphQLError('Invalid organization token', { extensions: { - code: "FORBIDDEN" - } + code: 'FORBIDDEN', + }, }) } const event = await Event.findById(eventId) if (!event) { - throw new GraphQLError("No such event found", { + throw new GraphQLError('No such event found', { extensions: { - code: "EVENT_NOT_FOUND" - } + code: 'EVENT_NOT_FOUND', + }, }) } - if(event.user.toString() !== user._id.toString()){ - throw new GraphQLError("User not authorized",{ + if (event.user.toString() !== user._id.toString()) { + throw new GraphQLError('User not authorized', { extensions: { - code: "FORBIDDEN" - } + code: 'FORBIDDEN', + }, }) } //check for non-existing users and users that do not belong to the organization - const validUsers = await User.find({ email: { $in: invitees }, organizations: { $in: [org.name] } }) - const validEmails = validUsers.map((user)=>user.email) - const invalidEmails = invitees.filter((email: string)=> !validEmails.includes(email)) + const validUsers = await User.find({ + email: { $in: invitees }, + organizations: { $in: [org.name] }, + }) + const validEmails = validUsers.map((user) => user.email) + const invalidEmails = invitees.filter( + (email: string) => !validEmails.includes(email) + ) if (invalidEmails.length) { - throw new GraphQLError(`Invitees contain invalid users ${invalidEmails.toString()}`, { - extensions: { - code: "FORBIDDEN" + throw new GraphQLError( + `Invitees contain invalid users ${invalidEmails.toString()}`, + { + extensions: { + code: 'FORBIDDEN', + }, } - }) + ) } - const duplicates = invitees.filter((email: string,index: number)=> invitees.indexOf(email) !== index) + const duplicates = invitees.filter( + (email: string, index: number) => invitees.indexOf(email) !== index + ) if (duplicates.length) { - throw new GraphQLError(`Invitees contain duplicated users ${duplicates.toString()}`, { - extensions: { - code: "FORBIDDEN" + throw new GraphQLError( + `Invitees contain duplicated users ${duplicates.toString()}`, + { + extensions: { + code: 'FORBIDDEN', + }, } - }) + ) } - const oldInvitees = event.invitees.map(invitee => { + const oldInvitees = event.invitees.map((invitee) => { return invitee.email }) - const newInvitees = invitees.filter((email: string) => !oldInvitees.includes(email)) - const excludedInvitees = oldInvitees.slice(1).filter((email: string) => !invitees.includes(email)) + const newInvitees = invitees.filter( + (email: string) => !oldInvitees.includes(email) + ) + const excludedInvitees = oldInvitees + .slice(1) + .filter((email: string) => !invitees.includes(email)) event.title = title event.hostName = hostName @@ -308,20 +393,32 @@ const eventResolvers: any = { event.timeToStart = timeToStart event.timeToEnd = timeToEnd - event.invitees.push(...newInvitees.map((email: string) => { - return { - email: email, - status: INVITEE_STATUS.PENDING - } - }) + event.invitees.push( + ...newInvitees.map((email: string) => { + return { + email: email, + status: INVITEE_STATUS.PENDING, + } + }) ) - event.invitees = event.invitees.filter(invitee => !excludedInvitees.includes(invitee.email)) + event.invitees = event.invitees.filter( + (invitee) => !excludedInvitees.includes(invitee.email) + ) await event.save() if (newInvitees.length) { newInvitees.forEach(async (email: string) => { - await sendEventInvitations(email, event.id, event.title, event.hostName, event.start, event.end, event.timeToStart, event.timeToEnd) + await sendEventInvitations( + email, + event.id, + event.title, + event.hostName, + event.start, + event.end, + event.timeToStart, + event.timeToEnd + ) }) } @@ -331,93 +428,104 @@ const eventResolvers: any = { }) } - return event; + const inviteesToUpdate = event.invitees.map((invitee) => invitee.email) + inviteesToUpdate.forEach(async (email: string) => { + await sendEventUpdates( + email, + event.title, + event.hostName, + event.start, + event.end, + event.timeToStart, + event.timeToEnd + ) + }) + return event }, - async cancelEvent( - _: any, - { eventId, authToken }: any - ) { - const decoded = decodeAuthHeader(authToken); + async cancelEvent(_: any, { eventId, authToken }: any) { + const decoded = decodeAuthHeader(authToken) const user = await User.findById(decoded.userId) - if (!user){ - throw new GraphQLError("User not found",{ + if (!user) { + throw new GraphQLError('User not found', { extensions: { - code: "USER_NOT_FOUND" - } + code: 'USER_NOT_FOUND', + }, }) } - if(user.role === "trainee"){ - throw new GraphQLError("User not authorized",{ + if (user.role === 'trainee') { + throw new GraphQLError('User not authorized', { extensions: { - code: "FORBIDDEN" - } + code: 'FORBIDDEN', + }, }) } - const event = await Event.findById(eventId); + const event = await Event.findById(eventId) if (!event) { - throw new GraphQLError("No such event found", { + throw new GraphQLError('No such event found', { extensions: { - code: "EVENT_NOT_FOUND" - } + code: 'EVENT_NOT_FOUND', + }, }) } - if(event.user.toString() !== user._id.toString()){ - throw new GraphQLError("User not authorized",{ - extensions:{ - code: "FORBIDDEN" - } + if (event.user.toString() !== user._id.toString()) { + throw new GraphQLError('User not authorized', { + extensions: { + code: 'FORBIDDEN', + }, }) } await Event.findByIdAndDelete(eventId) - event.invitees.forEach(async invitee => { + event.invitees.forEach(async (invitee) => { await sendEventCancellations(invitee.email, event.title) }) - return event; + return event }, async respondToEventInvitation( _: any, - { eventToken, authToken }: { eventToken: string, authToken: string }) { + { eventToken, authToken }: { eventToken: string; authToken: string } + ) { const { userId } = decodeAuthHeader(authToken) const { email, eventId, response } = decodeEventResponseToken(eventToken) const user = await User.findById(userId) if (!user) { - throw new GraphQLError("No such user found", { + throw new GraphQLError('No such user found', { extensions: { - code: "USER_NOT_FOUND" - } + code: 'USER_NOT_FOUND', + }, }) } - if(user.email!==email){ - throw new GraphQLError("Invalid Token", { + if (user.email !== email) { + throw new GraphQLError('Invalid Token', { extensions: { - code: "INVALID_EVENT_TOKEN" - } + code: 'INVALID_EVENT_TOKEN', + }, }) } const event = await Event.findById(eventId) if (!event) { - throw new GraphQLError("No such event found", { + throw new GraphQLError('No such event found', { extensions: { - code: "EVENT_NOT_FOUND" - } + code: 'EVENT_NOT_FOUND', + }, }) } - const existingInvitee = event.invitees.find(invitee => invitee.email === user.email) + const existingInvitee = event.invitees.find( + (invitee) => invitee.email === user.email + ) if (!existingInvitee) { - throw new GraphQLError("No such event invitee found", { + throw new GraphQLError('No such event invitee found', { extensions: { - code: "INVITEE_NOT_FOUND" - } + code: 'INVITEE_NOT_FOUND', + }, }) } existingInvitee.status = response await event.save() return event - } - + }, }, -}; -export default eventResolvers; +} +export default eventResolvers diff --git a/src/resolvers/invitation.resolvers.ts b/src/resolvers/invitation.resolvers.ts index cec36a8d..7f296314 100644 --- a/src/resolvers/invitation.resolvers.ts +++ b/src/resolvers/invitation.resolvers.ts @@ -33,7 +33,11 @@ const invitationResolvers: IResolvers = { invitees, orgToken, orgName, - }: { invitees: { email: string; role: string }[]; orgName: string; orgToken: string }, + }: { + invitees: { email: string; role: string }[] + orgName: string + orgToken: string + }, context ) => { try { @@ -166,7 +170,11 @@ const invitationResolvers: IResolvers = { async uploadInvitationFile( _: any, - { file,orgName, orgToken }: { file: any;orgName: string, orgToken: string }, + { + file, + orgName, + orgToken, + }: { file: any; orgName: string; orgToken: string }, context: any ) { const { userId } = (await checkUserLoggedIn(context))(['admin']) @@ -365,64 +373,71 @@ const invitationResolvers: IResolvers = { return { message: 'Invitation deleted successfully ' } }, - resendInvitation:async(_:any,{invitationId,orgToken}:{invitationId:string,orgToken:string},context:any)=>{ - + resendInvitation: async ( + _: any, + { invitationId, orgToken }: { invitationId: string; orgToken: string }, + context: any + ) => { try { - const {userId}= (await checkUserLoggedIn(context))(['admin']); - if(!userId){ - throw new GraphQLError('User not logged In',{ - extensions:{ - code:'UNAUTHENTICATED' - } + const { userId } = (await checkUserLoggedIn(context))(['admin']) + if (!userId) { + throw new GraphQLError('User not logged In', { + extensions: { + code: 'UNAUTHENTICATED', + }, }) } - const org=await checkLoggedInOrganization(orgToken); - if(!org){ - throw new GraphQLError('Organization not logged In',{ - extensions:{ - code:'UNAUTHENTICATED' - } + const org = await checkLoggedInOrganization(orgToken) + if (!org) { + throw new GraphQLError('Organization not logged In', { + extensions: { + code: 'UNAUTHENTICATED', + }, }) } - const invitation= await Invitation.findOne({_id:invitationId,status:'pending',orgName:org.name.toLocaleLowerCase()}); - + const invitation = await Invitation.findOne({ + _id: invitationId, + status: 'pending', + orgName: org.name.toLocaleLowerCase(), + }) - if(!invitation){ - throw new GraphQLError('Invitation with the given id does not exists',{ - extensions:{ - code:'INVALID_INPUT' + if (!invitation) { + throw new GraphQLError( + 'Invitation with the given id does not exists', + { + extensions: { + code: 'INVALID_INPUT', + }, } - }) + ) } - const{invitees,orgName}=invitation; - - for( let invitee of invitees){ - const {newToken,link}= await generateInvitationTokenAndLink(invitee?.email as string, invitee.role,orgName); - invitation.createdAt=new Date(); - invitation.invitationToken=newToken; - await sendInvitationEmail(invitee?.email as string, org.name, link); - await invitation.save(); + const { invitees, orgName } = invitation + + for (const invitee of invitees) { + const { newToken, link } = await generateInvitationTokenAndLink( + invitee?.email as string, + invitee.role, + orgName + ) + invitation.createdAt = new Date() + invitation.invitationToken = newToken + await sendInvitationEmail(invitee?.email as string, org.name, link) + await invitation.save() } - return { - success:true, - message:"Invitation was resent successfully" + success: true, + message: 'Invitation was resent successfully', } - - } catch (error:any) { - - throw new GraphQLError(error.message,{ - extensions:{ - code:'INTERNAL_SERVER_ERROR' - } + } catch (error: any) { + throw new GraphQLError(error.message, { + extensions: { + code: 'INTERNAL_SERVER_ERROR', + }, }) - - } - - } + }, }, } diff --git a/src/resolvers/ratingsResolvers.ts b/src/resolvers/ratingsResolvers.ts index f7895b84..3b61777f 100644 --- a/src/resolvers/ratingsResolvers.ts +++ b/src/resolvers/ratingsResolvers.ts @@ -206,9 +206,9 @@ const ratingResolvers: any = { if (!userExists) throw new Error('User does not exist!') if (userExists.status?.status === 'drop') { - throw new Error('The trainee is dropped'); - } - + throw new Error('The trainee is dropped') + } + const Kohort = await Cohort.findOne({ _id: cohort }) const Phase = await Cohort.findOne({ _id: cohort }).populate( 'phase', diff --git a/src/utils/templates/eventInvitationTemplates.ts b/src/utils/templates/eventInvitationTemplates.ts index e7625fa1..15414139 100644 --- a/src/utils/templates/eventInvitationTemplates.ts +++ b/src/utils/templates/eventInvitationTemplates.ts @@ -1,4 +1,4 @@ -import { format } from "date-fns" +import { format } from 'date-fns' export function eventInvitationTemplate( eventTitle: string, @@ -9,7 +9,7 @@ export function eventInvitationTemplate( eventTimeToEnd: string, acceptedEventToken: string, declinedEventToken: string -):string { +): string { const acceptedResponseLink = `${process.env.FRONTEND_LINK}/calendar/confirm?eventToken=${acceptedEventToken}` const declinedResponseLink = `${process.env.FRONTEND_LINK}/calendar/confirm?eventToken=${declinedEventToken}` return ` @@ -20,7 +20,10 @@ export function eventInvitationTemplate(

Hello,

- You have been invited to an event ${eventTitle} hosted by ${hostName} that will occur from ${format(new Date(eventStart),"yyyy-MM-dd")} to ${format(new Date(eventEnd),"yyyy-MM-dd")}. + You have been invited to an event ${eventTitle} hosted by ${hostName} that will occur from ${format( + new Date(eventStart), + 'yyyy-MM-dd' + )} to ${format(new Date(eventEnd), 'yyyy-MM-dd')}. This event will take place daily from ${eventTimeToStart} to ${eventTimeToEnd}. We look forward to your participation.

@@ -45,9 +48,41 @@ export function eventInvitationTemplate( ` } -export function eventCancellationTemplate( +export function eventUpdateTemplate( eventTitle: string, -):string { + hostName: string, + eventStart: string, + eventEnd: string, + eventTimeToStart: string, + eventTimeToEnd: string +): string { + return ` + + + + + + +
+

Hello,

+ +

+ The Event has been updated to ${eventTitle} hosted by ${hostName}. It will occur from ${format( + new Date(eventStart), + 'yyyy-MM-dd' + )} to ${format(new Date(eventEnd), 'yyyy-MM-dd')}. + The event will take place daily from ${eventTimeToStart} to ${eventTimeToEnd}. Thank you for your understanding +

+

+ If you think this email reached your inbox by mistake, simply ignore it. +

+ +

Best Regards,

+

Pulse Team

+
` +} + +export function eventCancellationTemplate(eventTitle: string): string { return ` @@ -65,9 +100,7 @@ export function eventCancellationTemplate(
` } -export function invitationCancellationTemplate( - eventTitle: string, -):string { +export function invitationCancellationTemplate(eventTitle: string): string { return `