├── .gitignore
├── .idea
├── Library-Management-System.iml
├── modules.xml
└── vcs.xml
├── README.md
├── config
└── default.js
├── index.js
├── lib
└── mongo.js
├── middlewares
└── check.js
├── models
├── borrowBooks.js
├── library.js
└── users.js
├── package-lock.json
├── package.json
├── public
├── css
│ ├── common.css
│ ├── semantic.min.css
│ └── themes
│ │ ├── basic
│ │ └── assets
│ │ │ └── fonts
│ │ │ ├── icons.eot
│ │ │ ├── icons.svg
│ │ │ ├── icons.ttf
│ │ │ └── icons.woff
│ │ └── default
│ │ └── assets
│ │ ├── fonts
│ │ ├── icons.eot
│ │ ├── icons.otf
│ │ ├── icons.svg
│ │ ├── icons.ttf
│ │ ├── icons.woff
│ │ └── icons.woff2
│ │ └── images
│ │ └── flags.png
├── img
│ ├── upload_3424d6994a994d4340ab043b0717d6a4.jpg
│ ├── upload_4c1fdd5646bd120237aaa5ffe7ddd40d.jpg
│ ├── upload_60d2f41215d11b1d20d57bb3dc65c131.jpeg
│ ├── upload_637c32ec1ab0534d2fb4f090a504c556.jpg
│ └── upload_71930cd725a347a06009b3061468f7aa.jpeg
└── js
│ ├── jquery-3.2.1.min.js
│ └── semantic.min.js
├── routes
├── borrow.js
├── home.js
├── index.js
├── library.js
├── post.js
├── profile.js
├── quick_borrow.js
├── search.js
├── signin.js
├── signout.js
├── signup.js
└── users.js
└── views
├── 404.ejs
├── book.ejs
├── borrow.ejs
├── error.ejs
├── home.ejs
├── layout
├── footer.ejs
├── header.ejs
├── nav-setting.ejs
├── nav.ejs
└── notification.ejs
├── library.ejs
├── profile.ejs
├── quick_borrow.ejs
├── signin.ejs
├── signup.ejs
└── users.ejs
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 | *.pid.lock
13 |
14 | # Directory for instrumented libs generated by jscoverage/JSCover
15 | lib-cov
16 |
17 | # Coverage directory used by tools like istanbul
18 | coverage
19 |
20 | # nyc test coverage
21 | .nyc_output
22 |
23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
24 | .grunt
25 |
26 | # Bower dependency directory (https://bower.io/)
27 | bower_components
28 |
29 | # node-waf configuration
30 | .lock-wscript
31 |
32 | # Compiled binary addons (http://nodejs.org/api/addons.html)
33 | build/Release
34 |
35 | # Dependency directories
36 | node_modules/
37 | jspm_packages/
38 |
39 | # Typescript v1 declaration files
40 | typings/
41 |
42 | # Optional npm cache directory
43 | .npm
44 |
45 | # Optional eslint cache
46 | .eslintcache
47 |
48 | # Optional REPL history
49 | .node_repl_history
50 |
51 | # Output of 'npm pack'
52 | *.tgz
53 |
54 | # Yarn Integrity file
55 | .yarn-integrity
56 |
57 | # dotenv environment variables file
58 | .env
59 |
60 |
--------------------------------------------------------------------------------
/.idea/Library-Management-System.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Online Library System
2 |
3 | ### Implemented following major functionalities:
4 | - User signup: Register a new user to the system.
5 | - Check the new username or email address if it’s already registered to the system.
6 | - Form validation: Check if all mandatory fields are filled out.
7 | - Check if password is strong enough. Define the rules of having a strong password. User passwords will be hashed and hashed version of passwords will be stored in the database.
8 | - User login
9 | - List available books in the system. User can filter the results based on at least one criterion (i.e. Book's name). Also, can “Search” for a specific item.
10 | - Implemented Favorites function.
11 | - For Admin user(s):
12 | - List all items
13 | - Add new item
14 | - Delete item
15 | - Update item
16 | - For delete, soft-delete should be implemented.
17 |
18 | ### Frond-end Design
19 | HTML5, CSS, Bootstrap.
20 |
21 | ### Back-end Design
22 | Node.JS, MongoDB.
23 |
24 | ### How to run the project
25 | - Install mongo, node js, npm.
26 | - Use npm to install all node_modules showed in json file.
27 | - In terminal, run `mongod` to start mongo.
28 | - In GUI, create a new db connnection, default port is 27017 or access mongodb in terminal, open another window, run `mongo`.
29 | - Run `node index` under project folder, go to your browser, http://localhost:port/.
30 |
--------------------------------------------------------------------------------
/config/default.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | port: 3000,
3 | session: {
4 | secret: 'libraryManagemengtSys',
5 | key: 'librarySys',
6 | maxAge: 2592000000
7 | },
8 | mongodb: 'mongodb://localhost:27017/library_system'
9 | }
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 | var express = require('express');
3 | var session = require('express-session');
4 | var MongoStore = require('connect-mongo')(session);
5 | var flash = require('connect-flash');
6 | var config = require('config-lite')(__dirname);
7 | var routes = require('./routes');
8 | var pkg = require('./package');
9 | var winston = require('winston');
10 | var expressWinston = require('express-winston');
11 |
12 | var app = express();
13 |
14 |
15 | app.set('views', path.join(__dirname, 'views'));
16 | app.set('view engine', 'ejs');
17 |
18 | app.use(express.static(path.join(__dirname, 'public')));
19 |
20 | app.use(session({
21 | name: config.session.key,
22 | secret: config.session.secret,
23 | resave: true,
24 | saveUninitialized: false,
25 | cookie: {
26 | maxAge: config.session.maxAge
27 | },
28 | store: new MongoStore({
29 | url: config.mongodb
30 | })
31 | }));
32 | app.use(flash());
33 | app.use(require('express-formidable')({
34 | uploadDir: path.join(__dirname, 'public/img'),
35 | keepExtensions: true
36 | }));
37 |
38 | app.locals.blog = {
39 | title: 'Welcome to Sierra!'
40 | };
41 |
42 | app.use(function (req, res, next) {
43 | res.locals.user = req.session.user;
44 | res.locals.success = req.flash('success').toString();
45 | res.locals.error = req.flash('error').toString();
46 | next();
47 | });
48 |
49 | app.use(expressWinston.logger({
50 | transports: [
51 | new (winston.transports.Console)({
52 | json: true,
53 | colorize: true
54 | }),
55 | new winston.transports.File({
56 | filename: 'logs/success.log'
57 | })
58 | ]
59 | }));
60 |
61 | routes(app);
62 |
63 | app.use(expressWinston.errorLogger({
64 | transports: [
65 | new winston.transports.Console({
66 | json: true,
67 | colorize: true
68 | }),
69 | new winston.transports.File({
70 | filename: 'logs/error.log'
71 | })
72 | ]
73 | }));
74 |
75 |
76 | app.use(function (err, req, res, next) {
77 | res.render('error', {
78 | error: err
79 | });
80 | });
81 | app.listen(config.port, function () {
82 | console.log(`${pkg.name} listening on port ${config.port}`);
83 | });
--------------------------------------------------------------------------------
/lib/mongo.js:
--------------------------------------------------------------------------------
1 | var config = require('config-lite')(__dirname);
2 | var Mongolass = require('mongolass');
3 | var moment = require('moment');
4 | var objectIdToTimestamp = require('objectid-to-timestamp');
5 |
6 | var mongolass = new Mongolass();
7 |
8 | mongolass.connect(config.mongodb);
9 |
10 | mongolass.plugin('addCreatedAt', {
11 | afterFind: function (results) {
12 | results.forEach(function (item) {
13 | item.created_at = moment(objectIdToTimestamp(item._id)).format('YYYY-MM-DD HH:mm');
14 | });
15 | return results;
16 | },
17 | afterFindOne: function (result) {
18 | if (result) {
19 | result.created_at = moment(objectIdToTimestamp(result._id)).format('YYYY-MM-DD HH:mm');
20 | }
21 | return result;
22 | }
23 | });
24 |
25 | exports.User = mongolass.model('User', {
26 | id: { type: 'string'},
27 | name: { type: 'string' },
28 | password: { type: 'string' },
29 | avatar: { type: 'string' },
30 | gender: { type: 'string', enum: ['m', 'f', 'x'] },
31 | bio: { type: 'string' },
32 | isAdmin: { type: 'boolean'}
33 | });
34 | exports.User.index({ id: 1 }, { unique: true }).exec();
35 |
36 | exports.Library = mongolass.model('Library', {
37 | admin: {
38 | type: Mongolass.Types.ObjectId
39 | },
40 | name: {
41 | type: 'string'
42 | },
43 | location: {
44 | type: 'string'
45 | },
46 | author: {
47 | type: 'string'
48 | },
49 | press: {
50 | type: 'string'
51 | },
52 | inventory: {
53 | type: 'number'
54 | },
55 | date: {
56 | type: 'string'
57 | },
58 | score: {
59 | type: 'number'
60 | },
61 | cover: {
62 | type: 'string'
63 | },
64 | introduction: {
65 | type: 'string'
66 | },
67 | pv: {
68 | type: 'number'
69 | },
70 | show: {
71 | type: 'boolean'
72 | }
73 | });
74 | exports.Library.index({
75 | admin: 1,
76 | _id: -1
77 | }).exec();
78 |
79 | exports.BorrowBook = mongolass.model('BorrowBook', {
80 | userId: {
81 | type: Mongolass.Types.ObjectId,
82 | },
83 | bookId: {
84 | type: Mongolass.Types.ObjectId
85 | },
86 | bool: {
87 | type: 'boolean'
88 | },
89 | return_time: {
90 | type: 'string'
91 | }
92 | });
93 |
94 | exports.Favorite = mongolass.model('Favorite', {
95 | userId: {
96 | type: Mongolass.Types.ObjectId,
97 | },
98 | bookId: {
99 | type: Mongolass.Types.ObjectId
100 | },
101 | favorite: {
102 | type: 'boolean'
103 | }
104 | })
105 |
106 | exports.BorrowBook.index({
107 | userId: 1,
108 | _id: 1
109 | }).exec();
110 |
--------------------------------------------------------------------------------
/middlewares/check.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | checkLogin: function checkLogin(req, res, next) {
3 | if (!req.session.user) {
4 | req.flash('error', 'Not logged in');
5 | return res.redirect('/signin');
6 | }
7 | next();
8 | },
9 |
10 | checkNotLogin: function checkNotLogin(req, res, next) {
11 | if (req.session.user) {
12 | req.flash('error', 'Has logged');
13 | return res.redirect('back');
14 | }
15 | next();
16 | },
17 |
18 | checkIsAdmin: function checkIsAdmin(req, res, next) {
19 | if (!req.session.user) {
20 | req.flash('error', 'Not logged in');
21 | return res.redirect('/signin');
22 | } else {
23 | if (!req.session.user.isAdmin) {
24 | req.flash('error', 'No Access');
25 | return res.redirect('back');
26 | }
27 | }
28 | next();
29 | }
30 | };
--------------------------------------------------------------------------------
/models/borrowBooks.js:
--------------------------------------------------------------------------------
1 | var BorrowBooks = require('../lib/mongo').BorrowBook;
2 | var moment = require('moment');
3 | var objectIdToTimestamp = require('objectid-to-timestamp');
4 | module.exports = {
5 | create: function(borrowbook) {
6 | return BorrowBooks.create(borrowbook).exec();
7 | },
8 | getBorrowBooks: function(userId) {
9 | return BorrowBooks
10 | .find({ userId: userId })
11 | .populate({ path: 'admin', model: 'User' })
12 | .sort({ _id: -1 })
13 | .addCreatedAt()
14 | .exec();
15 | },
16 | getBorrowBooksCount: function(bookId) {
17 | return BorrowBooks
18 | .count({ bookId: bookId, bool: false})
19 | .exec();
20 | },
21 | returnBookById: function (id) {
22 | return BorrowBooks.remove({ _id: id }).exec();
23 | },
24 | getBorrowUsers: function(bookId) {
25 | return BorrowBooks
26 | .find({ bookId: bookId})
27 | .sort({ _id: 1 })
28 | .addCreatedAt()
29 | .exec();
30 | },
31 | returnBookByBookId: function(bookId, userId) {
32 | return BorrowBooks.update({ bookId: bookId, userId: userId, bool: false, return_time: null}, { $set: { bool: true, return_time: moment().format('YYYY-MM-DD HH:mm')}}).exec();
33 | }
34 | }
--------------------------------------------------------------------------------
/models/library.js:
--------------------------------------------------------------------------------
1 | var Library = require('../lib/mongo').Library;
2 | var async = require('asyncawait/async');
3 | var await = require('asyncawait/await');
4 |
5 | module.exports = {
6 | create: function create(book) {
7 | return Library.create(book).exec();
8 | },
9 | getBookById: function (bookId) {
10 | return Library
11 | .findOne({ _id: bookId })
12 | .populate({ path: 'admin', model: 'User' })
13 | .addCreatedAt()
14 | .exec();
15 | },
16 | getBooks: function(admin) {
17 | var query = {};
18 | if (admin) {
19 | query.admin = "5a246f7a4015d2070b89df75";
20 | }
21 | return Library
22 | .find(query)
23 | .populate({ path: 'admin', model: 'User' })
24 | .sort({"inventory" : -1})
25 | .addCreatedAt()
26 | .exec();
27 | },
28 | searchBook: function(data) {
29 | var queryData = new RegExp(data.trim());
30 | return Library
31 | .find({
32 | '$or': [{
33 | name: queryData
34 | }, {
35 | author: queryData
36 | }, {
37 | press: queryData
38 | }]
39 | })
40 | .sort({ _id: -1 })
41 | .exec();
42 | },
43 | checkBook: function(bookName) {
44 | return Library
45 | .find({ name: bookName })
46 | .exec();
47 | },
48 | getRawBookById: function (bookId) {
49 | return Library
50 | .findOne({ _id: bookId })
51 | .populate({ path: 'admin', model: 'User' })
52 | .exec();
53 | },
54 | updateBookById: function (bookId, admin, data) {
55 | return Library.update({ admin: admin, _id: bookId }, { $set: data }).exec();
56 | },
57 | delBookById: function (bookId, admin) {
58 | return Library.update({ admin: admin, _id: bookId }, { $set: {show : false}}).exec();
59 | },
60 | incPv: function incPv(bookId) {
61 | return Library
62 | .update({ _id: bookId }, { $inc: { pv: 1 } })
63 | .exec();
64 | }
65 | };
--------------------------------------------------------------------------------
/models/users.js:
--------------------------------------------------------------------------------
1 | var User = require('../lib/mongo').User;
2 |
3 | module.exports = {
4 | create: function (user) {
5 | return User.create(user).exec();
6 | },
7 | getUserById: function (id) {
8 | return User
9 | .findOne({ id: id })
10 | .addCreatedAt()
11 | .exec();
12 | },
13 | getUserByDefaultId: function(id) {
14 | return User
15 | .findOne({ _id: id})
16 | .addCreatedAt()
17 | .exec();
18 | }
19 | };
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "library_system",
3 | "version": "1.0.0",
4 | "lockfileVersion": 1,
5 | "requires": true,
6 | "dependencies": {
7 | "accepts": {
8 | "version": "1.3.7",
9 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
10 | "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
11 | "requires": {
12 | "mime-types": "~2.1.24",
13 | "negotiator": "0.6.2"
14 | }
15 | },
16 | "another-json-schema": {
17 | "version": "2.1.1",
18 | "resolved": "https://registry.npmjs.org/another-json-schema/-/another-json-schema-2.1.1.tgz",
19 | "integrity": "sha512-9yaRsy+XUnBC+KzfpwPVeQgCXJjrTzwffZSvMzabRCbV91gqM8I4+JTL68ig5tkgi26eo6s8Fg+k2tMkdTcBGQ==",
20 | "requires": {
21 | "is-buffer": "^1.1.2"
22 | }
23 | },
24 | "ansi-styles": {
25 | "version": "3.2.1",
26 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
27 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
28 | "requires": {
29 | "color-convert": "^1.9.0"
30 | }
31 | },
32 | "argparse": {
33 | "version": "1.0.10",
34 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
35 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
36 | "requires": {
37 | "sprintf-js": "~1.0.2"
38 | }
39 | },
40 | "array-flatten": {
41 | "version": "1.1.1",
42 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
43 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
44 | },
45 | "async": {
46 | "version": "1.0.0",
47 | "resolved": "https://registry.npmjs.org/async/-/async-1.0.0.tgz",
48 | "integrity": "sha1-+PwEyjoTeErenhZBr5hXjPvWR6k="
49 | },
50 | "asyncawait": {
51 | "version": "1.0.8",
52 | "resolved": "https://registry.npmjs.org/asyncawait/-/asyncawait-1.0.8.tgz",
53 | "integrity": "sha512-yssMQjNRaFYJbJPXnZQ/G4o5uqBj6Ol7HqjEzjyO7306RHnqLGoenKaVbqUgqhk1QBXZSJ3yf2xhQCWcZjWt6w==",
54 | "requires": {
55 | "bluebird": "^3.1.1",
56 | "fibers": "^2.0.2",
57 | "lodash": "^4.17.11"
58 | }
59 | },
60 | "bluebird": {
61 | "version": "3.7.1",
62 | "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.1.tgz",
63 | "integrity": "sha512-DdmyoGCleJnkbp3nkbxTLJ18rjDsE4yCggEwKNXkeV123sPNfOCYeDoeuOY+F2FrSjO1YXcTU+dsy96KMy+gcg=="
64 | },
65 | "bson": {
66 | "version": "1.0.9",
67 | "resolved": "https://registry.npmjs.org/bson/-/bson-1.0.9.tgz",
68 | "integrity": "sha512-IQX9/h7WdMBIW/q/++tGd+emQr0XMdeZ6icnT/74Xk9fnabWn+gZgpE+9V+gujL3hhJOoNrnDVY7tWdzc7NUTg=="
69 | },
70 | "buffer-shims": {
71 | "version": "1.0.0",
72 | "resolved": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz",
73 | "integrity": "sha1-mXjOMXOIxkmth5MCjDR37wRKi1E="
74 | },
75 | "chalk": {
76 | "version": "2.1.0",
77 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz",
78 | "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==",
79 | "requires": {
80 | "ansi-styles": "^3.1.0",
81 | "escape-string-regexp": "^1.0.5",
82 | "supports-color": "^4.0.0"
83 | }
84 | },
85 | "charenc": {
86 | "version": "0.0.2",
87 | "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz",
88 | "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc="
89 | },
90 | "co": {
91 | "version": "4.6.0",
92 | "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
93 | "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ="
94 | },
95 | "color-convert": {
96 | "version": "1.9.3",
97 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
98 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
99 | "requires": {
100 | "color-name": "1.1.3"
101 | }
102 | },
103 | "color-name": {
104 | "version": "1.1.3",
105 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
106 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
107 | },
108 | "colors": {
109 | "version": "1.0.3",
110 | "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz",
111 | "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs="
112 | },
113 | "config-lite": {
114 | "version": "2.1.0",
115 | "resolved": "https://registry.npmjs.org/config-lite/-/config-lite-2.1.0.tgz",
116 | "integrity": "sha512-eYPW4i7lDKYTo3CSutjL/v08pFZqyyhR6Ql4/X5auZqWQ+tZlWE3INSv+InzxTl6csasyQHQGudqq86kWS/JKA==",
117 | "requires": {
118 | "chalk": "2.1.0",
119 | "js-yaml": "3.9.1",
120 | "lodash": "4.17.4",
121 | "optimist": "0.6.1",
122 | "resolve": "1.4.0",
123 | "toml": "2.3.2"
124 | },
125 | "dependencies": {
126 | "lodash": {
127 | "version": "4.17.4",
128 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz",
129 | "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4="
130 | }
131 | }
132 | },
133 | "connect-flash": {
134 | "version": "0.1.1",
135 | "resolved": "https://registry.npmjs.org/connect-flash/-/connect-flash-0.1.1.tgz",
136 | "integrity": "sha1-2GMPJtlaf4UfmVax6MxnMvO2qjA="
137 | },
138 | "connect-mongo": {
139 | "version": "2.0.0",
140 | "resolved": "https://registry.npmjs.org/connect-mongo/-/connect-mongo-2.0.0.tgz",
141 | "integrity": "sha512-2Nj5d4XO55AXSy1GOXDZteSEEUObGm/kvJaXyEQCa8cCHsCiZH+V/+sjk3b+khc4V8oyVi34rCtUxor4TfETLA==",
142 | "requires": {
143 | "mongodb": "^2.0.36"
144 | }
145 | },
146 | "content-disposition": {
147 | "version": "0.5.1",
148 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.1.tgz",
149 | "integrity": "sha1-h0dsamfI2qh+Muh2Ft+IO6f7Bxs="
150 | },
151 | "content-type": {
152 | "version": "1.0.4",
153 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
154 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
155 | },
156 | "cookie": {
157 | "version": "0.3.1",
158 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
159 | "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s="
160 | },
161 | "cookie-signature": {
162 | "version": "1.0.6",
163 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
164 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
165 | },
166 | "core-util-is": {
167 | "version": "1.0.2",
168 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
169 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
170 | },
171 | "crc": {
172 | "version": "3.4.4",
173 | "resolved": "https://registry.npmjs.org/crc/-/crc-3.4.4.tgz",
174 | "integrity": "sha1-naHpgOO9RPxck79as9ozeNheRms="
175 | },
176 | "crypt": {
177 | "version": "0.0.2",
178 | "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz",
179 | "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs="
180 | },
181 | "cycle": {
182 | "version": "1.0.3",
183 | "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz",
184 | "integrity": "sha1-IegLK+hYD5i0aPN5QwZisEbDStI="
185 | },
186 | "debug": {
187 | "version": "2.2.0",
188 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
189 | "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=",
190 | "requires": {
191 | "ms": "0.7.1"
192 | }
193 | },
194 | "depd": {
195 | "version": "1.1.2",
196 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
197 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
198 | },
199 | "destroy": {
200 | "version": "1.0.4",
201 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
202 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
203 | },
204 | "ee-first": {
205 | "version": "1.1.1",
206 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
207 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
208 | },
209 | "ejs": {
210 | "version": "2.5.7",
211 | "resolved": "http://r.cnpmjs.org/ejs/download/ejs-2.5.7.tgz",
212 | "integrity": "sha1-zIcsFoiArjxxiXYv1f/ACJbJUYo="
213 | },
214 | "encodeurl": {
215 | "version": "1.0.2",
216 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
217 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
218 | },
219 | "es6-promise": {
220 | "version": "3.2.1",
221 | "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.2.1.tgz",
222 | "integrity": "sha1-7FYjOGgDKQkgcXDDlEjiREndH8Q="
223 | },
224 | "escape-html": {
225 | "version": "1.0.3",
226 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
227 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
228 | },
229 | "escape-string-regexp": {
230 | "version": "1.0.5",
231 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
232 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
233 | },
234 | "esprima": {
235 | "version": "4.0.1",
236 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
237 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
238 | },
239 | "etag": {
240 | "version": "1.7.0",
241 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.7.0.tgz",
242 | "integrity": "sha1-A9MLX2fdbmMtKUXTDWZScxo01dg="
243 | },
244 | "express": {
245 | "version": "4.14.0",
246 | "resolved": "https://registry.npmjs.org/express/-/express-4.14.0.tgz",
247 | "integrity": "sha1-we4/Qs3Ikfs9xlCoki1R7IR9DWY=",
248 | "requires": {
249 | "accepts": "~1.3.3",
250 | "array-flatten": "1.1.1",
251 | "content-disposition": "0.5.1",
252 | "content-type": "~1.0.2",
253 | "cookie": "0.3.1",
254 | "cookie-signature": "1.0.6",
255 | "debug": "~2.2.0",
256 | "depd": "~1.1.0",
257 | "encodeurl": "~1.0.1",
258 | "escape-html": "~1.0.3",
259 | "etag": "~1.7.0",
260 | "finalhandler": "0.5.0",
261 | "fresh": "0.3.0",
262 | "merge-descriptors": "1.0.1",
263 | "methods": "~1.1.2",
264 | "on-finished": "~2.3.0",
265 | "parseurl": "~1.3.1",
266 | "path-to-regexp": "0.1.7",
267 | "proxy-addr": "~1.1.2",
268 | "qs": "6.2.0",
269 | "range-parser": "~1.2.0",
270 | "send": "0.14.1",
271 | "serve-static": "~1.11.1",
272 | "type-is": "~1.6.13",
273 | "utils-merge": "1.0.0",
274 | "vary": "~1.1.0"
275 | }
276 | },
277 | "express-formidable": {
278 | "version": "1.0.0",
279 | "resolved": "https://registry.npmjs.org/express-formidable/-/express-formidable-1.0.0.tgz",
280 | "integrity": "sha1-3JIvBFUTIyJFip7BowHYkbP/yo0=",
281 | "requires": {
282 | "formidable": "^1.0.17"
283 | }
284 | },
285 | "express-session": {
286 | "version": "1.15.6",
287 | "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.15.6.tgz",
288 | "integrity": "sha512-r0nrHTCYtAMrFwZ0kBzZEXa1vtPVrw0dKvGSrKP4dahwBQ1BJpF2/y1Pp4sCD/0kvxV4zZeclyvfmw0B4RMJQA==",
289 | "requires": {
290 | "cookie": "0.3.1",
291 | "cookie-signature": "1.0.6",
292 | "crc": "3.4.4",
293 | "debug": "2.6.9",
294 | "depd": "~1.1.1",
295 | "on-headers": "~1.0.1",
296 | "parseurl": "~1.3.2",
297 | "uid-safe": "~2.1.5",
298 | "utils-merge": "1.0.1"
299 | },
300 | "dependencies": {
301 | "debug": {
302 | "version": "2.6.9",
303 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
304 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
305 | "requires": {
306 | "ms": "2.0.0"
307 | }
308 | },
309 | "ms": {
310 | "version": "2.0.0",
311 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
312 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
313 | },
314 | "utils-merge": {
315 | "version": "1.0.1",
316 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
317 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
318 | }
319 | }
320 | },
321 | "express-winston": {
322 | "version": "2.4.0",
323 | "resolved": "https://registry.npmjs.org/express-winston/-/express-winston-2.4.0.tgz",
324 | "integrity": "sha1-J6ts2TBT4t/cNbzuoUoHfcfVLkk=",
325 | "requires": {
326 | "chalk": "~0.4.0",
327 | "lodash": "~4.11.1"
328 | },
329 | "dependencies": {
330 | "ansi-styles": {
331 | "version": "1.0.0",
332 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.0.0.tgz",
333 | "integrity": "sha1-yxAt8cVvUSPquLZ817mAJ6AnkXg="
334 | },
335 | "chalk": {
336 | "version": "0.4.0",
337 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.4.0.tgz",
338 | "integrity": "sha1-UZmj3c0MHv4jvAjBsCewYXbgxk8=",
339 | "requires": {
340 | "ansi-styles": "~1.0.0",
341 | "has-color": "~0.1.0",
342 | "strip-ansi": "~0.1.0"
343 | }
344 | },
345 | "lodash": {
346 | "version": "4.11.2",
347 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.11.2.tgz",
348 | "integrity": "sha1-1rQzixEKWOIdrlzrz9u/0rxM2zs="
349 | }
350 | }
351 | },
352 | "eyes": {
353 | "version": "0.1.8",
354 | "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz",
355 | "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A="
356 | },
357 | "fibers": {
358 | "version": "2.0.2",
359 | "resolved": "https://registry.npmjs.org/fibers/-/fibers-2.0.2.tgz",
360 | "integrity": "sha512-HfVRxhYG7C8Jl9FqtrlElMR2z/8YiLQVDKf67MLY25Ic+ILx3ecmklfT1v3u+7P5/4vEFjuxaAFXhr2/Afwk5g=="
361 | },
362 | "finalhandler": {
363 | "version": "0.5.0",
364 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-0.5.0.tgz",
365 | "integrity": "sha1-6VCKvs6bbbqHGmlCodeRG5GRGsc=",
366 | "requires": {
367 | "debug": "~2.2.0",
368 | "escape-html": "~1.0.3",
369 | "on-finished": "~2.3.0",
370 | "statuses": "~1.3.0",
371 | "unpipe": "~1.0.0"
372 | }
373 | },
374 | "formidable": {
375 | "version": "1.2.1",
376 | "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.1.tgz",
377 | "integrity": "sha512-Fs9VRguL0gqGHkXS5GQiMCr1VhZBxz0JnJs4JmMp/2jL18Fmbzvv7vOFRU+U8TBkHEE/CX1qDXzJplVULgsLeg=="
378 | },
379 | "forwarded": {
380 | "version": "0.1.2",
381 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
382 | "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ="
383 | },
384 | "fresh": {
385 | "version": "0.3.0",
386 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.3.0.tgz",
387 | "integrity": "sha1-ZR+DjiJCTnVm3hYdg1jKoZn4PU8="
388 | },
389 | "has-color": {
390 | "version": "0.1.7",
391 | "resolved": "https://registry.npmjs.org/has-color/-/has-color-0.1.7.tgz",
392 | "integrity": "sha1-ZxRKUmDDT8PMpnfQQdr1L+e3iy8="
393 | },
394 | "has-flag": {
395 | "version": "2.0.0",
396 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz",
397 | "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE="
398 | },
399 | "hash-set": {
400 | "version": "1.0.1",
401 | "resolved": "https://registry.npmjs.org/hash-set/-/hash-set-1.0.1.tgz",
402 | "integrity": "sha1-wLbTLTP95zEgQyCQiRKETELonMU="
403 | },
404 | "http-errors": {
405 | "version": "1.5.1",
406 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.5.1.tgz",
407 | "integrity": "sha1-eIwNLB3iyBuebowBhDtrl+uSB1A=",
408 | "requires": {
409 | "inherits": "2.0.3",
410 | "setprototypeof": "1.0.2",
411 | "statuses": ">= 1.3.1 < 2"
412 | },
413 | "dependencies": {
414 | "inherits": {
415 | "version": "2.0.3",
416 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
417 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
418 | }
419 | }
420 | },
421 | "inflected": {
422 | "version": "2.0.2",
423 | "resolved": "https://registry.npmjs.org/inflected/-/inflected-2.0.2.tgz",
424 | "integrity": "sha1-G8MaxCfKUyGyoWzFbW/yn80v+Aw="
425 | },
426 | "inherits": {
427 | "version": "2.0.4",
428 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
429 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
430 | },
431 | "ipaddr.js": {
432 | "version": "1.4.0",
433 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.4.0.tgz",
434 | "integrity": "sha1-KWrKh4qCGBbluF0KKFqZvP9FgvA="
435 | },
436 | "is-buffer": {
437 | "version": "1.1.6",
438 | "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
439 | "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
440 | },
441 | "isarray": {
442 | "version": "1.0.0",
443 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
444 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
445 | },
446 | "isstream": {
447 | "version": "0.1.2",
448 | "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
449 | "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
450 | },
451 | "js-yaml": {
452 | "version": "3.9.1",
453 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.9.1.tgz",
454 | "integrity": "sha512-CbcG379L1e+mWBnLvHWWeLs8GyV/EMw862uLI3c+GxVyDHWZcjZinwuBd3iW2pgxgIlksW/1vNJa4to+RvDOww==",
455 | "requires": {
456 | "argparse": "^1.0.7",
457 | "esprima": "^4.0.0"
458 | }
459 | },
460 | "lodash": {
461 | "version": "4.17.15",
462 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
463 | "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
464 | },
465 | "marked": {
466 | "version": "0.7.0",
467 | "resolved": "https://registry.npmjs.org/marked/-/marked-0.7.0.tgz",
468 | "integrity": "sha512-c+yYdCZJQrsRjTPhUx7VKkApw9bwDkNbHUKo1ovgcfDjb2kc8rLuRbIFyXL5WOEUwzSSKo3IXpph2K6DqB/KZg=="
469 | },
470 | "media-typer": {
471 | "version": "0.3.0",
472 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
473 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
474 | },
475 | "merge-descriptors": {
476 | "version": "1.0.1",
477 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
478 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
479 | },
480 | "methods": {
481 | "version": "1.1.2",
482 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
483 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
484 | },
485 | "mime": {
486 | "version": "1.3.4",
487 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz",
488 | "integrity": "sha1-EV+eO2s9rylZmDyzjxSaLUDrXVM="
489 | },
490 | "mime-db": {
491 | "version": "1.40.0",
492 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz",
493 | "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA=="
494 | },
495 | "mime-types": {
496 | "version": "2.1.24",
497 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz",
498 | "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==",
499 | "requires": {
500 | "mime-db": "1.40.0"
501 | }
502 | },
503 | "minimist": {
504 | "version": "0.0.10",
505 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
506 | "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8="
507 | },
508 | "moment": {
509 | "version": "2.18.1",
510 | "resolved": "https://registry.npmjs.org/moment/-/moment-2.18.1.tgz",
511 | "integrity": "sha1-w2GT3Tzhwu7SrbfIAtu8d6gbHA8="
512 | },
513 | "mongodb": {
514 | "version": "2.2.36",
515 | "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-2.2.36.tgz",
516 | "integrity": "sha512-P2SBLQ8Z0PVx71ngoXwo12+FiSfbNfGOClAao03/bant5DgLNkOPAck5IaJcEk4gKlQhDEURzfR3xuBG1/B+IA==",
517 | "requires": {
518 | "es6-promise": "3.2.1",
519 | "mongodb-core": "2.1.20",
520 | "readable-stream": "2.2.7"
521 | }
522 | },
523 | "mongodb-core": {
524 | "version": "2.1.20",
525 | "resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-2.1.20.tgz",
526 | "integrity": "sha512-IN57CX5/Q1bhDq6ShAR6gIv4koFsZP7L8WOK1S0lR0pVDQaScffSMV5jxubLsmZ7J+UdqmykKw4r9hG3XQEGgQ==",
527 | "requires": {
528 | "bson": "~1.0.4",
529 | "require_optional": "~1.0.0"
530 | }
531 | },
532 | "mongolass": {
533 | "version": "3.1.5",
534 | "resolved": "https://registry.npmjs.org/mongolass/-/mongolass-3.1.5.tgz",
535 | "integrity": "sha512-BV08Q/xWPjupWw9XCYfvUVRsM8cY6mnTRz8sHdyl1vgrxRixDNuLcoDzB65p1Uf6fAhHAge5vYtTPDuoFkRPmg==",
536 | "requires": {
537 | "another-json-schema": "2.1.1",
538 | "co": "4.6.0",
539 | "debug": "3.0.0",
540 | "inflected": "2.0.2",
541 | "lodash": "4.17.4",
542 | "mongodb": "2.2.31",
543 | "mongolass-plugin-populate": "*",
544 | "validator": "8.0.0"
545 | },
546 | "dependencies": {
547 | "debug": {
548 | "version": "3.0.0",
549 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.0.0.tgz",
550 | "integrity": "sha512-XQkHxxqbsCb+zFurCHbotmJZl5jXsxvkRt952pT6Hpo7LmjWAJF12d9/kqBg5owjbLADbBDli1olravjSiSg8g==",
551 | "requires": {
552 | "ms": "2.0.0"
553 | }
554 | },
555 | "lodash": {
556 | "version": "4.17.4",
557 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz",
558 | "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4="
559 | },
560 | "mongodb": {
561 | "version": "2.2.31",
562 | "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-2.2.31.tgz",
563 | "integrity": "sha1-GUBEXGYeGSF7s7+CRdmFSq71SNs=",
564 | "requires": {
565 | "es6-promise": "3.2.1",
566 | "mongodb-core": "2.1.15",
567 | "readable-stream": "2.2.7"
568 | }
569 | },
570 | "mongodb-core": {
571 | "version": "2.1.15",
572 | "resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-2.1.15.tgz",
573 | "integrity": "sha1-hB9TuH//9MdFgYnDXIroJ+EWl2Q=",
574 | "requires": {
575 | "bson": "~1.0.4",
576 | "require_optional": "~1.0.0"
577 | }
578 | },
579 | "ms": {
580 | "version": "2.0.0",
581 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
582 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
583 | }
584 | }
585 | },
586 | "mongolass-plugin-populate": {
587 | "version": "0.4.0",
588 | "resolved": "https://registry.npmjs.org/mongolass-plugin-populate/-/mongolass-plugin-populate-0.4.0.tgz",
589 | "integrity": "sha512-umM40jqPi/wf5YitZ3ILRKDbwEPeWAMhDR7scFMTXJo0m4doi9C4pGneXqFBHtlSVCrlhpwJV9AhZyiZdd3vRg==",
590 | "requires": {
591 | "lodash": "4.17.10"
592 | },
593 | "dependencies": {
594 | "lodash": {
595 | "version": "4.17.10",
596 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
597 | "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg=="
598 | }
599 | }
600 | },
601 | "ms": {
602 | "version": "0.7.1",
603 | "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz",
604 | "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg="
605 | },
606 | "negotiator": {
607 | "version": "0.6.2",
608 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
609 | "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
610 | },
611 | "objectid-to-timestamp": {
612 | "version": "1.3.0",
613 | "resolved": "https://registry.npmjs.org/objectid-to-timestamp/-/objectid-to-timestamp-1.3.0.tgz",
614 | "integrity": "sha1-Yeys9lgHUdIGOzVEZwndjM7C5fE="
615 | },
616 | "on-finished": {
617 | "version": "2.3.0",
618 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
619 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
620 | "requires": {
621 | "ee-first": "1.1.1"
622 | }
623 | },
624 | "on-headers": {
625 | "version": "1.0.2",
626 | "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
627 | "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA=="
628 | },
629 | "optimist": {
630 | "version": "0.6.1",
631 | "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
632 | "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",
633 | "requires": {
634 | "minimist": "~0.0.1",
635 | "wordwrap": "~0.0.2"
636 | }
637 | },
638 | "parseurl": {
639 | "version": "1.3.3",
640 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
641 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
642 | },
643 | "path-parse": {
644 | "version": "1.0.6",
645 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
646 | "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw=="
647 | },
648 | "path-to-regexp": {
649 | "version": "0.1.7",
650 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
651 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
652 | },
653 | "process-nextick-args": {
654 | "version": "1.0.7",
655 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz",
656 | "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M="
657 | },
658 | "proxy-addr": {
659 | "version": "1.1.5",
660 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-1.1.5.tgz",
661 | "integrity": "sha1-ccDuOxAt4/IC87ZPYI0XP8uhqRg=",
662 | "requires": {
663 | "forwarded": "~0.1.0",
664 | "ipaddr.js": "1.4.0"
665 | }
666 | },
667 | "qs": {
668 | "version": "6.2.0",
669 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.2.0.tgz",
670 | "integrity": "sha1-O3hIwDwt7OaalSKw+ujEEm10Xzs="
671 | },
672 | "random-bytes": {
673 | "version": "1.0.0",
674 | "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz",
675 | "integrity": "sha1-T2ih3Arli9P7lYSMMDJNt11kNgs="
676 | },
677 | "range-parser": {
678 | "version": "1.2.1",
679 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
680 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
681 | },
682 | "readable-stream": {
683 | "version": "2.2.7",
684 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.7.tgz",
685 | "integrity": "sha1-BwV6y+JGeyIELTb5jFrVBwVOlbE=",
686 | "requires": {
687 | "buffer-shims": "~1.0.0",
688 | "core-util-is": "~1.0.0",
689 | "inherits": "~2.0.1",
690 | "isarray": "~1.0.0",
691 | "process-nextick-args": "~1.0.6",
692 | "string_decoder": "~1.0.0",
693 | "util-deprecate": "~1.0.1"
694 | }
695 | },
696 | "require_optional": {
697 | "version": "1.0.1",
698 | "resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz",
699 | "integrity": "sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==",
700 | "requires": {
701 | "resolve-from": "^2.0.0",
702 | "semver": "^5.1.0"
703 | }
704 | },
705 | "resolve": {
706 | "version": "1.4.0",
707 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.4.0.tgz",
708 | "integrity": "sha512-aW7sVKPufyHqOmyyLzg/J+8606v5nevBgaliIlV7nUpVMsDnoBGV/cbSLNjZAg9q0Cfd/+easKVKQ8vOu8fn1Q==",
709 | "requires": {
710 | "path-parse": "^1.0.5"
711 | }
712 | },
713 | "resolve-from": {
714 | "version": "2.0.0",
715 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz",
716 | "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c="
717 | },
718 | "safe-buffer": {
719 | "version": "5.1.2",
720 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
721 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
722 | },
723 | "semver": {
724 | "version": "5.7.1",
725 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
726 | "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
727 | },
728 | "send": {
729 | "version": "0.14.1",
730 | "resolved": "https://registry.npmjs.org/send/-/send-0.14.1.tgz",
731 | "integrity": "sha1-qVSYQyU5L1FTKndgdg5FlZjIn3o=",
732 | "requires": {
733 | "debug": "~2.2.0",
734 | "depd": "~1.1.0",
735 | "destroy": "~1.0.4",
736 | "encodeurl": "~1.0.1",
737 | "escape-html": "~1.0.3",
738 | "etag": "~1.7.0",
739 | "fresh": "0.3.0",
740 | "http-errors": "~1.5.0",
741 | "mime": "1.3.4",
742 | "ms": "0.7.1",
743 | "on-finished": "~2.3.0",
744 | "range-parser": "~1.2.0",
745 | "statuses": "~1.3.0"
746 | }
747 | },
748 | "serve-static": {
749 | "version": "1.11.2",
750 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.11.2.tgz",
751 | "integrity": "sha1-LPmIm9RDWjIMw2iVyapXvWYuasc=",
752 | "requires": {
753 | "encodeurl": "~1.0.1",
754 | "escape-html": "~1.0.3",
755 | "parseurl": "~1.3.1",
756 | "send": "0.14.2"
757 | },
758 | "dependencies": {
759 | "ms": {
760 | "version": "0.7.2",
761 | "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz",
762 | "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U="
763 | },
764 | "send": {
765 | "version": "0.14.2",
766 | "resolved": "https://registry.npmjs.org/send/-/send-0.14.2.tgz",
767 | "integrity": "sha1-ObBDiz9RC+Xcb2Z6EfcWiTaM3u8=",
768 | "requires": {
769 | "debug": "~2.2.0",
770 | "depd": "~1.1.0",
771 | "destroy": "~1.0.4",
772 | "encodeurl": "~1.0.1",
773 | "escape-html": "~1.0.3",
774 | "etag": "~1.7.0",
775 | "fresh": "0.3.0",
776 | "http-errors": "~1.5.1",
777 | "mime": "1.3.4",
778 | "ms": "0.7.2",
779 | "on-finished": "~2.3.0",
780 | "range-parser": "~1.2.0",
781 | "statuses": "~1.3.1"
782 | }
783 | }
784 | }
785 | },
786 | "setprototypeof": {
787 | "version": "1.0.2",
788 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.2.tgz",
789 | "integrity": "sha1-gaVSFB7BBLiOic44MQOtXGZWTQg="
790 | },
791 | "sha1": {
792 | "version": "1.1.1",
793 | "resolved": "https://registry.npmjs.org/sha1/-/sha1-1.1.1.tgz",
794 | "integrity": "sha1-rdqnqTFo85PxnrKxUJFhjicA+Eg=",
795 | "requires": {
796 | "charenc": ">= 0.0.1",
797 | "crypt": ">= 0.0.1"
798 | }
799 | },
800 | "sprintf-js": {
801 | "version": "1.0.3",
802 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
803 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
804 | },
805 | "stack-trace": {
806 | "version": "0.0.10",
807 | "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
808 | "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA="
809 | },
810 | "statuses": {
811 | "version": "1.3.1",
812 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz",
813 | "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4="
814 | },
815 | "string_decoder": {
816 | "version": "1.0.3",
817 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
818 | "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
819 | "requires": {
820 | "safe-buffer": "~5.1.0"
821 | }
822 | },
823 | "strip-ansi": {
824 | "version": "0.1.1",
825 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.1.1.tgz",
826 | "integrity": "sha1-OeipjQRNFQZgq+SmgIrPcLt7yZE="
827 | },
828 | "supports-color": {
829 | "version": "4.5.0",
830 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz",
831 | "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=",
832 | "requires": {
833 | "has-flag": "^2.0.0"
834 | }
835 | },
836 | "toml": {
837 | "version": "2.3.2",
838 | "resolved": "https://registry.npmjs.org/toml/-/toml-2.3.2.tgz",
839 | "integrity": "sha1-Xt7VykKIeSSUn9BusOlVZWAB6DQ="
840 | },
841 | "type-is": {
842 | "version": "1.6.18",
843 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
844 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
845 | "requires": {
846 | "media-typer": "0.3.0",
847 | "mime-types": "~2.1.24"
848 | }
849 | },
850 | "uid-safe": {
851 | "version": "2.1.5",
852 | "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz",
853 | "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==",
854 | "requires": {
855 | "random-bytes": "~1.0.0"
856 | }
857 | },
858 | "unpipe": {
859 | "version": "1.0.0",
860 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
861 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
862 | },
863 | "util-deprecate": {
864 | "version": "1.0.2",
865 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
866 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
867 | },
868 | "utils-merge": {
869 | "version": "1.0.0",
870 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz",
871 | "integrity": "sha1-ApT7kiu5N1FTVBxPcJYjHyh8ivg="
872 | },
873 | "validator": {
874 | "version": "8.0.0",
875 | "resolved": "https://registry.npmjs.org/validator/-/validator-8.0.0.tgz",
876 | "integrity": "sha512-ni6X82obaR98FomBC8M/IF01u7d8WBjNhadxDDo+xGHGSfbTug1IS0j1zaoViYWQaMMFVfz40UhYxgs3dzvnZg=="
877 | },
878 | "vary": {
879 | "version": "1.1.2",
880 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
881 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
882 | },
883 | "winston": {
884 | "version": "2.4.0",
885 | "resolved": "https://registry.npmjs.org/winston/-/winston-2.4.0.tgz",
886 | "integrity": "sha1-gIBQuT1SZh7Z+2wms/DIJnCLCu4=",
887 | "requires": {
888 | "async": "~1.0.0",
889 | "colors": "1.0.x",
890 | "cycle": "1.0.x",
891 | "eyes": "0.1.x",
892 | "isstream": "0.1.x",
893 | "stack-trace": "0.0.x"
894 | }
895 | },
896 | "wordwrap": {
897 | "version": "0.0.3",
898 | "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
899 | "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc="
900 | }
901 | }
902 | }
903 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "library_system",
3 | "version": "1.0.0",
4 | "description": "a library system",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [
10 | "node",
11 | "express",
12 | "mongodb"
13 | ],
14 | "author": "nickj",
15 | "license": "ISC",
16 | "dependencies": {
17 | "asyncawait": "^1.0.6",
18 | "config-lite": "2.1.0",
19 | "connect-flash": "0.1.1",
20 | "connect-mongo": "2.0.0",
21 | "ejs": "2.5.7",
22 | "express": "4.14.0",
23 | "express-formidable": "1.0.0",
24 | "express-session": "1.15.6",
25 | "express-winston": "2.4.0",
26 | "hash-set": "^1.0.1",
27 | "marked": "0.7.0",
28 | "moment": "2.18.1",
29 | "mongolass": "3.1.5",
30 | "objectid-to-timestamp": "1.3.0",
31 | "sha1": "1.1.1",
32 | "winston": "2.4.0"
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/public/css/common.css:
--------------------------------------------------------------------------------
1 | body {
2 | /* width: 1100px; */
3 | height: 100%;
4 | margin: 0 auto;
5 | }
6 |
7 | .button {
8 | background-color: #4fc08d;
9 | color: #fff;
10 | }
11 |
12 | .avatar {
13 | border-radius: 3px;
14 | width: 48px;
15 | height: 48px;
16 | float: right;
17 | }
18 |
19 |
20 | /* ---------- nav ---------- */
21 |
22 | .nav {
23 | margin-bottom: 20px;
24 | color: #999;
25 | text-align: center;
26 | }
27 |
28 | .nav h1 {
29 | color: #4fc08d;
30 | display: inline-block;
31 | margin: 10px 0;
32 | }
33 |
34 |
35 | /* ---------- nav-setting ---------- */
36 |
37 | .nav-setting {
38 | position: fixed;
39 | right: 30px;
40 | top: 35px;
41 | z-index: 999;
42 | }
43 |
44 | .nav-setting .ui.dropdown.button {
45 | padding: 10px 10px 0 10px;
46 | background-color: #fff !important;
47 | }
48 |
49 | .nav-setting .icon.bars {
50 | color: #000;
51 | font-size: 18px;
52 | }
53 |
54 |
55 | /* ---------- post-content ---------- */
56 |
57 | .post-content h3 a {
58 | color: #4fc08d !important;
59 | }
60 |
61 | .post-content .tag {
62 | font-size: 13px;
63 | margin-right: 5px;
64 | color: #999;
65 | }
66 |
67 | .post-content .tag.right {
68 | float: right;
69 | margin-right: 0;
70 | }
71 |
72 | .post-content .tag.right a {
73 | color: #999;
74 | }
--------------------------------------------------------------------------------
/public/css/themes/basic/assets/fonts/icons.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lzhongzhang/Online-Library-System/e41682073273fb1b7ffc09ef0f633df9979f519b/public/css/themes/basic/assets/fonts/icons.eot
--------------------------------------------------------------------------------
/public/css/themes/basic/assets/fonts/icons.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
451 |
--------------------------------------------------------------------------------
/public/css/themes/basic/assets/fonts/icons.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lzhongzhang/Online-Library-System/e41682073273fb1b7ffc09ef0f633df9979f519b/public/css/themes/basic/assets/fonts/icons.ttf
--------------------------------------------------------------------------------
/public/css/themes/basic/assets/fonts/icons.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lzhongzhang/Online-Library-System/e41682073273fb1b7ffc09ef0f633df9979f519b/public/css/themes/basic/assets/fonts/icons.woff
--------------------------------------------------------------------------------
/public/css/themes/default/assets/fonts/icons.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lzhongzhang/Online-Library-System/e41682073273fb1b7ffc09ef0f633df9979f519b/public/css/themes/default/assets/fonts/icons.eot
--------------------------------------------------------------------------------
/public/css/themes/default/assets/fonts/icons.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lzhongzhang/Online-Library-System/e41682073273fb1b7ffc09ef0f633df9979f519b/public/css/themes/default/assets/fonts/icons.otf
--------------------------------------------------------------------------------
/public/css/themes/default/assets/fonts/icons.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lzhongzhang/Online-Library-System/e41682073273fb1b7ffc09ef0f633df9979f519b/public/css/themes/default/assets/fonts/icons.ttf
--------------------------------------------------------------------------------
/public/css/themes/default/assets/fonts/icons.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lzhongzhang/Online-Library-System/e41682073273fb1b7ffc09ef0f633df9979f519b/public/css/themes/default/assets/fonts/icons.woff
--------------------------------------------------------------------------------
/public/css/themes/default/assets/fonts/icons.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lzhongzhang/Online-Library-System/e41682073273fb1b7ffc09ef0f633df9979f519b/public/css/themes/default/assets/fonts/icons.woff2
--------------------------------------------------------------------------------
/public/css/themes/default/assets/images/flags.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lzhongzhang/Online-Library-System/e41682073273fb1b7ffc09ef0f633df9979f519b/public/css/themes/default/assets/images/flags.png
--------------------------------------------------------------------------------
/public/img/upload_3424d6994a994d4340ab043b0717d6a4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lzhongzhang/Online-Library-System/e41682073273fb1b7ffc09ef0f633df9979f519b/public/img/upload_3424d6994a994d4340ab043b0717d6a4.jpg
--------------------------------------------------------------------------------
/public/img/upload_4c1fdd5646bd120237aaa5ffe7ddd40d.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lzhongzhang/Online-Library-System/e41682073273fb1b7ffc09ef0f633df9979f519b/public/img/upload_4c1fdd5646bd120237aaa5ffe7ddd40d.jpg
--------------------------------------------------------------------------------
/public/img/upload_60d2f41215d11b1d20d57bb3dc65c131.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lzhongzhang/Online-Library-System/e41682073273fb1b7ffc09ef0f633df9979f519b/public/img/upload_60d2f41215d11b1d20d57bb3dc65c131.jpeg
--------------------------------------------------------------------------------
/public/img/upload_637c32ec1ab0534d2fb4f090a504c556.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lzhongzhang/Online-Library-System/e41682073273fb1b7ffc09ef0f633df9979f519b/public/img/upload_637c32ec1ab0534d2fb4f090a504c556.jpg
--------------------------------------------------------------------------------
/public/img/upload_71930cd725a347a06009b3061468f7aa.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lzhongzhang/Online-Library-System/e41682073273fb1b7ffc09ef0f633df9979f519b/public/img/upload_71930cd725a347a06009b3061468f7aa.jpeg
--------------------------------------------------------------------------------
/routes/borrow.js:
--------------------------------------------------------------------------------
1 | var express = require('express');
2 | var router = express.Router();
3 | var async = require('asyncawait/async');
4 | var await = require('asyncawait/await');
5 | var UserModel = require('../models/users');
6 | var BorrowBookModel = require('../models/borrowBooks');
7 | var BorrowBooks = require('../lib/mongo').BorrowBook;
8 | var checkIsAdmin = require('../middlewares/check').checkIsAdmin;
9 |
10 | router.get('/:bookId', checkIsAdmin, async (function (req, res, next) {
11 | var bookId = req.params.bookId;
12 | var result = [];
13 | try {
14 | var users = await (BorrowBookModel.getBorrowUsers(bookId));
15 | users.forEach(async (function(user){
16 | var userInfo = await (UserModel.getUserByDefaultId(user.userId))
17 | result.push({
18 | userId: user.userId,
19 | name: userInfo.name,
20 | id: userInfo.id,
21 | avatar: userInfo.avatar,
22 | borrowTime: user.created_at,
23 | borrowId: user._id,
24 | bookId: bookId,
25 | returnTime: user.return_time,
26 | bool: user.bool
27 | })
28 | }));
29 |
30 | setTimeout(function() {
31 | res.render('borrow', {
32 | borrowUser: result
33 | });
34 | }, 1000);
35 |
36 | } catch (error) {
37 | next();
38 | }
39 |
40 | }));
41 |
42 | module.exports = router;
--------------------------------------------------------------------------------
/routes/home.js:
--------------------------------------------------------------------------------
1 | var express = require('express');
2 | var router = express.Router();
3 | var Library = require('../lib/mongo').Library;
4 | var async = require('asyncawait/async');
5 | var await = require('asyncawait/await');
6 | var mongo = require('mongodb');
7 | var LibraryModel = require('../models/library');
8 | var checkLogin = require('../middlewares/check').checkLogin;
9 |
10 | var FavoriteModel = require('../lib/mongo').Favorite;
11 |
12 |
13 | router.get('/', async (function (req, res, next) {
14 | var query = {};
15 | query.admin = '5a246f7a4015d2070b89df75';
16 | // var perPage = 4;
17 | // var page = req.query.page || 1;
18 |
19 | var curcount;
20 | var books = await (Library
21 | .find(query)
22 | .populate({ path: 'admin', model: 'User' })
23 | .sort({"inventory" : -1})
24 | .addCreatedAt()
25 | .exec());
26 | var result = [];
27 | if(req.session.user) {
28 | books.forEach(async (function(book) {
29 | var userId = new mongo.ObjectId(req.session.user._id);
30 | var bookId = new mongo.ObjectId(book._id);
31 |
32 | var record = await (FavoriteModel.findOne({userId: userId, bookId: bookId}).exec());
33 | var like = false;
34 | if(record !== null) {
35 | like = record.favorite;
36 | }
37 |
38 | result.push({
39 | _id: book._id,
40 | name: book.name,
41 | cover: book.cover,
42 | score: book.score,
43 | author: book.author,
44 | like: like,
45 | show: book.show
46 | })
47 | }));
48 | }
49 | else {
50 | result = books;
51 | }
52 | setTimeout(function() {
53 |
54 | res.render('home', {
55 | books: result
56 | });
57 | }, 1000);
58 | }));
59 |
60 |
61 | router.get('/:bookId/favorite', async (function(req,res){
62 | var userId = new mongo.ObjectId(req.session.user._id);
63 | var book_Id = new mongo.ObjectId(req.params.bookId);
64 | var record = await (FavoriteModel.findOne({userId: userId, bookId: book_Id}).exec());
65 | if(record === null) {
66 | await(FavoriteModel.insertOne({
67 | userId: userId,
68 | bookId: book_Id,
69 | favorite: true
70 | }).exec());
71 | }
72 | else {
73 | await(FavoriteModel.update({userId: userId, bookId: book_Id, favorite: false}, {$set:{favorite : true}}).exec());
74 | }
75 | setTimeout(function() {
76 | res.redirect('/');
77 | }, 10);
78 | }));
79 |
80 | router.get('/:bookId/unfavorite', async (function(req,res){
81 | var userId = new mongo.ObjectId(req.session.user._id);
82 | var book_Id = new mongo.ObjectId(req.params.bookId);
83 |
84 | await(FavoriteModel.update({userId: userId, bookId: book_Id, favorite: true}, {$set:{favorite : false}}).exec());
85 |
86 | setTimeout(function() {
87 | res.redirect('/');
88 | }, 10);
89 | }));
90 | module.exports = router;
--------------------------------------------------------------------------------
/routes/index.js:
--------------------------------------------------------------------------------
1 | module.exports = function (app) {
2 | app.get('/', function (req, res) {
3 | res.redirect('./home');
4 | });
5 | app.use('/home', require('./home'));
6 | app.use('/signup', require('./signup'));
7 | app.use('/signin', require('./signin'));
8 | app.use('/signout', require('./signout'));
9 | app.use('/library', require('./library'));
10 | app.use('/search', require('./search'));
11 | app.use('/profile', require('./profile'));
12 | app.use('/borrow', require('./borrow'));
13 | app.use('/quick_borrow', require('./quick_borrow'));
14 | // 404 page
15 | app.use(function (req, res) {
16 | if (!res.headersSent) {
17 | res.status(404).render('404');
18 | }
19 | });
20 | };
--------------------------------------------------------------------------------
/routes/library.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs');
2 | var path = require('path');
3 | var express = require('express');
4 | var router = express.Router();
5 | var async = require('asyncawait/async');
6 | var await = require('asyncawait/await');
7 | var LibraryModel = require('../models/library');
8 | var BorrowBookModel = require('../models/borrowBooks');
9 | var UserModel = require('../models/users');
10 | var checkLogin = require('../middlewares/check').checkLogin;
11 | var checkIsAdmin = require('../middlewares/check').checkIsAdmin;
12 |
13 | router.get('/', checkIsAdmin, async(function (req, res, next) {
14 | var admin = req.query.admin;
15 |
16 | try {
17 | var books = await (LibraryModel.getBooks(admin));
18 | books.forEach(async (function(book) {
19 | try {
20 | var borrowCount = await (BorrowBookModel.getBorrowBooksCount(book._id));
21 | book.borrowCount = borrowCount;
22 | } catch (error) {
23 | req.flash('error', 'Something go wrong, please try again!');
24 | }
25 | }), this);
26 |
27 | setTimeout(() => {
28 | res.render('library', {
29 | books: books
30 | });
31 | }, 1000)
32 | } catch (error) {
33 | req.flash('error', 'Something go wrong, please try again!');
34 | next();
35 | }
36 |
37 | }));
38 |
39 | router.post('/', checkIsAdmin, async (function (req, res, next) {
40 | var admin = req.session.user._id;
41 |
42 | var bookData = {
43 | admin: req.session.user._id,
44 | name: req.fields.name,
45 | location: req.fields.location,
46 | author: req.fields.author,
47 | press: req.fields.press,
48 | inventory: parseInt(req.fields.inventory),
49 | date: req.fields.date,
50 | score: parseInt(req.fields.score),
51 | cover: req.fields.cover_url || req.files.cover.path.split(path.sep).pop() ,
52 | introduction: req.fields.introduction
53 | }
54 | try {
55 | if (!bookData.name.length) {
56 | throw new Error('Please fill in the name!');
57 | }
58 | if (!bookData.introduction.length) {
59 | throw new Error('Please fill in the introduction!');
60 | }
61 | } catch (e) {
62 | req.flash('error', e.message);
63 | return res.redirect('back');
64 | }
65 |
66 | var book = {
67 | admin: bookData.admin,
68 | name: bookData.name,
69 | location: bookData.location,
70 | author: bookData.author,
71 | press: bookData.press,
72 | inventory: bookData.inventory,
73 | date: bookData.date,
74 | score: bookData.score,
75 | cover: bookData.cover,
76 | introduction: bookData.introduction,
77 | pv: 0,
78 | show: true
79 | };
80 |
81 | var checkBook = await (LibraryModel.checkBook(book.name));
82 |
83 | if (!checkBook.length) {
84 | LibraryModel.create(book)
85 | .then(function (result) {
86 | book = result.ops[0];
87 | req.flash('success', 'Add successfully!');
88 | res.redirect(`/library`);
89 | })
90 | .catch(next);
91 | } else {
92 | req.flash('error', 'This book has already exist!');
93 | res.redirect(`/library`);
94 | }
95 |
96 | }));
97 |
98 | router.get('/:bookId', function (req, res, next) {
99 | var bookId = req.params.bookId;
100 |
101 | Promise.all([
102 | LibraryModel.getBookById(bookId),
103 | LibraryModel.incPv(bookId)
104 | ])
105 | .then(function (result) {
106 | var book = result[0];
107 | if (!book) {
108 | throw new Error('The book does not exist!');
109 | }
110 | book.location = book.location;
111 | res.render('book', {
112 | book: book
113 | });
114 | })
115 | .catch(next);
116 | });
117 |
118 | router.get('/:bookId/remove', checkIsAdmin, function (req, res, next) {
119 | var bookId = req.params.bookId;
120 | var admin = req.session.user._id;
121 |
122 | LibraryModel.delBookById(bookId, admin)
123 | .then(function () {
124 | req.flash('success', 'Delete the book successfully!');
125 | res.redirect('/library');
126 | })
127 | .catch(next);
128 | });
129 |
130 | router.post('/:bookId/edit', checkIsAdmin, function (req, res, next) {
131 | var bookId = req.params.bookId;
132 | var admin = req.session.user._id;
133 |
134 | var bookData = {
135 | name: req.fields.name,
136 | author: req.fields.author,
137 | press: req.fields.press,
138 | inventory: parseInt(req.fields.inventory),
139 | date: req.fields.date,
140 | score: parseInt(req.fields.score),
141 | introduction: req.fields.introduction
142 | };
143 |
144 | LibraryModel.updateBookById(bookId, admin, bookData)
145 | .then(function () {
146 | req.flash('success', 'Edit book success!');
147 | res.redirect('/library');
148 | })
149 | .catch(next);
150 | });
151 |
152 | router.get('/:bookId/borrow', checkIsAdmin, async (function (req, res, next) {
153 | var userId = req.session.user._id;
154 | var bookId = req.params.bookId;
155 |
156 | var borrow = {
157 | userId: userId,
158 | bookId: bookId,
159 | bool: false
160 | };
161 | try {
162 | var book = await (LibraryModel.getRawBookById(borrow.bookId));
163 | if (book.inventory >= 1) {
164 | try {
165 | await (LibraryModel.updateBookById(borrow.bookId, '5a246f7a4015d2070b89df75', {
166 | inventory: book.inventory - 1
167 | }))
168 | try {
169 | await (BorrowBookModel.create(borrow))
170 | req.flash('success', 'Borrow Successfully!');
171 | res.redirect('back');
172 | } catch (error) {
173 | req.flash('error', 'Something go wrong, please try again!');
174 | res.redirect('back');
175 | }
176 | } catch (error) {
177 | req.flash('error', 'Something go wrong, please try again!');
178 | res.redirect('back');
179 | }
180 |
181 | } else {
182 | req.flash('error', 'Zero inventory!');
183 | res.redirect('back');
184 | }
185 | } catch (error) {
186 | req.flash('error', 'Something go wrong, please try again!');
187 | res.redirect('back');
188 | }
189 |
190 | }));
191 | router.get('/:bookId/borrow/:userId', checkIsAdmin, async (function (req, res, next) {
192 | var userId = req.params.userId;
193 | var bookId = req.params.bookId;
194 | var user = await (UserModel.getUserById(userId));
195 | if (!user) {
196 | req.flash('error', 'There is no Student Id exist, please try another one!');
197 | res.redirect('back');
198 | return false;
199 | }
200 |
201 | var borrow = {
202 | userId: user._id,
203 | bookId: bookId,
204 | bool: false,
205 | };
206 |
207 | try {
208 | var book = await (LibraryModel.getRawBookById(borrow.bookId));
209 | if (book.inventory >= 1) {
210 | try {
211 | await (LibraryModel.updateBookById(borrow.bookId, '5a246f7a4015d2070b89df75', {
212 | inventory: book.inventory - 1
213 | }))
214 | try {
215 | await (BorrowBookModel.create(borrow))
216 | req.flash('success', 'Borrow Successfully by ' + userId +'!');
217 | res.redirect('back');
218 | } catch (error) {
219 | req.flash('error', 'Something go wrong, please try again!');
220 | res.redirect('back');
221 | }
222 | } catch (error) {
223 | req.flash('error', 'Something go wrong, please try again!');
224 | res.redirect('back');
225 | }
226 |
227 | } else {
228 | req.flash('error', 'Zero inventory!');
229 | res.redirect('back');
230 | }
231 | } catch (error) {
232 | req.flash('error', 'Your book Id maybe wrong, please try again!');
233 | res.redirect('back');
234 | }
235 |
236 | }));
237 |
238 |
239 |
240 | module.exports = router;
--------------------------------------------------------------------------------
/routes/post.js:
--------------------------------------------------------------------------------
1 | var express = require('express');
2 | var router = express.Router();
3 |
4 | var BorrowBookModel = require('../models/borrowBooks');
5 |
6 | var checkLogin = require('../middlewares/check').checkLogin;
7 |
8 | router.get('/:userId', function(req, res) {
9 |
10 | })
--------------------------------------------------------------------------------
/routes/profile.js:
--------------------------------------------------------------------------------
1 | var express = require('express');
2 | var router = express.Router();
3 | var async = require('asyncawait/async');
4 | var await = require('asyncawait/await');
5 | var UserModel = require('../models/users');
6 | var LibraryModel = require('../models/library');
7 | var BorrowBookModel = require('../models/borrowBooks');
8 | var checkLogin = require('../middlewares/check').checkLogin;
9 | var checkIsAdmin = require('../middlewares/check').checkIsAdmin;
10 |
11 | router.get('/:userId', checkLogin, async (function (req, res, next) {
12 | var currentUser = req.session.user;
13 | var userId = req.params.userId;
14 | var user = await (UserModel.getUserByDefaultId(userId));
15 |
16 | try {
17 | var bBook = await (BorrowBookModel.getBorrowBooks(user._id))
18 |
19 | var result = [];
20 | bBook.forEach(async (function(item) {
21 | var book = await (LibraryModel.getRawBookById(item.bookId));
22 |
23 | var temp = item.created_at.split(" ");
24 | var returnTime = temp[0].split("-");
25 | var rtMonth = parseInt(returnTime[1]) + 1;
26 | var rtYear = parseInt(returnTime[0]);
27 | if (rtMonth > 12) {
28 | rtYear += 1;
29 | rtMonth -= 12;
30 | }
31 | var rTime = rtYear + "-" + rtMonth + "-" + returnTime[2];
32 |
33 | var returnDate = item.return_time;
34 |
35 |
36 | result.push({
37 | id: item._id,
38 | userId: userId,
39 | bookId: item.bookId,
40 | created_at: item.created_at,
41 | returnTime: rTime,
42 | name: book.name,
43 | author: book.author,
44 | cover: book.cover,
45 | introduction: book.introduction,
46 | bool: item.bool,
47 | returnDate: returnDate
48 | })
49 | }));
50 | setTimeout(() => {
51 | res.render('profile', {
52 | profile: user,
53 | borrow: result
54 | })
55 | }, 1000)
56 | } catch(e) {
57 | req.flash('error', 'Something go wrong, please try again!');
58 | }
59 | }));
60 |
61 | router.get('/:bookId/return2/:userId', checkIsAdmin, async (function (req, res, next) {
62 | var bookId = req.params.bookId,
63 | userId = req.params.userId;
64 |
65 | var user = await (UserModel.getUserById(userId));
66 |
67 | try {
68 | await (BorrowBookModel.returnBookByBookId(bookId, user._id)); // bookid, user._id
69 | var book = await (LibraryModel.getRawBookById(bookId));
70 | try {
71 | await (LibraryModel.updateBookById(bookId, '5a246f7a4015d2070b89df75', {
72 | inventory: book.inventory + 1
73 | }))
74 | req.flash('success', 'Return Successfully!');
75 | res.redirect('back');
76 | } catch (e) {
77 | req.flash('error', 'Something go wrong, please try again!');
78 | res.redirect('back');
79 | }
80 | } catch (error) {
81 | req.flash('error', 'Can\'t find the borrowed record, please try again!');
82 | res.redirect('back');
83 | }
84 | }));
85 |
86 | module.exports = router;
--------------------------------------------------------------------------------
/routes/quick_borrow.js:
--------------------------------------------------------------------------------
1 | var express = require('express');
2 | var router = express.Router();
3 | var async = require('asyncawait/async');
4 | var await = require('asyncawait/await');
5 | var UserModel = require('../models/users');
6 | var LibraryModel = require('../models/library');
7 | var BorrowBookModel = require('../models/borrowBooks');
8 |
9 | var checkIsAdmin = require('../middlewares/check').checkIsAdmin;
10 |
11 | router.get('/', checkIsAdmin, async (function (req, res, next) {
12 | var admin = req.query.admin;
13 |
14 | res.render('quick_borrow');
15 |
16 | }));
17 |
18 | module.exports = router;
--------------------------------------------------------------------------------
/routes/search.js:
--------------------------------------------------------------------------------
1 | var express = require('express');
2 | var router = express.Router();
3 |
4 | var LibraryModel = require('../models/library');
5 | var checkLogin = require('../middlewares/check').checkLogin;
6 |
7 | router.get('/:payload', function (req, res, next) {
8 | var payload = req.params.payload,
9 | type = req.query.type;
10 |
11 | LibraryModel.searchBook(payload)
12 | .then(function (books) {
13 | switch (type) {
14 | case 'library':
15 | res.render('library', {
16 | books: books
17 | });
18 | break;
19 | default:
20 | res.render('home', {
21 | books: books
22 | });
23 | }
24 | })
25 | .catch(next);
26 | });
27 |
28 |
29 |
30 | module.exports = router;
--------------------------------------------------------------------------------
/routes/signin.js:
--------------------------------------------------------------------------------
1 | var sha1 = require('sha1');
2 | var express = require('express');
3 | var router = express.Router();
4 |
5 | var UserModel = require('../models/users');
6 | var checkNotLogin = require('../middlewares/check').checkNotLogin;
7 |
8 | router.get('/', checkNotLogin, function (req, res, next) {
9 | res.render('signin')
10 | });
11 |
12 | router.post('/', checkNotLogin, function (req, res, next) {
13 | var id = req.fields.id;
14 | var password = req.fields.password;
15 |
16 | UserModel.getUserById(id)
17 | .then(function (user) {
18 | if (!id) {
19 | req.flash('error', 'User does not exist!');
20 | return res.redirect('back');
21 | }
22 | if (sha1(password) !== user.password) {
23 | req.flash('error', 'Wrong user name or password!');
24 | return res.redirect('back');
25 | }
26 | req.flash('success', 'Signin successful!');
27 | delete user.password;
28 | req.session.user = user;
29 | res.redirect('/home');
30 | })
31 | .catch(function(e) {
32 | req.flash('error', 'This user has not registered yet!');
33 | res.redirect('/signin');
34 | next(e)
35 | });
36 | });
37 |
38 |
39 | module.exports = router;
--------------------------------------------------------------------------------
/routes/signout.js:
--------------------------------------------------------------------------------
1 | var express = require('express');
2 | var router = express.Router();
3 |
4 | var checkLogin = require('../middlewares/check').checkLogin;
5 |
6 | router.get('/', checkLogin, function (req, res, next) {
7 | req.session.user = null;
8 | req.flash('success', 'Sign out successfully!');
9 | res.redirect('/home');
10 | });
11 |
12 | module.exports = router;
--------------------------------------------------------------------------------
/routes/signup.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs');
2 | var path = require('path');
3 | var sha1 = require('sha1');
4 | var express = require('express');
5 | var router = express.Router();
6 |
7 | var UserModel = require('../models/users');
8 | var checkNotLogin = require('../middlewares/check').checkNotLogin;
9 | var checkIsAdmin = require('../middlewares/check').checkIsAdmin;
10 |
11 | router.get('/', function (req, res, next) {
12 | res.render('signup');
13 | });
14 |
15 | router.post('/', function (req, res, next) {
16 | var userData = {
17 | id: req.fields.id,
18 | name: req.fields.name,
19 | gender: req.fields.gender,
20 | bio: req.fields.bio,
21 | avatar: req.files.avatar.path.split(path.sep).pop(),
22 | password: req.fields.password,
23 | repassword: req.fields.repassword
24 | }
25 | try {
26 | if (userData.password !== userData.repassword) {
27 | throw new Error('not match');
28 | }
29 | } catch (e) {
30 | fs.unlink(req.files.avatar.path);
31 | req.flash('error', e.message);
32 | return res.redirect('/signup');
33 | }
34 |
35 | userData.password = sha1(userData.password);
36 |
37 | var user = {
38 | id: userData.id,
39 | name: userData.name,
40 | password: userData.password,
41 | gender: userData.gender,
42 | bio: userData.bio,
43 | avatar: userData.avatar,
44 | isAdmin: false
45 | };
46 | UserModel.create(user)
47 | .then(function (result) {
48 | user = result.ops[0];
49 | delete user.password;
50 | req.flash('success', 'Registration success');
51 | res.redirect('/home');
52 | })
53 | .catch(function (e) {
54 | fs.unlink(req.files.avatar.path);
55 | if (e.message.match('E11000 duplicate key')) {
56 | req.flash('error', 'This Student\'s ID has been used, please try another one!');
57 | return res.redirect('/signup');
58 | }
59 | next(e);
60 | });
61 | });
62 |
63 | module.exports = router;
--------------------------------------------------------------------------------
/routes/users.js:
--------------------------------------------------------------------------------
1 | var express = require('express');
2 | var router = express.Router();
3 |
4 | router.get('/:name', function(req, res) {
5 | res.render('users', {
6 | name: req.params.name
7 | })
8 | });
9 |
10 | module.exports = router;
--------------------------------------------------------------------------------
/views/404.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | <%= blog.title %>
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/views/book.ejs:
--------------------------------------------------------------------------------
1 | <%- include('./layout/header') %>
2 |
7 |
8 |
9 | <%= book.name %>
10 |
11 |
12 |
13 |
14 |

">
15 |
16 |
17 |
18 | Book ID: <%= book._id%>
19 |
20 |
21 | Location: <%= book.location%>
22 |
23 |
24 | Author: <%= book.author%>
25 |
26 |
27 | Press: <%= book.press%>
28 |
29 |
30 | Published Date: <%= book.date%>
31 |
32 |
33 | Score:
34 |
35 |
36 |
37 | Inventory: <%= book.inventory%>
38 |
39 |
40 | Pv: <%= book.pv%>
41 |
42 |
43 |
44 |
45 |
46 | <% if (user) { %>
47 | <% if(user.isAdmin){%>
48 |
54 | <% } %>
55 | <% } %>
56 |
57 |
58 |
59 |
60 |
61 |
Brief Introduction
62 |
<%- book.introduction %>
63 |
64 |
65 |
66 |
67 | <% if (user) { %>
68 | <% if(user.isAdmin){%>
69 |
90 | <%}%>
91 | <% } %>
92 |
93 |
94 |
118 | <%- include('./layout/footer') %>
--------------------------------------------------------------------------------
/views/borrow.ejs:
--------------------------------------------------------------------------------
1 | <%- include('./layout/header') %>
2 |
3 | <% borrowUser.forEach(function(user){ %>
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
Id : <%= user.id%>
12 |
Borrow Time: <%= user.borrowTime%>
13 |
Return Time: <%= user.bool == false ? "Not returned" : user.returnTime%>
14 |
15 |
16 |
17 |
18 | <% }) %>
19 |
20 | <%- include('./layout/footer') %>
--------------------------------------------------------------------------------
/views/error.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | <%= blog.title %>
8 |
9 |
10 |
11 |
12 |
13 |
14 | <%= error.message %>
15 |
16 |
17 | <%= error.stack %>
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/views/home.ejs:
--------------------------------------------------------------------------------
1 | <%- include('./layout/header') %>
2 |
7 |
8 |
9 | <% books.forEach(function (book) { %>
10 | <%if (book.show) {%>
11 |
12 |
13 |
14 |
15 |
">
16 |
17 |
18 |
22 |
23 |
26 |
27 |
28 | Like
29 | <% if(book.like){ %>
30 |
31 | <%} else {%>
32 |
33 | <% } %>
34 |
35 |
36 |
37 |
38 | <%}%>
39 | <% }) %>
40 |
41 |
42 |
76 |
77 | <%- include('./layout/footer') %>
--------------------------------------------------------------------------------
/views/layout/footer.ejs:
--------------------------------------------------------------------------------
1 |
2 |
23 |
24 |