summaryrefslogtreecommitdiff
path: root/src/routes/frontend.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/routes/frontend.ts')
-rw-r--r--src/routes/frontend.ts227
1 files changed, 225 insertions, 2 deletions
diff --git a/src/routes/frontend.ts b/src/routes/frontend.ts
index 71984ec..c9594ef 100644
--- a/src/routes/frontend.ts
+++ b/src/routes/frontend.ts
@@ -1,11 +1,12 @@
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";
+import { addToLog, exportICal } from "../helpers.js";
+import Event from "../models/Event.js";
+import EventGroup, { IEventGroup } from "../models/EventGroup.js";
const config = getConfig();
@@ -69,6 +70,13 @@ router.get("/:eventID", async (req: Request, res: Response) => {
let parsedEnd = moment
.tz(event.end, event.timezone)
.format("YYYYMMDD[T]HHmmss");
+ // See: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/datetime-local
+ const parsedStartForDateInput = moment
+ .tz(event.start, event.timezone)
+ .format("YYYY-MM-DDTHH:mm");
+ const parsedEndForDateInput = moment
+ .tz(event.end, event.timezone)
+ .format("YYYY-MM-DDTHH:mm");
let eventHasConcluded = false;
if (
moment
@@ -194,6 +202,8 @@ router.get("/:eventID", async (req: Request, res: Response) => {
parsedLocation: parsedLocation,
parsedStart: parsedStart,
parsedEnd: parsedEnd,
+ parsedStartForDateInput,
+ parsedEndForDateInput,
displayDate: displayDate,
fromNow: fromNow,
timezone: event.timezone,
@@ -205,6 +215,31 @@ router.get("/:eventID", async (req: Request, res: Response) => {
eventHasConcluded: eventHasConcluded,
eventHasBegun: eventHasBegun,
metadata: metadata,
+ jsonData: {
+ name: event.name,
+ id: event.id,
+ description: event.description,
+ location: event.location,
+ timezone: event.timezone,
+ url: event.url,
+ hostName: event.hostName,
+ creatorEmail: event.creatorEmail,
+ eventGroupID: event.eventGroup
+ ? (event.eventGroup as unknown as IEventGroup).id
+ : null,
+ eventGroupEditToken: event.eventGroup
+ ? (event.eventGroup as unknown as IEventGroup).editToken
+ : null,
+ usersCanAttend: event.usersCanAttend,
+ usersCanComment: event.usersCanComment,
+ maxAttendees: event.maxAttendees,
+ startISO: eventStartISO,
+ endISO: eventEndISO,
+ startForDateInput: parsedStartForDateInput,
+ endForDateInput: parsedEndForDateInput,
+ image: event.image,
+ editToken: editingEnabled ? eventEditToken : null,
+ },
});
}
} catch (err) {
@@ -221,4 +256,192 @@ router.get("/:eventID", async (req: Request, res: Response) => {
}
});
+router.get("/group/:eventGroupID", async (req: Request, res: Response) => {
+ try {
+ const eventGroup = await EventGroup.findOne({
+ id: req.params.eventGroupID,
+ }).lean();
+
+ if (!eventGroup) {
+ return res.status(404).render("404", { url: req.url });
+ }
+ const parsedDescription = marked.parse(eventGroup.description);
+ const eventGroupEditToken = eventGroup.editToken;
+ const escapedName = eventGroup.name.replace(/\s+/g, "+");
+ const eventGroupHasCoverImage = !!eventGroup.image;
+ const eventGroupHasHost = !!eventGroup.hostName;
+
+ const events = await Event.find({ eventGroup: eventGroup._id })
+ .lean()
+ .sort("start");
+
+ const updatedEvents = events.map((event) => {
+ const startMoment = moment.tz(event.start, event.timezone);
+ const endMoment = moment.tz(event.end, event.timezone);
+ const isSameDay = startMoment.isSame(endMoment, "day");
+
+ return {
+ id: event.id,
+ name: event.name,
+ displayDate: isSameDay
+ ? startMoment.format("D MMM YYYY")
+ : `${startMoment.format("D MMM YYYY")} - ${endMoment.format(
+ "D MMM YYYY",
+ )}`,
+ eventHasConcluded: endMoment.isBefore(
+ moment.tz(event.timezone),
+ ),
+ };
+ });
+
+ const upcomingEventsExist = updatedEvents.some(
+ (e) => !e.eventHasConcluded,
+ );
+
+ let firstLoad = false;
+ if (eventGroup.firstLoad === true) {
+ firstLoad = true;
+ await EventGroup.findOneAndUpdate(
+ { id: req.params.eventGroupID },
+ { firstLoad: false },
+ );
+ }
+
+ let editingEnabled = false;
+ if (Object.keys(req.query).length !== 0) {
+ if (!req.query.e) {
+ editingEnabled = false;
+ } else {
+ editingEnabled = req.query.e === eventGroupEditToken;
+ }
+ }
+
+ const metadata = {
+ title: eventGroup.name,
+ description: marked
+ .parse(eventGroup.description, {
+ renderer: renderPlain(),
+ })
+ .split(" ")
+ .splice(0, 40)
+ .join(" ")
+ .trim(),
+ image: eventGroupHasCoverImage
+ ? `https://${config.general.domain}/events/` + eventGroup.image
+ : null,
+ url: `https://${config.general.domain}/` + req.params.eventID,
+ };
+
+ res.set("X-Robots-Tag", "noindex");
+ res.render("eventgroup", {
+ domain: config.general.domain,
+ title: eventGroup.name,
+ eventGroupData: eventGroup,
+ escapedName: escapedName,
+ events: updatedEvents,
+ upcomingEventsExist: upcomingEventsExist,
+ parsedDescription: parsedDescription,
+ editingEnabled: editingEnabled,
+ eventGroupHasCoverImage: eventGroupHasCoverImage,
+ eventGroupHasHost: eventGroupHasHost,
+ firstLoad: firstLoad,
+ metadata: metadata,
+ jsonData: {
+ name: eventGroup.name,
+ id: eventGroup.id,
+ description: eventGroup.description,
+ url: eventGroup.url,
+ hostName: eventGroup.hostName,
+ creatorEmail: eventGroup.creatorEmail,
+ image: eventGroup.image,
+ editToken: editingEnabled ? eventGroupEditToken : null,
+ },
+ });
+ } catch (err) {
+ addToLog(
+ "displayEventGroup",
+ "error",
+ `Attempt to display event group ${req.params.eventGroupID} failed with error: ${err}`,
+ );
+ console.log(err);
+ return res.status(404).render("404", { url: req.url });
+ }
+});
+
+router.get(
+ "/group/:eventGroupID/feed.ics",
+ async (req: Request, res: Response) => {
+ try {
+ const eventGroup = await EventGroup.findOne({
+ id: req.params.eventGroupID,
+ }).lean();
+
+ if (eventGroup) {
+ const events = await Event.find({
+ eventGroup: eventGroup._id,
+ }).sort("start");
+ const string = exportICal(events, eventGroup.name);
+ res.set("Content-Type", "text/calendar");
+ res.send(string);
+ }
+ } catch (err) {
+ addToLog(
+ "eventGroupFeed",
+ "error",
+ `Attempt to display event group feed for ${req.params.eventGroupID} failed with error: ${err}`,
+ );
+ console.log(err);
+ res.status(404).render("404", { url: req.url });
+ }
+ },
+);
+
+router.get("/export/event/:eventID", async (req: Request, res: Response) => {
+ try {
+ const event = await Event.findOne({
+ id: req.params.eventID,
+ }).populate("eventGroup");
+
+ if (event) {
+ const string = exportICal([event], event.name);
+ res.send(string);
+ }
+ } catch (err) {
+ addToLog(
+ "exportEvent",
+ "error",
+ `Attempt to export event ${req.params.eventID} failed with error: ${err}`,
+ );
+ console.log(err);
+ res.status(404).render("404", { url: req.url });
+ }
+});
+
+router.get(
+ "/export/group/:eventGroupID",
+ async (req: Request, res: Response) => {
+ try {
+ const eventGroup = await EventGroup.findOne({
+ id: req.params.eventGroupID,
+ }).lean();
+
+ if (eventGroup) {
+ const events = await Event.find({
+ eventGroup: eventGroup._id,
+ }).sort("start");
+ const string = exportICal(events, eventGroup.name);
+ res.send(string);
+ }
+ } catch (err) {
+ addToLog(
+ "exportEvent",
+ "error",
+ `Attempt to export event group ${req.params.eventGroupID} failed with error: ${err}`,
+ );
+ console.log(err);
+ res.status(404).render("404", { url: req.url });
+ }
+ },
+);
+
export default router;