From 115210bfd9a5ae7bb8b516ce0d2cf3d9042dead7 Mon Sep 17 00:00:00 2001 From: Raphael Kabo Date: Fri, 6 Oct 2023 16:18:13 +0100 Subject: refactor: frontend routes into TS file, new event path --- src/routes/frontend.ts | 220 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 220 insertions(+) create mode 100644 src/routes/frontend.ts (limited to 'src/routes/frontend.ts') diff --git a/src/routes/frontend.ts b/src/routes/frontend.ts new file mode 100644 index 0000000..9dea619 --- /dev/null +++ b/src/routes/frontend.ts @@ -0,0 +1,220 @@ +import { Router, Request, Response } from "express"; +import Event from "../models/Event.js"; +import moment from "moment-timezone"; +import { marked } from "marked"; +import { frontendConfig } from "../util/config.js"; +import { renderPlain } from "../util/markdown.js"; +import getConfig from "../lib/config.js"; +import { addToLog } from "../helpers.js"; + +const config = getConfig(); + +const router = Router(); +router.get("/", (_: Request, res: Response) => { + res.render("home", frontendConfig()); +}); + +router.get("/new", (_: Request, res: Response) => { + res.render("newevent", { + title: "New event", + ...frontendConfig(), + }); +}); + +router.get("/:eventID", async (req: Request, res: Response) => { + try { + const event = await Event.findOne({ + id: req.params.eventID, + }) + .lean() // Required, see: https://stackoverflow.com/questions/59690923/handlebars-access-has-been-denied-to-resolve-the-property-from-because-it-is + .populate("eventGroup"); + if (!event) { + res.status(404); + res.render("404", { url: req.url }); + return; + } + const parsedLocation = event.location.replace(/\s+/g, "+"); + let displayDate; + if (moment.tz(event.end, event.timezone).isSame(event.start, "day")) { + // Happening during one day + displayDate = + moment + .tz(event.start, event.timezone) + .format( + 'dddd D MMMM YYYY [from] h:mm a' + ) + + moment + .tz(event.end, event.timezone) + .format( + ' [to] h:mm a [](z)[]' + ); + } else { + displayDate = + moment + .tz(event.start, event.timezone) + .format( + 'dddd D MMMM YYYY [at] h:mm a' + ) + + moment + .tz(event.end, event.timezone) + .format( + ' [] dddd D MMMM YYYY [at] h:mm a [](z)[]' + ); + } + let eventStartISO = moment.tz(event.start, "Etc/UTC").toISOString(); + let eventEndISO = moment.tz(event.end, "Etc/UTC").toISOString(); + let parsedStart = moment + .tz(event.start, event.timezone) + .format("YYYYMMDD[T]HHmmss"); + let parsedEnd = moment + .tz(event.end, event.timezone) + .format("YYYYMMDD[T]HHmmss"); + let eventHasConcluded = false; + if ( + moment.tz(event.end, event.timezone).isBefore(moment.tz(event.timezone)) + ) { + eventHasConcluded = true; + } + let eventHasBegun = false; + if ( + moment.tz(event.start, event.timezone).isBefore(moment.tz(event.timezone)) + ) { + eventHasBegun = true; + } + let fromNow = moment.tz(event.start, event.timezone).fromNow(); + let parsedDescription = marked.parse(event.description); + let eventEditToken = event.editToken; + + let escapedName = event.name.replace(/\s+/g, "+"); + + let eventHasCoverImage = false; + if (event.image) { + eventHasCoverImage = true; + } else { + eventHasCoverImage = false; + } + let eventHasHost = false; + if (event.hostName) { + eventHasHost = true; + } else { + eventHasHost = false; + } + let firstLoad = false; + if (event.firstLoad === true) { + firstLoad = true; + await Event.findOneAndUpdate( + { id: req.params.eventID }, + { firstLoad: false } + ); + } + let editingEnabled = false; + if (Object.keys(req.query).length !== 0) { + if (!req.query.e) { + editingEnabled = false; + console.log("No edit token set"); + } else { + if (req.query.e === eventEditToken) { + editingEnabled = true; + } else { + editingEnabled = false; + } + } + } + let eventAttendees = event.attendees + ?.sort((a, b) => (a.name > b.name ? 1 : b.name > a.name ? -1 : 0)) + .map((el) => { + if (!el.id) { + el.id = el._id; + } + if (el.number && el.number > 1) { + el.name = `${el.name} (${el.number} people)`; + } + return el; + }) + .filter((obj, pos, arr) => { + return ( + obj.status === "attending" && + arr.map((mapObj) => mapObj.id).indexOf(obj.id) === pos + ); + }); + + let spotsRemaining, noMoreSpots; + let numberOfAttendees = + eventAttendees?.reduce((acc, attendee) => { + if (attendee.status === "attending") { + return acc + (attendee.number || 1); + } + return acc; + }, 0) || 0; + if (event.maxAttendees) { + spotsRemaining = event.maxAttendees - numberOfAttendees; + if (spotsRemaining <= 0) { + noMoreSpots = true; + } + } + let metadata = { + title: event.name, + description: marked + .parse(event.description, { renderer: renderPlain() }) + .split(" ") + .splice(0, 40) + .join(" ") + .trim(), + image: eventHasCoverImage + ? `https://${config.general.domain}/events/` + event.image + : null, + url: `https://${config.general.domain}/` + req.params.eventID, + }; + if ( + req.headers.accept && + (req.headers.accept.includes("application/activity+json") || + req.headers.accept.includes("application/json") || + req.headers.accept.includes("application/json+ld")) + ) { + res + .header("Content-Type", "application/activity+json") + .send(JSON.parse(event.activityPubActor || "{}")); + } else { + res.set("X-Robots-Tag", "noindex"); + res.render("event", { + ...frontendConfig(), + title: event.name, + escapedName: escapedName, + eventData: event, + eventAttendees: eventAttendees, + numberOfAttendees, + spotsRemaining: spotsRemaining, + noMoreSpots: noMoreSpots, + eventStartISO: eventStartISO, + eventEndISO: eventEndISO, + parsedLocation: parsedLocation, + parsedStart: parsedStart, + parsedEnd: parsedEnd, + displayDate: displayDate, + fromNow: fromNow, + timezone: event.timezone, + parsedDescription: parsedDescription, + editingEnabled: editingEnabled, + eventHasCoverImage: eventHasCoverImage, + eventHasHost: eventHasHost, + firstLoad: firstLoad, + eventHasConcluded: eventHasConcluded, + eventHasBegun: eventHasBegun, + metadata: metadata, + }); + } + } catch (err) { + addToLog( + "displayEvent", + "error", + "Attempt to display event " + + req.params.eventID + + " failed with error: " + + err + ); + console.log(err); + res.status(404).render("404", { url: req.url }); + } +}); + +export default router; -- cgit v1.2.3