diff options
| author | Gavin Mogan <git@gavinmogan.com> | 2025-04-23 15:06:54 -0700 | 
|---|---|---|
| committer | Gavin Mogan <git@gavinmogan.com> | 2025-04-23 15:30:37 -0700 | 
| commit | aace2c7e6ccb6e74df83faac74c427d43bfaf79b (patch) | |
| tree | 72853ba15eae2c1ec46afc0dbf62fe2c0b4550cf | |
| parent | a9a33edbd90f8eb7a011ec839994fb07f084bd8b (diff) | |
Fix ReferenceError: nodemailerTransporter is not defined
Part of https://github.com/lowercasename/gathio/pull/200 was migrating
more code to use the shared init email function, but all the local
usages of nodemailerTransporter were missed
| -rwxr-xr-x | src/app.ts | 39 | ||||
| -rw-r--r-- | src/lib/email.ts | 57 | ||||
| -rw-r--r-- | src/lib/handlebars.ts | 27 | ||||
| -rwxr-xr-x | src/routes.js | 568 | ||||
| -rw-r--r-- | src/routes/frontend.ts | 5 | 
5 files changed, 302 insertions, 394 deletions
@@ -15,16 +15,28 @@ import {      activityPubContentType,      alternateActivityPubContentType,  } from "./lib/activitypub.js"; +import getConfig from "./lib/config.js";  const app = express(); +const config = getConfig(); -app.locals.sendEmails = initEmailService(); +initEmailService().then((sendEmails) => (app.locals.sendEmails = sendEmails));  // View engine //  const hbsInstance = hbs.create({      defaultLayout: "main",      partialsDir: ["views/partials/"],      layoutsDir: "views/layouts/", +    runtimeOptions: { +        data: { +            domain: config.general.domain, +            contactEmail: config.general.email, +            siteName: config.general.site_name, +            mailService: config.general.mail_service, +            siteLogo: config.general.email_logo_url, +            isFederated: config.general.is_federated || true, +        }, +    },      helpers: {          plural: function (number: number, text: string) {              var singular = number === 1; @@ -46,6 +58,31 @@ const hbsInstance = hbs.create({          },      },  }); +app.locals.renderEmail = async function renderEmail( +    template: string, +    data: object +) { +    const [html, text] = await Promise.all([ +        hbsInstance.renderView( +            `./views/emails/${template}Html.handlebars`, +            { +                cache: true, +                layout: "email.handlebars", +                ...data, +            } +        ), +        hbsInstance.renderView( +            `./views/emails/${template}Text.handlebars`, +            { +                cache: true, +                layout: "email.handlebars", +                ...data, +            } +        ), +    ]); +    return { html, text } +} +  app.engine("handlebars", hbsInstance.engine);  app.set("view engine", "handlebars");  app.set("hbsInstance", hbsInstance); diff --git a/src/lib/email.ts b/src/lib/email.ts index 7b7a7a1..e7243aa 100644 --- a/src/lib/email.ts +++ b/src/lib/email.ts @@ -1,10 +1,10 @@ -import { Request } from "express";  import sgMail from "@sendgrid/mail";  import nodemailer, { Transporter } from "nodemailer";  import { getConfig } from "./config.js";  import SMTPTransport from "nodemailer/lib/smtp-transport/index.js";  import { exitWithError } from "./process.js";  import { renderTemplate } from "./handlebars.js"; +import { ExpressHandlebars } from "express-handlebars";  const config = getConfig();  type EmailTemplate = @@ -36,10 +36,12 @@ export const initEmailService = async (): Promise<boolean> => {              sgMail.setApiKey(config.sendgrid.api_key);              console.log("Sendgrid is ready to send emails.");              return true; -        case "nodemailer": -            let nodemailerTransporter:Transporter|undefined = undefined; +        case "nodemailer": { +            let nodemailerTransporter: Transporter | undefined = undefined;              if (config.nodemailer?.smtp_url) { -                nodemailerTransporter = nodemailer.createTransport(config.nodemailer?.smtp_url); +                nodemailerTransporter = nodemailer.createTransport( +                    config.nodemailer?.smtp_url, +                );              } else {                  if (                      !config.nodemailer?.smtp_server || @@ -52,7 +54,7 @@ export const initEmailService = async (): Promise<boolean> => {                  const nodemailerConfig = {                      host: config.nodemailer?.smtp_server,                      port: Number(config.nodemailer?.smtp_port) || 587, -                    tls: {  +                    tls: {                          // do not fail on invalid certs                          rejectUnauthorized: false,                      }, @@ -61,10 +63,11 @@ export const initEmailService = async (): Promise<boolean> => {                  if (config.nodemailer?.smtp_username) {                      nodemailerConfig.auth = {                          user: config.nodemailer?.smtp_username, -                        pass: config.nodemailer?.smtp_password +                        pass: config.nodemailer?.smtp_password,                      };                  } -                nodemailerTransporter = nodemailer.createTransport(nodemailerConfig); +                nodemailerTransporter = +                    nodemailer.createTransport(nodemailerConfig);              }              const nodemailerVerified = await nodemailerTransporter.verify(); @@ -76,6 +79,7 @@ export const initEmailService = async (): Promise<boolean> => {                      "Error verifying Nodemailer transporter. Please check your Nodemailer configuration.",                  );              } +        }          case "none":          default:              console.warn( @@ -85,10 +89,34 @@ export const initEmailService = async (): Promise<boolean> => {      }  }; -export const sendEmail = async ( +export const sendTemplatedEmail = async ( +    hbs: ExpressHandlebars,      to: string,      bcc: string,      subject: string, +    template: string, +    data: object, +): Promise<boolean> => { +    const [html, text] = await Promise.all([ +        hbs.renderView(`./views/emails/${template}Html.handlebars`, { +            cache: true, +            layout: "email.handlebars", +            ...data, +        }), +        hbs.renderView(`./views/emails/${template}Text.handlebars`, { +            cache: true, +            layout: "email.handlebars", +            ...data, +        }), +    ]); + +    return await sendEmail(to, bcc, subject, text, html); +}; + +export const sendEmail = async ( +    to: string | string[], +    bcc: string | string[] | undefined, +    subject: string,      text: string,      html?: string,  ): Promise<boolean> => { @@ -104,7 +132,7 @@ export const sendEmail = async (                      html,                  });                  return true; -            } catch (e: any) { +            } catch (e: Error) {                  if (e.response) {                      console.error(e.response.body);                  } else { @@ -114,9 +142,11 @@ export const sendEmail = async (              }          case "nodemailer":              try { -                let nodemailerTransporter:Transporter|undefined = undefined; +                let nodemailerTransporter: Transporter | undefined = undefined;                  if (config.nodemailer?.smtp_url) { -                    nodemailerTransporter = nodemailer.createTransport(config.nodemailer?.smtp_url); +                    nodemailerTransporter = nodemailer.createTransport( +                        config.nodemailer?.smtp_url, +                    );                  } else {                      const nodemailerConfig = {                          host: config.nodemailer?.smtp_server, @@ -126,11 +156,12 @@ export const sendEmail = async (                      if (config.nodemailer?.smtp_username) {                          nodemailerConfig.auth = {                              user: config.nodemailer?.smtp_username, -                            pass: config.nodemailer?.smtp_password +                            pass: config.nodemailer?.smtp_password,                          };                      } -                    nodemailerTransporter = nodemailer.createTransport(nodemailerConfig); +                    nodemailerTransporter = +                        nodemailer.createTransport(nodemailerConfig);                  }                  await nodemailerTransporter.sendMail({                      envelope: { diff --git a/src/lib/handlebars.ts b/src/lib/handlebars.ts index d5a8b6e..42f8010 100644 --- a/src/lib/handlebars.ts +++ b/src/lib/handlebars.ts @@ -1,4 +1,5 @@  import { Request } from "express"; +import { ExpressHandlebars } from "express-handlebars";  export const renderTemplate = async (      req: Request, @@ -21,3 +22,29 @@ export const renderTemplate = async (              );      });  }; + +export const renderEmail = async ( +    hbsInstance: ExpressHandlebars, +    templateName: string, +    data: Record<string, unknown>, +): Promise<{ html: string, text: string }> => { +    const [html, text] = await Promise.all([ +        hbsInstance.renderView( +            `./views/emails/${templateName}Html.handlebars`, +            { +                cache: true, +                layout: "email.handlebars", +                ...data, +            } +        ), +        hbsInstance.renderView( +            `./views/emails/${templateName}Text.handlebars`, +            { +                cache: true, +                layout: "email.handlebars", +                ...data, +            } +        ), +    ]); +    return { html, text } +} diff --git a/src/routes.js b/src/routes.js index e758e6b..f609f94 100755 --- a/src/routes.js +++ b/src/routes.js @@ -19,12 +19,13 @@ import {      broadcastDeleteMessage,      processInbox,  } from "./activitypub.js"; +import { renderEmail } from "./lib/handlebars.js";  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"; -import { initEmailService } from "./lib/email.js"; +import { initEmailService, sendEmail } from "./lib/email.js";  const config = getConfig();  const domain = config.general.domain; @@ -44,9 +45,7 @@ const nanoid = customAlphabet(  const router = express.Router();  let sendEmails = false; -initEmailService().then((emailService) => { -    sendEmails = emailService -}); +initEmailService().then((emailService) => (sendEmails = emailService));  router.use(fileUpload()); @@ -58,7 +57,10 @@ schedule.scheduleJob("59 23 * * *", function (fireDate) {          return;      } -    const too_old = moment.tz("Etc/UTC").subtract(deleteAfterDays, "days").toDate(); +    const too_old = moment +        .tz("Etc/UTC") +        .subtract(deleteAfterDays, "days") +        .toDate();      console.log(          "Old event deletion running! Deleting all events concluding before ",          too_old, @@ -81,9 +83,9 @@ schedule.scheduleJob("59 23 * * *", function (fireDate) {                                  "deleteOldEvents",                                  "error",                                  "Attempt to delete old event " + -                                id + -                                " failed with error: " + -                                err, +                                    id + +                                    " failed with error: " + +                                    err,                              );                          });                  }; @@ -100,9 +102,9 @@ schedule.scheduleJob("59 23 * * *", function (fireDate) {                                      "deleteOldEvents",                                      "error",                                      "Attempt to delete event image for old event " + -                                    event.id + -                                    " failed with error: " + -                                    err, +                                        event.id + +                                        " failed with error: " + +                                        err,                                  );                              }                              // Image removed @@ -149,9 +151,9 @@ schedule.scheduleJob("59 23 * * *", function (fireDate) {                  "deleteOldEvents",                  "error",                  "Attempt to delete old event " + -                event.id + -                " failed with error: " + -                err, +                    event.id + +                    " failed with error: " + +                    err,              );          }); @@ -204,9 +206,9 @@ router.post("/deleteimage/:eventID/:editToken", (req, res) => {                              "deleteEventImage",                              "error",                              "Attempt to delete event image for event " + -                            req.params.eventID + -                            " failed with error: " + -                            err, +                                req.params.eventID + +                                " failed with error: " + +                                err,                          );                      }                      // Image removed @@ -227,9 +229,9 @@ router.post("/deleteimage/:eventID/:editToken", (req, res) => {                                  "deleteEventImage",                                  "error",                                  "Attempt to delete event image for event " + -                                req.params.eventID + -                                " failed with error: " + -                                err, +                                    req.params.eventID + +                                    " failed with error: " + +                                    err,                              );                          });                  }, @@ -271,9 +273,9 @@ router.post("/deleteevent/:eventID/:editToken", (req, res) => {                                          "deleteEvent",                                          "error",                                          "Attempt to delete event " + -                                        req.params.eventID + -                                        " failed with error: " + -                                        err, +                                            req.params.eventID + +                                            " failed with error: " + +                                            err,                                      );                                  }                              }, @@ -293,9 +295,9 @@ router.post("/deleteevent/:eventID/:editToken", (req, res) => {                                                      "deleteEvent",                                                      "error",                                                      "Attempt to delete event image for event " + -                                                    req.params.eventID + -                                                    " failed with error: " + -                                                    err, +                                                        req.params.eventID + +                                                        " failed with error: " + +                                                        err,                                                  );                                              }                                              // Image removed @@ -303,8 +305,8 @@ router.post("/deleteevent/:eventID/:editToken", (req, res) => {                                                  "deleteEvent",                                                  "success",                                                  "Event " + -                                                req.params.eventID + -                                                " deleted", +                                                    req.params.eventID + +                                                    " deleted",                                              );                                          },                                      ); @@ -316,63 +318,29 @@ router.post("/deleteevent/:eventID/:editToken", (req, res) => {                                  // Send emails here otherwise they don't exist lol                                  if (sendEmails) { -                                    const attendeeEmails = event.attendees -                                        .filter( +                                    const attendeeEmails = event?.attendees?.filter(                                              (o) =>                                                  o.status === "attending" &&                                                  o.email,                                          ) -                                        .map((o) => o.email); +                                        .map((o) => o.email || '') || [];                                      if (attendeeEmails.length) {                                          console.log(                                              "Sending emails to: " + -                                            attendeeEmails, +                                                attendeeEmails,                                          ); -                                        req.app.get("hbsInstance").renderView( -                                            "./views/emails/deleteEvent/deleteEventHtml.handlebars", +                                        renderEmail( +                                            req.app.get("hbsInstance"), +                                            "deleteEvent/deleteEvent",                                              { -                                                siteName, -                                                siteLogo, -                                                domain, -                                                eventName: event.name, -                                                cache: true, -                                                layout: "email.handlebars", +                                                eventName: event?.name,                                              }, -                                            function (err, html) { -                                                const msg = { -                                                    to: attendeeEmails, -                                                    from: contactEmail, -                                                    subject: `${siteName}: ${event.name} was deleted`, -                                                    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; -                                                } -                                            }, -                                        ); +                                        ).then( +                                            ({ html, text }) => sendEmail(attendeeEmails, '', `${siteName}: ${event?.name} was deleted`, text, html) +                                        ).catch((e) => { +                                            console.error('error sending attendy email', e.toString()); +                                            res.status(500).end(); +                                        });                                      } else {                                          console.log("Nothing to send!");                                      } @@ -381,15 +349,15 @@ router.post("/deleteevent/:eventID/:editToken", (req, res) => {                              .catch((err) => {                                  res.send(                                      "Sorry! Something went wrong (error deleting): " + -                                    err, +                                        err,                                  );                                  addToLog(                                      "deleteEvent",                                      "error",                                      "Attempt to delete event " + -                                    req.params.eventID + -                                    " failed with error: " + -                                    err, +                                        req.params.eventID + +                                        " failed with error: " + +                                        err,                                  );                              });                      }, @@ -401,8 +369,8 @@ router.post("/deleteevent/:eventID/:editToken", (req, res) => {                      "deleteEvent",                      "error",                      "Attempt to delete event " + -                    req.params.eventID + -                    " failed with error: token does not match", +                        req.params.eventID + +                        " failed with error: token does not match",                  );              }          }) @@ -412,9 +380,9 @@ router.post("/deleteevent/:eventID/:editToken", (req, res) => {                  "deleteEvent",                  "error",                  "Attempt to delete event " + -                req.params.eventID + -                " failed with error: " + -                err, +                    req.params.eventID + +                    " failed with error: " + +                    err,              );          });  }); @@ -447,9 +415,9 @@ router.post("/deleteeventgroup/:eventGroupID/:editToken", (req, res) => {                                  "deleteEventGroup",                                  "error",                                  "Attempt to delete event group " + -                                req.params.eventGroupID + -                                " failed with error: " + -                                err, +                                    req.params.eventGroupID + +                                    " failed with error: " + +                                    err,                              );                          }                      }, @@ -469,9 +437,9 @@ router.post("/deleteeventgroup/:eventGroupID/:editToken", (req, res) => {                                              "deleteEventGroup",                                              "error",                                              "Attempt to delete event image for event group " + -                                            req.params.eventGroupID + -                                            " failed with error: " + -                                            err, +                                                req.params.eventGroupID + +                                                " failed with error: " + +                                                err,                                          );                                      }                                  }, @@ -487,8 +455,8 @@ router.post("/deleteeventgroup/:eventGroupID/:editToken", (req, res) => {                                      "deleteEventGroup",                                      "success",                                      "Event group " + -                                    req.params.eventGroupID + -                                    " deleted", +                                        req.params.eventGroupID + +                                        " deleted",                                  );                                  res.writeHead(302, {                                      Location: "/", @@ -498,30 +466,30 @@ router.post("/deleteeventgroup/:eventGroupID/:editToken", (req, res) => {                              .catch((err) => {                                  res.send(                                      "Sorry! Something went wrong (error deleting): " + -                                    err, +                                        err,                                  );                                  addToLog(                                      "deleteEventGroup",                                      "error",                                      "Attempt to delete event group " + -                                    req.params.eventGroupID + -                                    " failed with error: " + -                                    err, +                                        req.params.eventGroupID + +                                        " failed with error: " + +                                        err,                                  );                              });                      })                      .catch((err) => {                          res.send(                              "Sorry! Something went wrong (error deleting): " + -                            err, +                                err,                          );                          addToLog(                              "deleteEventGroup",                              "error",                              "Attempt to delete event group " + -                            req.params.eventGroupID + -                            " failed with error: " + -                            err, +                                req.params.eventGroupID + +                                " failed with error: " + +                                err,                          );                      });              } else { @@ -531,8 +499,8 @@ router.post("/deleteeventgroup/:eventGroupID/:editToken", (req, res) => {                      "deleteEventGroup",                      "error",                      "Attempt to delete event group " + -                    req.params.eventGroupID + -                    " failed with error: token does not match", +                        req.params.eventGroupID + +                        " failed with error: token does not match",                  );              }          }) @@ -542,9 +510,9 @@ router.post("/deleteeventgroup/:eventGroupID/:editToken", (req, res) => {                  "deleteEventGroup",                  "error",                  "Attempt to delete event group " + -                req.params.eventGroupID + -                " failed with error: " + -                err, +                    req.params.eventGroupID + +                    " failed with error: " + +                    err,              );          });  }); @@ -562,9 +530,9 @@ router.post("/attendee/provision", async (req, res) => {              "provisionEventAttendee",              "error",              "Attempt to provision attendee in event " + -            req.query.eventID + -            " failed with error: " + -            e, +                req.query.eventID + +                " failed with error: " + +                e,          );          return res.sendStatus(500);      }); @@ -580,9 +548,9 @@ router.post("/attendee/provision", async (req, res) => {              "provisionEventAttendee",              "error",              "Attempt to provision attendee in event " + -            req.query.eventID + -            " failed with error: " + -            e, +                req.query.eventID + +                " failed with error: " + +                e,          );          return res.sendStatus(500);      }); @@ -618,9 +586,9 @@ router.post("/attendevent/:eventID", async (req, res) => {              "attendEvent",              "error",              "Attempt to attend event " + -            req.params.eventID + -            " failed with error: " + -            e, +                req.params.eventID + +                " failed with error: " + +                e,          );          return res.sendStatus(500);      }); @@ -659,7 +627,9 @@ router.post("/attendevent/:eventID", async (req, res) => {                  "attendees.$.name": req.body.attendeeName,                  "attendees.$.email": req.body.attendeeEmail,                  "attendees.$.number": req.body.attendeeNumber, -                "attendees.$.visibility": !!req.body.attendeeVisible ? "public" : "private", +                "attendees.$.visibility": req.body.attendeeVisible +                    ? "public" +                    : "private",              },          },      ) @@ -670,44 +640,23 @@ router.post("/attendevent/:eventID", async (req, res) => {                  "Attendee added to event " + req.params.eventID,              );              if (sendEmails) { -                if (req.body.attendeeEmail) { -                    req.app.get("hbsInstance").renderView( -                        "./views/emails/addEventAttendee/addEventAttendeeHtml.handlebars", +                if (req.body.attendeeEmail) {           +                    renderEmail( +                        req.app.get("hbsInstance"), +                        "addEventAttendee/addEventAttendee",                          {                              eventID: req.params.eventID, -                            siteName, -                            siteLogo, -                            domain,                              removalPassword: req.body.removalPassword, -                            removalPasswordHash: hashString(req.body.removalPassword), -                            cache: true, -                            layout: "email.handlebars", -                        }, -                        function (err, html) { -                            const msg = { -                                to: req.body.attendeeEmail, -                                from: contactEmail, -                                subject: `${siteName}: You're RSVPed to ${event.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; -                            } +                            removalPasswordHash: hashString( +                                req.body.removalPassword, +                            ),                          }, -                    ); +                    ).then( +                        ({ html, text }) => sendEmail(req.body.attendeeEmail, '', `${siteName}: You're RSVPed to ${event.name}`, text, html) +                    ).catch((e) => { +                        console.error('error sending addEventAttendee email', e.toString()); +                        res.status(500).end(); +                    });                  }              }              res.redirect(`/${req.params.eventID}`); @@ -718,9 +667,9 @@ router.post("/attendevent/:eventID", async (req, res) => {                  "addEventAttendee",                  "error",                  "Attempt to add attendee to event " + -                req.params.eventID + -                " failed with error: " + -                error, +                    req.params.eventID + +                    " failed with error: " + +                    error,              );          });  }); @@ -750,40 +699,18 @@ router.get("/oneclickunattendevent/:eventID/:attendeeID", (req, res) => {              if (sendEmails) {                  // 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/removeEventAttendeeHtml.handlebars", +                    renderEmail( +                        req.app.get("hbsInstance"), +                        "removeEventAttendee/removeEventAttendee",                          {                              eventName: req.params.eventName, -                            siteName, -                            domain, -                            cache: true, -                            layout: "email.handlebars",                          }, -                        function (err, html) { -                            const msg = { -                                to: req.body.attendeeEmail, -                                from: contactEmail, -                                subject: `${siteName}: You have been removed from an event`, -                                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; -                            } -                        }, -                    ); +                    ).then( +                        ({ html, text }) => sendEmail(req.body.attendeeEmail, '', `${siteName}: You have been removed from an event`, text, html) +                    ).catch((e) => { +                        console.error('error sending removeEventAttendeeHtml email', e.toString()); +                        res.status(500).end(); +                    });                  }              }              res.writeHead(302, { @@ -797,9 +724,9 @@ router.get("/oneclickunattendevent/:eventID/:attendeeID", (req, res) => {                  "removeEventAttendee",                  "error",                  "Attempt to remove attendee by admin from event " + -                req.params.eventID + -                " failed with error: " + -                err, +                    req.params.eventID + +                    " failed with error: " + +                    err,              );          });  }); @@ -818,41 +745,18 @@ router.post("/removeattendee/:eventID/:attendeeID", (req, res) => {              if (sendEmails) {                  // 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/removeEventAttendeeHtml.handlebars", +                    renderEmail( +                        req.app.get("hbsInstance"), +                        "removeEventAttendee/removeEventAttendee",                          {                              eventName: req.params.eventName, -                            siteName, -                            siteLogo, -                            domain, -                            cache: true, -                            layout: "email.handlebars", -                        }, -                        function (err, html) { -                            const msg = { -                                to: req.body.attendeeEmail, -                                from: contactEmail, -                                subject: `${siteName}: You have been removed from an event`, -                                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; -                            }                          }, -                    ); +                    ).then( +                        ({ html, text }) => sendEmail(req.body.attendeeEmail, '', `${siteName}: You have been removed from an event`, text, html) +                    ).catch((e) => { +                        console.error('error sending removeEventAttendeeHtml email', e.toString()); +                        res.status(500).end();                   +                    });                  }              }              res.writeHead(302, { @@ -866,9 +770,9 @@ router.post("/removeattendee/:eventID/:attendeeID", (req, res) => {                  "removeEventAttendee",                  "error",                  "Attempt to remove attendee by admin from event " + -                req.params.eventID + -                " failed with error: " + -                err, +                    req.params.eventID + +                    " failed with error: " + +                    err,              );          });  }); @@ -894,43 +798,20 @@ router.post("/subscribe/:eventGroupID", (req, res) => {              eventGroup.subscribers.push(subscriber);              eventGroup.save();              if (sendEmails) { -                req.app.get("hbsInstance").renderView( -                    "./views/emails/subscribed/subscribedHtml.handlebars", +                renderEmail( +                    req.app.get("hbsInstance"), +                    "subscribed/subscribed",                      {                          eventGroupName: eventGroup.name,                          eventGroupID: eventGroup.id,                          emailAddress: encodeURIComponent(subscriber.email), -                        siteName, -                        siteLogo, -                        domain, -                        cache: true, -                        layout: "email.handlebars",                      }, -                    function (err, html) { -                        const msg = { -                            to: subscriber.email, -                            from: contactEmail, -                            subject: `${siteName}: You have subscribed to an event group`, -                            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; -                        } -                    }, -                ); +                ).then( +                    ({ html, text }) => sendEmail(subscriber.email, '', `${siteName}: You have subscribed to an event group`, text, html) +                ).catch((e) => { +                    console.error('error sending removeEventAttendeeHtml email', e.toString()); +                    res.status(500).end();                   +                });              }              return res.redirect(`/group/${eventGroup.id}`);          }) @@ -939,11 +820,11 @@ router.post("/subscribe/:eventGroupID", (req, res) => {                  "addSubscription",                  "error",                  "Attempt to subscribe " + -                req.body.emailAddress + -                " to event group " + -                req.params.eventGroupID + -                " failed with error: " + -                error, +                    req.body.emailAddress + +                    " to event group " + +                    req.params.eventGroupID + +                    " failed with error: " + +                    error,              );              return res.sendStatus(500);          }); @@ -970,11 +851,11 @@ router.get("/unsubscribe/:eventGroupID", (req, res) => {                  "removeSubscription",                  "error",                  "Attempt to unsubscribe " + -                req.query.email + -                " from event group " + -                req.params.eventGroupID + -                " failed with error: " + -                error, +                    req.query.email + +                    " from event group " + +                    req.params.eventGroupID + +                    " failed with error: " + +                    error,              );              return res.sendStatus(500);          }); @@ -1028,58 +909,24 @@ router.post("/post/comment/:eventID", (req, res) => {                                          (o) =>                                              o.status === "attending" && o.email,                                      ) -                                    .map((o) => o.email); +                                    .map((o) => o.email || '')  || [];                                  if (attendeeEmails.length) {                                      console.log(                                          "Sending emails to: " + attendeeEmails,                                      ); -                                    req.app.get("hbsInstance").renderView( -                                        "./views/emails/addEventComment/addEventCommentHtml.handlebars", +                                    renderEmail( +                                        req.app.get("hbsInstance"), +                                        "addEventComment/addEventComment",                                          { -                                            siteName, -                                            siteLogo, -                                            domain,                                              eventID: req.params.eventID, -                                            commentAuthor: -                                                req.body.commentAuthor, -                                            cache: true, -                                            layout: "email.handlebars", -                                        }, -                                        function (err, html) { -                                            const msg = { -                                                to: attendeeEmails, -                                                from: contactEmail, -                                                subject: `${siteName}: New comment in ${event.name}`, -                                                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; -                                            } +                                            commentAuthor: req.body.commentAuthor,                                          }, -                                    ); +                                    ).then( +                                        ({ html, text }) => sendEmail(attendeeEmails, '', `${siteName}: New comment in ${event.name}`, text, html) +                                    ).catch((e) => { +                                        console.error('error sending removeEventAttendeeHtml email', e.toString()); +                                        res.status(500).end();                   +                                    });                                  } else {                                      console.log("Nothing to send!");                                  } @@ -1097,9 +944,9 @@ router.post("/post/comment/:eventID", (req, res) => {                          "addEventComment",                          "error",                          "Attempt to add comment to event " + -                        req.params.eventID + -                        " failed with error: " + -                        err, +                            req.params.eventID + +                            " failed with error: " + +                            err,                      );                  });          }, @@ -1130,9 +977,9 @@ router.post("/post/reply/:eventID/:commentID", (req, res) => {                          "addEventReply",                          "success",                          "Reply added to comment " + -                        commentID + -                        " in event " + -                        req.params.eventID, +                            commentID + +                            " in event " + +                            req.params.eventID,                      );                      // broadcast an identical message to all followers, will show in their home timeline                      const guidObject = crypto.randomBytes(16).toString("hex"); @@ -1157,57 +1004,24 @@ router.post("/post/reply/:eventID/:commentID", (req, res) => {                                          (o) =>                                              o.status === "attending" && o.email,                                      ) -                                    .map((o) => o.email); +                                    .map((o) => o.email || '') || [];                                  if (attendeeEmails.length) {                                      console.log(                                          "Sending emails to: " + attendeeEmails,                                      ); -                                    req.app.get("hbsInstance").renderView( -                                        "./views/emails/addEventComment/addEventCommentHtml.handlebars", +                                    renderEmail( +                                        req.app.get("hbsInstance"), +                                        "addEventComment/addEventComment",                                          { -                                            siteName, -                                            siteLogo, -                                            domain,                                              eventID: req.params.eventID,                                              commentAuthor: req.body.replyAuthor, -                                            cache: true, -                                            layout: "email.handlebars",                                          }, -                                        function (err, html) { -                                            const msg = { -                                                to: attendeeEmails, -                                                from: contactEmail, -                                                subject: `${siteName}: New comment in ${event.name}`, -                                                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; -                                            } -                                        }, -                                    ); +                                    ).then( +                                        ({ html, text }) => sendEmail(attendeeEmails, '', `${siteName}: New comment in ${event.name}`, text, html) +                                    ).catch((e) => { +                                        console.error('error sending removeEventAttendeeHtml email', e.toString()); +                                        res.status(500).end();                   +                                    });                                  } else {                                      console.log("Nothing to send!");                                  } @@ -1225,11 +1039,11 @@ router.post("/post/reply/:eventID/:commentID", (req, res) => {                          "addEventReply",                          "error",                          "Attempt to add reply to comment " + -                        commentID + -                        " in event " + -                        req.params.eventID + -                        " failed with error: " + -                        err, +                            commentID + +                            " in event " + +                            req.params.eventID + +                            " failed with error: " + +                            err,                      );                  });          }, @@ -1265,17 +1079,17 @@ router.post("/deletecomment/:eventID/:commentID/:editToken", (req, res) => {                      .catch((err) => {                          res.send(                              "Sorry! Something went wrong (error deleting): " + -                            err, +                                err,                          );                          addToLog(                              "deleteComment",                              "error",                              "Attempt to delete comment " + -                            req.params.commentID + -                            "from event " + -                            req.params.eventID + -                            " failed with error: " + -                            err, +                                req.params.commentID + +                                "from event " + +                                req.params.eventID + +                                " failed with error: " + +                                err,                          );                      });              } else { @@ -1285,10 +1099,10 @@ router.post("/deletecomment/:eventID/:commentID/:editToken", (req, res) => {                      "deleteComment",                      "error",                      "Attempt to delete comment " + -                    req.params.commentID + -                    "from event " + -                    req.params.eventID + -                    " failed with error: token does not match", +                        req.params.commentID + +                        "from event " + +                        req.params.eventID + +                        " failed with error: token does not match",                  );              }          }) @@ -1298,11 +1112,11 @@ router.post("/deletecomment/:eventID/:commentID/:editToken", (req, res) => {                  "deleteComment",                  "error",                  "Attempt to delete comment " + -                req.params.commentID + -                "from event " + -                req.params.eventID + -                " failed with error: " + -                err, +                    req.params.commentID + +                    "from event " + +                    req.params.eventID + +                    " failed with error: " + +                    err,              );          });  }); diff --git a/src/routes/frontend.ts b/src/routes/frontend.ts index 14bb779..1b95763 100644 --- a/src/routes/frontend.ts +++ b/src/routes/frontend.ts @@ -1,5 +1,4 @@  import { Router, Request, Response } from "express"; -import fs from "fs";  import moment from "moment-timezone";  import { marked } from "marked";  import { markdownToSanitizedHTML, renderPlain } from "../util/markdown.js"; @@ -25,7 +24,7 @@ const router = Router();  // Add config middleware to all routes  router.use(getConfigMiddleware); -router.get("/", (_: Request, res: Response) => { +router.get("/", (_, res) => {      if (res.locals.config?.general.show_public_event_list) {          return res.redirect("/events");      } @@ -44,7 +43,7 @@ router.get("/about", (_: Request, res: Response) => {      });  }); -router.get("/new", (req: Request, res: Response) => { +router.get("/new", (_: Request, res: Response) => {      if (res.locals.config?.general.creator_email_addresses?.length) {          return res.render("createEventMagicLink", frontendConfig(res));      }  | 
