Update dependencies, refactor as needed
This commit is contained in:
parent
4d2ffda447
commit
f11560681e
8 changed files with 2872 additions and 191 deletions
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -1,4 +1,5 @@
|
|||
node_modules
|
||||
development.yml
|
||||
production.yml
|
||||
local.json
|
||||
development.json
|
||||
production.json
|
||||
vendor
|
||||
|
|
61
README.md
61
README.md
|
@ -15,10 +15,10 @@ A basic node server for sending email forms.
|
|||
</form>
|
||||
```
|
||||
|
||||
This project is, in some way, a clone of a great free service: [Formspree.io](https://formspree.io/). Although Formspree is great, it might **not** be the best option for everyone; 2 key factors drived me to create this clone:
|
||||
This project is, in some way, a clone of an excellent free service: [Formspree.io](https://formspree.io/). Although Formspree is outstanding, it might **not** be the best option for everyone; 2 key factors drove me to create this clone:
|
||||
|
||||
1. Setup (and maintenance) should be minimal.
|
||||
Formspree is opensource and it's code is on GitHub, but the setup process is way more than a trivial task, not to mention the requirements. Requirement 1 not met.
|
||||
Formspree is opensource, and its code is on GitHub, but the setup process is way more than a trivial task, not to mention the requirements. Requirement 1 not met.
|
||||
|
||||
1. Should allow me to send attachments.
|
||||
Formspree does not allow you to send email forms with attachments (at least not at the time when this written). Requirement 2 not met.
|
||||
|
@ -32,38 +32,39 @@ This project is, in some way, a clone of a great free service: [Formspree.io](ht
|
|||
|
||||
Clone this repo on your server or download the zip file.
|
||||
|
||||
Once you have the code, run `npn install --production` to download and install all the project dependencies required to run this project.
|
||||
Once you have the code, run `npm install --production` to download and install all the project dependencies required to run this project.
|
||||
|
||||
Next step, configure your server. Open `config/config.yml` which should look like this:
|
||||
Next step, configure your server. Open `config/config.json` which should look like this:
|
||||
|
||||
```yml
|
||||
emails:
|
||||
mailgun:
|
||||
url:
|
||||
key:
|
||||
```json
|
||||
{
|
||||
"emails": [],
|
||||
"mailgun": {
|
||||
"url": "",
|
||||
"key": ""
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
And update the values to match your preferences:
|
||||
|
||||
- **emails** is an array of email addresses. This emails are the **ONLY** emails this server will be allowed to send emails to (authorized emails)
|
||||
- **emails** is an array of email addresses. These emails are the **ONLY** emails this server will be allowed to send emails to (authorized emails)
|
||||
- **mailgun.url** your Mailgun API URL
|
||||
- **mailgun.key** you Mailgun Domain API Key
|
||||
|
||||
An example of a `config.yml` file:
|
||||
An example of a `config.json` file:
|
||||
|
||||
```yml
|
||||
emails:
|
||||
- sales@example.com
|
||||
- contact@example.com
|
||||
- support@example.com
|
||||
mailgun:
|
||||
url: https://api.mailgun.net/v3/example.com/messages
|
||||
key: key-l0r3m1p5umd0l0r5174m37c0n53c737u
|
||||
```json
|
||||
{
|
||||
"emails": ["sales@example.com", "contact@example.com", "support@example.com"],
|
||||
"mailgun": {
|
||||
"url": "https://api.mailgun.net/v3/example.com/messages",
|
||||
"key": "key-l0r3m1p5umd0l0r5174m37c0n53c737u"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Contact** uses [indecent.js][indecent] for loading its YAML configuration files, this allows you to override the above settings based on the value of `NODE_ENV`. You can read more about that in the [module documentation][indecent].
|
||||
|
||||
[indecent]: https://github.com/eruizdechavez/indecent.js
|
||||
**Contact** uses `NODE_ENV` environment variable for loading its JSON configuration files, this allows you to override the above settings with other JSON files, for example, `config/production.json`.
|
||||
|
||||
## Server Usage
|
||||
|
||||
|
@ -73,15 +74,15 @@ To run the server, just run `node index.js`. You can use other node runners to k
|
|||
|
||||
Once your server is up and running, all you need to do is create an HTML form and point it to your server.
|
||||
|
||||
Your form's action should point to your **contact** server using a valid email address (defined in the YAML file). If the email address is not in the whitelist the email will not be sent.
|
||||
Your form's action should point to your **contact** server using a valid email address (defined in the YAML file). If the email address is not in the whitelist, the email will not be sent.
|
||||
|
||||
### Fields
|
||||
|
||||
- **_from**: *Required*. This is usually the email address of the user submitting the email form. It will be used as the Form field.
|
||||
- **_subject**: *Optional*. The email subject.
|
||||
- **_info**: *Optional*. This text will be included in the email body before the values. Useful for providing some context in the email body.
|
||||
- **_attachment**: *Optional*. A file can be attached to the email form using this for the name of an `<input type="file"/>`. When sending attachments do not forget to include `enctype="multipart/form-data"` in your form tag.
|
||||
- **_next**: *Optional*. A URL to redirect the user once the form was submited succesfully.
|
||||
- **_fake**: *For testing*. If `true`, the email will not be sent and instead a JSON paylod will be shown. Useful when testing the form with a REST client.
|
||||
- **\_from**: _Required_. This is usually the email address of the user submitting the email form. It will be used as the Form field.
|
||||
- **\_subject**: _Optional_. The email subject.
|
||||
- **\_info**: _Optional_. This text will be included in the email body before the values. Useful for providing some context in the email body.
|
||||
- **\_attachment**: _Optional_. A file can be attached to the email form using this for the name of an `<input type="file"/>`. When sending attachments do not forget to include `enctype="multipart/form-data"` in your form tag.
|
||||
- **\_next**: _Optional_. A URL to redirect the user once the form was submitted successfully.
|
||||
- **\_fake**: _For testing_. If `true`, the email will not be sent and instead a JSON payload will be shown. Useful when testing the form with a REST client.
|
||||
|
||||
All other form fields will be send by title casing the name. For example `<input type="text" name="first_name" />` will be displayed in the email as "First Name:"
|
||||
All other form fields will be sent by title casing the name. For example `<input type="text" name="first_name" />` will be displayed in the email as "First Name:"
|
||||
|
|
7
config/config.json
Normal file
7
config/config.json
Normal file
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"emails": [],
|
||||
"mailgun": {
|
||||
"url": "",
|
||||
"key": ""
|
||||
}
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
emails:
|
||||
mailgun:
|
||||
url:
|
||||
key:
|
|
@ -1,5 +1,6 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<style media="screen">
|
||||
|
@ -9,6 +10,7 @@
|
|||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<p>{{info}}</p>
|
||||
<table>
|
||||
|
@ -28,4 +30,5 @@
|
|||
<p> </p>
|
||||
<p> </p>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
65
index.js
65
index.js
|
@ -3,27 +3,38 @@ const restify = require('restify');
|
|||
const Handlebars = require('handlebars');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const config = require('indecent');
|
||||
|
||||
const corsMiddleware = require('restify-cors-middleware');
|
||||
const cors = corsMiddleware({
|
||||
preflightMaxAge: 5,
|
||||
origins: ['*'],
|
||||
});
|
||||
const { chain, get, indexOf, merge, set, startCase } = require('lodash');
|
||||
|
||||
const knownEmails = get(config, 'emails');
|
||||
let defaults;
|
||||
try {
|
||||
defaults = JSON.parse(fs.readFileSync(path.join(__dirname, 'config', 'config.json'), { encoding: 'utf8' }));
|
||||
} catch (err) {
|
||||
console.log(err.message);
|
||||
defaults = {};
|
||||
}
|
||||
let environment;
|
||||
|
||||
try {
|
||||
environment = JSON.parse(
|
||||
fs.readFileSync(path.join(__dirname, 'config', `${process.env.NODE_ENV}.json`), { encoding: 'utf8' })
|
||||
);
|
||||
} catch (err) {
|
||||
console.log(err.message);
|
||||
environment = {};
|
||||
}
|
||||
|
||||
const config = merge(defaults, environment);
|
||||
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 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' });
|
||||
|
@ -31,11 +42,17 @@ const htmlTemplate = Handlebars.compile(htmlSource);
|
|||
const textTemplate = Handlebars.compile(textSource);
|
||||
|
||||
var server = restify.createServer();
|
||||
server.use(restify.CORS());
|
||||
server.use(restify.bodyParser());
|
||||
server.pre(cors.preflight);
|
||||
server.use(cors.actual);
|
||||
server.use(
|
||||
restify.plugins.bodyParser({
|
||||
mapParams: true,
|
||||
})
|
||||
);
|
||||
|
||||
server.get('/status', (req, res, next) => {
|
||||
res.send('contact running');
|
||||
return next();
|
||||
});
|
||||
|
||||
server.post('/:_to', (req, res, next) => {
|
||||
|
@ -49,13 +66,14 @@ server.post('/:_to', (req, res, next) => {
|
|||
formData,
|
||||
auth: {
|
||||
user: 'api',
|
||||
pass: MAILGUN_API_KEY
|
||||
pass: MAILGUN_API_KEY,
|
||||
},
|
||||
url: MAILGUN_URL,
|
||||
method: 'post'
|
||||
method: 'post',
|
||||
};
|
||||
|
||||
sendMail(fields, params).then(response => {
|
||||
sendMail(fields, params)
|
||||
.then(response => {
|
||||
const redirect = get(fields, 'next');
|
||||
if (redirect) {
|
||||
res.redirect(redirect, next);
|
||||
|
@ -64,7 +82,8 @@ server.post('/:_to', (req, res, next) => {
|
|||
}
|
||||
|
||||
return next();
|
||||
}).catch(error => {
|
||||
})
|
||||
.catch(error => {
|
||||
return next(error);
|
||||
});
|
||||
});
|
||||
|
@ -104,8 +123,8 @@ function parseRequest (req) {
|
|||
value,
|
||||
options: {
|
||||
filename: get(attachment, 'name'),
|
||||
contentType: get(attachment, 'type')
|
||||
}
|
||||
contentType: get(attachment, 'type'),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
|
2654
package-lock.json
generated
Normal file
2654
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
10
package.json
10
package.json
|
@ -17,11 +17,11 @@
|
|||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"handlebars": "4.0.5",
|
||||
"indecent": "1.0.1",
|
||||
"lodash": "4.13.1",
|
||||
"request": "2.72.0",
|
||||
"restify": "4.1.1"
|
||||
"handlebars": "4.1.2",
|
||||
"lodash": "4.17.11",
|
||||
"request": "2.88.0",
|
||||
"restify": "8.3.2",
|
||||
"restify-cors-middleware": "1.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"semistandard": "*"
|
||||
|
|
Loading…
Reference in a new issue