diff --git a/.gitignore b/.gitignore
index 1dcef2d..75a2ede 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
node_modules
-.env
\ No newline at end of file
+.env
+ssl
\ No newline at end of file
diff --git a/README.md b/README.md
index 8249961..3203cf2 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,37 @@
# CodeLibrary
-Демо-проект для курса "Node.js в действии"
\ No newline at end of file
+Демо-проект для курса "Node.js в действии".
+Приложение представляет из себя библиотеку книг.
+
+## Основные маршруты
+
+* `/` - главная страница
+* Вход и регистрация
+ * `/auth/register` - регистрация
+ * `/auth/login` - вход
+* Профиль пользователя
+ * `/user` - страница пользователя
+ * `/user/edit` - редактирование пользователя
+* Книги
+ * `/books` - книгами
+ * `/books/new` - новые книги
+ * `/books/best` - лучшие книги
+ * `/books/search` - поиск
+ * `/books/:topic` - книги по теме
+ * `/books/:book` - книга
+* Администратор
+ * `/admin` - главная страница
+ * `/admin/login` - вход
+ * Книги
+ * `/admin/books` - список книг
+ * `/admin/books/create` - создание книги
+ * `/admin/books/:book/update` - редактирование книги
+ * `/admin/books/:book/delete` - удаление книги
+ * Темы
+ * `/admin/topics` - список тем
+ * `/admin/topics/create` - создание темы
+ * `/admin/topics/:book/update` - редактирование темы
+ * `/admin/topics/:book/delete` - удаление темы
+ * Пользователи
+ * `/admin/users` - список пользователей
+ * `/admin/users/:user` - пользователь
\ No newline at end of file
diff --git a/admin/controllers/book.js b/admin/controllers/book.js
index 0d47a25..0a86156 100644
--- a/admin/controllers/book.js
+++ b/admin/controllers/book.js
@@ -1,4 +1,4 @@
-const { book: Book } = require('../../models');
+const { Book} = require('../../shared/models');
module.exports = {
findBook(req, res, next, id) {
@@ -17,6 +17,7 @@ module.exports = {
.catch(next);
},
+ // GET /admin/books
showIndexPage(req, res, next) {
Book.find()
.then(books => {
@@ -27,36 +28,44 @@ module.exports = {
.catch(next);
},
+ // GET /admin/books/create
showCreatePage(req, res) {
res.render('books/form', {
- book: new Book()
+ book: new Book(),
+ topics: req.topics
});
},
+ // GET /admin/books/:book/update
showUpdatePage(req, res) {
res.render('books/form', {
- book: req.book
+ book: req.book,
+ topics: req.topics
});
},
+ // GET /admin/books/:book/update
showDeletePage(req, res) {
res.render('books/delete', {
book: req.book
});
},
+ // POST /admin/books
createBook(req, res, next) {
Book.create(req.body)
.then(() => res.redirect('/admin/books'))
.catch(next);
},
+ // POST /admin/books/:book/update
updateBook(req, res, next) {
- Book.findOneAndUpdate({ _id: req.topic.id }, req.body)
- .then(topic => res.redirect(`/admin/books/${topic.id}/update`))
+ Book.findOneAndUpdate({ _id: req.book.id }, Book.validateBody(req.body), { new: true })
+ .then(book => res.redirect(`/admin/books/${book.id}/update`))
.catch(next);
},
+ // POST /admin/books/:book/update
deleteBook(req, res, next) {
req.book.remove()
.then(() => res.redirect('/admin/books'))
diff --git a/admin/controllers/home.js b/admin/controllers/home.js
index 31dcaa2..172a2eb 100644
--- a/admin/controllers/home.js
+++ b/admin/controllers/home.js
@@ -1,5 +1,7 @@
module.exports = {
showIndexPage(req, res) {
-
+ res.render('index', {
+ id: 'admin'
+ });
}
};
\ No newline at end of file
diff --git a/admin/controllers/index.js b/admin/controllers/index.js
index 697d939..dd1ab34 100644
--- a/admin/controllers/index.js
+++ b/admin/controllers/index.js
@@ -1,12 +1,5 @@
-const fs = require('fs');
-const path = require('path');
-
-let index = path.basename(__filename);
-let files = fs.readdirSync(__dirname);
-
-for (let file of files) {
- if (file !== index) {
- let name = path.basename(file, '.js');
- module.exports[name] = require(`./${file}`);
- }
-}
\ No newline at end of file
+module.exports = {
+ book: require('./book'),
+ home: require('./home'),
+ topic: require('./topic')
+};
\ No newline at end of file
diff --git a/admin/controllers/topic.js b/admin/controllers/topic.js
index 88300ab..17cf85e 100644
--- a/admin/controllers/topic.js
+++ b/admin/controllers/topic.js
@@ -1,6 +1,16 @@
-const { topic: Topic } = require('../../models');
+const { Topic } = require('../../shared/models');
module.exports = {
+ findTopics(req, res, next) {
+ Topic.find()
+ .then(topics => {
+ req.topics = topics;
+
+ next();
+ })
+ .catch(next);
+ },
+
findTopic(req, res, next, id) {
Topic.findById(id)
.then(topic => {
diff --git a/admin/index.js b/admin/index.js
index 5e6fad9..9268dfe 100644
--- a/admin/index.js
+++ b/admin/index.js
@@ -1,10 +1,11 @@
const express = require('express');
const path = require('path');
-const admin = express();
-
+const middleware = require('./middleware');
const routers = require('./routers');
+const admin = express();
+
admin.set('views', path.join(__dirname, 'views'));
admin.set('view engine', 'pug');
@@ -12,6 +13,8 @@ admin.on('mount', server => {
admin.locals = Object.assign(server.locals, admin.locals);
});
+admin.use(middleware.auth.allowAdmin);
+
admin.use('/', routers.home);
admin.use('/books', routers.book);
admin.use('/topics', routers.topic);
diff --git a/admin/middleware/auth.js b/admin/middleware/auth.js
new file mode 100644
index 0000000..3b1bbac
--- /dev/null
+++ b/admin/middleware/auth.js
@@ -0,0 +1,9 @@
+const { NotFoundError } = require('../../shared/utils/error');
+
+module.exports = {
+ allowAdmin(req, res, next) {
+ if (req.user.isAdmin) return next();
+
+ next(new NotFoundError());
+ }
+};
\ No newline at end of file
diff --git a/admin/middleware/index.js b/admin/middleware/index.js
new file mode 100644
index 0000000..0652a05
--- /dev/null
+++ b/admin/middleware/index.js
@@ -0,0 +1,3 @@
+module.exports = {
+ auth: require('./auth')
+};
\ No newline at end of file
diff --git a/admin/routers/book.js b/admin/routers/book.js
index 73056e5..847d77c 100644
--- a/admin/routers/book.js
+++ b/admin/routers/book.js
@@ -1,21 +1,30 @@
const router = require('express').Router();
-const { book: controller } = require('../controllers');
+const {
+ book: bookController,
+ topic: topicController
+} = require('../controllers');
-router.param('book', controller.findBook);
+router.param('book', bookController.findBook);
-router.get('/', controller.showIndexPage);
+router.get('/', bookController.showIndexPage);
router.route('/create')
- .get(controller.showCreatePage)
- .post(controller.createBook);
+ .get(
+ topicController.findTopics,
+ bookController.showCreatePage
+ )
+ .post(bookController.createBook);
router.route('/:book/update')
- .get(controller.showUpdatePage)
- .post(controller.updateBook);
+ .get(
+ topicController.findTopics,
+ bookController.showUpdatePage
+ )
+ .post(bookController.updateBook);
router.route('/:book/delete')
- .get(controller.showDeletePage)
- .post(controller.deleteBook);
+ .get(bookController.showDeletePage)
+ .post(bookController.deleteBook);
module.exports = router;
\ No newline at end of file
diff --git a/admin/routers/home.js b/admin/routers/home.js
index 2fc5adf..f42d3b3 100644
--- a/admin/routers/home.js
+++ b/admin/routers/home.js
@@ -1,7 +1,7 @@
const router = require('express').Router();
-router.get('/', (req, res) => {
- res.render('index', {});
-});
+const { home: homeController } = require('../controllers');
+
+router.get('/', homeController.showIndexPage);
module.exports = router;
\ No newline at end of file
diff --git a/admin/routers/index.js b/admin/routers/index.js
index 697d939..dd1ab34 100644
--- a/admin/routers/index.js
+++ b/admin/routers/index.js
@@ -1,12 +1,5 @@
-const fs = require('fs');
-const path = require('path');
-
-let index = path.basename(__filename);
-let files = fs.readdirSync(__dirname);
-
-for (let file of files) {
- if (file !== index) {
- let name = path.basename(file, '.js');
- module.exports[name] = require(`./${file}`);
- }
-}
\ No newline at end of file
+module.exports = {
+ book: require('./book'),
+ home: require('./home'),
+ topic: require('./topic')
+};
\ No newline at end of file
diff --git a/admin/routers/topic.js b/admin/routers/topic.js
index c888057..4588095 100644
--- a/admin/routers/topic.js
+++ b/admin/routers/topic.js
@@ -1,21 +1,21 @@
const router = require('express').Router();
-const { topic: controller } = require('../controllers');
+const { topic: topicController } = require('../controllers');
-router.param('topic', controller.findTopic);
+router.param('topic', topicController.findTopic);
-router.get('/', controller.showIndexPage);
+router.get('/', topicController.showIndexPage);
router.route('/create')
- .get(controller.showCreatePage)
- .post(controller.createTopic);
+ .get(topicController.showCreatePage)
+ .post(topicController.createTopic);
router.route('/:topic/update')
- .get(controller.showUpdatePage)
- .post(controller.updateTopic);
+ .get(topicController.showUpdatePage)
+ .post(topicController.updateTopic);
router.route('/:topic/delete')
- .get(controller.showDeletePage)
- .post(controller.deleteTopic);
+ .get(topicController.showDeletePage)
+ .post(topicController.deleteTopic);
module.exports = router;
\ No newline at end of file
diff --git a/admin/views/_layout.pug b/admin/views/_layout.pug
index 4eb238e..4403539 100644
--- a/admin/views/_layout.pug
+++ b/admin/views/_layout.pug
@@ -1,5 +1,6 @@
extends /_layout
+include /_mixins/form
include /_mixins/mdc/index
block content
diff --git a/admin/views/books/delete.pug b/admin/views/books/delete.pug
new file mode 100644
index 0000000..4ca0b6d
--- /dev/null
+++ b/admin/views/books/delete.pug
@@ -0,0 +1,7 @@
+extends ../_layout
+
+block main
+ +form(method='post')
+ p Вы уверены что хотите удалить книгу "#{book.title}"
+ +mdc-button('Нет')(href='/admin/books')
+ +mdc-button('Да')(type='submit')
\ No newline at end of file
diff --git a/admin/views/books/form.pug b/admin/views/books/form.pug
new file mode 100644
index 0000000..36a0bce
--- /dev/null
+++ b/admin/views/books/form.pug
@@ -0,0 +1,41 @@
+extends ../_layout
+
+block main
+ +form(method='post')
+ +mdc-text-field('title', 'Название', book.title)(required)
+ +mdc-text-field('slug', 'Слаг', book.slug)(required)
+ +mdc-text-field('authors', 'Авторы', book.authors.join(', '))(required)
+
+ select(name='publishers')
+ option(value='orielly') O'Reilly
+ option(value='manning') Manning
+ option(value='microsoft') Microsoft Press
+
+ +mdc-text-field('date', 'Дата', book.date.format('YYYY-MM-DD'))(type='date')
+ +mdc-text-field('edition', 'Издание', book.edition)(type='number')
+ +mdc-text-field('pages', 'Страницы', book.pages)(type='number')
+
+ select(name='language')
+ for language in LANGUAGES
+ option(value=language.value selected=(book.language === language.value))= language.title
+
+ select(name='level')
+ option(value='beg' selected=(book.level === 'beg')) Легкий
+ option(value='int' selected=(book.level === 'int')) Средний
+ option(value='adv' selected=(book.level === 'adv')) Сложный
+
+ select(name='topics' multiple)
+ for topic in topics
+ option(value=topic.id selected=(book.topics.includes(topic.id)))= topic.title
+
+ +mdc-text-field('tags', 'Теги', book.tags.join(', '))
+
+ +mdc-text-field('url', 'Ссылка', book.url)
+ +mdc-text-field('imageUrl', 'Ссылка', book.imageUrl)
+
+ textarea(name='description' placeholder='Описание')= book.description
+ textarea(name='contents' placeholder='Описание')= book.contents
+
+ +mdc-button(book._id ? 'Сохранить' : 'Создать')(type='submit' raised)
+ if book._id
+ +mdc-button('Удалить')(href=`/admin/books/${book._id}/delete`)
\ No newline at end of file
diff --git a/admin/views/books/index.pug b/admin/views/books/index.pug
index 47e8c71..f39fc5a 100644
--- a/admin/views/books/index.pug
+++ b/admin/views/books/index.pug
@@ -1 +1,14 @@
-extends ../_layout
\ No newline at end of file
+extends ../_layout
+
+block main
+ ul.mdc-list
+ for book in books
+ li.mdc-list-item
+ = book.title
+ a.mdc-list-item__meta.material-icons(href=`/admin/books/${book.id}/update`) edit
+ a.mdc-list-item__meta.material-icons(href=`/admin/books/${book.id}/delete`) delete
+ else
+ p Нет книг
+
+ a(href='/admin/books/create').mdc-fab
+ i.mdc-fab__icon.material-icons add
\ No newline at end of file
diff --git a/admin/views/index.pug b/admin/views/index.pug
index ab7c278..3952ac3 100644
--- a/admin/views/index.pug
+++ b/admin/views/index.pug
@@ -1 +1 @@
-extends _layout
\ No newline at end of file
+extends /_layout
\ No newline at end of file
diff --git a/admin/views/topics/delete.pug b/admin/views/topics/delete.pug
index f47b7b5..7755b98 100644
--- a/admin/views/topics/delete.pug
+++ b/admin/views/topics/delete.pug
@@ -1,7 +1,7 @@
extends ../_layout
block main
- form(method='post')
+ +form(method='post')
p Вы уверены что хотите удалить тему "#{topic.title}"
+mdc-button('Нет')(href='/admin/topics')
+mdc-button('Да')(type='submit')
\ No newline at end of file
diff --git a/admin/views/topics/form.pug b/admin/views/topics/form.pug
index bee41be..a5a926a 100644
--- a/admin/views/topics/form.pug
+++ b/admin/views/topics/form.pug
@@ -1,11 +1,10 @@
extends ../_layout
block main
- form(method='post')
- input(type='hidden' name='secret_string' value='qwerty')
+ +form(method='post')
if !topic._id
- +mdc-text-field('id', topic._id)(placeholder='ID' required)
- +mdc-text-field('title', topic.title)(placeholder='Название' required)
+ +mdc-text-field('id', 'ID', topic._id)(required)
+ +mdc-text-field('title', 'Название', topic.title)(required)
+mdc-button(topic._id ? 'Сохранить' : 'Создать')(type='submit' raised)
if topic._id
diff --git a/admin/views/topics/index.pug b/admin/views/topics/index.pug
index b6dcbbe..9d6bbef 100644
--- a/admin/views/topics/index.pug
+++ b/admin/views/topics/index.pug
@@ -8,4 +8,7 @@ block main
= topic.title
a.mdc-list-item__meta.material-icons(href=`/admin/topics/${topic._id}/update`) edit
else
- p Нет топиков
\ No newline at end of file
+ p Нет топиков
+
+ a(href='/admin/topics/create').mdc-fab
+ i.mdc-fab__icon.material-icons add
\ No newline at end of file
diff --git a/admin/views/users/index.pug b/admin/views/users/index.pug
new file mode 100644
index 0000000..692a88e
--- /dev/null
+++ b/admin/views/users/index.pug
@@ -0,0 +1,11 @@
+extends ../_layout
+
+block main
+ ul.mdc-list.mdc-list--avatar-list
+ for user in users
+ li.mdc-list-item
+ img.mdc-list-item__graphic(src=user.image)
+ = user.title
+ a.mdc-list-item__meta.material-icons(href=`/admin/users/${user._id}/delete`) delete
+ else
+ p Нет топиков
\ No newline at end of file
diff --git a/api/controllers/book.js b/api/controllers/book.js
new file mode 100644
index 0000000..8414706
--- /dev/null
+++ b/api/controllers/book.js
@@ -0,0 +1,62 @@
+const { Book } = require('../../shared/models');
+
+module.exports = {
+ books: {
+ // GET /api/books
+ get(req, res, next) {
+ Book.find()
+ .then(books => res.status(200).json(books))
+ .catch(next);
+ },
+
+ // POST /api/books
+ post(req, res, next) {
+ Book.create(req.body)
+ .then(book => res.status(201).json(book))
+ .catch(next);
+ }
+ },
+
+ book: {
+ find(req, res, next, id) {
+ Book.findById(id)
+ .then(book => {
+ if (!book) return res.sendStatus(404);
+ req.book = book;
+ next();
+ })
+ .catch(next);
+ },
+
+ // GET /api/books/:id
+ get(req, res) {
+ res.send(req.book);
+ },
+
+ // PUT /api/books/:id
+ put(req, res, next) {
+ req.book = Object.assign(req.book, req.body);
+
+ req.book.save()
+ .then(book => res.status(201).json(book))
+ .catch(next);
+ },
+
+ // DELETE /api/books/:id
+ delete(req, res, next) {
+ req.book.remove()
+ .then(() => res.sendStatus(204))
+ .catch(next);
+ },
+
+ likes: {
+ put(req, res, next) {
+ req.book.likes += 1;
+
+ req.book.save()
+ .then(book => res.status(201).json(book.likes))
+ .catch(next);
+ }
+ }
+ }
+};
\ No newline at end of file
diff --git a/api/controllers/index.js b/api/controllers/index.js
new file mode 100644
index 0000000..dd2a9b7
--- /dev/null
+++ b/api/controllers/index.js
@@ -0,0 +1,3 @@
+module.exports = {
+ book: require('./book')
+};
\ No newline at end of file
diff --git a/api/index.js b/api/index.js
new file mode 100644
index 0000000..f4075e6
--- /dev/null
+++ b/api/index.js
@@ -0,0 +1,29 @@
+const express = require('express');
+const passport = require('passport');
+const cache = require('apicache').middleware;
+const RateLimit = require('express-rate-limit');
+const cors = require('cors');
+
+const api = express();
+
+const limit = new RateLimit({
+ windowMs: 60 * 1000, // 15 minutes
+ max: 1, // limit each IP to 100 requests per windowMs
+ delayMs: 0 // disable delaying - full speed until the max limit is reached
+});
+
+const routers = require('./routers');
+
+api.use(cors());
+
+api.use(routers.auth);
+api.use(passport.authenticate('jwt', { session: false }));
+api.use(limit);
+api.use(cache('1 minute'));
+api.use('/books', cache('1 minute'), routers.book);
+
+api.use((error, req, res, next) => {
+ res.status(500).json(error);
+});
+
+module.exports = api;
\ No newline at end of file
diff --git a/api/routers/auth.js b/api/routers/auth.js
new file mode 100644
index 0000000..782830c
--- /dev/null
+++ b/api/routers/auth.js
@@ -0,0 +1,23 @@
+const router = require('express').Router();
+const jwt = require('jwt-simple');
+
+const { jwtSecret } = require('../../shared/config');
+const { User } = require('../../shared/models');
+
+router.post('/token', (req, res, next) => {
+ if (!req.body.email || !req.body.password) return res.sendStatus(401);
+
+ User.findOne({ email: req.body.email })
+ .then(user => {
+ if (!user) return res.sendStatus(401);
+ if (!user.isCorrectPassword(req.body.password)) return res.sendStatus(201);
+
+ let payload = { id: user.id };
+ let token = jwt.encode(payload, jwtSecret);
+
+ res.json({ token });
+ })
+ .catch(next);
+});
+
+module.exports = router;
\ No newline at end of file
diff --git a/api/routers/book.js b/api/routers/book.js
new file mode 100644
index 0000000..11f59d8
--- /dev/null
+++ b/api/routers/book.js
@@ -0,0 +1,19 @@
+const router = require('express').Router();
+
+const { book: bookController } = require('../controllers');
+
+router.param('id', bookController.book.find);
+
+router.route('/')
+ .get(bookController.books.get)
+ .post(bookController.books.post);
+
+router.route('/:id')
+ .get(bookController.book.get)
+ .put(bookController.book.put)
+ .delete(bookController.book.delete);
+
+router.route('/:id/likes')
+ .put(bookController.book.likes.put);
+
+module.exports = router;
\ No newline at end of file
diff --git a/api/routers/index.js b/api/routers/index.js
new file mode 100644
index 0000000..b4a9295
--- /dev/null
+++ b/api/routers/index.js
@@ -0,0 +1,4 @@
+module.exports = {
+ auth: require('./auth'),
+ book: require('./book')
+};
\ No newline at end of file
diff --git a/client/index.html b/client/index.html
new file mode 100644
index 0000000..f3552b7
--- /dev/null
+++ b/client/index.html
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+ Document
+
+
+
+
+
\ No newline at end of file
diff --git a/client/package-lock.json b/client/package-lock.json
new file mode 100644
index 0000000..0194da5
--- /dev/null
+++ b/client/package-lock.json
@@ -0,0 +1,165 @@
+{
+ "name": "client",
+ "version": "1.0.0",
+ "lockfileVersion": 1,
+ "requires": true,
+ "dependencies": {
+ "async": {
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
+ "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo="
+ },
+ "colors": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz",
+ "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs="
+ },
+ "corser": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz",
+ "integrity": "sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c="
+ },
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "ecstatic": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/ecstatic/-/ecstatic-3.2.0.tgz",
+ "integrity": "sha512-Goilx/2cfU9vvfQjgtNgc2VmJAD8CasQ6rZDqCd2u4Hsyd/qFET6nBf60jiHodevR3nl3IGzNKtrzPXWP88utQ==",
+ "requires": {
+ "he": "1.1.1",
+ "mime": "1.6.0",
+ "minimist": "1.2.0",
+ "url-join": "2.0.5"
+ }
+ },
+ "eventemitter3": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-1.2.0.tgz",
+ "integrity": "sha1-HIaZHYFq0eUEdQ5zh0Ik7PO+xQg="
+ },
+ "he": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz",
+ "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0="
+ },
+ "http-proxy": {
+ "version": "1.16.2",
+ "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.16.2.tgz",
+ "integrity": "sha1-Bt/ykpUr9k2+hHH6nfcwZtTzd0I=",
+ "requires": {
+ "eventemitter3": "1.2.0",
+ "requires-port": "1.0.0"
+ }
+ },
+ "http-server": {
+ "version": "0.11.1",
+ "resolved": "https://registry.npmjs.org/http-server/-/http-server-0.11.1.tgz",
+ "integrity": "sha512-6JeGDGoujJLmhjiRGlt8yK8Z9Kl0vnl/dQoQZlc4oeqaUoAKQg94NILLfrY3oWzSyFaQCVNTcKE5PZ3cH8VP9w==",
+ "requires": {
+ "colors": "1.0.3",
+ "corser": "2.0.1",
+ "ecstatic": "3.2.0",
+ "http-proxy": "1.16.2",
+ "opener": "1.4.3",
+ "optimist": "0.6.1",
+ "portfinder": "1.0.13",
+ "union": "0.4.6"
+ }
+ },
+ "mime": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
+ },
+ "minimist": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
+ },
+ "mkdirp": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
+ "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
+ "requires": {
+ "minimist": "0.0.8"
+ },
+ "dependencies": {
+ "minimist": {
+ "version": "0.0.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
+ "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
+ }
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+ },
+ "opener": {
+ "version": "1.4.3",
+ "resolved": "https://registry.npmjs.org/opener/-/opener-1.4.3.tgz",
+ "integrity": "sha1-XG2ixdflgx6P+jlklQ+NZnSskLg="
+ },
+ "optimist": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
+ "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",
+ "requires": {
+ "minimist": "0.0.10",
+ "wordwrap": "0.0.3"
+ },
+ "dependencies": {
+ "minimist": {
+ "version": "0.0.10",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
+ "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8="
+ }
+ }
+ },
+ "portfinder": {
+ "version": "1.0.13",
+ "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.13.tgz",
+ "integrity": "sha1-uzLs2HwnEErm7kS1o8y/Drsa7ek=",
+ "requires": {
+ "async": "1.5.2",
+ "debug": "2.6.9",
+ "mkdirp": "0.5.1"
+ }
+ },
+ "qs": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-2.3.3.tgz",
+ "integrity": "sha1-6eha2+ddoLvkyOBHaghikPhjtAQ="
+ },
+ "requires-port": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
+ "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8="
+ },
+ "union": {
+ "version": "0.4.6",
+ "resolved": "https://registry.npmjs.org/union/-/union-0.4.6.tgz",
+ "integrity": "sha1-GY+9rrolTniLDvy2MLwR8kopWeA=",
+ "requires": {
+ "qs": "2.3.3"
+ }
+ },
+ "url-join": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/url-join/-/url-join-2.0.5.tgz",
+ "integrity": "sha1-WvIvGMBSoACkjXuCxenC4v7tpyg="
+ },
+ "wordwrap": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
+ "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc="
+ }
+ }
+}
diff --git a/client/package.json b/client/package.json
new file mode 100644
index 0000000..d4273c1
--- /dev/null
+++ b/client/package.json
@@ -0,0 +1,15 @@
+{
+ "name": "client",
+ "version": "1.0.0",
+ "description": "",
+ "main": "index.js",
+ "scripts": {
+ "start": "http-server"
+ },
+ "keywords": [],
+ "author": "",
+ "license": "ISC",
+ "dependencies": {
+ "http-server": "^0.11.1"
+ }
+}
diff --git a/config/index.js b/config/index.js
deleted file mode 100644
index 14e9050..0000000
--- a/config/index.js
+++ /dev/null
@@ -1,17 +0,0 @@
-const path = require('path');
-
-module.exports = {
- version: process.env.APP_VERSION,
- env: process.env.NODE_ENV,
- port: process.env.PORT || 3000,
- sessionSecret: 'HacJmB3ma6crKKtK',
- mongodbUri: {
- development: 'mongodb://localhost:27017/codedojo'
- },
- paths: {
- views: path.resolve(__dirname, '..', 'views'),
- public: path.resolve(__dirname, '..', 'public'),
- favicon: path.resolve(__dirname, '..', 'public', 'favicon.ico'),
- lib: path.resolve(__dirname, '..', 'node_modules')
- }
-};
\ No newline at end of file
diff --git a/controllers/auth.js b/controllers/auth.js
deleted file mode 100644
index 91208ef..0000000
--- a/controllers/auth.js
+++ /dev/null
@@ -1,65 +0,0 @@
-const { user: User } = require('../models');
-
-module.exports = {
- // GET /auth/register
- showRegisterPage(req, res) {
- res.render('auth/register', {
- id: 'register',
- className: 'auth-page',
- title: 'Регистрация'
- });
- },
-
- // GET /auth/login
- showLoginPage(req, res) {
- res.render('auth/login', {
- id: 'login',
- className: 'auth-page',
- title: 'Вход'
- });
- },
-
- // POST /auth/register
- register(req, res, next) {
- let { email, password, confirmPassword } = req.body;
-
- if (!email || !password) return next(new Error('Необходимо ввести email и пароль'));
- else if (password !== confirmPassword) return next (new Error('Пароли не совпадают'));
-
- User.create({ email, password })
- .then(user => {
- req.session.userId = user.id;
- res.redirect('/profile');
- })
- .catch(next);
- },
-
- // POST /auth/login
- login(req, res, next) {
- let { email, password } = req.body;
-
- if (!email || !password) {
- let error = new Error('Необходимо ввести логин и пароль');
- error.status = 401;
- return next(error);
- }
-
- User.authenticate(email, password)
- .then(user => {
- req.session.userId = user.id;
- res.redirect('/profile');
- })
- .catch(next);
- },
-
- // GET /auth/logout
- logout(req, res, next) {
- if (req.session) {
- req.session.destroy(error => {
- if (error) return next(error);
-
- res.redirect('/');
- });
- }
- }
-};
\ No newline at end of file
diff --git a/controllers/search.js b/controllers/search.js
deleted file mode 100644
index db32917..0000000
--- a/controllers/search.js
+++ /dev/null
@@ -1,6 +0,0 @@
-module.exports = {
- // GET /search?query=value
- showResults(req, res) {
- res.render('search', {});
- }
-};
\ No newline at end of file
diff --git a/gulpfile.js b/gulpfile.js
index e1647d8..d655ae0 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -5,14 +5,14 @@ const rename = require('gulp-rename');
const paths = {
vendor: './node_modules/',
- src: './styles/',
- dist: './public/css/'
+ src: './shared/styles/',
+ dist: './shared/public/css/'
};
gulp.task('sass', () => {
gulp.src(`${paths.src}index.scss`)
.pipe(sass({
- includePaths: [paths.vendor]
+ includePaths: [paths.vendor, './shared/styles']
}).on('error', sass.logError))
.pipe(autoprefixer({
browsers: ['last 2 versions', 'ie >= 9']
@@ -21,5 +21,6 @@ gulp.task('sass', () => {
.pipe(gulp.dest(paths.dist));
});
-gulp.task('watch:sass', () =>
- gulp.watch(paths.src + '**/*.scss', ['sass']));
\ No newline at end of file
+gulp.task('watch:sass', () => {
+ gulp.watch(paths.src + '**/*.scss', ['sass']);
+});
\ No newline at end of file
diff --git a/index.js b/index.js
index 55a0f35..fd3f1c2 100644
--- a/index.js
+++ b/index.js
@@ -1,62 +1,16 @@
-const express = require('express');
-const logger = require('morgan');
-const favicon = require('serve-favicon');
-const session = require('express-session');
-const MongoStore = require('connect-mongo')(session);
-
-const db = require('./services/db');
-const config = require('./config');
-const { error, auth } = require('./middleware');
-const routers = require('./routers');
-const admin = require('./admin');
-
-const app = express();
-
-app.set('view engine', 'pug');
-app.set('views', config.paths.views);
-app.set('config', config);
-
-app.locals.version = config.version;
-app.locals.basedir = config.paths.views;
-
-app.use(express.static(config.paths.public));
-app.use('/lib', express.static(config.paths.lib));
-app.use(express.urlencoded({ extended: false }));
-
-app.use(favicon(config.paths.favicon));
-app.use(logger('dev'));
-app.use(express.urlencoded({ extended: false }));
-app.use(session({
- name: 'sessionId',
- secret: config.sessionSecret,
- resave: false,
- saveUninitialized: false,
- cookie: {
- httpOnly: true,
- // secure: true,
- signed: true,
- maxAge: 1000 * 60 * 60 * 24 * 3 // 3 days
- },
- store: new MongoStore({
- mongooseConnection: db.connection,
- ttl: 60 * 60 * 24 * 3, // 3 days
- touchAfter: 60 * 60 * 24 // 1 day
- })
-}));
-
-app.use(auth.findUser);
-
-app.use('/', routers.main);
-app.use('/auth', routers.auth);
-
-app.use(auth.authenticated);
-app.use('/profile', routers.profile);
-app.use('/books', routers.book);
-app.use('/topics', routers.topic);
-app.use('/search', routers.search);
-app.use('/admin', admin);
-
-app.use(error.notFound);
-app.use(app.get('env') === 'development' ? error.development : error.production);
-
-app.listen(config.port, () => console.log('Express:', config.port));
\ No newline at end of file
+const server = require('./server');
+const port = server.get('port');
+
+if (server.get('env') === 'development') {
+ const fs = require('fs');
+ const https = require('https');
+
+ const ssl = {
+ key: fs.readFileSync(__dirname + '/ssl/key.pem'),
+ cert: fs.readFileSync(__dirname + '/ssl/cert.crt')
+ };
+
+ https.createServer(ssl, server).listen(port, () => console.log('Express:', port));
+} else {
+ server.listen(port, () => console.log('Express:', port));
+}
\ No newline at end of file
diff --git a/main/controllers/auth.js b/main/controllers/auth.js
new file mode 100644
index 0000000..c864deb
--- /dev/null
+++ b/main/controllers/auth.js
@@ -0,0 +1,44 @@
+const { passport } = require('../../shared/services');
+
+module.exports = {
+ // GET /auth/register
+ showRegisterPage(req, res) {
+ res.render('auth/register', {
+ id: 'register',
+ className: 'auth-page',
+ title: 'Регистрация'
+ });
+ },
+
+ // GET /auth/login
+ showLoginPage(req, res) {
+ res.render('auth/login', {
+ id: 'login',
+ className: 'auth-page',
+ title: 'Вход'
+ });
+ },
+
+ // POST /auth/register
+ register: passport.authenticate('local-register', {
+ failureRedirect: '/auth/register',
+ successRedirect: '/user'
+ }),
+
+ // POST /auth/login
+ login: passport.authenticate('local-login', {
+ failureRedirect: '/auth/login',
+ successRedirect: '/user'
+ }),
+
+ // GET /auth/logout
+ logout(req, res, next) {
+ if (req.session) {
+ req.session.destroy(error => {
+ if (error) return next(error);
+
+ res.redirect('/');
+ });
+ }
+ }
+};
\ No newline at end of file
diff --git a/controllers/book.js b/main/controllers/book.js
similarity index 71%
rename from controllers/book.js
rename to main/controllers/book.js
index bd3f632..f929bd2 100644
--- a/controllers/book.js
+++ b/main/controllers/book.js
@@ -1,4 +1,4 @@
-const { book: Book, topic: Topic } = require('../models');
+const { Book, Topic } = require('../../shared/models');
module.exports = {
findBook(req, res, next, slug) {
@@ -75,6 +75,32 @@ module.exports = {
.catch(next);
},
+ // GET /books/search?query=value
+ showResults(req, res, next) {
+ let regex = new RegExp(req.query.query, 'gi');
+ let { skip = 0, limit = 0 } = req.query;
+
+ Book.find({
+ $or: [
+ { title: regex },
+ { authors: regex },
+ { topics: regex },
+ { tags: regex }
+ ]
+ })
+ .skip(Number(skip))
+ .limit(Number(limit))
+ .then(books => {
+ res.render('books', {
+ id: 'book-search',
+ title: `Результаты поиска по запрос: ${req.query.query}`,
+ query: req.query.query,
+ books
+ });
+ })
+ .catch(next);
+ },
+
// GET /books/:book
showBook(req, res) {
res.render('books/book', {
diff --git a/main/controllers/cart.js b/main/controllers/cart.js
new file mode 100644
index 0000000..c903995
--- /dev/null
+++ b/main/controllers/cart.js
@@ -0,0 +1,31 @@
+module.exports = {
+ // GET /
+ showCart(req, res, next) {
+ req.cart.populate('items')
+ .execPopulate()
+ .then(cart => {
+ res.render('cart', {
+ id: 'cart',
+ title: 'Корзина',
+ cart
+ });
+ })
+ .catch(next);
+ },
+
+ // POST /cart
+ addProduct(req, res) {
+ req.cart.addProduct(req.body.productId);
+ req.flash('success', 'Товар добавлен');
+
+ res.redirect('back');
+ },
+
+ // GET /cart/remove?productId=value
+ removeProduct(req, res) {
+ req.cart.removeProduct(req.query.productId);
+ req.flash('success', 'Товар удален');
+
+ res.redirect('back');
+ }
+};
\ No newline at end of file
diff --git a/main/controllers/index.js b/main/controllers/index.js
new file mode 100644
index 0000000..deeeb7c
--- /dev/null
+++ b/main/controllers/index.js
@@ -0,0 +1,8 @@
+module.exports = {
+ auth: require('./auth'),
+ book: require('./book'),
+ cart: require('./cart'),
+ main: require('./main'),
+ oauth: require('./oauth'),
+ topic: require('./topic')
+};
\ No newline at end of file
diff --git a/controllers/main.js b/main/controllers/main.js
similarity index 81%
rename from controllers/main.js
rename to main/controllers/main.js
index 8d7005b..ce7f3f0 100644
--- a/controllers/main.js
+++ b/main/controllers/main.js
@@ -1,6 +1,6 @@
module.exports = {
// GET /
- showMain(req, res, next) {
+ showMain(req, res) {
res.render('index', {
id: 'main',
title: 'CodeLibrary'
diff --git a/main/controllers/oauth.js b/main/controllers/oauth.js
new file mode 100644
index 0000000..6cdd9ff
--- /dev/null
+++ b/main/controllers/oauth.js
@@ -0,0 +1,11 @@
+const { passport } = require('../../shared/services');
+
+module.exports = {
+ github: {
+ authenticate: passport.authenticate('github'),
+ callback: passport.authenticate('github', {
+ failureRedirect: '/auth/login',
+ successRedirect: '/user'
+ })
+ }
+};
\ No newline at end of file
diff --git a/controllers/topic.js b/main/controllers/topic.js
similarity index 52%
rename from controllers/topic.js
rename to main/controllers/topic.js
index 074bd3a..f59266b 100644
--- a/controllers/topic.js
+++ b/main/controllers/topic.js
@@ -1,4 +1,4 @@
-const { topic: Topic } = require('../models');
+const { Topic } = require('../../shared/models');
module.exports = {
findTopics(req, res, next) {
@@ -11,5 +11,15 @@ module.exports = {
next();
})
.catch(next);
+ },
+
+ findTopic(req, res, next, id) {
+ Topic.findById(id)
+ .then(topic => {
+ topic.req = topic;
+
+ next();
+ })
+ .catch(next);
}
};
\ No newline at end of file
diff --git a/main/index.js b/main/index.js
new file mode 100644
index 0000000..2f2b71f
--- /dev/null
+++ b/main/index.js
@@ -0,0 +1,34 @@
+const express = require('express');
+const path = require('path');
+const csurf = require('csurf');
+
+const { csrf } = require('../shared/middleware');
+const middleware = require('./middleware');
+const routers = require('./routers');
+
+const main = express();
+
+main.set('views', path.join(__dirname, 'views'));
+main.set('view engine', 'pug');
+
+main.on('mount', server => {
+ main.locals = Object.assign(server.locals, main.locals);
+});
+
+main.use(csurf(), csrf);
+
+main.use((req, res, next) => {
+ res.locals.user = req.user;
+
+ next();
+});
+
+main.use('/', routers.main);
+main.use('/auth', routers.auth);
+main.use(middleware.auth.allowAuthenticated);
+main.use('/user', routers.user);
+main.use('/books', routers.book);
+main.use('/topics', routers.topic);
+main.use('/cart', routers.cart);
+
+module.exports = main;
\ No newline at end of file
diff --git a/main/middleware/auth.js b/main/middleware/auth.js
new file mode 100644
index 0000000..20fe157
--- /dev/null
+++ b/main/middleware/auth.js
@@ -0,0 +1,15 @@
+module.exports = {
+ allowAuthenticated(req, res, next) {
+ if (req.isAuthenticated()) return next();
+
+ req.flash('error', 'Для продолжения необходимо войти или зарегистрироваться');
+
+ res.status(403).redirect('/auth/login');
+ },
+
+ allowUnauthenticated(req, res, next) {
+ if (req.isUnauthenticated()) return next();
+
+ res.redirect('/books');
+ }
+};
\ No newline at end of file
diff --git a/main/middleware/index.js b/main/middleware/index.js
new file mode 100644
index 0000000..0652a05
--- /dev/null
+++ b/main/middleware/index.js
@@ -0,0 +1,3 @@
+module.exports = {
+ auth: require('./auth')
+};
\ No newline at end of file
diff --git a/main/routers/auth.js b/main/routers/auth.js
new file mode 100644
index 0000000..8a354b1
--- /dev/null
+++ b/main/routers/auth.js
@@ -0,0 +1,24 @@
+const router = require('express').Router();
+
+const { auth: authMiddleware } = require('../middleware');
+const {
+ auth: authController,
+ oauth: oauthController
+} = require('../controllers');
+
+router.route('/register')
+ .all(authMiddleware.allowUnauthenticated)
+ .get(authController.showRegisterPage)
+ .post(authController.register);
+
+router.route('/login')
+ .all(authMiddleware.allowUnauthenticated)
+ .get(authController.showLoginPage)
+ .post(authController.login);
+
+router.get('/github', oauthController.github.authenticate);
+router.get('/github/callback', oauthController.github.callback);
+
+router.get('/logout', authMiddleware.allowAuthenticated, authController.logout);
+
+module.exports = router;
\ No newline at end of file
diff --git a/routers/book.js b/main/routers/book.js
similarity index 89%
rename from routers/book.js
rename to main/routers/book.js
index 3b10d19..d83f88d 100644
--- a/routers/book.js
+++ b/main/routers/book.js
@@ -9,6 +9,7 @@ router.param('book', bookController.findBook);
router.get('/', bookController.showLatestBooks);
router.get('/new', bookController.showNewBooks);
router.get('/best', bookController.showBestBooks);
+router.get('/search', bookController.showResults);
router.get('/:book', bookController.showBook);
module.exports = router;
\ No newline at end of file
diff --git a/main/routers/cart.js b/main/routers/cart.js
new file mode 100644
index 0000000..40f5730
--- /dev/null
+++ b/main/routers/cart.js
@@ -0,0 +1,9 @@
+const router = require('express').Router();
+
+const { cart } = require('../controllers');
+
+router.get('/', cart.showCart);
+router.post('/', cart.addProduct);
+router.get('/remove', cart.removeProduct);
+
+module.exports = router;
\ No newline at end of file
diff --git a/main/routers/index.js b/main/routers/index.js
new file mode 100644
index 0000000..cdaa7e9
--- /dev/null
+++ b/main/routers/index.js
@@ -0,0 +1,8 @@
+module.exports = {
+ auth: require('./auth'),
+ book: require('./book'),
+ cart: require('./cart'),
+ main: require('./main'),
+ topic: require('./topic'),
+ user: require('./user')
+};
\ No newline at end of file
diff --git a/routers/main.js b/main/routers/main.js
similarity index 100%
rename from routers/main.js
rename to main/routers/main.js
diff --git a/routers/topic.js b/main/routers/topic.js
similarity index 100%
rename from routers/topic.js
rename to main/routers/topic.js
diff --git a/routers/profile.js b/main/routers/user.js
similarity index 76%
rename from routers/profile.js
rename to main/routers/user.js
index 3ed96c1..43ff37f 100644
--- a/routers/profile.js
+++ b/main/routers/user.js
@@ -1,8 +1,8 @@
const router = require('express').Router();
router.get('/', (req, res) => {
- res.render('profile', {
- id: 'profile',
+ res.render('user', {
+ id: 'user',
title: 'Профиль',
user: req.user
});
diff --git a/main/views/_includes/search-form.pug b/main/views/_includes/search-form.pug
new file mode 100644
index 0000000..5d71bc5
--- /dev/null
+++ b/main/views/_includes/search-form.pug
@@ -0,0 +1,3 @@
+form#search-form(method='get' action='/books/search')
+ +mdc-text-field('query', 'Поиск', value)(type='search')
+ +mdc-button('Найти')(type='submit')
\ No newline at end of file
diff --git a/views/_includes/sidenav.pug b/main/views/_includes/sidenav.pug
similarity index 100%
rename from views/_includes/sidenav.pug
rename to main/views/_includes/sidenav.pug
diff --git a/views/_includes/toolbar.pug b/main/views/_includes/toolbar.pug
similarity index 83%
rename from views/_includes/toolbar.pug
rename to main/views/_includes/toolbar.pug
index cd4af84..08c8f92 100644
--- a/views/_includes/toolbar.pug
+++ b/main/views/_includes/toolbar.pug
@@ -5,9 +5,11 @@ header.mdc-toolbar
section.mdc-toolbar__section.mdc-toolbar__serction--align-left.mdc-toolbar__section--shrink-to-fit
nav.mdc-tab-bar
+ a.mdc-tab(href='/books') Книги
+
unless user
a.mdc-tab(href='/auth/login') Войти
a.mdc-tab(href='/auth/register') Зарегистрироваться
else
- a.mdc-tab(href='/profile')= user.email
+ a.mdc-tab(href='/user')= user.email
a.mdc-tab(href='/auth/logout') Выйти
\ No newline at end of file
diff --git a/main/views/_layout.pug b/main/views/_layout.pug
new file mode 100644
index 0000000..bb0fb31
--- /dev/null
+++ b/main/views/_layout.pug
@@ -0,0 +1,6 @@
+extends /_layout
+
+include /_mixins/mdc/index
+
+block header
+ include _includes/toolbar
\ No newline at end of file
diff --git a/views/_mixins/book-card.pug b/main/views/_mixins/book-card.pug
similarity index 74%
rename from views/_mixins/book-card.pug
rename to main/views/_mixins/book-card.pug
index 9bcb394..8b58a98 100644
--- a/views/_mixins/book-card.pug
+++ b/main/views/_mixins/book-card.pug
@@ -14,5 +14,9 @@ mixin book-card(book)
button.mdc-button.mdc-button--compact.mdc-card__action
i.mdc-button__icon.material-icons thumb_up
span= book.likes
+ form(method='post' action='/cart')
+ input(type='hidden' name='productId' value=book.id)
+ button(type='submit').mdc-button.mdc-button--compact.mdc-card__action
+ i.mdc-button__icon.material-icons shopping_basket
a.mdc-button.mdc-button--compact.mdc-card__action(href=`/books/${book.slug}`) Подробнее
\ No newline at end of file
diff --git a/main/views/auth/login.pug b/main/views/auth/login.pug
new file mode 100644
index 0000000..566d0bf
--- /dev/null
+++ b/main/views/auth/login.pug
@@ -0,0 +1,22 @@
+extends ../_layout
+
+block header
+
+block content
+ main#main
+ form(id='login-form' class='auth-form' method='POST' action='/auth/login').mdc-card
+ input(type='hidden' name='_csrf' value=csrfToken)
+
+ header.mdc-card__primary
+ h1.mdc-card__title.mdc-card__title--large= title
+
+ section.mdc-card__supporting-text
+ div.mdc-text-field
+ input.mdc-text-field__input(type='email' name='email' placeholder='Электронная почта' required)
+ div.mdc-text-field
+ input.mdc-text-field__input(type='password' name='password' placeholder='Пароль' required)
+
+ footer.mdc-card__actions
+ button.mdc-button.mdc-card__action.mdc-button--raised.mdc-button--dense(type='submit') Войти
+ a.mdc-button.mdc-card__action.mdc-button--dense(href='/auth/github') GitHub
+ a.mdc-button.mdc-card__action.mdc-button--dense(href='/auth/register') Зарегистрироваться
\ No newline at end of file
diff --git a/main/views/auth/register.pug b/main/views/auth/register.pug
new file mode 100644
index 0000000..e830983
--- /dev/null
+++ b/main/views/auth/register.pug
@@ -0,0 +1,23 @@
+extends ../_layout
+
+block header
+
+block content
+ main#main
+ form(id='register-form' class='auth-form' method='POST' action='/auth/register').mdc-card
+ input(type='hidden' name='_csrf' value=csrfToken)
+
+ header.mdc-card__primary
+ h1.mdc-card__title.mdc-card__title--large= title
+
+ section.mdc-card__supporting-text
+ div.mdc-text-field
+ input.mdc-text-field__input(type='email' name='email' placeholder='Электронная почта' required)
+ div.mdc-text-field
+ input.mdc-text-field__input(type='password' name='password' placeholder='Пароль' required)
+ div.mdc-text-field
+ input.mdc-text-field__input(type='password' name='confirmPassword' placeholder='Подтвердите пароль' required)
+
+ footer.mdc-card__actions
+ button.mdc-button.mdc-card__action.mdc-button--raised.mdc-button--dense(type='submit') Зарегистрироваться
+ a.mdc-button.mdc-card__action.mdc-button--dense(href='/auth/login') Войти
\ No newline at end of file
diff --git a/main/views/books/_layout.pug b/main/views/books/_layout.pug
new file mode 100644
index 0000000..e996dc3
--- /dev/null
+++ b/main/views/books/_layout.pug
@@ -0,0 +1,10 @@
+extends ../_layout
+
+block content
+ section#content
+ include ../_includes/sidenav
+
+ div
+ include ../_includes/search-form
+
+ block main
\ No newline at end of file
diff --git a/views/books/book.pug b/main/views/books/book.pug
similarity index 97%
rename from views/books/book.pug
rename to main/views/books/book.pug
index 4584c57..928e472 100644
--- a/views/books/book.pug
+++ b/main/views/books/book.pug
@@ -1,10 +1,10 @@
-extends ../_layout
+extends _layout
block main
main#main
div.mdc-layout-grid
div.mdc-layout-grid__inner
- div.mdc-layout-grid__cell.mdc-layout-grid__cell--span-6
+ div.mdc-layout-grid__cell.mdc-layout-grid__cell--span-12
div.mdc-card.book-card
div.mdc-card__horizontal-block
header.mdc-card__primary
@@ -36,6 +36,7 @@ block main
section.mdc-card__supporting-text
h2.mdc-typography--title Описание
+
!= book.description
section.mdc-card__supporting-text
diff --git a/views/books/index.pug b/main/views/books/index.pug
similarity index 94%
rename from views/books/index.pug
rename to main/views/books/index.pug
index 3c4b956..ee02a81 100644
--- a/views/books/index.pug
+++ b/main/views/books/index.pug
@@ -1,4 +1,4 @@
-extends ../_layout
+extends _layout
include ../_mixins/book-card
diff --git a/main/views/cart/index.pug b/main/views/cart/index.pug
new file mode 100644
index 0000000..cf1667b
--- /dev/null
+++ b/main/views/cart/index.pug
@@ -0,0 +1,11 @@
+extends ../_layout
+
+block content
+ section#content
+ ul
+ for item in cart.items
+ li
+ span= item.title
+ |
+ a(href=`/cart/remove?productId=${item.id}`) Удалить
+ li Итого #{cart.calculateTotal()} руб.
\ No newline at end of file
diff --git a/main/views/index.pug b/main/views/index.pug
new file mode 100644
index 0000000..1998a08
--- /dev/null
+++ b/main/views/index.pug
@@ -0,0 +1,13 @@
+extends _layout
+
+block header
+
+block content
+ main#main
+ i.material-icons book
+ h1 CodeLibrary
+ p Библиотека разработчика
+
+ a.mdc-button.mdc-button--raised(href='/auth/login') Войти
+ | или
+ a.mdc-button.mdc-button--raised(href='/auth/register') Зарегистрироваться
\ No newline at end of file
diff --git a/main/views/user/index.pug b/main/views/user/index.pug
new file mode 100644
index 0000000..79e6b23
--- /dev/null
+++ b/main/views/user/index.pug
@@ -0,0 +1,8 @@
+extends ../_layout
+
+block content
+ main#main
+ if user.photo
+ img.user-photo(src=user.photo)
+ h1.user-name= user.displayName
+ p.user-email= user.email
\ No newline at end of file
diff --git a/middleware/auth.js b/middleware/auth.js
deleted file mode 100644
index 61bc81c..0000000
--- a/middleware/auth.js
+++ /dev/null
@@ -1,30 +0,0 @@
-const { user: User } = require('../models');
-
-module.exports = {
- findUser(req, res, next) {
- if (req.session) {
- User.findById(req.session.userId)
- .then(user => {
- req.user = user;
- res.locals.user = user;
-
- next();
- })
- .catch();
- } else {
- next();
- }
- },
-
- authenticated(req, res, next) {
- if (req.user) return next();
-
- res.status(403).redirect('/auth/login');
- },
-
- unauthenticated(req, res, next) {
- if (!req.user) return next();
-
- res.redirect('/books');
- }
-};
\ No newline at end of file
diff --git a/middleware/error.js b/middleware/error.js
deleted file mode 100644
index 922db5d..0000000
--- a/middleware/error.js
+++ /dev/null
@@ -1,26 +0,0 @@
-module.exports = {
- notFound(req, res, next) {
- let error = new Error('Не найдено');
- error.status = 404;
-
- next(error);
- },
-
- development(error, req, res, next) {
- console.error(error);
-
- res.render('error', {
- id: 'error',
- title: 'Ошибка',
- error
- });
- },
-
- production(error, req, res, next) {
- res.render('error', {
- id: 'error',
- title: 'Ошибка',
- message: error.message
- });
- }
-};
\ No newline at end of file
diff --git a/middleware/index.js b/middleware/index.js
deleted file mode 100644
index 697d939..0000000
--- a/middleware/index.js
+++ /dev/null
@@ -1,12 +0,0 @@
-const fs = require('fs');
-const path = require('path');
-
-let index = path.basename(__filename);
-let files = fs.readdirSync(__dirname);
-
-for (let file of files) {
- if (file !== index) {
- let name = path.basename(file, '.js');
- module.exports[name] = require(`./${file}`);
- }
-}
\ No newline at end of file
diff --git a/models/index.js b/models/index.js
deleted file mode 100644
index 697d939..0000000
--- a/models/index.js
+++ /dev/null
@@ -1,12 +0,0 @@
-const fs = require('fs');
-const path = require('path');
-
-let index = path.basename(__filename);
-let files = fs.readdirSync(__dirname);
-
-for (let file of files) {
- if (file !== index) {
- let name = path.basename(file, '.js');
- module.exports[name] = require(`./${file}`);
- }
-}
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index ba65e42..45d70b4 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -113,6 +113,19 @@
"resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
"integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU="
},
+ "amp": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/amp/-/amp-0.3.1.tgz",
+ "integrity": "sha1-at+NWKdPNh6CwfqNOJwHnhOfxH0="
+ },
+ "amp-message": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/amp-message/-/amp-message-0.1.2.tgz",
+ "integrity": "sha1-p48cmJlQh602GSpBKY5NtJ49/EU=",
+ "requires": {
+ "amp": "0.3.1"
+ }
+ },
"ansi-align": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz",
@@ -145,8 +158,7 @@
"ansi-styles": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
- "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
- "dev": true
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4="
},
"ansi-wrap": {
"version": "0.1.0",
@@ -164,6 +176,11 @@
"normalize-path": "2.1.1"
}
},
+ "apicache": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/apicache/-/apicache-1.2.0.tgz",
+ "integrity": "sha512-SwA6mpYhEEQ0cbDXFKxuVKcW9d1LS2AX3aJSX0gaWMWK8y3bXIQXcj77BqVlYKIlS3VY+PE+veyG7/AJA2x6yg=="
+ },
"aproba": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
@@ -188,7 +205,6 @@
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz",
"integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=",
- "dev": true,
"requires": {
"sprintf-js": "1.0.3"
}
@@ -205,14 +221,12 @@
"arr-flatten": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
- "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==",
- "dev": true
+ "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg=="
},
"arr-union": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz",
- "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=",
- "dev": true
+ "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ="
},
"array-differ": {
"version": "1.0.0",
@@ -289,8 +303,7 @@
"assign-symbols": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
- "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=",
- "dev": true
+ "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c="
},
"async": {
"version": "2.1.4",
@@ -303,8 +316,7 @@
"async-each": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz",
- "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=",
- "dev": true
+ "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0="
},
"async-foreach": {
"version": "0.1.3",
@@ -312,6 +324,15 @@
"integrity": "sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=",
"dev": true
},
+ "async-listener": {
+ "version": "0.6.9",
+ "resolved": "https://registry.npmjs.org/async-listener/-/async-listener-0.6.9.tgz",
+ "integrity": "sha512-E7Z2/QMs0EPt/o9wpYO/J3hmMCDdr1aVDS3ttlur5D5JlZtxhfuOwi4e7S8zbYIxA5qOOYdxfqGj97XAfdNvkQ==",
+ "requires": {
+ "semver": "5.4.1",
+ "shimmer": "1.2.0"
+ }
+ },
"asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
@@ -320,8 +341,7 @@
"atob": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/atob/-/atob-2.0.3.tgz",
- "integrity": "sha1-GcenYEc3dEaPILLS0DNyrX1Mv10=",
- "dev": true
+ "integrity": "sha1-GcenYEc3dEaPILLS0DNyrX1Mv10="
},
"autoprefixer": {
"version": "7.2.3",
@@ -392,7 +412,6 @@
"version": "0.11.2",
"resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz",
"integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==",
- "dev": true,
"requires": {
"cache-base": "1.0.1",
"class-utils": "0.3.5",
@@ -406,11 +425,15 @@
"isobject": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
- "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
- "dev": true
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
}
}
},
+ "base64url": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/base64url/-/base64url-2.0.0.tgz",
+ "integrity": "sha1-6sFuA+oUOO/5Qj1puqNiYu0fcLs="
+ },
"basic-auth": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.0.tgz",
@@ -453,8 +476,12 @@
"binary-extensions": {
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.11.0.tgz",
- "integrity": "sha1-RqoXUftqL5PuXmibsQh9SxTGwgU=",
- "dev": true
+ "integrity": "sha1-RqoXUftqL5PuXmibsQh9SxTGwgU="
+ },
+ "blessed": {
+ "version": "0.1.81",
+ "resolved": "https://registry.npmjs.org/blessed/-/blessed-0.1.81.tgz",
+ "integrity": "sha1-+WLWh+wsNpVwrnGvhDJW5tDKESk="
},
"block-stream": {
"version": "0.0.9",
@@ -492,6 +519,13 @@
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+ }
}
}
}
@@ -555,6 +589,11 @@
"resolved": "https://registry.npmjs.org/bson/-/bson-1.0.4.tgz",
"integrity": "sha1-k8ENOeqltYQVy8QFLz5T5WKwtyw="
},
+ "buffer-equal-constant-time": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
+ "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk="
+ },
"buffer-shims": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz",
@@ -575,7 +614,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
"integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==",
- "dev": true,
"requires": {
"collection-visit": "1.0.0",
"component-emitter": "1.2.1",
@@ -591,8 +629,7 @@
"isobject": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
- "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
- "dev": true
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
}
}
},
@@ -635,6 +672,11 @@
}
}
},
+ "camelize": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz",
+ "integrity": "sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs="
+ },
"caniuse-lite": {
"version": "1.0.30000784",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000784.tgz",
@@ -707,6 +749,11 @@
"integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=",
"dev": true
},
+ "charm": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/charm/-/charm-0.1.2.tgz",
+ "integrity": "sha1-BsIe7RobBq62dVPNxT4jJ0usIpY="
+ },
"chokidar": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz",
@@ -733,7 +780,6 @@
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.5.tgz",
"integrity": "sha1-F+eTEDdQ+WJ7IXbqNM/RtWWQPIA=",
- "dev": true,
"requires": {
"arr-union": "3.1.0",
"define-property": "0.2.5",
@@ -746,7 +792,6 @@
"version": "0.2.5",
"resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
"integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
- "dev": true,
"requires": {
"is-descriptor": "0.1.6"
}
@@ -755,7 +800,6 @@
"version": "0.1.6",
"resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
"integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
- "dev": true,
"requires": {
"is-accessor-descriptor": "0.1.6",
"is-data-descriptor": "0.1.4",
@@ -765,20 +809,17 @@
"isobject": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
- "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
- "dev": true
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
},
"kind-of": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
- "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
- "dev": true
+ "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw=="
},
"lazy-cache": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-2.0.2.tgz",
"integrity": "sha1-uRkKT5EzVGlIQIWfio9whNiCImQ=",
- "dev": true,
"requires": {
"set-getter": "0.1.0"
}
@@ -809,6 +850,36 @@
"restore-cursor": "2.0.0"
}
},
+ "cli-table-redemption": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/cli-table-redemption/-/cli-table-redemption-1.0.1.tgz",
+ "integrity": "sha512-SjVCciRyx01I4azo2K2rcc0NP/wOceXGzG1ZpYkEulbbIxDA/5YWv0oxG2HtQ4v8zPC6bgbRI7SbNaTZCxMNkg==",
+ "requires": {
+ "chalk": "1.1.3"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "requires": {
+ "ansi-styles": "2.2.1",
+ "escape-string-regexp": "1.0.5",
+ "has-ansi": "2.0.0",
+ "strip-ansi": "3.0.1",
+ "supports-color": "2.0.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "requires": {
+ "ansi-regex": "2.1.1"
+ }
+ }
+ }
+ },
"cli-width": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz",
@@ -835,8 +906,7 @@
"clone": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/clone/-/clone-1.0.3.tgz",
- "integrity": "sha1-KY1+IjFmD0DAA8LtMUDezz9TCF8=",
- "dev": true
+ "integrity": "sha1-KY1+IjFmD0DAA8LtMUDezz9TCF8="
},
"clone-stats": {
"version": "0.0.1",
@@ -858,7 +928,6 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
"integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=",
- "dev": true,
"requires": {
"map-visit": "1.0.0",
"object-visit": "1.0.1"
@@ -885,6 +954,12 @@
"integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==",
"dev": true
},
+ "colors": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz",
+ "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=",
+ "dev": true
+ },
"combined-stream": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz",
@@ -904,8 +979,7 @@
"component-emitter": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
- "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=",
- "dev": true
+ "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY="
},
"concat-map": {
"version": "0.0.1",
@@ -937,6 +1011,11 @@
"xdg-basedir": "3.0.0"
}
},
+ "connect-flash": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/connect-flash/-/connect-flash-0.1.1.tgz",
+ "integrity": "sha1-2GMPJtlaf4UfmVax6MxnMvO2qjA="
+ },
"connect-mongo": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/connect-mongo/-/connect-mongo-2.0.1.tgz",
@@ -1006,11 +1085,25 @@
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz",
"integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ="
},
+ "content-security-policy-builder": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/content-security-policy-builder/-/content-security-policy-builder-2.0.0.tgz",
+ "integrity": "sha512-j+Nhmj1yfZAikJLImCvPJFE29x/UuBi+/MWqggGGc515JKaZrjuei2RhULJmy0MsstW3E3htl002bwmBNMKr7w=="
+ },
"content-type": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
"integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
},
+ "continuation-local-storage": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/continuation-local-storage/-/continuation-local-storage-3.2.1.tgz",
+ "integrity": "sha512-jx44cconVqkCEEyLSKWwkvUXwO561jXMa3LPjTPsm5QR22PA0/mhe33FT4Xb5y74JDvt/Cq+5lm8S8rskLv9ZA==",
+ "requires": {
+ "async-listener": "0.6.9",
+ "emitter-listener": "1.1.1"
+ }
+ },
"cookie": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
@@ -1024,14 +1117,28 @@
"copy-descriptor": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
- "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=",
- "dev": true
+ "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40="
},
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
},
+ "cors": {
+ "version": "2.8.4",
+ "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.4.tgz",
+ "integrity": "sha1-K9OB8usgECAQXNUOpZ2mMJBpRoY=",
+ "requires": {
+ "object-assign": "4.1.1",
+ "vary": "1.1.2"
+ }
+ },
+ "corser": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz",
+ "integrity": "sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c=",
+ "dev": true
+ },
"crc": {
"version": "3.4.4",
"resolved": "https://registry.npmjs.org/crc/-/crc-3.4.4.tgz",
@@ -1046,6 +1153,14 @@
"capture-stack-trace": "1.0.0"
}
},
+ "cron": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/cron/-/cron-1.3.0.tgz",
+ "integrity": "sha512-K/SF7JlgMmNjcThWxkKvsHhey2EDB4CeOEWJ9aXWj3fbQJppsvTPIeyLdHfNq5IbbsMUUjRW1nr5dSO95f2E4w==",
+ "requires": {
+ "moment-timezone": "0.5.14"
+ }
+ },
"cross-spawn": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
@@ -1072,6 +1187,54 @@
"integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=",
"dev": true
},
+ "csrf": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/csrf/-/csrf-3.0.6.tgz",
+ "integrity": "sha1-thEg3c7q/JHnbtUxO7XAsmZ7cQo=",
+ "requires": {
+ "rndm": "1.2.0",
+ "tsscmp": "1.0.5",
+ "uid-safe": "2.1.4"
+ },
+ "dependencies": {
+ "uid-safe": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.4.tgz",
+ "integrity": "sha1-Otbzg2jG1MjHXsF2I/t5qh0HHYE=",
+ "requires": {
+ "random-bytes": "1.0.0"
+ }
+ }
+ }
+ },
+ "csurf": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/csurf/-/csurf-1.9.0.tgz",
+ "integrity": "sha1-SdLGkl/87Ht95VlZfBU/pTM2QTM=",
+ "requires": {
+ "cookie": "0.3.1",
+ "cookie-signature": "1.0.6",
+ "csrf": "3.0.6",
+ "http-errors": "1.5.1"
+ },
+ "dependencies": {
+ "http-errors": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.5.1.tgz",
+ "integrity": "sha1-eIwNLB3iyBuebowBhDtrl+uSB1A=",
+ "requires": {
+ "inherits": "2.0.3",
+ "setprototypeof": "1.0.2",
+ "statuses": "1.3.1"
+ }
+ },
+ "setprototypeof": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.2.tgz",
+ "integrity": "sha1-gaVSFB7BBLiOic44MQOtXGZWTQg="
+ }
+ }
+ },
"currently-unhandled": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",
@@ -1096,6 +1259,11 @@
}
}
},
+ "dasherize": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/dasherize/-/dasherize-2.0.0.tgz",
+ "integrity": "sha1-bYCcnNDPe7iVLYD8hPoT1H3bEwg="
+ },
"dateformat": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/dateformat/-/dateformat-2.2.0.tgz",
@@ -1106,9 +1274,15 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
- "dev": true,
"requires": {
"ms": "2.0.0"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+ }
}
},
"decamelize": {
@@ -1119,8 +1293,7 @@
"decode-uri-component": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
- "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
- "dev": true
+ "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU="
},
"deep-extend": {
"version": "0.4.2",
@@ -1133,11 +1306,18 @@
"integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=",
"dev": true
},
+ "deep-metrics": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/deep-metrics/-/deep-metrics-0.0.1.tgz",
+ "integrity": "sha512-732WmZgCWxOkf4QBvrCjPPuT6wTEzaGye/4JqYsU/sO0J53UNX4PBwK0JV262BZ5cxgLmKhU+NlrtKdPDgybkg==",
+ "requires": {
+ "semver": "5.4.1"
+ }
+ },
"defaults": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz",
"integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=",
- "dev": true,
"requires": {
"clone": "1.0.3"
}
@@ -1146,7 +1326,6 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
"integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
- "dev": true,
"requires": {
"is-descriptor": "1.0.1"
}
@@ -1198,6 +1377,11 @@
"integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=",
"dev": true
},
+ "dns-prefetch-control": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/dns-prefetch-control/-/dns-prefetch-control-0.1.0.tgz",
+ "integrity": "sha1-YN20V3dOF48flBXwyrsOhbCzALI="
+ },
"doctrine": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.0.2.tgz",
@@ -1212,6 +1396,11 @@
"resolved": "https://registry.npmjs.org/doctypes/-/doctypes-1.1.0.tgz",
"integrity": "sha1-6oCxBqh1OHdOijpKWv4pPeSJ4Kk="
},
+ "dont-sniff-mimetype": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/dont-sniff-mimetype/-/dont-sniff-mimetype-1.0.0.tgz",
+ "integrity": "sha1-WTKJDcn04vGeXrAqIAJuXl78j1g="
+ },
"dot-prop": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz",
@@ -1282,6 +1471,35 @@
"jsbn": "0.1.1"
}
},
+ "ecdsa-sig-formatter": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.9.tgz",
+ "integrity": "sha1-S8kmJ07Dtau1AW5+HWCSGsJisqE=",
+ "requires": {
+ "base64url": "2.0.0",
+ "safe-buffer": "5.1.1"
+ }
+ },
+ "ecstatic": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/ecstatic/-/ecstatic-3.2.0.tgz",
+ "integrity": "sha512-Goilx/2cfU9vvfQjgtNgc2VmJAD8CasQ6rZDqCd2u4Hsyd/qFET6nBf60jiHodevR3nl3IGzNKtrzPXWP88utQ==",
+ "dev": true,
+ "requires": {
+ "he": "1.1.1",
+ "mime": "1.4.1",
+ "minimist": "1.2.0",
+ "url-join": "2.0.5"
+ },
+ "dependencies": {
+ "minimist": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
+ "dev": true
+ }
+ }
+ },
"ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
@@ -1302,6 +1520,14 @@
"electron-releases": "2.1.0"
}
},
+ "emitter-listener": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/emitter-listener/-/emitter-listener-1.1.1.tgz",
+ "integrity": "sha1-6Lu+gkS8jg0LTvcc0UKUx/JBx+w=",
+ "requires": {
+ "shimmer": "1.2.0"
+ }
+ },
"encodeurl": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.1.tgz",
@@ -1346,11 +1572,15 @@
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
"integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
},
+ "escape-regexp": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/escape-regexp/-/escape-regexp-0.0.1.tgz",
+ "integrity": "sha1-9EvaEtRbvfnLf4Yu5+SCez3TIlQ="
+ },
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
- "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
- "dev": true
+ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
},
"eslint": {
"version": "4.13.1",
@@ -1474,6 +1704,17 @@
"through": "2.3.8"
}
},
+ "eventemitter2": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-1.0.5.tgz",
+ "integrity": "sha1-+YNhBRexc3wLncZDvsqTiTwE3xg="
+ },
+ "eventemitter3": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-1.2.0.tgz",
+ "integrity": "sha1-HIaZHYFq0eUEdQ5zh0Ik7PO+xQg=",
+ "dev": true
+ },
"execa": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz",
@@ -1516,6 +1757,11 @@
"homedir-polyfill": "1.0.1"
}
},
+ "expect-ct": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/expect-ct/-/expect-ct-0.1.0.tgz",
+ "integrity": "sha1-UnNWeN4YUwiQ2Ne5XwrGNkCVgJQ="
+ },
"express": {
"version": "4.16.2",
"resolved": "https://registry.npmjs.org/express/-/express-4.16.2.tgz",
@@ -1559,10 +1805,25 @@
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+ }
}
}
}
},
+ "express-rate-limit": {
+ "version": "2.11.0",
+ "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-2.11.0.tgz",
+ "integrity": "sha512-KMZayDxj3Wr7zYuwTuDZj5hMW0nhnyJVBVCwMEVKwMdW6CkYh4vnfnUbRJYhKC0v6UuIbPerwKY0dqWmEzFjKA==",
+ "requires": {
+ "defaults": "1.0.3"
+ }
+ },
"express-session": {
"version": "1.15.6",
"resolved": "https://registry.npmjs.org/express-session/-/express-session-1.15.6.tgz",
@@ -1585,6 +1846,13 @@
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+ }
}
}
}
@@ -1598,7 +1866,6 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
- "dev": true,
"requires": {
"is-extendable": "0.1.1"
}
@@ -1655,6 +1922,11 @@
"integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
"dev": true
},
+ "fclone": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/fclone/-/fclone-1.0.11.tgz",
+ "integrity": "sha1-EOhdo4v+p/xZk0HClu4ddyZu5kA="
+ },
"figures": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
@@ -1713,6 +1985,13 @@
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+ }
}
}
}
@@ -1783,6 +2062,14 @@
"dev": true,
"requires": {
"ms": "2.0.0"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ }
}
},
"expand-brackets": {
@@ -1976,8 +2263,7 @@
"for-in": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
- "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=",
- "dev": true
+ "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA="
},
"for-own": {
"version": "0.1.5",
@@ -2013,11 +2299,15 @@
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
"integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=",
- "dev": true,
"requires": {
"map-cache": "0.2.2"
}
},
+ "frameguard": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/frameguard/-/frameguard-3.0.0.tgz",
+ "integrity": "sha1-e8rUae57lukdEs6zlZx4I1qScuk="
+ },
"fresh": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
@@ -2154,8 +2444,7 @@
"get-value": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
- "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=",
- "dev": true
+ "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg="
},
"getpass": {
"version": "0.1.7",
@@ -2172,6 +2461,11 @@
}
}
},
+ "gkt": {
+ "version": "https://tgz.pm2.io/gkt-1.0.0.tgz",
+ "integrity": "sha1-QFUCsAfzGcP0cXXER0UnMA8qta0=",
+ "optional": true
+ },
"glob": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
@@ -2661,7 +2955,6 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
"integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
- "dev": true,
"requires": {
"ansi-regex": "2.1.1"
}
@@ -2690,7 +2983,6 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
"integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=",
- "dev": true,
"requires": {
"get-value": "2.0.6",
"has-values": "1.0.0",
@@ -2700,8 +2992,7 @@
"isobject": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
- "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
- "dev": true
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
}
}
},
@@ -2709,7 +3000,6 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz",
"integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=",
- "dev": true,
"requires": {
"is-number": "3.0.0",
"kind-of": "4.0.0"
@@ -2719,7 +3009,6 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
"integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
- "dev": true,
"requires": {
"kind-of": "3.2.2"
},
@@ -2728,7 +3017,6 @@
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
"integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
- "dev": true,
"requires": {
"is-buffer": "1.1.6"
}
@@ -2739,7 +3027,6 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
"integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=",
- "dev": true,
"requires": {
"is-buffer": "1.1.6"
}
@@ -2758,11 +3045,52 @@
"sntp": "1.0.9"
}
},
+ "he": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz",
+ "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=",
+ "dev": true
+ },
+ "helmet": {
+ "version": "3.11.0",
+ "resolved": "https://registry.npmjs.org/helmet/-/helmet-3.11.0.tgz",
+ "integrity": "sha512-Xqf6VXmjpZoyH4reGyeBCO5nHH0NVeRQnx23LFj6AK9ocPRgZJfSH6zZ8SvNO2tB+fKhsqy1RSjIjWHVvH1X+w==",
+ "requires": {
+ "dns-prefetch-control": "0.1.0",
+ "dont-sniff-mimetype": "1.0.0",
+ "expect-ct": "0.1.0",
+ "frameguard": "3.0.0",
+ "helmet-csp": "2.7.0",
+ "hide-powered-by": "1.0.0",
+ "hpkp": "2.0.0",
+ "hsts": "2.1.0",
+ "ienoopen": "1.0.0",
+ "nocache": "2.0.0",
+ "referrer-policy": "1.1.0",
+ "x-xss-protection": "1.0.0"
+ }
+ },
+ "helmet-csp": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/helmet-csp/-/helmet-csp-2.7.0.tgz",
+ "integrity": "sha512-IGIAkWnxjRbgMXFA2/kmDqSIrIaSfZ6vhMHlSHw7jm7Gm9nVVXqwJ2B1YEpYrJsLrqY+w2Bbimk7snux9+sZAw==",
+ "requires": {
+ "camelize": "1.0.0",
+ "content-security-policy-builder": "2.0.0",
+ "dasherize": "2.0.0",
+ "lodash.reduce": "4.6.0",
+ "platform": "1.3.5"
+ }
+ },
+ "hide-powered-by": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/hide-powered-by/-/hide-powered-by-1.0.0.tgz",
+ "integrity": "sha1-SoWtZYgfYoV/xwr3F0oRhNzM4ys="
+ },
"hoek": {
"version": "2.16.3",
"resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz",
- "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=",
- "dev": true
+ "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0="
},
"homedir-polyfill": {
"version": "1.0.1",
@@ -2779,6 +3107,16 @@
"integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg==",
"dev": true
},
+ "hpkp": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/hpkp/-/hpkp-2.0.0.tgz",
+ "integrity": "sha1-EOFCJk52IVpdMMROxD3mTe5tFnI="
+ },
+ "hsts": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/hsts/-/hsts-2.1.0.tgz",
+ "integrity": "sha512-zXhh/DqgrTXJ7erTN6Fh5k/xjMhDGXCqdYN3wvxUvGUQvnxcFfUd8E+6vLg/nk3ss1TYMb+DhRl25fYABioTvA=="
+ },
"http-errors": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz",
@@ -2797,6 +3135,32 @@
}
}
},
+ "http-proxy": {
+ "version": "1.16.2",
+ "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.16.2.tgz",
+ "integrity": "sha1-Bt/ykpUr9k2+hHH6nfcwZtTzd0I=",
+ "dev": true,
+ "requires": {
+ "eventemitter3": "1.2.0",
+ "requires-port": "1.0.0"
+ }
+ },
+ "http-server": {
+ "version": "0.11.1",
+ "resolved": "https://registry.npmjs.org/http-server/-/http-server-0.11.1.tgz",
+ "integrity": "sha512-6JeGDGoujJLmhjiRGlt8yK8Z9Kl0vnl/dQoQZlc4oeqaUoAKQg94NILLfrY3oWzSyFaQCVNTcKE5PZ3cH8VP9w==",
+ "dev": true,
+ "requires": {
+ "colors": "1.0.3",
+ "corser": "2.0.1",
+ "ecstatic": "3.2.0",
+ "http-proxy": "1.16.2",
+ "opener": "1.4.3",
+ "optimist": "0.6.1",
+ "portfinder": "1.0.13",
+ "union": "0.4.6"
+ }
+ },
"http-signature": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz",
@@ -2813,6 +3177,11 @@
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz",
"integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ=="
},
+ "ienoopen": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/ienoopen/-/ienoopen-1.0.0.tgz",
+ "integrity": "sha1-NGpCj0dKrI9QzzeE6i0PFvYr2ms="
+ },
"ignore": {
"version": "3.3.7",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.7.tgz",
@@ -2896,8 +3265,7 @@
"interpret": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz",
- "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=",
- "dev": true
+ "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ="
},
"invert-kv": {
"version": "1.0.0",
@@ -2910,6 +3278,11 @@
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.5.2.tgz",
"integrity": "sha1-1LUFvemUaYfM8PxY2QEP+WB+P6A="
},
+ "is": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/is/-/is-3.2.1.tgz",
+ "integrity": "sha1-0Kwq1V63sL7JJqUmb2xmKqqD3KU="
+ },
"is-absolute": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz",
@@ -2924,7 +3297,6 @@
"version": "0.1.6",
"resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
"integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
- "dev": true,
"requires": {
"kind-of": "3.2.2"
}
@@ -2939,7 +3311,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
"integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=",
- "dev": true,
"requires": {
"binary-extensions": "1.11.0"
}
@@ -2962,7 +3333,6 @@
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
"integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
- "dev": true,
"requires": {
"kind-of": "3.2.2"
}
@@ -2971,7 +3341,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.1.tgz",
"integrity": "sha512-G3fFVFTqfaqu7r4YuSBHKBAuOaLz8Sy7ekklUpFEliaLMP1Y2ZjoN9jS62YWCAPQrQpMUQSitRlrzibbuCZjdA==",
- "dev": true,
"requires": {
"is-accessor-descriptor": "0.1.6",
"is-data-descriptor": "0.1.4",
@@ -2981,8 +3350,7 @@
"kind-of": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
- "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
- "dev": true
+ "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw=="
}
}
},
@@ -3020,8 +3388,7 @@
"is-extendable": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
- "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=",
- "dev": true
+ "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik="
},
"is-extglob": {
"version": "1.0.0",
@@ -3144,7 +3511,6 @@
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
"integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
- "dev": true,
"requires": {
"isobject": "3.0.1"
},
@@ -3152,8 +3518,7 @@
"isobject": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
- "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
- "dev": true
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
}
}
},
@@ -3252,6 +3617,11 @@
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
},
+ "isemail": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/isemail/-/isemail-1.2.0.tgz",
+ "integrity": "sha1-vgPfjMPineTSxd9lASY/H6RZXpo="
+ },
"isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
@@ -3272,6 +3642,17 @@
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
},
+ "joi": {
+ "version": "6.10.1",
+ "resolved": "https://registry.npmjs.org/joi/-/joi-6.10.1.tgz",
+ "integrity": "sha1-TVDDGAeRIgAP5fFq8f+OGRe3fgY=",
+ "requires": {
+ "hoek": "2.16.3",
+ "isemail": "1.2.0",
+ "moment": "2.20.1",
+ "topo": "1.1.0"
+ }
+ },
"js-base64": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.4.0.tgz",
@@ -3332,6 +3713,18 @@
"integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=",
"dev": true
},
+ "jsonwebtoken": {
+ "version": "7.4.3",
+ "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-7.4.3.tgz",
+ "integrity": "sha1-d/UCHeBYtgWheD+hKD6ZgS5kVjg=",
+ "requires": {
+ "joi": "6.10.1",
+ "jws": "3.1.4",
+ "lodash.once": "4.1.1",
+ "ms": "2.1.1",
+ "xtend": "4.0.1"
+ }
+ },
"jsprim": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
@@ -3359,11 +3752,37 @@
"promise": "7.3.1"
}
},
- "kareem": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.0.1.tgz",
- "integrity": "sha512-SsR+TZe595qXYzbWS5KWHBt4mM5h1MA7HFXp3oZnPkunxjaymx0fKhB8cxl6/R7Qm8aFXnI6J7DnyxV/QUSKLA=="
- },
+ "jwa": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.1.5.tgz",
+ "integrity": "sha1-oFUs4CIHQs1S4VN3SjKQXDDnVuU=",
+ "requires": {
+ "base64url": "2.0.0",
+ "buffer-equal-constant-time": "1.0.1",
+ "ecdsa-sig-formatter": "1.0.9",
+ "safe-buffer": "5.1.1"
+ }
+ },
+ "jws": {
+ "version": "3.1.4",
+ "resolved": "https://registry.npmjs.org/jws/-/jws-3.1.4.tgz",
+ "integrity": "sha1-+ei5M46KhHJ31kRLFGT2GIDgUKI=",
+ "requires": {
+ "base64url": "2.0.0",
+ "jwa": "1.1.5",
+ "safe-buffer": "5.1.1"
+ }
+ },
+ "jwt-simple": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/jwt-simple/-/jwt-simple-0.5.1.tgz",
+ "integrity": "sha1-eeoBiRth3mto4T5nwLS1vak3spQ="
+ },
+ "kareem": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.0.1.tgz",
+ "integrity": "sha512-SsR+TZe595qXYzbWS5KWHBt4mM5h1MA7HFXp3oZnPkunxjaymx0fKhB8cxl6/R7Qm8aFXnI6J7DnyxV/QUSKLA=="
+ },
"kind-of": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
@@ -3381,6 +3800,11 @@
"package-json": "4.0.1"
}
},
+ "lazy": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/lazy/-/lazy-1.0.11.tgz",
+ "integrity": "sha1-2qBoIGKCVCwIgojpdcKXwa53tpA="
+ },
"lazy-cache": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz",
@@ -3516,6 +3940,11 @@
"integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=",
"dev": true
},
+ "lodash.endswith": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/lodash.endswith/-/lodash.endswith-4.2.1.tgz",
+ "integrity": "sha1-/tWawXOO0+I27dcGTsRWRIs3vAk="
+ },
"lodash.escape": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz",
@@ -3525,6 +3954,11 @@
"lodash._root": "3.0.1"
}
},
+ "lodash.findindex": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/lodash.findindex/-/lodash.findindex-4.6.0.tgz",
+ "integrity": "sha1-oyRd7mH7m24GJLU1ElYku2nBEQY="
+ },
"lodash.get": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
@@ -3542,6 +3976,21 @@
"integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=",
"dev": true
},
+ "lodash.isequal": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
+ "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA="
+ },
+ "lodash.isfunction": {
+ "version": "3.0.9",
+ "resolved": "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz",
+ "integrity": "sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw=="
+ },
+ "lodash.isstring": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
+ "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE="
+ },
"lodash.keys": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz",
@@ -3553,18 +4002,38 @@
"lodash.isarray": "3.0.4"
}
},
+ "lodash.merge": {
+ "version": "4.6.1",
+ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.1.tgz",
+ "integrity": "sha512-AOYza4+Hf5z1/0Hztxpm2/xiPZgi/cjMqdnKTUWTBSKchJlxXXuUSxCCl8rJlf4g6yww/j6mA8nC8Hw/EZWxKQ=="
+ },
"lodash.mergewith": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.0.tgz",
"integrity": "sha1-FQzwoWeR9ZA7iJHqsVRgknS96lU=",
"dev": true
},
+ "lodash.once": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
+ "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w="
+ },
+ "lodash.reduce": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/lodash.reduce/-/lodash.reduce-4.6.0.tgz",
+ "integrity": "sha1-8atrg5KZrUj3hKu/R2WW8DuRTTs="
+ },
"lodash.restparam": {
"version": "3.6.1",
"resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz",
"integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=",
"dev": true
},
+ "lodash.startswith": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/lodash.startswith/-/lodash.startswith-4.2.1.tgz",
+ "integrity": "sha1-xZjErc4YiiflMUVzHNxsDnF3YAw="
+ },
"lodash.template": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz",
@@ -3652,8 +4121,7 @@
"map-cache": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
- "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=",
- "dev": true
+ "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8="
},
"map-obj": {
"version": "1.0.1",
@@ -3671,7 +4139,6 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz",
"integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=",
- "dev": true,
"requires": {
"object-visit": "1.0.1"
}
@@ -4107,7 +4574,6 @@
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.0.tgz",
"integrity": "sha512-dgaCvoh6i1nosAUBKb0l0pfJ78K8+S9fluyIR2YvAeUD/QuMahnFnF3xYty5eYXMjhGSsB0DsW6A0uAZyetoAg==",
- "dev": true,
"requires": {
"for-in": "1.0.2",
"is-extendable": "1.0.1"
@@ -4117,7 +4583,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
"integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
- "dev": true,
"requires": {
"is-plain-object": "2.0.4"
}
@@ -4132,6 +4597,19 @@
"minimist": "0.0.8"
}
},
+ "moment": {
+ "version": "2.20.1",
+ "resolved": "https://registry.npmjs.org/moment/-/moment-2.20.1.tgz",
+ "integrity": "sha512-Yh9y73JRljxW5QxN08Fner68eFLxM5ynNOAw2LbIB1YAGeQzZT8QFSUvkAz609Zf+IHhhaUxqZK8dG3W/+HEvg=="
+ },
+ "moment-timezone": {
+ "version": "0.5.14",
+ "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.14.tgz",
+ "integrity": "sha1-TrOP+VOLgBCLpGekWPPtQmjM/LE=",
+ "requires": {
+ "moment": "2.20.1"
+ }
+ },
"mongodb": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.0.1.tgz",
@@ -4165,6 +4643,13 @@
"ms": "2.0.0",
"regexp-clone": "0.0.1",
"sliced": "1.0.1"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+ }
}
},
"mongoose-legacy-pluralize": {
@@ -4190,6 +4675,13 @@
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+ }
}
}
}
@@ -4216,6 +4708,13 @@
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+ }
}
},
"sliced": {
@@ -4226,9 +4725,9 @@
}
},
"ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
+ "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
},
"multipipe": {
"version": "0.1.2",
@@ -4242,8 +4741,7 @@
"mute-stream": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
- "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=",
- "dev": true
+ "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s="
},
"nan": {
"version": "2.8.0",
@@ -4302,11 +4800,43 @@
"integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
"dev": true
},
+ "needle": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/needle/-/needle-2.2.0.tgz",
+ "integrity": "sha512-eFagy6c+TYayorXw/qtAdSvaUpEbBsDwDyxYFgLZ0lTojfH7K+OdBqAF7TAFwDokJaGpubpSGG0wO3iC0XPi8w==",
+ "requires": {
+ "debug": "2.6.9",
+ "iconv-lite": "0.4.19",
+ "sax": "1.2.4"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "requires": {
+ "ms": "2.0.0"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+ }
+ }
+ }
+ }
+ },
"negotiator": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz",
"integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk="
},
+ "nocache": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/nocache/-/nocache-2.0.0.tgz",
+ "integrity": "sha1-ICtIAhoMTL3i34DeFaF0Q8i0OYA="
+ },
"node-gyp": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.6.2.tgz",
@@ -4607,6 +5137,14 @@
"dev": true,
"requires": {
"ms": "2.0.0"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ }
}
}
}
@@ -4636,7 +5174,6 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
"integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
- "dev": true,
"requires": {
"remove-trailing-separator": "1.1.0"
}
@@ -4672,6 +5209,22 @@
"set-blocking": "2.0.0"
}
},
+ "nssocket": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/nssocket/-/nssocket-0.6.0.tgz",
+ "integrity": "sha1-Wflvb/MhVm8zxw99vu7N/cBxVPo=",
+ "requires": {
+ "eventemitter2": "0.4.14",
+ "lazy": "1.0.11"
+ },
+ "dependencies": {
+ "eventemitter2": {
+ "version": "0.4.14",
+ "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz",
+ "integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas="
+ }
+ }
+ },
"num2fraction": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz",
@@ -4683,6 +5236,11 @@
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
},
+ "oauth": {
+ "version": "0.9.15",
+ "resolved": "https://registry.npmjs.org/oauth/-/oauth-0.9.15.tgz",
+ "integrity": "sha1-vR/vr2hslrdUda7VGWQS/2DPucE="
+ },
"oauth-sign": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz",
@@ -4697,7 +5255,6 @@
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz",
"integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=",
- "dev": true,
"requires": {
"copy-descriptor": "0.1.1",
"define-property": "0.2.5",
@@ -4708,7 +5265,6 @@
"version": "0.2.5",
"resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
"integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
- "dev": true,
"requires": {
"is-descriptor": "0.1.6"
}
@@ -4717,7 +5273,6 @@
"version": "0.1.6",
"resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
"integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
- "dev": true,
"requires": {
"is-accessor-descriptor": "0.1.6",
"is-data-descriptor": "0.1.4",
@@ -4727,8 +5282,7 @@
"kind-of": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
- "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
- "dev": true
+ "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw=="
}
}
}
@@ -4738,7 +5292,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz",
"integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=",
- "dev": true,
"requires": {
"isobject": "3.0.1"
},
@@ -4746,8 +5299,7 @@
"isobject": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
- "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
- "dev": true
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
}
}
},
@@ -4815,7 +5367,6 @@
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
"integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=",
- "dev": true,
"requires": {
"isobject": "3.0.1"
},
@@ -4823,8 +5374,7 @@
"isobject": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
- "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
- "dev": true
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
}
}
},
@@ -4858,6 +5408,30 @@
"mimic-fn": "1.1.0"
}
},
+ "opener": {
+ "version": "1.4.3",
+ "resolved": "https://registry.npmjs.org/opener/-/opener-1.4.3.tgz",
+ "integrity": "sha1-XG2ixdflgx6P+jlklQ+NZnSskLg=",
+ "dev": true
+ },
+ "optimist": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
+ "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",
+ "dev": true,
+ "requires": {
+ "minimist": "0.0.8",
+ "wordwrap": "0.0.3"
+ },
+ "dependencies": {
+ "wordwrap": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
+ "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=",
+ "dev": true
+ }
+ }
+ },
"optionator": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz",
@@ -4981,8 +5555,62 @@
"pascalcase": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
- "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=",
- "dev": true
+ "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ="
+ },
+ "passport": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/passport/-/passport-0.4.0.tgz",
+ "integrity": "sha1-xQlWkTR71a07XhgCOMORTRbwWBE=",
+ "requires": {
+ "passport-strategy": "1.0.0",
+ "pause": "0.0.1"
+ }
+ },
+ "passport-github": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/passport-github/-/passport-github-1.1.0.tgz",
+ "integrity": "sha1-jOHj/NYa11eOsd9ZWDnkrqEjVdQ=",
+ "requires": {
+ "passport-oauth2": "1.4.0"
+ }
+ },
+ "passport-jwt": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/passport-jwt/-/passport-jwt-3.0.1.tgz",
+ "integrity": "sha1-5Pcnba2L0lHUPG/DiIMTC5YycvY=",
+ "requires": {
+ "jsonwebtoken": "7.4.3",
+ "passport-strategy": "1.0.0"
+ }
+ },
+ "passport-local": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/passport-local/-/passport-local-1.0.0.tgz",
+ "integrity": "sha1-H+YyaMkudWBmJkN+O5BmYsFbpu4=",
+ "requires": {
+ "passport-strategy": "1.0.0"
+ }
+ },
+ "passport-oauth2": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/passport-oauth2/-/passport-oauth2-1.4.0.tgz",
+ "integrity": "sha1-9i+BWDy+EmCb585vFguTlaJ7hq0=",
+ "requires": {
+ "oauth": "0.9.15",
+ "passport-strategy": "1.0.0",
+ "uid2": "0.0.3",
+ "utils-merge": "1.0.1"
+ }
+ },
+ "passport-strategy": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz",
+ "integrity": "sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ="
+ },
+ "path-dirname": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz",
+ "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA="
},
"path-exists": {
"version": "2.1.0",
@@ -5024,74 +5652,657 @@
"path-root-regex": "0.1.2"
}
},
- "path-root-regex": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz",
- "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=",
- "dev": true
- },
- "path-to-regexp": {
- "version": "0.1.7",
- "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
- "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
- },
- "path-type": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
- "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=",
- "dev": true,
+ "path-root-regex": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz",
+ "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=",
+ "dev": true
+ },
+ "path-to-regexp": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
+ "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
+ },
+ "path-type": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
+ "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "4.1.11",
+ "pify": "2.3.0",
+ "pinkie-promise": "2.0.1"
+ }
+ },
+ "pause": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz",
+ "integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10="
+ },
+ "pause-stream": {
+ "version": "0.0.11",
+ "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz",
+ "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=",
+ "dev": true,
+ "requires": {
+ "through": "2.3.8"
+ }
+ },
+ "performance-now": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
+ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
+ },
+ "pidusage": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/pidusage/-/pidusage-1.2.0.tgz",
+ "integrity": "sha512-OGo+iSOk44HRJ8q15AyG570UYxcm5u+R99DI8Khu8P3tKGkVu5EZX4ywHglWSTMNNXQ274oeGpYrvFEhDIFGPg=="
+ },
+ "pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
+ "dev": true
+ },
+ "pinkie": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
+ "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=",
+ "dev": true
+ },
+ "pinkie-promise": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
+ "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
+ "dev": true,
+ "requires": {
+ "pinkie": "2.0.4"
+ }
+ },
+ "platform": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.5.tgz",
+ "integrity": "sha512-TuvHS8AOIZNAlE77WUDiR4rySV/VMptyMfcfeoMgs4P8apaZM3JrnbzBiixKUv+XR6i+BXrQh8WAnjaSPFO65Q=="
+ },
+ "pluralize": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz",
+ "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==",
+ "dev": true
+ },
+ "pm2": {
+ "version": "2.10.1",
+ "resolved": "https://registry.npmjs.org/pm2/-/pm2-2.10.1.tgz",
+ "integrity": "sha512-l5U3Hh908TMw7qyOVAlCCoRlgonpnEw5pr2YnKT8+8fuay9tAysPTccU+SLPDjI6hQ9Q03p4lfNOtJUczzTrPA==",
+ "requires": {
+ "async": "2.6.0",
+ "blessed": "0.1.81",
+ "chalk": "1.1.3",
+ "chokidar": "2.0.2",
+ "cli-table-redemption": "1.0.1",
+ "commander": "2.13.0",
+ "cron": "1.3.0",
+ "debug": "3.1.0",
+ "eventemitter2": "1.0.5",
+ "fclone": "1.0.11",
+ "gkt": "https://tgz.pm2.io/gkt-1.0.0.tgz",
+ "mkdirp": "0.5.1",
+ "moment": "2.20.1",
+ "needle": "2.2.0",
+ "nssocket": "0.6.0",
+ "pidusage": "1.2.0",
+ "pm2-axon": "3.1.0",
+ "pm2-axon-rpc": "0.5.0",
+ "pm2-deploy": "0.3.9",
+ "pm2-multimeter": "0.1.2",
+ "pmx": "1.6.4",
+ "promptly": "2.2.0",
+ "semver": "5.4.1",
+ "shelljs": "0.7.8",
+ "source-map-support": "0.5.3",
+ "sprintf-js": "1.1.1",
+ "v8-compile-cache": "1.1.2",
+ "vizion": "0.2.13",
+ "yamljs": "0.3.0"
+ },
+ "dependencies": {
+ "anymatch": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz",
+ "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==",
+ "requires": {
+ "micromatch": "3.1.8",
+ "normalize-path": "2.1.1"
+ }
+ },
+ "arr-diff": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
+ "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA="
+ },
+ "array-unique": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
+ "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg="
+ },
+ "async": {
+ "version": "2.6.0",
+ "resolved": "https://registry.npmjs.org/async/-/async-2.6.0.tgz",
+ "integrity": "sha512-xAfGg1/NTLBBKlHFmnd7PlmUW9KhVQIUuSrYem9xzFUZy13ScvtyGGejaae9iAVRiRq9+Cx7DPFaAAhCpyxyPw==",
+ "requires": {
+ "lodash": "4.17.4"
+ }
+ },
+ "braces": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.1.tgz",
+ "integrity": "sha512-SO5lYHA3vO6gz66erVvedSCkp7AKWdv6VcQ2N4ysXfPxdAlxAMMAdwegGGcv1Bqwm7naF1hNdk5d6AAIEHV2nQ==",
+ "requires": {
+ "arr-flatten": "1.1.0",
+ "array-unique": "0.3.2",
+ "define-property": "1.0.0",
+ "extend-shallow": "2.0.1",
+ "fill-range": "4.0.0",
+ "isobject": "3.0.1",
+ "kind-of": "6.0.2",
+ "repeat-element": "1.1.2",
+ "snapdragon": "0.8.1",
+ "snapdragon-node": "2.1.1",
+ "split-string": "3.1.0",
+ "to-regex": "3.0.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+ "requires": {
+ "is-descriptor": "1.0.1"
+ }
+ },
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "requires": {
+ "is-extendable": "0.1.1"
+ }
+ }
+ }
+ },
+ "chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "requires": {
+ "ansi-styles": "2.2.1",
+ "escape-string-regexp": "1.0.5",
+ "has-ansi": "2.0.0",
+ "strip-ansi": "3.0.1",
+ "supports-color": "2.0.0"
+ }
+ },
+ "chokidar": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.2.tgz",
+ "integrity": "sha512-l32Hw3wqB0L2kGVmSbK/a+xXLDrUEsc84pSgMkmwygHvD7ubRsP/vxxHa5BtB6oix1XLLVCHyYMsckRXxThmZw==",
+ "requires": {
+ "anymatch": "2.0.0",
+ "async-each": "1.0.1",
+ "braces": "2.3.1",
+ "glob-parent": "3.1.0",
+ "inherits": "2.0.3",
+ "is-binary-path": "1.0.1",
+ "is-glob": "4.0.0",
+ "normalize-path": "2.1.1",
+ "path-is-absolute": "1.0.1",
+ "readdirp": "2.1.0",
+ "upath": "1.0.2"
+ }
+ },
+ "commander": {
+ "version": "2.13.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.13.0.tgz",
+ "integrity": "sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA=="
+ },
+ "define-property": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
+ "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
+ "requires": {
+ "is-descriptor": "1.0.2",
+ "isobject": "3.0.1"
+ },
+ "dependencies": {
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "requires": {
+ "is-accessor-descriptor": "1.0.0",
+ "is-data-descriptor": "1.0.0",
+ "kind-of": "6.0.2"
+ }
+ }
+ }
+ },
+ "expand-brackets": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
+ "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=",
+ "requires": {
+ "debug": "2.6.9",
+ "define-property": "0.2.5",
+ "extend-shallow": "2.0.1",
+ "posix-character-classes": "0.1.1",
+ "regex-not": "1.0.0",
+ "snapdragon": "0.8.1",
+ "to-regex": "3.0.1"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "requires": {
+ "ms": "2.0.0"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+ }
+ }
+ },
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "requires": {
+ "is-descriptor": "0.1.6"
+ }
+ },
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "requires": {
+ "is-extendable": "0.1.1"
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+ "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
+ "requires": {
+ "kind-of": "3.2.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "requires": {
+ "is-buffer": "1.1.6"
+ }
+ }
+ }
+ },
+ "is-data-descriptor": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+ "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
+ "requires": {
+ "kind-of": "3.2.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "requires": {
+ "is-buffer": "1.1.6"
+ }
+ }
+ }
+ },
+ "is-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+ "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+ "requires": {
+ "is-accessor-descriptor": "0.1.6",
+ "is-data-descriptor": "0.1.4",
+ "kind-of": "5.1.0"
+ }
+ },
+ "kind-of": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+ "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw=="
+ }
+ }
+ },
+ "extend-shallow": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+ "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=",
+ "requires": {
+ "assign-symbols": "1.0.0",
+ "is-extendable": "1.0.1"
+ },
+ "dependencies": {
+ "is-extendable": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+ "requires": {
+ "is-plain-object": "2.0.4"
+ }
+ }
+ }
+ },
+ "extglob": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
+ "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",
+ "requires": {
+ "array-unique": "0.3.2",
+ "define-property": "1.0.0",
+ "expand-brackets": "2.1.4",
+ "extend-shallow": "2.0.1",
+ "fragment-cache": "0.2.1",
+ "regex-not": "1.0.0",
+ "snapdragon": "0.8.1",
+ "to-regex": "3.0.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+ "requires": {
+ "is-descriptor": "1.0.1"
+ }
+ },
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "requires": {
+ "is-extendable": "0.1.1"
+ }
+ }
+ }
+ },
+ "fill-range": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
+ "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
+ "requires": {
+ "extend-shallow": "2.0.1",
+ "is-number": "3.0.0",
+ "repeat-string": "1.6.1",
+ "to-regex-range": "2.1.1"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "requires": {
+ "is-extendable": "0.1.1"
+ }
+ }
+ }
+ },
+ "glob-parent": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
+ "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=",
+ "requires": {
+ "is-glob": "3.1.0",
+ "path-dirname": "1.0.2"
+ },
+ "dependencies": {
+ "is-glob": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
+ "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
+ "requires": {
+ "is-extglob": "2.1.1"
+ }
+ }
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "requires": {
+ "kind-of": "6.0.2"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "requires": {
+ "kind-of": "6.0.2"
+ }
+ },
+ "is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI="
+ },
+ "is-glob": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz",
+ "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=",
+ "requires": {
+ "is-extglob": "2.1.1"
+ }
+ },
+ "is-number": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+ "requires": {
+ "kind-of": "3.2.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "requires": {
+ "is-buffer": "1.1.6"
+ }
+ }
+ }
+ },
+ "is-odd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-odd/-/is-odd-2.0.0.tgz",
+ "integrity": "sha512-OTiixgpZAT1M4NHgS5IguFp/Vz2VI3U7Goh4/HA1adtwyLtSBrxYlcSYkhpAE07s4fKEcjrFxyvtQBND4vFQyQ==",
+ "requires": {
+ "is-number": "4.0.0"
+ },
+ "dependencies": {
+ "is-number": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz",
+ "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ=="
+ }
+ }
+ },
+ "is-windows": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
+ "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA=="
+ },
+ "isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
+ },
+ "kind-of": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
+ "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA=="
+ },
+ "micromatch": {
+ "version": "3.1.8",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.8.tgz",
+ "integrity": "sha512-/XeuOQqYg+B5kwjDWekXseSwGS7CzE0w9Gjo4Cjkf/uFitNh47NrZHAY2vp/oS2YQVfebPIdbEIvgdy+kIcAog==",
+ "requires": {
+ "arr-diff": "4.0.0",
+ "array-unique": "0.3.2",
+ "braces": "2.3.1",
+ "define-property": "2.0.2",
+ "extend-shallow": "3.0.2",
+ "extglob": "2.0.4",
+ "fragment-cache": "0.2.1",
+ "kind-of": "6.0.2",
+ "nanomatch": "1.2.9",
+ "object.pick": "1.3.0",
+ "regex-not": "1.0.0",
+ "snapdragon": "0.8.1",
+ "to-regex": "3.0.1"
+ }
+ },
+ "nanomatch": {
+ "version": "1.2.9",
+ "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.9.tgz",
+ "integrity": "sha512-n8R9bS8yQ6eSXaV6jHUpKzD8gLsin02w1HSFiegwrs9E098Ylhw5jdyKPaYqvHknHaSCKTPp7C8dGCQ0q9koXA==",
+ "requires": {
+ "arr-diff": "4.0.0",
+ "array-unique": "0.3.2",
+ "define-property": "2.0.2",
+ "extend-shallow": "3.0.2",
+ "fragment-cache": "0.2.1",
+ "is-odd": "2.0.0",
+ "is-windows": "1.0.2",
+ "kind-of": "6.0.2",
+ "object.pick": "1.3.0",
+ "regex-not": "1.0.0",
+ "snapdragon": "0.8.1",
+ "to-regex": "3.0.1"
+ }
+ },
+ "sprintf-js": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.1.tgz",
+ "integrity": "sha1-Nr54Mgr+WAH2zqPueLblqrlA6gw="
+ },
+ "strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "requires": {
+ "ansi-regex": "2.1.1"
+ }
+ }
+ }
+ },
+ "pm2-axon": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/pm2-axon/-/pm2-axon-3.1.0.tgz",
+ "integrity": "sha512-5sBM+vHw0Cp2K9CJ9ZOYhKtNCCcgQ0eKOyFrSo5Jusbq9FfvuelsMG4WDaxkqosaQbf8N5YfyHhD7eOUcnm5rQ==",
"requires": {
- "graceful-fs": "4.1.11",
- "pify": "2.3.0",
- "pinkie-promise": "2.0.1"
+ "amp": "0.3.1",
+ "amp-message": "0.1.2",
+ "debug": "3.1.0",
+ "escape-regexp": "0.0.1"
}
},
- "pause-stream": {
- "version": "0.0.11",
- "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz",
- "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=",
- "dev": true,
+ "pm2-axon-rpc": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/pm2-axon-rpc/-/pm2-axon-rpc-0.5.0.tgz",
+ "integrity": "sha512-jKiAlnIitx+TtJ1++jThmN49gM0Dte4gm27Kqu2xAUQn33Rh9+5lOOqShS5Xbp0RPZL42hKNEgaVVOSqm3sJCg==",
"requires": {
- "through": "2.3.8"
+ "debug": "3.1.0",
+ "fclone": "1.0.11"
}
},
- "performance-now": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
- "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
+ "pm2-deploy": {
+ "version": "0.3.9",
+ "resolved": "https://registry.npmjs.org/pm2-deploy/-/pm2-deploy-0.3.9.tgz",
+ "integrity": "sha512-IYF45fPwfLE27BivrtodK7zzN56BNDErK7brcldIHjVIHLlk+cdhijq3kwTkPPP3Tpc3H2C942QGRgjg0hHajA==",
+ "requires": {
+ "async": "1.5.2",
+ "tv4": "1.3.0"
+ },
+ "dependencies": {
+ "async": {
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
+ "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo="
+ }
+ }
},
- "pify": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
- "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
- "dev": true
+ "pm2-multimeter": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/pm2-multimeter/-/pm2-multimeter-0.1.2.tgz",
+ "integrity": "sha1-Gh5VFT1BoFU0zqI8/oYKuqDrSs4=",
+ "requires": {
+ "charm": "0.1.2"
+ }
},
- "pinkie": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
- "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=",
- "dev": true
+ "pmx": {
+ "version": "1.6.4",
+ "resolved": "https://registry.npmjs.org/pmx/-/pmx-1.6.4.tgz",
+ "integrity": "sha512-uk6REZHe8j3RhGlFUfyVwFrE6JFhZigTpMFs/4iYO4MzCqVTpNp1cED032oCc4R+m32wUITV/2RDmPX21T1LLg==",
+ "requires": {
+ "debug": "3.1.0",
+ "deep-metrics": "0.0.1",
+ "json-stringify-safe": "5.0.1",
+ "semver": "5.4.1",
+ "vxx": "1.2.2"
+ }
},
- "pinkie-promise": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
- "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
+ "portfinder": {
+ "version": "1.0.13",
+ "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.13.tgz",
+ "integrity": "sha1-uzLs2HwnEErm7kS1o8y/Drsa7ek=",
"dev": true,
"requires": {
- "pinkie": "2.0.4"
+ "async": "1.5.2",
+ "debug": "2.6.9",
+ "mkdirp": "0.5.1"
+ },
+ "dependencies": {
+ "async": {
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
+ "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=",
+ "dev": true
+ },
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dev": true,
+ "requires": {
+ "ms": "2.0.0"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ }
+ }
+ }
}
},
- "pluralize": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz",
- "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==",
- "dev": true
- },
"posix-character-classes": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
- "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=",
- "dev": true
+ "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs="
},
"postcss": {
"version": "6.0.14",
@@ -5170,6 +6381,14 @@
"asap": "2.0.6"
}
},
+ "promptly": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/promptly/-/promptly-2.2.0.tgz",
+ "integrity": "sha1-KhP6BjaIoqWYOxYf/wEIoH0m/HQ=",
+ "requires": {
+ "read": "1.0.7"
+ }
+ },
"proxy-addr": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.2.tgz",
@@ -5423,6 +6642,14 @@
}
}
},
+ "read": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz",
+ "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=",
+ "requires": {
+ "mute-stream": "0.0.7"
+ }
+ },
"read-pkg": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
@@ -5462,7 +6689,6 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz",
"integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=",
- "dev": true,
"requires": {
"graceful-fs": "4.1.11",
"minimatch": "3.0.4",
@@ -5474,7 +6700,6 @@
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
"integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=",
- "dev": true,
"requires": {
"resolve": "1.5.0"
}
@@ -5489,6 +6714,11 @@
"strip-indent": "1.0.1"
}
},
+ "referrer-policy": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/referrer-policy/-/referrer-policy-1.1.0.tgz",
+ "integrity": "sha1-NXdOtzW/UPtsB46DM0tHI1AgfXk="
+ },
"regex-cache": {
"version": "0.4.4",
"resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz",
@@ -5502,7 +6732,6 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.0.tgz",
"integrity": "sha1-Qvg+OXcWIt+CawKvF2Ul1qXxV/k=",
- "dev": true,
"requires": {
"extend-shallow": "2.0.1"
}
@@ -5534,14 +6763,12 @@
"remove-trailing-separator": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
- "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=",
- "dev": true
+ "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8="
},
"repeat-element": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz",
- "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=",
- "dev": true
+ "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo="
},
"repeat-string": {
"version": "1.6.1",
@@ -5637,6 +6864,12 @@
}
}
},
+ "requires-port": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
+ "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=",
+ "dev": true
+ },
"resolve": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.5.0.tgz",
@@ -5664,8 +6897,7 @@
"resolve-url": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
- "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=",
- "dev": true
+ "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo="
},
"restore-cursor": {
"version": "2.0.0",
@@ -5693,6 +6925,11 @@
"glob": "7.1.2"
}
},
+ "rndm": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/rndm/-/rndm-1.2.0.tgz",
+ "integrity": "sha1-8z/pz7Urv9UgqhgyO8ZdsRCht2w="
+ },
"run-async": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz",
@@ -5803,6 +7040,11 @@
}
}
},
+ "sax": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
+ "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
+ },
"scss-tokenizer": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz",
@@ -5854,6 +7096,11 @@
"requires": {
"ms": "2.0.0"
}
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
}
}
},
@@ -5873,6 +7120,13 @@
"ms": "2.0.0",
"parseurl": "1.3.2",
"safe-buffer": "5.1.1"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+ }
}
},
"serve-static": {
@@ -5895,7 +7149,6 @@
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/set-getter/-/set-getter-0.1.0.tgz",
"integrity": "sha1-12nBgsnVpR9AkUXy+6guXoboA3Y=",
- "dev": true,
"requires": {
"to-object-path": "0.3.0"
}
@@ -5903,14 +7156,12 @@
"set-immediate-shim": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz",
- "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=",
- "dev": true
+ "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E="
},
"set-value": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz",
"integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==",
- "dev": true,
"requires": {
"extend-shallow": "2.0.1",
"is-extendable": "0.1.1",
@@ -5938,6 +7189,21 @@
"integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
"dev": true
},
+ "shelljs": {
+ "version": "0.7.8",
+ "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.8.tgz",
+ "integrity": "sha1-3svPh0sNHl+3LhSxZKloMEjprLM=",
+ "requires": {
+ "glob": "7.1.2",
+ "interpret": "1.1.0",
+ "rechoir": "0.6.2"
+ }
+ },
+ "shimmer": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.0.tgz",
+ "integrity": "sha512-xTCx2vohXC2EWWDqY/zb4+5Mu28D+HYNSOuFzsyRDRvI/e1ICb69afwaUwfjr+25ZXldbOLyp+iDUZHq8UnTag=="
+ },
"sigmund": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz",
@@ -5967,7 +7233,6 @@
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.1.tgz",
"integrity": "sha1-4StUh/re0+PeoKyR6UAL91tAE3A=",
- "dev": true,
"requires": {
"base": "0.11.2",
"debug": "2.6.9",
@@ -5983,16 +7248,21 @@
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "dev": true,
"requires": {
"ms": "2.0.0"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+ }
}
},
"define-property": {
"version": "0.2.5",
"resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
"integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
- "dev": true,
"requires": {
"is-descriptor": "0.1.6"
}
@@ -6001,7 +7271,6 @@
"version": "0.1.6",
"resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
"integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
- "dev": true,
"requires": {
"is-accessor-descriptor": "0.1.6",
"is-data-descriptor": "0.1.4",
@@ -6011,14 +7280,12 @@
"kind-of": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
- "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
- "dev": true
+ "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw=="
},
"source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
- "dev": true
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
}
}
},
@@ -6026,7 +7293,6 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz",
"integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==",
- "dev": true,
"requires": {
"define-property": "1.0.0",
"isobject": "3.0.1",
@@ -6036,8 +7302,7 @@
"isobject": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
- "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
- "dev": true
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
}
}
},
@@ -6045,7 +7310,6 @@
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz",
"integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==",
- "dev": true,
"requires": {
"kind-of": "3.2.2"
}
@@ -6071,7 +7335,6 @@
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.1.tgz",
"integrity": "sha512-0KW2wvzfxm8NCTb30z0LMNyPqWCdDGE2viwzUaucqJdkTRXtZiSY3I+2A6nVAjmdOy0I4gU8DwnVVGsk9jvP2A==",
- "dev": true,
"requires": {
"atob": "2.0.3",
"decode-uri-component": "0.2.0",
@@ -6080,11 +7343,25 @@
"urix": "0.1.0"
}
},
+ "source-map-support": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.3.tgz",
+ "integrity": "sha512-eKkTgWYeBOQqFGXRfKabMFdnWepo51vWqEdoeikaEPFiJC7MCU5j2h4+6Q8npkZTeLGbSyecZvRxiSoWl3rh+w==",
+ "requires": {
+ "source-map": "0.6.1"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
+ }
+ }
+ },
"source-map-url": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz",
- "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=",
- "dev": true
+ "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM="
},
"sparkles": {
"version": "1.0.0",
@@ -6126,7 +7403,6 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
"integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==",
- "dev": true,
"requires": {
"extend-shallow": "3.0.2"
},
@@ -6135,7 +7411,6 @@
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
"integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=",
- "dev": true,
"requires": {
"assign-symbols": "1.0.0",
"is-extendable": "1.0.1"
@@ -6145,7 +7420,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
"integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
- "dev": true,
"requires": {
"is-plain-object": "2.0.4"
}
@@ -6155,8 +7429,7 @@
"sprintf-js": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
- "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
- "dev": true
+ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
},
"sshpk": {
"version": "1.13.1",
@@ -6184,7 +7457,6 @@
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
"integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=",
- "dev": true,
"requires": {
"define-property": "0.2.5",
"object-copy": "0.1.0"
@@ -6194,7 +7466,6 @@
"version": "0.2.5",
"resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
"integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
- "dev": true,
"requires": {
"is-descriptor": "0.1.6"
}
@@ -6203,7 +7474,6 @@
"version": "0.1.6",
"resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
"integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
- "dev": true,
"requires": {
"is-accessor-descriptor": "0.1.6",
"is-data-descriptor": "0.1.4",
@@ -6213,8 +7483,7 @@
"kind-of": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
- "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
- "dev": true
+ "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw=="
}
}
},
@@ -6320,8 +7589,7 @@
"supports-color": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
- "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
- "dev": true
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc="
},
"tabbable": {
"version": "1.1.2",
@@ -6373,6 +7641,13 @@
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+ }
}
}
}
@@ -6442,7 +7717,6 @@
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
"integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=",
- "dev": true,
"requires": {
"kind-of": "3.2.2"
}
@@ -6451,7 +7725,6 @@
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.1.tgz",
"integrity": "sha1-FTWL7kosg712N3uh3ASdDxiDeq4=",
- "dev": true,
"requires": {
"define-property": "0.2.5",
"extend-shallow": "2.0.1",
@@ -6462,7 +7735,6 @@
"version": "0.2.5",
"resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
"integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
- "dev": true,
"requires": {
"is-descriptor": "0.1.6"
}
@@ -6471,7 +7743,6 @@
"version": "0.1.6",
"resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
"integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
- "dev": true,
"requires": {
"is-accessor-descriptor": "0.1.6",
"is-data-descriptor": "0.1.4",
@@ -6481,8 +7752,7 @@
"kind-of": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
- "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
- "dev": true
+ "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw=="
}
}
},
@@ -6490,7 +7760,6 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
"integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
- "dev": true,
"requires": {
"is-number": "3.0.0",
"repeat-string": "1.6.1"
@@ -6500,7 +7769,6 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
"integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
- "dev": true,
"requires": {
"kind-of": "3.2.2"
}
@@ -6512,6 +7780,14 @@
"resolved": "https://registry.npmjs.org/token-stream/-/token-stream-0.0.1.tgz",
"integrity": "sha1-zu78cXp2xDFvEm0LnbqlXX598Bo="
},
+ "topo": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/topo/-/topo-1.1.0.tgz",
+ "integrity": "sha1-6ddRYV0buH3IZdsYL6HKCl71NtU=",
+ "requires": {
+ "hoek": "2.16.3"
+ }
+ },
"touch": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz",
@@ -6559,12 +7835,22 @@
}
}
},
+ "tsscmp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.5.tgz",
+ "integrity": "sha1-fcSjOvcVgatDN9qR2FylQn69mpc="
+ },
"tunnel-agent": {
"version": "0.4.3",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz",
"integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=",
"dev": true
},
+ "tv4": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/tv4/-/tv4-1.3.0.tgz",
+ "integrity": "sha1-0CDIRvrdUMhVq7JeuuzGj8EPeWM="
+ },
"tweetnacl": {
"version": "0.14.5",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
@@ -6631,6 +7917,11 @@
"random-bytes": "1.0.0"
}
},
+ "uid2": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/uid2/-/uid2-0.0.3.tgz",
+ "integrity": "sha1-SDEm4Rd03y9xuLY53NeZw3YWK4I="
+ },
"unc-path-regex": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz",
@@ -6643,11 +7934,27 @@
"integrity": "sha1-7Mo6A+VrmvFzhbqsgSrIO5lKli8=",
"dev": true
},
+ "union": {
+ "version": "0.4.6",
+ "resolved": "https://registry.npmjs.org/union/-/union-0.4.6.tgz",
+ "integrity": "sha1-GY+9rrolTniLDvy2MLwR8kopWeA=",
+ "dev": true,
+ "requires": {
+ "qs": "2.3.3"
+ },
+ "dependencies": {
+ "qs": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-2.3.3.tgz",
+ "integrity": "sha1-6eha2+ddoLvkyOBHaghikPhjtAQ=",
+ "dev": true
+ }
+ }
+ },
"union-value": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz",
"integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=",
- "dev": true,
"requires": {
"arr-union": "3.1.0",
"get-value": "2.0.6",
@@ -6659,7 +7966,6 @@
"version": "0.4.3",
"resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz",
"integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=",
- "dev": true,
"requires": {
"extend-shallow": "2.0.1",
"is-extendable": "0.1.1",
@@ -6693,7 +7999,6 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz",
"integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=",
- "dev": true,
"requires": {
"has-value": "0.3.1",
"isobject": "3.0.1"
@@ -6703,7 +8008,6 @@
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz",
"integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=",
- "dev": true,
"requires": {
"get-value": "2.0.6",
"has-values": "0.1.4",
@@ -6714,7 +8018,6 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
"integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
- "dev": true,
"requires": {
"isarray": "1.0.0"
}
@@ -6724,14 +8027,12 @@
"has-values": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz",
- "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=",
- "dev": true
+ "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E="
},
"isobject": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
- "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
- "dev": true
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
}
}
},
@@ -6741,6 +8042,17 @@
"integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=",
"dev": true
},
+ "upath": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/upath/-/upath-1.0.2.tgz",
+ "integrity": "sha512-fCmij7T5LnwUme3dbnVSejvOHHlARjB3ikJFwgZfz386pHmf/gueuTLRFU94FZEaeCLlbQrweiUU700gG41tUw==",
+ "requires": {
+ "lodash.endswith": "4.2.1",
+ "lodash.isfunction": "3.0.9",
+ "lodash.isstring": "4.0.1",
+ "lodash.startswith": "4.2.1"
+ }
+ },
"update-notifier": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-2.3.0.tgz",
@@ -6761,7 +8073,12 @@
"urix": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
- "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=",
+ "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI="
+ },
+ "url-join": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/url-join/-/url-join-2.0.5.tgz",
+ "integrity": "sha1-WvIvGMBSoACkjXuCxenC4v7tpyg=",
"dev": true
},
"url-parse-lax": {
@@ -6777,7 +8094,6 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/use/-/use-2.0.2.tgz",
"integrity": "sha1-riig1y+TvyJCKhii43mZMRLeyOg=",
- "dev": true,
"requires": {
"define-property": "0.2.5",
"isobject": "3.0.1",
@@ -6788,7 +8104,6 @@
"version": "0.2.5",
"resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
"integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
- "dev": true,
"requires": {
"is-descriptor": "0.1.6"
}
@@ -6797,7 +8112,6 @@
"version": "0.1.6",
"resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
"integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
- "dev": true,
"requires": {
"is-accessor-descriptor": "0.1.6",
"is-data-descriptor": "0.1.4",
@@ -6807,20 +8121,17 @@
"isobject": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
- "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
- "dev": true
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
},
"kind-of": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
- "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
- "dev": true
+ "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw=="
},
"lazy-cache": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-2.0.2.tgz",
"integrity": "sha1-uRkKT5EzVGlIQIWfio9whNiCImQ=",
- "dev": true,
"requires": {
"set-getter": "0.1.0"
}
@@ -6848,6 +8159,11 @@
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz",
"integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g=="
},
+ "v8-compile-cache": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-1.1.2.tgz",
+ "integrity": "sha512-ejdrifsIydN1XDH7EuR2hn8ZrkRKUYF7tUcBjBy/lhrCvs2K+zRlbW9UHc0IQ9RsYFZJFqJrieoIHfkCa0DBRA=="
+ },
"v8flags": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/v8flags/-/v8flags-2.1.1.tgz",
@@ -6994,11 +8310,61 @@
}
}
},
+ "vizion": {
+ "version": "0.2.13",
+ "resolved": "https://registry.npmjs.org/vizion/-/vizion-0.2.13.tgz",
+ "integrity": "sha1-ExTN7is0EW+fWxJIU2+V2/zW718=",
+ "requires": {
+ "async": "1.5.2"
+ },
+ "dependencies": {
+ "async": {
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
+ "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo="
+ }
+ }
+ },
"void-elements": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz",
"integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w="
},
+ "vxx": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/vxx/-/vxx-1.2.2.tgz",
+ "integrity": "sha1-dB+1HG8R0zg9pvm5IBil17qAdhE=",
+ "requires": {
+ "continuation-local-storage": "3.2.1",
+ "debug": "2.6.9",
+ "extend": "3.0.1",
+ "is": "3.2.1",
+ "lodash.findindex": "4.6.0",
+ "lodash.isequal": "4.5.0",
+ "lodash.merge": "4.6.1",
+ "methods": "1.1.2",
+ "semver": "5.4.1",
+ "shimmer": "1.2.0",
+ "uuid": "3.1.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "requires": {
+ "ms": "2.0.0"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+ }
+ }
+ }
+ }
+ },
"which": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz",
@@ -7152,6 +8518,11 @@
"signal-exit": "3.0.2"
}
},
+ "x-xss-protection": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/x-xss-protection/-/x-xss-protection-1.0.0.tgz",
+ "integrity": "sha1-iYr7k4abJGYc+cUvnujbjtB2Tdk="
+ },
"xdg-basedir": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz",
@@ -7161,8 +8532,7 @@
"xtend": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
- "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=",
- "dev": true
+ "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68="
},
"y18n": {
"version": "3.2.1",
@@ -7176,6 +8546,15 @@
"integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=",
"dev": true
},
+ "yamljs": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/yamljs/-/yamljs-0.3.0.tgz",
+ "integrity": "sha512-C/FsVVhht4iPQYXOInoxUM/1ELSf9EsgKH34FofQOp6hwCPrW4vG4w5++TED3xRUo8gD7l0P1J1dLlDYzODsTQ==",
+ "requires": {
+ "argparse": "1.0.9",
+ "glob": "7.1.2"
+ }
+ },
"yargs": {
"version": "3.10.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",
diff --git a/package.json b/package.json
index e43846a..61a0285 100644
--- a/package.json
+++ b/package.json
@@ -4,10 +4,11 @@
"private": true,
"main": "index.js",
"scripts": {
- "start": "node index",
+ "start": "pm2 start index.js -i max",
"dev": "nodemon -r dotenv/config index.js",
"sass": "gulp watch:sass",
- "lint": "eslint"
+ "lint": "eslint",
+ "stop": "pm2 stop all"
},
"devDependencies": {
"eslint": "^4.13.1",
@@ -15,18 +16,33 @@
"gulp-autoprefixer": "^4.0.0",
"gulp-rename": "^1.2.2",
"gulp-sass": "^3.1.0",
+ "http-server": "^0.11.1",
"nodemon": "^1.14.1"
},
"dependencies": {
+ "apicache": "^1.2.0",
"bcrypt": "^1.0.3",
+ "connect-flash": "^0.1.1",
"connect-mongo": "^2.0.1",
+ "cors": "^2.8.4",
+ "csurf": "^1.9.0",
"dotenv": "^4.0.0",
"express": "^4.16.2",
+ "express-rate-limit": "^2.11.0",
"express-session": "^1.15.6",
+ "helmet": "^3.11.0",
+ "jwt-simple": "^0.5.1",
"material-components-web": "^0.28.0",
+ "moment": "^2.20.1",
"mongoose": "^5.0.1",
"morgan": "^1.9.0",
+ "ms": "^2.1.1",
"normalize.css": "^7.0.0",
+ "passport": "^0.4.0",
+ "passport-github": "^1.1.0",
+ "passport-jwt": "^3.0.1",
+ "passport-local": "^1.0.0",
+ "pm2": "^2.10.1",
"pug": "^2.0.0-rc.4",
"serve-favicon": "^2.4.5"
}
diff --git a/public/css/app.css b/public/css/app.css
deleted file mode 100644
index fea5f74..0000000
--- a/public/css/app.css
+++ /dev/null
@@ -1,430 +0,0 @@
-/*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */
-/* Document
- ========================================================================== */
-/**
- * 1. Correct the line height in all browsers.
- * 2. Prevent adjustments of font size after orientation changes in
- * IE on Windows Phone and in iOS.
- */
-html {
- line-height: 1.15;
- /* 1 */
- -ms-text-size-adjust: 100%;
- /* 2 */
- -webkit-text-size-adjust: 100%;
- /* 2 */ }
-
-/* Sections
- ========================================================================== */
-/**
- * Remove the margin in all browsers (opinionated).
- */
-body {
- margin: 0; }
-
-/**
- * Add the correct display in IE 9-.
- */
-article,
-aside,
-footer,
-header,
-nav,
-section {
- display: block; }
-
-/**
- * Correct the font size and margin on `h1` elements within `section` and
- * `article` contexts in Chrome, Firefox, and Safari.
- */
-h1 {
- font-size: 2em;
- margin: 0.67em 0; }
-
-/* Grouping content
- ========================================================================== */
-/**
- * Add the correct display in IE 9-.
- * 1. Add the correct display in IE.
- */
-figcaption,
-figure,
-main {
- /* 1 */
- display: block; }
-
-/**
- * Add the correct margin in IE 8.
- */
-figure {
- margin: 1em 40px; }
-
-/**
- * 1. Add the correct box sizing in Firefox.
- * 2. Show the overflow in Edge and IE.
- */
-hr {
- -webkit-box-sizing: content-box;
- box-sizing: content-box;
- /* 1 */
- height: 0;
- /* 1 */
- overflow: visible;
- /* 2 */ }
-
-/**
- * 1. Correct the inheritance and scaling of font size in all browsers.
- * 2. Correct the odd `em` font sizing in all browsers.
- */
-pre {
- font-family: monospace, monospace;
- /* 1 */
- font-size: 1em;
- /* 2 */ }
-
-/* Text-level semantics
- ========================================================================== */
-/**
- * 1. Remove the gray background on active links in IE 10.
- * 2. Remove gaps in links underline in iOS 8+ and Safari 8+.
- */
-a {
- background-color: transparent;
- /* 1 */
- -webkit-text-decoration-skip: objects;
- /* 2 */ }
-
-/**
- * 1. Remove the bottom border in Chrome 57- and Firefox 39-.
- * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
- */
-abbr[title] {
- border-bottom: none;
- /* 1 */
- text-decoration: underline;
- /* 2 */
- -webkit-text-decoration: underline dotted;
- text-decoration: underline dotted;
- /* 2 */ }
-
-/**
- * Prevent the duplicate application of `bolder` by the next rule in Safari 6.
- */
-b,
-strong {
- font-weight: inherit; }
-
-/**
- * Add the correct font weight in Chrome, Edge, and Safari.
- */
-b,
-strong {
- font-weight: bolder; }
-
-/**
- * 1. Correct the inheritance and scaling of font size in all browsers.
- * 2. Correct the odd `em` font sizing in all browsers.
- */
-code,
-kbd,
-samp {
- font-family: monospace, monospace;
- /* 1 */
- font-size: 1em;
- /* 2 */ }
-
-/**
- * Add the correct font style in Android 4.3-.
- */
-dfn {
- font-style: italic; }
-
-/**
- * Add the correct background and color in IE 9-.
- */
-mark {
- background-color: #ff0;
- color: #000; }
-
-/**
- * Add the correct font size in all browsers.
- */
-small {
- font-size: 80%; }
-
-/**
- * Prevent `sub` and `sup` elements from affecting the line height in
- * all browsers.
- */
-sub,
-sup {
- font-size: 75%;
- line-height: 0;
- position: relative;
- vertical-align: baseline; }
-
-sub {
- bottom: -0.25em; }
-
-sup {
- top: -0.5em; }
-
-/* Embedded content
- ========================================================================== */
-/**
- * Add the correct display in IE 9-.
- */
-audio,
-video {
- display: inline-block; }
-
-/**
- * Add the correct display in iOS 4-7.
- */
-audio:not([controls]) {
- display: none;
- height: 0; }
-
-/**
- * Remove the border on images inside links in IE 10-.
- */
-img {
- border-style: none; }
-
-/**
- * Hide the overflow in IE.
- */
-svg:not(:root) {
- overflow: hidden; }
-
-/* Forms
- ========================================================================== */
-/**
- * 1. Change the font styles in all browsers (opinionated).
- * 2. Remove the margin in Firefox and Safari.
- */
-button,
-input,
-optgroup,
-select,
-textarea {
- font-family: sans-serif;
- /* 1 */
- font-size: 100%;
- /* 1 */
- line-height: 1.15;
- /* 1 */
- margin: 0;
- /* 2 */ }
-
-/**
- * Show the overflow in IE.
- * 1. Show the overflow in Edge.
- */
-button,
-input {
- /* 1 */
- overflow: visible; }
-
-/**
- * Remove the inheritance of text transform in Edge, Firefox, and IE.
- * 1. Remove the inheritance of text transform in Firefox.
- */
-button,
-select {
- /* 1 */
- text-transform: none; }
-
-/**
- * 1. Prevent a WebKit bug where (2) destroys native `audio` and `video`
- * controls in Android 4.
- * 2. Correct the inability to style clickable types in iOS and Safari.
- */
-button,
-html [type="button"],
-[type="reset"],
-[type="submit"] {
- -webkit-appearance: button;
- /* 2 */ }
-
-/**
- * Remove the inner border and padding in Firefox.
- */
-button::-moz-focus-inner,
-[type="button"]::-moz-focus-inner,
-[type="reset"]::-moz-focus-inner,
-[type="submit"]::-moz-focus-inner {
- border-style: none;
- padding: 0; }
-
-/**
- * Restore the focus styles unset by the previous rule.
- */
-button:-moz-focusring,
-[type="button"]:-moz-focusring,
-[type="reset"]:-moz-focusring,
-[type="submit"]:-moz-focusring {
- outline: 1px dotted ButtonText; }
-
-/**
- * Correct the padding in Firefox.
- */
-fieldset {
- padding: 0.35em 0.75em 0.625em; }
-
-/**
- * 1. Correct the text wrapping in Edge and IE.
- * 2. Correct the color inheritance from `fieldset` elements in IE.
- * 3. Remove the padding so developers are not caught out when they zero out
- * `fieldset` elements in all browsers.
- */
-legend {
- -webkit-box-sizing: border-box;
- box-sizing: border-box;
- /* 1 */
- color: inherit;
- /* 2 */
- display: table;
- /* 1 */
- max-width: 100%;
- /* 1 */
- padding: 0;
- /* 3 */
- white-space: normal;
- /* 1 */ }
-
-/**
- * 1. Add the correct display in IE 9-.
- * 2. Add the correct vertical alignment in Chrome, Firefox, and Opera.
- */
-progress {
- display: inline-block;
- /* 1 */
- vertical-align: baseline;
- /* 2 */ }
-
-/**
- * Remove the default vertical scrollbar in IE.
- */
-textarea {
- overflow: auto; }
-
-/**
- * 1. Add the correct box sizing in IE 10-.
- * 2. Remove the padding in IE 10-.
- */
-[type="checkbox"],
-[type="radio"] {
- -webkit-box-sizing: border-box;
- box-sizing: border-box;
- /* 1 */
- padding: 0;
- /* 2 */ }
-
-/**
- * Correct the cursor style of increment and decrement buttons in Chrome.
- */
-[type="number"]::-webkit-inner-spin-button,
-[type="number"]::-webkit-outer-spin-button {
- height: auto; }
-
-/**
- * 1. Correct the odd appearance in Chrome and Safari.
- * 2. Correct the outline style in Safari.
- */
-[type="search"] {
- -webkit-appearance: textfield;
- /* 1 */
- outline-offset: -2px;
- /* 2 */ }
-
-/**
- * Remove the inner padding and cancel buttons in Chrome and Safari on macOS.
- */
-[type="search"]::-webkit-search-cancel-button,
-[type="search"]::-webkit-search-decoration {
- -webkit-appearance: none; }
-
-/**
- * 1. Correct the inability to style clickable types in iOS and Safari.
- * 2. Change font properties to `inherit` in Safari.
- */
-::-webkit-file-upload-button {
- -webkit-appearance: button;
- /* 1 */
- font: inherit;
- /* 2 */ }
-
-/* Interactive
- ========================================================================== */
-/*
- * Add the correct display in IE 9-.
- * 1. Add the correct display in Edge, IE, and Firefox.
- */
-details,
-menu {
- display: block; }
-
-/*
- * Add the correct display in all browsers.
- */
-summary {
- display: list-item; }
-
-/* Scripting
- ========================================================================== */
-/**
- * Add the correct display in IE 9-.
- */
-canvas {
- display: inline-block; }
-
-/**
- * Add the correct display in IE.
- */
-template {
- display: none; }
-
-/* Hidden
- ========================================================================== */
-/**
- * Add the correct display in IE 10-.
- */
-[hidden] {
- display: none; }
-
-body {
- background-color: rgba(0, 0, 0, 0.05); }
-
-#content {
- display: -webkit-box;
- display: -ms-flexbox;
- display: flex; }
-
-.book-card {
- background-color: white; }
- .book-card .mdc-card__action {
- min-width: 36px; }
- .book-card .mdc-card__action .mdc-button__icon:only-child {
- margin-right: 0; }
- .book-card .mdc-card__action:last-child {
- margin-left: auto; }
-
-.auth-page {
- display: -webkit-box;
- display: -ms-flexbox;
- display: flex;
- height: 100vh;
- -webkit-box-pack: center;
- -ms-flex-pack: center;
- justify-content: center;
- -webkit-box-align: center;
- -ms-flex-align: center;
- align-items: center; }
- .auth-page .auth-form {
- width: 100%;
- max-width: 400px; }
- .auth-page .auth-form .mdc-text-field {
- display: 100%;
- max-width: 200px;
- display: block; }
diff --git a/routers/auth.js b/routers/auth.js
deleted file mode 100644
index 24d4ccf..0000000
--- a/routers/auth.js
+++ /dev/null
@@ -1,18 +0,0 @@
-const router = require('express').Router();
-
-const { auth: { authenticated, unauthenticated } } = require('../middleware');
-const { auth: controller } = require('../controllers');
-
-router.route('/register')
- .all(unauthenticated)
- .get(controller.showRegisterPage)
- .post(controller.register);
-
-router.route('/login')
- .all(unauthenticated)
- .get(controller.showLoginPage)
- .post(controller.login);
-
-router.get('/logout', authenticated, controller.logout);
-
-module.exports = router;
\ No newline at end of file
diff --git a/routers/index.js b/routers/index.js
deleted file mode 100644
index 697d939..0000000
--- a/routers/index.js
+++ /dev/null
@@ -1,12 +0,0 @@
-const fs = require('fs');
-const path = require('path');
-
-let index = path.basename(__filename);
-let files = fs.readdirSync(__dirname);
-
-for (let file of files) {
- if (file !== index) {
- let name = path.basename(file, '.js');
- module.exports[name] = require(`./${file}`);
- }
-}
\ No newline at end of file
diff --git a/routers/search.js b/routers/search.js
deleted file mode 100644
index dd6ca31..0000000
--- a/routers/search.js
+++ /dev/null
@@ -1,7 +0,0 @@
-const router = require('express').Router();
-
-const { search } = require('../controllers');
-
-router.get('/', search.showResults);
-
-module.exports = router;
\ No newline at end of file
diff --git a/server.js b/server.js
new file mode 100644
index 0000000..9f74490
--- /dev/null
+++ b/server.js
@@ -0,0 +1,73 @@
+const express = require('express');
+const logger = require('morgan');
+const favicon = require('serve-favicon');
+const session = require('express-session');
+const flash = require('connect-flash');
+const MongoStore = require('connect-mongo')(session);
+const helmet = require('helmet');
+
+const data = require('./shared/data');
+const config = require('./shared/config');
+const services = require('./shared/services');
+const middleware = require('./shared/middleware');
+
+const main = require('./main');
+const admin = require('./admin');
+const api = require('./api');
+
+const server = express();
+
+server.set('view engine', 'pug');
+server.set('views', config.paths.views);
+server.set('config', config);
+server.set('port', config.port);
+
+server.locals.basedir = config.paths.views;
+server.locals.VERSION = config.version;
+server.locals.LANGUAGES = data.languages;
+
+server.use(helmet({
+ frameguard: { action: 'deny' },
+ hsts: false
+}));
+
+//server.use(middleware.https());
+
+server.use(express.static(config.paths.public));
+server.use('/lib', express.static(config.paths.lib));
+server.use(favicon(config.paths.favicon));
+server.use(express.urlencoded({ extended: false }));
+server.use(express.json());
+server.use(logger('dev'));
+server.use(session({
+ name: 'sessionId',
+ secret: config.sessionSecret,
+ resave: false,
+ saveUninitialized: false,
+ cookie: {
+ httpOnly: true,
+ //secure: true,
+ signed: true,
+ maxAge: 1000 * 60 * 60 * 24 * 3 // 3 days
+ },
+ store: new MongoStore({
+ mongooseConnection: services.db.connection,
+ ttl: 60 * 60 * 24 * 3, // 3 days
+ touchAfter: 60 * 60 * 24 // 1 day
+ })
+}));
+
+server.use(services.passport.initialize());
+server.use(services.passport.session());
+server.use(flash());
+server.use(middleware.flash);
+server.use(middleware.cart);
+
+server.use('/', main);
+server.use('/admin', admin);
+server.use('/api', api);
+
+server.use(middleware.error.notFound);
+server.use(server.get('env') === 'development' ? middleware.error.development : middleware.error.production);
+
+module.exports = server;
\ No newline at end of file
diff --git a/shared/config/index.js b/shared/config/index.js
new file mode 100644
index 0000000..f791be7
--- /dev/null
+++ b/shared/config/index.js
@@ -0,0 +1,26 @@
+const path = require('path');
+
+const env = process.env.NODE_ENV;
+const ROOT_PATH = path.resolve(__dirname, '..', '..');
+
+module.exports = {
+ version: process.env.APP_VERSION,
+ env,
+ port: process.env.PORT || 3001,
+ sessionSecret: 'HacJmB3ma6crKKtK',
+ jwtSecret: '8UG^LmgL!!N#42vq',
+ mongodbUri: env === 'development' ? 'mongodb://localhost:27017/codedojo' : process.env.MONGODB_URL,
+ paths: {
+ views: path.join(ROOT_PATH, 'shared', 'views'),
+ public: path.join(ROOT_PATH, 'shared', 'public'),
+ favicon: path.join(ROOT_PATH, 'shared', 'public', 'favicon.ico'),
+ lib: path.join(ROOT_PATH, 'node_modules')
+ },
+ oauth: {
+ github: {
+ clientID: process.env.GITHUB_CLIENT_ID,
+ clientSecret: process.env.GITHUB_CLIENT_SECRET,
+ callbackURL: process.env.GITHUB_CALLBACK_URL
+ }
+ }
+};
\ No newline at end of file
diff --git a/shared/data/index.js b/shared/data/index.js
new file mode 100644
index 0000000..6c93f7d
--- /dev/null
+++ b/shared/data/index.js
@@ -0,0 +1,3 @@
+module.exports = {
+ languages: require('./languages')
+};
\ No newline at end of file
diff --git a/shared/data/languages.json b/shared/data/languages.json
new file mode 100644
index 0000000..2d2b92e
--- /dev/null
+++ b/shared/data/languages.json
@@ -0,0 +1,4 @@
+[
+ { "value": "en", "title": "Английский" },
+ { "value": "ru", "title": "Русский" }
+]
\ No newline at end of file
diff --git a/shared/middleware/cart.js b/shared/middleware/cart.js
new file mode 100644
index 0000000..d5aa29f
--- /dev/null
+++ b/shared/middleware/cart.js
@@ -0,0 +1,24 @@
+const { Cart } = require('../../shared/models');
+
+module.exports = function cart(req, res, next) {
+ if (!req.session) throw new Error('Session is required. Try installing `npm install express-session`');
+
+ if (req.session.cartId) {
+ Cart.findById(req.session.cartId)
+ .then(cart => {
+ req.cart = cart;
+
+ next();
+ })
+ .catch(next);
+ } else {
+ Cart.create({})
+ .then(cart => {
+ req.session.cartId = cart.id;
+ req.cart = cart;
+
+ next();
+ })
+ .catch(next);
+ }
+};
\ No newline at end of file
diff --git a/shared/middleware/csrf.js b/shared/middleware/csrf.js
new file mode 100644
index 0000000..c9c7055
--- /dev/null
+++ b/shared/middleware/csrf.js
@@ -0,0 +1,7 @@
+module.exports = function csrf(req, res, next) {
+ let csrfToken = req.csrfToken();
+
+ res.locals.csrfToken = csrfToken;
+
+ next();
+};
\ No newline at end of file
diff --git a/shared/middleware/error.js b/shared/middleware/error.js
new file mode 100644
index 0000000..a972555
--- /dev/null
+++ b/shared/middleware/error.js
@@ -0,0 +1,33 @@
+const { NotFoundError } = require('../utils/error');
+
+module.exports = {
+ notFound(req, res, next) {
+ next(new NotFoundError());
+ },
+
+ csrf(err, req, res, next) {
+ if (err.code !== 'EBADCSRFTOKEN') return next(err);
+
+ // handle CSRF token errors here
+ res.status(403);
+ res.send('form tampered with');
+ },
+
+ development(error, req, res, next) {
+ console.error(error);
+
+ res.status(error.status).render('error', {
+ id: 'error',
+ title: 'Ошибка',
+ error
+ });
+ },
+
+ production(error, req, res, next) {
+ res.status(error.status).render('error', {
+ id: 'error',
+ title: 'Ошибка',
+ message: error.message
+ });
+ }
+};
\ No newline at end of file
diff --git a/shared/middleware/flash.js b/shared/middleware/flash.js
new file mode 100644
index 0000000..38438ef
--- /dev/null
+++ b/shared/middleware/flash.js
@@ -0,0 +1,5 @@
+module.exports = function flash(req, res, next) {
+ res.locals.errors = req.flash('error');
+
+ next();
+};
\ No newline at end of file
diff --git a/shared/middleware/https.js b/shared/middleware/https.js
new file mode 100644
index 0000000..26bf23c
--- /dev/null
+++ b/shared/middleware/https.js
@@ -0,0 +1,11 @@
+module.exports = function ensureHttps() {
+ return (req, res, next) => {
+ if (req.secure) next();
+ else {
+ if (req.method === 'GET')
+ res.redirect(301, `https://${req.headers.host}${req.originalUrl}`);
+ else
+ res.status(403).send('Для доступа к сайту необходимо использовать защищенное соединение через HTTPS.');
+ }
+ };
+};
\ No newline at end of file
diff --git a/shared/middleware/index.js b/shared/middleware/index.js
new file mode 100644
index 0000000..31b4510
--- /dev/null
+++ b/shared/middleware/index.js
@@ -0,0 +1,7 @@
+module.exports = {
+ csrf: require('./csrf'),
+ cart: require('./cart'),
+ error: require('./error'),
+ flash: require('./flash'),
+ https: require('./https')
+};
\ No newline at end of file
diff --git a/shared/middleware/www.js b/shared/middleware/www.js
new file mode 100644
index 0000000..ef90e82
--- /dev/null
+++ b/shared/middleware/www.js
@@ -0,0 +1,11 @@
+module.exports = function ensureNoWww() {
+ return (req, res, next) => {
+ let host = req.hostname;
+
+ if (host.match(/^www\./) !== null) {
+ res.redirect(301, req.protocol + '://' + host.replace(/^www\./, '') + req.originalUrl);
+ } else {
+ next();
+ }
+ };
+};
\ No newline at end of file
diff --git a/models/book.js b/shared/models/book.js
similarity index 64%
rename from models/book.js
rename to shared/models/book.js
index 1c72da2..4830f8d 100644
--- a/models/book.js
+++ b/shared/models/book.js
@@ -1,4 +1,7 @@
const mongoose = require('mongoose');
+const moment = require('moment');
+
+const splitByComma = require('../utils/format').splitBy(',');
const Schema = mongoose.Schema;
@@ -7,25 +10,37 @@ const Book = new Schema({
slug: { type: String, required: true, unique: true, trim: true, lowercase: true },
authors: { type: [String], required: true },
publisher: { type: String, ref: 'Publisher' },
- date: { type: Date, default: Date.now },
+ date: { type: Date, default: Date.now, get: value => moment(value) },
edition: { type: Number, default: 1, min: 1 },
pages: { type: Number, min: 0, default: 0 },
language: { type: String, enum: ['en', 'ru'] },
level: { type: String, enum: ['beg', 'int', 'adv'] },
topics: [{ type: String, ref: 'Topic' }],
- subtopics: [{ type: String }],
tags: [{ type: String }],
likes: { type: Number, default: 0 },
url: String,
imageUrl: String,
+ price: { type: Number, default: 1000 },
codeUrl: String,
githubUrl: String,
description: { type: String, default: '', trim: true },
contents: { type: String, default: '', trim: true }
-},{
+}, {
toObject: { getters: false, virtuals: false },
- toJSON: { versionKey: false, getters: true },
+ toJSON: { versionKey: false, getters: false },
timestamps: true
});
+Book.options.toJSON.transform = function(doc, obj) {
+ delete obj._id;
+ return obj;
+};
+
+Book.statics.validateBody = function(body) {
+ return Object.assign(body, {
+ authors: splitByComma(body.authors),
+ tags: splitByComma(body.tags)
+ });
+};
+
module.exports = mongoose.model('Book', Book);
\ No newline at end of file
diff --git a/shared/models/cart.js b/shared/models/cart.js
new file mode 100644
index 0000000..0b1c535
--- /dev/null
+++ b/shared/models/cart.js
@@ -0,0 +1,28 @@
+const mongoose = require('mongoose');
+
+const Schema = mongoose.Schema;
+
+const Cart = new Schema({
+ user: { type: Schema.Types.ObjectId, ref: 'User' },
+ items: [{ type: Schema.Types.ObjectId, ref: 'Book' }]
+}, {
+ timestamps: true
+});
+
+Cart.methods.calculateTotal = function() {
+ return this.items.reduce((total, item) => item.price + total, 0);
+};
+
+Cart.methods.addProduct = function(productId) {
+ this.items.addToSet(productId);
+
+ return this.save();
+};
+
+Cart.methods.removeProduct = function(productId) {
+ this.items.pull(productId);
+
+ return this.save();
+};
+
+module.exports = mongoose.model('Cart', Cart);
\ No newline at end of file
diff --git a/shared/models/index.js b/shared/models/index.js
new file mode 100644
index 0000000..ed77e1c
--- /dev/null
+++ b/shared/models/index.js
@@ -0,0 +1,7 @@
+module.exports = {
+ Book: require('./book'),
+ Cart: require('./cart'),
+ Publisher: require('./publisher'),
+ Topic: require('./topic'),
+ User: require('./user')
+};
\ No newline at end of file
diff --git a/models/publisher.js b/shared/models/publisher.js
similarity index 100%
rename from models/publisher.js
rename to shared/models/publisher.js
diff --git a/models/topic.js b/shared/models/topic.js
similarity index 100%
rename from models/topic.js
rename to shared/models/topic.js
diff --git a/models/user.js b/shared/models/user.js
similarity index 63%
rename from models/user.js
rename to shared/models/user.js
index 65263d3..2cb0cf5 100644
--- a/models/user.js
+++ b/shared/models/user.js
@@ -11,11 +11,24 @@ const User = new mongoose.Schema({
maxlength: [256, 'Адрес электронный почты слишком длинный.'],
match: [/^[a-zA-Z0-9'._%+-]+@[a-zA-Z0-9-][a-zA-Z0-9.-]*\.[a-zA-Z]{2,63}$/, 'Неверный формат адреса электронной почты.']
},
- password: { type: String, required: true }
+ password: { type: String, required: true },
+ username: { type: String, unique: true, sparse: true },
+ firstname: { type: String },
+ lastname: { type: String },
+ photo: { type: String },
+ role: { type: String, default: 'user', enum: ['user', 'admin'] }
}, {
timestamps: true
});
+User.virtual('displayName').get(function() {
+ return `${this.firstname} ${this.lastname}`;
+});
+
+User.virtual('isAdmin').get(function() {
+ return this.role === 'admin';
+});
+
User.pre('save', function(next) {
if (!this.isModified('password')) return next();
@@ -35,26 +48,8 @@ User.post('save', function(error, user, next) {
}
});
-User.statics.authenticate = function(email, password) {
- return this.findOne({ email })
- .then(user => {
- if (!user) {
- let error = new Error('Пользователь не найден');
- error.status = 401;
- throw error;
- }
-
- return bcrypt.compare(password, user.password)
- .then(isEqual => {
- if (!isEqual) {
- let error = new Error('Неверный пароль');
- error.status = 401;
- throw error;
- }
-
- return user;
- });
- });
+User.methods.isCorrectPassword = function(password) {
+ return bcrypt.compare(password, this.password);
};
module.exports = mongoose.model('User', User);
\ No newline at end of file
diff --git a/shared/public/css/app.css b/shared/public/css/app.css
new file mode 100644
index 0000000..bcf15f4
--- /dev/null
+++ b/shared/public/css/app.css
@@ -0,0 +1,93 @@
+body {
+ background-color: rgba(0, 0, 0, 0.05); }
+
+.mdc-card {
+ background-color: white; }
+
+#content {
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex; }
+
+.book-card {
+ background-color: white; }
+ .book-card .mdc-card__action {
+ min-width: 36px; }
+ .book-card .mdc-card__action .mdc-button__icon:only-child {
+ margin-right: 0; }
+ .book-card .mdc-card__action:last-child {
+ margin-left: auto; }
+
+.flash {
+ padding: 16px;
+ text-align: center; }
+ .flash.flash--error {
+ background-color: tomato;
+ color: white; }
+
+#search-form {
+ padding: 4px 24px 0px; }
+
+.auth-page {
+ background-image: url("../img/bg.jpg"); }
+ .auth-page #main {
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-orient: vertical;
+ -webkit-box-direction: normal;
+ -ms-flex-direction: column;
+ flex-direction: column;
+ height: 100vh;
+ -webkit-box-pack: center;
+ -ms-flex-pack: center;
+ justify-content: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center; }
+ .auth-page .auth-form {
+ width: 100%;
+ max-width: 400px; }
+ .auth-page .auth-form .mdc-text-field {
+ display: 100%;
+ max-width: 200px;
+ display: block; }
+
+#error-page #main {
+ max-width: 1024px;
+ margin: 2em auto;
+ text-align: center; }
+ #error-page #main .error-icon {
+ color: grey;
+ font-size: 5em; }
+ #error-page #main pre {
+ text-align: left; }
+
+#main-page {
+ background-image: url("../img/bg.jpg"); }
+ #main-page .mdc-toolbar {
+ background-color: transparent; }
+ #main-page #main {
+ color: white;
+ text-align: center;
+ margin-top: 128px; }
+ #main-page #main i {
+ font-size: 72px; }
+ #main-page #main h1 {
+ font-size: 64px;
+ margin: .25em; }
+ #main-page #main p {
+ font-size: 36px;
+ margin: .25em 0 1em; }
+ #main-page #main a {
+ display: inline-block;
+ margin: .5em; }
+
+#user-page #main {
+ text-align: center;
+ padding: 64px 16px 0px; }
+
+#user-page .user-photo {
+ max-width: 128px;
+ border-radius: 100%;
+ display: inline-block; }
diff --git a/public/favicon.ico b/shared/public/favicon.ico
similarity index 100%
rename from public/favicon.ico
rename to shared/public/favicon.ico
diff --git a/shared/public/img/bg.jpg b/shared/public/img/bg.jpg
new file mode 100644
index 0000000..799b45f
Binary files /dev/null and b/shared/public/img/bg.jpg differ
diff --git a/public/img/library.jpg b/shared/public/img/library.jpg
similarity index 100%
rename from public/img/library.jpg
rename to shared/public/img/library.jpg
diff --git a/public/img/topics/angular.svg b/shared/public/img/topics/angular.svg
similarity index 100%
rename from public/img/topics/angular.svg
rename to shared/public/img/topics/angular.svg
diff --git a/public/img/topics/angularjs.svg b/shared/public/img/topics/angularjs.svg
similarity index 100%
rename from public/img/topics/angularjs.svg
rename to shared/public/img/topics/angularjs.svg
diff --git a/public/img/topics/aspnet.svg b/shared/public/img/topics/aspnet.svg
similarity index 100%
rename from public/img/topics/aspnet.svg
rename to shared/public/img/topics/aspnet.svg
diff --git a/public/img/topics/babel.svg b/shared/public/img/topics/babel.svg
similarity index 100%
rename from public/img/topics/babel.svg
rename to shared/public/img/topics/babel.svg
diff --git a/public/img/topics/bootstrap.svg b/shared/public/img/topics/bootstrap.svg
similarity index 100%
rename from public/img/topics/bootstrap.svg
rename to shared/public/img/topics/bootstrap.svg
diff --git a/public/img/topics/bower.svg b/shared/public/img/topics/bower.svg
similarity index 100%
rename from public/img/topics/bower.svg
rename to shared/public/img/topics/bower.svg
diff --git a/public/img/topics/csharp.svg b/shared/public/img/topics/csharp.svg
similarity index 100%
rename from public/img/topics/csharp.svg
rename to shared/public/img/topics/csharp.svg
diff --git a/public/img/topics/css.svg b/shared/public/img/topics/css.svg
similarity index 100%
rename from public/img/topics/css.svg
rename to shared/public/img/topics/css.svg
diff --git a/public/img/topics/dotnet.svg b/shared/public/img/topics/dotnet.svg
similarity index 100%
rename from public/img/topics/dotnet.svg
rename to shared/public/img/topics/dotnet.svg
diff --git a/public/img/topics/ef.svg b/shared/public/img/topics/ef.svg
similarity index 100%
rename from public/img/topics/ef.svg
rename to shared/public/img/topics/ef.svg
diff --git a/public/img/topics/express.svg b/shared/public/img/topics/express.svg
similarity index 100%
rename from public/img/topics/express.svg
rename to shared/public/img/topics/express.svg
diff --git a/public/img/topics/foundation.svg b/shared/public/img/topics/foundation.svg
similarity index 100%
rename from public/img/topics/foundation.svg
rename to shared/public/img/topics/foundation.svg
diff --git a/public/img/topics/git.svg b/shared/public/img/topics/git.svg
similarity index 100%
rename from public/img/topics/git.svg
rename to shared/public/img/topics/git.svg
diff --git a/public/img/topics/github.svg b/shared/public/img/topics/github.svg
similarity index 100%
rename from public/img/topics/github.svg
rename to shared/public/img/topics/github.svg
diff --git a/public/img/topics/gulp.svg b/shared/public/img/topics/gulp.svg
similarity index 100%
rename from public/img/topics/gulp.svg
rename to shared/public/img/topics/gulp.svg
diff --git a/public/img/topics/haskell.svg b/shared/public/img/topics/haskell.svg
similarity index 100%
rename from public/img/topics/haskell.svg
rename to shared/public/img/topics/haskell.svg
diff --git a/public/img/topics/html-css.svg b/shared/public/img/topics/html-css.svg
similarity index 100%
rename from public/img/topics/html-css.svg
rename to shared/public/img/topics/html-css.svg
diff --git a/public/img/topics/html.svg b/shared/public/img/topics/html.svg
similarity index 100%
rename from public/img/topics/html.svg
rename to shared/public/img/topics/html.svg
diff --git a/public/img/topics/java.svg b/shared/public/img/topics/java.svg
similarity index 100%
rename from public/img/topics/java.svg
rename to shared/public/img/topics/java.svg
diff --git a/public/img/topics/javascript.svg b/shared/public/img/topics/javascript.svg
similarity index 100%
rename from public/img/topics/javascript.svg
rename to shared/public/img/topics/javascript.svg
diff --git a/public/img/topics/jquery.svg b/shared/public/img/topics/jquery.svg
similarity index 100%
rename from public/img/topics/jquery.svg
rename to shared/public/img/topics/jquery.svg
diff --git a/public/img/topics/json.svg b/shared/public/img/topics/json.svg
similarity index 100%
rename from public/img/topics/json.svg
rename to shared/public/img/topics/json.svg
diff --git a/public/img/topics/laravel.svg b/shared/public/img/topics/laravel.svg
similarity index 100%
rename from public/img/topics/laravel.svg
rename to shared/public/img/topics/laravel.svg
diff --git a/public/img/topics/mean.svg b/shared/public/img/topics/mean.svg
similarity index 100%
rename from public/img/topics/mean.svg
rename to shared/public/img/topics/mean.svg
diff --git a/public/img/topics/microsoft.net.svg b/shared/public/img/topics/microsoft.net.svg
similarity index 100%
rename from public/img/topics/microsoft.net.svg
rename to shared/public/img/topics/microsoft.net.svg
diff --git a/public/img/topics/mongodb.svg b/shared/public/img/topics/mongodb.svg
similarity index 100%
rename from public/img/topics/mongodb.svg
rename to shared/public/img/topics/mongodb.svg
diff --git a/public/img/topics/mysql.svg b/shared/public/img/topics/mysql.svg
similarity index 100%
rename from public/img/topics/mysql.svg
rename to shared/public/img/topics/mysql.svg
diff --git a/public/img/topics/nodejs.svg b/shared/public/img/topics/nodejs.svg
similarity index 100%
rename from public/img/topics/nodejs.svg
rename to shared/public/img/topics/nodejs.svg
diff --git a/public/img/topics/php.svg b/shared/public/img/topics/php.svg
similarity index 100%
rename from public/img/topics/php.svg
rename to shared/public/img/topics/php.svg
diff --git a/public/img/topics/programming.svg b/shared/public/img/topics/programming.svg
similarity index 100%
rename from public/img/topics/programming.svg
rename to shared/public/img/topics/programming.svg
diff --git a/public/img/topics/python.svg b/shared/public/img/topics/python.svg
similarity index 100%
rename from public/img/topics/python.svg
rename to shared/public/img/topics/python.svg
diff --git a/public/img/topics/react.svg b/shared/public/img/topics/react.svg
similarity index 100%
rename from public/img/topics/react.svg
rename to shared/public/img/topics/react.svg
diff --git a/public/img/topics/redux.svg b/shared/public/img/topics/redux.svg
similarity index 100%
rename from public/img/topics/redux.svg
rename to shared/public/img/topics/redux.svg
diff --git a/public/img/topics/regex.svg b/shared/public/img/topics/regex.svg
similarity index 100%
rename from public/img/topics/regex.svg
rename to shared/public/img/topics/regex.svg
diff --git a/public/img/topics/ruby.svg b/shared/public/img/topics/ruby.svg
similarity index 100%
rename from public/img/topics/ruby.svg
rename to shared/public/img/topics/ruby.svg
diff --git a/public/img/topics/sass.svg b/shared/public/img/topics/sass.svg
similarity index 100%
rename from public/img/topics/sass.svg
rename to shared/public/img/topics/sass.svg
diff --git a/public/img/topics/sqlserver.svg b/shared/public/img/topics/sqlserver.svg
similarity index 100%
rename from public/img/topics/sqlserver.svg
rename to shared/public/img/topics/sqlserver.svg
diff --git a/public/img/topics/typescript.svg b/shared/public/img/topics/typescript.svg
similarity index 100%
rename from public/img/topics/typescript.svg
rename to shared/public/img/topics/typescript.svg
diff --git a/public/img/topics/uwp.svg b/shared/public/img/topics/uwp.svg
similarity index 100%
rename from public/img/topics/uwp.svg
rename to shared/public/img/topics/uwp.svg
diff --git a/public/img/topics/vs.svg b/shared/public/img/topics/vs.svg
similarity index 100%
rename from public/img/topics/vs.svg
rename to shared/public/img/topics/vs.svg
diff --git a/public/img/topics/vue.svg b/shared/public/img/topics/vue.svg
similarity index 100%
rename from public/img/topics/vue.svg
rename to shared/public/img/topics/vue.svg
diff --git a/public/img/topics/web-apps.svg b/shared/public/img/topics/web-apps.svg
similarity index 100%
rename from public/img/topics/web-apps.svg
rename to shared/public/img/topics/web-apps.svg
diff --git a/public/img/topics/webpack.svg b/shared/public/img/topics/webpack.svg
similarity index 100%
rename from public/img/topics/webpack.svg
rename to shared/public/img/topics/webpack.svg
diff --git a/public/img/topics/windows.svg b/shared/public/img/topics/windows.svg
similarity index 100%
rename from public/img/topics/windows.svg
rename to shared/public/img/topics/windows.svg
diff --git a/public/img/topics/wordpress.svg b/shared/public/img/topics/wordpress.svg
similarity index 100%
rename from public/img/topics/wordpress.svg
rename to shared/public/img/topics/wordpress.svg
diff --git a/public/img/topics/xaml.svg b/shared/public/img/topics/xaml.svg
similarity index 100%
rename from public/img/topics/xaml.svg
rename to shared/public/img/topics/xaml.svg
diff --git a/services/db.js b/shared/services/db.js
similarity index 93%
rename from services/db.js
rename to shared/services/db.js
index 7879a15..4b1cf6a 100644
--- a/services/db.js
+++ b/shared/services/db.js
@@ -4,7 +4,7 @@ const { mongodbUri } = require('../config');
mongoose.Promise = global.Promise;
-mongoose.connect(mongodbUri.development);
+mongoose.connect(mongodbUri);
mongoose.connection.on('error', console.error.bind(console, 'MongoDB connection error:'));
mongoose.connection.once('open', () => console.log('Connected to MongoDB'));
diff --git a/controllers/index.js b/shared/services/index.js
similarity index 100%
rename from controllers/index.js
rename to shared/services/index.js
diff --git a/shared/services/passport/github.js b/shared/services/passport/github.js
new file mode 100644
index 0000000..7dcf3f5
--- /dev/null
+++ b/shared/services/passport/github.js
@@ -0,0 +1,25 @@
+const passport = require('passport');
+const { Strategy: GitHubStrategy } = require('passport-github');
+const { User } = require('../../models');
+
+const config = require('../../config');
+
+passport.use(new GitHubStrategy(config.oauth.github, (accessToken, refreshToken, profile, done) => {
+ if (!profile.emails) return done(null, false, { message: 'Для входа необходимо получить от GitHub email' });
+
+ let [firstname, lastname] = profile.displayName ? profile.displayName.split(' ') : [];
+ let email = profile.emails[0].value;
+ let username = profile.username;
+ let photo = profile.photos[0].value;
+
+ User.findOneAndUpdate({ email }, {
+ firstname,
+ lastname,
+ email,
+ username,
+ photo
+ }, {
+ upsert: true,
+ new: true
+ }, done);
+}));
\ No newline at end of file
diff --git a/shared/services/passport/index.js b/shared/services/passport/index.js
new file mode 100644
index 0000000..a4a8bf3
--- /dev/null
+++ b/shared/services/passport/index.js
@@ -0,0 +1,16 @@
+const passport = require('passport');
+
+const { User } = require('../../models');
+require('./local');
+require('./github');
+require('./jwt');
+
+passport.serializeUser((user, done) => {
+ done(null, user._id);
+});
+
+passport.deserializeUser((userId, done) => {
+ User.findById(userId, done);
+});
+
+module.exports = passport;
\ No newline at end of file
diff --git a/shared/services/passport/jwt.js b/shared/services/passport/jwt.js
new file mode 100644
index 0000000..03b91b6
--- /dev/null
+++ b/shared/services/passport/jwt.js
@@ -0,0 +1,19 @@
+const passport = require('passport');
+const { Strategy, ExtractJwt } = require('passport-jwt');
+const { User } = require('../../models');
+
+const config = require('../../config');
+const options = {
+ secretOrKey: config.jwtSecret,
+ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken()
+};
+
+passport.use(new Strategy(options, (payload, done) => {
+ User.findById(payload.id)
+ .then(user => {
+ if (!user) return done(null, false);
+
+ done(null, user);
+ })
+ .catch(done);
+}));
\ No newline at end of file
diff --git a/shared/services/passport/local.js b/shared/services/passport/local.js
new file mode 100644
index 0000000..9008d02
--- /dev/null
+++ b/shared/services/passport/local.js
@@ -0,0 +1,34 @@
+const passport = require('passport');
+const { Strategy: LocalStrategy } = require('passport-local');
+
+const { User } = require('../../models');
+
+const options = {
+ usernameField: 'email',
+ passwordField: 'password',
+ passReqToCallback: true
+};
+
+passport.use('local-register', new LocalStrategy(options, (req, email, password, done) => {
+ if (password !== req.confirmPassword) return done(new Error('Пароли не совпадают'));
+
+ User.create({ email, password })
+ .then(user => done(null, user))
+ .catch(done);
+}));
+
+passport.use('local-login', new LocalStrategy(options, (req, email, password, done) => {
+ User.findOne({ email })
+ .then(user => {
+ if (!user) return done(null, false);
+
+ user.isCorrectPassword(password)
+ .then(isEqual => {
+ if (!isEqual) return done(null, false);
+ console.log(user)
+ done(null, user);
+ })
+ .catch(done);
+ })
+ .catch(done);
+}));
\ No newline at end of file
diff --git a/styles/base.scss b/shared/styles/base.scss
similarity index 53%
rename from styles/base.scss
rename to shared/styles/base.scss
index 5f9c479..17bfcb3 100644
--- a/styles/base.scss
+++ b/shared/styles/base.scss
@@ -1,3 +1,7 @@
body {
background-color: rgba(0, 0, 0, 0.05);
+}
+
+.mdc-card {
+ background-color: white;
}
\ No newline at end of file
diff --git a/shared/styles/components/_index.scss b/shared/styles/components/_index.scss
new file mode 100644
index 0000000..176c642
--- /dev/null
+++ b/shared/styles/components/_index.scss
@@ -0,0 +1,3 @@
+@import 'book-card';
+@import 'flash';
+@import 'search-form';
\ No newline at end of file
diff --git a/styles/components/book-card.scss b/shared/styles/components/book-card.scss
similarity index 100%
rename from styles/components/book-card.scss
rename to shared/styles/components/book-card.scss
diff --git a/shared/styles/components/flash.scss b/shared/styles/components/flash.scss
new file mode 100644
index 0000000..b36b28a
--- /dev/null
+++ b/shared/styles/components/flash.scss
@@ -0,0 +1,9 @@
+.flash {
+ padding: 16px;
+ text-align: center;
+
+ &.flash--error {
+ background-color: tomato;
+ color: white;
+ }
+}
\ No newline at end of file
diff --git a/shared/styles/components/search-form.scss b/shared/styles/components/search-form.scss
new file mode 100644
index 0000000..1d45ccd
--- /dev/null
+++ b/shared/styles/components/search-form.scss
@@ -0,0 +1,3 @@
+#search-form {
+ padding: 4px 24px 0px;
+}
\ No newline at end of file
diff --git a/styles/index.scss b/shared/styles/index.scss
similarity index 70%
rename from styles/index.scss
rename to shared/styles/index.scss
index bf04e3c..b1be336 100644
--- a/styles/index.scss
+++ b/shared/styles/index.scss
@@ -1,5 +1,3 @@
-@import 'normalize.css/normalize';
-
@import 'base';
@import 'layout';
@import 'components/index';
diff --git a/styles/layout.scss b/shared/styles/layout.scss
similarity index 100%
rename from styles/layout.scss
rename to shared/styles/layout.scss
diff --git a/shared/styles/pages/_index.scss b/shared/styles/pages/_index.scss
new file mode 100644
index 0000000..22dfe57
--- /dev/null
+++ b/shared/styles/pages/_index.scss
@@ -0,0 +1,4 @@
+@import 'auth/index';
+@import 'error';
+@import 'main';
+@import 'user';
\ No newline at end of file
diff --git a/styles/pages/auth/_index.scss b/shared/styles/pages/auth/_index.scss
similarity index 100%
rename from styles/pages/auth/_index.scss
rename to shared/styles/pages/auth/_index.scss
diff --git a/styles/pages/auth/common.scss b/shared/styles/pages/auth/common.scss
similarity index 50%
rename from styles/pages/auth/common.scss
rename to shared/styles/pages/auth/common.scss
index fb41315..e2929af 100644
--- a/styles/pages/auth/common.scss
+++ b/shared/styles/pages/auth/common.scss
@@ -1,8 +1,13 @@
.auth-page {
- display: flex;
- height: 100vh;
- justify-content: center;
- align-items: center;
+ background-image: url('../img/bg.jpg');
+
+ #main {
+ display: flex;
+ flex-direction: column;
+ height: 100vh;
+ justify-content: center;
+ align-items: center;
+ }
.auth-form {
width: 100%;
diff --git a/styles/pages/auth/login.scss b/shared/styles/pages/auth/login.scss
similarity index 100%
rename from styles/pages/auth/login.scss
rename to shared/styles/pages/auth/login.scss
diff --git a/styles/pages/auth/register.scss b/shared/styles/pages/auth/register.scss
similarity index 100%
rename from styles/pages/auth/register.scss
rename to shared/styles/pages/auth/register.scss
diff --git a/shared/styles/pages/error.scss b/shared/styles/pages/error.scss
new file mode 100644
index 0000000..561e426
--- /dev/null
+++ b/shared/styles/pages/error.scss
@@ -0,0 +1,16 @@
+#error-page {
+ #main {
+ max-width: 1024px;
+ margin: 2em auto;
+ text-align: center;
+
+ .error-icon {
+ color: grey;
+ font-size: 5em;
+ }
+
+ pre {
+ text-align: left;
+ }
+ }
+}
\ No newline at end of file
diff --git a/shared/styles/pages/main.scss b/shared/styles/pages/main.scss
new file mode 100644
index 0000000..252ba9f
--- /dev/null
+++ b/shared/styles/pages/main.scss
@@ -0,0 +1,32 @@
+#main-page {
+ background-image: url('../img/bg.jpg');
+
+ .mdc-toolbar {
+ background-color: transparent;
+ }
+
+ #main {
+ color: white;
+ text-align: center;
+ margin-top: 128px;
+
+ i {
+ font-size: 72px;
+ }
+
+ h1 {
+ font-size: 64px;
+ margin: .25em;
+ }
+
+ p {
+ font-size: 36px;
+ margin: .25em 0 1em;
+ }
+
+ a {
+ display: inline-block;
+ margin: .5em;
+ }
+ }
+}
\ No newline at end of file
diff --git a/shared/styles/pages/user.scss b/shared/styles/pages/user.scss
new file mode 100644
index 0000000..7137934
--- /dev/null
+++ b/shared/styles/pages/user.scss
@@ -0,0 +1,21 @@
+#user-page {
+
+ #main {
+ text-align: center;
+ padding: 64px 16px 0px;
+ }
+
+ .user-photo {
+ max-width: 128px;
+ border-radius: 100%;
+ display: inline-block;
+ }
+
+ .user-name {
+
+ }
+
+ .user-email {
+
+ }
+}
\ No newline at end of file
diff --git a/shared/utils/error.js b/shared/utils/error.js
new file mode 100644
index 0000000..9595c6a
--- /dev/null
+++ b/shared/utils/error.js
@@ -0,0 +1,10 @@
+module.exports = {
+ NotFoundError: class NotFoundError extends Error {
+ constructor(message = 'Не найдено') {
+ super(message);
+
+ this.name = 'NotFoundError';
+ this.status = 404;
+ }
+ }
+};
\ No newline at end of file
diff --git a/shared/utils/format.js b/shared/utils/format.js
new file mode 100644
index 0000000..dd4bd2d
--- /dev/null
+++ b/shared/utils/format.js
@@ -0,0 +1,9 @@
+module.exports = {
+ splitBy: symbol => value => {
+ if (typeof value !== 'string') {
+ return value;
+ } else {
+ return value.split(symbol).map(value => value.trim());
+ }
+ }
+};
\ No newline at end of file
diff --git a/views/_layout.pug b/shared/views/_layout.pug
similarity index 82%
rename from views/_layout.pug
rename to shared/views/_layout.pug
index 2bdb7e9..c94cdc3 100644
--- a/views/_layout.pug
+++ b/shared/views/_layout.pug
@@ -9,6 +9,7 @@ html(lang='ru')
link(rel='stylesheet' href='https://fonts.googleapis.com/css?family=Roboto:300,400,400i,700&subset=cyrillic')
link(rel='stylesheet' href='https://fonts.googleapis.com/icon?family=Material+Icons')
+ link(rel='stylesheet' href='/lib/normalize.css/normalize.css')
link(rel='stylesheet' href='/lib/material-components-web/dist/material-components-web.min.css')
link(rel='stylesheet' href=`/css/app.css?v=${version}`)
@@ -16,14 +17,12 @@ html(lang='ru')
block head
body(id=`${id}-page` class=className).mdc-typography
- block header
- include _includes/toolbar
+ if errors
+ for error in errors
+ div.flash.flash--error= error
+ block header
+
block content
- section#content
- block sidenav
- include _includes/sidenav
-
- block main
block scripts
\ No newline at end of file
diff --git a/shared/views/_mixins/form.pug b/shared/views/_mixins/form.pug
new file mode 100644
index 0000000..5036765
--- /dev/null
+++ b/shared/views/_mixins/form.pug
@@ -0,0 +1,3 @@
+mixin form(method='post', action)
+ form&attributes(attributes)
+ block
\ No newline at end of file
diff --git a/views/_mixins/mdc/button.pug b/shared/views/_mixins/mdc/button.pug
similarity index 100%
rename from views/_mixins/mdc/button.pug
rename to shared/views/_mixins/mdc/button.pug
diff --git a/shared/views/_mixins/mdc/index.pug b/shared/views/_mixins/mdc/index.pug
new file mode 100644
index 0000000..e6f8654
--- /dev/null
+++ b/shared/views/_mixins/mdc/index.pug
@@ -0,0 +1,2 @@
+include button
+include text-field
\ No newline at end of file
diff --git a/views/_mixins/mdc/textfield.pug b/shared/views/_mixins/mdc/text-field.pug
similarity index 79%
rename from views/_mixins/mdc/textfield.pug
rename to shared/views/_mixins/mdc/text-field.pug
index 3685298..077f99e 100644
--- a/views/_mixins/mdc/textfield.pug
+++ b/shared/views/_mixins/mdc/text-field.pug
@@ -1,4 +1,4 @@
mixin mdc-text-field(name, label, value)
div.mdc-text-field
- input.mdc-text-field__input(type=attributes.type || 'text' name=name placeholder=label)
+ input.mdc-text-field__input(type=attributes.type || 'text' name=name value=value placeholder=label)
div.mdc-text-field__bottom-line
\ No newline at end of file
diff --git a/views/error.pug b/shared/views/error.pug
similarity index 97%
rename from views/error.pug
rename to shared/views/error.pug
index 984cedb..d7fa8fa 100644
--- a/views/error.pug
+++ b/shared/views/error.pug
@@ -1,7 +1,5 @@
extends _layout
-block header
-
block content
main#main
i.error-icon.material-icons error
diff --git a/styles/components/_index.scss b/styles/components/_index.scss
deleted file mode 100644
index 1c81bd4..0000000
--- a/styles/components/_index.scss
+++ /dev/null
@@ -1 +0,0 @@
-@import 'book-card';
\ No newline at end of file
diff --git a/styles/pages/_index.scss b/styles/pages/_index.scss
deleted file mode 100644
index 5764c53..0000000
--- a/styles/pages/_index.scss
+++ /dev/null
@@ -1 +0,0 @@
-@import 'auth/index';
\ No newline at end of file
diff --git a/utils/format.js b/utils/format.js
deleted file mode 100644
index 36b9fd8..0000000
--- a/utils/format.js
+++ /dev/null
@@ -1,7 +0,0 @@
-function split(value) {
- if (typeof value !== 'string') {
- return value;
- } else {
- return value.split(',').map(value => value.trim());
- }
-}
\ No newline at end of file
diff --git a/views/404.pug b/views/404.pug
deleted file mode 100644
index c8e20a2..0000000
--- a/views/404.pug
+++ /dev/null
@@ -1,4 +0,0 @@
-extends _layout
-
-block content
- h1 Не найдено
\ No newline at end of file
diff --git a/views/_mixins/mdc/index.pug b/views/_mixins/mdc/index.pug
deleted file mode 100644
index f718893..0000000
--- a/views/_mixins/mdc/index.pug
+++ /dev/null
@@ -1,2 +0,0 @@
-include button
-include textfield
\ No newline at end of file
diff --git a/views/auth/login.pug b/views/auth/login.pug
deleted file mode 100644
index 939669e..0000000
--- a/views/auth/login.pug
+++ /dev/null
@@ -1,21 +0,0 @@
-extends ../_layout
-
-block header
-
-block content
- form(id='login-form' class='auth-form' method='POST' action='/auth/login').mdc-card
- header.mdc-card__primary
- h1.mdc-card__title.mdc-card__title--large= title
-
- section.mdc-card__supporting-text
- div.mdc-text-field
- input.mdc-text-field__input(type='email' name='email' placeholder='Электронная почта' required)
- div.mdc-text-field
- input.mdc-text-field__input(type='password' name='password' placeholder='Пароль' required)
-
- footer.mdc-card__actions
- button.mdc-button.mdc-card__action.mdc-button--raised.mdc-button--dense(type='submit') Войти
- a.mdc-button.mdc-card__action.mdc-button--dense(href='/auth/register') Зарегистрироваться
-
- section.mdc-card__actions
- a.mdc-button.mdc-card__action.mdc-button--dense(href='/auth/reset-password') Восстановить пароль
\ No newline at end of file
diff --git a/views/auth/register.pug b/views/auth/register.pug
deleted file mode 100644
index 163a97d..0000000
--- a/views/auth/register.pug
+++ /dev/null
@@ -1,20 +0,0 @@
-extends ../_layout
-
-block header
-
-block content
- form(id='register-form' class='auth-form' method='POST' action='/auth/register').mdc-card
- header.mdc-card__primary
- h1.mdc-card__title.mdc-card__title--large= title
-
- section.mdc-card__supporting-text
- div.mdc-text-field
- input.mdc-text-field__input(type='email' name='email' placeholder='Электронная почта')
- div.mdc-text-field
- input.mdc-text-field__input(type='password' name='password' placeholder='Пароль')
- div.mdc-text-field
- input.mdc-text-field__input(type='password' name='confirmPassword' placeholder='Подтвердите пароль')
-
- footer.mdc-card__actions
- button.mdc-button.mdc-card__action.mdc-button--raised.mdc-button--dense(type='submit') Зарегистрироваться
- a.mdc-button.mdc-card__action.mdc-button--dense(href='/auth/login') Войти
\ No newline at end of file
diff --git a/views/dev.pug b/views/dev.pug
deleted file mode 100644
index e69de29..0000000
diff --git a/views/index.pug b/views/index.pug
deleted file mode 100644
index 4196241..0000000
--- a/views/index.pug
+++ /dev/null
@@ -1,4 +0,0 @@
-extends _layout
-
-block content
- h1 Главная страница
\ No newline at end of file
diff --git a/views/profile/edit.pug b/views/profile/edit.pug
deleted file mode 100644
index e69de29..0000000
diff --git a/views/profile/index.pug b/views/profile/index.pug
deleted file mode 100644
index 70245e8..0000000
--- a/views/profile/index.pug
+++ /dev/null
@@ -1,7 +0,0 @@
-extends ../_layout
-
-block sidenav
-
-block main
- main#main
- h1=user.email
\ No newline at end of file