diff options
Diffstat (limited to 'src')
-rwxr-xr-x | src/routes.js | 2 | ||||
-rw-r--r-- | src/routes/event.ts | 42 | ||||
-rw-r--r-- | src/routes/frontend.ts | 2 | ||||
-rw-r--r-- | src/util/generator.ts | 3 | ||||
-rw-r--r-- | src/util/messages.ts | 9 |
5 files changed, 58 insertions, 0 deletions
diff --git a/src/routes.js b/src/routes.js index 3d6902f..2cbec4f 100755 --- a/src/routes.js +++ b/src/routes.js @@ -23,6 +23,7 @@ import Event from "./models/Event.js"; import EventGroup from "./models/EventGroup.js"; import path from "path"; import { activityPubContentType } from "./lib/activitypub.js"; +import { hashString } from "./util/generator.js"; const config = getConfig(); const domain = config.general.domain; @@ -713,6 +714,7 @@ router.post("/attendevent/:eventID", async (req, res) => { siteLogo, domain, removalPassword: req.body.removalPassword, + removalPasswordHash: hashString(req.body.removalPassword), cache: true, layout: "email.handlebars", }, diff --git a/src/routes/event.ts b/src/routes/event.ts index 3595e0a..1b79f12 100644 --- a/src/routes/event.ts +++ b/src/routes/event.ts @@ -6,6 +6,7 @@ import { generateEditToken, generateEventID, generateRSAKeypair, + hashString, } from "../util/generator.js"; import { validateEventData } from "../util/validation.js"; import { addToLog } from "../helpers.js"; @@ -712,4 +713,45 @@ router.delete( }, ); +// Used to one-click unattend an event from an email. +router.get( + "/event/:eventID/unattend/:removalPasswordHash", + async (req: Request, res: Response) => { + // Find the attendee by the unattendPasswordHash + const event = await Event.findOne({ id: req.params.eventID }); + if (!event) { + return res.redirect("/404"); + } + const attendee = event.attendees?.find( + (o) => + hashString(o.removalPassword || "") === + req.params.removalPasswordHash, + ); + if (!attendee) { + return res.redirect(`/${req.params.eventID}`); + } + // Remove the attendee from the event + event.attendees = event.attendees?.filter( + (o) => o.removalPassword !== attendee.removalPassword, + ); + await event.save(); + // Send email to the attendee + if (req.app.locals.sendEmails && attendee.email) { + sendEmailFromTemplate( + attendee.email, + `You have been removed from ${event.name}`, + "unattendEvent", + { + event, + siteName: res.locals.config?.general.site_name, + siteLogo: res.locals.config?.general.email_logo_url, + domain: res.locals.config?.general.domain, + }, + req, + ); + } + return res.redirect(`/${req.params.eventID}?m=unattend`); + }, +); + export default router; diff --git a/src/routes/frontend.ts b/src/routes/frontend.ts index 58128a0..4d977d7 100644 --- a/src/routes/frontend.ts +++ b/src/routes/frontend.ts @@ -12,6 +12,7 @@ import { } from "../lib/activitypub.js"; import MagicLink from "../models/MagicLink.js"; import { getConfigMiddleware } from "../lib/middleware.js"; +import { getMessage } from "../util/messages.js"; const router = Router(); @@ -377,6 +378,7 @@ router.get("/:eventID", async (req: Request, res: Response) => { image: event.image, editToken: editingEnabled ? eventEditToken : null, }, + message: getMessage(req.query.m as string), }); } } catch (err) { diff --git a/src/util/generator.ts b/src/util/generator.ts index d959145..18dcf32 100644 --- a/src/util/generator.ts +++ b/src/util/generator.ts @@ -34,3 +34,6 @@ export const generateRSAKeypair = () => { }, }); }; + +export const hashString = (input: string) => + crypto.createHash("sha256").update(input).digest("hex"); diff --git a/src/util/messages.ts b/src/util/messages.ts new file mode 100644 index 0000000..ae1568c --- /dev/null +++ b/src/util/messages.ts @@ -0,0 +1,9 @@ +type MessageId = "unattend"; + +const queryStringMessages: Record<MessageId, string> = { + unattend: `You have been removed from this event.`, +}; + +export const getMessage = (id?: string) => { + return queryStringMessages[id as MessageId] || ""; +}; |