diff --git a/server/index.js b/server/index.js index 740fb92..851e0a5 100644 --- a/server/index.js +++ b/server/index.js @@ -188,7 +188,9 @@ router.use(bodyParser.urlencoded({ })) // main views -router.get('/', async (req, res) => { + +// the home view is used in a couple of places, so we've moved it out +let homeView = async (req, res) => { if (DEBUG) console.debug('Returning home page') // count people @@ -206,6 +208,25 @@ router.get('/', async (req, res) => { ).models if (DEBUG) console.log(`Listing ${recentPledges.length} pledges`) + if (DEBUG && req.params.referralCode) console.log(`Referral code: ${req.params.referralCode}`) + + let referrer + if (req.params.referralCode) { + try { + let pledge = await (Pledge + .query({ + where: { + referral_code: req.params.referralCode, + } + }) + .fetch()) + + referrer = pledge.get('anonymous') ? 'Anonymous' : pledge.get('name') + } catch(e) { + if (DEBUG) console.debug(`Skipping referral ${req.params.referralCode} because not found: ${e}`) + } + } + twing.render('index.htm.twig', { 'goal_rupees': Number(goalRupees).toLocaleString('en-IN'), @@ -215,13 +236,117 @@ router.get('/', async (req, res) => { 'percent_rupees': `style="width: ${total_rupees/goalRupees*100}%"`, 'percent_people': `style="width: ${total_people/goalPeople*100}%"`, 'recent_pledges': recentPledges, + 'referral_code': req.params.referralCode || null, // if it's there + 'referrer': referrer, }).then((output) => { res.end(output) }) -}) +} + +router.get('/', homeView) +router.get('/r/:referralCode', homeView) + +// helpers to generate and decode referrals +function randomCode() { + let chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789' + + let code = '' + + for (let i=0; i<10; i++) { + code += chars.charAt(Math.floor(Math.random() * chars.length)) + } + + return code +} +async function findReferralCode(email) { + let referral_code + + // fetch existing referral code, if exists + try { + let pledge = await (Pledge + .query({ + where: { + email: email, + } + }) + .fetch()) + + referral_code = pledge.get('referral_code') + if (DEBUG) console.log(`Using existing referral code: ${referral_code}`) + } catch(e) { + if (e.message == 'EmptyResponse' && DEBUG) { + console.log('No matching referrals found') + } + } + + if (!referral_code) { + // no code found; create a new one and ensure uniqueness + console.log(`Generating new referral code for: ${email}`) + async function checkUniqueness(referral_code) { + let a = await UnverifiedPledge.query({where: {referral_code: referral_code}}).count() + let b = await Pledge.query({where: {referral_code: referral_code}}).count() + + return a == 0 && b == 0 + } + do { + referral_code = randomCode() + } while (!checkUniqueness(referral_code)) + } + + return referral_code +} + +async function findReferrer(code) { + let email + + // first, check for an entry with this referral code + try { + let pledge = await (Pledge + .query({ + where: { + referral_code: code, + } + }) + .fetch()) + + email = pledge.get('email') + console.log(`Found: ${email}`) + } catch(e) { + if (e.message == 'EmptyResponse' && DEBUG) { + console.log('No matching referrals found') + } else { + console.error(e) + } + + // next, check for an entry with this email + // (maybe it's already been converted from code to email) + try { + let pledge = await (Pledge + .query({ + where: { + email: code, + } + }) + .fetch()) + + email = pledge.get('email') + console.log('it seems to be') + } catch(e) { + if (e.message == 'EmptyResponse' && DEBUG) { + console.debug('No matching emails found either') + } else { + console.error(e) + } + + return null + } + } + + return email +} // function to validate pledges before saving -function validatePledge(body, PledgeModel = Pledge) { +async function validatePledge(body, PledgeModel = Pledge) { // errors get saved here let errors = [] @@ -268,6 +393,19 @@ function validatePledge(body, PledgeModel = Pledge) { let overseas = body.overseas == 'yes' ? true : false let other_message = body.other_message + // manage referrals + let referral_code = await findReferralCode(email) + let referrer = null + + console.log('ref co', body.referral_code) + if (body.referral_code) { + try { + referrer = await findReferrer(body.referral_code) + } catch (e) { + console.debug(`Error loading referrer: ${e}`) + } + } + // enter the info let pledge = new PledgeModel() // may be Pledge or UnverifiedPledge pledge.set('was_robot', was_robot) @@ -281,6 +419,9 @@ function validatePledge(body, PledgeModel = Pledge) { pledge.set('get_newsletter', get_newsletter) pledge.set('other_message', other_message) + pledge.set('referral_code', referral_code) + pledge.set('referrer', referrer) + // return it all! return { pledge: pledge, @@ -298,7 +439,7 @@ router.post('/pledge', async (req, res) => { } // process the pledge with our handy function - let {pledge, errors} = validatePledge(req.body, UnverifiedPledge) + let {pledge, errors} = await validatePledge(req.body, UnverifiedPledge) // fail if there were errors if (!!errors.length) { @@ -454,6 +595,32 @@ router.get('/verify', async (req, res) => { newPledge.set('get_newsletter', pledge.get('get_newsletter')) newPledge.set('other_message', pledge.get('other_message')) + newPledge.set('referral_code', await findReferralCode(pledge.get('email'))) + + // set referrer in priority: old pledge > new pledge + try { + let oldPledge = await (Pledge + .query({ + where: { + email: req.query.email, + } + }) + .fetch()) + + newPledge.set('referrer', + oldPledge.get('referrer') || pledge.get('referrer') || null) + } catch(e) { + if (e.message == 'EmptyResponse' && DEBUG) { + console.log('No matching referrals found') + } else { + console.error(e) + } + + newPledge.set('referrer', pledge.get('referrer') || null) + } + + console.log(`Saved referrer: ${newPledge.get('referrer')}`) + // destroy previous pledges by that user try { await (Pledge @@ -471,6 +638,7 @@ router.get('/verify', async (req, res) => { await newPledge.save() // send the confirmation email + let referralLink = `${req.protocol}://${req.hostname}/?ref=${newPledge.get('referral_code')}` let text = `Hi ${pledge.get('name')}, Your pledge of β‚Ή${Number(pledge.get('amount')).toLocaleString('en-IN')} to Snipette Analog has been saved! @@ -494,6 +662,16 @@ a pledge with the same email address as you used before. If you have any questions, don't hesitate to reach out: you can drop a line anytime to editors@snipettemag.com. +### Share for Stickers! + +Money helps, but we need people tooβ€”and that's where you can help! Here's your +unique referral link: + + ${referralLink} + +Get 5 or more of your friends to sign up using that link, and, once we collect +the money and start printing, we'll send you a free pack of Snipette stickers! + Thanks, The Snipette Team` @@ -505,11 +683,13 @@ The Snipette Team` }) // Send confirmation message - res.redirect('/thanks') + res.redirect(`/thanks?ref=${newPledge.get('referral_code')}`) }) router.get('/thanks', async (req, res) => { - let output = await twing.render('thanks.htm.twig') + let output = await twing.render('thanks.htm.twig', { + referral_code: req.query.ref, + }) res.send(output) return diff --git a/src/index.htm.twig b/src/index.htm.twig index a788253..749541b 100644 --- a/src/index.htm.twig +++ b/src/index.htm.twig @@ -33,7 +33,7 @@
- Snipette Analog Fundraiser + Snipette Analog Fundraiser{% if referrer %} (referred by: {{referrer}}){% endif %}
Snipette @@ -385,6 +385,7 @@
+ {% if referral_code %}{% endif %} diff --git a/src/thanks.htm.twig b/src/thanks.htm.twig index e4549cd..75030bd 100644 --- a/src/thanks.htm.twig +++ b/src/thanks.htm.twig @@ -1,17 +1,23 @@ {% extends "base.htm.twig" %} {% block title %}Snipette Crowdfunding: Error{% endblock %} -{% block heading %}Thank you!{% endblock %} +{% block heading %}{% if referral_code %}Wait, there's stickers!{% else %}Thank you!{% endif %}{% endblock %} {% block message %}

Your pledge has been recorded. Thank you so much! Please check your inbox for a receipt.

-

Meanwhile, to help us reach our subscriber goal, do consider sharing our campaign with your friends and family. We can't print if we don't have enough subscribers to send copies too, so who knows: this could be even more helpful than the pledge itself!

+

+{% if referral_code %} +Meanwhile to help us reach our goal, we're offering free stickers! All you have to do is share your unique referral link with friends and family. If 5 or more of them pledge, you'll get a set of Snipette-themed puppy stickers along with your first issue! Find your referral link below: +{% else %} +Meanwhile, to help us reach our subscriber goal, do consider sharing our campaign with your friends and family. We can't print if we don't have enough subscribers to send copies too, so who knows: this could be even more helpful than the pledge itself! +{% endif %} +

- Tweet - - WhatsApp + Tweet + + WhatsApp

- +