initial commit
This commit is contained in:
commit
cf79c07476
6 changed files with 203 additions and 0 deletions
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
node_modules
|
||||||
|
development.yml
|
||||||
|
production.yml
|
4
config/config.yml
Normal file
4
config/config.yml
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
emails:
|
||||||
|
mailgun:
|
||||||
|
url:
|
||||||
|
key:
|
31
html_template.hbs
Normal file
31
html_template.hbs
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<style media="screen">
|
||||||
|
th {
|
||||||
|
text-align: right;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p>{{info}}</p>
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
{{#data}}
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
{{key}}:
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
{{value}}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{{/data}}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<p> </p>
|
||||||
|
<p> </p>
|
||||||
|
</body>
|
||||||
|
</html>
|
131
index.js
Normal file
131
index.js
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
const request = require('request');
|
||||||
|
const restify = require('restify');
|
||||||
|
const Handlebars = require('handlebars');
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const config = require('indecent');
|
||||||
|
|
||||||
|
const { chain, get, indexOf, merge, set, startCase } = require('lodash');
|
||||||
|
|
||||||
|
const knownEmails = get(config, 'emails');
|
||||||
|
|
||||||
|
const MAILGUN_URL = get(config, 'mailgun.url');
|
||||||
|
const MAILGUN_API_KEY = get(config, 'mailgun.key');
|
||||||
|
|
||||||
|
const FORM_FIELDS = [
|
||||||
|
'_from',
|
||||||
|
'_subject',
|
||||||
|
'_to',
|
||||||
|
'_attachment'
|
||||||
|
];
|
||||||
|
|
||||||
|
const PRIVATE_FIELDS = [
|
||||||
|
'_fake',
|
||||||
|
'_info',
|
||||||
|
'_next'
|
||||||
|
];
|
||||||
|
|
||||||
|
const htmlSource = fs.readFileSync(path.join(__dirname, 'html_template.hbs'), { encoding: 'utf8' });
|
||||||
|
const textSource = fs.readFileSync(path.join(__dirname, 'text_template.hbs'), { encoding: 'utf8' });
|
||||||
|
const htmlTemplate = Handlebars.compile(htmlSource);
|
||||||
|
const textTemplate = Handlebars.compile(textSource);
|
||||||
|
|
||||||
|
var server = restify.createServer();
|
||||||
|
server.use(restify.CORS());
|
||||||
|
server.use(restify.bodyParser());
|
||||||
|
|
||||||
|
server.post('/:_to', (req, res, next) => {
|
||||||
|
const { formData, fields } = parseRequest(req);
|
||||||
|
|
||||||
|
if (indexOf(knownEmails, get(formData, 'to')) < 0) {
|
||||||
|
return next(new Error('Unknown email address'));
|
||||||
|
}
|
||||||
|
|
||||||
|
const params = {
|
||||||
|
formData,
|
||||||
|
auth: {
|
||||||
|
user: 'api',
|
||||||
|
pass: MAILGUN_API_KEY
|
||||||
|
},
|
||||||
|
url: MAILGUN_URL,
|
||||||
|
method: 'post'
|
||||||
|
};
|
||||||
|
|
||||||
|
sendMail(fields, params).then(response => {
|
||||||
|
const redirect = get(fields, 'next');
|
||||||
|
if (redirect) {
|
||||||
|
res.redirect(redirect, next);
|
||||||
|
} else {
|
||||||
|
res.json(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
return next();
|
||||||
|
}).catch(error => {
|
||||||
|
return next(error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function parseRequest (req) {
|
||||||
|
const body = get(req, 'params');
|
||||||
|
|
||||||
|
const formData = chain(body)
|
||||||
|
.pick(FORM_FIELDS)
|
||||||
|
.mapKeys((value, key) => key.replace('_', ''))
|
||||||
|
.value();
|
||||||
|
|
||||||
|
const fields = chain(body)
|
||||||
|
.pick(PRIVATE_FIELDS)
|
||||||
|
.mapKeys((value, key) => key.replace('_', ''))
|
||||||
|
.value();
|
||||||
|
|
||||||
|
const data = chain(body)
|
||||||
|
.omit(PRIVATE_FIELDS)
|
||||||
|
.omit(FORM_FIELDS)
|
||||||
|
.mapKeys((value, key) => startCase(key))
|
||||||
|
.map((value, key) => {
|
||||||
|
return { key, value };
|
||||||
|
})
|
||||||
|
.value();
|
||||||
|
|
||||||
|
set(fields, 'data', data);
|
||||||
|
set(formData, 'html', htmlTemplate(fields));
|
||||||
|
set(formData, 'text', textTemplate(fields));
|
||||||
|
|
||||||
|
const attachment = get(req, 'files._attachment');
|
||||||
|
if (attachment) {
|
||||||
|
const filePath = get(attachment, 'path');
|
||||||
|
const value = get(fields, 'fake') ? filePath : fs.createReadStream(filePath);
|
||||||
|
|
||||||
|
set(formData, 'attachment', {
|
||||||
|
value,
|
||||||
|
options: {
|
||||||
|
filename: get(attachment, 'name'),
|
||||||
|
contentType: get(attachment, 'type')
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return { data, fields, formData };
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendMail (fields, params) {
|
||||||
|
const fake = get(fields, 'fake');
|
||||||
|
|
||||||
|
if (fake) {
|
||||||
|
return Promise.resolve(merge({ message: 'fake response' }, params));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
request(params, (error, msg, response) => {
|
||||||
|
if (error) {
|
||||||
|
return reject(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolve(JSON.parse(response));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
server.listen(8081, () => {
|
||||||
|
console.log(`${server.name} listening at ${server.url}`);
|
||||||
|
});
|
29
package.json
Normal file
29
package.json
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
{
|
||||||
|
"name": "contact",
|
||||||
|
"version": "1.0.1",
|
||||||
|
"description": "A basic clone of formspree.io for internal use",
|
||||||
|
"main": "index.js",
|
||||||
|
"homepage": "https://github.com/eruizdechavez/contact",
|
||||||
|
"bugs": "https://github.com/eruizdechavez/contact/issues",
|
||||||
|
"license": "MIT",
|
||||||
|
"author": {
|
||||||
|
"name": "Erick Ruiz de Chavez",
|
||||||
|
"email": "eruizdechavez@fastmail.com",
|
||||||
|
"url": "https://github.com/eruizdechavez"
|
||||||
|
},
|
||||||
|
"repository": "eruizdechavez/contact",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0.0"
|
||||||
|
},
|
||||||
|
"private": true,
|
||||||
|
"dependencies": {
|
||||||
|
"handlebars": "4.0.5",
|
||||||
|
"indecent": "1.0.1",
|
||||||
|
"lodash": "4.13.1",
|
||||||
|
"request": "2.72.0",
|
||||||
|
"restify": "4.1.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"semistandard": "*"
|
||||||
|
}
|
||||||
|
}
|
5
text_template.hbs
Normal file
5
text_template.hbs
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{{info}}
|
||||||
|
|
||||||
|
{{#data}}
|
||||||
|
{{key}}: {{value}}
|
||||||
|
{{/data}}
|
Loading…
Reference in a new issue