diff --git a/CONTRIBUTE.md b/CONTRIBUTE.md new file mode 100644 index 0000000..a20ac6d --- /dev/null +++ b/CONTRIBUTE.md @@ -0,0 +1,19 @@ +/* CONTRIBUTE */ + +This is the contribute.md of our project. Great to have you here. Here are a few ways you can help make this project better! + +# Contribute.md + +## Team members + +This section introduces the core team members. + +* James Dickerson +* Misha Devine +* Keown Creese +* Chris Fortin +* Aldo Gonzalez +* Jacob Nigh +* Tyler Richard +* Brad Beltowski +* Chris Chapman diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..4705f62 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,8 @@ +The MIT License (MIT) +Copyright (c) 2016 Gravity + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Procfile b/Procfile new file mode 100644 index 0000000..255a64e --- /dev/null +++ b/Procfile @@ -0,0 +1 @@ +web: node server/server.js diff --git a/models/inventory.js b/models/inventory.js new file mode 100644 index 0000000..a4ca002 --- /dev/null +++ b/models/inventory.js @@ -0,0 +1,52 @@ +'use strict'; +module.exports = function() { + const db = require('../server/db.js'); + const sequelize = db.connection; + + function _create(data, err, success) { + let payload = data; + db.inventory.create(payload) + .then(success) + .catch(err); + } + + function _update(data, err, success) { + let payload = data; + db.inventory.find({where: {sku: payload.sku}}) + .then(function(matchedOrder) { + matchedOrder.updateAttributes(data) + .then(success) + .catch(err) + }) + .catch(err) + } + + function _find(data, err, success) { + let payload = data; + db.inventory.findAll({where: {sku: payload.sku}}) + .then(success) + .catch(err); + } + + function _findAll(err, success) { + db.inventory.findAll() + .then(success) + .catch(err); + } + + function _destroy(data, err, success) { + let payload = data; + db.inventory.destroy({where: {sku: payload.sku}}) + .then(success) + .catch(err); + } + + return { + create: _create, + update: _update, + find: _find, + findAll: _findAll, + destroy: _destroy + } + +}(); diff --git a/models/ordered-items.js b/models/ordered-items.js new file mode 100644 index 0000000..220e17e --- /dev/null +++ b/models/ordered-items.js @@ -0,0 +1,54 @@ +'use strict'; +module.exports = function() { + const db = require('../server/db.js'); + const sequelize = db.connection; + + function _create(data, err, success) { + for(let i = 0; i < data.units.length; i++) { + data.units[i].uuid = data.uuid; + db.orderedItems.create(data.units[i]) + .then(success) + .catch(err); + } + } + + function _update(data, err, success) { + let payload = data; + db.orderedItems.find({where: {uuid: payload.uuid}}) + .then(function(matchedOrder) { + matchedOrder.updateAttributes(data) + .then(success) + .catch(err); + }) + .catch(err); + } + + function _find(data, err, success) { + let payload = data; + db.orderedItems.findAll({where: {uuid: payload.uuid}}) + .then(success) + .catch(err); + } + + function _findAll(err, success) { + db.orderedItems.findAll() + .then(success) + .catch(err); + } + + function _destroy(data, err, success) { + let payload = data; + db.orderedItems.destroy({where: {uuid: payload.uuid}}) + .then(success) + .catch(err); + } + + return { + create: _create, + update: _update, + find: _find, + findAll: _findAll, + destroy: _destroy + } + +}(); diff --git a/models/orders.js b/models/orders.js new file mode 100644 index 0000000..be960cf --- /dev/null +++ b/models/orders.js @@ -0,0 +1,52 @@ +'use strict'; +module.exports = function() { + const db = require('../server/db.js'); + const sequelize = db.connection; + + function _create(data, err, success) { + let payload = data; + db.orders.create(data) + .then(success) + .catch(err); + } + + function _update(data, err, success) { + let payload = data; + db.orders.find({where: payload}) + .then(function(matchedOrder) { + matchedOrder.updateAttributes(data) + .then(success) + .catch(err); + }) + .catch(err); + } + + function _find(data, err, success) { + let payload = data; + db.orders.find({where: payload}) + .then(success) + .catch(err); + } + + function _findAll(err, success) { + db.orders.findAll() + .then(success) + .catch(err); + } + + function _destroy(data, err, success) { + let payload = data; + db.orders.destroy({where: {uuid: payload.uuid}}) + .then(success) + .catch(err); + } + + return { + create: _create, + update: _update, + find: _find, + findAll: _findAll, + destroy: _destroy + } + +}(); diff --git a/models/units.js b/models/units.js new file mode 100644 index 0000000..8537625 --- /dev/null +++ b/models/units.js @@ -0,0 +1,52 @@ +'use strict'; +module.exports = function() { + const db = require('../server/db.js'); + const sequelize = db.connection; + + function _create(data, err, success) { + let payload = data; + db.units.create(payload) + .then(success) + .catch(err); + } + + function _update(data, err, success) { + let payload = data; + db.units.findAll({where: {sku: payload.sku}}) + .then(function(matchedOrder) { + matchedOrder.updateAttributes(data) + .then(success) + .catch(err); + }) + .catch(err); + } + + function _find(data, err, success) { + let payload = data; + db.units.findAll({where: {sku: payload.sku}}) + .then(success) + .catch(err) + } + + function _findAll(err, success) { + db.units.findAll() + .then(success) + .catch(err) + } + + function _destroy(data, err, success) { + let payload = data; + db.units.destroy({where: {sku: payload.sku}}) + .then(success) + .catch(err); + } + + return { + create: _create, + update: _update, + find: _find, + findAll: _findAll, + destroy: _destroy + } + +}(); diff --git a/order_bot/request.js b/order_bot/request.js index 4f81058..3bd4b8c 100644 --- a/order_bot/request.js +++ b/order_bot/request.js @@ -3,7 +3,7 @@ const request = require('request'); const faker = require('faker'); // Hits variable controls how many times the request loop will autoamtically run -let hits = 900; +let hits = 1; // Automated request loop let i; @@ -13,25 +13,22 @@ for(i = 0; i < hits; i++) { * Faker API documentation at https://github.com/marak/faker.js */ const payload = { - units: [ + "units": [ { - sku: 'a5296ab9-9eee-7ba0-0a79-b801594f2c91', - quantity: faker.random.number()}, + "sku": 'a5296ab9-9eee-7ba0-0a79-b801594f2c91', + "quantity": 5}, { - sku: 'a5296ab9-9eee-7ba0-0a79-b801594f2c92', - quantity: faker.random.number()} - ], - recipients: { - name: faker.name.findName(), - address: { - street: faker.address.streetAddress(), - city: faker.address.city(), - state: faker.address.stateAbbr(), - zip: faker.address.zipCode() - }, - phone: faker.phone.phoneNumberFormat(), - email: faker.internet.email() - } + "sku": 'a5296ab9-9eee-7ba0-0a79-b801594f2c92', + "quantity": 2} + ], + + "fullName": "James Dickerson", + "streetAddress": "14250 Cheval Mayfaire", + "city": "Orlando", + "state": "FL", + "zip": "32828", + "phone": "305-710-8220", + "email": "jamesalexanderdickerson@gmail.com" }; /** diff --git a/package.json b/package.json index daaf393..4b9eabb 100644 --- a/package.json +++ b/package.json @@ -5,23 +5,30 @@ "main": "server.js", "scripts": { "test": "echo \"Tests not setup yet\" && exit 0", - "start": "node server.js" + "start": "node server/server.js" }, "repository": { "type": "git", "url": "git+https://github.com/reactivepixel/Gravity.git" }, "author": "", - "license": "ISC", + "license": "MIT", "bugs": { "url": "https://github.com/reactivepixel/Gravity/issues" }, "homepage": "https://github.com/reactivepixel/Gravity#readme", "dependencies": { + "async": "1.5.2", "body-parser": "1.15.0", "express": "4.13.4", - "faker": "3.0.1", + "mysql": "2.10.2", "request": "2.69.0", "sequelize": "3.19.2" + }, + "devDependencies": { + "dotenv": "2.0.0", + "faker": "3.0.1", + "mocha": "2.4.5", + "supertest": "1.2.0" } } diff --git a/readme.md b/readme.md index 8e5d3fb..6bf6915 100644 --- a/readme.md +++ b/readme.md @@ -1,6 +1,67 @@ -# Gravity +# InventoryManager -Business backend logic for Sol +Business backend logic for Gravity + +## Setting up + +Clone the git repository to your machine using ssh. +``` +$ git clone git@github.com:reactivepixel/Gravity.git +$ npm install //Installs the package.json file. +``` + +## Database Installation + +### Installing MySQL & adding .env file + +Check to see if you have MySQL installed on your machine. +``` +$ mysql --version +``` + +If MySQL is not installed. Install it with [Homebrew](http://brew.sh/). +``` +$ brew install mysql +``` + +Start MySQL server. +``` +$ mysql.server start //Starting MySQL server. +$ mysql -u root //Logging in as root. +``` +Once logged into MySQL. +``` +mysql> create database gravity; +``` + +Create an .env file in your root directory. +``` +$ touch .env + +//Add this to the .env file +DB_HOST=localhost +DB_NAME=gravity +DB_USER={local user} //Default root unless otherwise specified. +DB_PASS={local password} //Standard install is set to blank. +DB_PORT={local port running mysql} //Standard port is 3306. +``` + +If MySQL does not work try: +``` +$ mysql.server restart +``` + +## Server Environments +Here are the links to all the Environments + +# Development +Link to [Development](https://github.com/reactivepixel/Gravity/tree/server_dev). + +# Staging +Link to [Staging](https://github.com/reactivepixel/Gravity/tree/db_create). + +# Production +Link to [Production](https://github.com/reactivepixel/Gravity/tree/master) ## API Documentation @@ -9,32 +70,30 @@ Business backend logic for Sol | Endpoint | Method | Development Status | |---|---|:---:| -| `/order` | `PUT` | In Progress | +| `/order` | `PUT` | In Production | ##### Request ```javascript { - order: { - units: [ - { - sku: 'a5296ab9-9eee-7ba0-0a79-b801594f2c91', - quantity: 1}, - { - sku: 'a5296ab9-9eee-7ba0-0a79-b801594f2c91', - quantity: 1} - ], - recipients: { - name: 'John Doe', - address:{ - street: '3300 University Blvd', - city: 'Winter Park', - state: 'FL', - zip: '32792' - }, - phone: '555-555-5555', - email: 'jdoe@gmail.com' - } + units: [ + { + sku: 'a5296ab9-9eee-7ba0-0a79-b801594f2c91', + quantity: 1}, + { + sku: 'a5296ab9-9eee-7ba0-0a79-b801594f2c91', + quantity: 1} + ], + recipients: { + name: 'John Doe', + address:{ + street: '3300 University Blvd', + city: 'Winter Park', + state: 'FL', + zip: '32792' + }, + phone: '555-555-5555', + email: 'jdoe@gmail.com' } } ``` @@ -43,34 +102,53 @@ Business backend logic for Sol ```javascript { - order: { - units: [ - { - sku: 'a5296ab9-9eee-7ba0-0a79-b801594f2c91', - quantity: 1}, - { - sku: 'a5296ab9-9eee-7ba0-0a79-b801594f2c91', - quantity: 1} - ], - recipients: { - name: 'John Doe', - address:{ - street: '3300 University Blvd', - city: 'Winter Park', - state: 'FL', - zip: '32792' - }, - phone: '555-555-5555', - email: 'jdoe@gmail.com' + units: [ + { + sku: 'a5296ab9-9eee-7ba0-0a79-b801594f2c91', + quantity: 1}, + { + sku: 'a5296ab9-9eee-7ba0-0a79-b801594f2c91', + quantity: 1} + ], + recipients: { + name: 'John Doe', + address:{ + street: '3300 University Blvd', + city: 'Winter Park', + state: 'FL', + zip: '32792' }, - uuid: 'generated uuid', - timestamp: '2/12/2016 2:10:25 AM' - } + phone: '555-555-5555', + email: 'jdoe@gmail.com' + }, + uuid: 'generated uuid', + timestamp: '2/12/2016 2:10:25 AM' } ``` + + + + + + + +## How To Adapt the Model Template + +To use the Unit model as a template for building out other models you will need to adjust the definition of your model in '/server/db.js'. It must contain the appropriate fields for your model to meet the documentation. db.js is just a rough structure and will need to be adjusted. + +Copy /server/models/unit.js and rename it to match your model. You will need to restructure the definitions in this file to reflect the changes you have made to /server/db.js + +## Documentation + +Each public method in /server/models/unit.js is documented according to the AirBNB Standards. Your own adaptation of this file means you will need to document its use. In your pull request if additional information is needed for team members to understand how to use your contributions please mark it down in the description of your pull request (just like I'm doing now). Additionally, copy / paste your modifications to the /readme.md file so this can be saved for later use by other devs. + + ## Contributing +See [Contribute.md](https://github.com/reactivepixel/Gravity/blob/order_bot/CONTRIBUTE.md) + for more information on how to contribute + 1. Fork it! 2. Create your feature branch: `git checkout -b my-new-feature` 3. Commit your changes: `git commit -am 'Add some feature'` diff --git a/routes/home.js b/routes/home.js index 891fdfe..4776f87 100644 --- a/routes/home.js +++ b/routes/home.js @@ -1,3 +1,4 @@ +'use strict'; module.exports = function (express) { // Config diff --git a/routes/inventory.js b/routes/inventory.js new file mode 100644 index 0000000..8b1ebfd --- /dev/null +++ b/routes/inventory.js @@ -0,0 +1,95 @@ +'use strict'; +module.exports = function(express) { + const router = express.Router(); + const async = require('async'); + let inventory = require('../models/inventory.js'); + const db = require('../server/db.js'); + + router.route('/') + + //Get request to access all records in database. + .get(function(req, res) { + inventory.findAll(function(err) { + //Encoutered an error. + res.status(500).json(err); + }, function(data) { + res.status(200).json(data); + }); + }) + + //Put request to create a record in database. + .put(function(req, res) { + // payload data is the request body + let data = req.body; + + var savedData = {}; + + async.waterfall([ + function(callback) { + // Create the inventory passing through the payload data + inventory.create(data, function(e) { + res.status(500).json({error: e}); + }, function(createdInventory) { + // pass the createdInventory to the next fn() to be able to access the createdInventory + callback(null, createdInventory.dataValues); + }); + }, + function(createdInventory, callback) { + // Find the newly created inventory passing through the createdInventory from the previous fn() + inventory.find(createdInventory, function(e) { + res.status(500).json({error: e}); + }, function(foundInventory) { + // Construct the final json object for the response + savedData = foundInventory; + // pass the final json object to the final fn() handling the error / response + callback(null, savedData); + }); + } + ], + function(err, savedData) { + // Display the error if there is one, otherwise, show the response data from the db + if(err) { + res.status(500).json({error: err}); + } else{ + res.status(200).json(savedData); + } + }); + }); + + router.route('/:sku') + + //Put request to update a record in the database. + .put(function(req, res) { + req.body.sku = req.params.sku; + inventory.update(req.body, function(err) { + //Encoutered an error. + res.status(500).json(err); + }, function(data) { + res.status(200).json(data); + }); + }) + + //Get request to read one record from the database. + .get(function(req, res) { + req.body.sku = req.params.sku; + inventory.find(req.body, function(err) { + //Encoutered an error. + res.status(500).json(err); + }, function(data) { + res.status(200).json(data); + }); + }) + + //Delete reuqest to remove one record from database. + .delete(function(req, res) { + req.body.sku = req.params.sku; + inventory.destroy(req.body, function(err) { + //Encoutered an error. + res.status(500).json(err); + }, function(data) { + res.status(200).json({success: data}); + }) + }) + + return router; +} diff --git a/routes/order.js b/routes/order.js index 9c4e04e..d57b265 100644 --- a/routes/order.js +++ b/routes/order.js @@ -1,26 +1,151 @@ -module.exports = function (express) { +'use strict'; +module.exports = function(express) { - // Config - const router = express.Router(); +// Config +const router = express.Router(); +const async = require('async'); +let orderedItems = require('../models/ordered-items.js'); +let orders = require('../models/orders.js'); +const db = require('../server/db.js'); - // Include uuid generator and timestamp generator - const uuid_generator = require('../server/uuid-generator.js'); - const timestamp = require('../server/timestamp.js'); +// Include uuid generator and timestamp generator +const uuid_generator = require('../server/uuid-generator.js'); +const timestamp = require('../server/timestamp.js'); - // Display - router.route('/') - .get(function(req, res) { - res.send('Making PUT request to /order'); - }) +// Display +router.route('/') + + //Get request to access all records in database. + .get(function(req, res) { + orders.findAll(function(err) { + //Encoutered an error. + res.status(500).json(err); + }, function(data) { + res.status(200).json(data); + }); + }) + + //Put request to create a record in database. + .put(function(req, res) { + // payload data is the request body + let data = req.body; + + // generating uuid and timestamp and adding them to the payload data + data.uuid = uuid_generator.generateUUID(); + data.timestamp = timestamp.makeTimestamp(); + + // declaring variable for the retrieved data from the db + var savedData = {}; + savedData.units = []; + + /* + * + * Async.waterfall() Quick Tip: + * + * The functions run in sequential order since some fn() are dependant on other fn() + * + * The .waterfall() method passes the result of the fn() in the callback(null, result) + * There can be more than one result added inside of the callback + * ex: callback(null, result1, result2, result3...); + * + * callback is the argument for every fn() except for the final fn() or if you don't + * need to pass on any data from the previous fn() + * + * The results are only immediately available in the next fn() + * + * More documentation can be found here: https://github.com/caolan/async + * + * TODO: Find a better way to handle the errors in the async.waterfall() + * + */ + async.waterfall([ + function(callback) { + // Create the order passing through the payload data + orders.create(data, function(e) { + res.status(500).json({error: e}); + }, function(createdOrder) { + // pass the createdOrder to the next fn() to be able to access the uuid + callback(null, createdOrder); + }) + }, + function(createdOrder, callback) { + // Find the newly created order passing through the createdOrder from the previous fn() + orders.find(createdOrder, function(e) { + res.status(500).json({error: e}); + }, function(foundOrder) { + // pass the foundOrder to the next fn() to still be able to access the uuid later on + callback(null, foundOrder); + }); + }, + function(foundOrder, callback) { + // Create the orderedItems by passing through the payload data + orderedItems.create(data, function(e) { + res.status(500).json({error: e}); + }, function(createdOrderedItem) { + // pass the foundOrder to the next fn() to construct the final object + callback(null, foundOrder); + }); + }, + function(foundOrder, callback) { + // Find the orderedItems passing through the foundOrder to find the matching orderedItems + orderedItems.find(foundOrder, function(e) { + res.status(500).json({error: e}); + }, function(foundOrderedItem) { + // Construct the final json object for the response + savedData = foundOrder.dataValues; + savedData.units = foundOrderedItem; + // pass the final json object to the final fn() handling the error / response + callback(null, savedData); + }); + } + ], + function(err, savedData) { + // Display the error if there is one, otherwise, show the response data from the db + if(err) { + res.status(500).json({error: err}); + } else{ + res.status(200).json(savedData); + } + }); - .put(function(req, res, body) { - const data = req.body; - // adding generated UUID and timestamp to the json data - data.uuid = uuid_generator.generateUUID(); - data.timestamp = timestamp.makeTimestamp(); - // ending the response and console logging the response data - console.log(data); + }); + + +router.route('/:uuid') + + //Put request to update a record in the database. + .put(function(req, res) { + req.body.uuid = req.params.uuid; + orders.update(req.body, function(err) { + //Encoutered an error. + res.status(500).json(err); + }, function(data) { + res.status(200).json(data); + }); + }) + + //Get request to read one record from the database. + .get(function(req, res) { + req.body.uuid = req.params.uuid; + orders.find(req.body, function(err) { + //Encoutered an error. + res.status(500).json(err); + }, function(data) { + res.status(200).json(data); }); + }) + + //Delete reuqest to remove one record from database. + .delete(function(req, res) { + req.body.uuid = req.params.uuid; + orders.destroy(req.body, function(err) { + //Encoutered an error. + res.status(500).json(err); + }, function(data) { + res.status(200).json({success: data}); + }) + }) + +return router; - return router; -}; +} diff --git a/routes/ordered-items.js b/routes/ordered-items.js new file mode 100644 index 0000000..22d376e --- /dev/null +++ b/routes/ordered-items.js @@ -0,0 +1,42 @@ +'use strict' +module.exports = function(express) { + const router = express.Router(); + let orderedItems = require('../models/ordered-items.js'); + const db = require('../server/db.js'); + + router.route('/') + .get(function(req, res) { + orderedItems.findAll(function(err) { + res.status(500).json(err); + }, function(data) { + res.status(200).json(data); + }); + }) + router.route('/:uuid') + .get(function(req, res) { + req.body.uuid = req.params.uuid; + orderedItems.find(req.body, function(err) { + res.status(500).json(err); + }, function(data) { + res.status(200).json(data); + }); + }) + .delete(function(req, res) { + req.body.uuid = req.params.uuid; + orderedItems.destroy(req.body, function(err) { + res.status(500).json(err); + }, function(data) { + res.status(200).json({success: data}); + }); + }) + .put(function(req, res) { + req.body.uuid = req.params.uuid; + orderedItems.update(req.body, function(err) { + res.status(500).json(err); + }, function(data) { + res.status(200).json(data); + }); + }) + + return router; +} diff --git a/routes/unit.js b/routes/unit.js new file mode 100644 index 0000000..e6b8ac9 --- /dev/null +++ b/routes/unit.js @@ -0,0 +1,95 @@ +'use strict'; +module.exports = function(express) { + const router = express.Router(); + const async = require('async'); + let units = require('../models/units.js'); + const db = require('../server/db.js'); + + router.route('/') + + //Get request to access all records in database. + .get(function(req, res) { + units.findAll(function(err) { + //Encoutered an error. + res.status(500).json(err); + }, function(data) { + res.status(200).json(data); + }); + }) + + //Put request to create a record in database. + .put(function(req, res) { + // payload data is the request body + let data = req.body; + + var savedData = {}; + + async.waterfall([ + function(callback) { + // Create the unit passing through the payload data + units.create(data, function(e) { + res.status(500).json({error: e}); + }, function(createdUnit) { + // pass the createdUnit to the next fn() + callback(null, createdUnit.dataValues); + }) + }, + function(createdUnit, callback) { + // Find the newly created unit passing through the createdUnit from the previous fn() + units.find(createdUnit, function(e) { + res.status(500).json({error: e}); + }, function(foundUnit) { + // Construct the final json object for the response + savedData = foundUnit; + // pass the final json object to the final fn() handling the error / response + callback(null, savedData); + }); + } + ], + function(err, savedData) { + // Display the error if there is one, otherwise, show the response data from the db + if(err) { + res.status(500).json({error: err}); + } else{ + res.status(200).json(savedData); + } + }); // End of .waterfall() + }); // End of PUT route + + router.route('/:sku') + + //Put request to update a record in the database. + .put(function(req, res) { + req.body.sku = req.params.sku; + units.update(req.body, function(err) { + //Encoutered an error. + res.status(500).json(err); + }, function(data) { + res.status(200).json(data); + }); + }) + + //Get request to read one record from the database. + .get(function(req, res) { + req.body.sku = req.params.sku; + units.find(req.body, function(err) { + //Encoutered an error. + res.status(500).json(err); + }, function(data) { + res.status(200).json(data); + }); + }) + + //Delete reuqest to remove one record from database. + .delete(function(req, res) { + req.body.sku = req.params.sku; + units.destroy(req.body, function(err) { + //Encoutered an error. + res.status(500).json(err); + }, function(data) { + res.status(200).json({success: data}); + }) + }) + + return router; +} diff --git a/server/db.js b/server/db.js index e69de29..8684a4d 100644 --- a/server/db.js +++ b/server/db.js @@ -0,0 +1,100 @@ +'use strict'; +module.exports = function() { + + // Requiring dependencies. + const dotenv = require('dotenv').load(); + const Sequelize = require('sequelize'); + const mysql = require('mysql'); + + // Initializing sequelize + const _sequelize = new Sequelize(process.env.DB_NAME, process.env.DB_USER, process.env.DB_PASS, { + host: process.env.DB_HOST, + dialect: 'mysql', + port: process.env.DB_PORT, + pool: { + max: 5, + min: 0, + idle: 10000 + } + }); + + // Creating inventory table schema + const _inventory = _sequelize.define('inventory', { + sku: { + type: Sequelize.STRING + }, + location: { + type: Sequelize.STRING + } + }); + + // Creating orderedItems table schema + const _orderedItems = _sequelize.define('orderedItems', { + sku: { + type: Sequelize.STRING + }, + quantity: { + type: Sequelize.STRING + } + }); + + // Creating orders table schema + const _orders = _sequelize.define('orders', { + uuid: { + type: Sequelize.STRING, + primaryKey: true + }, + fullName: { + type: Sequelize.STRING + }, + streetAddress: { + type: Sequelize.STRING + }, + city: { + type: Sequelize.STRING + }, + state: { + type: Sequelize.STRING + }, + zip: { + type: Sequelize.STRING + }, + phone: { + type: Sequelize.STRING + }, + email: { + type: Sequelize.STRING + }, + timestamp: { + type: Sequelize.STRING + } + }); + + // Creating units table schema + const _units = _sequelize.define('units', { + sku: { + type: Sequelize.STRING + }, + name: { + type: Sequelize.STRING + }, + description: { + type: Sequelize.STRING + } + }); + + + _orders.hasMany(_orderedItems, {foreignKey: 'uuid'}); + + // Syncs newly created tables and data inside the tables + _sequelize.sync(); + + // Returns data to be called in the models + return { + connection: _sequelize, + inventory: _inventory, + orderedItems: _orderedItems, + orders: _orders, + units: _units + }; +}(); diff --git a/server/server.js b/server/server.js index 14c690a..3b95f53 100644 --- a/server/server.js +++ b/server/server.js @@ -3,17 +3,23 @@ // Config const express = require('express'); const body_parser = require('body-parser'); + const app = express(); const port = process.env.PORT || 3000; -// Adding body parser +// Adding body parser to parse json automatically app.use(body_parser.json()); // Routes app.use('/', require('../routes/home.js')(express)); app.use('/order', require('../routes/order.js')(express)); +app.use('/inventory', require('../routes/inventory.js')(express)); +app.use('/orderedItems', require('../routes/ordered-items.js')(express)); +app.use('/units', require('../routes/unit.js')(express)); // Start server -app.listen(port, function() { +var server = app.listen(port, function() { console.log("Listening on " + port + "..."); }); + +module.exports = server; diff --git a/server/timestamp.js b/server/timestamp.js index 2d29711..545ae28 100644 --- a/server/timestamp.js +++ b/server/timestamp.js @@ -1,3 +1,4 @@ +'use strict'; module.exports = { // Created a function to get the date diff --git a/server/uuid-generator.js b/server/uuid-generator.js index 8758602..3724081 100644 --- a/server/uuid-generator.js +++ b/server/uuid-generator.js @@ -1,3 +1,4 @@ +'use strict'; module.exports = { // Create a function to generate a new UUID number diff --git a/test/__db-ordered-items.js b/test/__db-ordered-items.js new file mode 100644 index 0000000..ba0a0eb --- /dev/null +++ b/test/__db-ordered-items.js @@ -0,0 +1,60 @@ +const request = require('supertest'); + +describe('OrderItem Route', function() { + var server; + var testOrderItems; + + beforeEach(function() { + server = require('../server/server.js'); + }); + + afterEach(function() { + server.close(); + }); + + it('OrderItem Read All', function(done) { + request(server) + .get('/orderedItems') + .set('Accept', 'application/json') + .expect('Content-Type', /json/) + .expect(function(res) { + if(res.body.length < 1) throw new Error('There are no entries in the database.'); + testOrderItems = res.body; + }) + .expect(200, done); + }); + + it('OrderItem Read One', function(done) { + request(server) + .get('/orderedItems/' + testOrderItems[0].uuid) + .set('Accept', 'application/json') + .expect('Content-Type', /json/) + .expect(function(res) { + if(testOrderItems.uuid !== res.body.uuid) throw new Error('The UUID returned does not match.'); + }) + .expect(200, done); + }); + + it('OrderItem Update', function(done) { + request(server) + .get('/orderedItems/' + testOrderItems[0].uuid) + .set('Accept', 'application/json') + .expect('Content-Type', /json/) + .expect(function(res) { + if(testOrderItems.uuid !== res.body.uuid) throw new Error('Did not update record'); + }) + .expect(200, done); + }); + + it('OrderItem Destroy', function(done) { + request(server) + .delete('/orderedItems/' + testOrderItems[0].uuid) + .set('Accept', 'application/json') + .send({force: true}) + .expect('Content-Type', /json/) + .expect(function(res) { + if(!res.body.success) throw new Error ('Destroy failed.') + }) + .expect(200, done); + }); +}) diff --git a/test/__dbconnection.js b/test/__dbconnection.js new file mode 100644 index 0000000..c0a6976 --- /dev/null +++ b/test/__dbconnection.js @@ -0,0 +1,94 @@ +const request = require('supertest'); + +describe('Order Routes', function() { + var server; + var testOrderData = { + "units": [ + { + "sku": 'a5296ab9-9eee-7ba0-0a79-b801594f2c91', + "quantity": 5}, + { + "sku": 'a5296ab9-9eee-7ba0-0a79-b801594f2c92', + "quantity": 2} + ], + "fullName": "James Dickerson", + "streetAddress": "14250 Cheval Mayfaire", + "city": "Orlando", + "state": "FL", + "zip": "32828", + "phone": "305-710-8220", + "email": "jamesalexanderdickerson@gmail.com" + } + + var testOrder; + + beforeEach(function() { + server = require('../server/server.js'); + }); + + afterEach(function() { + server.close(); + }); + + + + //Testing if an order was created. + it('Order Create', function(done) { + request(server) + .put('/order') + .set('Accept', 'application/json') + .send(testOrderData) + .expect('Content-Type', /json/) + .expect(function(res) { + if(res.body.fullName !== testOrderData.fullName) + throw new Error('Order was not properly created.'); + testOrder = res.body; + }) + .expect(200, done); + }); + + it('Order Read One', function(done) { + request(server) + .get('/order/' + testOrder.uuid.toString()) + .set('Accept', 'application/json') + .expect('Content-Type', /json/) + .expect(function(res) { + if(testOrder.uuid !== res.body.uuid) throw new Error('The UUID returned does not match.'); + }) + .expect(200, done); + }); + + it('Order Read All', function(done) { + request(server) + .get('/order') + .set('Accept', 'application/json') + .expect('Content-Type', /json/) + .expect(function(res) { + if(res.body.length < 1) throw new Error('There are no entries in the database.'); + }) + .expect(200, done); + }); + + it('Order Update', function(done) { + request(server) + .get('/order/' + testOrder.uuid.toString()) + .set('Accept', 'application/json') + .expect('Content-Type', /json/) + .expect(function(res) { + if(testOrder.fullName !== res.body.fullName) throw new Error('Did not update record'); + }) + .expect(200, done); + }); + + it('Order Destroy', function(done) { + request(server) + .delete('/order/' + testOrder.uuid.toString()) + .set('Accept', 'application/json') + .send({force: true}) + .expect('Content-Type', /json/) + .expect(function(res) { + if(!res.body.success) throw new Error ('Destroy failed.') + }) + .expect(200, done); + }); +}) diff --git a/test/__inventory.js b/test/__inventory.js new file mode 100644 index 0000000..ac5a4b9 --- /dev/null +++ b/test/__inventory.js @@ -0,0 +1,79 @@ +const request = require('supertest'); + +describe('Inventory Route', function() { + var server; + var testOrderData = { + "sku": "a5296ab9-9eee-7ba0-0a79-b801594f2c94", + "location": "California" + } + + var testInventory; + + beforeEach(function() { + server = require('../server/server.js'); + }); + + afterEach(function() { + server.close(); + }); + + //Testing if the inventory was created. + it('Inventory Create', function(done) { + request(server) + .put('/inventory') + .set('Accept', 'application/json') + .send(testOrderData) + .expect('Content-Type', /json/) + .expect(function(res) { + if(res.body.sku !== testOrderData.sku) + throw new Error('Inventory was not properly created.'); + testInventory = res.body; + }) + .expect(200, done); + }); + + it('Inventory Read One', function(done) { + request(server) + .get('/inventory/' + testInventory.sku.toString()) + .set('Accept', 'application/json') + .expect('Content-Type', /json/) + .expect(function(res) { + if(testInventory[0].sku !== res.body.sku) throw new Error('The sku returned does not match.'); + }) + .expect(200, done); + }); + + it('Inventory Read All', function(done) { + request(server) + .get('/inventory') + .set('Accept', 'application/json') + .expect('Content-Type', /json/) + .expect(function(res) { + if(res.body.length < 1) throw new Error('There are no entries in the database.'); + }) + .expect(200, done); + }); + + it('Inventory Update', function(done) { + request(server) + .get('/inventory/' + testInventory.sku.toString()) + .set('Accept', 'application/json') + .expect('Content-Type', /json/) + .expect(function(res) { + if(testInventory[0].sku !== res.body.sku) throw new Error('Did not update record'); + }) + .expect(200, done); + }); + + it('Inventory Destroy', function(done) { + request(server) + .delete('/inventory/' + testInventory[0].sku) + .set('Accept', 'application/json') + .send({force: true}) + .expect('Content-Type', /json/) + .expect(function(res) { + if(!res.body.success) throw new Error ('Destroy failed.') + }) + .expect(200, done); + }); +}) diff --git a/test/__order.js b/test/__order.js new file mode 100644 index 0000000..88f6d1b --- /dev/null +++ b/test/__order.js @@ -0,0 +1,78 @@ +process.env.PORT = 1234; +const request = require('supertest'); +const dataToInsert = {uuid: 'j42bc2ed9899a490fa44dbb2f756542e5', timestamp: 'Mon Feb 22 2016 13:14:26 GMT-0500 (EST)'}; + +// Manually configure Test Routes, they will be mapped to individual tests +// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +const known_routes = [ + {title: 'Basic Order Test', route: '/order', status_code: 200, res: {healthy: true }, req: dataToInsert}, + // {title: 'Status Check', route: '/api/v1/status', status_code: 200, res: {healthy: true}} +]; + +describe('Loading Express', function () { + var server; + + // Before / After each test create / destroy the express server to fully simulate unique requests. + // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + beforeEach(function (){ + server = require('../server/server.js'); + }); + afterEach(function (){ + server.close(); + }); + + for(var route_index in known_routes){ + it('[' + known_routes[route_index].status_code + '] ' + known_routes[route_index].route + ' ' + + known_routes[route_index].title , function testHealth(done){ + request(server) + .put(known_routes[route_index].route) + .set('Accept', 'application/json') + .expect('Content-Type', /json/) + .expect(function(res){ + + console.log(res.body); + + var matchedKeys = []; + for(matchKey in known_routes[route_index].req){ + matchedKeys.push(matchKey); + } + + var matchCount = 0; + for(resKey in res.body){ + if((matchedKeys.indexOf(resKey) < 0)) { + // Un Matched Key + } else { + // Key is matched + matchCount++; + } + } + + if(matchCount !== matchedKeys.length){ + throw new Error('Incorrect total of matches made'); + } + + if(known_routes[route_index].req === known_routes[route_index].res){ + throw new Error('key is not match'); + } + + if(!res.body.uuid){ + throw new Error('uuid is not been returned/added'); + } + + if(!res.body.timestamp){ + throw new Error('timestamp is not been returned/added'); + } + }) + .expect(known_routes[route_index].status_code, done) + }); + } + + + // Force a bad route + // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + it('404 everything bad routes', function testHealth(done){ + request(server) + .get('/not/a/real/route') + .expect(404, done); + }); +}); diff --git a/test/__order.old b/test/__order.old new file mode 100644 index 0000000..58c325c --- /dev/null +++ b/test/__order.old @@ -0,0 +1,77 @@ +const request = require('supertest'); +const dataToInsert = {uuid: 'j42bc2ed9899a490fa44dbb2f756542e5',timestamp: 'Mon Feb 22 2016 13:14:26 GMT-0500 (EST)', healthy: true}; + +// Manually configure Test Routes, they will be mapped to individual tests +// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +const known_routes = [ + {title: 'Basic Order Test', route: '/order', status_code: 200, res: {healthy: true },req: dataToInsert}, + // {title: 'Status Check', route: '/api/v1/status', status_code: 200, res: {healthy: true}} +]; + +describe('Loading Express', function () { + var server; + + // Before / After each test create / destroy the express server to fully simulate unique requests. + // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + beforeEach(function (){ + server = require('../server/server.js'); + }); + afterEach(function (){ + server.close(); + }); + + for(var route_index in known_routes){ + it('[' + known_routes[route_index].status_code + '] ' + known_routes[route_index].route + ' ' + + known_routes[route_index].title , function testHealth(done){ + request(server) + .put(known_routes[route_index].route) + .set('Accept', 'application/json') + .expect('Content-Type', /json/) + .expect(function(res){ + + console.log(res.body); + + var matchedKeys = []; + for(matchKey in known_routes[route_index].req){ + matchedKeys.push(matchKey); + } + + var matchCount = 0; + for(resKey in res.body){ + if((matchedKeys.indexOf(resKey) < 0)) { + // Un Matched Key + } else { + // Key is matched + matchCount++; + } + } + + if(matchCount !== matchedKeys.length){ + throw new Error('Incorrect total of matches made'); + } + + if(known_routes[route_index].req === known_routes[route_index].res){ + throw new Error('key is not match'); + } + + if(!res.body.uuid){ + throw new Error('uuid is not been returned/added'); + } + + if(!res.body.timestamp){ + throw new Error('timestamp is not been returned/added'); + } + }) + .expect(known_routes[route_index].status_code, done) + }); + } + + + // Force a bad route + // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + it('404 everything bad routes', function testHealth(done){ + request(server) + .get('/not/a/real/route') + .expect(404, done); + }); +}); diff --git a/test/__units.js b/test/__units.js new file mode 100644 index 0000000..a22ac5d --- /dev/null +++ b/test/__units.js @@ -0,0 +1,82 @@ +const request = require('supertest'); + +describe('Units Route', function() { + var server; + var testOrderData = { + "sku": "a5296ab9-9eee-7ba0-0a79-b801594f2c94", + "name": "Christopher Fortin", + "location": "Florida" + } + + var testUnit; + + beforeEach(function() { + server = require('../server/server.js'); + }); + + afterEach(function() { + server.close(); + }); + + //Testing if the Unit was created. + it('Unit Create', function(done) { + request(server) + .put('/unit') + .set('Accept', 'application/json') + .send(testOrderData) + .expect('Content-Type', /json/) + .expect(function(res) + if(res.body.sku !== testOrderData.sku) + throw new Error('Unit was not properly created.'); + testUnit = res.body; + }) + .expect(200, done); + }); + + it('Unit Read One', function(done) { + request(server) + .get('/unit/' + testUnit.sku.toString()) + .set('Accept', 'application/json') + .expect('Content-Type', /json/) + .expect(function(res) { + if(testUnit.sku !== res.body.sku) throw new Error('The sku returned does not match.'); + }) + .expect(200, done); + }); + + it('unit Read All', function(done) { + request(server) + .get('/unit') + .set('Accept', 'application/json') + .expect('Content-Type', /json/) + .expect(function(res) { + if(res.body.length < 1) throw new Error('There are no entries in the database.'); + }) + .expect(200, done); + }); + + it('unit Update', function(done) { + request(server) + .get('/unit/' + testUnit.sku.toString()) + .set('Accept', 'application/json') + .expect('Content-Type', /json/) + .expect(function(res) { + if(testUnit.sku !== res.body.sku) throw new Error('Did not update record'); + }) + .expect(200, done); + }); + + it('unit Destroy', function(done) { + request(server) + .delete('/unit/' + testUnit.sku.toString()) + .set('Accept', 'application/json') + .send({force: true}) + .expect('Content-Type', /json/) + .expect(function(res) { + if(!res.body.success) throw new Error ('Destroy failed.') + }) + .expect(200, done); + }); + + +})