diff --git a/server/index.js b/server/index.js
index 85b2052..417d95d 100644
--- a/server/index.js
+++ b/server/index.js
@@ -737,12 +737,120 @@ router.get('/pledges', async (req, res) => {
})
})
+router.get('/back-out', async (req, res) => {
+ if (DEBUG) console.debug('Backing out:', req.query)
+
+ // unpack verification link (unless it's expired)
+ let serialiser = makeSerialiser(req.query.email)
+ let staySubscribed
+
+ try {
+ // we allow them a month to do this
+ staySubscribed = serialiser.loads(req.query.key, 60 * 60 * 24 * 30)
+
+ // clean up the variable
+ if (staySubscribed == 'yes' || staySubscribed == 'true') {
+ staySubscribed = true
+ } else {
+ staySubscribed = false
+ }
+ } catch(e) {
+ if (e.name == 'SignatureExpired') {
+
+ let output = await twing.render('error.htm.twig', {
+ error: "It looks like you've clicked on the link of a very old email! Nothing lasts forever, including verification links, so if you're having trouble please contact editors@snipettemag.com. Sorry for the inconvenience 🙁",
+ })
+
+ } else {
+
+ let output = await twing.render('error.htm.twig', {
+ error: "An unknown error occurred, and our robots can't figure out what it is. Please contact editors@snipettemag.com for help. Sorry for the inconvenience 🤦",
+ })
+
+ }
+
+ res.send(output)
+ return
+ }
+
+ // now that we've got past that check...
+ let pledge
+ try {
+ pledge = await (Pledge
+ .query({
+ where: {
+ 'email': req.query.email,
+ },
+ })
+ .orderBy('created_at', 'DESC')
+ .fetch())
+ } catch(e) {
+ if (e.name == 'EmptyResponse') {
+ let output = await twing.render('error.htm.twig', {
+ error: "That pledge was not found in our records. Are you sure you made it? 🔎",
+ })
+
+ res.send(output)
+ return
+ } else {
+
+ let output = await twing.render('error.htm.twig', {
+ error: "An unknown error occurred, and we can't figure out what it is. Please contact editors@snipettemag.com for help (we're guessing you're trying to unsubscribe, in which case we'll handle it immediately upon receiving your email). Sorry for the inconvenience 🤦",
+ })
+
+ res.send(output)
+ return
+ }
+ }
+
+ // update settings for our new pledge
+ pledge.set('backed_out', true)
+ pledge.set('unsubscribed', !staySubscribed)
+
+ // save the new pledge
+
+ await pledge.save()
+
+ // send the confirmation email
+ let text = `Hi ${pledge.get('name')},
+We have received your back-out request for your pledge of ${Number(pledge.get('amount')).toLocaleString('en-IN')}${pledge.get('overseas') ? ' (plus $25 for shipping)' : ''}. We have removed you from our list and you will receive no further emails regarding collecting your contribution.${staySubscribed ? ' However, you will still receive general crowdfunding updates and are welcome to join back again later.' : ''}
+
+If you think this was a mistake, please reply to this email and one of us will get back to you.
+
+We realise that some people may want to continue supporting Snipette even if it doesn't make sense for them to go with the original pledge. You are always welcome to subscribe directly at: https://snipettemag.com/subscribe/
+
+Thank you for your support so far, and apologies for the fact that it didn't work out quite as expected this time.
+
+Thanks,
+The Snipette Team`
+
+ // to make things snappier, we won't `await` for the sending to finish
+ let receipt = sendMail({
+ to: pledge.get('email'),
+ subject: 'Pledge withdrawn from Snipette crowdfunding',
+ text: text,
+ })
+
+ // Send confirmation message
+ res.redirect('/bye')
+})
+
+router.get('/bye', async (req, res) => {
+
+ let output = await twing.render('bye.htm.twig', {})
+
+ res.send(output)
+ return
+})
+
router.use(express.static('src/assets'))
// start the listener!
-app.listen(port, () => {
- console.log(`Server is up at port ${port}`)
-})
+if (!module.parent) {
+ app.listen(port, () => {
+ console.log(`Server is up at port ${port}`)
+ })
+}
// end note: in case we want to import this somewhere for testing
module.exports = {