Skip to content

Commit cf5702b

Browse files
authored
Merge pull request #88 from CodeForBaltimore/revjtanton/v1-finalize
feat: Adding production support
2 parents 0cbf201 + 6acd386 commit cf5702b

File tree

10 files changed

+729
-38
lines changed

10 files changed

+729
-38
lines changed

Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ RUN npm install
1212
# Bundle app source
1313
COPY . .
1414

15+
1516
# Expose port (will not be respected by Heroku, must be defined in app)
1617
EXPOSE $port
1718

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ Our API spec is on Swagger. You can view it here https://app.swaggerhub.com/apis
3232
Our database documentation can be found in our `docs` folder under `database.csv`. This documentation was created using SchemaSpy. Instructions for use can be found here https://github.com/bcgov/schemaspy
3333

3434
# Setup
35-
A `Dockerfile` and `docker-compose` file have been included for convenience, however this may not be the best local setup for this project. For more information on how to use Docker with this project, please see the [docker section](#24-docker).
35+
A `Dockerfile` and `docker-compose` file have been included for convenience, however this may not be the best local setup for this project. For more information on how to use Docker with this project, please see the [docker section](#docker).
3636

3737
To work on this project you should have:
3838
- NodeJS
@@ -86,9 +86,9 @@ To make this easier included below is an example `.env` file using all default v
8686
```
8787
NODE_ENV=development
8888
PORT=3000
89-
DATABASE_SCHEMA=public
9089
JWT_KEY=test123
9190
DATABASE_URL=postgres://postgres:postgres@localhost:5432/postgres
91+
DATABASE_SCHEMA=public
9292
BYPASS_LOGIN=true
9393
```
9494

@@ -114,7 +114,7 @@ To create new models, migrations, and seeders you _must_ use the Sequelize CLI c
114114
- `npx sequelize-cli seed:generate --name demo-user` - Creates a seeder for the `User` model and migration previously setup.
115115

116116
## Docker
117-
To use the `docker-compose.yml` file included you will first need to set [environment variables](#22-environment-variables). You **MUST** set your `DATABASE_HOST` to `db` to use the `docker-compose` solution.
117+
To use the `docker-compose.yml` file included you will first need to set [environment variables](#environment-variables). You **MUST** set your `DATABASE_HOST` to `db` to use the `docker-compose` solution.
118118

119119
If you are running your own database, but want to use the `Dockerfile` you will need to run that this way:
120120
```
@@ -127,9 +127,9 @@ You can manually set the environment variables and not use a `.env` file by sett
127127
```
128128
-e NODE_ENV=development
129129
-e PORT=3000
130-
-e DATABASE_DATABASE_SCHEMA=<your database schema>
131130
-e JWT_KEY=<your JWT phrase>
132131
-e DATABASE_URL=<your connection string>
132+
-e DATABASE_DATABASE_SCHEMA=<your database schema>
133133
```
134134

135135
# Using this product

docs/swagger/swagger.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,10 @@
404404
"type" : "string",
405405
"example" : "The Leftorium"
406406
},
407+
"type" : {
408+
"type" : "string",
409+
"example" : "Store"
410+
},
407411
"address" : {
408412
"type" : "object",
409413
"properties" : {
@@ -613,6 +617,10 @@
613617
"type" : "string",
614618
"example" : "The Leftorium"
615619
},
620+
"type" : {
621+
"type" : "string",
622+
"example" : "Store"
623+
},
616624
"address" : {
617625
"type" : "object",
618626
"properties" : {
@@ -1257,6 +1265,10 @@
12571265
"type" : "string",
12581266
"example" : "The Leftorium"
12591267
},
1268+
"type" : {
1269+
"type" : "string",
1270+
"example" : "Store"
1271+
},
12601272
"address" : {
12611273
"type" : "object",
12621274
"properties" : {

rds-combined-ca-bundle.pem

Lines changed: 624 additions & 0 deletions
Large diffs are not rendered by default.

sequelize/config.js

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,26 @@
11
require('dotenv').config();
2+
const fs = require('fs');
3+
const rdsCa = fs.readFileSync('./rds-combined-ca-bundle.pem');
4+
25
module.exports = {
36
development: {
4-
use_env_variable: 'DATABASE_URL',
5-
dialect: 'postgres',
6-
}
7+
use_env_variable: 'DATABASE_URL',
8+
dialect: 'postgres',
9+
},
10+
production: {
11+
use_env_variable: 'DATABASE_URL',
12+
dialect: 'postgres',
13+
dialectOptions: {
14+
ssl: {
15+
rejectUnauthorized: true,
16+
ca: [rdsCa],
17+
checkServerIdentity: (host, cert) => {
18+
const error = tls.checkServerIdentity(host, cert);
19+
if (error && !cert.subject.CN.endsWith('.rds.amazonaws.com')) {
20+
return error;
21+
}
22+
}
23+
}
24+
}
25+
},
726
};

src/models/index.js

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,40 @@ import Sequelize from 'sequelize';
22
import path from 'path';
33
import fs from 'fs';
44
import _ from 'lodash';
5-
5+
const rdsCa = fs.readFileSync('./rds-combined-ca-bundle.pem');
6+
console.log(__dirname)
67
let dbUrl;
7-
88
if (process.env.DATABASE_URL) {
99
dbUrl = process.env.DATABASE_URL;
1010
} else {
1111
dbUrl = `postgres://${process.env.DATABASE_USERNAME}:${process.env.DATABASE_PASSWORD}@${process.env.DATABASE_HOST}:${process.env.DATABASE_PORT}/${process.env.DATABASE_NAME}`;
1212
}
1313

14+
// Securing our db connection if prod
15+
/** @todo allow other options besides RDS */
16+
17+
let dialectOptions;
18+
if (process.env.NODE_ENV === 'production') {
19+
dialectOptions = {
20+
ssl: {
21+
rejectUnauthorized: true,
22+
ca: [rdsCa],
23+
checkServerIdentity: (host, cert) => {
24+
const error = tls.checkServerIdentity(host, cert);
25+
if (error && !cert.subject.CN.endsWith('.rds.amazonaws.com')) {
26+
return error;
27+
}
28+
}
29+
}
30+
};
31+
}
32+
1433
// Initializes the database.
1534
const sequelize = new Sequelize(
1635
dbUrl,
1736
{
18-
dialect: 'postgres'
37+
dialect: 'postgres',
38+
dialectOptions: dialectOptions
1939
}
2040
);
2141
const basename = path.basename(__filename);
@@ -47,5 +67,5 @@ Object.keys(models).forEach(key => {
4767
}
4868
});
4969

50-
export {sequelize};
70+
export { sequelize };
5171
export default models;

src/routes/contact.js

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,13 @@ router.post('/', async (req, res) => {
6060
try {
6161
if (req.body.name !== undefined) {
6262
const { name, phone, email, UserId, EntityId } = req.body;
63+
64+
// Validating emails
65+
if (email) {
66+
const goodEmail = await utils.validateEmails(email);
67+
if (!goodEmail) return utils.response(res, 422);
68+
}
69+
6370
const contact = await req.context.models.Contact.create({ name, email, phone, UserId, EntityId });
6471

6572
code = 200;
@@ -83,9 +90,11 @@ router.put('/', async (req, res) => {
8390
if (validator.isUUID(req.body.id)) {
8491
const { id, name, phone, email, UserId, EntityId } = req.body;
8592

86-
/** @todo validate emails */
8793
// Validating emails
88-
// if (await !utils.validateEmails(email)) res.status(500).send('Server error');
94+
if (email) {
95+
const goodEmail = await utils.validateEmails(email);
96+
if (!goodEmail) return utils.response(res, 422);
97+
}
8998

9099
const contact = await req.context.models.Contact.findOne({
91100
where: {

src/routes/entity.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,14 @@ import validator from 'validator';
33
import utils from '../utils';
44

55
const router = new Router();
6-
router.use(utils.authMiddleware)
6+
router.use(utils.authMiddleware);
77

88
// Gets all entities.
99
router.get('/', async (req, res) => {
1010
let code;
1111
let message;
1212
try {
13-
const entities = await req.context.models.Entity.findAll({
14-
});
13+
const entities = await req.context.models.Entity.findAll();
1514

1615
code = 200;
1716
message = {
@@ -101,7 +100,7 @@ router.put('/', async (req, res) => {
101100
let code;
102101
let message;
103102
try {
104-
if (validator.isUUID(req.body.id)) {
103+
if (validator.isUUID(req.body.id) && validator.isEmail(req.body.email)) {
105104
let { id, name, address, phone, email, checkIn } = req.body;
106105

107106
/** @todo validate emails */

src/routes/user.js

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -124,27 +124,29 @@ router.get('/:email', utils.authMiddleware, async (req, res) => {
124124
return utils.response(res, code, message);
125125
});
126126

127-
// Creates a new user.
128-
router.post('/', async (req, res) => {
129-
let code;
130-
let message;
131-
try {
132-
if (validator.isEmail(req.body.email)) {
133-
const { email, password, roles } = req.body;
134-
const user = await req.context.models.User.create({ email, password, roles });
135-
136-
code = 200;
137-
message = user.email + ' created';
138-
} else {
139-
code = 422;
127+
// Creates a new user. ONLY if we're in dev
128+
if (process.env.NODE_ENV === 'development') {
129+
router.post('/', async (req, res) => {
130+
let code;
131+
let message;
132+
try {
133+
if (validator.isEmail(req.body.email)) {
134+
const { email, password, roles } = req.body;
135+
const user = await req.context.models.User.create({ email, password, roles });
136+
137+
code = 200;
138+
message = user.email + ' created';
139+
} else {
140+
code = 422;
141+
}
142+
} catch (e) {
143+
console.error(e);
144+
code = 500;
140145
}
141-
} catch (e) {
142-
console.error(e);
143-
code = 500;
144-
}
145-
146-
return utils.response(res, code, message);
147-
});
146+
147+
return utils.response(res, code, message);
148+
});
149+
}
148150

149151
// Updates any user.
150152
router.put('/', utils.authMiddleware, async (req, res) => {

src/utils/index.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,12 @@ const authMiddleware = async (req, res, next) => {
5959

6060
}
6161

62+
/**
63+
*
64+
* @param {*} res the response object
65+
* @param {Number} code the response code
66+
* @param {String} message a custom response message
67+
*/
6268
const response = (res, code, message) => {
6369
const codes = {
6470
200: message,
@@ -97,7 +103,6 @@ const encryptPassword = (password, salt) => {
97103
*/
98104
const validateEmails = async emails => {
99105
for (let email of emails) {
100-
console.log(email.address)
101106
if (!validator.isEmail(email.address)) return false;
102107
}
103108

0 commit comments

Comments
 (0)