Skip to content

Commit

Permalink
Improve group deletion
Browse files Browse the repository at this point in the history
  • Loading branch information
lowercasename committed Jun 14, 2024
1 parent 1b50e3c commit c21ffff
Show file tree
Hide file tree
Showing 6 changed files with 142 additions and 132 deletions.
1 change: 1 addition & 0 deletions src/lib/email.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ type EmailTemplate =
| "createEventGroup"
| "createEventMagicLink"
| "deleteEvent"
| "deleteGroup"
| "editEvent"
| "eventGroupUpdated"
| "subscribed"
Expand Down
131 changes: 1 addition & 130 deletions src/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -189,136 +189,6 @@ schedule.scheduleJob("59 23 * * *", function (fireDate) {

// BACKEND ROUTES

router.post("/deleteeventgroup/:eventGroupID/:editToken", (req, res) => {
let submittedEditToken = req.params.editToken;
EventGroup.findOne({
id: req.params.eventGroupID,
})
.then(async (eventGroup) => {
if (eventGroup.editToken === submittedEditToken) {
// Token matches

let linkedEvents = await Event.find({
eventGroup: eventGroup._id,
});

let linkedEventIDs = linkedEvents.map((event) => event._id);
let eventGroupImage = false;
if (eventGroup.image) {
eventGroupImage = eventGroup.image;
}

EventGroup.deleteOne(
{ id: req.params.eventGroupID },
function (err, raw) {
if (err) {
res.send(err);
addToLog(
"deleteEventGroup",
"error",
"Attempt to delete event group " +
req.params.eventGroupID +
" failed with error: " +
err,
);
}
},
)
.then(() => {
// Delete image
if (eventGroupImage) {
fs.unlink(
path.join(
process.cwd(),
"/public/events/" + eventGroupImage,
),
(err) => {
if (err) {
res.send(err);
addToLog(
"deleteEventGroup",
"error",
"Attempt to delete event image for event group " +
req.params.eventGroupID +
" failed with error: " +
err,
);
}
},
);
}
Event.updateOne(
{ _id: { $in: linkedEventIDs } },
{ $set: { eventGroup: null } },
{ multi: true },
)
.then((response) => {
addToLog(
"deleteEventGroup",
"success",
"Event group " +
req.params.eventGroupID +
" deleted",
);
res.writeHead(302, {
Location: "/",
});
res.end();
})
.catch((err) => {
res.send(
"Sorry! Something went wrong (error deleting): " +
err,
);
addToLog(
"deleteEventGroup",
"error",
"Attempt to delete event group " +
req.params.eventGroupID +
" failed with error: " +
err,
);
});
})
.catch((err) => {
res.send(
"Sorry! Something went wrong (error deleting): " +
err,
);
addToLog(
"deleteEventGroup",
"error",
"Attempt to delete event group " +
req.params.eventGroupID +
" failed with error: " +
err,
);
});
} else {
// Token doesn't match
res.send("Sorry! Something went wrong");
addToLog(
"deleteEventGroup",
"error",
"Attempt to delete event group " +
req.params.eventGroupID +
" failed with error: token does not match",
);
}
})
.catch((err) => {
res.send("Sorry! Something went wrong: " + err);
addToLog(
"deleteEventGroup",
"error",
"Attempt to delete event group " +
req.params.eventGroupID +
" failed with error: " +
err,
);
});
});

router.post("/attendee/provision", async (req, res) => {
const removalPassword = niceware.generatePassphrase(6).join("-");
const newAttendee = {
Expand Down Expand Up @@ -655,6 +525,7 @@ router.post("/removeattendee/:eventID/:attendeeID", (req, res) => {
/*
* Create an email subscription on an event group.
*/
// TODO: Prevent subscribing more than once with the same email
router.post("/subscribe/:eventGroupID", (req, res) => {
const subscriber = {
email: req.body.emailAddress,
Expand Down
124 changes: 124 additions & 0 deletions src/routes/group.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import { Router, Response, Request } from "express";
import fs from "fs";
import path from "path";
import multer from "multer";
import { generateEditToken, generateEventID } from "../util/generator.js";
import { validateGroupData } from "../util/validation.js";
import Jimp from "jimp";
import { addToLog } from "../helpers.js";
import EventGroup from "../models/EventGroup.js";
import Event from "../models/Event.js";
import { sendEmailFromTemplate } from "../lib/email.js";
import { marked } from "marked";
import { renderPlain } from "../util/markdown.js";
Expand Down Expand Up @@ -311,4 +314,125 @@ router.post(
},
);

router.delete(
"/group/:eventGroupID/:editToken",
async (req: Request, res: Response) => {
try {
const submittedEditToken = req.params.editToken;

const eventGroup = await EventGroup.findOne({
id: req.params.eventGroupID,
});
if (!eventGroup) {
addToLog(
"deleteEventGroup",
"error",
`Event group ${req.params.eventGroupID} not found`,
);
return res.status(404).json({
errors: [
{
message: "Event group not found.",
},
],
});
}

if (eventGroup.editToken !== submittedEditToken) {
// Token doesn't match
addToLog(
"deleteEventGroup",
"error",
`Attempt to delete event group ${req.params.eventGroupID} failed with error: token does not match`,
);
return res.status(403).json({
errors: [
{
message: "Edit token is invalid.",
},
],
});
}

// Token matches

const linkedEvents = await Event.find({
eventGroup: eventGroup._id,
});
const linkedEventIDs = linkedEvents.map((event) => event._id);

// Delete the event group
await EventGroup.deleteOne({ id: req.params.eventGroupID });

// Delete image if it exists
if (eventGroup.image) {
try {
await fs.promises.unlink(
path.join(
process.cwd(),
"/public/events/",
eventGroup.image,
),
);
} catch (err) {
res.send(err);
addToLog(
"deleteEventGroup",
"error",
`Attempt to delete event image for event group ${req.params.eventGroupID} failed with error: ${err}`,
);
return;
}
}

// Update linked events
await Event.updateMany(
{ _id: { $in: linkedEventIDs } },
{ $set: { eventGroup: null } },
);

addToLog(
"deleteEventGroup",
"success",
`Event group ${req.params.eventGroupID} deleted`,
);

if (eventGroup.subscribers && req.app.locals.sendEmails) {
const subscriberEmails = eventGroup.subscribers.map(
(o) => o.email,
) as string[];

if (subscriberEmails) {
for (const subscriberEmail of subscriberEmails) {
sendEmailFromTemplate(
subscriberEmail,
`${eventGroup.name} was deleted`,
"deleteGroup",
{
groupName: eventGroup.name,
},
req,
);
}
}
}

res.sendStatus(200);
} catch (err) {
addToLog(
"deleteEventGroup",
"error",
`Attempt to delete event group ${req.params.eventGroupID} failed with error: ${err}`,
);
return res.status(500).json({
errors: [
{
message: err,
},
],
});
}
},
);

export default router;
4 changes: 4 additions & 0 deletions views/emails/deleteGroup/deleteGroupHtml.handlebars
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<p style="font-family: sans-serif; font-size: 14px; font-weight: normal; margin: 0; margin-bottom: 15px;">The group '{{groupName}}' you're following on {{siteName}} has been deleted by its creator.</p>
<hr/>
<p style="font-family: sans-serif; font-size: 14px; font-weight: normal; margin: 0; margin-bottom: 15px;"><strong>Hold up - I have no idea what this email is about!</strong></p>
<p style="font-family: sans-serif; font-size: 14px; font-weight: normal; margin: 0; margin-bottom: 15px;">If you didn't follow this group on {{siteName}}, someone may have accidentally typed your email instead of theirs. Don't worry - that group, and your email, is deleted from the system now.</p>
3 changes: 3 additions & 0 deletions views/emails/deleteGroup/deleteGroupText.handlebars
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
The group '{{groupName}}' you're following on {{siteName}} has been deleted by its creator.

If you didn't follow this group on {{siteName}}, someone may have accidentally typed your email instead of theirs. Don't worry - that group, and your email, is deleted from the system now.
11 changes: 9 additions & 2 deletions views/eventgroup.handlebars
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@
{{#if editingEnabled}}
{{> editeventgroupmodal }}

<div class="modal fade" id="deleteModal" tabindex="-1" role="dialog" aria-labelledby="deleteModalLabel" aria-hidden="true">
<div class="modal fade" id="deleteModal" tabindex="-1" role="dialog" aria-labelledby="deleteModalLabel" aria-hidden="true" x-data="{}">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
Expand All @@ -139,7 +139,14 @@
<span aria-hidden="true">&times;</span>
</button>
</div>
<form id="deleteEventGroupForm" action="/deleteeventgroup/{{eventGroupData.id}}/{{eventGroupData.editToken}}" method="post">
<form
id="deleteEventGroupForm"
x-on:submit.prevent="
fetch('/group/{{eventGroupData.id}}/{{eventGroupData.editToken}}', { method: 'DELETE' })
.then(response => response.ok ? window.location.href = '/' : response.json())
.then(data => console.log(data))
"
>
<div class="modal-body">
<p>Are you sure you want to delete this event group? This action cannot be undone.</p>
<p>This will <strong>not</strong> delete the individual events contained in this group. They can be linked to another group later.</p>
Expand Down

0 comments on commit c21ffff

Please sign in to comment.