From 5565d8576242103582ab7e0ea9b385a383c393ed Mon Sep 17 00:00:00 2001 From: ridho0 Date: Tue, 25 Apr 2017 16:25:11 +0700 Subject: [PATCH 1/2] udah dapet token --- .gitignore | 1 + README.md | 22 ++++- app.js | 46 +++++++++ bin/www | 90 +++++++++++++++++ config/config.json | 23 +++++ controllers/user.js | 97 +++++++++++++++++++ migrations/20170425040805-create-contact.js | 33 +++++++ .../20170425080056-add_username_and_role.js | 43 ++++++++ models/contact.js | 17 ++++ models/index.js | 36 +++++++ package.json | 19 ++++ public/stylesheets/style.css | 8 ++ routes/index.js | 9 ++ routes/users.js | 19 ++++ seeders/20170425042049-seed_data_contact.js | 24 +++++ views/error.jade | 6 ++ views/index.jade | 5 + views/layout.jade | 7 ++ 18 files changed, 504 insertions(+), 1 deletion(-) create mode 100644 .gitignore create mode 100644 app.js create mode 100755 bin/www create mode 100644 config/config.json create mode 100644 controllers/user.js create mode 100644 migrations/20170425040805-create-contact.js create mode 100644 migrations/20170425080056-add_username_and_role.js create mode 100644 models/contact.js create mode 100644 models/index.js create mode 100644 package.json create mode 100644 public/stylesheets/style.css create mode 100644 routes/index.js create mode 100644 routes/users.js create mode 100644 seeders/20170425042049-seed_data_contact.js create mode 100644 views/error.jade create mode 100644 views/index.jade create mode 100644 views/layout.jade diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/README.md b/README.md index b2e3b8b..ce711e1 100644 --- a/README.md +++ b/README.md @@ -1 +1,21 @@ -# api-auth \ No newline at end of file +# api-auth + +# My Phone Contact App + +sebuah aplikasi yg dapat menyimpan nomor contacts + +|Route|http|description| +|-----|----|-----------| +/api/signup|POST|Sign up with new user info +/api/signin|POST|Sign in while get an access token based on credentials +/api/users|GET|Get all the users (admin only) +/api/users/:id|GET|Get a single users (admin and authenticated user) +/api/users|POST|Create a user (admin only) +/api/users/:id|DELETE|Delete a user (admin only) +/api/users/:id|PUT|Update a user with new info (admin and authenticated user) + +To Use +```javascript +npm install +npm start +``` diff --git a/app.js b/app.js new file mode 100644 index 0000000..e84735a --- /dev/null +++ b/app.js @@ -0,0 +1,46 @@ +var express = require('express'); +var path = require('path'); +var favicon = require('serve-favicon'); +var logger = require('morgan'); +var cookieParser = require('cookie-parser'); +var bodyParser = require('body-parser'); + +var index = require('./routes/index'); +var users = require('./routes/users'); + +var app = express(); + +// view engine setup +app.set('views', path.join(__dirname, 'views')); +app.set('view engine', 'jade'); + +// uncomment after placing your favicon in /public +//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico'))); +app.use(logger('dev')); +app.use(bodyParser.json()); +app.use(bodyParser.urlencoded({ extended: false })); +app.use(cookieParser()); +app.use(express.static(path.join(__dirname, 'public'))); + +app.use('/', index); +app.use('/api', users); + +// catch 404 and forward to error handler +app.use(function(req, res, next) { + var err = new Error('Not Found'); + err.status = 404; + next(err); +}); + +// error handler +app.use(function(err, req, res, next) { + // set locals, only providing error in development + res.locals.message = err.message; + res.locals.error = req.app.get('env') === 'development' ? err : {}; + + // render the error page + res.status(err.status || 500); + res.render('error'); +}); + +module.exports = app; diff --git a/bin/www b/bin/www new file mode 100755 index 0000000..e49e193 --- /dev/null +++ b/bin/www @@ -0,0 +1,90 @@ +#!/usr/bin/env node + +/** + * Module dependencies. + */ + +var app = require('../app'); +var debug = require('debug')('api-basic:server'); +var http = require('http'); + +/** + * Get port from environment and store in Express. + */ + +var port = normalizePort(process.env.PORT || '3000'); +app.set('port', port); + +/** + * Create HTTP server. + */ + +var server = http.createServer(app); + +/** + * Listen on provided port, on all network interfaces. + */ + +server.listen(port); +server.on('error', onError); +server.on('listening', onListening); + +/** + * Normalize a port into a number, string, or false. + */ + +function normalizePort(val) { + var port = parseInt(val, 10); + + if (isNaN(port)) { + // named pipe + return val; + } + + if (port >= 0) { + // port number + return port; + } + + return false; +} + +/** + * Event listener for HTTP server "error" event. + */ + +function onError(error) { + if (error.syscall !== 'listen') { + throw error; + } + + var bind = typeof port === 'string' + ? 'Pipe ' + port + : 'Port ' + port; + + // handle specific listen errors with friendly messages + switch (error.code) { + case 'EACCES': + console.error(bind + ' requires elevated privileges'); + process.exit(1); + break; + case 'EADDRINUSE': + console.error(bind + ' is already in use'); + process.exit(1); + break; + default: + throw error; + } +} + +/** + * Event listener for HTTP server "listening" event. + */ + +function onListening() { + var addr = server.address(); + var bind = typeof addr === 'string' + ? 'pipe ' + addr + : 'port ' + addr.port; + debug('Listening on ' + bind); +} diff --git a/config/config.json b/config/config.json new file mode 100644 index 0000000..b2cb307 --- /dev/null +++ b/config/config.json @@ -0,0 +1,23 @@ +{ + "development": { + "username": "postgres", + "password": "postgres1", + "database": "api-auth", + "host": "127.0.0.1", + "dialect": "postgres" + }, + "test": { + "username": "root", + "password": null, + "database": "database_test", + "host": "127.0.0.1", + "dialect": "mysql" + }, + "production": { + "username": "root", + "password": null, + "database": "database_production", + "host": "127.0.0.1", + "dialect": "mysql" + } +} diff --git a/controllers/user.js b/controllers/user.js new file mode 100644 index 0000000..811b5c6 --- /dev/null +++ b/controllers/user.js @@ -0,0 +1,97 @@ +const db = require('../models') +const methods = {} +const passwordHash = require('password-hash') +const jwt = require('jsonwebtoken') + + +methods.signup = function(req, res, next) { + let pass = passwordHash.generate(req.body.password) + db.Contact.create( + {name: req.body.name, user_name: req.body.user_name, password: pass, role: req.body.role, phone: req.body.phone} + ) .then(data => { + res.send("data berhasil ditambahkan !") + }) + .catch( error => { + res.json({error}) + }) +}//signup +// passwordHash.verify('password123', hashedPassword) +methods.signin = function(req, res, next) { + db.Contact.findOne({ where: {user_name:req.body.user_name} }) + .then(user => { + if( passwordHash.verify(req.body.password, user.password) ) { + let token = jwt.sign({user_name: user.user_name, role: user.role}, 'secret', {expiresIn:'1h'}) + res.send(token) + } else { + res.send('password salah') + } + }) +}//signin + + +// router.get('/', userController.getAll ); +methods.getAll = function(req, res, next) { + db.Contact.findAll() + .then( user => { + res.json(user) + }) + .catch( error => { + res.json({error}) + }) +}// getAll + +// router.get('/:id', userController.getById ); +methods.getById = function(req, res, next) { + db.Contact.findById(req.params.id) + .then( contact => { + res.json(contact) + }) + .catch( error => { + res.json({error}) + })// getByd +} +// router.post('/', userController.createUser ); +methods.createUser = function(req, res, next) { + let pass = passwordHash.generate(req.body.password) + db.Contact.create( + {name: req.body.name, user_name: req.body.user_name, password: pass, role: req.body.role, phone: req.body.phone} + ) .then(data => { + res.send("data berhasil ditambahkan !") + }) + .catch( error => { + res.json({error}) + }) +}//createUser + +// router.delete('/:id', userController.deleteById ); +methods.deleteById = function(req, res, next) { + db.Contact.destroy({ + where: {id:req.params.id} + }) + .then( contact => { + res.send("berhasil dihapus") + }) + .catch( error => { + res.json({error}) + }) +} +// router.put('/:id', userController.updateById ); +methods.updateById = function(req, res, next) { + let pass = passwordHash.generate(req.body.password) + db.Contact.update({ + name: req.body.name, + user_name: req.body.user_name, + password: pass, + role: req.body.role, + phone: req.body.phone + },{ + where: {id:req.params.id} + }) + .then( contact => { + res.send('berhasil di update') + }) + .catch( error => { + res.json({error}) + }) +} +module.exports = methods diff --git a/migrations/20170425040805-create-contact.js b/migrations/20170425040805-create-contact.js new file mode 100644 index 0000000..4e718d4 --- /dev/null +++ b/migrations/20170425040805-create-contact.js @@ -0,0 +1,33 @@ +'use strict'; +module.exports = { + up: function(queryInterface, Sequelize) { + return queryInterface.createTable('Contacts', { + id: { + allowNull: false, + autoIncrement: true, + primaryKey: true, + type: Sequelize.INTEGER + }, + name: { + type: Sequelize.STRING + }, + password: { + type: Sequelize.STRING + }, + phone: { + type: Sequelize.STRING + }, + createdAt: { + allowNull: false, + type: Sequelize.DATE + }, + updatedAt: { + allowNull: false, + type: Sequelize.DATE + } + }); + }, + down: function(queryInterface, Sequelize) { + return queryInterface.dropTable('Contacts'); + } +}; diff --git a/migrations/20170425080056-add_username_and_role.js b/migrations/20170425080056-add_username_and_role.js new file mode 100644 index 0000000..02a24b7 --- /dev/null +++ b/migrations/20170425080056-add_username_and_role.js @@ -0,0 +1,43 @@ +'use strict'; + +module.exports = { + up: function (queryInterface, Sequelize) { + /* + Add altering commands here. + Return a promise to correctly handle asynchronicity. + + Example: + return queryInterface.createTable('users', { id: Sequelize.INTEGER }); + */ + // return queryInterface.addColumn('Contacts', 'user_name', Sequelize.STRING) + return [ + queryInterface.addColumn( + 'Contacts', + 'user_name', + { + type: Sequelize.STRING + } + ), + queryInterface.addColumn( + 'Contacts', + 'role', + { + type: Sequelize.STRING + } + ) + ]; + }, + + down: function (queryInterface, Sequelize) { + /* + Add reverting commands here. + Return a promise to correctly handle asynchronicity. + + Example: + */ + return [ + queryInterface.removeColumn('Contacts', 'user_name'), + queryInterface.removeColumn('Contacts', 'role') + ]; + } +}; diff --git a/models/contact.js b/models/contact.js new file mode 100644 index 0000000..249fb1f --- /dev/null +++ b/models/contact.js @@ -0,0 +1,17 @@ +'use strict'; +module.exports = function(sequelize, DataTypes) { + var Contact = sequelize.define('Contact', { + name: DataTypes.STRING, + password: DataTypes.STRING, + phone: DataTypes.INTEGER, + user_name: DataTypes.STRING, + role: DataTypes.STRING + }, { + classMethods: { + associate: function(models) { + // associations can be defined here + } + } + }); + return Contact; +}; diff --git a/models/index.js b/models/index.js new file mode 100644 index 0000000..7540dba --- /dev/null +++ b/models/index.js @@ -0,0 +1,36 @@ +'use strict'; + +var fs = require('fs'); +var path = require('path'); +var Sequelize = require('sequelize'); +var basename = path.basename(module.filename); +var env = process.env.NODE_ENV || 'development'; +var config = require(__dirname + '/../config/config.json')[env]; +var db = {}; + +if (config.use_env_variable) { + var sequelize = new Sequelize(process.env[config.use_env_variable]); +} else { + var sequelize = new Sequelize(config.database, config.username, config.password, config); +} + +fs + .readdirSync(__dirname) + .filter(function(file) { + return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js'); + }) + .forEach(function(file) { + var model = sequelize['import'](path.join(__dirname, file)); + db[model.name] = model; + }); + +Object.keys(db).forEach(function(modelName) { + if (db[modelName].associate) { + db[modelName].associate(db); + } +}); + +db.sequelize = sequelize; +db.Sequelize = Sequelize; + +module.exports = db; diff --git a/package.json b/package.json new file mode 100644 index 0000000..22e92a3 --- /dev/null +++ b/package.json @@ -0,0 +1,19 @@ +{ + "name": "api-basic", + "version": "0.0.0", + "private": true, + "scripts": { + "start": "nodemon ./bin/www" + }, + "dependencies": { + "body-parser": "~1.16.0", + "cookie-parser": "~1.4.3", + "debug": "~2.6.0", + "express": "~4.14.1", + "jade": "~1.11.0", + "jsonwebtoken": "^7.4.0", + "morgan": "~1.7.0", + "password-hash": "^1.2.2", + "serve-favicon": "~2.3.2" + } +} diff --git a/public/stylesheets/style.css b/public/stylesheets/style.css new file mode 100644 index 0000000..9453385 --- /dev/null +++ b/public/stylesheets/style.css @@ -0,0 +1,8 @@ +body { + padding: 50px; + font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; +} + +a { + color: #00B7FF; +} diff --git a/routes/index.js b/routes/index.js new file mode 100644 index 0000000..ecca96a --- /dev/null +++ b/routes/index.js @@ -0,0 +1,9 @@ +var express = require('express'); +var router = express.Router(); + +/* GET home page. */ +router.get('/', function(req, res, next) { + res.render('index', { title: 'Express' }); +}); + +module.exports = router; diff --git a/routes/users.js b/routes/users.js new file mode 100644 index 0000000..712e4bb --- /dev/null +++ b/routes/users.js @@ -0,0 +1,19 @@ +const express = require('express'); +const router = express.Router(); +const userController = require('../controllers/user') + +/* GET users listing. */ +// router.get('/', function(req, res, next) { +// res.send('respond with a resource'); +// }); + +router.post('/signup', userController.signup ); +router.post('/signin', userController.signin ); + +router.get('/users', userController.getAll ); +router.get('/users/:id', userController.getById ); +router.post('/users/', userController.createUser ); +router.delete('/users/:id', userController.deleteById ); +router.put('/users/:id', userController.updateById ); + +module.exports = router; diff --git a/seeders/20170425042049-seed_data_contact.js b/seeders/20170425042049-seed_data_contact.js new file mode 100644 index 0000000..8076c24 --- /dev/null +++ b/seeders/20170425042049-seed_data_contact.js @@ -0,0 +1,24 @@ +'use strict'; + +module.exports = { + up: function (queryInterface, Sequelize) { + return queryInterface.bulkInsert('Contacts', [{ + name: 'John Doe', + password: '1234', + phone: '0218884592', + createdAt: new Date(), + updatedAt: new Date() + },{ + name: 'John Doe2', + password: '1234', + phone: '0218884592', + createdAt: new Date(), + updatedAt: new Date() + }], {}); + + }, + + down: function (queryInterface, Sequelize) { + return queryInterface.bulkDelete('Contacts', null, {}); + } +}; diff --git a/views/error.jade b/views/error.jade new file mode 100644 index 0000000..51ec12c --- /dev/null +++ b/views/error.jade @@ -0,0 +1,6 @@ +extends layout + +block content + h1= message + h2= error.status + pre #{error.stack} diff --git a/views/index.jade b/views/index.jade new file mode 100644 index 0000000..3d63b9a --- /dev/null +++ b/views/index.jade @@ -0,0 +1,5 @@ +extends layout + +block content + h1= title + p Welcome to #{title} diff --git a/views/layout.jade b/views/layout.jade new file mode 100644 index 0000000..15af079 --- /dev/null +++ b/views/layout.jade @@ -0,0 +1,7 @@ +doctype html +html + head + title= title + link(rel='stylesheet', href='/stylesheets/style.css') + body + block content From 73781245dbe7d4d4ffb73465739da2b924532fc1 Mon Sep 17 00:00:00 2001 From: ridho0 Date: Tue, 25 Apr 2017 17:50:07 +0700 Subject: [PATCH 2/2] kayaknya selesai --- controllers/user.js | 2 +- helpers/jwt.js | 35 +++++++++++++++++++++++++++++++++++ routes/users.js | 12 +++++++----- 3 files changed, 43 insertions(+), 6 deletions(-) create mode 100644 helpers/jwt.js diff --git a/controllers/user.js b/controllers/user.js index 811b5c6..bb933df 100644 --- a/controllers/user.js +++ b/controllers/user.js @@ -2,7 +2,7 @@ const db = require('../models') const methods = {} const passwordHash = require('password-hash') const jwt = require('jsonwebtoken') - +const jwtHelpers = require('../helpers/jwt') methods.signup = function(req, res, next) { let pass = passwordHash.generate(req.body.password) diff --git a/helpers/jwt.js b/helpers/jwt.js new file mode 100644 index 0000000..f9d8dfa --- /dev/null +++ b/helpers/jwt.js @@ -0,0 +1,35 @@ +const jwt = require('jsonwebtoken'); +// require('dotenv').config() + +const jwtHelpers = {} + + + jwtHelpers.isAdmin = function(req, res, next) { + // jwt.verify(req.headers.token, process.env.SECRET_KEY, + jwt.verify(req.headers.token, 'secret', + function(err, decoded) { + if(decoded) { + if(decoded.role == 'admin'){ + // res.send('berhasil') + next() + } + } else { + res.send(err) + } + }) + } + jwtHelpers.isLogin = function(req, res, next) { + // jwt.verify(req.headers.token, process.env.SECRET_KEY, + jwt.verify(req.headers.token, 'secret', + function(err, decoded) { + if(decoded) { + if(decoded.role == 'admin' || decoded.role == 'user'){ + // res.send('berhasil') + next() + } + } else { + res.send(err) + } + }) + } +module.exports = jwtHelpers diff --git a/routes/users.js b/routes/users.js index 712e4bb..d09ef73 100644 --- a/routes/users.js +++ b/routes/users.js @@ -1,6 +1,7 @@ const express = require('express'); const router = express.Router(); const userController = require('../controllers/user') +const jwtHelpers = require('../helpers/jwt') /* GET users listing. */ // router.get('/', function(req, res, next) { @@ -9,11 +10,12 @@ const userController = require('../controllers/user') router.post('/signup', userController.signup ); router.post('/signin', userController.signin ); +// router.get('/jwtTest', userController.jwtTest ); -router.get('/users', userController.getAll ); -router.get('/users/:id', userController.getById ); -router.post('/users/', userController.createUser ); -router.delete('/users/:id', userController.deleteById ); -router.put('/users/:id', userController.updateById ); +router.get('/users', jwtHelpers.isAdmin, userController.getAll ); +router.get('/users/:id', jwtHelpers.isLogin, userController.getById ); +router.post('/users/', jwtHelpers.isAdmin, userController.createUser ); +router.delete('/users/:id', jwtHelpers.isAdmin, userController.deleteById ); +router.put('/users/:id', jwtHelpers.isLogin, userController.updateById ); module.exports = router;