Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pids
lib-cov

# Coverage directory used by tools like istanbul
coverage
coverage/

# nyc test coverage
.nyc_output
Expand Down Expand Up @@ -59,3 +59,9 @@ typings/

# next.js build output
.next

#log files
.log

#VS Code files
.vscode
3 changes: 2 additions & 1 deletion config/default.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"name": "Vidly - Movie Rental App",
"jwtPrivateKey": ""
"jwtPrivateKey": "",
"db":"mongodb://localhost/vidly"
}
5 changes: 5 additions & 0 deletions config/test.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "Vidly - Movie Rental App",
"jwtPrivateKey": "1234",
"db":"mongodb://localhost/vidly_tests"
}
63 changes: 14 additions & 49 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,54 +1,19 @@
//TODO Start the app using this
const express = require('express');
const app = express();

const genres = require('./routes/genres');
const customers = require('./routes/customers');
const movies = require('./routes/movies');
const rentals = require('./routes/rentals');
const users = require('./routes/users');
const login = require('./routes/login');

//Read the config files to get jwt-private-key
const config = require('config');
if(!config.get('jwtPrivateKey')){
console.error('Fatal Error: jwtPrivateKey is not defined.');
process.exit(1);//0 means success. anything other than 0 means error
}

//To validate object ids
const Joi = require('joi');
Joi.objectId = require('joi-objectid')(Joi);

//Connect to mongo db
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/vidly')
.then(() => console.log('Connected to vidly db...'))
.catch(err => console.error('Could not connect to vidly db'));

//Enable JSON
app.use(express.json());
//app.use(express.urlencoded({extended = true}));
app.use(express.static('public'));


//Read config files
const conf = require('./config/config');
conf(app);

//Use genre api's
app.use('/api/genres', genres);
//Use customer api's
app.use('/api/customers', customers);
//Use movie api's
app.use('/api/movies', movies);
//Use rental api's
app.use('/api/rentals', rentals);
//Use user api's
app.use('/api/users', users);
//Use auth api's
app.use('/api/login', login);

const winston = require('winston');

//Setup logging
require('./startup/logging')();
//setup routes
require('./startup/routes')(app);
//Setup db
require('./startup/db')();
//Setup configurations
require('./startup/config')(app);
//Setup validations
require('./startup/validation')(app);

const port = process.env.PORT || 3000;
app.listen(port, () => console.log(`Listening port ${port}`));
const server = app.listen(port, () => winston.info(`Listening port ${port}`));
module.exports = server;
10 changes: 10 additions & 0 deletions middleware/admin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
function checkRole(req, res, next){
//Checks for admin role
console.log(req.user);
if(!req.user.isAdmin){
return res.status(403).send('Access denied.');
}
next();
}

module.exports = checkRole;
10 changes: 10 additions & 0 deletions middleware/async.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module.exports = function (handler) {
return async (req, res, next) => {
try {
await handler(req, res);
}
catch(ex) {
next(ex);
}
};
}
7 changes: 5 additions & 2 deletions middleware/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@ function authenticate(req, res, next){
//this method works as a middleware function so that any endpoint which uses this function will check for a valid token.
const token = req.header('x-auth-token');
if(!token){
return res.status(402).send('Access denied. No token provided');
return res.status(401).send('Access denied. No token provided');
}
try{
const decodedToken = jwt.decode(toASCII, config.get('jwtPrivateKey'));
const decodedToken = jwt.decode(token, process.env.jwtPrivateKey);
if(!decodedToken){
res.status(400).send('Invalid token');
}
req.user = decodedToken;
next();
}
Expand Down
14 changes: 14 additions & 0 deletions middleware/error.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const winston = require('winston');

module.exports = function(err, req, res, next){
winston.error(err.message, err);

// error
// warn
// info
// verbose
// debug
// silly

res.status(500).send('Something failed.');
}
9 changes: 9 additions & 0 deletions middleware/validateObjectId.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const mongoose = require('mongoose');
function validateObjectId(req, res, next){
if(!mongoose.Types.ObjectId.isValid(req.params.id)){
return res.status(404).send('Invalid genre id');
}
next();
}

module.exports = validateObjectId;
2 changes: 1 addition & 1 deletion models/genre.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const Genre = mongoose.model('Genre', genreSchema);
function validateGenre(genre){
//Input validation
const schema = { //this schema is used to validate the request body
name: Joi.string().min(3).required()
name: Joi.string().min(5).max(50).required()
};
return Joi.validate(genre, schema);

Expand Down
14 changes: 12 additions & 2 deletions models/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ const userScheme = new mongoose.Schema({
required: true,
minlength: 2,
maxlength: 1024//Password is saved after hashing. Therefore the length of the saved password will be longer than the actual password.
},
isAdmin: {
type: Boolean,
default: false
}
});

Expand All @@ -31,18 +35,24 @@ const userScheme = new mongoose.Schema({
*/
userScheme.methods.generateAuthToken = function(){
//This cannot be replaced by an arrow function as arrow functions does not support "this" keyword
const token = jwt.sign({_id:this._id}, config.get('jwtPrivateKey'));
let secretKey = process.env.jwtPrivateKey;
if(!secretKey){ //TODO: This is only for unit testing
secretKey = config.get('jwtPrivateKey');
}
const token = jwt.sign({_id:this._id, isAdmin: this.isAdmin}, secretKey);
return token;
}

const User = mongoose.model('User', userScheme);

function validateUser(user){
console.log(user);
//Input validation
const schema = { //this schema is used to validate the request body
name: Joi.string().min(2).max(50).required(),
email: Joi.string().email(),
password: Joi.string().min(2).max(255).required()
password: Joi.string().min(2).max(255).required(),
isAdmin: Joi.boolean()
};
return Joi.validate(user, schema);
}
Expand Down
Loading