diff --git a/app/config/db.config.js b/app/config/db.config.js index b78ef2d..6247742 100644 --- a/app/config/db.config.js +++ b/app/config/db.config.js @@ -1,16 +1,10 @@ const Sequelize = require('sequelize'), DonorsModel = require('../models/donors.model.js'), - CampaignsModel = require('../models/campaigns.model.js'); + GrantsModel = require('../models/grants.model.js'); -const host = 'am1shyeyqbxzy8gc.cbetxkdyhwsb.us-east-1.rds.amazonaws.com', - username = 'fyro63k2989tyibh', - password = 'ykjkyenyvxig208z', - port = '3306', - database = 'n0j9gxnf4ijr7g8t'; +const connection_uri = process.env.JAWSDB_MARIA_URL; -const sequelize = new Sequelize(database, username, password, { - host: host, - dialect: 'mysql', +const sequelize = new Sequelize(connection_uri, { operatorsAliases: false, // research for pool/connections @@ -21,17 +15,24 @@ const sequelize = new Sequelize(database, username, password, { idle: 10000 }, + // default options for all models + define: { + underscored: true, // true: use underscore for automatically added attributes like timestamps below + freezeTableName: true, // true: table name/first parameter of define method will be table name + timestamps: true // createdAt and updatedAt automatically added + }, + // disable logging; default: console.log logging: false }); const db = {}; -//creating tables/models from imported function +//creating tables/models from imported functions const Donors = DonorsModel(sequelize, Sequelize); -const Campaigns = CampaignsModel(sequelize, Sequelize); +const Grants = GrantsModel(sequelize, Sequelize); db.donors = Donors; -db.campaigns = Campaigns; +db.grants = Grants; db.Sequelize = Sequelize; db.sequelize = sequelize; diff --git a/app/controllers/auth.controller.js b/app/controllers/auth.controller.js index 63b41be..391ee83 100644 --- a/app/controllers/auth.controller.js +++ b/app/controllers/auth.controller.js @@ -1,11 +1,12 @@ const db = require('../config/db.config.js'), bcrypt = require('bcrypt-nodejs'), - jwt = require('jsonwebtoken'); + jwt = require('jsonwebtoken'), + errorMaker = require('../helpers/error.maker'); const Donors = db.donors; // Find a Donor by email + login with JWT -exports.login = (req, res) => { +exports.login = (req, res, next) => { Donors.findAll({ where: { email: req.body.email @@ -13,15 +14,11 @@ exports.login = (req, res) => { }) .then(donors => { if (donors.length < 1) { - return res.status(401).json({ - message: 'Auth failed' - }); + return next(errorMaker(401, 'Invalid or nonexistent email')); } bcrypt.compare(req.body.password, donors[0].password, (error, result) => { if (error) { - return res.status(401).json({ - message: 'Auth failed' - }); + return next(error); } if (result) { const token = jwt.sign( @@ -40,16 +37,8 @@ exports.login = (req, res) => { token }); } - return res.status(401).json({ - message: 'Auth failed' - }); + return next(errorMaker(401, 'Invalid user')); }); }) - .catch(error => { - console.log(error); - - return res.status(500).json({ - error - }); - }); + .catch(error => next(error)); }; diff --git a/app/controllers/donors.controller.js b/app/controllers/donors.controller.js index 654bcbe..aa13f78 100644 --- a/app/controllers/donors.controller.js +++ b/app/controllers/donors.controller.js @@ -13,17 +13,13 @@ exports.create = (req, res) => { }) .then(donors => { if (donors.length >= 1) { - return res.status(409).json({ - message: 'Email exists' - }); + return next(errorMaker(409, `Email Exists: ${req.body.email}`)); } else { // hash and store bcrypt.hash(req.body.password, null, null, function(error, hash) { // Store hash in your password DB. if (error) { - return res.status(500).json({ - error - }); + return next(error); } else { Donors.create({ first_name: req.body.first_name, @@ -45,20 +41,12 @@ exports.create = (req, res) => { donor }); }) - .catch(error => { - return res.status(500).json({ - error - }); - }); + .catch(error => next(error)); } }); } }) - .catch(error => { - return res.status(500).json({ - error - }); - }); + .catch(error => next(error)); }; // FETCH all Donors diff --git a/app/helpers/error.maker.js b/app/helpers/error.maker.js new file mode 100644 index 0000000..1fdc33a --- /dev/null +++ b/app/helpers/error.maker.js @@ -0,0 +1,5 @@ +module.exports = (status, message) => { + const error = new Error(message); + error.status = status; + return error; +}; diff --git a/app/middleware/check-auth.js b/app/middleware/check-auth.js index 8496680..fd4e5de 100644 --- a/app/middleware/check-auth.js +++ b/app/middleware/check-auth.js @@ -1,15 +1,14 @@ -const jwt = require('jsonwebtoken'); +const jwt = require('jsonwebtoken'), + errorMaker = require('../helpers/error.maker'); module.exports = (req, res, next) => { try { const token = req.headers.authorization.split(' ')[1]; const decoded = jwt.verify(token, process.env.JWT_KEY); - req.donorData = decoded; //for use till end of request + req.userData = decoded; //for use till end of request next(); } catch (error) { - return res.status(401).json({ - message: 'Auth failed' - }); + return next(error); } }; diff --git a/app/models/campaigns.model.js b/app/models/campaigns.model.js deleted file mode 100644 index cf55878..0000000 --- a/app/models/campaigns.model.js +++ /dev/null @@ -1,23 +0,0 @@ -module.exports = (sequelize, DataTypes) => { - const Campaigns = sequelize.define('campaigns', { - id: { - type: DataTypes.INTEGER, - primaryKey: true, - autoIncrement: true - }, - first_name: DataTypes.STRING, - middle_name: DataTypes.STRING, - last_name: DataTypes.STRING, - email: DataTypes.STRING, - phone: DataTypes.STRING, - address: DataTypes.STRING, - city: DataTypes.STRING, - state: DataTypes.STRING, - country: DataTypes.STRING, - }, - { - freezeTableName: true, - } - ); - return Campaigns; -} \ No newline at end of file diff --git a/app/models/donors.model.js b/app/models/donors.model.js index 35dec49..fc44809 100644 --- a/app/models/donors.model.js +++ b/app/models/donors.model.js @@ -1,40 +1,34 @@ module.exports = (sequelize, DataTypes) => { - const Donors = sequelize.define( - 'donors', - { - id: { - type: DataTypes.INTEGER, - primaryKey: true, - autoIncrement: true - }, - first_name: { - type: DataTypes.STRING, - allowNull: false - }, - middle_name: DataTypes.STRING, - last_name: { - type: DataTypes.STRING, - allowNull: false - }, - email: { - type: DataTypes.STRING, - isEmail: true, - allowNull: false - }, - password: { - type: DataTypes.STRING, - allowNull: false - }, - age: DataTypes.INTEGER, - phone: DataTypes.BIGINT, - address: DataTypes.STRING, - city: DataTypes.STRING, - state: DataTypes.STRING, - country: DataTypes.STRING + const Donors = sequelize.define('donors', { + id: { + type: DataTypes.INTEGER, + primaryKey: true, + autoIncrement: true }, - { - freezeTableName: true - } - ); + first_name: { + type: DataTypes.STRING, + allowNull: false + }, + middle_name: DataTypes.STRING, + last_name: { + type: DataTypes.STRING, + allowNull: false + }, + email: { + type: DataTypes.STRING, + isEmail: true, + allowNull: false + }, + password: { + type: DataTypes.STRING, + allowNull: false + }, + age: DataTypes.INTEGER, + phone: DataTypes.BIGINT, + address: DataTypes.STRING, + city: DataTypes.STRING, + state: DataTypes.STRING, + country: DataTypes.STRING + }); return Donors; }; diff --git a/app/models/grants.model.js b/app/models/grants.model.js new file mode 100644 index 0000000..6e14af5 --- /dev/null +++ b/app/models/grants.model.js @@ -0,0 +1,21 @@ +module.exports = (sequelize, DataTypes) => { + const Campaigns = sequelize.define('campaigns', { + id: { + type: DataTypes.INTEGER, + primaryKey: true, + autoIncrement: true + }, + // user_id: { + // type: DataTypes.INTEGER, + // references: { + // // This is a reference to another model + // model: Donors, + // // This is the column name of the referenced model + // key: 'id' + // } + // }, + name: DataTypes.STRING, + amount: DataTypes.INTEGER + }); + return Campaigns; +}; diff --git a/app/routes/donors.route.js b/app/routes/donors.route.js index 3f7aa17..9286483 100644 --- a/app/routes/donors.route.js +++ b/app/routes/donors.route.js @@ -4,7 +4,7 @@ const express = require('express'), const donors = require('../controllers/donors.controller.js'); -// Create a new Donor +// Signup route router.post('/', donors.create); // Retrieve all Donors diff --git a/bin/dev.js b/bin/dev.js new file mode 100644 index 0000000..5e632d7 --- /dev/null +++ b/bin/dev.js @@ -0,0 +1,2 @@ +require('dotenv/config'); +require('../server'); diff --git a/package-lock.json b/package-lock.json index 659cac2..398e440 100644 --- a/package-lock.json +++ b/package-lock.json @@ -117,6 +117,12 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" }, + "dotenv": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-6.2.0.tgz", + "integrity": "sha512-HygQCKUBSFl8wKQZBSemMywRWcEDNidvNbjGVyZu3nbZ8qq9ubiPoGLMdRDpfSrpkkm9BXYFkpKxxFX38o/76w==", + "dev": true + }, "dottie": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.1.tgz", diff --git a/package.json b/package.json index 23fefdd..952b67e 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "PORT=4200 & set JWT_KEY=secretkey & node server.js", - "dev": "set NODE_ENV=test & set PORT=4205 & set JWT_KEY=secretkey & nodemon server.js" + "dev": "nodemon bin/dev.js" }, "repository": { "type": "git", @@ -25,5 +25,8 @@ "jsonwebtoken": "^8.4.0", "mysql2": "^1.6.4", "sequelize": "^4.42.0" + }, + "devDependencies": { + "dotenv": "^6.2.0" } } diff --git a/server.js b/server.js index 3dfd52f..5746c0d 100644 --- a/server.js +++ b/server.js @@ -1,9 +1,8 @@ //require dependencies const express = require('express'), app = express(), - router = express.Router(), bodyParser = require('body-parser'), - port = process.env.PORT || 4200, + port = process.env.PORT, db = require('./app/config/db.config.js'); app.use(bodyParser.json()); @@ -34,13 +33,13 @@ db.sequelize console.error('Unable to connect to the database:', err); }); -// force: true will drop the table if it already exists +//force: true will drop the table if it already exists const drop_tables = false; db.sequelize.sync({ force: drop_tables }).then(() => { console.log(`Drop and Resync with { force: ${drop_tables} }`); }); -//define a route, usually this would be a bunch of routes imported from another file +//main route for api; perhaps for api docs frontend app.get('/', function(req, res, next) { res.send('Welcome to the Ucharify API'); }); @@ -49,18 +48,26 @@ app.get('/', function(req, res, next) { app.use('/api/donors', require('./app/routes/donors.route.js')); app.use('/api/auth', require('./app/routes/auth.route.js')); +//404 not found error handling on any other routes app.use((req, res, next) => { const error = new Error('Not found'); error.status = 404; next(error); }); +//General error handler for anything app.use((error, req, res, next) => { + //can log the error internally + // console.log(error); + + if (req.app.get('env') !== 'development' && req.app.get('env') !== 'test') { + delete error.stack; + } + + //status is set from other logic depending on the error itself res.status(error.status || 500); res.json({ - error: { - message: error.message - } + error: error.message }); });