diff --git a/Node/Demo1/.eslintrc.json b/Node/Demo1/.eslintrc.json new file mode 100755 index 0000000..f866eec --- /dev/null +++ b/Node/Demo1/.eslintrc.json @@ -0,0 +1,20 @@ +{ + "env": { + "node": true + }, + "extends": "airbnb", + "plugins": [ + "react" + ], + "rules": { + "new-cap": 0, + "prefer-template": 0, + "global-require": 0 + }, + "globals": { + "describe": true, + "it": true, + "beforeEach": true, + "afterEach": true + } +} diff --git a/Node/Demo1/.gitignore b/Node/Demo1/.gitignore new file mode 100755 index 0000000..9b7a561 --- /dev/null +++ b/Node/Demo1/.gitignore @@ -0,0 +1,8 @@ +.DS_store +node_modules +.env +.env.json +*.logs +*.log +out +build diff --git a/Node/Demo1/README.md b/Node/Demo1/README.md new file mode 100755 index 0000000..81689d6 --- /dev/null +++ b/Node/Demo1/README.md @@ -0,0 +1,540 @@ +# Appstore + +[ ![codeship status for seanedw1/appstore](https://codeship.com/projects/b4c62d70-506b-0134-4880-4efbbc592ce7/status?branch=master)](https://codeship.com/projects/171009) + +Full sail student app store + +## Package dependencies + +To install all dependencies in command line run. + +``` +npm i + +npm i mocha -g + +``` + +### Postman + +postman is a http client used for testing apis. postman will be required for this api. + +[Get postman](https://www.getpostman.com/) + + +### ENV file + +create a .env following this file structure on root level + +```javascript +DB_HOST=localhost +DB_NAME=apiCRUD +DB_USER=root +DB_PASS= +DB_SCHEMA=mysql +DB_PORT=3306 +``` + +### config.json + +create a config.json file following this file structure on root level + +```json +{ + "secret": "yourseceretgoeshere" +} + +``` + +### jsonwebtoken (jwt) + +a jwt, is a signed token that is used to securely send or receive information that has been encrypted by a digital signature. + +sample +```json +eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyTmFtZSI6InBldGVyIiwicGFzc3dvcmQiOiIxMjM0IiwiaWF0IjoxNDcyMTA2NzYxLCJleHAiOjE0NzIxMTY4NDF9.Jn4MCFozU0685i6ic12E3FfgaApHd3PJgUQYqTb_xTM +``` + +## Generating a token + + +### Protected routes + +applying jwt to authenticate via postman for protected route +``` +x-access-token +``` + +sample +``` + +``` + +applying jwt to authenticate via url for protected route + +sample +``` +http://localhost:3000/api/v1/betas?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyTmFtZSI6InBldGVyIiwicGFzc3dvcmQiOiIxMjM0IiwiaWF0IjoxNDcyMTA2NzYxLCJleHAiOjE0NzIxMTY4NDF9.Jn4MCFozU0685i6ic12E3FfgaApHd3PJgUQYqTb_xTM +``` + +### Server + +To start sever in command line run. + +Server runs on port 3000. + +``` +npm start +``` + +Server runs on port 3000. + + +### Unit test + +To run unit test sever must be off. + +To start unit test in command line run. + +``` +npm test +``` + +### Workflow + +1) Confirm in master branch + +2) create a new branch + +``` +git checkout -b branchname +``` + +3) push up to new feature branch + +``` +git add -A + +git commit -m 'insert your msg here' + +git push + +``` + +if this is your first time pushing to new branch run + +``` +git push --set-upstream origin branchname +``` + +5) once pushed we return to the master branch to merge (pull in) the feature branch + +``` +git checkout master +``` +6) now that we are back in the master branch merge your feature branch into your master branch use the merge command followed by a push + +``` +git merge branchname + +git push +``` + +7) now that we have successfully merged our feature branch our ci tool will check to make sure your code is passing. + +8) once codeship confirms that the build passes we want to tag this version then merge our master into our release branch. + +9) to create a tag run + +``` +git tag v1.0.6 commitidgoeshere +``` + +10) once we have created our tag we want to continue with our merge to the release branch + +``` +git checkout release + +git merge branchname + +git push +``` +11) once we push to release branch our codebase enters the first phase of the Deployment pipeline + +### Deployment + +1) once we merge our code to master our ci test run to confirm our codebase is passing our automated test. + +2) if our codebase passes ci test (codeship) we manually merge master branch to the release branch +which is the first step in the deployment pipeline. + +3) once ci tool (codeship) confirms the build is good it will automatically be deployed from release repo onto our staging server. + +4) once completed and we confirmed out codebase is good we will manually push on heroku to the production server + +## Endpoints + +### AUTH + +POST localhost:3000/api/v1/auth - Create jsonwebtoken(jwt) + +success sample + +* this is not a real token + +```json +{ + "message": "here is your token!", + "token":"eyJhbGciOiJIUefI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InRlc3R1c2VyMSIsInBhc3N3b3JkIjorMTIzNCIImlhdCI6MTQ3MjExNTYyNiwiZXhwIjoxNDcyMTE1NjQ2fQ.b1YLQI_Y5iic7xrDb-zn6nJsi76gJox8anfpzYITnMs" +} +``` + +fail sample + +* this is not a real token + +```json +{ + "message": "user not found", +} +``` +### CRUD FOR USERS + +* POST localhost:3000/api/v1/users - Create User + +sample +```json +{ + "username": "jd2016", + "name": "john doe", + "age": 50, + "hobby": "dancing", +} +``` + +* GET localhost:3000/api/v1/users/1 - Display User by id + +sample response +```json +{ + "id": 1, + "username": "jd2016", + "name": "john doe", + "age": 50, + "hobby": "dancing", + "createdAt": "2016-08-08T01:45:31.000Z", + "updatedAt": "2016-08-08T01:45:31.000Z", + "apps": [] +} +``` + +* GET localhost:3000/api/v1/users - Display All Users + +sample response +```json +[ + { + "id": 1, + "username": "jd2016", + "name": "john doe", + "age": 50, + "hobby": "dancing", + "createdAt": "2016-08-07T01:45:31.000Z", + "updatedAt": "2016-08-07T01:45:31.000Z" + }, + { + "id": 2, + "username": "jed2016", + "name": "jane doe", + "age": 34, + "hobby": "softball", + "createdAt": "2016-08-7T21:56:43.000Z", + "updatedAt": "2016-08-7T21:56:43.000Z" + }, + { + "id": 3, + "username": "ks2016", + "name": "kevin smith", + "age": 21, + "hobby": "programming", + "createdAt": "2016-08-07T00:25:11.000Z", + "updatedAt": "2016-08-07T00:25:13.000Z" + } +] +``` + +* POST localhost:3000/api/v1/users/1 - Update User by id + +sample +```json +{ + "id": 1, + "username": "st2016", + "name": "steven smith", + "age": 45, + "hobby": "sports", + "createdAt": "2016-08-08T01:45:31.000Z", + "updatedAt": "2016-08-11T21:54:21.000Z", +} +``` + +* DELETE localhost:3000/api/v1/users/1 - DELETE User by id + +sample response +```json +1 +``` + +### CRUD FOR APPS + + +* POST localhost:3000/api/v1/apps - create app + +sample +```json +{ + "title": "test app", + "description": "fjndclkdlj", +} +``` + + +* GET localhost:3000/api/v1/apps/1 - Display App by id + +sample response +```json +{ + "id": 1, + "title": "test app", + "description": "fjndclkdlj", + "releaseDate": null, + "createdAt": "2016-08-11T21:57:20.000Z", + "updatedAt": "2016-08-11T21:57:20.000Z", + "userID": null +} +``` + +* GET localhost:3000/api/v1/users/1 - Display All Apps from specific user + +sample response +```json +{ + "id": 1, + "username": "jd2016", + "name": "john doe", + "age": 50, + "hobby": "dancing", + "createdAt": "2016-06-08T01:45:31.000Z", + "updatedAt": "2016-06-11T21:54:21.000Z", + "apps": [ + { + "id": 1, + "title": "test app", + "description": "fjndclkdlj", + "releaseDate": null, + "createdAt": "2016-08-11T21:57:20.000Z", + "updatedAt": "2016-08-12T18:30:49.000Z", + "userID": 1 + } + ], + "betas": [ + { + "id": 1, + "title": "test app", + "description": "fjndclkdlj", + "releaseDate": null, + "createdAt": "2016-08-11T21:57:20.000Z", + "updatedAt": "2016-08-12T18:30:49.000Z", + "userID": 1 + } + ] + +} +``` + +* GET localhost:3000/api/v1/users/1 - Display All Beta Apps from specific user + +sample response +```json +{ + "id": 1, + "username": "jd2016", + "name": "john doe", + "age": 50, + "hobby": "dancing", + "createdAt": "2016-06-08T01:45:31.000Z", + "updatedAt": "2016-06-11T21:54:21.000Z", + "apps": [ + { + "id": 1, + "title": "test app", + "description": "fjndclkdlj", + "releaseDate": null, + "createdAt": "2016-08-11T21:57:20.000Z", + "updatedAt": "2016-08-12T18:30:49.000Z", + "userID": 1 + } + ], + "betas": [ + { + "id": 1, + "title": "test app", + "description": "fjndclkdlj", + "releaseDate": null, + "createdAt": "2016-08-11T21:57:20.000Z", + "updatedAt": "2016-08-12T18:30:49.000Z", + "userID": 1 + } + ] + +} +``` + +* GET localhost:3000/api/v1/apps - Display All Apps + +sample response +```json +[ + { + "id": 1, + "title": "test app", + "description": "fake app", + "releaseDate": null, + "createdAt": "2016-08-11T21:57:20.000Z", + "updatedAt": "2016-08-11T21:57:20.000Z", + "userID": null + }, + { + "id": 2, + "title": "test app 2", + "description": "fake app 2", + "releaseDate": null, + "createdAt": "2016-08-11T21:57:20.000Z", + "updatedAt": "2016-08-11T21:57:20.000Z", + "userID": null + }, + { + "id": 3, + "title": "test app 3", + "description": "fake app 3", + "releaseDate": null, + "createdAt": "2016-08-11T21:57:20.000Z", + "updatedAt": "2016-08-11T21:57:20.000Z", + "userID": null + }, +] +``` + +* POST localhost:3000/api/v1/apps/1 - UPDATE App by id + +sample +```json +{ + "id": 1, + "title": "testing", + "description": "you are updating", + "releaseDate": null, + "createdAt": "2016-08-12T18:31:36.000Z", + "updatedAt": "2016-08-12T19:41:46.000Z", + "userID": null +} +``` + +* DELETE localhost:3000/api/v1/apps/1 - DELETE App by id + +sample response +```json +1 +``` + +### CRUD FOR BETA APPS + +* POST localhost:3000/api/v1/betas - Create betas apps + +sample +```json +{ + "title": "test app", + "description": "fjndclkdlj", +} +``` + +* GET localhost:3000/api/v1/betas/1 - Display betas apps by id + +sample response +```json +{ + "id": 1, + "title": "test app", + "description": "fjndclkdlj", + "releaseDate": null, + "createdAt": "2016-08-11T21:57:20.000Z", + "updatedAt": "2016-08-11T21:57:20.000Z", + "userID": null +} + +``` + +* GET localhost:3000/api/v1/betas - Display All betas apps + +sample response +```json +[ + { + "id": 1, + "title": "test app", + "description": "fake app", + "releaseDate": null, + "createdAt": "2016-08-11T21:57:20.000Z", + "updatedAt": "2016-08-11T21:57:20.000Z", + "userID": null + }, + { + "id": 2, + "title": "test app 2", + "description": "fake app 2", + "releaseDate": null, + "createdAt": "2016-08-11T21:57:20.000Z", + "updatedAt": "2016-08-11T21:57:20.000Z", + "userID": null + }, + { + "id": 3, + "title": "test app 3", + "description": "fake app 3", + "releaseDate": null, + "createdAt": "2016-08-11T21:57:20.000Z", + "updatedAt": "2016-08-11T21:57:20.000Z", + "userID": null + }, +] +``` + + +* POST localhost:3000/api/v1/betas/1 - Update betas apps by id + +sample +```json +{ + "id": 1, + "title": "testing", + "description": "you are updating", + "releaseDate": null, + "createdAt": "2016-08-12T18:31:36.000Z", + "updatedAt": "2016-08-12T19:41:46.000Z", + "userID": null +} +``` + +* DELETE localhost:3000/api/v1/betas/1 - DELETE betas apps by id + +sample response +```json +1 +``` + +##### Contributors +[View Contributors](https://github.com/seanedw1/appstore/graphs/contributors) + +###### Style Guide reference +[Airbnb](https://github.com/airbnb/javascript) diff --git a/Node/Demo1/config.json b/Node/Demo1/config.json new file mode 100755 index 0000000..ddeebc7 --- /dev/null +++ b/Node/Demo1/config.json @@ -0,0 +1,3 @@ +{ + "secret": "seanisawsome" +} diff --git a/Node/Demo1/package.json b/Node/Demo1/package.json new file mode 100755 index 0000000..cf0c5b8 --- /dev/null +++ b/Node/Demo1/package.json @@ -0,0 +1,53 @@ +{ + "name": "appstore", + "version": "1.9.0", + "description": "fullsail appstore", + "main": "src/server.js", + "engines": { + "node": "v6.3.1", + "npm": "v3.10.5" + }, + "directories": { + "test": "test" + }, + "scripts": { + "start": "node src/server.js", + "test": "mocha" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/seanedw1/appstore.git" + }, + "author": "sean ed", + "license": "ISC", + "bugs": { + "url": "https://github.com/seanedw1/appstore/issues" + }, + "homepage": "https://github.com/seanedw1/appstore#readme", + "devDependencies": { + "dotenv": "^2.0.0", + "mocha": "^3.0.0", + "eslint": "3.2.2", + "eslint-config-airbnb": "10.0.0", + "eslint-plugin-import": "1.12.0", + "eslint-plugin-jsx-a11y": "2.0.1", + "eslint-plugin-react": "6.0.0" + }, + "dependencies": { + "body-parser": "^1.15.2", + "chai": "^3.5.0", + "colors": "^1.1.2", + "dotenv": "^2.0.0", + "express": "^4.14.0", + "express-jwt": "^3.4.0", + "express-jwt-blacklist": "^1.1.0", + "faker": "^3.1.0", + "jsonwebtoken": "^7.1.9", + "morgan": "^1.7.0", + "mysql": "^2.11.1", + "sequelize": "^3.23.6", + "slogs": "^1.0.3", + "supertest": "^2.0.0", + "underscore": "^1.8.3" + } +} diff --git a/Node/Demo1/src/models/app.js b/Node/Demo1/src/models/app.js new file mode 100755 index 0000000..3af1f3c --- /dev/null +++ b/Node/Demo1/src/models/app.js @@ -0,0 +1,51 @@ +const db = require('./db'); +const slog = require('slogs'); +const colors = require('colors'); + +// create +exports.add = (payload, err, success) => { + db.app.create(payload).then(success).catch(err); + slog.debug(colors.green('CREATE ') + 'App Route hit'); +}; + +// read all +exports.all = (err, success) => { + db.app.findAll().then(success).catch(err); + slog.debug(colors.cyan('READ ') + 'App Route hit'); +}; + +// read by id +exports.one = (payload, err, success) => { + db.app.find({ + where: { + id: payload.id, + }, + include: [{ + all: true, + nested: true, + }], + }).then(success).catch(err); + slog.debug(colors.cyan('READ BY ID ') + 'App Route hit'); +}; + +// update +exports.update = (payload, err, success) => { + db.app.find({ + where: { + id: payload.id, + }, + }).then((existingData) => { + existingData.updateAttributes(payload).then(success).catch(err); + }).catch(err); + slog.debug(colors.green('UPDATE ') + 'App Route hit'); +}; + +// delete +exports.remove = (payload, err, success) => { + db.app.destroy({ + where: { + id: payload.id, + }, + }).then(success).catch(err); + slog.debug(colors.red('DELETE ') + 'App Route hit'); +}; diff --git a/Node/Demo1/src/models/auth.js b/Node/Demo1/src/models/auth.js new file mode 100755 index 0000000..24d5909 --- /dev/null +++ b/Node/Demo1/src/models/auth.js @@ -0,0 +1,27 @@ +const db = require('./db'); +const slog = require('slogs'); +const colors = require('colors'); + +// read user db table +exports.check = (payload, err, sucess) => { + db.user.find({ + where: { + username: payload.username, + password: payload.password, + }, + }).then(sucess).catch(err); + slog.debug(colors.green('Create ') + 'token hit'); + // closes exports +}; + +// read user db table +exports.remove = (payload, err, sucess) => { + db.user.find({ + where: { + username: payload.username, + password: payload.password, + }, + }).then(sucess).catch(err); + slog.debug(colors.green('Delete ') + 'token hit'); + // closes exports +}; diff --git a/Node/Demo1/src/models/beta.js b/Node/Demo1/src/models/beta.js new file mode 100755 index 0000000..6b7b38d --- /dev/null +++ b/Node/Demo1/src/models/beta.js @@ -0,0 +1,51 @@ +const db = require('./db'); +const slog = require('slogs'); +const colors = require('colors'); + +// create +exports.add = (payload, err, success) => { + db.beta.create(payload).then(success).catch(err); + slog.debug(colors.green('CREATE ') + 'Beta app Route hit'); +}; + +// read all +exports.all = (err, success) => { + db.beta.findAll().then(success).catch(err); + slog.debug(colors.cyan('READ ') + 'Beta app Route hit'); +}; + +// read by id +exports.one = (payload, err, success) => { + db.beta.find({ + where: { + id: payload.id, + }, + include: [{ + all: true, + nested: true, + }], + }).then(success).catch(err); + slog.debug(colors.cyan('READ BY ID ') + 'Beta app Route hit'); +}; + +// update +exports.update = (payload, err, success) => { + db.beta.find({ + where: { + id: payload.id, + }, + }).then((existingData) => { + existingData.updateAttributes(payload).then(success).catch(err); + }).catch(err); + slog.debug(colors.green('UPDATE ') + 'Beta app Route hit'); +}; + +// delete +exports.remove = (payload, err, success) => { + db.beta.destroy({ + where: { + id: payload.id, + }, + }).then(success).catch(err); + slog.debug(colors.red('DELETE ') + 'Beta app Route hit'); +}; diff --git a/Node/Demo1/src/models/db.js b/Node/Demo1/src/models/db.js new file mode 100755 index 0000000..36d7050 --- /dev/null +++ b/Node/Demo1/src/models/db.js @@ -0,0 +1,90 @@ +// set constant of sequelize for orm +const Sequelize = require('sequelize'); + +// load in env file +if (!process.env.DB_HOST) require('dotenv').config(); + +// setting constant for envs +const sequelize = new Sequelize(process.env.DB_NAME, process.env.DB_USER, process.env.DB_PASS, { + host: process.env.DB_HOST, + dialect: process.env.DB_SCHEMA, + port: process.env.DB_PORT, + +// how many connections are happening to our system + pool: { + max: 5, + min: 0, + idle: 10000, + }, +// turn of logging + logging: false, +}); + +// In db user table will be displayed as users (plural) +const user = sequelize.define('user', { + username: { + type: Sequelize.STRING, + }, + name: { + type: Sequelize.STRING, + }, + password: { + type: Sequelize.STRING, + }, + age: { + type: Sequelize.INTEGER, + }, + hobby: { + type: Sequelize.STRING, + }, + admin: { + type: Sequelize.BOOLEAN, + }, + student: { + type: Sequelize.BOOLEAN, + }, +}); + +// In db app table will be displayed as users (plural) +const app = sequelize.define('app', { + title: { + type: Sequelize.STRING, + }, + description: { + type: Sequelize.STRING, + }, + releaseDate: { + type: Sequelize.DATE, + }, +}); + +// In db course table will be displayed as courses (plural) +const beta = sequelize.define('beta', { + title: { + type: Sequelize.STRING, + }, + description: { + type: Sequelize.STRING, + }, + releaseDate: { + type: Sequelize.DATE, + }, +}); + +// establish relation in db for user and apps +user.hasMany(app, { + foreignKey: 'userID', +}); + +// establish relation in db for user and beta apps +user.hasMany(beta, { + foreignKey: 'betaID', +}); + +// setup ability to reach to db to syncronize to this format +sequelize.sync(); + +exports.sequelize = sequelize; +exports.user = user; +exports.app = app; +exports.beta = beta; diff --git a/Node/Demo1/src/models/user.js b/Node/Demo1/src/models/user.js new file mode 100755 index 0000000..7fd2409 --- /dev/null +++ b/Node/Demo1/src/models/user.js @@ -0,0 +1,51 @@ +const db = require('./db'); +const slog = require('slogs'); +const colors = require('colors'); + +// create +exports.add = (payload, err, success) => { + db.user.create(payload).then(success).catch(err); + slog.debug(colors.green('CREATE ') + 'User Route hit'); +}; + +// read all +exports.all = (err, success) => { + db.user.findAll().then(success).catch(err); + slog.debug(colors.cyan('READ ') + 'User Route hit'); +}; + +// read by id +exports.one = (payload, err, success) => { + db.user.find({ + where: { + id: payload.id, + }, + include: [{ + all: true, + nested: true, + }], + }).then(success).catch(err); + slog.debug(colors.cyan('READ BY ID ') + 'User Route hit'); +}; + +// update +exports.update = (payload, err, success) => { + db.user.find({ + where: { + id: payload.id, + }, + }).then((existingData) => { + existingData.updateAttributes(payload).then(success).catch(err); + }).catch(err); + slog.debug(colors.green('UPDATE ') + 'User Route hit'); +}; + +// delete +exports.remove = (payload, err, success) => { + db.user.destroy({ + where: { + id: payload.id, + }, + }).then(success).catch(err); + slog.debug(colors.red('DELETE ') + 'User Route hit'); +}; diff --git a/Node/Demo1/src/routes/api/api.js b/Node/Demo1/src/routes/api/api.js new file mode 100755 index 0000000..2fa598e --- /dev/null +++ b/Node/Demo1/src/routes/api/api.js @@ -0,0 +1,24 @@ +const slog = require('slogs'); +const colors = require('colors'); + +// Set module.exports to a function that excepts express as a paramater of express. +module.exports = (express) => { +// Sets constant of router to express.Router() function + const router = express.Router(); + +// respond on index with json when a GET request is made to index route + router.get('/', (req, res) => { +// respond with this json data + res.json({ hello: 'world' }); + slog.debug(colors.green('Success ') + 'API Route hit'); + }); + +// respond on status with json when a GET request is made to status route + router.get('/status', (req, res) => { +// respond with this json data + res.json({ healthy: 'true' }); + slog.debug(colors.green('Success ') + 'Status Route hit'); + }); +// returns router with correct data + return router; +}; diff --git a/Node/Demo1/src/routes/api/app.js b/Node/Demo1/src/routes/api/app.js new file mode 100755 index 0000000..4a6ad03 --- /dev/null +++ b/Node/Demo1/src/routes/api/app.js @@ -0,0 +1,75 @@ +const app = require('../../models/app'); +const slog = require('slogs'); +const colors = require('colors'); + +// Set module.exports to a function that excepts express as a paramater of express. +module.exports = (express) => { +// Sets constant of router to express.Router() function + const router = express.Router(); + +// read - respond with apps json when a GET request is made to the apps route + router.get('/apps', (req, res) => { + app.all((err) => { + res.status(500).json(err); + slog.debug(colors.red('Fail ') + 'READ App Route'); + }, (data) => { + res.status(200).json(data); + slog.debug(colors.green('Success ') + 'READ App Route hit'); + }); + }); + +// create + router.post('/apps', (req, res) => { + app.add(req.body, (err) => { + res.status(500).json(err); + slog.debug(colors.red('Fail ') + 'CREATE App Route'); + }, (data) => { + res.status(200).json(data); + slog.debug(colors.green('Success ') + 'CREATE App Route hit'); + }); + }); + +// update + router.post('/apps/:id', (req, res) => { + const rb = req.body; + rb.id = req.params.id; +// respond with this json data + app.update(req.body, (err) => { + res.status(500).json(err); + slog.debug(colors.red('Fail ') + 'UPDATE App Route'); + }, (data) => { + res.status(200).json(data); + slog.debug(colors.green('Success ') + 'UPDATE App Route hit'); + }); + }); + +// delete + router.delete('/apps/:id', (req, res) => { + const rb = req.body; + rb.id = req.params.id; +// respond with this json data + app.remove(req.body, (err) => { + res.status(500).json(err); + slog.debug(colors.red('Fail ') + 'DELETE App Route'); + }, (data) => { + res.status(200).json(data); + slog.debug(colors.green('Success ') + 'DELETE App Route hit'); + }); + }); + + // respond with apps by id when a GET request is made to the courses by id route + router.get('/apps/:id', (req, res) => { + const rb = req.body; + rb.id = req.params.id; + // respond with this json data + app.one(req.body, (err) => { + res.status(500).json(err); + slog.debug(colors.red('Fail ') + 'READ BY ID App Route'); + }, (data) => { + res.status(200).json(data); + slog.debug(colors.green('Success ') + 'READ BY ID App Route hit'); + }); + }); +// returns router with correct data + return router; +}; diff --git a/Node/Demo1/src/routes/api/auth.js b/Node/Demo1/src/routes/api/auth.js new file mode 100755 index 0000000..8113d36 --- /dev/null +++ b/Node/Demo1/src/routes/api/auth.js @@ -0,0 +1,50 @@ +const auth = require('../../models/auth'); +const jwt = require('jsonwebtoken'); +const config = require('../../../config'); +const _ = require('underscore'); +const slog = require('slogs'); +const colors = require('colors'); + +module.exports = (express) => { + const router = express.Router(); + + // mock form post + router.post('/auth', (req, res) => { + auth.check(req.body, (err) => { + res.status(500).json(err); + slog.debug(colors.red('Fail ') + 'CREATE JWT Route'); + }, (data) => { + if (!data) { + res.status(500).send({ message: 'User not found.' }); + } else if (data) { + // check password + if (data.password !== req.body.password) { + res.status(500).send({ message: 'Wrong password.' }); + } else { + // sets specifs fields of object required to sign + const User = { username: req.body.username, password: req.body.password }; + // create a token + const token = jwt.sign(_.omit(User, 'password'), config.secret, { + // expires in 2 mins + expiresIn: 2 * 60000, + // id for token + jwtid: 'id123456', + // issuer of the token + issuer: 'Test', + // audience that JWT is for + audience: 'http://localhost:3000/api/v1/', + }); + // return the information including token as JSON + res.status(200).send({ + message: 'here is your token!', + token, + }); + } + } + slog.debug(colors.green('Success ') + 'Auth Route hit'); + }); + }); + // returns router with correct data + return router; + // closing module +}; diff --git a/Node/Demo1/src/routes/api/beta.js b/Node/Demo1/src/routes/api/beta.js new file mode 100755 index 0000000..50980cd --- /dev/null +++ b/Node/Demo1/src/routes/api/beta.js @@ -0,0 +1,85 @@ +const beta = require('../../models/beta'); +const slog = require('slogs'); +const colors = require('colors'); +const jwt = require('express-jwt'); +const config = require('../../../config'); + +// Set module.exports to a function that excepts express as a paramater of express. +module.exports = (express) => { +// Sets constant of router to express.Router() function + const router = express.Router(); +// verify secret + + const jwtCheck = jwt({ + secret: config.secret, + }); + + router.use('./routes/api/beta', jwtCheck); + +// read - respond with courses json when a GET request is made to the courses route + router.get('/betas', (req, res) => { + beta.all((err) => { + res.status(500).json(err); + slog.debug(colors.red('Fail ') + 'READ beta Route'); + }, (data) => { + res.status(200).json(data); + slog.debug(colors.green('Success ') + 'READ beta Route hit'); + }); + }); + +// create + router.post('/betas', (req, res) => { + beta.add(req.body, (err) => { + res.status(500).json(err); + slog.debug(colors.red('Fail ') + 'CREATE beta Route'); + }, (data) => { + res.status(200).json(data); + slog.debug(colors.green('Success ') + 'CREATE beta Route hit'); + }); + }); + +// update + router.post('/betas/:id', (req, res) => { + const rb = req.body; + rb.id = req.params.id; +// respond with this json data + beta.update(req.body, (err) => { + res.status(500).json(err); + slog.debug(colors.red('Fail ') + 'UPDATE beta Route'); + }, (data) => { + res.status(200).json(data); + slog.debug(colors.green('Success ') + 'UPDATE beta Route hit'); + }); + }); + +// delete + router.delete('/betas/:id', (req, res) => { + const rb = req.body; + rb.id = req.params.id; +// respond with this json data + beta.remove(req.body, (err) => { + res.status(500).json(err); + slog.debug(colors.red('Fail ') + 'DELETE beta Route'); + }, (data) => { + res.status(200).json(data); + slog.debug(colors.green('Success ') + 'DELETE beta Route hit'); + }); + }); + +// respond with course by id when a GET request is made to the courses by id route + router.get('/betas/:id', (req, res) => { + const rb = req.body; + rb.id = req.params.id; +// respond with this json data + beta.one(req.body, (err) => { + res.status(500).json(err); + slog.debug(colors.red('Fail ') + 'READ BY ID beta Route'); + }, (data) => { + res.status(200).json(data); + slog.debug(colors.green('Success ') + 'READ BY ID beta Route hit'); + }); + }); + +// returns router with correct data + return router; +}; diff --git a/Node/Demo1/src/routes/api/revoke.js b/Node/Demo1/src/routes/api/revoke.js new file mode 100755 index 0000000..beb04b2 --- /dev/null +++ b/Node/Demo1/src/routes/api/revoke.js @@ -0,0 +1,47 @@ +const auth = require('../../models/auth'); +const jwt = require('express-jwt'); +const blacklist = require('express-jwt-blacklist'); +const config = require('../../../config'); +const slog = require('slogs'); +const colors = require('colors'); + +module.exports = (express) => { + const router = express.Router(); + + const jwtCheck = jwt({ + secret: config.secret, + blacklist: blacklist.isRevoked, + }); + + router.use('/api/v1/revoke', jwtCheck); + + // mock form post + router.post('/revoke', (req, res) => { + auth.check(req.body, (err) => { + res.status(500).json(err); + slog.debug(colors.red('Fail ') + 'REVOKE JWT Route'); + }, (data) => { + if (!data) { + res.status(500).send({ message: 'User not found.' }); + } else if (data) { + // check password + if (data.password !== req.body.password) { + res.status(500).send({ message: 'Wrong password.' }); + } else { + // sets specifs fields of object required to sign + const User = { username: req.body.username, password: req.body.password }; + // create a token + blacklist.revoke(User); + // return the information including token as JSON + res.status(200).send({ + message: 'token revoked!', + }); + } + } + slog.debug(colors.green('Success ') + 'REVOKE Route hit'); + }); + }); + // returns router with correct data + return router; + // closing module +}; diff --git a/Node/Demo1/src/routes/api/user.js b/Node/Demo1/src/routes/api/user.js new file mode 100755 index 0000000..72f1c3a --- /dev/null +++ b/Node/Demo1/src/routes/api/user.js @@ -0,0 +1,86 @@ +const user = require('../../models/user'); +const slog = require('slogs'); +const colors = require('colors'); +const config = require('../../../config'); +const jwt = require('express-jwt'); + + +// Set module.exports to a function that excepts express as a paramater of express. +module.exports = (express) => { +// Sets constant of router to express.Router() function + const router = express.Router(); + + const jwtCheck = jwt({ + secret: config.secret, + }); + + router.use('/api/v1/user', jwtCheck); + +// respond with users json when a GET request is made to the users route + router.get('/users', (req, res) => { + user.all((err) => { + res.status(500).json(err); + slog.debug(colors.red('Fail ') + 'READ user Route'); + }, (data) => { + res.status(200).json(data); + + slog.debug(colors.green('Success ') + 'READ user Route hit'); + }); + }); + +// create + router.post('/users', (req, res) => { + user.add(req.body, (err) => { + res.status(500).json(err); + slog.debug(colors.red('Fail ') + 'CREATE user Route'); + }, (data) => { + res.status(200).json(data); + slog.debug(colors.green('Success ') + 'CREATE user Route'); + }); + }); + +// update + router.post('/users/:id', (req, res) => { + const rb = req.body; + rb.id = req.params.id; +// respond with this json data + user.update(req.body, (err) => { + res.status(500).json(err); + slog.debug(colors.red('Fail ') + 'UPDATE user Route'); + }, (data) => { + res.status(200).json(data); + slog.debug(colors.green('Success ') + 'UPDATE user Route hit'); + }); + }); + +// delete + router.delete('/users/:id', (req, res) => { + const rb = req.body; + rb.id = req.params.id; +// respond with this json data + user.remove(req.body, (err) => { + res.status(500).json(err); + slog.debug(colors.red('Fail ') + 'DELETE user Route'); + }, (data) => { + res.status(200).json(data); + slog.debug(colors.green('Success ') + 'DELETE user Route hit'); + }); + }); + +// respond with user by id when a GET request is made to the users by id route + router.get('/users/:id', (req, res) => { + const rb = req.body; + rb.id = req.params.id; +// respond with this json data + user.one(req.body, (err) => { + res.status(500).json(err); + slog.debug(colors.red('Fail ') + 'READ BY ID user Route'); + }, (data) => { + res.status(200).json(data); + slog.debug(colors.green('Success ') + 'READ BY ID user Route hit'); + }); + }); + +// returns router with correct data + return router; +}; diff --git a/Node/Demo1/src/routes/index.js b/Node/Demo1/src/routes/index.js new file mode 100755 index 0000000..9a9dad2 --- /dev/null +++ b/Node/Demo1/src/routes/index.js @@ -0,0 +1,12 @@ +const slog = require('slogs'); +const colors = require('colors'); + +module.exports = (express) => { + const router = express.Router(); + + router.get('/status', (req, res) => { + res.json({ healthy: true }); + slog.debug(colors.green('Success ') + 'Index hit'); + }); + return router; +}; diff --git a/Node/Demo1/src/server.js b/Node/Demo1/src/server.js new file mode 100755 index 0000000..bb8721c --- /dev/null +++ b/Node/Demo1/src/server.js @@ -0,0 +1,47 @@ +// Sets constant express to 'express' module +const express = require('express'); + +// Sets constant 'body_parser' to module +const bodyParser = require('body-parser'); + +// sets constant 'app' to express functionality +const app = express(); + +// config sets what port to run on +const port = process.env.PORT || 3000; +// utility tool +const slog = require('slogs'); + +// JSON formatting +app.set('json spaces', 2); + +// body_parser.json - Parses the text as JSON and exposes the resulting object on req.body. +app.use(bodyParser.json()); + +// bodyParser.urlencoded - Parses the text as URL encoded data and exposes the resulting object +app.use(bodyParser.urlencoded({ + extended: true, +})); + +// const config = require('../config'); +// const jwt = require('express-jwt'); +// const jwtCheck = jwt({ +// secret: config.secret, +// }); + +// linking routes +app.use('/', require('./routes')(express)); +app.use('/api/v1', require('./routes/api/api')(express)); +app.use('/api/v1', require('./routes/api/app')(express)); +app.use('/api/v1', require('./routes/api/user')(express)); +app.use('/api/v1', require('./routes/api/auth')(express)); +app.use('/api/v1', require('./routes/api/beta')(express)); +app.use('/api/v1', require('./routes/api/revoke')(express)); + +// sets variable server to the listening action on port +const server = app.listen(port, () => { +// console.log('server active on', port); + slog.debug('server active on ' + port); +}); +// exports server to be used elsewhere +module.exports = server; diff --git a/Node/Demo1/test/__models_apps.js b/Node/Demo1/test/__models_apps.js new file mode 100755 index 0000000..b7f851b --- /dev/null +++ b/Node/Demo1/test/__models_apps.js @@ -0,0 +1,100 @@ +const expect = require('chai').expect; +const faker = require('faker'); +const App = require('../src/models/app'); + +describe('App Model', () => { + // Test for all Apps + it('Gets All', (done) => { + App.all( + (err) => { + throw new Error(err); + }, + (apps) => { + this.testApps = apps; + expect(this.testApps.length).to.be.above(0); + done(); + } + ); + }); + + // Add a App + it('Adds a new App', (done) => { + // Generate a fake App with a random title + const fakeApp = { title: faker.name.firstName() }; + + // Call app model for adding + App.add(fakeApp, + (err) => { + throw new Error(err); + }, + (app) => { + // Save the returned data for later use in tests + this.tempApp = app.dataValues; + + // App.title returned from model should match app.title supplied + expect(app.title).to.be.equal(fakeApp.title); + done(); + } + ); + }); + + // Find a App + it('Find a App', (done) => { + // Generate a fake App with a random title + const targetApp = this.testApps[0]; + + // Call app model for finding + App.one(targetApp, + (err) => { + throw new Error(err); + }, + (app) => { + // App.title returned from model should match app.title supplied + expect(app.title).to.be.equal(targetApp.title); + done(); + } + ); + }); + + // Update a App + it('Update a App', (done) => { + // Load in the info for an existing app + const updateApp = this.tempApp; + + // Generate a new title for hte app + updateApp.title = 'Not A Real Name'; + + // Call app model for updating + App.update(updateApp, + (err) => { + throw new Error(err); + }, + (app) => { + // Save the returned data for later use in tests + this.tempApp = app; + // App.title returned from model should match app.title supplied + expect(app.title).to.be.equal(updateApp.title); + done(); + } + ); + }); + + // Remove a App + it('Remove a App', (done) => { + // Load in the info for an existing app + const removeApp = this.tempApp; + removeApp.force = true; + + // Call app model for updating + App.remove(removeApp, + (err) => { + throw new Error(err); + }, + (response) => { + // if successfully removed a 1 should be returned + expect(response).to.be.equal(1); + done(); + } + ); + }); +}); diff --git a/Node/Demo1/test/__models_beta.js b/Node/Demo1/test/__models_beta.js new file mode 100755 index 0000000..f93791b --- /dev/null +++ b/Node/Demo1/test/__models_beta.js @@ -0,0 +1,100 @@ +const expect = require('chai').expect; +const faker = require('faker'); +const Beta = require('../src/models/beta'); + +describe('Beta Model', () => { + // Test for all Betas + it('Gets All', (done) => { + Beta.all( + (err) => { + throw new Error(err); + }, + (betas) => { + this.testBetas = betas; + expect(this.testBetas.length).to.be.above(0); + done(); + } + ); + }); + + // Add a Beta + it('Adds a new Beta', (done) => { + // Generate a fake Beta with a random title + const fakeBeta = { title: faker.name.firstName() }; + + // Call beta model for adding + Beta.add(fakeBeta, + (err) => { + throw new Error(err); + }, + (beta) => { + // Save the returned data for later use in tests + this.tempBeta = beta.dataValues; + + // Beta.title returned from model should match beta.title supplied + expect(beta.title).to.be.equal(fakeBeta.title); + done(); + } + ); + }); + + // Find a Beta + it('Find a Beta', (done) => { + // Generate a fake Beta with a random title + const targetBeta = this.testBetas[0]; + + // Call beta model for finding + Beta.one(targetBeta, + (err) => { + throw new Error(err); + }, + (beta) => { + // Beta.title returned from model should match beta.title supplied + expect(beta.title).to.be.equal(targetBeta.title); + done(); + } + ); + }); + + // Update a Beta + it('Update a Beta', (done) => { + // Load in the info for an existing beta + const updateBeta = this.tempBeta; + + // Generate a new title for hte beta + updateBeta.title = 'Not A Real Name'; + + // Call beta model for updating + Beta.update(updateBeta, + (err) => { + throw new Error(err); + }, + (beta) => { + // Save the returned data for later use in tests + this.tempBeta = beta; + // Beta.title returned from model should match beta.title supplied + expect(beta.title).to.be.equal(updateBeta.title); + done(); + } + ); + }); + + // Remove a Beta + it('Remove a Beta', (done) => { + // Load in the info for an existing beta + const removeBeta = this.tempBeta; + removeBeta.force = true; + + // Call beta model for updating + Beta.remove(removeBeta, + (err) => { + throw new Error(err); + }, + (response) => { + // if successfully removed a 1 should be returned + expect(response).to.be.equal(1); + done(); + } + ); + }); +}); diff --git a/Node/Demo1/test/__models_users.js b/Node/Demo1/test/__models_users.js new file mode 100755 index 0000000..388abe9 --- /dev/null +++ b/Node/Demo1/test/__models_users.js @@ -0,0 +1,100 @@ +const expect = require('chai').expect; +const faker = require('faker'); +const User = require('../src/models/user'); + +describe('User Model', () => { + // Test for all Users + it('Gets All', (done) => { + User.all( + (err) => { + throw new Error(err); + }, + (users) => { + this.testUsers = users; + expect(this.testUsers.length).to.be.above(0); + done(); + } + ); + }); + + // Add a User + it('Adds a new User', (done) => { + // Generate a fake User with a random name + const fakeUser = { name: faker.name.firstName() }; + + // Call user model for adding + User.add(fakeUser, + (err) => { + throw new Error(err); + }, + (user) => { + // Save the returned data for later use in tests + this.tempUser = user.dataValues; + + // User.name returned from model should match user.name supplied + expect(user.name).to.be.equal(fakeUser.name); + done(); + } + ); + }); + + // Find a User + it('Find a User', (done) => { + // Generate a fake User with a random name + const targetUser = this.testUsers[0]; + + // Call user model for finding + User.one(targetUser, + (err) => { + throw new Error(err); + }, + (user) => { + // User.name returned from model should match user.name supplied + expect(user.name).to.be.equal(targetUser.name); + done(); + } + ); + }); + + // Update a User + it('Update a User', (done) => { + // Load in the info for an existing user + const updateUser = this.tempUser; + + // Generate a new name for hte user + updateUser.name = 'Not A Real Name'; + + // Call user model for updating + User.update(updateUser, + (err) => { + throw new Error(err); + }, + (user) => { + // Save the returned data for later use in tests + this.tempUser = user; + // User.name returned from model should match user.name supplied + expect(user.name).to.be.equal(updateUser.name); + done(); + } + ); + }); + + // Remove a User + it('Remove a User', (done) => { + // Load in the info for an existing user + const removeUser = this.tempUser; + removeUser.force = true; + + // Call user model for updating + User.remove(removeUser, + (err) => { + throw new Error(err); + }, + (response) => { + // if successfully removed a 1 should be returned + expect(response).to.be.equal(1); + done(); + } + ); + }); +}); diff --git a/Node/Demo1/test/__routes.js b/Node/Demo1/test/__routes.js new file mode 100755 index 0000000..724fdbc --- /dev/null +++ b/Node/Demo1/test/__routes.js @@ -0,0 +1,139 @@ + const request = require('supertest'); + const slog = require('slogs'); + const colors = require('colors'); + + +// array of all routes include keys call specific properties of object + const routes = [ + { + description: 'Create an app', + route: 'api/v1/apps', + method: 'post', + }, + { + description: 'Read an app', + route: 'api/v1/apps', + method: 'get', + }, + { + description: 'Read an app by id', + route: 'api/v1/apps/:id', + method: 'get', + }, + { + description: 'update an app', + route: 'api/v1/apps/:id', + method: 'post', + }, + { + description: 'delete an app', + route: 'api/v1/apps/:id', + method: 'delete', + }, + { + description: 'Create an user', + route: 'api/v1/users', + method: 'post', + }, + { + description: 'Read an user', + route: 'api/v1/users', + method: 'get', + }, + { + description: 'Read an user by id', + route: 'api/v1/users/:id', + method: 'get', + }, + { + description: 'Read all apps for user', + route: 'api/v1/users/:id/apps', + method: 'get', + }, + { + description: 'Update an user', + route: 'api/v1/users/:id', + method: 'post', + }, + { + description: 'Delete an user', + route: 'api/v1/users/:id', + method: 'delete', + }, + { + description: 'Create an Course', + route: 'api/v1/courses', + method: 'post', + }, + { + description: 'Read an Course', + route: 'api/v1/courses', + method: 'get', + }, + { + description: 'Read an Course by id', + route: 'api/v1/courses/:id', + method: 'get', + }, + { + description: 'update an Course', + route: 'api/v1/courses/:id', + method: 'post', + }, + { + description: 'delete an Course', + route: 'api/v1/courses/:id', + method: 'delete', + }, + ]; + +// setup a group of test + describe('Route testing', () => { + // declare block scope for server + let server; + +// before each instance + beforeEach(() => { + server = require('../src/server'); + }); + +// after each instance + afterEach(() => { + server.close(); + }); + +// loop to run threw routes + for (let i = 0; i < routes.length; i++) { +// it statement gives description of what test is suppose to do + it(routes[i].description, () => { + // if methed is equal to get + if (routes[i].method === 'get') { + request(server) + .get(routes[i]) + .set('Accept', 'application/json') + .expect('Content-Type', /json/) + .expect(200) + .end(); + slog.debug(colors.green('sucess on get')); + } else if (routes[i].method === 'post') { + request(server) + .post(routes[i]) + .set('Accept', 'application/json') + .expect('Content-Type', /json/) + .expect(200) + .end(); + slog.debug(colors.green('sucess on post')); + } else { + request(server) + .delete(routes[i]) + .set('Accept', 'application/json') + .expect('Content-Type', /json/) + .expect(200) + .end(); + slog.debug(colors.green('sucess on delete')); + } + // closing of the it statement + }); + } + // closing describe + });