├── Assignment-4 ├── favorite.js ├── app.js ├── favoriteRouter.js └── db.json ├── Assignment-1 ├── server.js ├── dishRouter.js ├── leaderRouter.js └── promoRouter.js ├── Assignment-2 ├── leaders.js ├── promotions.js ├── leaderRouter.js └── promoRouter.js ├── README.md └── Assignment-3 ├── authenticate.js ├── users.js └── dishRouter.js /Assignment-4/favorite.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | const Schema = mongoose.Schema; 3 | 4 | const favouriteSchema = new Schema({ 5 | user: { 6 | type: mongoose.Schema.Types.ObjectId, 7 | ref: 'User' 8 | }, 9 | dishes: [ 10 | { 11 | type: mongoose.Schema.Types.ObjectId, 12 | ref: 'Dish' 13 | } 14 | ] 15 | },{ 16 | timestamps: true 17 | }); 18 | 19 | var Favourites = mongoose.model('Favourite', favouriteSchema); 20 | 21 | module.exports = Favourites; -------------------------------------------------------------------------------- /Assignment-1/server.js: -------------------------------------------------------------------------------- 1 | // Assignment 1 2 | var express = require('express'); 3 | var morgan = require('morgan'); 4 | 5 | var hostname = 'localhost'; 6 | var port = 3000; 7 | 8 | var app = express(); 9 | 10 | app.use(morgan('dev')); 11 | 12 | var dishRouter = require('./dishRouter'); 13 | app.use('/dishes', dishRouter.router); 14 | 15 | var promoRouter = require('./promoRouter'); 16 | app.use('/promotions', promoRouter.router); 17 | 18 | var leaderRouter = require('./leaderRouter'); 19 | app.use('/leadership', leaderRouter.router); 20 | 21 | app.use(express.static(__dirname + '/public')); 22 | 23 | app.listen(port, hostname, function () { 24 | console.log(`Server running at http://${hostname}:${port}/`); 25 | }); -------------------------------------------------------------------------------- /Assignment-2/leaders.js: -------------------------------------------------------------------------------- 1 | var mongoose = require('mongoose'); 2 | var Schema = mongoose.Schema; 3 | 4 | var leaderSchema = new Schema({ 5 | name: { 6 | type: String, 7 | required: true, 8 | unique: true 9 | }, 10 | image: { 11 | type: String, 12 | required: true 13 | }, 14 | designation: { 15 | type: String, 16 | required: true, 17 | }, 18 | abbr: { 19 | type: String, 20 | required: true, 21 | }, 22 | description: { 23 | type: String, 24 | required: true 25 | }, 26 | featured: { 27 | type: Boolean, 28 | required: false 29 | } 30 | }, { 31 | timestamps: true 32 | }); 33 | 34 | var Leaders = mongoose.model('Leader', leaderSchema); 35 | 36 | module.exports = Leaders; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Server-Side-Development-with-NodeJS-coursera 2 | Solutions for assignment for the Server side development course with NodeJS - Coursera. 3 | This course is focused on the server-side 4 | part of coding. Interesting and various 5 | servers to make this course a great 6 | learning tool in back-end coding. 7 | Week 1 and 2: 8 | 9 | Node.js and NPM 10 | Node Modules 11 | Node and the HTTP module 12 | Express, REST API, Express generator 13 | MongoDB, MongooseODM 14 | 15 | Week 3 and 4: 16 | 17 | REST API with MongoDB, Express and Mongoose 18 | Authentication 19 | Cookies 20 | User-Authentication with passport 21 | Mongoose Population 22 | HTTPS and Secure communication 23 | OAuth with passport and facebook 24 | Loopback, Data sources and Access control 25 | -------------------------------------------------------------------------------- /Assignment-2/promotions.js: -------------------------------------------------------------------------------- 1 | var mongoose = require('mongoose'); 2 | require('mongoose-currency').loadType(mongoose); 3 | 4 | var Currency = mongoose.Types.Currency; 5 | var Schema = mongoose.Schema; 6 | 7 | var promoSchema = new Schema({ 8 | name: { 9 | type: String, 10 | required: true, 11 | unique: true 12 | }, 13 | image: { 14 | type: String, 15 | required: true 16 | }, 17 | label: { 18 | type: String, 19 | default: "" 20 | }, 21 | price: { 22 | type: Currency, 23 | required: true, 24 | min: 0 25 | }, 26 | description: { 27 | type: String, 28 | required: true 29 | }, 30 | featured: { 31 | type: Boolean, 32 | required: fasle 33 | } 34 | }, { 35 | timestamps: true 36 | }); 37 | 38 | var Promotions = mongoose.model('Promotion', promoSchema); 39 | 40 | module.exports = Promotions; -------------------------------------------------------------------------------- /Assignment-1/dishRouter.js: -------------------------------------------------------------------------------- 1 | // Assignment 1 2 | var express = require('express'); 3 | var bodyParser = require('body-parser'); 4 | 5 | var dishRouter = express.Router(); 6 | 7 | dishRouter.use(bodyParser.json()); 8 | 9 | dishRouter.route('/') 10 | .all(function (req, res, next) { 11 | res.writeHead(200, {'Content-Type': 'text/plain'}); 12 | next(); 13 | }) 14 | 15 | .get(function (req, res, next) { 16 | res.end('Will send all the dishes to you!'); 17 | }) 18 | 19 | .post(function (req, res, next) { 20 | res.end('Will add the dish: ' + req.body.name + ' with details: ' + req.body.description); 21 | }) 22 | 23 | .delete(function (req, res, next) { 24 | res.end('Deleting all dishes'); 25 | }); 26 | 27 | dishRouter.route('/:dishId') 28 | .all(function (req, res, next) { 29 | res.writeHead(200, {'Content-Type': 'text/plain'}); 30 | next(); 31 | }) 32 | 33 | .get(function (req, res, next) { 34 | res.end('Will send details of the dish: ' + req.params.dishId + ' to you!'); 35 | }) 36 | 37 | .put(function (req, res, next) { 38 | res.write('Updating the dish: ' + req.params.dishId + '\n'); 39 | res.end('Will update the dish: ' + req.body.name + 40 | ' with details: ' + req.body.description); 41 | }) 42 | 43 | .delete(function (req, res, next) { 44 | res.end('Deleting dish: ' + req.params.dishId); 45 | }); 46 | 47 | exports.router = dishRouter; -------------------------------------------------------------------------------- /Assignment-1/leaderRouter.js: -------------------------------------------------------------------------------- 1 | // Assignment 1 2 | var express = require('express'); 3 | var bodyParser = require('body-parser'); 4 | 5 | var leaderRouter = express.Router(); 6 | 7 | leaderRouter.use(bodyParser.json()); 8 | 9 | leaderRouter.route('/') 10 | .all(function (req, res, next) { 11 | res.writeHead(200, {'Content-Type': 'text/plain'}); 12 | next(); 13 | }) 14 | 15 | .get(function (req, res, next) { 16 | res.end('Will send all the leaders to you!'); 17 | }) 18 | 19 | .post(function (req, res, next) { 20 | res.end('Will add the leader: ' + req.body.name + ' with details: ' + req.body.description); 21 | }) 22 | 23 | .delete(function (req, res, next) { 24 | res.end('Deleting all leaders'); 25 | }); 26 | 27 | leaderRouter.route('/:leaderId') 28 | .all(function (req, res, next) { 29 | res.writeHead(200, {'Content-Type': 'text/plain'}); 30 | next(); 31 | }) 32 | 33 | .get(function (req, res, next) { 34 | res.end('Will send details of the leader: ' + req.params.leaderId + ' to you!'); 35 | }) 36 | 37 | .put(function (req, res, next) { 38 | res.write('Updating the leader: ' + req.params.leaderId + '\n'); 39 | res.end('Will update the leader: ' + req.body.name + 40 | ' with details: ' + req.body.description); 41 | }) 42 | 43 | .delete(function (req, res, next) { 44 | res.end('Deleting leader: ' + req.params.leaderId); 45 | }); 46 | 47 | exports.router = leaderRouter; -------------------------------------------------------------------------------- /Assignment-1/promoRouter.js: -------------------------------------------------------------------------------- 1 | // Assignment 1 2 | var express = require('express'); 3 | var bodyParser = require('body-parser'); 4 | 5 | var promoRouter = express.Router(); 6 | 7 | promoRouter.use(bodyParser.json()); 8 | 9 | promoRouter.route('/') 10 | .all(function (req, res, next) { 11 | res.writeHead(200, {'Content-Type': 'text/plain'}); 12 | next(); 13 | }) 14 | 15 | .get(function (req, res, next) { 16 | res.end('Will send all the promotions to you!'); 17 | }) 18 | 19 | .post(function (req, res, next) { 20 | res.end('Will add the promotion: ' + req.body.name + ' with details: ' + req.body.description); 21 | }) 22 | 23 | .delete(function (req, res, next) { 24 | res.end('Deleting all promotions'); 25 | }); 26 | 27 | promoRouter.route('/:promoId') 28 | .all(function (req, res, next) { 29 | res.writeHead(200, {'Content-Type': 'text/plain'}); 30 | next(); 31 | }) 32 | 33 | .get(function (req, res, next) { 34 | res.end('Will send details of the promotion: ' + req.params.promoId + ' to you!'); 35 | }) 36 | 37 | .put(function (req, res, next) { 38 | res.write('Updating the promotion: ' + req.params.promoId + '\n'); 39 | res.end('Will update the promotion: ' + req.body.name + 40 | ' with details: ' + req.body.description); 41 | }) 42 | 43 | .delete(function (req, res, next) { 44 | res.end('Deleting promotion: ' + req.params.promoId); 45 | }); 46 | 47 | exports.router = promoRouter; -------------------------------------------------------------------------------- /Assignment-3/authenticate.js: -------------------------------------------------------------------------------- 1 | var passport = require('passport'); 2 | var LocalStrategy = require('passport-local').Strategy; 3 | var User = require('./models/user'); 4 | var JwtStrategy = require('passport-jwt').Strategy; 5 | var ExtractJwt = require('passport-jwt').ExtractJwt; 6 | var jwt = require('jsonwebtoken'); 7 | 8 | var config = require('./config'); 9 | 10 | exports.local = passport.use(new LocalStrategy(User.authenticate())); 11 | passport.serializeUser(User.serializeUser()); 12 | passport.deserializeUser(User.deserializeUser()); 13 | 14 | exports.getToken = function (user) { 15 | return jwt.sign(user, config.secretKey, { 16 | expiresIn: 3600 17 | }); 18 | } 19 | 20 | var opts = {}; 21 | opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken(); 22 | opts.secretOrKey = config.secretKey; 23 | 24 | exports.jwtPassport = passport.use(new JwtStrategy(opts, (jwt_payload, done) => { 25 | console.log("JWT Payload : ", jwt_payload); 26 | User.findOne({ 27 | _id: jwt_payload._id 28 | }, (err, user) => { 29 | if (err) { 30 | return done(err, false); 31 | } else if (user) { 32 | return done(null, user); 33 | } else { 34 | return done(null, false); 35 | } 36 | }) 37 | 38 | })); 39 | 40 | exports.verifyUser = function (req, res, next) { 41 | var token = req.body.token || req.query.token || req.headers['x-access-token']; 42 | if (token) { 43 | jwt.verify(token, config.secretKey, function (err, decoded) { 44 | if (err) { 45 | var err = new Error('You are not authenticated!'); 46 | err.status = 401; 47 | return next(err); 48 | } else { 49 | req.decoded = decoded; 50 | next(); 51 | } 52 | }); 53 | } else { 54 | var err = new Error('No token provided!'); 55 | err.status = 403; 56 | return next(err); 57 | } 58 | }; 59 | 60 | exports.verifyAdmin = function (req, res, next) { 61 | if (req.user.admin) { 62 | next(); 63 | } else { 64 | var err = new Error('You are not authorized to perform this operation!'); 65 | err.status = 403; 66 | return next(err); 67 | } 68 | } -------------------------------------------------------------------------------- /Assignment-3/users.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var bodyParser = require('body-parser'); 3 | var User = require('../models/user'); 4 | var passport = require('passport'); 5 | var authenticate = require('../authenticate'); 6 | 7 | var router = express.Router(); 8 | router.use(bodyParser.json()); 9 | 10 | 11 | router.get('/', authenticate.verifyUser, authenticate.verifyAdmin, (req, res, next) => { 12 | User.find({}, (err, users) => { 13 | if (err) { 14 | return next(err); 15 | } else { 16 | res.statusCode = 200; 17 | res.setHeader('Content_type', 'application/json'); 18 | res.json(users); 19 | } 20 | }) 21 | }); 22 | 23 | router.post('/signup', (req, res, next) => { 24 | User.register(new User({ 25 | username: req.body.username 26 | }), 27 | req.body.password, (err, user) => { 28 | if (err) { 29 | res.statusCode = 500; 30 | res.setHeader('Content-Type', 'application/json'); 31 | res.json({ 32 | err: err 33 | }); 34 | } else { 35 | if (req.body.firstname) { 36 | user.firstname = req.body.firstname; 37 | } 38 | if (req.body.lastname) { 39 | user.lastname = req.body.lastname; 40 | } 41 | user.save((err, user) => { 42 | passport.authenticate('local')(req, res, () => { 43 | if (err) { 44 | res.statusCode = 500; 45 | res.setHeader('Content-Type', 'application/json'); 46 | res.json({ 47 | err: err 48 | }); 49 | return; 50 | } 51 | res.statusCode = 200; 52 | res.setHeader('Content-Type', 'application/json'); 53 | res.json({ 54 | success: true, 55 | status: 'Registration Successful!' 56 | }); 57 | }); 58 | }); 59 | } 60 | }); 61 | }); 62 | 63 | router.post('/login', passport.authenticate('local'), (req, res) => { 64 | var token = authenticate.getToken({ 65 | _id: req.user._id, 66 | firstname: req.user.firstname, 67 | lastname: req.user.lastname 68 | }); 69 | 70 | res.statusCode = 200; 71 | res.setHeader('Content-Type', 'application/json'); 72 | res.json({ 73 | success: true, 74 | status: 'You are successfully logged in!', 75 | token: token 76 | }); 77 | }); 78 | 79 | 80 | router.get('/logout', (req, res, next) => { 81 | if (req.session) { 82 | req.session.destroy(); 83 | res.clearCookie('session-id'); 84 | res.redirect('/'); 85 | } 86 | }); 87 | 88 | module.exports = router; -------------------------------------------------------------------------------- /Assignment-2/leaderRouter.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const bodyParser = require('body-parser'); 3 | const mongoose = require('mongoose'); 4 | const Leaders = require('../models/leaders'); 5 | 6 | const leaderRouter = express.Router(); 7 | 8 | leaderRouter.use(bodyParser.json()); 9 | 10 | leaderRouter.route('/') 11 | .get((req,res,next) => { 12 | Leaders.find({}) 13 | .then((leaders) => { 14 | res.statusCode = 200; 15 | res.setHeader('Content-Type', 'application/json'); 16 | res.json(leaders); 17 | }, (err) => next(err)) 18 | .catch((err) => next(err)); 19 | }) 20 | .post((req, res, next) => { 21 | Leaders.create(req.body) 22 | .then((leader) => { 23 | console.log('Leader Created ', leader); 24 | res.statusCode = 200; 25 | res.setHeader('Content-Type', 'application/json'); 26 | res.json(leader); 27 | }, (err) => next(err)) 28 | .catch((err) => next(err)); 29 | }) 30 | .put((req, res, next) => { 31 | res.statusCode = 403; 32 | res.setHeader('Content-Type', 'text/plain'); 33 | res.end('PUT operation not supported on /leaders'); 34 | }) 35 | .delete((req, res, next) => { 36 | Leaders.remove({}) 37 | .then((resp) => { 38 | res.statusCode = 200; 39 | res.setHeader('Content-Type', 'application/json'); 40 | res.json(resp); 41 | }, (err) => next(err)) 42 | .catch((err) => next(err)); 43 | }); 44 | 45 | leaderRouter.route('/:leaderId') 46 | .get((req,res,next) => { 47 | Leaders.findById(req.params.leaderId) 48 | .then((leader) => { 49 | res.statusCode = 200; 50 | res.setHeader('Content-Type', 'application/json'); 51 | res.json(leader); 52 | }, (err) => next(err)) 53 | .catch((err) => next(err)); 54 | }) 55 | .post((req, res, next) => { 56 | res.statusCode = 403; 57 | res.setHeader('Content-Type', 'text/plain'); 58 | res.end('POST operation not supported on /leaders/'+ req.params.leaderId); 59 | }) 60 | .put((req, res, next) => { 61 | Leaders.findByIdAndUpdate(req.params.leaderId, { 62 | $set: req.body 63 | }, { new: true }) 64 | .then((leader) => { 65 | res.statusCode = 200; 66 | res.setHeader('Content-Type', 'application/json'); 67 | res.json(leader); 68 | }, (err) => next(err)) 69 | .catch((err) => next(err)); 70 | }) 71 | .delete((req, res, next) => { 72 | Leaders.findByIdAndRemove(req.params.leaderId) 73 | .then((resp) => { 74 | res.statusCode = 200; 75 | res.setHeader('Content-Type', 'application/json'); 76 | res.json(resp); 77 | }, (err) => next(err)) 78 | .catch((err) => next(err)); 79 | }); 80 | 81 | module.exports = leaderRouter; -------------------------------------------------------------------------------- /Assignment-2/promoRouter.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const bodyParser = require('body-parser'); 3 | const mongoose = require('mongoose'); 4 | const Promotions = require('../models/promotions'); 5 | 6 | const promoRouter = express.Router(); 7 | 8 | promoRouter.use(bodyParser.json()); 9 | 10 | promoRouter.route('/') 11 | .get((req,res,next) => { 12 | Promotions.find({}) 13 | .then((promotions) => { 14 | res.statusCode = 200; 15 | res.setHeader('Content-Type', 'application/json'); 16 | res.json(promotions); 17 | }, (err) => next(err)) 18 | .catch((err) => next(err)); 19 | }) 20 | .post((req, res, next) => { 21 | Promotions.create(req.body) 22 | .then((promotion) => { 23 | console.log('Promotion Created ', promotion); 24 | res.statusCode = 200; 25 | res.setHeader('Content-Type', 'application/json'); 26 | res.json(promotion); 27 | }, (err) => next(err)) 28 | .catch((err) => next(err)); 29 | }) 30 | .put((req, res, next) => { 31 | res.statusCode = 403; 32 | res.setHeader('Content-Type', 'text/plain'); 33 | res.end('PUT operation not supported on /promotions'); 34 | }) 35 | .delete((req, res, next) => { 36 | Promotions.remove({}) 37 | .then((resp) => { 38 | res.statusCode = 200; 39 | res.setHeader('Content-Type', 'application/json'); 40 | res.json(resp); 41 | }, (err) => next(err)) 42 | .catch((err) => next(err)); 43 | }); 44 | 45 | promoRouter.route('/:promoId') 46 | .get((req,res,next) => { 47 | Promotions.findById(req.params.promoId) 48 | .then((promotion) => { 49 | res.statusCode = 200; 50 | res.setHeader('Content-Type', 'application/json'); 51 | res.json(promotion); 52 | }, (err) => next(err)) 53 | .catch((err) => next(err)); 54 | }) 55 | .post((req, res, next) => { 56 | res.statusCode = 403; 57 | res.setHeader('Content-Type', 'text/plain'); 58 | res.end('POST operation not supported on /promotions/'+ req.params.promoId); 59 | }) 60 | .put((req, res, next) => { 61 | Promotions.findByIdAndUpdate(req.params.promoId, { 62 | $set: req.body 63 | }, { new: true }) 64 | .then((promotion) => { 65 | res.statusCode = 200; 66 | res.setHeader('Content-Type', 'application/json'); 67 | res.json(promotion); 68 | }, (err) => next(err)) 69 | .catch((err) => next(err)); 70 | }) 71 | .delete((req, res, next) => { 72 | Promotions.findByIdAndRemove(req.params.promoId) 73 | .then((resp) => { 74 | res.statusCode = 200; 75 | res.setHeader('Content-Type', 'application/json'); 76 | res.json(resp); 77 | }, (err) => next(err)) 78 | .catch((err) => next(err)); 79 | }); 80 | 81 | module.exports = promoRouter; -------------------------------------------------------------------------------- /Assignment-4/app.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var path = require('path'); 3 | var favicon = require('serve-favicon'); 4 | var logger = require('morgan'); 5 | var cookieParser = require('cookie-parser'); 6 | var bodyParser = require('body-parser'); 7 | var session = require('express-session'); 8 | var FileStore = require('session-file-store')(session); 9 | var passport = require('passport'); 10 | var authenticate = require('./authenticate'); 11 | var config = require('./config'); 12 | 13 | var index = require('./routes/index'); 14 | var users = require('./routes/users'); 15 | var dishRouter = require('./routes/dishRouter'); 16 | var leaderRouter = require('./routes/leaderRouter'); 17 | var promoRouter = require('./routes/promoRouter'); 18 | var uploadRouter = require('./routes/uploadRouter'); 19 | var favouriteRouter = require('./routes/favouriteRouter'); 20 | 21 | const mongoose = require('mongoose'); 22 | mongoose.Promise = require('bluebird'); 23 | 24 | const Dishes = require('./models/dishes'); 25 | 26 | const url = config.mongoUrl; 27 | 28 | const connect = mongoose.connect(url, { 29 | useMongoClient: true 30 | }); 31 | 32 | connect.then((db) => { 33 | console.log('Connected to server!'); 34 | }, (err) => { 35 | console.log(err); 36 | }); 37 | 38 | var app = express(); 39 | 40 | app.all('*', (req, res, nxt) => { 41 | if(req.secure) { 42 | return nxt(); 43 | } else { 44 | res.redirect(307, 'https://' + req.hostname + ':' + app.get('secPort') + req.url); 45 | } 46 | }); 47 | 48 | // view engine setup 49 | app.set('views', path.join(__dirname, 'views')); 50 | app.set('view engine', 'jade'); 51 | 52 | app.use(logger('dev')); 53 | app.use(bodyParser.json()); 54 | app.use(bodyParser.urlencoded({ extended: false })); 55 | 56 | app.use(session({ 57 | name: 'session-id', 58 | secret: 'Jesus-Loves-w@ch!ra-so-Much!!', 59 | saveUninitialized: false, 60 | resave: false, 61 | store: new FileStore() 62 | })); 63 | // app.use(session({secret: 'SECRET'})); 64 | app.use(passport.initialize()); 65 | app.use(passport.session()); 66 | 67 | app.use('/', index); 68 | app.use('/users', users); 69 | 70 | // authentication before resource access 71 | // function auth(req, res, next) { 72 | // // console.log(req.signedCookies); 73 | // console.log(req.session); 74 | 75 | // // if(!req.signedCookies.user){ 76 | // if(!req.user){ 77 | // // var authHeader = req.headers.authorization; 78 | // // if(!authHeader){ 79 | // var err = new Error('You are not authenticated!'); 80 | // // res.setHeader('WWW-Authenticate', 'Basic'); 81 | // err.status = 403; 82 | // return next(err); 83 | // } 84 | // else { 85 | // // if(req.signedCookies.user === 'admin'){ 86 | // next(); 87 | // } 88 | // } 89 | // app.use(auth); 90 | // uncomment after placing your favicon in /public 91 | //app.use(favicon(path.join(__dirname, 'public', 'favicon.ico'))); 92 | app.use(express.static(path.join(__dirname, 'public'))); 93 | 94 | app.use('/dishes', dishRouter); 95 | app.use('/leaders', leaderRouter); 96 | app.use('/promotions', promoRouter); 97 | app.use('/imageUpload', uploadRouter); 98 | app.use('/favorites', favouriteRouter); 99 | 100 | // catch 404 and forward to error handler 101 | app.use(function(req, res, next) { 102 | var err = new Error('Not Found'); 103 | err.status = 404; 104 | next(err); 105 | }); 106 | 107 | // error handler 108 | app.use(function(err, req, res, next) { 109 | // set locals, only providing error in development 110 | res.locals.message = err.message; 111 | res.locals.error = req.app.get('env') === 'development' ? err : {}; 112 | 113 | // render the error page 114 | res.status(err.status || 500); 115 | res.render('error'); 116 | }); 117 | 118 | module.exports = app; -------------------------------------------------------------------------------- /Assignment-4/favoriteRouter.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const bodyParser = require('body-parser'); 3 | const mongoose = require('mongoose'); 4 | const authenticate = require('../authenticate'); 5 | const cors = require('./cors'); 6 | const Favourites = require('../models/favourite'); 7 | 8 | const favouriteRouter = express.Router(); 9 | 10 | favouriteRouter.use(bodyParser.json()); 11 | 12 | favouriteRouter.route('/') 13 | .options(cors.corsWithOptions, (req, res) => { res.sendStatus(200); }) 14 | .get(cors.cors, authenticate.verifyUser, (req, res, next) => { 15 | Favourites.find({}) 16 | .populate('user') 17 | .populate('dishes') 18 | .then((favourites) => { 19 | // extract favourites that match the req.user.id 20 | if (favourites) { 21 | user_favourites = favourites.filter(fav => fav.user._id.toString() === req.user.id.toString())[0]; 22 | if(!user_favourites) { 23 | var err = new Error('You have no favourites!'); 24 | err.status = 404; 25 | return next(err); 26 | } 27 | res.statusCode = 200; 28 | res.setHeader("Content-Type", "application/json"); 29 | res.json(user_favourites); 30 | } else { 31 | var err = new Error('There are no favourites'); 32 | err.status = 404; 33 | return next(err); 34 | } 35 | 36 | }, (err) => next(err)) 37 | .catch((err) => next(err)); 38 | }) 39 | .post(cors.corsWithOptions, authenticate.verifyUser, 40 | (req, res, next) => { 41 | Favourites.find({}) 42 | .populate('user') 43 | .populate('dishes') 44 | .then((favourites) => { 45 | var user; 46 | if(favourites) 47 | user = favourites.filter(fav => fav.user._id.toString() === req.user.id.toString())[0]; 48 | if(!user) 49 | user = new Favourites({user: req.user.id}); 50 | for(let i of req.body){ 51 | if(user.dishes.find((d_id) => { 52 | if(d_id._id){ 53 | return d_id._id.toString() === i._id.toString(); 54 | } 55 | })) 56 | continue; 57 | user.dishes.push(i._id); 58 | } 59 | user.save() 60 | .then((userFavs) => { 61 | res.statusCode = 201; 62 | res.setHeader("Content-Type", "application/json"); 63 | res.json(userFavs); 64 | console.log("Favourites Created"); 65 | }, (err) => next(err)) 66 | .catch((err) => next(err)); 67 | 68 | }) 69 | .catch((err) => next(err)); 70 | }) 71 | 72 | .put(cors.corsWithOptions, authenticate.verifyUser, (req, res, next) => { 73 | res.statusCode = 403; 74 | res.end('PUT operation is not supported on /favourites'); 75 | }) 76 | .delete(cors.corsWithOptions, authenticate.verifyUser, (req, res, next) => { 77 | Favourites.find({}) 78 | .populate('user') 79 | .populate('dishes') 80 | .then((favourites) => { 81 | var favToRemove; 82 | if (favourites) { 83 | favToRemove = favourites.filter(fav => fav.user._id.toString() === req.user.id.toString())[0]; 84 | } 85 | if(favToRemove){ 86 | favToRemove.remove() 87 | .then((result) => { 88 | res.statusCode = 200; 89 | res.setHeader("Content-Type", "application/json"); 90 | res.json(result); 91 | }, (err) => next(err)); 92 | 93 | } else { 94 | var err = new Error('You do not have any favourites'); 95 | err.status = 404; 96 | return next(err); 97 | } 98 | }, (err) => next(err)) 99 | .catch((err) => next(err)); 100 | }); 101 | 102 | favouriteRouter.route('/:dishId') 103 | .options(cors.corsWithOptions, (req, res) => { res.sendStatus(200); }) 104 | .get(cors.cors, authenticate.verifyUser, (req, res, next) => { 105 | Favourites.find({}) 106 | .populate('user') 107 | .populate('dishes') 108 | .then((favourites) => { 109 | if (favourites) { 110 | const favs = favourites.filter(fav => fav.user._id.toString() === req.user.id.toString())[0]; 111 | const dish = favs.dishes.filter(dish => dish.id === req.params.dishId)[0]; 112 | if(dish) { 113 | res.statusCode = 200; 114 | res.setHeader("Content-Type", "application/json"); 115 | res.json(dish); 116 | } else { 117 | var err = new Error('You do not have dish ' + req.params.dishId); 118 | err.status = 404; 119 | return next(err); 120 | } 121 | } else { 122 | var err = new Error('You do not have any favourites'); 123 | err.status = 404; 124 | return next(err); 125 | } 126 | }, (err) => next(err)) 127 | .catch((err) => next(err)); 128 | }) 129 | .post(cors.corsWithOptions, authenticate.verifyUser, 130 | (req, res, next) => { 131 | Favourites.find({}) 132 | .populate('user') 133 | .populate('dishes') 134 | .then((favourites) => { 135 | var user; 136 | if(favourites) 137 | user = favourites.filter(fav => fav.user._id.toString() === req.user.id.toString())[0]; 138 | if(!user) 139 | user = new Favourites({user: req.user.id}); 140 | if(!user.dishes.find((d_id) => { 141 | if(d_id._id) 142 | return d_id._id.toString() === req.params.dishId.toString(); 143 | })) 144 | user.dishes.push(req.params.dishId); 145 | 146 | user.save() 147 | .then((userFavs) => { 148 | res.statusCode = 201; 149 | res.setHeader("Content-Type", "application/json"); 150 | res.json(userFavs); 151 | console.log("Favourites Created"); 152 | }, (err) => next(err)) 153 | .catch((err) => next(err)); 154 | 155 | }) 156 | .catch((err) => next(err)); 157 | }) 158 | 159 | .put(cors.corsWithOptions, authenticate.verifyUser, (req, res, next) => { 160 | res.statusCode = 403; 161 | res.end('PUT operation is not supported on /favourites/:dishId'); 162 | }) 163 | .delete(cors.corsWithOptions, authenticate.verifyUser, (req, res, next) => { 164 | Favourites.find({}) 165 | .populate('user') 166 | .populate('dishes') 167 | .then((favourites) => { 168 | var user; 169 | if(favourites) 170 | user = favourites.filter(fav => fav.user._id.toString() === req.user.id.toString())[0]; 171 | if(user){ 172 | user.dishes = user.dishes.filter((dishid) => dishid._id.toString() !== req.params.dishId); 173 | user.save() 174 | .then((result) => { 175 | res.statusCode = 200; 176 | res.setHeader("Content-Type", "application/json"); 177 | res.json(result); 178 | }, (err) => next(err)); 179 | 180 | } else { 181 | var err = new Error('You do not have any favourites'); 182 | err.status = 404; 183 | return next(err); 184 | } 185 | }, (err) => next(err)) 186 | .catch((err) => next(err)); 187 | }); 188 | 189 | module.exports = favouriteRouter; -------------------------------------------------------------------------------- /Assignment-4/db.json: -------------------------------------------------------------------------------- 1 | { 2 | "dishes": [ 3 | { 4 | "name": "Uthappizza", 5 | "image": "images/uthappizza.png", 6 | "category": "mains", 7 | "label": "Hot", 8 | "price": "4.99", 9 | "featured": "true", 10 | "description": "A unique combination of Indian Uthappam (pancake) and Italian pizza, topped with Cerignola olives, ripe vine cherry tomatoes, Vidalia onion, Guntur chillies and Buffalo Paneer.", 11 | "comments": [ 12 | { 13 | "rating": 5, 14 | "comment": "Imagine all the eatables, living in conFusion!", 15 | "author": "John Lemon", 16 | "date": "2012-10-16T17:57:28.556094Z" 17 | }, 18 | { 19 | "rating": 4, 20 | "comment": "Sends anyone to heaven, I wish I could get my mother-in-law to eat it!", 21 | "author": "Paul McVites", 22 | "date": "2014-09-05T17:57:28.556094Z" 23 | }, 24 | { 25 | "rating": 3, 26 | "comment": "Eat it, just eat it!", 27 | "author": "Michael Jaikishan", 28 | "date": "2015-02-13T17:57:28.556094Z" 29 | }, 30 | { 31 | "rating": 4, 32 | "comment": "Ultimate, Reaching for the stars!", 33 | "author": "Ringo Starry", 34 | "date": "2013-12-02T17:57:28.556094Z" 35 | }, 36 | { 37 | "rating": 2, 38 | "comment": "It's your birthday, we're gonna party!", 39 | "author": "25 Cent", 40 | "date": "2011-12-02T17:57:28.556094Z" 41 | } 42 | ] 43 | }, 44 | { 45 | "name": "Zucchipakoda", 46 | "image": "images/zucchipakoda.png", 47 | "category": "appetizer", 48 | "label": "", 49 | "price": "1.99", 50 | "featured": "false", 51 | "description": "Deep fried Zucchini coated with mildly spiced Chickpea flour batter accompanied with a sweet-tangy tamarind sauce", 52 | "comments": [ 53 | { 54 | "rating": 5, 55 | "comment": "Imagine all the eatables, living in conFusion!", 56 | "author": "John Lemon", 57 | "date": "2012-10-16T17:57:28.556094Z" 58 | }, 59 | { 60 | "rating": 4, 61 | "comment": "Sends anyone to heaven, I wish I could get my mother-in-law to eat it!", 62 | "author": "Paul McVites", 63 | "date": "2014-09-05T17:57:28.556094Z" 64 | }, 65 | { 66 | "rating": 3, 67 | "comment": "Eat it, just eat it!", 68 | "author": "Michael Jaikishan", 69 | "date": "2015-02-13T17:57:28.556094Z" 70 | }, 71 | { 72 | "rating": 4, 73 | "comment": "Ultimate, Reaching for the stars!", 74 | "author": "Ringo Starry", 75 | "date": "2013-12-02T17:57:28.556094Z" 76 | }, 77 | { 78 | "rating": 2, 79 | "comment": "It's your birthday, we're gonna party!", 80 | "author": "25 Cent", 81 | "date": "2011-12-02T17:57:28.556094Z" 82 | } 83 | ] 84 | }, 85 | { 86 | "name": "Vadonut", 87 | "image": "images/vadonut.png", 88 | "category": "appetizer", 89 | "label": "New", 90 | "price": "1.99", 91 | "featured": "false", 92 | "description": "A quintessential ConFusion experience, is it a vada or is it a donut?", 93 | "comments": [ 94 | { 95 | "rating": 5, 96 | "comment": "Imagine all the eatables, living in conFusion!", 97 | "author": "John Lemon", 98 | "date": "2012-10-16T17:57:28.556094Z" 99 | }, 100 | { 101 | "rating": 4, 102 | "comment": "Sends anyone to heaven, I wish I could get my mother-in-law to eat it!", 103 | "author": "Paul McVites", 104 | "date": "2014-09-05T17:57:28.556094Z" 105 | }, 106 | { 107 | "rating": 3, 108 | "comment": "Eat it, just eat it!", 109 | "author": "Michael Jaikishan", 110 | "date": "2015-02-13T17:57:28.556094Z" 111 | }, 112 | { 113 | "rating": 4, 114 | "comment": "Ultimate, Reaching for the stars!", 115 | "author": "Ringo Starry", 116 | "date": "2013-12-02T17:57:28.556094Z" 117 | }, 118 | { 119 | "rating": 2, 120 | "comment": "It's your birthday, we're gonna party!", 121 | "author": "25 Cent", 122 | "date": "2011-12-02T17:57:28.556094Z" 123 | } 124 | ] 125 | }, 126 | { 127 | "name": "ElaiCheese Cake", 128 | "image": "images/elaicheesecake.png", 129 | "category": "dessert", 130 | "label": "", 131 | "price": "2.99", 132 | "featured": "false", 133 | "description": "A delectable, semi-sweet New York Style Cheese Cake, with Graham cracker crust and spiced with Indian cardamoms", 134 | "comments": [ 135 | { 136 | "rating": 5, 137 | "comment": "Imagine all the eatables, living in conFusion!", 138 | "author": "John Lemon", 139 | "date": "2012-10-16T17:57:28.556094Z" 140 | }, 141 | { 142 | "rating": 4, 143 | "comment": "Sends anyone to heaven, I wish I could get my mother-in-law to eat it!", 144 | "author": "Paul McVites", 145 | "date": "2014-09-05T17:57:28.556094Z" 146 | }, 147 | { 148 | "rating": 3, 149 | "comment": "Eat it, just eat it!", 150 | "author": "Michael Jaikishan", 151 | "date": "2015-02-13T17:57:28.556094Z" 152 | }, 153 | { 154 | "rating": 4, 155 | "comment": "Ultimate, Reaching for the stars!", 156 | "author": "Ringo Starry", 157 | "date": "2013-12-02T17:57:28.556094Z" 158 | }, 159 | { 160 | "rating": 2, 161 | "comment": "It's your birthday, we're gonna party!", 162 | "author": "25 Cent", 163 | "date": "2011-12-02T17:57:28.556094Z" 164 | } 165 | ] 166 | } 167 | ], 168 | "promotions": [ 169 | { 170 | "name": "Weekend Grand Buffet", 171 | "image": "images/buffet.png", 172 | "label": "New", 173 | "price": "19.99", 174 | "featured": "true", 175 | "description": "Featuring mouthwatering combinations with a choice of five different salads, six enticing appetizers, six main entrees and five choicest desserts. Free flowing bubbly and soft drinks. All for just $19.99 per person " 176 | } 177 | ], 178 | "leaders": [ 179 | { 180 | "name": "Peter Pan", 181 | "image": "images/alberto.png", 182 | "designation": "Chief Epicurious Officer", 183 | "abbr": "CEO", 184 | "featured": "false", 185 | "description": "Our CEO, Peter, credits his hardworking East Asian immigrant parents who undertook the arduous journey to the shores of America with the intention of giving their children the best future. His mother's wizardy in the kitchen whipping up the tastiest dishes with whatever is available inexpensively at the supermarket, was his first inspiration to create the fusion cuisines for which The Frying Pan became well known. He brings his zeal for fusion cuisines to this restaurant, pioneering cross-cultural culinary connections." 186 | }, 187 | { 188 | "name": "Dhanasekaran Witherspoon", 189 | "image": "images/alberto.png", 190 | "designation": "Chief Food Officer", 191 | "abbr": "CFO", 192 | "featured": "false", 193 | "description": "Our CFO, Danny, as he is affectionately referred to by his colleagues, comes from a long established family tradition in farming and produce. His experiences growing up on a farm in the Australian outback gave him great appreciation for varieties of food sources. As he puts it in his own words, Everything that runs, wins, and everything that stays, pays!" 194 | }, 195 | { 196 | "name": "Agumbe Tang", 197 | "image": "images/alberto.png", 198 | "designation": "Chief Taste Officer", 199 | "abbr": "CTO", 200 | "featured": "false", 201 | "description": "Blessed with the most discerning gustatory sense, Agumbe, our CFO, personally ensures that every dish that we serve meets his exacting tastes. Our chefs dread the tongue lashing that ensues if their dish does not meet his exacting standards. He lives by his motto, You click only if you survive my lick." 202 | }, 203 | { 204 | "name": "Alberto Somayya", 205 | "image": "images/alberto.png", 206 | "designation": "Executive Chef", 207 | "abbr": "EC", 208 | "featured": "true", 209 | "description": "Award winning three-star Michelin chef with wide International experience having worked closely with whos-who in the culinary world, he specializes in creating mouthwatering Indo-Italian fusion experiences. He says, Put together the cuisines from the two craziest cultures, and you get a winning hit! Amma Mia!" 210 | } 211 | ], 212 | "feedback": [] 213 | } -------------------------------------------------------------------------------- /Assignment-3/dishRouter.js: -------------------------------------------------------------------------------- 1 | 2 | const express = require('express'); 3 | const bodyParser = require('body-parser'); 4 | const mongoose = require('mongoose'); 5 | const authenticate = require('../authenticate'); 6 | 7 | const Dishes = require('../models/dishes'); 8 | 9 | const dishRouter = express.Router(); 10 | 11 | dishRouter.use(bodyParser.json()); 12 | 13 | dishRouter.route('/') 14 | .get((req, res, next) => { 15 | Dishes.find({}).populate('comments.author') 16 | .then((dishes) => { 17 | res.statusCode = 200; 18 | res.setHeader("Content-Type", "application/json"); 19 | res.json(dishes); 20 | }, (err) => next(err)).catch((err) => next(err)); 21 | }) 22 | 23 | .post(authenticate.verifyUser, authenticate.verifyAdmin, (req, res, next) => { 24 | Dishes.create(req.body).then((dish) => { 25 | res.statusCode = 201; 26 | res.setHeader("Content-Type", "application/json"); 27 | res.json(dish); 28 | console.log("Dish Created"); 29 | }, (err) => next(err)).catch((err) => next(err)); 30 | }) 31 | 32 | .put(authenticate.verifyUser, authenticate.verifyAdmin, (req, res, next) => { 33 | res.statusCode = 403; 34 | res.end('PUT operation is not supported on /dishes'); 35 | }) 36 | 37 | .delete(authenticate.verifyUser, authenticate.verifyAdmin, (req, res, next) => { 38 | Dishes.remove({}).then((result) => { 39 | res.statusCode = 200; 40 | res.setHeader("Content-Type", "application/json"); 41 | res.json(result); 42 | }, (err) => next(err)).catch((err) => next(err)); 43 | }) 44 | 45 | dishRouter.route('/:dishId') 46 | .get((req, res, next) => { 47 | Dishes.findById(req.params.dishId).populate('comments.author').then((dishes) => { 48 | res.statusCode = 200; 49 | res.setHeader("Content-Type", "application/json"); 50 | res.json(dishes); 51 | }, (err) => next(err)).catch((err) => next(err)); 52 | }) 53 | 54 | .post(authenticate.verifyUser, authenticate.verifyAdmin, (req, res, next) => { 55 | res.statusCode = 403; 56 | res.end('POST operation is not supported on /dishes/' + req.params.dishId); 57 | }) 58 | 59 | .put(authenticate.verifyUser, authenticate.verifyAdmin, (req, res, next) => { 60 | Dishes.findByIdAndUpdate(req.params.dishId, { 61 | $set: req.body 62 | }, { 63 | new: true 64 | }).then((dish) => { 65 | res.statusCode = 200; 66 | res.setHeader("Content-Type", "application/json"); 67 | res.json(dish); 68 | }, (err) => next(err)).catch((err) => next(err)); 69 | }) 70 | 71 | .delete(authenticate.verifyUser, authenticate.verifyAdmin, (req, res, next) => { 72 | Dishes.findByIdAndRemove(req.params.dishId).then((result) => { 73 | res.statusCode = 200; 74 | res.setHeader("Content-Type", "application/json"); 75 | res.json(result); 76 | }, (err) => next(err)).catch((err) => next(err)); 77 | }); 78 | 79 | dishRouter.route('/:dishId/comments') 80 | .get((req, res, next) => { 81 | Dishes.findById(req.params.dishId).populate('comments.author').then((dish) => { 82 | if (dish != null) { 83 | res.statusCode = 200; 84 | res.setHeader("Content-Type", "application/json"); 85 | res.json(dish.comments); 86 | } else { 87 | err = new Error('Dish ' + req.params.dishId + ' not found'); 88 | err.status = 404; 89 | return next(err); 90 | } 91 | }, (err) => next(err)).catch((err) => next(err)); 92 | }) 93 | 94 | .post(authenticate.verifyUser, (req, res, next) => { 95 | Dishes.findById(req.params.dishId).then((dish) => { 96 | if (dish != null) { 97 | req.body.author = req.user._id; 98 | dish.comments.push(req.body); 99 | dish.save().then((dish) => { 100 | res.statusCode = 200; 101 | res.setHeader("Content-Type", "application/json"); 102 | res.json(dish); 103 | }, (err) => next(err)).catch((err) => next(err)); 104 | } else { 105 | err = new Error('Dish ' + req.params.dishId + ' not found'); 106 | err.status = 404; 107 | return next(err); 108 | } 109 | }, (err) => next(err)).catch((err) => next(err)); 110 | }) 111 | 112 | .put(authenticate.verifyUser, (req, res, next) => { 113 | res.statusCode = 403; 114 | res.end('PUT operation is not supported on /dishes/' + req.params.dishId + '/comments'); 115 | }) 116 | 117 | .delete(authenticate.verifyUser, authenticate.verifyAdmin, (req, res, next) => { 118 | Dishes.findById(req.params.dishId).then((dish) => { 119 | if (dish != null) { 120 | console.log(dish); 121 | for (var i = (dish.comments.length - 1); i >= 0; i--) { 122 | dish.comments.id(dish.comments[i]._id).remove(); 123 | } 124 | dish.save().then((dish) => { 125 | res.statusCode = 200; 126 | res.setHeader("Content-Type", "application/json"); 127 | res.json(dish); 128 | }, (err) => next(err)).catch((err) => next(err)); 129 | } else { 130 | err = new Error('Dish ' + req.params.dishId + ' not found'); 131 | err.status = 404; 132 | return next(err); 133 | } 134 | }, (err) => next(err)).catch((err) => next(err)); 135 | }) 136 | 137 | dishRouter.route('/:dishId/comments/:commentId') 138 | .get((req, res, next) => { 139 | Dishes.findById(req.params.dishId).populate('comments.author').then((dish) => { 140 | if (dish != null && dish.comments.id(req.params.commentId)) { 141 | res.statusCode = 200; 142 | res.setHeader("Content-Type", "application/json"); 143 | res.json(dish.comments.id(req.params.commentId)); 144 | } else if (dish == null) { 145 | err = new Error('Dish ' + req.params.dishId + ' not found'); 146 | err.status = 404; 147 | return next(err); 148 | } else { 149 | err = new Error('Comment ' + req.params.commentId + ' not found'); 150 | err.status = 404; 151 | return next(err); 152 | } 153 | }, (err) => next(err)).catch((err) => next(err)); 154 | }) 155 | 156 | .post(authenticate.verifyUser, (req, res, next) => { 157 | res.statusCode = 403; 158 | res.end('POST operation is not supported on /dishes/' + req.params.dishId + '/comments/' + req.params.commentId); 159 | }) 160 | 161 | .put(authenticate.verifyUser, (req, res, next) => { 162 | Dishes.findById(req.params.dishId).then((dish) => { 163 | if (dish != null && dish.comments.id(req.params.commentId)) { 164 | if (dish.comments.id(req.params.commentId).author.toString() != req.user._id.toString()) { 165 | err = new Error('You are not authorized to edit this comment'); 166 | err.status = 403; 167 | return next(err); 168 | } 169 | if (req.body.rating) { 170 | dish.comments.id(req.params.commentId).rating = req.body.rating; 171 | } 172 | 173 | if (req.body.comment) { 174 | dish.comments.id(req.params.commentId).comment = req.body.comment; 175 | } 176 | dish.save().then((dish) => { 177 | res.statusCode = 200; 178 | res.setHeader("Content-Type", "application/json"); 179 | res.json(dish); 180 | }, (err) => next(err)).catch((err) => next(err)); 181 | } else if (dish == null) { 182 | err = new Error('Dish ' + req.params.dishId + ' not found'); 183 | err.status = 404; 184 | return next(err); 185 | } else { 186 | err = new Error('Comment ' + req.params.commentId + ' not found'); 187 | err.status = 404; 188 | return next(err); 189 | } 190 | }, (err) => next(err)).catch((err) => next(err)); 191 | }) 192 | 193 | .delete(authenticate.verifyUser, (req, res, next) => { 194 | Dishes.findById(req.params.dishId).then((dish) => { 195 | if (dish != null && dish.comments.id(req.params.commentId)) { 196 | if (dish.comments.id(req.params.commentId).author.toString() != req.user._id.toString()) { 197 | err = new Error('You are not authorized to edit this comment'); 198 | err.status = 403; 199 | return next(err); 200 | } 201 | dish.comments.id(req.params.commentId).remove(); 202 | dish.save().then((dish) => { 203 | res.statusCode = 200; 204 | res.setHeader("Content-Type", "application/json"); 205 | res.json(dish); 206 | }, (err) => next(err)).catch((err) => next(err)); 207 | } else if (dish == null) { 208 | err = new Error('Dish ' + req.params.dishId + ' not found'); 209 | err.status = 404; 210 | return next(err); 211 | } else { 212 | err = new Error('Comment ' + req.params.commentId + ' not found'); 213 | err.status = 404; 214 | return next(err); 215 | } 216 | }, (err) => next(err)).catch((err) => next(err)); 217 | }); 218 | 219 | module.exports = dishRouter; --------------------------------------------------------------------------------