-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
40 changed files
with
7,095 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
node_modules |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
var createError = require('http-errors'); | ||
var express = require('express'); | ||
var path = require('path'); | ||
var cookieParser = require('cookie-parser'); | ||
var logger = require('morgan'); | ||
|
||
var indexRouter = require('./routes/index'); | ||
var usersRouter = require('./routes/users'); | ||
var catalogRouter = require('./routes/catalog'); //Import routes for "catalog" area of site | ||
var wiki = require('./routes/wiki'); | ||
var compression = require('compression'); | ||
var helmet = require('helmet'); | ||
|
||
var app = express(); | ||
|
||
app.use(helmet()); | ||
|
||
//Set up mongoose connection | ||
var mongoose = require('mongoose'); | ||
var mongoDB = 'mongodb+srv://hugo:[email protected]/local_library?retryWrites=true&w=majority'; | ||
mongoose.connect(mongoDB, { useNewUrlParser: true }); | ||
var db = mongoose.connection; | ||
db.on('error', console.error.bind(console, 'MongoDB connection error:')); | ||
|
||
// view engine setup | ||
app.set('views', path.join(__dirname, 'views')); | ||
app.set('view engine', 'pug'); | ||
|
||
app.use(logger('dev')); | ||
app.use(express.json()); | ||
app.use(express.urlencoded({ extended: false })); | ||
app.use(cookieParser()); | ||
|
||
app.use(compression()); //Compress all routes | ||
|
||
app.use(express.static(path.join(__dirname, 'public'))); | ||
|
||
app.use('/', indexRouter); | ||
app.use('/users', usersRouter); | ||
app.use('/catalog', catalogRouter); | ||
app.use('/wiki', wiki); | ||
|
||
// catch 404 and forward to error handler | ||
app.use((req, res, next) => { | ||
next(createError(404)); | ||
}); | ||
|
||
// error handler | ||
app.use((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; | ||
|
||
/* mongoDB username and password: | ||
--- | ||
username: hugo | ||
password: hugo | ||
Connection string: | ||
mongodb+srv://hugo:<password>@cluster0-kmdtl.mongodb.net/test?retryWrites=true&w=majority | ||
UPDATED STRING: | ||
mongodb+srv://hugo:[email protected]/local_library?retryWrites=true&w=majority | ||
Replace <password> with the password for the hugo user. | ||
Full Driver Example: | ||
const MongoClient = require('mongodb').MongoClient; | ||
const uri = "mongodb+srv://hugo:<password>@cluster0-kmdtl.mongodb.net/test?retryWrites=true&w=majority"; | ||
const client = new MongoClient(uri, { useNewUrlParser: true }); | ||
client.connect(err => { | ||
const collection = client.db("test").collection("devices"); | ||
// perform actions on the collection object | ||
client.close(); | ||
}); | ||
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
#!/usr/bin/env node | ||
|
||
/** | ||
* Module dependencies. | ||
*/ | ||
|
||
var app = require('../app'); | ||
var debug = require('debug')('local-library: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); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
|
||
var Author = require('../models/author'); | ||
var async = require('async'); | ||
var Book = require('../models/book'); | ||
const { body,validationResult } = require('express-validator/check'); | ||
const { sanitizeBody } = require('express-validator/filter'); | ||
|
||
// Display list of all Authors. | ||
exports.author_list = function(req, res, next) { | ||
|
||
Author.find() | ||
.populate('author') | ||
.sort([['family_name', 'ascending']]) | ||
.exec(function (err, list_authors) { | ||
if (err) { return next(err); } | ||
//Successful, so render | ||
res.render('author_list', { title: 'Author List', author_list: list_authors }); | ||
}); | ||
|
||
}; | ||
|
||
// Display detail page for a specific Author. | ||
exports.author_detail = function(req, res, next) { | ||
|
||
async.parallel({ | ||
author: function(callback) { | ||
Author.findById(req.params.id) | ||
.exec(callback) | ||
}, | ||
authors_books: function(callback) { | ||
Book.find({ 'author': req.params.id },'title summary') | ||
.exec(callback) | ||
}, | ||
}, function(err, results) { | ||
if (err) { return next(err); } // Error in API usage. | ||
if (results.author==null) { // No results. | ||
var err = new Error('Author not found'); | ||
err.status = 404; | ||
return next(err); | ||
} | ||
// Successful, so render. | ||
res.render('author_detail', { title: 'Author Detail', author: results.author, author_books: results.authors_books } ); | ||
}); | ||
|
||
}; | ||
|
||
// Display Author create form on GET. | ||
exports.author_create_get = function(req, res, next) { | ||
res.render('author_form', { title: 'Create Author'}); | ||
}; | ||
|
||
// Handle Author create on POST. | ||
exports.author_create_post = [ | ||
|
||
// Validate fields. | ||
body('first_name').isLength({ min: 1 }).trim().withMessage('First name must be specified.') | ||
.isAlphanumeric().withMessage('First name has non-alphanumeric characters.'), | ||
body('family_name').isLength({ min: 1 }).trim().withMessage('Family name must be specified.') | ||
.isAlphanumeric().withMessage('Family name has non-alphanumeric characters.'), | ||
body('date_of_birth', 'Invalid date of birth').optional({ checkFalsy: true }).isISO8601(), | ||
body('date_of_death', 'Invalid date of death').optional({ checkFalsy: true }).isISO8601(), | ||
|
||
// Sanitize fields. | ||
sanitizeBody('first_name').escape(), | ||
sanitizeBody('family_name').escape(), | ||
sanitizeBody('date_of_birth').toDate(), | ||
sanitizeBody('date_of_death').toDate(), | ||
|
||
// Process request after validation and sanitization. | ||
(req, res, next) => { | ||
|
||
// Extract the validation errors from a request. | ||
const errors = validationResult(req); | ||
|
||
if (!errors.isEmpty()) { | ||
// There are errors. Render form again with sanitized values/errors messages. | ||
res.render('author_form', { title: 'Create Author', author: req.body, errors: errors.array() }); | ||
return; | ||
} | ||
else { | ||
// Data from form is valid. | ||
|
||
// Create an Author object with escaped and trimmed data. | ||
var author = new Author( | ||
{ | ||
first_name: req.body.first_name, | ||
family_name: req.body.family_name, | ||
date_of_birth: req.body.date_of_birth, | ||
date_of_death: req.body.date_of_death | ||
}); | ||
author.save(function (err) { | ||
if (err) { return next(err); } | ||
// Successful - redirect to new author record. | ||
res.redirect(author.url); | ||
}); | ||
} | ||
} | ||
]; | ||
|
||
// Display Author delete form on GET. | ||
exports.author_delete_get = function(req, res, next) { | ||
|
||
async.parallel({ | ||
author: function(callback) { | ||
Author.findById(req.params.id).exec(callback) | ||
}, | ||
authors_books: function(callback) { | ||
Book.find({ 'author': req.params.id }).exec(callback) | ||
}, | ||
}, function(err, results) { | ||
if (err) { return next(err); } | ||
if (results.author==null) { // No results. | ||
res.redirect('/catalog/authors'); | ||
} | ||
// Successful, so render. | ||
res.render('author_delete', { title: 'Delete Author', author: results.author, author_books: results.authors_books } ); | ||
}); | ||
|
||
}; | ||
|
||
// Handle Author delete on POST. | ||
exports.author_delete_post = function(req, res, next) { | ||
|
||
async.parallel({ | ||
author: function(callback) { | ||
Author.findById(req.body.authorid).exec(callback) | ||
}, | ||
authors_books: function(callback) { | ||
Book.find({ 'author': req.body.authorid }).exec(callback) | ||
}, | ||
}, function(err, results) { | ||
if (err) { return next(err); } | ||
// Success | ||
if (results.authors_books.length > 0) { | ||
// Author has books. Render in same way as for GET route. | ||
res.render('author_delete', { title: 'Delete Author', author: results.author, author_books: results.authors_books } ); | ||
return; | ||
} | ||
else { | ||
// Author has no books. Delete object and redirect to the list of authors. | ||
Author.findByIdAndRemove(req.body.authorid, function deleteAuthor(err) { | ||
if (err) { return next(err); } | ||
// Success - go to author list | ||
res.redirect('/catalog/authors') | ||
}) | ||
} | ||
}); | ||
}; | ||
|
||
// Display Author update form on GET. | ||
exports.author_update_get = function(req, res) { | ||
res.send('NOT IMPLEMENTED: Author update GET'); | ||
}; | ||
|
||
// Handle Author update on POST. | ||
exports.author_update_post = function(req, res) { | ||
res.send('NOT IMPLEMENTED: Author update POST'); | ||
} |
Oops, something went wrong.