summaryrefslogtreecommitdiff
path: root/src/routes.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/routes.js')
-rwxr-xr-xsrc/routes.js1320
1 files changed, 10 insertions, 1310 deletions
diff --git a/src/routes.js b/src/routes.js
index 7257bdb..5371e0e 100755
--- a/src/routes.js
+++ b/src/routes.js
@@ -3,10 +3,8 @@ import express from "express";
import { customAlphabet } from "nanoid";
import randomstring from "randomstring";
import { getConfig } from "./lib/config.js";
-import { addToLog, exportIcal } from "./helpers.js";
+import { addToLog } from "./helpers.js";
import moment from "moment-timezone";
-import { marked } from "marked";
-import generateRSAKeypair from "generate-rsa-keypair";
import crypto from "crypto";
import request from "request";
import niceware from "niceware";
@@ -17,16 +15,8 @@ import fileUpload from "express-fileupload";
import Jimp from "jimp";
import schedule from "node-schedule";
import {
- createActivityPubActor,
- createActivityPubEvent,
- createFeaturedPost,
- createWebfinger,
- updateActivityPubActor,
- updateActivityPubEvent,
broadcastCreateMessage,
- broadcastUpdateMessage,
broadcastDeleteMessage,
- sendDirectMessage,
processInbox,
} from "./activitypub.js";
import Event from "./models/Event.js";
@@ -40,7 +30,6 @@ const siteName = config.general.site_name;
const mailService = config.general.mail_service;
const siteLogo = config.general.email_logo_url;
const isFederated = config.general.is_federated || true;
-const showKofi = config.general.show_kofi;
// This alphabet (used to generate all event, group, etc. IDs) is missing '-'
// because ActivityPub doesn't like it in IDs
@@ -193,864 +182,7 @@ schedule.scheduleJob("59 23 * * *", function (fireDate) {
// old (they're not going to become active)
});
-// return the JSON for the featured/pinned post for this event
-router.get("/:eventID/featured", (req, res) => {
- if (!isFederated) return res.sendStatus(404);
- const { eventID } = req.params;
- const guidObject = crypto.randomBytes(16).toString("hex");
- const featured = {
- "@context": "https://www.w3.org/ns/activitystreams",
- id: `https://${domain}/${eventID}/featured`,
- type: "OrderedCollection",
- orderedItems: [createFeaturedPost(eventID)],
- };
- if (
- req.headers.accept &&
- (req.headers.accept.includes("application/activity+json") ||
- req.headers.accept.includes("application/ld+json"))
- ) {
- res.header("Content-Type", "application/activity+json").send(featured);
- } else {
- res.header("Content-Type", "application/json").send(featured);
- }
-});
-
-// return the JSON for a given activitypub message
-router.get("/:eventID/m/:hash", (req, res) => {
- if (!isFederated) return res.sendStatus(404);
- const { hash, eventID } = req.params;
- const id = `https://${domain}/${eventID}/m/${hash}`;
-
- Event.findOne({
- id: eventID,
- })
- .then((event) => {
- if (!event) {
- res.status(404);
- res.render("404", { url: req.url });
- } else {
- const message = event.activityPubMessages.find(
- (el) => el.id === id,
- );
- if (message) {
- if (
- req.headers.accept &&
- (req.headers.accept.includes(
- "application/activity+json",
- ) ||
- req.headers.accept.includes("application/ld+json"))
- ) {
- res.header(
- "Content-Type",
- "application/activity+json",
- ).send(JSON.parse(message.content));
- } else {
- res.header("Content-Type", "application/json").send(
- JSON.parse(message.content),
- );
- }
- } else {
- res.status(404);
- return res.render("404", { url: req.url });
- }
- }
- })
- .catch((err) => {
- addToLog(
- "getActivityPubMessage",
- "error",
- "Attempt to get Activity Pub Message for " +
- id +
- " failed with error: " +
- err,
- );
- res.status(404);
- res.render("404", { url: req.url });
- return;
- });
-});
-
-// return the webfinger record required for the initial activitypub handshake
-router.get("/.well-known/webfinger", (req, res) => {
- if (!isFederated) return res.sendStatus(404);
- let resource = req.query.resource;
- if (!resource || !resource.includes("acct:")) {
- return res
- .status(400)
- .send(
- 'Bad request. Please make sure "acct:USER@DOMAIN" is what you are sending as the "resource" query parameter.',
- );
- } else {
- // "foo@domain"
- let activityPubAccount = resource.replace("acct:", "");
- // "foo"
- let eventID = activityPubAccount.replace(/@.*/, "");
- Event.findOne({
- id: eventID,
- })
- .then((event) => {
- if (!event) {
- res.status(404);
- res.render("404", { url: req.url });
- } else {
- if (
- req.headers.accept &&
- (req.headers.accept.includes(
- "application/activity+json",
- ) ||
- req.headers.accept.includes("application/ld+json"))
- ) {
- res.header(
- "Content-Type",
- "application/activity+json",
- ).send(createWebfinger(eventID, domain));
- } else {
- res.header("Content-Type", "application/json").send(
- createWebfinger(eventID, domain),
- );
- }
- }
- })
- .catch((err) => {
- addToLog(
- "renderWebfinger",
- "error",
- "Attempt to render webfinger for " +
- req.params.eventID +
- " failed with error: " +
- err,
- );
- res.status(404);
- res.render("404", { url: req.url });
- return;
- });
- }
-});
-
-router.get("/:eventID/followers", (req, res) => {
- if (!isFederated) return res.sendStatus(404);
- const eventID = req.params.eventID;
- Event.findOne({
- id: eventID,
- }).then((event) => {
- if (event) {
- const followers = event.followers.map((el) => el.actorId);
- let followersCollection = {
- type: "OrderedCollection",
- totalItems: followers.length,
- id: `https://${domain}/${eventID}/followers`,
- first: {
- type: "OrderedCollectionPage",
- totalItems: followers.length,
- partOf: `https://${domain}/${eventID}/followers`,
- orderedItems: followers,
- id: `https://${domain}/${eventID}/followers?page=1`,
- },
- "@context": ["https://www.w3.org/ns/activitystreams"],
- };
- if (
- req.headers.accept &&
- (req.headers.accept.includes("application/activity+json") ||
- req.headers.accept.includes("application/ld+json"))
- ) {
- return res
- .header("Content-Type", "application/activity+json")
- .send(followersCollection);
- } else {
- return res
- .header("Content-Type", "application/json")
- .send(followersCollection);
- }
- } else {
- return res.status(400).send("Bad request.");
- }
- });
-});
-
-router.get("/group/:eventGroupID", (req, res) => {
- EventGroup.findOne({
- id: req.params.eventGroupID,
- })
- .lean() // Required, see: https://stackoverflow.com/questions/59690923/handlebars-access-has-been-denied-to-resolve-the-property-from-because-it-is
- .then(async (eventGroup) => {
- if (eventGroup) {
- let parsedDescription = marked.parse(eventGroup.description);
- let eventGroupEditToken = eventGroup.editToken;
-
- let escapedName = eventGroup.name.replace(/\s+/g, "+");
-
- let eventGroupHasCoverImage = false;
- if (eventGroup.image) {
- eventGroupHasCoverImage = true;
- } else {
- eventGroupHasCoverImage = false;
- }
- let eventGroupHasHost = false;
- if (eventGroup.hostName) {
- eventGroupHasHost = true;
- } else {
- eventGroupHasHost = false;
- }
-
- let events = await Event.find({ eventGroup: eventGroup._id })
- .lean()
- .sort("start");
-
- events.map((event) => {
- if (
- moment
- .tz(event.end, event.timezone)
- .isSame(event.start, "day")
- ) {
- // Happening during one day
- event.displayDate = moment
- .tz(event.start, event.timezone)
- .format("D MMM YYYY");
- } else {
- event.displayDate =
- moment
- .tz(event.start, event.timezone)
- .format("D MMM YYYY") +
- moment
- .tz(event.end, event.timezone)
- .format(" - D MMM YYYY");
- }
- if (
- moment
- .tz(event.end, event.timezone)
- .isBefore(moment.tz(event.timezone))
- ) {
- event.eventHasConcluded = true;
- } else {
- event.eventHasConcluded = false;
- }
- return (({ id, name, displayDate, eventHasConcluded }) => ({
- id,
- name,
- displayDate,
- eventHasConcluded,
- }))(event);
- });
-
- let upcomingEventsExist = false;
- if (events.some((e) => e.eventHasConcluded === false)) {
- upcomingEventsExist = true;
- }
-
- let firstLoad = false;
- if (eventGroup.firstLoad === true) {
- firstLoad = true;
- EventGroup.findOneAndUpdate(
- { id: req.params.eventGroupID },
- { firstLoad: false },
- function (err, raw) {
- if (err) {
- res.send(err);
- }
- },
- );
- }
- 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 === eventGroupEditToken) {
- editingEnabled = true;
- } else {
- editingEnabled = false;
- }
- }
- }
- let metadata = {
- title: eventGroup.name,
- description: marked
- .parse(eventGroup.description, {
- renderer: render_plain(),
- })
- .split(" ")
- .splice(0, 40)
- .join(" ")
- .trim(),
- image: eventGroupHasCoverImage
- ? `https://${domain}/events/` + eventGroup.image
- : null,
- url: `https://${domain}/` + req.params.eventID,
- };
- res.set("X-Robots-Tag", "noindex");
- res.render("eventgroup", {
- domain: domain,
- title: eventGroup.name,
- eventGroupData: eventGroup,
- escapedName: escapedName,
- events: events,
- upcomingEventsExist: upcomingEventsExist,
- parsedDescription: parsedDescription,
- editingEnabled: editingEnabled,
- eventGroupHasCoverImage: eventGroupHasCoverImage,
- eventGroupHasHost: eventGroupHasHost,
- firstLoad: firstLoad,
- metadata: metadata,
- });
- } else {
- res.status(404);
- res.render("404", { url: req.url });
- }
- })
- .catch((err) => {
- addToLog(
- "displayEventGroup",
- "error",
- "Attempt to display event group " +
- req.params.eventGroupID +
- " failed with error: " +
- err,
- );
- console.log(err);
- res.status(404);
- res.render("404", { url: req.url });
- return;
- });
-});
-
-router.get("/group/:eventGroupID/feed.ics", (req, res) => {
- EventGroup.findOne({
- id: req.params.eventGroupID,
- })
- .lean() // Required, see: https://stackoverflow.com/questions/59690923/handlebars-access-has-been-denied-to-resolve-the-property-from-because-it-is
- .then(async (eventGroup) => {
- if (eventGroup) {
- let events = await Event.find({ eventGroup: eventGroup._id })
- .lean()
- .sort("start");
- const string = exportIcal(events, eventGroup.name);
- res.set("Content-Type", "text/calendar");
- return 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);
- res.render("404", { url: req.url });
- return;
- });
-});
-
-router.get("/exportevent/:eventID", (req, res) => {
- Event.findOne({
- id: req.params.eventID,
- })
- .populate("eventGroup")
- .then((event) => {
- if (event) {
- const string = exportIcal([event]);
- 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);
- res.render("404", { url: req.url });
- return;
- });
-});
-
-router.get("/exportgroup/:eventGroupID", (req, res) => {
- EventGroup.findOne({
- id: req.params.eventGroupID,
- })
- .lean() // Required, see: https://stackoverflow.com/questions/59690923/handlebars-access-has-been-denied-to-resolve-the-property-from-because-it-is
- .then(async (eventGroup) => {
- if (eventGroup) {
- let events = await Event.find({ eventGroup: eventGroup._id })
- .lean()
- .sort("start");
- const string = exportIcal(events);
- 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);
- res.render("404", { url: req.url });
- return;
- });
-});
-
// BACKEND ROUTES
-
-router.post("/newevent", async (req, res) => {
- let eventID = nanoid();
- let editToken = randomstring.generate();
- let eventImageFilename = "";
- let isPartOfEventGroup = false;
- if (req.files && Object.keys(req.files).length !== 0) {
- let eventImageBuffer = req.files.imageUpload.data;
- eventImageFilename = await Jimp.read(eventImageBuffer)
- .then((img) => {
- img.resize(920, Jimp.AUTO) // resize
- .quality(80) // set JPEG quality
- .write("./public/events/" + eventID + ".jpg"); // save
- const filename = eventID + ".jpg";
- return filename;
- })
- .catch((err) => {
- addToLog(
- "Jimp",
- "error",
- "Attempt to edit image failed with error: " + err,
- );
- });
- }
- let startUTC = moment.tz(
- req.body.eventStart,
- "D MMMM YYYY, hh:mm a",
- req.body.timezone,
- );
- let endUTC = moment.tz(
- req.body.eventEnd,
- "D MMMM YYYY, hh:mm a",
- req.body.timezone,
- );
- let eventGroup;
- if (req.body.eventGroupCheckbox) {
- eventGroup = await EventGroup.findOne({
- id: req.body.eventGroupID,
- editToken: req.body.eventGroupEditToken,
- });
- if (eventGroup) {
- isPartOfEventGroup = true;
- }
- }
-
- // generate RSA keypair for ActivityPub
- let pair = generateRSAKeypair();
-
- const event = new Event({
- id: eventID,
- type: "public", // This is for backwards compatibility
- name: req.body.eventName,
- location: req.body.eventLocation,
- start: startUTC,
- end: endUTC,
- timezone: req.body.timezone,
- description: req.body.eventDescription,
- image: eventImageFilename,
- creatorEmail: req.body.creatorEmail,
- url: req.body.eventURL,
- hostName: req.body.hostName,
- viewPassword: req.body.viewPassword,
- editPassword: req.body.editPassword,
- editToken: editToken,
- eventGroup: isPartOfEventGroup ? eventGroup._id : null,
- usersCanAttend: req.body.joinCheckbox ? true : false,
- showUsersList: req.body.guestlistCheckbox ? true : false,
- usersCanComment: req.body.interactionCheckbox ? true : false,
- maxAttendees: req.body.maxAttendees,
- firstLoad: true,
- activityPubActor: createActivityPubActor(
- eventID,
- domain,
- pair.public,
- marked.parse(req.body.eventDescription),
- req.body.eventName,
- req.body.eventLocation,
- eventImageFilename,
- startUTC,
- endUTC,
- req.body.timezone,
- ),
- activityPubEvent: createActivityPubEvent(
- req.body.eventName,
- startUTC,
- endUTC,
- req.body.timezone,
- req.body.eventDescription,
- req.body.eventLocation,
- ),
- activityPubMessages: [
- {
- id: `https://${domain}/${eventID}/m/featuredPost`,
- content: JSON.stringify(
- createFeaturedPost(
- eventID,
- req.body.eventName,
- startUTC,
- endUTC,
- req.body.timezone,
- req.body.eventDescription,
- req.body.eventLocation,
- ),
- ),
- },
- ],
- publicKey: pair.public,
- privateKey: pair.private,
- });
- event
- .save()
- .then((event) => {
- addToLog("createEvent", "success", "Event " + eventID + "created");
- // Send email with edit link
- if (req.body.creatorEmail && sendEmails) {
- req.app.get("hbsInstance").renderView(
- "./views/emails/createevent.handlebars",
- {
- eventID,
- editToken,
- siteName,
- siteLogo,
- domain,
- cache: true,
- layout: "email.handlebars",
- },
- function (err, html) {
- const msg = {
- to: req.body.creatorEmail,
- from: {
- name: siteName,
- email: contactEmail,
- address: contactEmail,
- },
- subject: `${siteName}: ${req.body.eventName}`,
- html,
- };
- switch (mailService) {
- case "sendgrid":
- sgMail.send(msg).catch((e) => {
- console.error(e.toString());
- res.status(500).end();
- });
- break;
- case "nodemailer":
- nodemailerTransporter
- .sendMail(msg)
- .catch((e) => {
- console.error(e.toString());
- res.status(500).end();
- });
- break;
- }
- },
- );
- }
- // If the event was added to a group, send an email to any group
- // subscribers
- if (event.eventGroup && sendEmails) {
- EventGroup.findOne({ _id: event.eventGroup._id }).then(
- (eventGroup) => {
- const subscribers = eventGroup.subscribers.reduce(
- (acc, current) => {
- if (acc.includes(current.email)) {
- return acc;
- }
- return [current.email, ...acc];
- },
- [],
- );
- subscribers.forEach((emailAddress) => {
- req.app.get("hbsInstance").renderView(
- "./views/emails/eventgroupupdated.handlebars",
- {
- siteName,
- siteLogo,
- domain,
- eventID: req.params.eventID,
- eventGroupName: eventGroup.name,
- eventName: event.name,
- eventID: event.id,
- eventGroupID: eventGroup.id,
- emailAddress:
- encodeURIComponent(emailAddress),
- cache: true,
- layout: "email.handlebars",
- },
- function (err, html) {
- const msg = {
- to: emailAddress,
- from: {
- name: siteName,
- email: contactEmail,
- },
- subject: `${siteName}: New event in ${eventGroup.name}`,
- html,
- };
- switch (mailService) {
- case "sendgrid":
- sgMail.send(msg).catch((e) => {
- console.error(e.toString());
- res.status(500).end();
- });
- break;
- case "nodemailer":
- nodemailerTransporter
- .sendMail(msg)
- .catch((e) => {
- console.error(e.toString());
- res.status(500).end();
- });
- break;
- }
- },
- );
- });
- },
- );
- }
- res.writeHead(302, {
- Location: "/" + eventID + "?e=" + editToken,
- });
- res.end();
- })
- .catch((err) => {
- console.error(err);
- res.status(500).send(
- "Database error, please try again :( - " + err,
- );
- addToLog(
- "createEvent",
- "error",
- "Attempt to create event failed with error: " + err,
- );
- });
-});
-
-router.post("/importevent", (req, res) => {
- let eventID = nanoid();
- let editToken = randomstring.generate();
- if (req.files && Object.keys(req.files).length !== 0) {
- let iCalObject = ical.parseICS(
- req.files.icsImportControl.data.toString("utf8"),
- );
- let importedEventData = iCalObject[Object.keys(iCalObject)];
-
- let creatorEmail;
- if (req.body.creatorEmail) {
- creatorEmail = req.body.creatorEmail;
- } else if (importedEventData.organizer) {
- creatorEmail = importedEventData.organizer.val.replace(
- "MAILTO:",
- "",
- );
- }
-
- const event = new Event({
- id: eventID,
- type: "public",
- name: importedEventData.summary,
- location: importedEventData.location,
- start: importedEventData.start,
- end: importedEventData.end,
- timezone:
- typeof importedEventData.start.tz !== "undefined"
- ? importedEventData.start.tz
- : "Etc/UTC",
- description: importedEventData.description,
- image: "",
- creatorEmail: creatorEmail,
- url: "",
- hostName: importedEventData.organizer
- ? importedEventData.organizer.params.CN.replace(/["]+/g, "")
- : "",
- viewPassword: "",
- editPassword: "",
- editToken: editToken,
- usersCanAttend: false,
- showUsersList: false,
- usersCanComment: false,
- firstLoad: true,
- });
- event
- .save()
- .then(() => {
- addToLog(
- "createEvent",
- "success",
- "Event " + eventID + " created",
- );
- // Send email with edit link
- if (creatorEmail && sendEmails) {
- req.app.get("hbsInstance").renderView(
- "./views/emails/createevent.handlebars",
- {
- eventID,
- editToken,
- siteName,
- siteLogo,
- domain,
- cache: true,
- layout: "email.handlebars",
- },
- function (err, html) {
- const msg = {
- to: req.body.creatorEmail,
- from: {
- name: siteName,
- email: contactEmail,
- address: contactEmail,
- },
- subject: `${siteName}: ${importedEventData.summary}`,
- html,
- };
- switch (mailService) {
- case "sendgrid":
- sgMail.send(msg).catch((e) => {
- console.error(e.toString());
- res.status(500).end();
- });
- break;
- case "nodemailer":
- nodemailerTransporter
- .sendMail(msg)
- .catch((e) => {
- console.error(e.toString());
- res.status(500).end();
- });
- break;
- }
- },
- );
- }
- res.writeHead(302, {
- Location: "/" + eventID + "?e=" + editToken,
- });
- res.end();
- })
- .catch((err) => {
- res.send("Database error, please try again :(");
- addToLog(
- "createEvent",
- "error",
- "Attempt to create event failed with error: " + err,
- );
- });
- } else {
- console.log("Files array is empty!");
- res.status(500).end();
- }
-});
-
-router.post("/neweventgroup", (req, res) => {
- let eventGroupID = nanoid();
- let editToken = randomstring.generate();
- let eventGroupImageFilename = "";
- if (req.files && Object.keys(req.files).length !== 0) {
- let eventImageBuffer = req.files.imageUpload.data;
- Jimp.read(eventImageBuffer, (err, img) => {
- if (err)
- addToLog(
- "Jimp",
- "error",
- "Attempt to edit image failed with error: " + err,
- );
- img.resize(920, Jimp.AUTO) // resize
- .quality(80) // set JPEG quality
- .write("./public/events/" + eventGroupID + ".jpg"); // save
- });
- eventGroupImageFilename = eventGroupID + ".jpg";
- }
- const eventGroup = new EventGroup({
- id: eventGroupID,
- name: req.body.eventGroupName,
- description: req.body.eventGroupDescription,
- image: eventGroupImageFilename,
- creatorEmail: req.body.creatorEmail,
- url: req.body.eventGroupURL,
- hostName: req.body.hostName,
- editToken: editToken,
- firstLoad: true,
- });
- eventGroup
- .save()
- .then(() => {
- addToLog(
- "createEventGroup",
- "success",
- "Event group " + eventGroupID + " created",
- );
- // Send email with edit link
- if (req.body.creatorEmail && sendEmails) {
- req.app.get("hbsInstance").renderView(
- "./views/emails/createeventgroup.handlebars",
- {
- eventGroupID,
- editToken,
- siteName,
- siteLogo,
- domain,
- cache: true,
- layout: "email.handlebars",
- },
- function (err, html) {
- const msg = {
- to: req.body.creatorEmail,
- from: {
- name: siteName,
- email: contactEmail,
- address: contactEmail,
- },
- subject: `${siteName}: ${req.body.eventGroupName}`,
- html,
- };
- switch (mailService) {
- case "sendgrid":
- sgMail.send(msg).catch((e) => {
- console.error(e.toString());
- res.status(500).end();
- });
- break;
- case "nodemailer":
- nodemailerTransporter
- .sendMail(msg)
- .catch((e) => {
- console.error(e.toString());
- res.status(500).end();
- });
- break;
- }
- },
- );
- }
- res.writeHead(302, {
- Location: "/group/" + eventGroupID + "?e=" + editToken,
- });
- res.end();
- })
- .catch((err) => {
- res.send("Database error, please try again :( - " + err);
- addToLog(
- "createEvent",
- "error",
- "Attempt to create event failed with error: " + err,
- );
- });
-});
-
router.post("/verifytoken/event/:eventID", (req, res) => {
Event.findOne({
id: req.params.eventID,
@@ -1071,441 +203,9 @@ router.post("/verifytoken/group/:eventGroupID", (req, res) => {
});
});
-router.post("/editevent/:eventID/:editToken", (req, res) => {
- let submittedEditToken = req.params.editToken;
- Event.findOne({
- id: req.params.eventID,
- })
- .then(async (event) => {
- if (event.editToken === submittedEditToken) {
- // Token matches
-
- // If there is a new image, upload that first
- let eventID = req.params.eventID;
- let eventImageFilename = event.image;
- if (req.files && Object.keys(req.files).length !== 0) {
- let eventImageBuffer = req.files.imageUpload.data;
- Jimp.read(eventImageBuffer, (err, img) => {
- if (err) throw err;
- img.resize(920, Jimp.AUTO) // resize
- .quality(80) // set JPEG
- .write("./public/events/" + eventID + ".jpg"); // save
- });
- eventImageFilename = eventID + ".jpg";
- }
- let startUTC = moment.tz(
- req.body.eventStart,
- "D MMMM YYYY, hh:mm a",
- req.body.timezone,
- );
- let endUTC = moment.tz(
- req.body.eventEnd,
- "D MMMM YYYY, hh:mm a",
- req.body.timezone,
- );
-
- let isPartOfEventGroup = false;
- let eventGroup;
- if (req.body.eventGroupCheckbox) {
- eventGroup = await EventGroup.findOne({
- id: req.body.eventGroupID,
- editToken: req.body.eventGroupEditToken,
- });
- if (eventGroup) {
- isPartOfEventGroup = true;
- }
- }
- const updatedEvent = {
- name: req.body.eventName,
- location: req.body.eventLocation,
- start: startUTC,
- end: endUTC,
- timezone: req.body.timezone,
- description: req.body.eventDescription,
- url: req.body.eventURL,
- hostName: req.body.hostName,
- image: eventImageFilename,
- usersCanAttend: req.body.joinCheckbox ? true : false,
- showUsersList: req.body.guestlistCheckbox ? true : false,
- usersCanComment: req.body.interactionCheckbox
- ? true
- : false,
- maxAttendees: req.body.maxAttendeesCheckbox
- ? req.body.maxAttendees
- : null,
- eventGroup: isPartOfEventGroup ? eventGroup._id : null,
- activityPubActor: event.activityPubActor
- ? updateActivityPubActor(
- JSON.parse(event.activityPubActor),
- req.body.eventDescription,
- req.body.eventName,
- req.body.eventLocation,
- eventImageFilename,
- startUTC,
- endUTC,
- req.body.timezone,
- )
- : null,
- activityPubEvent: event.activityPubEvent
- ? updateActivityPubEvent(
- JSON.parse(event.activityPubEvent),
- req.body.eventName,
- req.body.startUTC,
- req.body.endUTC,
- req.body.timezone,
- )
- : null,
- };
- let diffText =
- "<p>This event was just updated with new information.</p><ul>";
- let displayDate;
- if (event.name !== updatedEvent.name) {
- diffText += `<li>the event name changed to ${updatedEvent.name}</li>`;
- }
- if (event.location !== updatedEvent.location) {
- diffText += `<li>the location changed to ${updatedEvent.location}</li>`;
- }
- if (
- event.start.toISOString() !==
- updatedEvent.start.toISOString()
- ) {
- displayDate = moment
- .tz(updatedEvent.start, updatedEvent.timezone)
- .format("dddd D MMMM YYYY h:mm a");
- diffText += `<li>the start time changed to ${displayDate}</li>`;
- }
- if (
- event.end.toISOString() !== updatedEvent.end.toISOString()
- ) {
- displayDate = moment
- .tz(updatedEvent.end, updatedEvent.timezone)
- .format("dddd D MMMM YYYY h:mm a");
- diffText += `<li>the end time changed to ${displayDate}</li>`;
- }
- if (event.timezone !== updatedEvent.timezone) {
- diffText += `<li>the time zone changed to ${updatedEvent.timezone}</li>`;
- }
- if (event.description !== updatedEvent.description) {
- diffText += `<li>the event description changed</li>`;
- }
- diffText += `</ul>`;
- Event.findOneAndUpdate(
- { id: req.params.eventID },
- updatedEvent,
- function (err, raw) {
- if (err) {
- addToLog(
- "editEvent",
- "error",
- "Attempt to edit event " +
- req.params.eventID +
- " failed with error: " +
- err,
- );
- res.send(err);
- }
- },
- )
- .then(() => {
- addToLog(
- "editEvent",
- "success",
- "Event " + req.params.eventID + " edited",
- );
- // send update to ActivityPub subscribers
- Event.findOne(
- { id: req.params.eventID },
- function (err, event) {
- if (!event) return;
- let attendees = event.attendees.filter(
- (el) => el.id,
- );
- if (!err) {
- // broadcast an identical message to all followers, will show in home timeline
- const guidObject = crypto
- .randomBytes(16)
- .toString("hex");
- const jsonObject = {
- "@context":
- "https://www.w3.org/ns/activitystreams",
- id: `https://${domain}/${req.params.eventID}/m/${guidObject}`,
- name: `RSVP to ${event.name}`,
- type: "Note",
- cc: "https://www.w3.org/ns/activitystreams#Public",
- content: `${diffText} See here: <a href="https://${domain}/${req.params.eventID}">https://${domain}/${req.params.eventID}</a>`,
- };
- broadcastCreateMessage(
- jsonObject,
- event.followers,
- eventID,
- );
- // also broadcast an Update profile message to all followers so that at least Mastodon servers will update the local profile information
- const jsonUpdateObject = JSON.parse(
- event.activityPubActor,
- );
- broadcastUpdateMessage(
- jsonUpdateObject,
- event.followers,
- eventID,
- );
- // also broadcast an Update/Event for any calendar apps that are consuming our Events
- const jsonEventObject = JSON.parse(
- event.activityPubEvent,
- );
- broadcastUpdateMessage(
- jsonEventObject,
- event.followers,
- eventID,
- );
-
- // DM to attendees
- for (const attendee of attendees) {
- const jsonObject = {
- "@context":
- "https://www.w3.org/ns/activitystreams",
- name: `RSVP to ${event.name}`,
- type: "Note",
- content: `<span class=\"h-card\"><a href="${attendee.id}" class="u-url mention">@<span>${attendee.name}</span></a></span> ${diffText} See here: <a href="https://${domain}/${req.params.eventID}">https://${domain}/${req.params.eventID}</a>`,
- tag: [
- {
- type: "Mention",
- href: attendee.id,
- name: attendee.name,
- },
- ],
- };
- // send direct message to user
- sendDirectMessage(
- jsonObject,
- attendee.id,
- eventID,
- );
- }
- }
- },
- );
- // Send update to all attendees
- if (sendEmails) {
- Event.findOne({ id: req.params.eventID }).then(
- (event) => {
- const attendeeEmails = event.attendees
- .filter(
- (o) =>
- o.status === "attending" &&
- o.email,
- )
- .map((o) => o.email);
- if (attendeeEmails.length) {
- console.log(
- "Sending emails to: " +
- attendeeEmails,
- );
- req.app.get("hbsInstance").renderView(
- "./views/emails/editevent.handlebars",
- {
- diffText,
- eventID: req.params.eventID,
- siteName,
- siteLogo,
- domain,
- cache: true,
- layout: "email.handlebars",
- },
- function (err, html) {
- const msg = {
- to: attendeeEmails,
- from: {
- name: siteName,
- email: contactEmail,
- address: contactEmail,
- },
- subject: `${siteName}: ${event.name} was just edited`,
- html,
- };
- switch (mailService) {
- case "sendgrid":
- sgMail
- .sendMultiple(msg)
- .catch((e) => {
- console.error(
- e.toString(),
- );
- res.status(
- 500,
- ).end();
- });
- break;
- case "nodemailer":
- nodemailerTransporter
- .sendMail(msg)
- .catch((e) => {
- console.error(
- e.toString(),
- );
- res.status(
- 500,
- ).end();
- });
- break;
- }
- },
- );
- } else {
- console.log("Nothing to send!");
- }
- },
- );
- }
- res.writeHead(302, {
- Location:
- "/" +
- req.params.eventID +
- "?e=" +
- req.params.editToken,
- });
- res.end();
- })
- .catch((err) => {
- console.error(err);
- res.send("Sorry! Something went wrong!");
- addToLog(
- "editEvent",
- "error",
- "Attempt to edit event " +
- req.params.eventID +
- " failed with error: " +
- err,
- );
- });
- } else {
- // Token doesn't match
- res.send("Sorry! Something went wrong");
- addToLog(
- "editEvent",
- "error",
- "Attempt to edit event " +
- req.params.eventID +
- " failed with error: token does not match",
- );
- }
- })
- .catch((err) => {
- console.error(err);
- res.send("Sorry! Something went wrong!");
- addToLog(
- "editEvent",
- "error",
- "Attempt to edit event " +
- req.params.eventID +
- " failed with error: " +
- err,
- );
- });
-});
-
-router.post("/editeventgroup/:eventGroupID/:editToken", (req, res) => {
- let submittedEditToken = req.params.editToken;
- EventGroup.findOne({
- id: req.params.eventGroupID,
- })
- .then((eventGroup) => {
- if (eventGroup.editToken === submittedEditToken) {
- // Token matches
-
- // If there is a new image, upload that first
- let eventGroupID = req.params.eventGroupID;
- let eventGroupImageFilename = eventGroup.image;
- if (req.files && Object.keys(req.files).length !== 0) {
- let eventImageBuffer = req.files.eventGroupImageUpload.data;
- Jimp.read(eventImageBuffer, (err, img) => {
- if (err) throw err;
- img.resize(920, Jimp.AUTO) // resize
- .quality(80) // set JPEG
- .write("./public/events/" + eventGroupID + ".jpg"); // save
- });
- eventGroupImageFilename = eventGroupID + ".jpg";
- }
- const updatedEventGroup = {
- name: req.body.eventGroupName,
- description: req.body.eventGroupDescription,
- url: req.body.eventGroupURL,
- hostName: req.body.hostName,
- image: eventGroupImageFilename,
- };
- EventGroup.findOneAndUpdate(
- { id: req.params.eventGroupID },
- updatedEventGroup,
- function (err, raw) {
- if (err) {
- addToLog(
- "editEventGroup",
- "error",
- "Attempt to edit event group " +
- req.params.eventGroupID +
- " failed with error: " +
- err,
- );
- res.send(err);
- }
- },
- )
- .then(() => {
- addToLog(
- "editEventGroup",
- "success",
- "Event group " +
- req.params.eventGroupID +
- " edited",
- );
- res.writeHead(302, {
- Location:
- "/group/" +
- req.params.eventGroupID +
- "?e=" +
- req.params.editToken,
- });
- res.end();
- })
- .catch((err) => {
- console.error(err);
- res.send("Sorry! Something went wrong!");
- addToLog(
- "editEventGroup",
- "error",
- "Attempt to edit event group " +
- req.params.eventGroupID +
- " failed with error: " +
- err,
- );
- });
- } else {
- // Token doesn't match
- res.send("Sorry! Something went wrong");
- addToLog(
- "editEventGroup",
- "error",
- "Attempt to edit event group " +
- req.params.eventGroupID +
- " failed with error: token does not match",
- );
- }
- })
- .catch((err) => {
- console.error(err);
- res.send("Sorry! Something went wrong!");
- addToLog(
- "editEventGroup",
- "error",
- "Attempt to edit event group " +
- req.params.eventGroupID +
- " failed with error: " +
- err,
- );
- });
-});
-
router.post("/deleteimage/:eventID/:editToken", (req, res) => {
let submittedEditToken = req.params.editToken;
+ let eventImage;
Event.findOne({
id: req.params.eventID,
}).then((event) => {
@@ -1652,7 +352,7 @@ router.post("/deleteevent/:eventID/:editToken", (req, res) => {
attendeeEmails,
);
req.app.get("hbsInstance").renderView(
- "./views/emails/deleteevent.handlebars",
+ "./views/emails/deleteEvent/deleteEventHtml.handlebars",
{
siteName,
siteLogo,
@@ -1999,7 +699,7 @@ router.post("/attendevent/:eventID", async (req, res) => {
if (sendEmails) {
if (req.body.attendeeEmail) {
req.app.get("hbsInstance").renderView(
- "./views/emails/addeventattendee.handlebars",
+ "./views/emails/addEventAttendee/addEventAttendeeHtml.handlebars",
{
eventID: req.params.eventID,
siteName,
@@ -2075,7 +775,7 @@ router.post("/unattendevent/:eventID", (req, res) => {
if (sendEmails) {
if (req.body.attendeeEmail) {
req.app.get("hbsInstance").renderView(
- "./views/emails/unattendevent.handlebars",
+ "./views/emails/unattendEvent/unattendEventHtml.handlebars",
{
eventID: req.params.eventID,
siteName,
@@ -2157,7 +857,7 @@ router.get("/oneclickunattendevent/:eventID/:attendeeID", (req, res) => {
// currently this is never called because we don't have the email address
if (req.body.attendeeEmail) {
req.app.get("hbsInstance").renderView(
- "./views/emails/removeeventattendee.handlebars",
+ "./views/emails/removeEventAttendee/removeEventAttendeeHtml.handlebars",
{
eventName: req.params.eventName,
siteName,
@@ -2229,7 +929,7 @@ router.post("/removeattendee/:eventID/:attendeeID", (req, res) => {
// currently this is never called because we don't have the email address
if (req.body.attendeeEmail) {
req.app.get("hbsInstance").renderView(
- "./views/emails/removeeventattendee.handlebars",
+ "./views/emails/removeEventAttendee/removeEventAttendeeHtml.handlebars",
{
eventName: req.params.eventName,
siteName,
@@ -2308,7 +1008,7 @@ router.post("/subscribe/:eventGroupID", (req, res) => {
eventGroup.save();
if (sendEmails) {
req.app.get("hbsInstance").renderView(
- "./views/emails/subscribed.handlebars",
+ "./views/emails/subscribed/subscribedHtml.handlebars",
{
eventGroupName: eventGroup.name,
eventGroupID: eventGroup.id,
@@ -2451,7 +1151,7 @@ router.post("/post/comment/:eventID", (req, res) => {
"Sending emails to: " + attendeeEmails,
);
req.app.get("hbsInstance").renderView(
- "./views/emails/addeventcomment.handlebars",
+ "./views/emails/addEventComment/addEventCommentHtml.handlebars",
{
siteName,
siteLogo,
@@ -2583,7 +1283,7 @@ router.post("/post/reply/:eventID/:commentID", (req, res) => {
"Sending emails to: " + attendeeEmails,
);
req.app.get("hbsInstance").renderView(
- "./views/emails/addeventcomment.handlebars",
+ "./views/emails/addEventComment/addEventCommentHtml.handlebars",
{
siteName,
siteLogo,