From 77874c6a45de736010790d76e81c901a5517a3e4 Mon Sep 17 00:00:00 2001 From: Nick Downing Date: Sun, 23 Jan 2022 13:47:46 +1100 Subject: [PATCH] Implement a way to get/set the nodemailer object (has an entries for contact, feedback and noreply), use nodemailer object in database rather than the separate files /_config/nodemailer_*.json and the (now commented) NodeMailerCache object --- _config/n.sh | 1 + _config/nodemailer.json | 32 ++++++++++ _config/nodemailer_contact.json | 10 ---- _config/nodemailer_feedback.json | 10 ---- _config/nodemailer_noreply.json | 10 ---- _config/site.jst | 28 ++++----- api/account/password_reset.json.jst | 59 ++++++++++--------- .../send_email_verification_link.json.jst | 59 ++++++++++--------- api/contact/send_enquiry.json.jst | 13 ++-- api/feedback.json.jst | 12 ++-- api/nodemailer/get.json.jst | 38 ++++++++++++ api/nodemailer/set.json.jst | 39 ++++++++++++ package.json | 2 +- 13 files changed, 203 insertions(+), 110 deletions(-) create mode 100644 _config/nodemailer.json delete mode 100644 _config/nodemailer_contact.json delete mode 100644 _config/nodemailer_feedback.json delete mode 100644 _config/nodemailer_noreply.json create mode 100644 api/nodemailer/get.json.jst create mode 100644 api/nodemailer/set.json.jst diff --git a/_config/n.sh b/_config/n.sh index 197f13a..5bcb282 100755 --- a/_config/n.sh +++ b/_config/n.sh @@ -1,2 +1,3 @@ #!/bin/sh ./set.mjs /api/globals/set.json { } ) - assert(this.nodemailer_cache === undefined) - this.nodemailer_cache = await this.resources.ref( - 'nodemailer_cache', - async () => new NodeMailerCache(true) - ) + //assert(this.nodemailer_cache === undefined) + //this.nodemailer_cache = await this.resources.ref( + // 'nodemailer_cache', + // async () => new NodeMailerCache(true) + //) assert(this.zettair_cache === undefined) this.zettair_cache = await this.resources.ref( @@ -52,8 +52,8 @@ return async (resources, root, prev_site) => { assert(this.database !== undefined) await this.resources.unref('database') - assert(this.nodemailer_cache !== undefined) - await this.resources.unref('nodemailer_cache') + //assert(this.nodemailer_cache !== undefined) + //await this.resources.unref('nodemailer_cache') assert(this.zettair_cache !== undefined) await this.resources.unref('zettair_cache') @@ -80,17 +80,17 @@ return async (resources, root, prev_site) => { this.database_date = new_database_date } - assert(this.nodemailer_cache !== undefined) - this.nodemailer_cache.kick() + //assert(this.nodemailer_cache !== undefined) + //this.nodemailer_cache.kick() assert(this.zettair_cache !== undefined) this.zettair_cache.kick() } - // retrieves a particular email account (as a nodemailer transport) - get_nodemailer(pathname) { - return /*await*/ this.nodemailer_cache.get(this.root + pathname) - } + //// retrieves a particular email account (as a nodemailer transport) + //get_nodemailer(pathname) { + // return /*await*/ this.nodemailer_cache.get(this.root + pathname) + //} // retrieves a particular search index (node.js wrapper of a zettair object) get_zettair(pathname) { diff --git a/api/account/password_reset.json.jst b/api/account/password_reset.json.jst index ff6aed9..f652800 100644 --- a/api/account/password_reset.json.jst +++ b/api/account/password_reset.json.jst @@ -1,10 +1,8 @@ let crypto = require('crypto') +let nodemailer = require('nodemailer') let XDate = require('xdate') return async env => { - let nodemailer_noreply = await env.site.get_nodemailer( - '/_config/nodemailer_noreply.json' - ) let post_request = await _require('/_lib/post_request.jst') let session_cookie = await _require('/_lib/session_cookie.jst') let Problem = await _require('/_lib/Problem.jst') @@ -25,6 +23,9 @@ return async env => { ) let transaction = await env.site.database.Transaction() + let link_code + let nodemailer_noreply, noreply_from, noreply_signature + let given_names, family_name try { // initialize env.session_key, set cookie in env.response await session_cookie(env, transaction) @@ -41,7 +42,7 @@ return async env => { 421 ) - let link_code = crypto.randomBytes(16).toString('hex') + link_code = crypto.randomBytes(16).toString('hex') let expires = new XDate() expires.addDays(1) account.set_json( @@ -49,22 +50,33 @@ return async env => { {password, link_code, expires: expires.getTime()} ) - let globals = await (await transaction.get({})).get('globals') - let site_url = await globals.get_json('site_url') - let noreply_from = await globals.get_json('noreply_from') - let noreply_signature = await globals.get_json('noreply_signature') + let root = await transaction.get({}) + nodemailer_noreply = nodemailer.createTransport( + await (await root.get('nodemailer')).get_json('noreply') + ) + let globals = await root.get('globals') + site_url = await globals.get_json('site_url') + noreply_from = await globals.get_json('noreply_from') + noreply_signature = await globals.get_json('noreply_signature') + + given_names = await account.get_json('given_names', '') + family_name = await account.get_json('family_name', '') - let given_names = await account.get_json('given_names', '') - let family_name = await account.get_json('family_name', '') - let name = - family_name.length ? `${given_names} ${family_name}` : given_names + await transaction.commit() + } + catch (error) { + transaction.rollback() + throw error + } - await nodemailer_noreply.sendMail( - { - from: noreply_from, - to: `${name} <${email}>`, - subject: 'Password reset', - text: `Dear ${given_names}, + let name = + family_name.length ? `${given_names} ${family_name}` : given_names + await nodemailer_noreply.sendMail( + { + from: noreply_from, + to: `${name} <${email}>`, + subject: 'Password reset', + text: `Dear ${given_names}, We have received a request to reset the account password for your email address. @@ -76,15 +88,8 @@ The link is valid for 24 hours. Thanks, ${noreply_signature} ` - } - ) - - await transaction.commit() - } - catch (error) { - transaction.rollback() - throw error - } + } + ) } ) } diff --git a/api/account/sign_up/send_email_verification_link.json.jst b/api/account/sign_up/send_email_verification_link.json.jst index c682c2c..ac64ba5 100644 --- a/api/account/sign_up/send_email_verification_link.json.jst +++ b/api/account/sign_up/send_email_verification_link.json.jst @@ -1,10 +1,8 @@ let crypto = require('crypto') +let nodemailer = require('nodemailer') let XDate = require('xdate') return async env => { - let nodemailer_noreply = await env.site.get_nodemailer( - '/_config/nodemailer_noreply.json' - ) let post_request = await _require('/_lib/post_request.jst') let session_cookie = await _require('/_lib/session_cookie.jst') let Problem = await _require('/_lib/Problem.jst') @@ -24,6 +22,9 @@ return async env => { ) let transaction = await env.site.database.Transaction() + let link_code + let nodemailer_noreply, site_url, noreply_from, noreply_signature + let given_names, family_name try { // initialize env.session_key, set cookie in env.response await session_cookie(env, transaction) @@ -47,7 +48,7 @@ return async env => { 422 ) - let link_code = crypto.randomBytes(16).toString('hex') + link_code = crypto.randomBytes(16).toString('hex') let expires = new XDate() expires.addDays(1) account.set_json( @@ -55,22 +56,33 @@ return async env => { {link_code, expires: expires.getTime()} ) - let globals = await (await transaction.get({})).get('globals') - let site_url = await globals.get_json('site_url') - let noreply_from = await globals.get_json('noreply_from') - let noreply_signature = await globals.get_json('noreply_signature') + let root = await transaction.get({}) + nodemailer_noreply = nodemailer.createTransport( + await (await root.get('nodemailer')).get_json('noreply') + ) + let globals = await root.get('globals') + site_url = await globals.get_json('site_url') + noreply_from = await globals.get_json('noreply_from') + noreply_signature = await globals.get_json('noreply_signature') + + given_names = await account.get_json('given_names', '') + family_name = await account.get_json('family_name', '') - let given_names = await account.get_json('given_names', '') - let family_name = await account.get_json('family_name', '') - let name = - family_name.length ? `${given_names} ${family_name}` : given_names + await transaction.commit() + } + catch (error) { + transaction.rollback() + throw error + } - await nodemailer_noreply.sendMail( - { - from: noreply_from, - to: `${name} <${email}>`, - subject: 'Email address verification', - text: `Dear ${given_names}, + let name = + family_name.length ? `${given_names} ${family_name}` : given_names + await nodemailer_noreply.sendMail( + { + from: noreply_from, + to: `${name} <${email}>`, + subject: 'Email address verification', + text: `Dear ${given_names}, We have received a request to sign up using your email address. @@ -82,15 +94,8 @@ The link is valid for 24 hours. Thanks, ${noreply_signature} ` - } - ) - - await transaction.commit() - } - catch (error) { - transaction.rollback() - throw error - } + } + ) } ) } diff --git a/api/contact/send_enquiry.json.jst b/api/contact/send_enquiry.json.jst index 04ac3b0..f1e5598 100644 --- a/api/contact/send_enquiry.json.jst +++ b/api/contact/send_enquiry.json.jst @@ -1,10 +1,7 @@ -let crypto = require('crypto') +let nodemailer = require('nodemailer') let XDate = require('xdate') return async env => { - let nodemailer_contact = await env.site.get_nodemailer( - '/_config/nodemailer_contact.json' - ) let post_request = await _require('/_lib/post_request.jst') let session_cookie = await _require('/_lib/session_cookie.jst') let Problem = await _require('/_lib/Problem.jst') @@ -34,12 +31,16 @@ return async env => { ) let transaction = await env.site.database.Transaction() - let contact_from, contact_to + let nodemailer_contact, contact_from, contact_to try { // initialize env.session_key, set cookie in env.response session_cookie(env, transaction) - let globals = await (await transaction.get({})).get('globals') + let root = await transaction.get({}) + nodemailer_contact = nodemailer.createTransport( + await (await root.get('nodemailer')).get_json('contact') + ) + let globals = await root.get('globals') contact_from = await globals.get_json('contact_from') contact_to = await globals.get_json('contact_to') diff --git a/api/feedback.json.jst b/api/feedback.json.jst index 8d6f201..7cc4feb 100644 --- a/api/feedback.json.jst +++ b/api/feedback.json.jst @@ -1,9 +1,7 @@ +let nodemailer = require('nodemailer') let XDate = require('xdate') return async env => { - let nodemailer_feedback = await env.site.get_nodemailer( - '/_config/nodemailer_feedback.json' - ) let post_request = await _require('/_lib/post_request.jst') let session_cookie = await _require('/_lib/session_cookie.jst') @@ -23,12 +21,16 @@ return async env => { ) let transaction = await env.site.database.Transaction() - let feedback_from, feedback_to + let nodemailer_feedback, feedback_from, feedback_to try { // initialize env.session_key, set cookie in env.response await session_cookie(env, transaction) - let globals = await (await transaction.get({})).get('globals') + let root = await transaction.get({}) + nodemailer_feedback = nodemailer.createTransport( + await (await root.get('nodemailer')).get_json('feedback') + ) + let globals = await root.get('globals') feedback_from = await globals.get_json('feedback_from') feedback_to = await globals.get_json('feedback_to') diff --git a/api/nodemailer/get.json.jst b/api/nodemailer/get.json.jst new file mode 100644 index 0000000..6fcce8c --- /dev/null +++ b/api/nodemailer/get.json.jst @@ -0,0 +1,38 @@ +let XDate = require('xdate') + +return async env => { + let post_request = await _require('/_lib/post_request.jst') + let session_cookie = await _require('/_lib/session_cookie.jst') + let Problem = await _require('/_lib/Problem.jst') + + await post_request( + // env + env, + // handler + async () => { + let transaction = await env.site.database.Transaction() + try { + // initialize env.session_key, set cookie in env.response + await session_cookie(env, transaction) + if (env.signed_in_as === null) + throw new Problem('Unauthorized', 'Please sign in first.', 401) + + let root = await transaction.get({}) + let account = await ( + await root.get('accounts', {}) + ).get(env.signed_in_as) + if (!await account.get_json('administrator')) + throw new Problem('Unauthorized', 'Not administrator.', 401) + + nodemailer = await root.get_json('nodemailer', {}) + + await transaction.commit() + return nodemailer + } + catch (error) { + transaction.rollback() + throw error + } + } + ) +} diff --git a/api/nodemailer/set.json.jst b/api/nodemailer/set.json.jst new file mode 100644 index 0000000..101a7fc --- /dev/null +++ b/api/nodemailer/set.json.jst @@ -0,0 +1,39 @@ +let XDate = require('xdate') + +return async env => { + let post_request = await _require('/_lib/post_request.jst') + let session_cookie = await _require('/_lib/session_cookie.jst') + let Problem = await _require('/_lib/Problem.jst') + + await post_request( + // env + env, + // handler + async nodemailer => { + // do not bother trying to coerce and/or validate + // too complex and nested (do it when we have an automated routine) + + let transaction = await env.site.database.Transaction() + try { + // initialize env.session_key, set cookie in env.response + await session_cookie(env, transaction) + if (env.signed_in_as === null) + throw new Problem('Unauthorized', 'Please sign in first.', 401) + + let root = await transaction.get({}) + let account = await ( + await root.get('accounts', {}) + ).get(env.signed_in_as) + if (!await account.get_json('administrator')) + throw new Problem('Unauthorized', 'Not administrator.', 401) + + root.set_json('nodemailer', nodemailer) + await transaction.commit() + } + catch (error) { + transaction.rollback() + throw error + } + } + ) +} diff --git a/package.json b/package.json index 0c3a724..f31e278 100644 --- a/package.json +++ b/package.json @@ -5,10 +5,10 @@ "directories": {}, "dependencies": { "@ndcode/logjson": "^0.1.0", - "@ndcode/nodemailer_cache": "^0.1.0", "@ndcode/zettair_cache": "^0.1.0", "captchagen": "^1.2.0", "cookie": "^0.3.1", + "nodemailer": "^6.7.2", "querystring": "^0.2.0", "stream-buffers": "^3.0.2", "xdate": "^0.8.2" -- 2.34.1