diff --git a/src/emailTemplates/adminDeleteMeeting.html b/src/emailTemplates/adminDeleteMeeting.html new file mode 100644 index 00000000..45c20ff3 --- /dev/null +++ b/src/emailTemplates/adminDeleteMeeting.html @@ -0,0 +1,22 @@ + + +
++ This email is to let you know that a meeting has been removed by + administration. Please contact + clubpub@stuysu.org for + further details. +
+The original meeting details are below.
+Title: {{ meeting.title }}
+Start Date: {{ formattedStart }}
+End Date: {{ formattedEnd }}
+ + {{ renderedDescription | safe }} + ++ You are receiving this message because you are a member of {{ + org.name }}. +
+ + diff --git a/src/graphql/resolvers/Mutation/adminDeleteMeeting.js b/src/graphql/resolvers/Mutation/adminDeleteMeeting.js new file mode 100644 index 00000000..f77d7cb8 --- /dev/null +++ b/src/graphql/resolvers/Mutation/adminDeleteMeeting.js @@ -0,0 +1,95 @@ +import { ApolloError } from 'apollo-server-errors'; +import { deleteCalendarEvent } from '../../../googleApis/calendar'; +import sendEmail from '../../../utils/sendEmail'; +import { Op } from 'sequelize'; +import moment from 'moment-timezone'; + +export default async ( + root, + { meetingId }, + { + adminRoleRequired, + models: { + meetings, + googleCalendarEvents, + googleCalendars, + memberships, + organizations, + users + } + } +) => { + const meeting = await meetings.idLoader.load(meetingId); + + if (!meeting) { + throw new ApolloError( + "There's no meeting with that id", + 'MEETING_NOT_FOUND' + ); + } + + adminRoleRequired('charters'); + + const org = await organizations.idLoader.load(meeting.organizationId); + + let where = {}; + let include = { + model: memberships, + where: { + organizationId: org.id, + updateNotification: { + [Op.not]: false + } + }, + required: true + }; + + const formattedStart = moment(meeting.start) + .tz('America/New_York') + .format('dddd, MMMM Do YYYY, h:mm a'); + + const formattedEnd = moment(meeting.end) + .tz('America/New_York') + .format('dddd, MMMM Do YYYY, h:mm a'); + + let members = await users.findAll({ + where, + include + }); + + await Promise.all( + members.map(async member => { + await sendEmail({ + to: member.email, + subject: `${org.name}'s meeting has been cancelled | StuyActivities`, + template: 'adminDeleteMeeting.html', + variables: { + member, + org, + meeting, + formattedStart, + formattedEnd, + renderedDescription: meeting.description + } + }); + }) + ); + + const meetingCalEvent = await googleCalendarEvents.findOne({ + where: { + meetingId: meetingId, + recurringMeeting: false + } + }); + + const gCal = await googleCalendars.orgIdLoader.load(meeting.organizationId); + + if (meetingCalEvent) { + await deleteCalendarEvent(gCal.gCalId, meetingCalEvent.gCalEventId); + await meetingCalEvent.destroy(); + } + + await meeting.destroy(); + + return true; +}; diff --git a/src/graphql/resolvers/Mutation/index.js b/src/graphql/resolvers/Mutation/index.js index 5f868ace..72dfe59e 100644 --- a/src/graphql/resolvers/Mutation/index.js +++ b/src/graphql/resolvers/Mutation/index.js @@ -1,4 +1,5 @@ import addRoomToMeeting from './addRoomToMeeting'; +import adminDeleteMeeting from './adminDeleteMeeting'; import alterCharter from './alterCharter'; import alterClubFairResponse from './alterClubFairResponse'; import alterEmailSettings from './alterEmailSettings'; @@ -51,6 +52,7 @@ import createUser from './createUser'; export default { linkOAuthPlatform, login, + adminDeleteMeeting, alterCharter, alterClubFairResponse, alterEmailSettings, diff --git a/src/graphql/schema/Mutation.js b/src/graphql/schema/Mutation.js index 31570bc6..16179f76 100644 --- a/src/graphql/schema/Mutation.js +++ b/src/graphql/schema/Mutation.js @@ -177,7 +177,8 @@ export default gql` createPromotedClub(orgId: Int!, blurb: String!): PromotedClub deletePromotedClub(promotedClubId: Int!): Boolean - # --- settings --- + # --- admin --- + adminDeleteMeeting(meetingId: Int!): Boolean alterSettings(membershipRequirement: Int!): Settings # --- users ---