diff options
-rw-r--r-- | .travis.yml | 8 | ||||
-rw-r--r-- | Dockerfile | 7 | ||||
-rw-r--r-- | README.md | 4 | ||||
-rw-r--r-- | config/database-docker.js | 3 | ||||
-rw-r--r-- | config/domain-example.js | 4 | ||||
-rw-r--r-- | docker-compose.yml | 10 | ||||
-rw-r--r-- | public/images/gathio-email-logo.gif | bin | 0 -> 2198 bytes | |||
-rwxr-xr-x | routes.js | 112 | ||||
-rwxr-xr-x | test.sh | 15 | ||||
-rw-r--r-- | views/layouts/email.handlebars | 5 |
10 files changed, 110 insertions, 58 deletions
diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..cdf8b48 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,8 @@ +language: shell +os: linux + +services: + - docker + +script: + - ./test.sh
\ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..a436239 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,7 @@ +FROM node:13-alpine +WORKDIR /app +ADD package.json package-lock.json /app/ +RUN npm install +COPY . /app/ +RUN cp config/api-example.js config/api.js && cp config/domain-example.js config/domain.js && cp config/database-docker.js config/database.js +CMD npm start @@ -1,9 +1,11 @@ # gathio +[](https://travis-ci.com/lowercasename/gathio) + Self-destructing, shareable, no-registration event pages. You can use the publicly hosted version [here](https://gath.io). # Installation -See [the wiki](https://github.com/lowercasename/gathio/wiki/install) +See [the Wiki](https://github.com/lowercasename/gathio/wiki/install) for installation instructions. diff --git a/config/database-docker.js b/config/database-docker.js new file mode 100644 index 0000000..7847097 --- /dev/null +++ b/config/database-docker.js @@ -0,0 +1,3 @@ +module.exports = { + 'url' : 'mongodb://mongo:27017/gathio' // For dockerised MongoDB connection +}; diff --git a/config/domain-example.js b/config/domain-example.js index 3b77197..b84e210 100644 --- a/config/domain-example.js +++ b/config/domain-example.js @@ -3,5 +3,7 @@ module.exports = { 'domain' : 'localhost:3000' , 'port': '3000', 'email': 'contact@example.com', - 'sitename': 'gathio' + 'sitename': 'gathio', + // If left blank, this defaults to https://yourdomain.com/images/gathio-email-logo.gif. Set a full URL here to change it to your own logo (or just change the file itself) + 'logo_url': '' }; diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..d16e279 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,10 @@ +version: '3' +services: + gathio: + build: . + links: + - mongo + ports: + - 3000:3000 + mongo: + image: mongo:latest
\ No newline at end of file diff --git a/public/images/gathio-email-logo.gif b/public/images/gathio-email-logo.gif Binary files differnew file mode 100644 index 0000000..7374176 --- /dev/null +++ b/public/images/gathio-email-logo.gif @@ -27,6 +27,7 @@ const request = require('request'); const domain = require('./config/domain.js').domain; const contactEmail = require('./config/domain.js').email; const siteName = require('./config/domain.js').sitename +const siteLogo = require('./config/domain.js').logo_url; const ap = require('./activitypub.js'); // Extra marked renderer (used to render plaintext event description for page metadata) @@ -671,7 +672,7 @@ router.post('/newevent', async (req, res) => { addToLog("createEvent", "success", "Event " + eventID + "created"); // Send email with edit link if (sendEmails) { - req.app.get('hbsInstance').renderView('./views/emails/createevent.handlebars', {eventID, editToken, siteName, domain, cache: true, layout: 'email.handlebars'}, function(err, html) { + 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: { @@ -698,12 +699,10 @@ router.post('/newevent', async (req, res) => { router.post('/importevent', (req, res) => { let eventID = shortid.generate(); let editToken = randomstring.generate(); - if (req.files && Object.keys(req.files).length != 0) { - importediCalObject = ical.parseICS(req.files.icsImportControl.data.toString('utf8')); - for (var key in importediCalObject) { - importedEventData = importediCalObject[key]; - } - console.log(importedEventData) + 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 @@ -712,7 +711,7 @@ router.post('/importevent', (req, res) => { } else { res.status(500).send("Please supply an email address on the previous page."); } - + const event = new Event({ id: eventID, type: 'public', @@ -739,24 +738,24 @@ router.post('/importevent', (req, res) => { addToLog("createEvent", "success", "Event " + eventID + " created"); // Send email with edit link if (sendEmails) { - req.app.get('hbsInstance').renderView('./views/emails/createevent.handlebars', {eventID, editToken, siteName, domain, cache: true, layout: 'email.handlebars'}, function(err, html) { - const msg = { - to: req.body.creatorEmail, - from: { - name: siteName, - email: contactEmail, - }, - subject: `${siteName}: ${req.body.eventName}`, - html, - }; - sgMail.send(msg).catch(e => { - console.error(e.toString()); - res.status(500).end(); - }); - }); + 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, + }, + subject: `${siteName}: ${importedEventData.summary}`, + html, + }; + sgMail.send(msg).catch(e => { + console.error(e.toString()); + res.status(500).end(); + }); + }); } res.writeHead(302, { - 'Location': '/' + eventID + '?e=' + editToken + 'Location': '/' + eventID + '?e=' + editToken }); res.end(); }) @@ -799,7 +798,7 @@ router.post('/neweventgroup', (req, res) => { addToLog("createEventGroup", "success", "Event group " + eventGroupID + " created"); // Send email with edit link if (sendEmails) { - req.app.get('hbsInstance').renderView('./views/emails/createeventgroup.handlebars', {eventGroupID, editToken, siteName, domain, cache: true, layout: 'email.handlebars'}, function(err, html) { + 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: { @@ -953,7 +952,7 @@ router.post('/editevent/:eventID/:editToken', (req, res) => { let attendeeEmails = ids; if (!error && attendeeEmails !== ""){ console.log("Sending emails to: " + attendeeEmails); - req.app.get('hbsInstance').renderView('./views/emails/editevent.handlebars', {diffText, eventID: req.params.eventID, siteName, domain, cache: true, layout: 'email.handlebars'}, function(err, html) { + 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: { @@ -1093,6 +1092,7 @@ router.post('/deleteevent/:eventID/:editToken', (req, res) => { eventImage = event.image; } +<<<<<<< HEAD // broadcast a Delete profile message to all followers so that at least Mastodon servers will delete their local profile information const guidUpdateObject = crypto.randomBytes(16).toString('hex'); const jsonUpdateObject = JSON.parse(event.activityPubActor); @@ -1123,33 +1123,33 @@ router.post('/deleteevent/:eventID/:editToken', (req, res) => { }) .catch((err) => { res.send('Sorry! Something went wrong (error deleting): ' + err); addToLog("deleteEvent", "error", "Attempt to delete event " + req.params.eventID + " failed with error: " + err);}); }); - // send emails here otherwise they don't exist lol - if (sendEmails) { - Event.findOne({id: req.params.eventID}).distinct('attendees.email', function(error, ids) { - let attendeeEmails = ids; - if (!error){ - console.log("Sending emails to: " + attendeeEmails); - req.app.get('hbsInstance').renderView('./views/emails/deleteevent.handlebars', {siteName, domain, eventName: event.name, cache: true, layout: 'email.handlebars'}, function(err, html) { - const msg = { - to: attendeeEmails, - from: { - name: siteName, - email: contactEmail, - }, - subject: `${siteName}: ${event.name} was deleted`, - html, - }; - sgMail.sendMultiple(msg).catch(e => { - console.error(e.toString()); - res.status(500).end(); - }); + // Send emails here otherwise they don't exist lol + if (sendEmails) { + Event.findOne({id: req.params.eventID}).distinct('attendees.email', function(error, ids) { + attendeeEmails = ids; + if (!error){ + console.log("Sending emails to: " + attendeeEmails); + req.app.get('hbsInstance').renderView('./views/emails/deleteevent.handlebars', {siteName, siteLogo, domain, eventName: event.name, cache: true, layout: 'email.handlebars'}, function(err, html) { + const msg = { + to: attendeeEmails, + from: { + name: siteName, + email: contactEmail, + }, + subject: `${siteName}: ${event.name} was deleted`, + html, + }; + sgMail.sendMultiple(msg).catch(e => { + console.error(e.toString()); + res.status(500).end(); }); + }); } - else { - console.log("Nothing to send!"); - } - }); - } + else { + console.log("Nothing to send!"); + } + }); + } } else { // Token doesn't match @@ -1233,7 +1233,7 @@ router.post('/attendevent/:eventID', (req, res) => { addToLog("addEventAttendee", "success", "Attendee added to event " + req.params.eventID); if (sendEmails) { if (req.body.attendeeEmail){ - req.app.get('hbsInstance').renderView('./views/emails/addeventattendee.handlebars', {eventID: req.params.eventID, siteName, domain, cache: true, layout: 'email.handlebars'}, function(err, html) { + req.app.get('hbsInstance').renderView('./views/emails/addeventattendee.handlebars', {eventID: req.params.eventID, siteName, siteLogo, domain, cache: true, layout: 'email.handlebars'}, function(err, html) { const msg = { to: req.body.attendeeEmail, from: { @@ -1269,7 +1269,7 @@ router.post('/unattendevent/:eventID', (req, res) => { addToLog("unattendEvent", "success", "Attendee removed self from event " + req.params.eventID); if (sendEmails) { if (req.body.attendeeEmail){ - req.app.get('hbsInstance').renderView('./views/emails/unattendevent.handlebars', {eventID: req.params.eventID, siteName, domain, cache: true, layout: 'email.handlebars'}, function(err, html) { const msg = { + req.app.get('hbsInstance').renderView('./views/emails/unattendevent.handlebars', {eventID: req.params.eventID, siteName, siteLogo, domain, cache: true, layout: 'email.handlebars'}, function(err, html) { const msg = { to: req.body.attendeeEmail, from: { name: siteName, @@ -1349,7 +1349,7 @@ 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.handlebars', {eventName: req.params.eventName, siteName, domain, cache: true, layout: 'email.handlebars'}, function(err, html) { const msg = { + req.app.get('hbsInstance').renderView('./views/emails/removeeventattendee.handlebars', {eventName: req.params.eventName, siteName, siteLogo, domain, cache: true, layout: 'email.handlebars'}, function(err, html) { const msg = { to: req.body.attendeeEmail, from: { name: siteName, @@ -1409,7 +1409,7 @@ router.post('/post/comment/:eventID', (req, res) => { let attendeeEmails = ids; if (!error){ console.log("Sending emails to: " + attendeeEmails); - req.app.get('hbsInstance').renderView('./views/emails/addeventcomment.handlebars', {siteName, domain, eventID: req.params.eventID, commentAuthor: req.body.commentAuthor, cache: true, layout: 'email.handlebars'}, function(err, html) { + req.app.get('hbsInstance').renderView('./views/emails/addeventcomment.handlebars', {siteName, siteLogo, domain, eventID: req.params.eventID, commentAuthor: req.body.commentAuthor, cache: true, layout: 'email.handlebars'}, function(err, html) { const msg = { to: attendeeEmails, from: { @@ -1473,7 +1473,7 @@ router.post('/post/reply/:eventID/:commentID', (req, res) => { let attendeeEmails = ids; if (!error){ console.log("Sending emails to: " + attendeeEmails); - req.app.get('hbsInstance').renderView('./views/emails/addeventcomment.handlebars', {siteName, domain, eventID: req.params.eventID, commentAuthor: req.body.replyAuthor, cache: true, layout: 'email.handlebars'}, function(err, html) { + req.app.get('hbsInstance').renderView('./views/emails/addeventcomment.handlebars', {siteName, siteLogo, domain, eventID: req.params.eventID, commentAuthor: req.body.replyAuthor, cache: true, layout: 'email.handlebars'}, function(err, html) { const msg = { to: attendeeEmails, from: { @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +set -eux -o pipefail + +cleanup() { + docker-compose kill +} +trap cleanup 0 + +docker-compose up --build & + +while [[ "$(curl -s -o /dev/null -w "%{http_code}" http://localhost:3000/)" -ne "200" ]]; do sleep 5; done +curl -v http://localhost:3000/new/event/public + +cleanup
\ No newline at end of file diff --git a/views/layouts/email.handlebars b/views/layouts/email.handlebars index 6158ddb..2b54d6e 100644 --- a/views/layouts/email.handlebars +++ b/views/layouts/email.handlebars @@ -106,6 +106,11 @@ <td class="wrapper" style="font-family: sans-serif; font-size: 14px; vertical-align: top; box-sizing: border-box; padding: 20px;"> <table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;"> <tr> + <td style="font-family: sans-serif; font-size: 14px; vertical-align: top; text-align: right; padding-bottom: 14px;"> + <img src="{{#if siteLogo}}{{siteLogo}}{{else}}https://{{domain}}/images/gathio-email-logo.gif{{/if}}"> + </td> + </tr> + <tr> <td style="font-family: sans-serif; font-size: 14px; vertical-align: top;"> {{{ body }}} </td> |