From: Nick Downing Date: Sun, 16 Jan 2022 02:02:39 +0000 (+1100) Subject: Implement feedback as a JSON API, fix missing await on all post_request() calls X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?p=ndcode_site.git;a=commitdiff_plain;h=65f379c9e639ba3f2839ccbe5681dbc772a886a1 Implement feedback as a JSON API, fix missing await on all post_request() calls --- diff --git a/_config/globals.json b/_config/globals.json index 4b5779c..798870f 100644 --- a/_config/globals.json +++ b/_config/globals.json @@ -1,9 +1,9 @@ { "site_url": "https://www.ndcode.org", "site_title": "NDCODE", - "contact_from": "NDCODE Contact ", + "contact_from": "NDCODE contact ", "contact_to": "Nick Downing ", - "feedback_from": "NDCODE Feedback ", + "feedback_from": "NDCODE feedback ", "feedback_to": "Nick Downing ", "noreply_from": "NDCODE ", "noreply_signature": "NDCODE Team", diff --git a/_config/nodemailer_feedback.json b/_config/nodemailer_feedback.json index 0dd697f..675f676 100644 --- a/_config/nodemailer_feedback.json +++ b/_config/nodemailer_feedback.json @@ -4,7 +4,7 @@ "secure": false, "auth": { "user": "feedback@ndcode.org", - "pass": "XXXFeedback12", + "pass": "XXXFeedback12" }, "requireTLS": true } diff --git a/_lib/navbar.jst b/_lib/navbar.jst index 4e80d95..a993c46 100644 --- a/_lib/navbar.jst +++ b/_lib/navbar.jst @@ -253,21 +253,8 @@ return async (env, head, body, scripts) => { div.row { div.col-md-12 { div.form-group { - label(for="feedback-message") {'Message *'} - textarea.form-control#feedback-message(placeholder="Please tell us your thoughts" rows="4" required="required" data-error="Please, leave us a message.") {} - div.help-block.with-errors {} - } - } - } - p {} // fix this later - div.row { - div.col-md-12 { - p.text-muted { - strong {'*'} - 'These fields are required.' - //'Contact form template by ' - //a(href="https://bootstrapious.com/p/how-to-build-a-working-bootstrap-feedback-form" target="_blank") {'Bootstrapious'} - //'.' + label.form-label(for="feedback-message") {'Message'} + textarea.form-control#feedback-message(placeholder="Please tell us your thoughts" rows="4" required="required") {} } } } @@ -314,6 +301,10 @@ return async (env, head, body, scripts) => { '/api/sign_out.json', ...arguments ) + let feedback = async (...arguments) => api_call( + '/api/feedback.json', + ...arguments + ) // this function can be overridden in a further script function sign_in_out(status) { @@ -442,28 +433,35 @@ return async (env, head, body, scripts) => { document.getElementById('feedback-submit').addEventListener( 'click', - () => { - $.ajax( - { - url: '/api/feedback.html', - type: 'POST', - data: { - page: window.location.href, - message: $('#feedback-message').val() - }, - success: (data, textStatus, jqXHR) => { - $('#feedback-modal').modal('hide') - document.getElementById('message-modal-message').textContent = data - $('#message-modal-message').text(data) - $('#message-modal').modal('show') - }, - error: (jqXHR, textStatus, errorThrown) => { - $('#feedback-modal').modal('hide') - document.getElementById('message-modal-message').textContent = errorThrown - $('#message-modal').modal('show') - } - } - ) + async () => { + try { + await feedback( + location.href, + document.getElementById('feedback-message').value.slice(0, 65536) + ) + } + catch (error) { + let problem = + error instanceof Problem ? + error : + new Problem( + // title + 'Bad request', + // details + (error.stack || error.message).toString() + // status + 400 + ) + + document.getElementById('message-modal-message').textContent = problem.detail + $('#feedback-modal').modal('hide') + $('#message-modal').modal('show') + return + } + + document.getElementById('message-modal-message').textContent = 'Thanks! We have received your feedback.' + $('#feedback-modal').modal('hide') + $('#message-modal').modal('show') } ) } diff --git a/api/feedback.html.jst b/api/feedback.html.jst deleted file mode 100644 index b67836b..0000000 --- a/api/feedback.html.jst +++ /dev/null @@ -1,64 +0,0 @@ -let querystring = require('querystring') -let stream_buffers = require('stream-buffers') -let XDate = require('xdate') - -return async env => { - let globals = await env.site.get_json('/_config/globals.json') - let nodemailer_feedback = await env.site.get_nodemailer( - '/_config/email_feedback.json' - ) - - let message - if (env.request.method === 'POST') { - let write_stream = new stream_buffers.WritableStreamBuffer() - let data = new Promise( - (resolve, reject) => { - write_stream. - on('finish', () => {resolve(write_stream.getContents())}). - on('error', () => {reject()}) - } - ) - env.request.pipe(write_stream) - let query = querystring.parse((await data).toString()) - console.log('received feedback form:', query.page) - - // save the form contents in a dated logfile, so that we can - // recover manually if the email doesn't send for some reason - date = new XDate() - query.date = date.toUTCString() - - let transaction = await env.site.database.Transaction() - ;( - await ( - await ( - await ( - await transaction.get({}) - ).get('logs', {}) - ).get(date.toUTCString('yyyyMMdd'), {}) - ).get('feedback', []) - ).push(transaction.json_to_logjson(query)) - transaction.commit() - - // send email (asynchronously) - nodemailer_feedback.sendMail( - { - from: globals.feedback_from, - to: globals.feedback_to, - subject: 'Page: ' + query.page, - text: query.message, - }, - (err, message) => { - if (err) - console.error(err.stack || err.message) - else - console.log('sent feedback email:', query.page) - } - ) - - message = 'Thanks!' - } - else - message = 'Please POST.' - - env.site.serve(env, 200, Buffer.from(message), 'feedback.html.jst') -} diff --git a/api/feedback.json.jst b/api/feedback.json.jst new file mode 100644 index 0000000..860f3e2 --- /dev/null +++ b/api/feedback.json.jst @@ -0,0 +1,50 @@ +let logjson = (await import('@ndcode/logjson')).default +let XDate = require('xdate') + +return async env => { + let globals = await env.site.get_json('/_config/globals.json') + 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') + + await post_request( + // env + env, + // endpoint + '/api/feedback.json', + // handler + async (page, message) => { + // coerce and/or validate + page = page.slice(0, 256) + mesage = message.slice(0, 65536) + if (page.length === 0 || message.length === 0) + throw new Problem( + 'Bad request', + 'Minimum length check failed', + 400 + ) + + let transaction = await env.site.database.Transaction() + try { + // initialize env.session_key, set cookie in env.response + await session_cookie(env, transaction) + await transaction.commit() + } + catch (error) { + transaction.rollback() + throw error + } + + await nodemailer_feedback.sendMail( + { + from: globals.feedback_from, + to: globals.feedback_to, + subject: 'Page: ' + page, + text: message + } + ) + } + ) +} diff --git a/api/password_reset.json.jst b/api/password_reset.json.jst index 6f778fc..b439a17 100644 --- a/api/password_reset.json.jst +++ b/api/password_reset.json.jst @@ -11,7 +11,7 @@ return async env => { let session_cookie = await _require('/_lib/session_cookie.jst') let Problem = await _require('/_lib/Problem.jst') - post_request( + await post_request( // env env, // endpoint diff --git a/api/sign_in.json.jst b/api/sign_in.json.jst index 30f8564..bf3b02e 100644 --- a/api/sign_in.json.jst +++ b/api/sign_in.json.jst @@ -9,7 +9,7 @@ return async env => { let session_cookie = await _require('/_lib/session_cookie.jst') let Problem = await _require('/_lib/Problem.jst') - post_request( + await post_request( // env env, // endpoint diff --git a/api/sign_out.json.jst b/api/sign_out.json.jst index 768de0e..264fb3c 100644 --- a/api/sign_out.json.jst +++ b/api/sign_out.json.jst @@ -9,7 +9,7 @@ return async env => { let session_cookie = await _require('/_lib/session_cookie.jst') let Problem = await _require('/_lib/Problem.jst') - post_request( + await post_request( // env env, // endpoint diff --git a/api/sign_up/create_account.json.jst b/api/sign_up/create_account.json.jst index 5789c6a..bb96f5c 100644 --- a/api/sign_up/create_account.json.jst +++ b/api/sign_up/create_account.json.jst @@ -5,7 +5,7 @@ return async env => { let session_cookie = await _require('/_lib/session_cookie.jst') let Problem = await _require('/_lib/Problem.jst') - post_request( + await post_request( // env env, // endpoint diff --git a/api/sign_up/get_draft.json.jst b/api/sign_up/get_draft.json.jst index 6bdb55a..44f20f0 100644 --- a/api/sign_up/get_draft.json.jst +++ b/api/sign_up/get_draft.json.jst @@ -6,7 +6,7 @@ return async env => { let session_cookie = await _require('/_lib/session_cookie.jst') let Problem = await _require('/_lib/Problem.jst') - post_request( + await post_request( // env env, // endpoint diff --git a/api/sign_up/send_email_verification_link.json.jst b/api/sign_up/send_email_verification_link.json.jst index 92a77f6..08f0db6 100644 --- a/api/sign_up/send_email_verification_link.json.jst +++ b/api/sign_up/send_email_verification_link.json.jst @@ -11,7 +11,7 @@ return async env => { let session_cookie = await _require('/_lib/session_cookie.jst') let Problem = await _require('/_lib/Problem.jst') - post_request( + await post_request( // env env, // endpoint diff --git a/api/sign_up/set_draft.json.jst b/api/sign_up/set_draft.json.jst index 3b3c71b..e7d2457 100644 --- a/api/sign_up/set_draft.json.jst +++ b/api/sign_up/set_draft.json.jst @@ -5,7 +5,7 @@ return async env => { let session_cookie = await _require('/_lib/session_cookie.jst') let Problem = await _require('/_lib/Problem.jst') - post_request( + await post_request( // env env, // endpoint diff --git a/api/sign_up/verify_email.json.jst b/api/sign_up/verify_email.json.jst index d7f915c..8ff628a 100644 --- a/api/sign_up/verify_email.json.jst +++ b/api/sign_up/verify_email.json.jst @@ -7,7 +7,7 @@ return async env => { let session_cookie = await _require('/_lib/session_cookie.jst') let Problem = await _require('/_lib/Problem.jst') - post_request( + await post_request( // env env, // endpoint diff --git a/api/verify_password.json.jst b/api/verify_password.json.jst index 3e58569..bb36a53 100644 --- a/api/verify_password.json.jst +++ b/api/verify_password.json.jst @@ -7,7 +7,7 @@ return async env => { let session_cookie = await _require('/_lib/session_cookie.jst') let Problem = await _require('/_lib/Problem.jst') - post_request( + await post_request( // env env, // endpoint