From 4111b3229d005c02d6cb562f4465b97b5b283134 Mon Sep 17 00:00:00 2001 From: Amber Yan Date: Tue, 12 Oct 2021 14:39:08 +0800 Subject: [PATCH 001/135] add proxyquire & sequelize-mock npm lib --- package-lock.json | 44 ++++++++++++++++++++++++++++++++++++++++++++ package.json | 4 ++++ 2 files changed, 48 insertions(+) diff --git a/package-lock.json b/package-lock.json index 6cdb461e..4d773f32 100644 --- a/package-lock.json +++ b/package-lock.json @@ -581,6 +581,16 @@ "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==" }, + "fill-keys": { + "version": "1.0.2", + "resolved": "http://npm.ooapi.com:4873/fill-keys/-/fill-keys-1.0.2.tgz", + "integrity": "sha1-mo+jb06K1jTjv2tPPIiCVRRS6yA=", + "dev": true, + "requires": { + "is-object": "~1.0.1", + "merge-descriptors": "~1.0.0" + } + }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -822,6 +832,12 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" }, + "is-object": { + "version": "1.0.2", + "resolved": "http://npm.ooapi.com:4873/is-object/-/is-object-1.0.2.tgz", + "integrity": "sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==", + "dev": true + }, "is-plain-obj": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", @@ -1075,6 +1091,12 @@ } } }, + "module-not-found-error": { + "version": "1.0.1", + "resolved": "http://npm.ooapi.com:4873/module-not-found-error/-/module-not-found-error-1.0.1.tgz", + "integrity": "sha1-z4tP9PKWQGdNbN0CsOO8UjwrvcA=", + "dev": true + }, "moment": { "version": "2.29.1", "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", @@ -1278,6 +1300,17 @@ "ipaddr.js": "1.9.1" } }, + "proxyquire": { + "version": "2.1.3", + "resolved": "http://npm.ooapi.com:4873/proxyquire/-/proxyquire-2.1.3.tgz", + "integrity": "sha512-BQWfCqYM+QINd+yawJz23tbBM40VIGXOdDw3X344KcclI/gtBbdWF6SlQ4nK/bYhF9d27KYug9WzljHC6B9Ysg==", + "dev": true, + "requires": { + "fill-keys": "^1.0.2", + "module-not-found-error": "^1.0.1", + "resolve": "^1.11.1" + } + }, "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", @@ -1453,6 +1486,17 @@ "yargs": "^13.1.0" } }, + "sequelize-mock": { + "version": "0.10.2", + "resolved": "http://npm.ooapi.com:4873/sequelize-mock/-/sequelize-mock-0.10.2.tgz", + "integrity": "sha1-GdOXHM2utbhkFwwkznkqinHxRL0=", + "dev": true, + "requires": { + "bluebird": "^3.4.6", + "inflection": "^1.10.0", + "lodash": "^4.16.4" + } + }, "sequelize-pool": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/sequelize-pool/-/sequelize-pool-6.1.0.tgz", diff --git a/package.json b/package.json index dd99a5f1..c25bd055 100644 --- a/package.json +++ b/package.json @@ -27,5 +27,9 @@ "sequelize-cli": "^6.2.0", "sinon": "^9.2.0", "supertest": "^5.0.0" + }, + "devDependencies": { + "proxyquire": "^2.1.3", + "sequelize-mock": "^0.10.2" } } From 161a8374c8828e52923a8077fdc9d04ff669b7a4 Mon Sep 17 00:00:00 2001 From: Amber Yan Date: Tue, 12 Oct 2021 14:39:53 +0800 Subject: [PATCH 002/135] add new A17 test --- tests/A17.test.js | 142 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 tests/A17.test.js diff --git a/tests/A17.test.js b/tests/A17.test.js new file mode 100644 index 00000000..e04cface --- /dev/null +++ b/tests/A17.test.js @@ -0,0 +1,142 @@ +const chai = require('chai') +const request = require('supertest') +const sinon = require('sinon') +const should = chai.should() +const SequelizeMock = require('sequelize-mock'); +const proxyquire = require('proxyquire'); + +const dbMock = new SequelizeMock(); + +const app = require('../app'); + +const mockRequest = (query) => { + return { + ...query, + flash: sinon.spy() + }; +}; +const mockResponse = () => { + return { + redirect: sinon.spy() + } +}; + +describe('# A17', () => { + describe('登入測試: POST /signin', function(){ + it('should fail without proper username', function(done){ + request(app) + .post('/signin') + .type('urlencoded') + .send('email=root@example.com&password=123') + .expect('Location', '/signin') + .expect(302, done) + }) + + it('should fail without proper password', function(done){ + request(app) + .post('/signin') + .type('urlencoded') + .send('email=tu&password=12345678') + .expect('Location', '/signin') + .expect(302, done) + }) + + it('should succeed with proper credentials', function(done){ + request(app) + .post('/signin') + .type('urlencoded') + .send('email=root@example.com&password=12345678') + .expect('Location', '/') + .expect(302, done) + }) + }); + + describe('# A17: 使用者權限管理', function () { + before(() => { + this.UserMock = dbMock.define('User', { + id: 1, + email: 'root@example.com', + name: 'admin', + isAdmin: false, + }); + + this.adminController = proxyquire('../controllers/adminController', { + '../models': { User: this.UserMock } + }); + }) + + context('# [顯示使用者清單]', () => { + it(" GET /admin/users ", (done) => { + const req = {} + const res = { + render: (_, results) => { + results.users[0].name.should.equal("admin"); + done() + } + }; + + this.adminController.getUsers(req, res); + }); + }) + + context('# [修改使用者權限] for admin', () => { + before(() => { + this.UserMock = dbMock.define('User', { + id: 1, + email: 'root@example.com', + name: 'admin', + isAdmin: false, + }); + + this.adminController = proxyquire('../controllers/adminController', { + '../models': { User: this.UserMock } + }); + }) + + it(" PUT /admin/users/:id/toggleAdmin ", async () => { + const req = mockRequest({params: {id: 1}}); + const res = mockResponse(); + + await this.adminController.toggleAdmin(req, res); + + req.flash.calledWith('error_messages', 'core manager can not be changed').should.be.true; + res.redirect.calledWith('back').should.be.true; + }); + }) + + context('# [修改使用者權限] for user', () => { + before(() => { + this.UserMock = dbMock.define('User', { + id: 1, + email: 'user@example.com', + name: 'user', + isAdmin: false, + }, { + instanceMethods: { + update: (changes) => { + this.UserMock._defaults = {...changes}; + return Promise.resolve(); + } + } + }); + + this.adminController = proxyquire('../controllers/adminController', { + '../models': { User: this.UserMock } + }); + }) + + it(" PUT /admin/users/:id/toggleAdmin ", async () => { + const req = mockRequest({params: {id: 1}}); + const res = mockResponse(); + + await this.adminController.toggleAdmin(req, res); + + req.flash.calledWith('success_messages', 'user was successfully to update').should.be.true; + res.redirect.calledWith('/admin/users').should.be.true; + + const user = await this.UserMock.findOne({where: {id: 1}}); + user.isAdmin.should.equal(true); + }); + }) + }) +}) \ No newline at end of file From bb8ce8949d17ff04efd7fa721d3645f01c0a8988 Mon Sep 17 00:00:00 2001 From: Stanney Date: Tue, 19 Oct 2021 02:08:00 +0800 Subject: [PATCH 003/135] tests/A17.test.js added comments --- config/config.json | 2 +- package-lock.json | 2494 +++++++++++++++++++++++++++++++++++++++++++- tests/A17.test.js | 60 +- 3 files changed, 2524 insertions(+), 32 deletions(-) diff --git a/config/config.json b/config/config.json index 56636a1c..bfb32f98 100644 --- a/config/config.json +++ b/config/config.json @@ -1,7 +1,7 @@ { "development": { "username": "root", - "password": "password", + "password": "", "database": "forum", "host": "127.0.0.1", "dialect": "mysql" diff --git a/package-lock.json b/package-lock.json index 4d773f32..7ebc04a3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,8 +1,2480 @@ { "name": "forum-express-workspace", "version": "1.0.0", - "lockfileVersion": 1, + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "name": "forum-express-workspace", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "chai": "^4.2.0", + "express": "^4.17.1", + "mocha": "^8.2.0", + "mysql2": "^2.2.5", + "sequelize": "^6.3.5", + "sequelize-cli": "^6.2.0", + "sinon": "^9.2.0", + "supertest": "^5.0.0" + }, + "devDependencies": { + "proxyquire": "^2.1.3", + "sequelize-mock": "^0.10.2" + } + }, + "node_modules/@sinonjs/commons": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.1.tgz", + "integrity": "sha512-892K+kWUUi3cl+LlqEWIDrhvLgdL79tECi8JZUyq6IviKy/DNhuzCRlbHUjxK89f4ypPMMaFnFuR9Ie6DoIMsw==", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", + "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", + "dependencies": { + "@sinonjs/commons": "^1.7.0" + } + }, + "node_modules/@sinonjs/formatio": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-5.0.1.tgz", + "integrity": "sha512-KaiQ5pBf1MpS09MuA0kp6KBQt2JUOQycqVG1NZXvzeaXe5LGFqAKueIS0bw4w0P9r7KuBSVdUk5QjXsUdu2CxQ==", + "dependencies": { + "@sinonjs/commons": "^1", + "@sinonjs/samsam": "^5.0.2" + } + }, + "node_modules/@sinonjs/samsam": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-5.2.0.tgz", + "integrity": "sha512-CaIcyX5cDsjcW/ab7HposFWzV1kC++4HNsfnEdFJa7cP1QIuILAKV+BgfeqRXhcnSAc76r/Rh/O5C+300BwUIw==", + "dependencies": { + "@sinonjs/commons": "^1.6.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" + } + }, + "node_modules/@sinonjs/text-encoding": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", + "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==" + }, + "node_modules/@types/node": { + "version": "14.14.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.5.tgz", + "integrity": "sha512-H5Wn24s/ZOukBmDn03nnGTp18A60ny9AmCwnEcgJiTgSGsCO7k+NWP7zjCCbhlcnVCoI+co52dUAt9GMhOSULw==" + }, + "node_modules/@ungap/promise-all-settled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", + "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==" + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "node_modules/accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "dependencies": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=" + }, + "node_modules/anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "engines": { + "node": "*" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "node_modules/balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "node_modules/binary-extensions": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", + "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + }, + "node_modules/body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "dependencies": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==" + }, + "node_modules/bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/chai": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", + "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^3.0.1", + "get-func-name": "^2.0.0", + "pathval": "^1.1.0", + "type-detect": "^4.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/chalk/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/chalk/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "engines": { + "node": "*" + } + }, + "node_modules/chokidar": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz", + "integrity": "sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==", + "dependencies": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.5.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.1.2" + } + }, + "node_modules/cli-color": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-1.4.0.tgz", + "integrity": "sha512-xu6RvQqqrWEo6MPR1eixqGPywhYBHRs653F9jfXB2Hx4jdM/3WxiNE1vppRmxtMIfl16SFYTpYlrnqH/HsK/2w==", + "dependencies": { + "ansi-regex": "^2.1.1", + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "memoizee": "^0.4.14", + "timers-ext": "^0.1.5" + } + }, + "node_modules/cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dependencies": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "node_modules/component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "node_modules/config-chain": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz", + "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==", + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "node_modules/content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/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==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "node_modules/cookiejar": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz", + "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==" + }, + "node_modules/d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "dependencies": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/denque": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/denque/-/denque-1.4.1.tgz", + "integrity": "sha512-OfzPuSZKGcgr96rf1oODnfjqBFmr1DVoc/TrItj3Ohe0Ah1C5WX5Baquw/9U9KovnQ88EqmJbD66rKYUQYN1tQ==", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dottie": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.2.tgz", + "integrity": "sha512-fmrwR04lsniq/uSr8yikThDTrM7epXHBAAjH9TbeH3rEA8tdCO7mRzB9hdmdGyJCxF8KERo9CITcm3kGuoyMhg==" + }, + "node_modules/editorconfig": { + "version": "0.15.3", + "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz", + "integrity": "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==", + "dependencies": { + "commander": "^2.19.0", + "lru-cache": "^4.1.5", + "semver": "^5.6.0", + "sigmund": "^1.0.1" + }, + "bin": { + "editorconfig": "bin/editorconfig" + } + }, + "node_modules/editorconfig/node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/editorconfig/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/editorconfig/node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "node_modules/emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/es5-ext": { + "version": "0.10.53", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", + "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", + "dependencies": { + "es6-iterator": "~2.0.3", + "es6-symbol": "~3.1.3", + "next-tick": "~1.0.0" + } + }, + "node_modules/es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "dependencies": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, + "node_modules/es6-weak-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", + "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", + "dependencies": { + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", + "dependencies": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "node_modules/express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "dependencies": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/ext": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", + "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", + "dependencies": { + "type": "^2.0.0" + } + }, + "node_modules/ext/node_modules/type": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/type/-/type-2.1.0.tgz", + "integrity": "sha512-G9absDWvhAWCV2gmF1zKud3OyC61nZDwWvBL2DApaVFogI07CprggiQAOOjvp2NRjYWFzPyu7vwtDrQFq8jeSA==" + }, + "node_modules/fast-safe-stringify": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", + "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==" + }, + "node_modules/fill-keys": { + "version": "1.0.2", + "resolved": "http://npm.ooapi.com:4873/fill-keys/-/fill-keys-1.0.2.tgz", + "integrity": "sha1-mo+jb06K1jTjv2tPPIiCVRRS6yA=", + "dev": true, + "dependencies": { + "is-object": "~1.0.1", + "merge-descriptors": "~1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "bin": { + "flat": "cli.js" + } + }, + "node_modules/form-data": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.0.tgz", + "integrity": "sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/formidable": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.2.tgz", + "integrity": "sha512-V8gLm+41I/8kguQ4/o1D3RIHRmhYFG4pnNyonvua+40rqcEmT4+V71yaZ3B457xbbgCsCfjSPi65u/W6vK1U5Q==", + "funding": { + "url": "https://ko-fi.com/tunnckoCore/commissions" + } + }, + "node_modules/forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "node_modules/fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "deprecated": "\"Please update to latest v2.3 or v2.2\"", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/generate-function": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", + "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", + "dependencies": { + "is-property": "^1.0.2" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "engines": { + "node": "*" + } + }, + "node_modules/glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==" + }, + "node_modules/growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "engines": { + "node": ">=4.x" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "bin": { + "he": "bin/he" + } + }, + "node_modules/http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inflection": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz", + "integrity": "sha1-ogCTVlbW9fa8TcdQLhrstwMihBY=", + "engines": [ + "node >= 0.4.0" + ] + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "node_modules/ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "deprecated": "Please update to ini >=1.3.6 to avoid a prototype pollution issue", + "engines": { + "node": "*" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.0.0.tgz", + "integrity": "sha512-jq1AH6C8MuteOoBPwkxHafmByhL9j5q4OaPGdbuD+ZtQJVzH+i6E3BJDQcBA09k57i2Hh2yQbEG8yObZ0jdlWw==", + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "engines": { + "node": ">=4" + } + }, + "node_modules/is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-object": { + "version": "1.0.2", + "resolved": "http://npm.ooapi.com:4873/is-object/-/is-object-1.0.2.tgz", + "integrity": "sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-promise": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==" + }, + "node_modules/is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=" + }, + "node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "node_modules/js-beautify": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.13.0.tgz", + "integrity": "sha512-/Tbp1OVzZjbwzwJQFIlYLm9eWQ+3aYbBXLSaqb1mEJzhcQAfrqMMQYtjb6io+U6KpD0ID4F+Id3/xcjH3l/sqA==", + "dependencies": { + "config-chain": "^1.1.12", + "editorconfig": "^0.15.3", + "glob": "^7.1.3", + "mkdirp": "^1.0.4", + "nopt": "^5.0.0" + }, + "bin": { + "css-beautify": "js/bin/css-beautify.js", + "html-beautify": "js/bin/html-beautify.js", + "js-beautify": "js/bin/js-beautify.js" + } + }, + "node_modules/js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/just-extend": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.1.1.tgz", + "integrity": "sha512-aWgeGFW67BP3e5181Ep1Fv2v8z//iBJfrvyTnq8wG86vEESwmonn1zPBJ0VfmT9CJq2FIT0VsETtrNFm2a+SHA==" + }, + "node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" + }, + "node_modules/lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" + }, + "node_modules/log-symbols": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", + "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==", + "dependencies": { + "chalk": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/lru-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", + "integrity": "sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM=", + "dependencies": { + "es5-ext": "~0.10.2" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memoizee": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.14.tgz", + "integrity": "sha512-/SWFvWegAIYAO4NQMpcX+gcra0yEZu4OntmUdrBaWrJncxOqAziGFlHxc7yjKVK2uu3lpPW27P27wkR82wA8mg==", + "dependencies": { + "d": "1", + "es5-ext": "^0.10.45", + "es6-weak-map": "^2.0.2", + "event-emitter": "^0.3.5", + "is-promise": "^2.1", + "lru-queue": "0.1", + "next-tick": "1", + "timers-ext": "^0.1.5" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", + "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.27", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", + "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", + "dependencies": { + "mime-db": "1.44.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.2.0.tgz", + "integrity": "sha512-lEWEMq2LMfNJMKeuEwb5UELi+OgFDollXaytR5ggQcHpzG3NP/R7rvixAvF+9/lLsTWhWG+4yD2M70GsM06nxw==", + "dependencies": { + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.4.3", + "debug": "4.2.0", + "diff": "4.0.2", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.1.6", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "3.14.0", + "log-symbols": "4.0.0", + "minimatch": "3.0.4", + "ms": "2.1.2", + "nanoid": "3.1.12", + "serialize-javascript": "5.0.1", + "strip-json-comments": "3.1.1", + "supports-color": "7.2.0", + "which": "2.0.2", + "wide-align": "1.1.3", + "workerpool": "6.0.2", + "yargs": "13.3.2", + "yargs-parser": "13.1.2", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha" + }, + "engines": { + "node": ">= 10.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/mocha/node_modules/debug": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/mocha/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/mocha/node_modules/p-limit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.0.2.tgz", + "integrity": "sha512-iwqZSOoWIW+Ew4kAGUlN16J4M7OB3ysMLSZtnhmqx7njIHFPlxWBX8xo3lVTyFVq6mI/lL9qt2IsN1sHwaxJkg==", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/module-not-found-error": { + "version": "1.0.1", + "resolved": "http://npm.ooapi.com:4873/module-not-found-error/-/module-not-found-error-1.0.1.tgz", + "integrity": "sha1-z4tP9PKWQGdNbN0CsOO8UjwrvcA=", + "dev": true + }, + "node_modules/moment": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", + "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==", + "engines": { + "node": "*" + } + }, + "node_modules/moment-timezone": { + "version": "0.5.31", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.31.tgz", + "integrity": "sha512-+GgHNg8xRhMXfEbv81iDtrVeTcWt0kWmTEY1XQK14dICTXnWJnT0dxdlPspwqF3keKMVPXwayEsk1DI0AA/jdA==", + "dependencies": { + "moment": ">= 2.9.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/mysql2": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-2.2.5.tgz", + "integrity": "sha512-XRqPNxcZTpmFdXbJqb+/CtYVLCx14x1RTeNMD4954L331APu75IC74GDqnZMEt1kwaXy6TySo55rF2F3YJS78g==", + "dependencies": { + "denque": "^1.4.1", + "generate-function": "^2.3.1", + "iconv-lite": "^0.6.2", + "long": "^4.0.0", + "lru-cache": "^6.0.0", + "named-placeholders": "^1.1.2", + "seq-queue": "^0.0.5", + "sqlstring": "^2.3.2" + }, + "engines": { + "node": ">= 8.0" + } + }, + "node_modules/mysql2/node_modules/iconv-lite": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz", + "integrity": "sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/named-placeholders": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.2.tgz", + "integrity": "sha512-wiFWqxoLL3PGVReSZpjLVxyJ1bRqe+KKJVbr4hGs1KWfTZTQyezHFBbuKj9hsizHyGV2ne7EMjHdxEGAybD5SA==", + "dependencies": { + "lru-cache": "^4.1.3" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/named-placeholders/node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/named-placeholders/node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" + }, + "node_modules/nanoid": { + "version": "3.1.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.12.tgz", + "integrity": "sha512-1qstj9z5+x491jfiC4Nelk+f8XBad7LN20PmyWINJEMRSf3wcAjAWysw1qaA8z6NSKe2sjq1hRSDpBH5paCb6A==", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || >=13.7" + } + }, + "node_modules/negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/next-tick": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" + }, + "node_modules/nise": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/nise/-/nise-4.0.4.tgz", + "integrity": "sha512-bTTRUNlemx6deJa+ZyoCUTRvH3liK5+N6VQZ4NIw90AgDXY6iPnsqplNFf6STcj+ePk0H/xqxnP75Lr0J0Fq3A==", + "dependencies": { + "@sinonjs/commons": "^1.7.0", + "@sinonjs/fake-timers": "^6.0.0", + "@sinonjs/text-encoding": "^0.7.1", + "just-extend": "^4.0.2", + "path-to-regexp": "^1.7.0" + } + }, + "node_modules/nise/node_modules/path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "dependencies": { + "isarray": "0.0.1" + } + }, + "node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "engines": { + "node": ">=4" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" + }, + "node_modules/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=" + }, + "node_modules/pathval": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", + "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", + "engines": { + "node": "*" + } + }, + "node_modules/picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=" + }, + "node_modules/proxy-addr": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", + "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", + "dependencies": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxyquire": { + "version": "2.1.3", + "resolved": "http://npm.ooapi.com:4873/proxyquire/-/proxyquire-2.1.3.tgz", + "integrity": "sha512-BQWfCqYM+QINd+yawJz23tbBM40VIGXOdDw3X344KcclI/gtBbdWF6SlQ4nK/bYhF9d27KYug9WzljHC6B9Ysg==", + "dev": true, + "dependencies": { + "fill-keys": "^1.0.2", + "module-not-found-error": "^1.0.1", + "resolve": "^1.11.1" + } + }, + "node_modules/pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" + }, + "node_modules/qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "dependencies": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", + "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" + }, + "node_modules/resolve": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.18.1.tgz", + "integrity": "sha512-lDfCPaMKfOJXjy0dPayzPdF1phampNWr3qFCjAu+rw/qbQmr5jWH5xN2hwh9QKfw9E5v4hwV7A+jrCmL8yjjqA==", + "dependencies": { + "is-core-module": "^2.0.0", + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/retry-as-promised": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/retry-as-promised/-/retry-as-promised-3.2.0.tgz", + "integrity": "sha512-CybGs60B7oYU/qSQ6kuaFmRd9sTZ6oXSc0toqePvV74Ac6/IFZSI1ReFQmtCN+uvW1Mtqdwpvt/LGOiCBAY2Mg==", + "dependencies": { + "any-promise": "^1.3.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "dependencies": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + }, + "node_modules/seq-queue": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", + "integrity": "sha1-1WgS4cAXpuTnw+Ojeh2m143TyT4=" + }, + "node_modules/sequelize": { + "version": "6.3.5", + "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-6.3.5.tgz", + "integrity": "sha512-MiwiPkYSA8NWttRKAXdU9h0TxP6HAc1fl7qZmMO/VQqQOND83G4nZLXd0kWILtAoT9cxtZgFqeb/MPYgEeXwsw==", + "dependencies": { + "debug": "^4.1.1", + "dottie": "^2.0.0", + "inflection": "1.12.0", + "lodash": "^4.17.15", + "moment": "^2.26.0", + "moment-timezone": "^0.5.31", + "retry-as-promised": "^3.2.0", + "semver": "^7.3.2", + "sequelize-pool": "^6.0.0", + "toposort-class": "^1.0.1", + "uuid": "^8.1.0", + "validator": "^10.11.0", + "wkx": "^0.5.0" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependenciesMeta": { + "mariadb": { + "optional": true + }, + "mysql2": { + "optional": true + }, + "pg": { + "optional": true + }, + "pg-hstore": { + "optional": true + }, + "sqlite3": { + "optional": true + }, + "tedious": { + "optional": true + } + } + }, + "node_modules/sequelize-cli": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/sequelize-cli/-/sequelize-cli-6.2.0.tgz", + "integrity": "sha512-6WQ2x91hg30dUn66mXHnzvHATZ4pyI1GHSNbS/TNN/vRR4BLRSLijadeMgC8zqmKDsL0VqzVVopJWfJakuP++Q==", + "dependencies": { + "cli-color": "^1.4.0", + "fs-extra": "^7.0.1", + "js-beautify": "^1.8.8", + "lodash": "^4.17.5", + "resolve": "^1.5.0", + "umzug": "^2.3.0", + "yargs": "^13.1.0" + }, + "bin": { + "sequelize": "lib/sequelize", + "sequelize-cli": "lib/sequelize" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/sequelize-mock": { + "version": "0.10.2", + "resolved": "http://npm.ooapi.com:4873/sequelize-mock/-/sequelize-mock-0.10.2.tgz", + "integrity": "sha1-GdOXHM2utbhkFwwkznkqinHxRL0=", + "dev": true, + "dependencies": { + "bluebird": "^3.4.6", + "inflection": "^1.10.0", + "lodash": "^4.16.4" + } + }, + "node_modules/sequelize-pool": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/sequelize-pool/-/sequelize-pool-6.1.0.tgz", + "integrity": "sha512-4YwEw3ZgK/tY/so+GfnSgXkdwIJJ1I32uZJztIEgZeAO6HMgj64OzySbWLgxj+tXhZCJnzRfkY9gINw8Ft8ZMg==", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/sequelize/node_modules/debug": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/sequelize/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/serialize-javascript": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", + "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + }, + "node_modules/setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "node_modules/sigmund": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", + "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=" + }, + "node_modules/sinon": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-9.2.0.tgz", + "integrity": "sha512-eSNXz1XMcGEMHw08NJXSyTHIu6qTCOiN8x9ODACmZpNQpr0aXTBXBnI4xTzQzR+TEpOmLiKowGf9flCuKIzsbw==", + "dependencies": { + "@sinonjs/commons": "^1.8.1", + "@sinonjs/fake-timers": "^6.0.1", + "@sinonjs/formatio": "^5.0.1", + "@sinonjs/samsam": "^5.2.0", + "diff": "^4.0.2", + "nise": "^4.0.4", + "supports-color": "^7.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/sinon" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, + "node_modules/sqlstring": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.2.tgz", + "integrity": "sha512-vF4ZbYdKS8OnoJAWBmMxCQDkiEBkGQYU7UZPtL8flbDRSNkhaXvRJ279ZtI6M+zDaQovVU4tuRgzK5fVhvFAhg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/superagent": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-6.1.0.tgz", + "integrity": "sha512-OUDHEssirmplo3F+1HWKUrUjvnQuA+nZI6i/JJBdXb5eq9IyEQwPyPpqND+SSsxf6TygpBEkUjISVRN4/VOpeg==", + "dependencies": { + "component-emitter": "^1.3.0", + "cookiejar": "^2.1.2", + "debug": "^4.1.1", + "fast-safe-stringify": "^2.0.7", + "form-data": "^3.0.0", + "formidable": "^1.2.2", + "methods": "^1.1.2", + "mime": "^2.4.6", + "qs": "^6.9.4", + "readable-stream": "^3.6.0", + "semver": "^7.3.2" + }, + "engines": { + "node": ">= 7.0.0" + } + }, + "node_modules/superagent/node_modules/debug": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/superagent/node_modules/mime": { + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz", + "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/superagent/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/superagent/node_modules/qs": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz", + "integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==", + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/supertest": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-5.0.0.tgz", + "integrity": "sha512-2JAWpPrUOZF4hHH5ZTCN2xjKXvJS3AEwPNXl0HUseHsfcXFvMy9kcsufIHCNAmQ5hlGCvgeAqaR5PBEouN3hlQ==", + "dependencies": { + "methods": "1.1.2", + "superagent": "6.1.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/timers-ext": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz", + "integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==", + "dependencies": { + "es5-ext": "~0.10.46", + "next-tick": "1" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/toposort-class": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toposort-class/-/toposort-class-1.0.1.tgz", + "integrity": "sha1-f/0feMi+KMO6Rc1OGj9e4ZO9mYg=" + }, + "node_modules/type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "engines": { + "node": ">=4" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/umzug": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/umzug/-/umzug-2.3.0.tgz", + "integrity": "sha512-Z274K+e8goZK8QJxmbRPhl89HPO1K+ORFtm6rySPhFKfKc5GHhqdzD0SGhSWHkzoXasqJuItdhorSvY7/Cgflw==", + "dependencies": { + "bluebird": "^3.7.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.1.tgz", + "integrity": "sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/validator": { + "version": "10.11.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-10.11.0.tgz", + "integrity": "sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" + }, + "node_modules/wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dependencies": { + "string-width": "^1.0.2 || 2" + } + }, + "node_modules/wide-align/node_modules/ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "engines": { + "node": ">=4" + } + }, + "node_modules/wide-align/node_modules/string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dependencies": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/wide-align/node_modules/strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dependencies": { + "ansi-regex": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/wkx": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/wkx/-/wkx-0.5.0.tgz", + "integrity": "sha512-Xng/d4Ichh8uN4l0FToV/258EjMGU9MGcA0HV2d9B/ZpZB3lqQm7nkOdZdm5GhKtLLhAE7PiVQwN4eN+2YJJUg==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/workerpool": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.0.2.tgz", + "integrity": "sha512-DSNyvOpFKrNusaaUwk+ej6cBj1bmhLcBfj80elGk+ZIo5JSkq+unB1dLKEOcNfJDZgjGICfhQ0Q5TbP0PvF4+Q==" + }, + "node_modules/wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dependencies": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "node_modules/y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==" + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dependencies": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + }, + "node_modules/yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser/node_modules/camelcase": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", + "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yargs-unparser/node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + }, "dependencies": { "@sinonjs/commons": { "version": "1.8.1", @@ -1565,16 +4037,6 @@ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, "string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -1590,6 +4052,16 @@ } } }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, "strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", diff --git a/tests/A17.test.js b/tests/A17.test.js index e04cface..fe0fe948 100644 --- a/tests/A17.test.js +++ b/tests/A17.test.js @@ -7,7 +7,8 @@ const proxyquire = require('proxyquire'); const dbMock = new SequelizeMock(); -const app = require('../app'); +const app = require('../../app'); +const { classToInvokable } = require('sequelize/types/lib/utils'); const mockRequest = (query) => { return { @@ -23,7 +24,7 @@ const mockResponse = () => { describe('# A17', () => { describe('登入測試: POST /signin', function(){ - it('should fail without proper username', function(done){ + it('#1 密碼錯誤', function(done){ request(app) .post('/signin') .type('urlencoded') @@ -32,7 +33,7 @@ describe('# A17', () => { .expect(302, done) }) - it('should fail without proper password', function(done){ + it('#2 帳號錯誤', function(done){ request(app) .post('/signin') .type('urlencoded') @@ -41,7 +42,7 @@ describe('# A17', () => { .expect(302, done) }) - it('should succeed with proper credentials', function(done){ + it('#3 成功登入', function(done){ request(app) .post('/signin') .type('urlencoded') @@ -53,42 +54,50 @@ describe('# A17', () => { describe('# A17: 使用者權限管理', function () { before(() => { + // 製作假 db 資料: UserMock this.UserMock = dbMock.define('User', { id: 1, email: 'root@example.com', name: 'admin', isAdmin: false, }); - - this.adminController = proxyquire('../controllers/adminController', { + // 將 mock user db 中的 findByPK 用 findOne 取代 (sequelize mock not support findByPK) + this.UserMock.findByPk = (id) => this.UserMock.findOne({where: {id: id}}); + // 將 adminController 中的 User db 取代成 User mock db + this.adminController = proxyquire('../../controllers/adminController', { '../models': { User: this.UserMock } }); }) context('# [顯示使用者清單]', () => { - it(" GET /admin/users ", (done) => { - const req = {} - const res = { - render: (_, results) => { - results.users[0].name.should.equal("admin"); - done() - } - }; + it(" GET /admin/users ", async () => { + // 製作假 request & response + const req = mockRequest(); + const res = mockResponse(); - this.adminController.getUsers(req, res); + // 測試 adminController.getUsers function + await this.adminController.getUsers(req, res); + + // render 裡的第二個參數,回傳了 users, 名稱必須跟假資料一樣是 admin + res.render.getCall(0).args[1].users[0].name.should.equal('admin'); }); }) context('# [修改使用者權限] for admin', () => { before(() => { + // 製作假 db 資料: UserMock this.UserMock = dbMock.define('User', { id: 1, email: 'root@example.com', name: 'admin', - isAdmin: false, + isAdmin: true, }); - - this.adminController = proxyquire('../controllers/adminController', { + // 將 mock user db 中的 findByPK 用 findOne 取代 (sequelize mock not support findByPK) + // 將 count 的 function 預設回傳假資料數目 1 + this.UserMock.count = () => 1; + this.UserMock.findByPk = (id) => this.UserMock.findOne({where: {id: id}}); + // 將 adminController 中的 User db 取代成 User mock db + this.adminController = proxyquire('../../controllers/adminController', { '../models': { User: this.UserMock } }); }) @@ -97,9 +106,12 @@ describe('# A17', () => { const req = mockRequest({params: {id: 1}}); const res = mockResponse(); + // 測試 adminController.toggleAdmin function await this.adminController.toggleAdmin(req, res); + // 執行完 toggleAdmin 後,res.flash 有被呼叫而且呼叫的訊息正確 req.flash.calledWith('error_messages', 'core manager can not be changed').should.be.true; + // 執行完 toggleAmin 後 res.redirect 有被呼叫而且 redirect 到 back res.redirect.calledWith('back').should.be.true; }); }) @@ -113,19 +125,23 @@ describe('# A17', () => { isAdmin: false, }, { instanceMethods: { + // 模擬 update 函數,並依據傳入的變數,跟著修正,如果傳入 {isAdmin: true},假資料中的 isAdmin 變會變成 true update: (changes) => { this.UserMock._defaults = {...changes}; return Promise.resolve(); } } }); + + this.UserMock.count = () => 1; + this.UserMock.findByPk = (id) => this.UserMock.findOne({where: {id: id}}); - this.adminController = proxyquire('../controllers/adminController', { + this.adminController = proxyquire('../../controllers/adminController', { '../models': { User: this.UserMock } }); }) - it(" PUT /admin/users/:id/toggleAdmin ", async () => { + it(" PUT /admin/users/:id/toggleAdmin ", async (done) => { const req = mockRequest({params: {id: 1}}); const res = mockResponse(); @@ -134,8 +150,12 @@ describe('# A17', () => { req.flash.calledWith('success_messages', 'user was successfully to update').should.be.true; res.redirect.calledWith('/admin/users').should.be.true; + // 執行完 toggleAmin 後,因為假資料中使用者是 user@example.com,因此可以修改權限 isAdmin 從 false -> true + // 所以這邊將假資料撈出,比對看是否有修改到 const user = await this.UserMock.findOne({where: {id: 1}}); user.isAdmin.should.equal(true); + + done() }); }) }) From c15fe793c388a5ad9894838b0d84ff2715400cc0 Mon Sep 17 00:00:00 2001 From: Stanney Date: Tue, 19 Oct 2021 02:09:43 +0800 Subject: [PATCH 004/135] add A19 test --- tests/A19.test.js | 157 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 tests/A19.test.js diff --git a/tests/A19.test.js b/tests/A19.test.js new file mode 100644 index 00000000..996f9939 --- /dev/null +++ b/tests/A19.test.js @@ -0,0 +1,157 @@ +const chai = require('chai') +const request = require('supertest') +const sinon = require('sinon') +const should = chai.should() + +const app = require('../../app') +const routes = require('../../routes/index') +const db = require('../../models') +const helpers = require('../../_helpers'); +const SequelizeMock = require('sequelize-mock'); +const proxyquire = require('proxyquire'); + +const dbMock = new SequelizeMock(); + +const mockRequest = (query) => { + return { + ...query, + flash: sinon.spy() + }; +}; +const mockResponse = () => { + return { + redirect: sinon.spy(), + render: sinon.spy(), + } +}; +describe('# A19', () => { + describe('# A19: 建立 User Profile', function() { + context('# [瀏覽 Profile]', () => { + before(() => { + this.ensureAuthenticated = sinon.stub( + helpers, 'ensureAuthenticated' + ).returns(true); + this.getUser = sinon.stub( + helpers, 'getUser' + ).returns({id: 1}); + this.UserMock = dbMock.define('User', { + id: 1, + email: 'root@example.com', + name: 'admin', + isAdmin: false, + }); + + this.UserMock.findByPk = (id) => this.UserMock.findOne({where: {id: id}}); + + this.userController = proxyquire('../../controllers/userController', { + '../models': { User: this.UserMock } + }); + }) + + it(" GET /users/:id ", async () => { + const req = mockRequest({params: {id: 1}}); + const res = mockResponse(); + + await this.userController.getUser(req, res); + + res.render.getCall(0).args[0].should.equal('profile'); + res.render.getCall(0).args[1].userData.name.should.equal("admin"); + }); + + after(async () => { + this.ensureAuthenticated.restore(); + this.getUser.restore(); + }) + }) + + context('# [瀏覽編輯 Profile 頁面]', () => { + before(() => { + this.ensureAuthenticated = sinon.stub( + helpers, 'ensureAuthenticated' + ).returns(true); + this.getUser = sinon.stub( + helpers, 'getUser' + ).returns({id: 1}); + this.UserMock = dbMock.define('User', { + id: 1, + email: 'root@example.com', + name: 'admin', + isAdmin: false, + }); + + this.UserMock.findByPk = (id) => this.UserMock.findOne({where: {id: id}}); + + this.userController = proxyquire('../../controllers/userController', { + '../models': { User: this.UserMock } + }); + }) + + it(" GET /users/:id/edit ", async () => { + const req = mockRequest({params: {id: 1}}); + const res = mockResponse(); + + await this.userController.editUser(req, res); + + res.render.getCall(0).args[0].should.equal('edit'); + res.render.getCall(0).args[1].user.name.should.equal("admin"); + }); + + after(async () => { + this.ensureAuthenticated.restore(); + this.getUser.restore(); + }) + }) + + context('# [編輯 Profile]', () => { + before(async() => { + this.ensureAuthenticated = sinon.stub( + helpers, 'ensureAuthenticated' + ).returns(true); + this.getUser = sinon.stub( + helpers, 'getUser' + ).returns({id: 1}); + this.UserMock = dbMock.define('User', { + id: 1, + email: 'root@example.com', + name: 'admin', + isAdmin: false, + }, { + instanceMethods: { + update: (changes) => { + this.UserMock._defaults = {...changes}; + return Promise.resolve(); + } + } + }); + + this.UserMock.findByPk = (id) => this.UserMock.findOne({where: {id: id}}); + + this.userController = proxyquire('../../controllers/userController', { + '../models': { User: this.UserMock } + }); + }) + + it(" PUT /users/:id ", async () => { + const req = mockRequest({ + params: {id: 1}, + body: {name: "admin2", email: "admin_test@gmail.com"} + }); + const res = mockResponse(); + + await this.userController.putUser(req, res); + + req.flash.calledWith('success_messages', 'user was updated successfully').should.be.true; + res.redirect.calledWith('/users/1').should.be.true; + + const user = await this.UserMock.findOne({where: {id: 1}}); + user.name.should.equal('admin2'); + user.email.should.equal('admin_test@gmail.com'); + }); + + after(async () => { + this.ensureAuthenticated.restore(); + this.getUser.restore(); + }) + }) + }) +}) \ No newline at end of file From da713e00459d4dc1894b9bed059ec863cb4a6814 Mon Sep 17 00:00:00 2001 From: Stanney Date: Tue, 19 Oct 2021 02:10:04 +0800 Subject: [PATCH 005/135] add A20 test --- tests/A20.test.js | 74 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 tests/A20.test.js diff --git a/tests/A20.test.js b/tests/A20.test.js new file mode 100644 index 00000000..5ed231a0 --- /dev/null +++ b/tests/A20.test.js @@ -0,0 +1,74 @@ +const chai = require('chai') +const request = require('supertest') +const sinon = require('sinon') +const should = chai.should() + +const helpers = require('../_helpers') +const SequelizeMock = require('sequelize-mock'); +const proxyquire = require('proxyquire'); + +const dbMock = new SequelizeMock(); + + +const mockRequest = (query) => { + return { + ...query, + flash: sinon.spy() + }; +}; +const mockResponse = () => { + return { + redirect: sinon.spy(), + render: sinon.spy(), + } +}; + +describe('# A20: 餐廳資訊整理:Dashboard', function() { + + context('# [Q1: Dashboard - 1 - controller / view / route]', () => { + before(async() => { + this.UserMock = dbMock.define('User', { + id: 1, + email: 'root@example.com', + name: 'admin', + isAdmin: false, + }); + this.RestaurantMock = dbMock.define('Restaurant', { + id: 1, + name: '銷魂麵' + }); + this.CategoryMock = dbMock.define('Category', { + id: 1, + name: '食物' + }); + this.CommentMock = dbMock.define('Comment', { + id: 1, + text: "gogogo" + }) + + this.RestaurantMock.belongsTo(this.CategoryMock); + this.RestaurantMock.findByPk = (id) => this.RestaurantMock.findOne({where: {id: id}}); + this.CommentMock.count = () => 1; + + this.restController = proxyquire('../controllers/restController', { + '../models': { + User: this.UserMock, + Category: this.CategoryMock, + Restaurant: this.RestaurantMock, + Comment: this.CommentMock, + } + }); + }) + + it(" GET /restaurants/:id/dashboard ", async () => { + const req = mockRequest({params: {id: 1}}); + const res = mockResponse() + + await this.restController.getDashBoard(req, res); + + res.render.getCall(0).args[0].should.equal('dashboard'); + res.render.getCall(0).args[1].restaurant.name.should.equal('銷魂麵'); + res.render.getCall(0).args[1].n_comments.should.equal(1); + }); + }) +}) \ No newline at end of file From 88812da23bb63023626aabd3e4705ec5afcec3ca Mon Sep 17 00:00:00 2001 From: Stanney Date: Tue, 19 Oct 2021 02:10:20 +0800 Subject: [PATCH 006/135] add A21 test --- tests/A21.test.js | 124 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 tests/A21.test.js diff --git a/tests/A21.test.js b/tests/A21.test.js new file mode 100644 index 00000000..b5f9dd0d --- /dev/null +++ b/tests/A21.test.js @@ -0,0 +1,124 @@ +const chai = require('chai') +const request = require('supertest') +const sinon = require('sinon') +const should = chai.should() + +const db = require('../models') +const helpers = require('../_helpers') +const SequelizeMock = require('sequelize-mock'); +const proxyquire = require('proxyquire'); + +const dbMock = new SequelizeMock({autoQueryFallback: false}); + +const mockRequest = (query) => { + return { + ...query, + flash: sinon.spy() + }; +}; +const mockResponse = () => { + return { + redirect: sinon.spy(), + render: sinon.spy(), + } +}; + +let mockLikeData = [{ + UserId: 1, + RestaurantId: 2, +}] + +describe('# A21: Like / Unlike', function () { + + context('# Q1: 使用者可以 Like 餐廳', () => { + before(() => { + this.ensureAuthenticated = sinon.stub( + helpers, 'ensureAuthenticated' + ).returns(true); + this.getUser = sinon.stub( + helpers, 'getUser' + ).returns({id: 1}); + this.mockLikeData = []; + this.likeMock = dbMock.define('Like'); + this.likeMock.create = this.likeMock.upsert; + + this.likeMock.$queryInterface.$useHandler((query, queryOptions,done) => { + if (query === 'upsert') { + const {UserId, RestaurantId} = queryOptions[0]; + + this.mockLikeData.push({ UserId, RestaurantId }); + + return Promise.resolve(this.likeMock.build(this.mockLikeData)); + } else if (query === 'findAll') { + return Promise.resolve(this.mockLikeData); + } + }); + + this.userController = proxyquire('../controllers/userController', { + '../models': {Like: this.likeMock} + }); + }) + + it(" POST /like/:restaurantId ", async () => { + const req = mockRequest({params: {id: 1, restaurantId: 2}}); + const res = mockResponse(); + + await this.userController.addLike(req, res); + + const likes = await this.likeMock.findAll(); + console.log(likes); + likes.should.have.lengthOf(1); + }); + + after(async () => { + this.ensureAuthenticated.restore(); + this.getUser.restore(); + }) + }) + + context('# Q1: 使用者可以 unLike 餐廳', () => { + before(() => { + this.ensureAuthenticated = sinon.stub( + helpers, 'ensureAuthenticated' + ).returns(true); + this.getUser = sinon.stub( + helpers, 'getUser' + ).returns({id: 1}); + this.likeMock = dbMock.define('Like', { + id: 1, + UserId: 1, + RestaurantId: 2, + }); + + this.likeMock.$queryInterface.$useHandler((query, queryOptions,done) => { + if (query === 'destroy') { + const {UserId, RestaurantId} = queryOptions[0].where; + mockLikeData = mockLikeData.filter(d => !(d.UserId === UserId && d.RestaurantId === RestaurantId)) + + return Promise.resolve(this.likeMock.build(mockLikeData)); + } else if (query === 'findAll') { + return Promise.resolve(mockLikeData); + } + }); + + this.userController = proxyquire('../controllers/userController', { + '../models': {Like: this.likeMock} + }); + }) + + it(" DELETE /like/:restaurantId ", async () => { + const req = mockRequest({params: {id: 1, restaurantId: 2}}); + const res = mockResponse(); + + await this.userController.removeLike(req, res); + + const likes = await this.likeMock.findAll(); + likes.should.have.lengthOf(0); + }); + + after(async () => { + this.ensureAuthenticated.restore(); + this.getUser.restore(); + }) + }); +}) \ No newline at end of file From a7d56e15313697ca22f380dfd6c9e1557fe2be8a Mon Sep 17 00:00:00 2001 From: Stanney Date: Tue, 19 Oct 2021 02:10:30 +0800 Subject: [PATCH 007/135] add A22 test --- tests/A22.test.js | 143 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 tests/A22.test.js diff --git a/tests/A22.test.js b/tests/A22.test.js new file mode 100644 index 00000000..0ee0c78f --- /dev/null +++ b/tests/A22.test.js @@ -0,0 +1,143 @@ +const chai = require('chai') +const request = require('supertest') +const sinon = require('sinon') +const should = chai.should() + +const app = require('../app') +const helpers = require('../_helpers'); +const SequelizeMock = require('sequelize-mock'); +const proxyquire = require('proxyquire'); + +const dbMock = new SequelizeMock({autoQueryFallback: false}); + +const mockRequest = (query) => { + return { + ...query, + flash: sinon.spy() + }; +}; +const mockResponse = () => { + return { + redirect: sinon.spy(), + render: sinon.spy(), + } +}; + +let mockRestaurantData = [{ + id: 1, + name: 'Restaurant1', + tel: 'tel', + address: 'address', + opening_hours: 'opening_hours', + description: "test description", + FavoritedUsers: [{ + UserId: 1, + }] +}, { + id: 2, + name: 'Restaurant2', + tel: 'tel', + address: 'address', + opening_hours: 'opening_hours', + description: 'description', + CategoryId: 1, + FavoritedUsers: [] +}] + +describe('# A22: TOP 10 人氣餐廳 ', function () { + + context('# [網址正確、畫面正常執行]', () => { + before(async () => { + this.ensureAuthenticated = sinon.stub( + helpers, 'ensureAuthenticated' + ).returns(true); + this.getUser = sinon.stub( + helpers, 'getUser' + ).returns({ id: 1, Followings: [], FavoritedRestaurants: [] }); + }) + + it(" GET /restaurants/top ", (done) => { + request(app) + .get('/restaurants/top') + .end(function (err, res) { + done() + }); + }); + + after(async () => { + this.ensureAuthenticated.restore(); + this.getUser.restore(); + }) + + }) + + context('# [當你點擊畫面上的「加入最愛 / 移除最愛」按鈕時,會重新計算「收藏數」的數字]', () => { + before(async () => { + this.ensureAuthenticated = sinon.stub( + helpers, 'ensureAuthenticated' + ).returns(true); + this.getUser = sinon.stub( + helpers, 'getUser' + ).returns({ id: 1, Followings: [], FavoritedRestaurants: [] }); + + this.restaurantMock = dbMock.define('Restaurant'); + this.restaurantMock.$queryInterface.$useHandler((query, queryOptions,done) => { + if (query === 'findAll') { + return Promise.resolve(mockRestaurantData.map(d => this.restaurantMock.build(d))); + } + }); + this.restController = proxyquire('../controllers/restController', { + '../models': { + Restaurant: this.restaurantMock, + } + }); + + this.favoriteMock = dbMock.define('Favorite'); + this.favoriteMock.create = this.favoriteMock.upsert; + this.favoriteMock.$queryInterface.$useHandler((query, queryOptions,done) => { + if (query === 'upsert') { + const {UserId, RestaurantId} = queryOptions[0]; + const restaurant = mockRestaurantData.find(d => d.id === RestaurantId); + restaurant.FavoritedUsers.push({UserId: UserId}); + return Promise.resolve(mockRestaurantData.map(d => this.restaurantMock.build(d))); + } else if (query === 'destroy') { + const {UserId, RestaurantId} = queryOptions[0].where; + const restaurant = mockRestaurantData.find(d => d.id === RestaurantId); + restaurant.FavoritedUsers = restaurant.FavoritedUsers.filter(d => !(d.UserId === UserId)) + return Promise.resolve(mockRestaurantData.map(d => this.restaurantMock.build(d))); + } + }); + + this.userController = proxyquire('../controllers/userController', { + '../models': {Favorite: this.favoriteMock} + }) + }) + + it(" POST favorite ", async () => { + const req = mockRequest({user: { FavoritedRestaurants: []}, params: {restaurantId: 2}}); + const res = mockResponse(); + + await this.userController.addFavorite(req, res); + await this.restController.getTopRestaurant(req, res); + + res.render.getCall(0).args[1].restaurants[1].FavoritedCount.should.equal(1); + }) + + it(" DELETE favorite ", async() => { + const req = mockRequest({user: { FavoritedRestaurants: []}, params: {restaurantId: 1}}); + const res = mockResponse(); + + await this.userController.removeFavorite(req, res); + await this.restController.getTopRestaurant(req, res); + + res.render.getCall(0).args[1].restaurants[0].id.should.equal(2); + }) + + after(async () => { + this.ensureAuthenticated.restore(); + this.getUser.restore(); + }) + + }) + +}) \ No newline at end of file From d4a739111193241d59ead5ae5d49605d05e7363d Mon Sep 17 00:00:00 2001 From: Stanney Date: Tue, 19 Oct 2021 12:21:34 +0800 Subject: [PATCH 008/135] add commnets for A17 --- tests/A17.test.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/A17.test.js b/tests/A17.test.js index fe0fe948..13aa8b71 100644 --- a/tests/A17.test.js +++ b/tests/A17.test.js @@ -24,6 +24,7 @@ const mockResponse = () => { describe('# A17', () => { describe('登入測試: POST /signin', function(){ + // 以下測試會發出真實的 request 測試資料庫是否有正確的 user 資料 it('#1 密碼錯誤', function(done){ request(app) .post('/signin') @@ -47,7 +48,7 @@ describe('# A17', () => { .post('/signin') .type('urlencoded') .send('email=root@example.com&password=12345678') - .expect('Location', '/') + .expect('Location', '/restaurants') .expect(302, done) }) }); @@ -71,7 +72,7 @@ describe('# A17', () => { context('# [顯示使用者清單]', () => { it(" GET /admin/users ", async () => { - // 製作假 request & response + // 模擬 request & response const req = mockRequest(); const res = mockResponse(); @@ -85,7 +86,7 @@ describe('# A17', () => { context('# [修改使用者權限] for admin', () => { before(() => { - // 製作假 db 資料: UserMock + // 模擬 user db 資料: UserMock this.UserMock = dbMock.define('User', { id: 1, email: 'root@example.com', @@ -125,7 +126,7 @@ describe('# A17', () => { isAdmin: false, }, { instanceMethods: { - // 模擬 update 函數,並依據傳入的變數,跟著修正,如果傳入 {isAdmin: true},假資料中的 isAdmin 變會變成 true + // 模擬 update 函數,並依據傳入的變數,跟著修正,如果傳入 {isAdmin: true} update: (changes) => { this.UserMock._defaults = {...changes}; return Promise.resolve(); From e981eb0fe7ac8243658482ab3f17ea0464fae38b Mon Sep 17 00:00:00 2001 From: Stanney Date: Tue, 19 Oct 2021 12:21:49 +0800 Subject: [PATCH 009/135] add comments for A19 --- tests/A19.test.js | 44 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/tests/A19.test.js b/tests/A19.test.js index 996f9939..fd8cf8d7 100644 --- a/tests/A19.test.js +++ b/tests/A19.test.js @@ -28,37 +28,45 @@ describe('# A19', () => { describe('# A19: 建立 User Profile', function() { context('# [瀏覽 Profile]', () => { before(() => { + // 模擬驗證資料 this.ensureAuthenticated = sinon.stub( helpers, 'ensureAuthenticated' ).returns(true); this.getUser = sinon.stub( helpers, 'getUser' ).returns({id: 1}); + // 模擬 User db 資料 this.UserMock = dbMock.define('User', { id: 1, email: 'root@example.com', name: 'admin', isAdmin: false, }); - + // 將 mock user db 中的 findByPK 用 findOne 取代 (sequelize mock not support findByPK) this.UserMock.findByPk = (id) => this.UserMock.findOne({where: {id: id}}); - + // 將 userController 中的 User db 取代成 User mock db this.userController = proxyquire('../../controllers/userController', { '../models': { User: this.UserMock } }); }) it(" GET /users/:id ", async () => { + // 模擬發出 request, 帶入 params.id = 1 const req = mockRequest({params: {id: 1}}); const res = mockResponse(); - + + // 測試 userController.getUser await this.userController.getUser(req, res); + // 執行完後,call res.render 的參數測試 + // 1. 第一個參數是不是 profile + // 2. 第二個參數裡回傳的資料有 userData 而且 name 是 admin res.render.getCall(0).args[0].should.equal('profile'); res.render.getCall(0).args[1].userData.name.should.equal("admin"); }); after(async () => { + // 清除模擬驗證資料 this.ensureAuthenticated.restore(); this.getUser.restore(); }) @@ -66,37 +74,47 @@ describe('# A19', () => { context('# [瀏覽編輯 Profile 頁面]', () => { before(() => { + // 製作假驗證資料 this.ensureAuthenticated = sinon.stub( helpers, 'ensureAuthenticated' ).returns(true); this.getUser = sinon.stub( helpers, 'getUser' ).returns({id: 1}); + + // 模擬 User db 資料 this.UserMock = dbMock.define('User', { id: 1, email: 'root@example.com', name: 'admin', isAdmin: false, }); - + // 將 mock user db 中的 findByPK 用 findOne 取代 (sequelize mock not support findByPK) this.UserMock.findByPk = (id) => this.UserMock.findOne({where: {id: id}}); + // 將 userController 中的 User db 取代成 User mock db this.userController = proxyquire('../../controllers/userController', { '../models': { User: this.UserMock } }); }) it(" GET /users/:id/edit ", async () => { + // 模擬 request & response const req = mockRequest({params: {id: 1}}); const res = mockResponse(); + // 測試 adminController.editUser function await this.userController.editUser(req, res); + // 執行完 editUser 後,call res.render 的參數測試 + // 1. 第一個參數是不是 edit + // 2. 第二個參數裡回傳的資料有 user 而且 name 是 admin res.render.getCall(0).args[0].should.equal('edit'); res.render.getCall(0).args[1].user.name.should.equal("admin"); }); after(async () => { + // 清除模擬驗證資料 this.ensureAuthenticated.restore(); this.getUser.restore(); }) @@ -104,12 +122,14 @@ describe('# A19', () => { context('# [編輯 Profile]', () => { before(async() => { + // 模擬 request & response this.ensureAuthenticated = sinon.stub( helpers, 'ensureAuthenticated' ).returns(true); this.getUser = sinon.stub( helpers, 'getUser' ).returns({id: 1}); + // 製作假 db 資料: UserMock this.UserMock = dbMock.define('User', { id: 1, email: 'root@example.com', @@ -117,38 +137,44 @@ describe('# A19', () => { isAdmin: false, }, { instanceMethods: { + // 模擬 update 函數,並依據傳入的變數,跟著修正,如果傳入 {isAdmin: true} update: (changes) => { this.UserMock._defaults = {...changes}; return Promise.resolve(); } } }); - + // 將 mock user db 中的 findByPK 用 findOne 取代 (sequelize mock not support findByPK) this.UserMock.findByPk = (id) => this.UserMock.findOne({where: {id: id}}); - + // 將 userController 中的 User db 取代成 User mock db this.userController = proxyquire('../../controllers/userController', { '../models': { User: this.UserMock } }); }) it(" PUT /users/:id ", async () => { + // 模擬發送 request, 帶了 params.id = 1, body.name = amdin2, body.email = admin_test@gmail.com const req = mockRequest({ params: {id: 1}, body: {name: "admin2", email: "admin_test@gmail.com"} }); const res = mockResponse(); - - await this.userController.putUser(req, res); + // 修改模擬資料, call putUser function + await this.userController.putUser(req, res); + + // 測試成功修改 user 資料後,是否有回傳正確訊息 req.flash.calledWith('success_messages', 'user was updated successfully').should.be.true; + // 測試成功修改 user 資料後,是否有導向正確 route res.redirect.calledWith('/users/1').should.be.true; - + // 修改後,測試模擬資料中是否有成功修正, name = amdin2, email = admin_test@gmail.com const user = await this.UserMock.findOne({where: {id: 1}}); user.name.should.equal('admin2'); user.email.should.equal('admin_test@gmail.com'); }); after(async () => { + // 清除模擬驗證資料 this.ensureAuthenticated.restore(); this.getUser.restore(); }) From 5396cf6532c90e3a9d1dc4582fe8301dd989cbdb Mon Sep 17 00:00:00 2001 From: Stanney Date: Tue, 19 Oct 2021 12:22:01 +0800 Subject: [PATCH 010/135] add comments for A22 --- tests/A20.test.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/A20.test.js b/tests/A20.test.js index 5ed231a0..6ff35593 100644 --- a/tests/A20.test.js +++ b/tests/A20.test.js @@ -27,6 +27,7 @@ describe('# A20: 餐廳資訊整理:Dashboard', function() { context('# [Q1: Dashboard - 1 - controller / view / route]', () => { before(async() => { + // 模擬 user, restaurant, category, comment 資料 this.UserMock = dbMock.define('User', { id: 1, email: 'root@example.com', @@ -45,11 +46,12 @@ describe('# A20: 餐廳資訊整理:Dashboard', function() { id: 1, text: "gogogo" }) - - this.RestaurantMock.belongsTo(this.CategoryMock); + // 將 mock user db 中的 findByPK 用 findOne 取代 (sequelize mock not support findByPK) this.RestaurantMock.findByPk = (id) => this.RestaurantMock.findOne({where: {id: id}}); + // 將 count 的 function 預設回傳假資料數目 1 this.CommentMock.count = () => 1; + // 將 restController 中的 User,Category,Restaurant,Comment 都用模擬資料取代 this.restController = proxyquire('../controllers/restController', { '../models': { User: this.UserMock, @@ -63,9 +65,10 @@ describe('# A20: 餐廳資訊整理:Dashboard', function() { it(" GET /restaurants/:id/dashboard ", async () => { const req = mockRequest({params: {id: 1}}); const res = mockResponse() - + // call getDashBoard function await this.restController.getDashBoard(req, res); + // 確認執行 getDasgBoard 之後,回傳的 res.render 的參數是否與模擬資料相同 res.render.getCall(0).args[0].should.equal('dashboard'); res.render.getCall(0).args[1].restaurant.name.should.equal('銷魂麵'); res.render.getCall(0).args[1].n_comments.should.equal(1); From dab9f1d2d186ca36be9826945321aeb94889bffd Mon Sep 17 00:00:00 2001 From: Stanney Date: Tue, 19 Oct 2021 12:22:16 +0800 Subject: [PATCH 011/135] add comments for A21 --- tests/A21.test.js | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/tests/A21.test.js b/tests/A21.test.js index b5f9dd0d..5a82f84a 100644 --- a/tests/A21.test.js +++ b/tests/A21.test.js @@ -23,33 +23,42 @@ const mockResponse = () => { } }; +// 模擬 Like 資料 let mockLikeData = [{ UserId: 1, RestaurantId: 2, }] describe('# A21: Like / Unlike', function () { - context('# Q1: 使用者可以 Like 餐廳', () => { before(() => { + // 模擬驗證資料 this.ensureAuthenticated = sinon.stub( helpers, 'ensureAuthenticated' ).returns(true); this.getUser = sinon.stub( helpers, 'getUser' ).returns({id: 1}); + + // this.mockLikeData = []; this.likeMock = dbMock.define('Like'); + // 因為 mock 中的 create 有問題,因此指向 upsert function, 這樣可以在 useHandler 中取得 create 呼叫 this.likeMock.create = this.likeMock.upsert; + // 模擬 Like.create and Like.finall 的 function this.likeMock.$queryInterface.$useHandler((query, queryOptions,done) => { if (query === 'upsert') { + // create 時會帶 UserId 跟 RestaurantId (ex: Like.create({ UserId: 1, RestaurantId: 2})) const {UserId, RestaurantId} = queryOptions[0]; + // 新增這個 Like 的資訊到模擬資料裡 this.mockLikeData.push({ UserId, RestaurantId }); + // 回傳模擬資料 return Promise.resolve(this.likeMock.build(this.mockLikeData)); } else if (query === 'findAll') { + // 回傳模擬資料 return Promise.resolve(this.mockLikeData); } }); @@ -63,14 +72,16 @@ describe('# A21: Like / Unlike', function () { const req = mockRequest({params: {id: 1, restaurantId: 2}}); const res = mockResponse(); + // 呼叫 userController 中的 addLike await this.userController.addLike(req, res); const likes = await this.likeMock.findAll(); - console.log(likes); + // 確認呼叫 addLike 後,模擬資料中的 like 資料會多一個 likes.should.have.lengthOf(1); }); after(async () => { + // 清除驗證資料 this.ensureAuthenticated.restore(); this.getUser.restore(); }) @@ -78,21 +89,25 @@ describe('# A21: Like / Unlike', function () { context('# Q1: 使用者可以 unLike 餐廳', () => { before(() => { + // 模擬驗證資料 this.ensureAuthenticated = sinon.stub( helpers, 'ensureAuthenticated' ).returns(true); this.getUser = sinon.stub( helpers, 'getUser' ).returns({id: 1}); + // 模擬 Like db 資料 this.likeMock = dbMock.define('Like', { id: 1, UserId: 1, RestaurantId: 2, }); - + // 模擬 Like.destroy and Like.finall 的 function this.likeMock.$queryInterface.$useHandler((query, queryOptions,done) => { if (query === 'destroy') { const {UserId, RestaurantId} = queryOptions[0].where; + // destroy 可以從 where 取得要刪除的資料 + // 因此就可以模擬將模擬資料中的資料刪除 mockLikeData = mockLikeData.filter(d => !(d.UserId === UserId && d.RestaurantId === RestaurantId)) return Promise.resolve(this.likeMock.build(mockLikeData)); @@ -107,16 +122,20 @@ describe('# A21: Like / Unlike', function () { }) it(" DELETE /like/:restaurantId ", async () => { + // 模擬發出 request, 帶入 params.id = 1, restaurantId = 2 const req = mockRequest({params: {id: 1, restaurantId: 2}}); const res = mockResponse(); + // call DELETE /like/:restaurantId route 對應的 userController.removeLike await this.userController.removeLike(req, res); + // 刪除後,模擬資料會是空的 const likes = await this.likeMock.findAll(); likes.should.have.lengthOf(0); }); after(async () => { + // 清除模擬驗證資料 this.ensureAuthenticated.restore(); this.getUser.restore(); }) From c7a336da58970fb98f516deb9739c49ee8635de2 Mon Sep 17 00:00:00 2001 From: Stanney Date: Tue, 19 Oct 2021 12:22:31 +0800 Subject: [PATCH 012/135] add comments for A22 --- tests/A22.test.js | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/tests/A22.test.js b/tests/A22.test.js index 0ee0c78f..ab41c162 100644 --- a/tests/A22.test.js +++ b/tests/A22.test.js @@ -22,7 +22,7 @@ const mockResponse = () => { render: sinon.spy(), } }; - +// 模擬的餐廳資料 let mockRestaurantData = [{ id: 1, name: 'Restaurant1', @@ -48,6 +48,7 @@ describe('# A22: TOP 10 人氣餐廳 ', function () { context('# [網址正確、畫面正常執行]', () => { before(async () => { + // 模擬驗證資料 this.ensureAuthenticated = sinon.stub( helpers, 'ensureAuthenticated' ).returns(true); @@ -60,11 +61,14 @@ describe('# A22: TOP 10 人氣餐廳 ', function () { request(app) .get('/restaurants/top') .end(function (err, res) { + // 檢查回傳的資料中,是否有 Top 10 人氣餐廳資訊 + res.text.should.include('Top 10 人氣餐廳') // 可以正確執行,沒有 error 即可通過 done() }); }); after(async () => { + // 清除模擬驗證資料 this.ensureAuthenticated.restore(); this.getUser.restore(); }) @@ -73,6 +77,7 @@ describe('# A22: TOP 10 人氣餐廳 ', function () { context('# [當你點擊畫面上的「加入最愛 / 移除最愛」按鈕時,會重新計算「收藏數」的數字]', () => { before(async () => { + // 模擬驗證資料 this.ensureAuthenticated = sinon.stub( helpers, 'ensureAuthenticated' ).returns(true); @@ -80,27 +85,33 @@ describe('# A22: TOP 10 人氣餐廳 ', function () { helpers, 'getUser' ).returns({ id: 1, Followings: [], FavoritedRestaurants: [] }); + // 模擬 Restaurant db 資料 this.restaurantMock = dbMock.define('Restaurant'); this.restaurantMock.$queryInterface.$useHandler((query, queryOptions,done) => { if (query === 'findAll') { return Promise.resolve(mockRestaurantData.map(d => this.restaurantMock.build(d))); } }); + + // 將 restController 中的 Restaurant db 取代成 Restaurant mock db this.restController = proxyquire('../controllers/restController', { '../models': { Restaurant: this.restaurantMock, } }); + // 模擬 Favorite db 資料 this.favoriteMock = dbMock.define('Favorite'); this.favoriteMock.create = this.favoriteMock.upsert; this.favoriteMock.$queryInterface.$useHandler((query, queryOptions,done) => { if (query === 'upsert') { + // 新增 favortie 資料到模擬資料 const {UserId, RestaurantId} = queryOptions[0]; const restaurant = mockRestaurantData.find(d => d.id === RestaurantId); restaurant.FavoritedUsers.push({UserId: UserId}); return Promise.resolve(mockRestaurantData.map(d => this.restaurantMock.build(d))); } else if (query === 'destroy') { + // 刪除模擬資料中的某一筆 favortie 資料 const {UserId, RestaurantId} = queryOptions[0].where; const restaurant = mockRestaurantData.find(d => d.id === RestaurantId); restaurant.FavoritedUsers = restaurant.FavoritedUsers.filter(d => !(d.UserId === UserId)) @@ -108,32 +119,42 @@ describe('# A22: TOP 10 人氣餐廳 ', function () { } }); + // 將 userController 中的 Favorite db 取代成 Favorite mock db this.userController = proxyquire('../controllers/userController', { '../models': {Favorite: this.favoriteMock} }) }) it(" POST favorite ", async () => { + // 模擬 request 新增 user id = 1, 喜愛 restaurant id = 2 const req = mockRequest({user: { FavoritedRestaurants: []}, params: {restaurantId: 2}}); const res = mockResponse(); + // call addFavorite await this.userController.addFavorite(req, res); + + // 確認 getTopRestaurant 取得餐廳 2 的 favorite 數量會不同 await this.restController.getTopRestaurant(req, res); res.render.getCall(0).args[1].restaurants[1].FavoritedCount.should.equal(1); }) it(" DELETE favorite ", async() => { + // 模擬 request 新增 user id = 1, 不喜愛 restaurant id = 1 const req = mockRequest({user: { FavoritedRestaurants: []}, params: {restaurantId: 1}}); const res = mockResponse(); + // call removeFavorite await this.userController.removeFavorite(req, res); + // 取得餐廳排序資料 await this.restController.getTopRestaurant(req, res); + // 確認餐廳排序有變,第一個餐廳資料 id = 2 res.render.getCall(0).args[1].restaurants[0].id.should.equal(2); }) after(async () => { + // 清除模擬驗證資料 this.ensureAuthenticated.restore(); this.getUser.restore(); }) From a17581143603f12a12983e74a508c8011501ae1d Mon Sep 17 00:00:00 2001 From: Carrot7712 Date: Wed, 27 Oct 2021 14:26:09 +0800 Subject: [PATCH 013/135] adjust coding style --- _helpers.js | 6 +- models/index.js | 20 ++-- routes/index.js | 1 - tests/A17.test.js | 149 +++++++++++++------------ tests/A19.test.js | 186 +++++++++++++++---------------- tests/A20.test.js | 65 ++++++----- tests/A21.test.js | 136 +++++++++++------------ tests/A22.test.js | 272 +++++++++++++++++++++++++--------------------- tests/index.js | 21 ++-- 9 files changed, 451 insertions(+), 405 deletions(-) diff --git a/_helpers.js b/_helpers.js index 798e5325..61e51b67 100644 --- a/_helpers.js +++ b/_helpers.js @@ -1,12 +1,12 @@ function ensureAuthenticated(req) { - return req.isAuthenticated(); + return req.isAuthenticated() } function getUser(req) { - return req.user; + return req.user } module.exports = { ensureAuthenticated, getUser, -}; \ No newline at end of file +} diff --git a/models/index.js b/models/index.js index 66860356..3d701d98 100644 --- a/models/index.js +++ b/models/index.js @@ -13,22 +13,28 @@ let sequelize if (config.use_env_variable) { sequelize = new Sequelize(process.env[config.use_env_variable], config) } else { - sequelize = new Sequelize(config.database, config.username, config.password, config) + sequelize = new Sequelize( + config.database, + config.username, + config.password, + config + ) } // 動態引入其他 models -fs - .readdirSync(__dirname) - .filter(file => { - return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js') +fs.readdirSync(__dirname) + .filter((file) => { + return ( + file.indexOf('.') !== 0 && file !== basename && file.slice(-3) === '.js' + ) }) - .forEach(file => { + .forEach((file) => { const model = sequelize['import'](path.join(__dirname, file)) db[model.name] = model }) // 設定 Models 之間的關聯 -Object.keys(db).forEach(modelName => { +Object.keys(db).forEach((modelName) => { if (db[modelName].associate) { db[modelName].associate(db) } diff --git a/routes/index.js b/routes/index.js index fc55e842..b20f151b 100644 --- a/routes/index.js +++ b/routes/index.js @@ -1,5 +1,4 @@ module.exports = (app) => { - app.get('/', (req, res) => { res.send('Hello World!') }) diff --git a/tests/A17.test.js b/tests/A17.test.js index 13aa8b71..6320dca3 100644 --- a/tests/A17.test.js +++ b/tests/A17.test.js @@ -2,30 +2,30 @@ const chai = require('chai') const request = require('supertest') const sinon = require('sinon') const should = chai.should() -const SequelizeMock = require('sequelize-mock'); -const proxyquire = require('proxyquire'); +const SequelizeMock = require('sequelize-mock') +const proxyquire = require('proxyquire') -const dbMock = new SequelizeMock(); +const dbMock = new SequelizeMock() -const app = require('../../app'); -const { classToInvokable } = require('sequelize/types/lib/utils'); +const app = require('../../app') +const { classToInvokable } = require('sequelize/types/lib/utils') const mockRequest = (query) => { return { ...query, - flash: sinon.spy() - }; -}; + flash: sinon.spy(), + } +} const mockResponse = () => { return { - redirect: sinon.spy() + redirect: sinon.spy(), } -}; +} describe('# A17', () => { - describe('登入測試: POST /signin', function(){ + describe('登入測試: POST /signin', function () { // 以下測試會發出真實的 request 測試資料庫是否有正確的 user 資料 - it('#1 密碼錯誤', function(done){ + it('#1 密碼錯誤', function (done) { request(app) .post('/signin') .type('urlencoded') @@ -34,7 +34,7 @@ describe('# A17', () => { .expect(302, done) }) - it('#2 帳號錯誤', function(done){ + it('#2 帳號錯誤', function (done) { request(app) .post('/signin') .type('urlencoded') @@ -43,7 +43,7 @@ describe('# A17', () => { .expect(302, done) }) - it('#3 成功登入', function(done){ + it('#3 成功登入', function (done) { request(app) .post('/signin') .type('urlencoded') @@ -51,7 +51,7 @@ describe('# A17', () => { .expect('Location', '/restaurants') .expect(302, done) }) - }); + }) describe('# A17: 使用者權限管理', function () { before(() => { @@ -61,29 +61,30 @@ describe('# A17', () => { email: 'root@example.com', name: 'admin', isAdmin: false, - }); + }) // 將 mock user db 中的 findByPK 用 findOne 取代 (sequelize mock not support findByPK) - this.UserMock.findByPk = (id) => this.UserMock.findOne({where: {id: id}}); + this.UserMock.findByPk = (id) => + this.UserMock.findOne({ where: { id: id } }) // 將 adminController 中的 User db 取代成 User mock db this.adminController = proxyquire('../../controllers/adminController', { - '../models': { User: this.UserMock } - }); + '../models': { User: this.UserMock }, + }) }) - + context('# [顯示使用者清單]', () => { - it(" GET /admin/users ", async () => { + it(' GET /admin/users ', async () => { // 模擬 request & response - const req = mockRequest(); - const res = mockResponse(); + const req = mockRequest() + const res = mockResponse() // 測試 adminController.getUsers function - await this.adminController.getUsers(req, res); + await this.adminController.getUsers(req, res) // render 裡的第二個參數,回傳了 users, 名稱必須跟假資料一樣是 admin - res.render.getCall(0).args[1].users[0].name.should.equal('admin'); - }); + res.render.getCall(0).args[1].users[0].name.should.equal('admin') + }) }) - + context('# [修改使用者權限] for admin', () => { before(() => { // 模擬 user db 資料: UserMock @@ -92,72 +93,84 @@ describe('# A17', () => { email: 'root@example.com', name: 'admin', isAdmin: true, - }); + }) // 將 mock user db 中的 findByPK 用 findOne 取代 (sequelize mock not support findByPK) // 將 count 的 function 預設回傳假資料數目 1 - this.UserMock.count = () => 1; - this.UserMock.findByPk = (id) => this.UserMock.findOne({where: {id: id}}); - // 將 adminController 中的 User db 取代成 User mock db + this.UserMock.count = () => 1 + this.UserMock.findByPk = (id) => + this.UserMock.findOne({ where: { id: id } }) + // 將 adminController 中的 User db 取代成 User mock db this.adminController = proxyquire('../../controllers/adminController', { - '../models': { User: this.UserMock } - }); + '../models': { User: this.UserMock }, + }) }) - it(" PUT /admin/users/:id/toggleAdmin ", async () => { - const req = mockRequest({params: {id: 1}}); - const res = mockResponse(); + it(' PUT /admin/users/:id/toggleAdmin ', async () => { + const req = mockRequest({ params: { id: 1 } }) + const res = mockResponse() // 測試 adminController.toggleAdmin function - await this.adminController.toggleAdmin(req, res); + await this.adminController.toggleAdmin(req, res) // 執行完 toggleAdmin 後,res.flash 有被呼叫而且呼叫的訊息正確 - req.flash.calledWith('error_messages', 'core manager can not be changed').should.be.true; + req.flash.calledWith( + 'error_messages', + 'core manager can not be changed' + ).should.be.true // 執行完 toggleAmin 後 res.redirect 有被呼叫而且 redirect 到 back - res.redirect.calledWith('back').should.be.true; - }); + res.redirect.calledWith('back').should.be.true + }) }) context('# [修改使用者權限] for user', () => { before(() => { - this.UserMock = dbMock.define('User', { - id: 1, - email: 'user@example.com', - name: 'user', - isAdmin: false, - }, { - instanceMethods: { - // 模擬 update 函數,並依據傳入的變數,跟著修正,如果傳入 {isAdmin: true} - update: (changes) => { - this.UserMock._defaults = {...changes}; - return Promise.resolve(); - } + this.UserMock = dbMock.define( + 'User', + { + id: 1, + email: 'user@example.com', + name: 'user', + isAdmin: false, + }, + { + instanceMethods: { + // 模擬 update 函數,並依據傳入的變數,跟著修正,如果傳入 {isAdmin: true} + update: (changes) => { + this.UserMock._defaults = { ...changes } + return Promise.resolve() + }, + }, } - }); + ) + + this.UserMock.count = () => 1 + this.UserMock.findByPk = (id) => + this.UserMock.findOne({ where: { id: id } }) - this.UserMock.count = () => 1; - this.UserMock.findByPk = (id) => this.UserMock.findOne({where: {id: id}}); - this.adminController = proxyquire('../../controllers/adminController', { - '../models': { User: this.UserMock } - }); + '../models': { User: this.UserMock }, + }) }) - it(" PUT /admin/users/:id/toggleAdmin ", async (done) => { - const req = mockRequest({params: {id: 1}}); - const res = mockResponse(); + it(' PUT /admin/users/:id/toggleAdmin ', async (done) => { + const req = mockRequest({ params: { id: 1 } }) + const res = mockResponse() - await this.adminController.toggleAdmin(req, res); + await this.adminController.toggleAdmin(req, res) - req.flash.calledWith('success_messages', 'user was successfully to update').should.be.true; - res.redirect.calledWith('/admin/users').should.be.true; + req.flash.calledWith( + 'success_messages', + 'user was successfully to update' + ).should.be.true + res.redirect.calledWith('/admin/users').should.be.true // 執行完 toggleAmin 後,因為假資料中使用者是 user@example.com,因此可以修改權限 isAdmin 從 false -> true // 所以這邊將假資料撈出,比對看是否有修改到 - const user = await this.UserMock.findOne({where: {id: 1}}); - user.isAdmin.should.equal(true); + const user = await this.UserMock.findOne({ where: { id: 1 } }) + user.isAdmin.should.equal(true) done() - }); + }) }) }) -}) \ No newline at end of file +}) diff --git a/tests/A19.test.js b/tests/A19.test.js index fd8cf8d7..d00fa12f 100644 --- a/tests/A19.test.js +++ b/tests/A19.test.js @@ -6,178 +6,182 @@ const should = chai.should() const app = require('../../app') const routes = require('../../routes/index') const db = require('../../models') -const helpers = require('../../_helpers'); -const SequelizeMock = require('sequelize-mock'); -const proxyquire = require('proxyquire'); +const helpers = require('../../_helpers') +const SequelizeMock = require('sequelize-mock') +const proxyquire = require('proxyquire') -const dbMock = new SequelizeMock(); +const dbMock = new SequelizeMock() const mockRequest = (query) => { return { ...query, - flash: sinon.spy() - }; -}; + flash: sinon.spy(), + } +} const mockResponse = () => { return { redirect: sinon.spy(), render: sinon.spy(), } -}; +} describe('# A19', () => { - describe('# A19: 建立 User Profile', function() { + describe('# A19: 建立 User Profile', function () { context('# [瀏覽 Profile]', () => { before(() => { // 模擬驗證資料 - this.ensureAuthenticated = sinon.stub( - helpers, 'ensureAuthenticated' - ).returns(true); - this.getUser = sinon.stub( - helpers, 'getUser' - ).returns({id: 1}); + this.ensureAuthenticated = sinon + .stub(helpers, 'ensureAuthenticated') + .returns(true) + this.getUser = sinon.stub(helpers, 'getUser').returns({ id: 1 }) // 模擬 User db 資料 this.UserMock = dbMock.define('User', { id: 1, email: 'root@example.com', name: 'admin', isAdmin: false, - }); + }) // 將 mock user db 中的 findByPK 用 findOne 取代 (sequelize mock not support findByPK) - this.UserMock.findByPk = (id) => this.UserMock.findOne({where: {id: id}}); + this.UserMock.findByPk = (id) => + this.UserMock.findOne({ where: { id: id } }) // 將 userController 中的 User db 取代成 User mock db this.userController = proxyquire('../../controllers/userController', { - '../models': { User: this.UserMock } - }); + '../models': { User: this.UserMock }, + }) }) - it(" GET /users/:id ", async () => { + it(' GET /users/:id ', async () => { // 模擬發出 request, 帶入 params.id = 1 - const req = mockRequest({params: {id: 1}}); - const res = mockResponse(); + const req = mockRequest({ params: { id: 1 } }) + const res = mockResponse() // 測試 userController.getUser - await this.userController.getUser(req, res); + await this.userController.getUser(req, res) // 執行完後,call res.render 的參數測試 // 1. 第一個參數是不是 profile // 2. 第二個參數裡回傳的資料有 userData 而且 name 是 admin - res.render.getCall(0).args[0].should.equal('profile'); - res.render.getCall(0).args[1].userData.name.should.equal("admin"); - }); + res.render.getCall(0).args[0].should.equal('profile') + res.render.getCall(0).args[1].userData.name.should.equal('admin') + }) after(async () => { // 清除模擬驗證資料 - this.ensureAuthenticated.restore(); - this.getUser.restore(); + this.ensureAuthenticated.restore() + this.getUser.restore() }) }) context('# [瀏覽編輯 Profile 頁面]', () => { before(() => { // 製作假驗證資料 - this.ensureAuthenticated = sinon.stub( - helpers, 'ensureAuthenticated' - ).returns(true); - this.getUser = sinon.stub( - helpers, 'getUser' - ).returns({id: 1}); - - // 模擬 User db 資料 + this.ensureAuthenticated = sinon + .stub(helpers, 'ensureAuthenticated') + .returns(true) + this.getUser = sinon.stub(helpers, 'getUser').returns({ id: 1 }) + + // 模擬 User db 資料 this.UserMock = dbMock.define('User', { id: 1, email: 'root@example.com', name: 'admin', isAdmin: false, - }); + }) // 將 mock user db 中的 findByPK 用 findOne 取代 (sequelize mock not support findByPK) - this.UserMock.findByPk = (id) => this.UserMock.findOne({where: {id: id}}); - + this.UserMock.findByPk = (id) => + this.UserMock.findOne({ where: { id: id } }) + // 將 userController 中的 User db 取代成 User mock db this.userController = proxyquire('../../controllers/userController', { - '../models': { User: this.UserMock } - }); + '../models': { User: this.UserMock }, + }) }) - it(" GET /users/:id/edit ", async () => { + it(' GET /users/:id/edit ', async () => { // 模擬 request & response - const req = mockRequest({params: {id: 1}}); - const res = mockResponse(); - + const req = mockRequest({ params: { id: 1 } }) + const res = mockResponse() + // 測試 adminController.editUser function - await this.userController.editUser(req, res); + await this.userController.editUser(req, res) // 執行完 editUser 後,call res.render 的參數測試 // 1. 第一個參數是不是 edit // 2. 第二個參數裡回傳的資料有 user 而且 name 是 admin - res.render.getCall(0).args[0].should.equal('edit'); - res.render.getCall(0).args[1].user.name.should.equal("admin"); - }); + res.render.getCall(0).args[0].should.equal('edit') + res.render.getCall(0).args[1].user.name.should.equal('admin') + }) after(async () => { // 清除模擬驗證資料 - this.ensureAuthenticated.restore(); - this.getUser.restore(); + this.ensureAuthenticated.restore() + this.getUser.restore() }) }) context('# [編輯 Profile]', () => { - before(async() => { + before(async () => { // 模擬 request & response - this.ensureAuthenticated = sinon.stub( - helpers, 'ensureAuthenticated' - ).returns(true); - this.getUser = sinon.stub( - helpers, 'getUser' - ).returns({id: 1}); + this.ensureAuthenticated = sinon + .stub(helpers, 'ensureAuthenticated') + .returns(true) + this.getUser = sinon.stub(helpers, 'getUser').returns({ id: 1 }) // 製作假 db 資料: UserMock - this.UserMock = dbMock.define('User', { - id: 1, - email: 'root@example.com', - name: 'admin', - isAdmin: false, - }, { - instanceMethods: { - // 模擬 update 函數,並依據傳入的變數,跟著修正,如果傳入 {isAdmin: true} - update: (changes) => { - this.UserMock._defaults = {...changes}; - return Promise.resolve(); - } + this.UserMock = dbMock.define( + 'User', + { + id: 1, + email: 'root@example.com', + name: 'admin', + isAdmin: false, + }, + { + instanceMethods: { + // 模擬 update 函數,並依據傳入的變數,跟著修正,如果傳入 {isAdmin: true} + update: (changes) => { + this.UserMock._defaults = { ...changes } + return Promise.resolve() + }, + }, } - }); + ) // 將 mock user db 中的 findByPK 用 findOne 取代 (sequelize mock not support findByPK) - this.UserMock.findByPk = (id) => this.UserMock.findOne({where: {id: id}}); - // 將 userController 中的 User db 取代成 User mock db + this.UserMock.findByPk = (id) => + this.UserMock.findOne({ where: { id: id } }) + // 將 userController 中的 User db 取代成 User mock db this.userController = proxyquire('../../controllers/userController', { - '../models': { User: this.UserMock } - }); + '../models': { User: this.UserMock }, + }) }) - it(" PUT /users/:id ", async () => { + it(' PUT /users/:id ', async () => { // 模擬發送 request, 帶了 params.id = 1, body.name = amdin2, body.email = admin_test@gmail.com const req = mockRequest({ - params: {id: 1}, - body: {name: "admin2", email: "admin_test@gmail.com"} - }); - const res = mockResponse(); + params: { id: 1 }, + body: { name: 'admin2', email: 'admin_test@gmail.com' }, + }) + const res = mockResponse() // 修改模擬資料, call putUser function - await this.userController.putUser(req, res); - + await this.userController.putUser(req, res) + // 測試成功修改 user 資料後,是否有回傳正確訊息 - req.flash.calledWith('success_messages', 'user was updated successfully').should.be.true; + req.flash.calledWith( + 'success_messages', + 'user was updated successfully' + ).should.be.true // 測試成功修改 user 資料後,是否有導向正確 route - res.redirect.calledWith('/users/1').should.be.true; + res.redirect.calledWith('/users/1').should.be.true // 修改後,測試模擬資料中是否有成功修正, name = amdin2, email = admin_test@gmail.com - const user = await this.UserMock.findOne({where: {id: 1}}); - user.name.should.equal('admin2'); - user.email.should.equal('admin_test@gmail.com'); - }); + const user = await this.UserMock.findOne({ where: { id: 1 } }) + user.name.should.equal('admin2') + user.email.should.equal('admin_test@gmail.com') + }) after(async () => { // 清除模擬驗證資料 - this.ensureAuthenticated.restore(); - this.getUser.restore(); + this.ensureAuthenticated.restore() + this.getUser.restore() }) }) }) -}) \ No newline at end of file +}) diff --git a/tests/A20.test.js b/tests/A20.test.js index 6ff35593..e1d908b3 100644 --- a/tests/A20.test.js +++ b/tests/A20.test.js @@ -4,74 +4,73 @@ const sinon = require('sinon') const should = chai.should() const helpers = require('../_helpers') -const SequelizeMock = require('sequelize-mock'); -const proxyquire = require('proxyquire'); - -const dbMock = new SequelizeMock(); +const SequelizeMock = require('sequelize-mock') +const proxyquire = require('proxyquire') +const dbMock = new SequelizeMock() const mockRequest = (query) => { return { ...query, - flash: sinon.spy() - }; -}; + flash: sinon.spy(), + } +} const mockResponse = () => { return { redirect: sinon.spy(), render: sinon.spy(), } -}; +} -describe('# A20: 餐廳資訊整理:Dashboard', function() { - +describe('# A20: 餐廳資訊整理:Dashboard', function () { context('# [Q1: Dashboard - 1 - controller / view / route]', () => { - before(async() => { + before(async () => { // 模擬 user, restaurant, category, comment 資料 this.UserMock = dbMock.define('User', { id: 1, email: 'root@example.com', name: 'admin', isAdmin: false, - }); + }) this.RestaurantMock = dbMock.define('Restaurant', { id: 1, - name: '銷魂麵' - }); + name: '銷魂麵', + }) this.CategoryMock = dbMock.define('Category', { id: 1, - name: '食物' - }); + name: '食物', + }) this.CommentMock = dbMock.define('Comment', { id: 1, - text: "gogogo" + text: 'gogogo', }) // 將 mock user db 中的 findByPK 用 findOne 取代 (sequelize mock not support findByPK) - this.RestaurantMock.findByPk = (id) => this.RestaurantMock.findOne({where: {id: id}}); + this.RestaurantMock.findByPk = (id) => + this.RestaurantMock.findOne({ where: { id: id } }) // 將 count 的 function 預設回傳假資料數目 1 - this.CommentMock.count = () => 1; - + this.CommentMock.count = () => 1 + // 將 restController 中的 User,Category,Restaurant,Comment 都用模擬資料取代 this.restController = proxyquire('../controllers/restController', { - '../models': { - User: this.UserMock, - Category: this.CategoryMock, + '../models': { + User: this.UserMock, + Category: this.CategoryMock, Restaurant: this.RestaurantMock, Comment: this.CommentMock, - } - }); + }, + }) }) - it(" GET /restaurants/:id/dashboard ", async () => { - const req = mockRequest({params: {id: 1}}); + it(' GET /restaurants/:id/dashboard ', async () => { + const req = mockRequest({ params: { id: 1 } }) const res = mockResponse() // call getDashBoard function - await this.restController.getDashBoard(req, res); + await this.restController.getDashBoard(req, res) // 確認執行 getDasgBoard 之後,回傳的 res.render 的參數是否與模擬資料相同 - res.render.getCall(0).args[0].should.equal('dashboard'); - res.render.getCall(0).args[1].restaurant.name.should.equal('銷魂麵'); - res.render.getCall(0).args[1].n_comments.should.equal(1); - }); + res.render.getCall(0).args[0].should.equal('dashboard') + res.render.getCall(0).args[1].restaurant.name.should.equal('銷魂麵') + res.render.getCall(0).args[1].n_comments.should.equal(1) + }) }) -}) \ No newline at end of file +}) diff --git a/tests/A21.test.js b/tests/A21.test.js index 5a82f84a..f8a30bfa 100644 --- a/tests/A21.test.js +++ b/tests/A21.test.js @@ -5,139 +5,139 @@ const should = chai.should() const db = require('../models') const helpers = require('../_helpers') -const SequelizeMock = require('sequelize-mock'); -const proxyquire = require('proxyquire'); +const SequelizeMock = require('sequelize-mock') +const proxyquire = require('proxyquire') -const dbMock = new SequelizeMock({autoQueryFallback: false}); +const dbMock = new SequelizeMock({ autoQueryFallback: false }) const mockRequest = (query) => { return { ...query, - flash: sinon.spy() - }; -}; + flash: sinon.spy(), + } +} const mockResponse = () => { return { redirect: sinon.spy(), render: sinon.spy(), } -}; +} // 模擬 Like 資料 -let mockLikeData = [{ - UserId: 1, - RestaurantId: 2, -}] +let mockLikeData = [ + { + UserId: 1, + RestaurantId: 2, + }, +] describe('# A21: Like / Unlike', function () { context('# Q1: 使用者可以 Like 餐廳', () => { before(() => { // 模擬驗證資料 - this.ensureAuthenticated = sinon.stub( - helpers, 'ensureAuthenticated' - ).returns(true); - this.getUser = sinon.stub( - helpers, 'getUser' - ).returns({id: 1}); - - // - this.mockLikeData = []; - this.likeMock = dbMock.define('Like'); + this.ensureAuthenticated = sinon + .stub(helpers, 'ensureAuthenticated') + .returns(true) + this.getUser = sinon.stub(helpers, 'getUser').returns({ id: 1 }) + + // + this.mockLikeData = [] + this.likeMock = dbMock.define('Like') // 因為 mock 中的 create 有問題,因此指向 upsert function, 這樣可以在 useHandler 中取得 create 呼叫 - this.likeMock.create = this.likeMock.upsert; + this.likeMock.create = this.likeMock.upsert // 模擬 Like.create and Like.finall 的 function - this.likeMock.$queryInterface.$useHandler((query, queryOptions,done) => { + this.likeMock.$queryInterface.$useHandler((query, queryOptions, done) => { if (query === 'upsert') { // create 時會帶 UserId 跟 RestaurantId (ex: Like.create({ UserId: 1, RestaurantId: 2})) - const {UserId, RestaurantId} = queryOptions[0]; - + const { UserId, RestaurantId } = queryOptions[0] + // 新增這個 Like 的資訊到模擬資料裡 - this.mockLikeData.push({ UserId, RestaurantId }); - + this.mockLikeData.push({ UserId, RestaurantId }) + // 回傳模擬資料 - return Promise.resolve(this.likeMock.build(this.mockLikeData)); + return Promise.resolve(this.likeMock.build(this.mockLikeData)) } else if (query === 'findAll') { // 回傳模擬資料 - return Promise.resolve(this.mockLikeData); + return Promise.resolve(this.mockLikeData) } - }); + }) this.userController = proxyquire('../controllers/userController', { - '../models': {Like: this.likeMock} - }); + '../models': { Like: this.likeMock }, + }) }) - it(" POST /like/:restaurantId ", async () => { - const req = mockRequest({params: {id: 1, restaurantId: 2}}); - const res = mockResponse(); + it(' POST /like/:restaurantId ', async () => { + const req = mockRequest({ params: { id: 1, restaurantId: 2 } }) + const res = mockResponse() // 呼叫 userController 中的 addLike - await this.userController.addLike(req, res); + await this.userController.addLike(req, res) - const likes = await this.likeMock.findAll(); + const likes = await this.likeMock.findAll() // 確認呼叫 addLike 後,模擬資料中的 like 資料會多一個 - likes.should.have.lengthOf(1); - }); + likes.should.have.lengthOf(1) + }) after(async () => { // 清除驗證資料 - this.ensureAuthenticated.restore(); - this.getUser.restore(); + this.ensureAuthenticated.restore() + this.getUser.restore() }) }) context('# Q1: 使用者可以 unLike 餐廳', () => { before(() => { // 模擬驗證資料 - this.ensureAuthenticated = sinon.stub( - helpers, 'ensureAuthenticated' - ).returns(true); - this.getUser = sinon.stub( - helpers, 'getUser' - ).returns({id: 1}); + this.ensureAuthenticated = sinon + .stub(helpers, 'ensureAuthenticated') + .returns(true) + this.getUser = sinon.stub(helpers, 'getUser').returns({ id: 1 }) // 模擬 Like db 資料 this.likeMock = dbMock.define('Like', { id: 1, UserId: 1, RestaurantId: 2, - }); - // 模擬 Like.destroy and Like.finall 的 function - this.likeMock.$queryInterface.$useHandler((query, queryOptions,done) => { + }) + // 模擬 Like.destroy and Like.finall 的 function + this.likeMock.$queryInterface.$useHandler((query, queryOptions, done) => { if (query === 'destroy') { - const {UserId, RestaurantId} = queryOptions[0].where; + const { UserId, RestaurantId } = queryOptions[0].where // destroy 可以從 where 取得要刪除的資料 // 因此就可以模擬將模擬資料中的資料刪除 - mockLikeData = mockLikeData.filter(d => !(d.UserId === UserId && d.RestaurantId === RestaurantId)) + mockLikeData = mockLikeData.filter( + (d) => !(d.UserId === UserId && d.RestaurantId === RestaurantId) + ) - return Promise.resolve(this.likeMock.build(mockLikeData)); + return Promise.resolve(this.likeMock.build(mockLikeData)) } else if (query === 'findAll') { - return Promise.resolve(mockLikeData); + return Promise.resolve(mockLikeData) } - }); + }) this.userController = proxyquire('../controllers/userController', { - '../models': {Like: this.likeMock} - }); + '../models': { Like: this.likeMock }, + }) }) - it(" DELETE /like/:restaurantId ", async () => { + it(' DELETE /like/:restaurantId ', async () => { // 模擬發出 request, 帶入 params.id = 1, restaurantId = 2 - const req = mockRequest({params: {id: 1, restaurantId: 2}}); - const res = mockResponse(); + const req = mockRequest({ params: { id: 1, restaurantId: 2 } }) + const res = mockResponse() // call DELETE /like/:restaurantId route 對應的 userController.removeLike - await this.userController.removeLike(req, res); + await this.userController.removeLike(req, res) // 刪除後,模擬資料會是空的 - const likes = await this.likeMock.findAll(); - likes.should.have.lengthOf(0); - }); + const likes = await this.likeMock.findAll() + likes.should.have.lengthOf(0) + }) after(async () => { // 清除模擬驗證資料 - this.ensureAuthenticated.restore(); - this.getUser.restore(); + this.ensureAuthenticated.restore() + this.getUser.restore() }) - }); -}) \ No newline at end of file + }) +}) diff --git a/tests/A22.test.js b/tests/A22.test.js index ab41c162..9791f74e 100644 --- a/tests/A22.test.js +++ b/tests/A22.test.js @@ -4,161 +4,189 @@ const sinon = require('sinon') const should = chai.should() const app = require('../app') -const helpers = require('../_helpers'); -const SequelizeMock = require('sequelize-mock'); -const proxyquire = require('proxyquire'); +const helpers = require('../_helpers') +const SequelizeMock = require('sequelize-mock') +const proxyquire = require('proxyquire') -const dbMock = new SequelizeMock({autoQueryFallback: false}); +const dbMock = new SequelizeMock({ autoQueryFallback: false }) const mockRequest = (query) => { return { ...query, - flash: sinon.spy() - }; -}; + flash: sinon.spy(), + } +} const mockResponse = () => { return { redirect: sinon.spy(), render: sinon.spy(), } -}; +} // 模擬的餐廳資料 -let mockRestaurantData = [{ - id: 1, - name: 'Restaurant1', - tel: 'tel', - address: 'address', - opening_hours: 'opening_hours', - description: "test description", - FavoritedUsers: [{ - UserId: 1, - }] -}, { - id: 2, - name: 'Restaurant2', - tel: 'tel', - address: 'address', - opening_hours: 'opening_hours', - description: 'description', - CategoryId: 1, - FavoritedUsers: [] -}] +let mockRestaurantData = [ + { + id: 1, + name: 'Restaurant1', + tel: 'tel', + address: 'address', + opening_hours: 'opening_hours', + description: 'test description', + FavoritedUsers: [ + { + UserId: 1, + }, + ], + }, + { + id: 2, + name: 'Restaurant2', + tel: 'tel', + address: 'address', + opening_hours: 'opening_hours', + description: 'description', + CategoryId: 1, + FavoritedUsers: [], + }, +] describe('# A22: TOP 10 人氣餐廳 ', function () { - context('# [網址正確、畫面正常執行]', () => { before(async () => { // 模擬驗證資料 - this.ensureAuthenticated = sinon.stub( - helpers, 'ensureAuthenticated' - ).returns(true); - this.getUser = sinon.stub( - helpers, 'getUser' - ).returns({ id: 1, Followings: [], FavoritedRestaurants: [] }); + this.ensureAuthenticated = sinon + .stub(helpers, 'ensureAuthenticated') + .returns(true) + this.getUser = sinon + .stub(helpers, 'getUser') + .returns({ id: 1, Followings: [], FavoritedRestaurants: [] }) }) - it(" GET /restaurants/top ", (done) => { + it(' GET /restaurants/top ', (done) => { request(app) .get('/restaurants/top') .end(function (err, res) { // 檢查回傳的資料中,是否有 Top 10 人氣餐廳資訊 - res.text.should.include('Top 10 人氣餐廳') // 可以正確執行,沒有 error 即可通過 + res.text.should.include('Top 10 人氣餐廳') // 可以正確執行,沒有 error 即可通過 done() - }); - }); + }) + }) after(async () => { // 清除模擬驗證資料 - this.ensureAuthenticated.restore(); - this.getUser.restore(); + this.ensureAuthenticated.restore() + this.getUser.restore() }) - }) - context('# [當你點擊畫面上的「加入最愛 / 移除最愛」按鈕時,會重新計算「收藏數」的數字]', () => { - before(async () => { - // 模擬驗證資料 - this.ensureAuthenticated = sinon.stub( - helpers, 'ensureAuthenticated' - ).returns(true); - this.getUser = sinon.stub( - helpers, 'getUser' - ).returns({ id: 1, Followings: [], FavoritedRestaurants: [] }); - - // 模擬 Restaurant db 資料 - this.restaurantMock = dbMock.define('Restaurant'); - this.restaurantMock.$queryInterface.$useHandler((query, queryOptions,done) => { - if (query === 'findAll') { - return Promise.resolve(mockRestaurantData.map(d => this.restaurantMock.build(d))); - } - }); - - // 將 restController 中的 Restaurant db 取代成 Restaurant mock db - this.restController = proxyquire('../controllers/restController', { - '../models': { - Restaurant: this.restaurantMock, - } - }); - - // 模擬 Favorite db 資料 - this.favoriteMock = dbMock.define('Favorite'); - this.favoriteMock.create = this.favoriteMock.upsert; - this.favoriteMock.$queryInterface.$useHandler((query, queryOptions,done) => { - if (query === 'upsert') { - // 新增 favortie 資料到模擬資料 - const {UserId, RestaurantId} = queryOptions[0]; - const restaurant = mockRestaurantData.find(d => d.id === RestaurantId); - restaurant.FavoritedUsers.push({UserId: UserId}); - return Promise.resolve(mockRestaurantData.map(d => this.restaurantMock.build(d))); - } else if (query === 'destroy') { - // 刪除模擬資料中的某一筆 favortie 資料 - const {UserId, RestaurantId} = queryOptions[0].where; - const restaurant = mockRestaurantData.find(d => d.id === RestaurantId); - restaurant.FavoritedUsers = restaurant.FavoritedUsers.filter(d => !(d.UserId === UserId)) - return Promise.resolve(mockRestaurantData.map(d => this.restaurantMock.build(d))); - } - }); - - // 將 userController 中的 Favorite db 取代成 Favorite mock db - this.userController = proxyquire('../controllers/userController', { - '../models': {Favorite: this.favoriteMock} + context( + '# [當你點擊畫面上的「加入最愛 / 移除最愛」按鈕時,會重新計算「收藏數」的數字]', + () => { + before(async () => { + // 模擬驗證資料 + this.ensureAuthenticated = sinon + .stub(helpers, 'ensureAuthenticated') + .returns(true) + this.getUser = sinon + .stub(helpers, 'getUser') + .returns({ id: 1, Followings: [], FavoritedRestaurants: [] }) + + // 模擬 Restaurant db 資料 + this.restaurantMock = dbMock.define('Restaurant') + this.restaurantMock.$queryInterface.$useHandler( + (query, queryOptions, done) => { + if (query === 'findAll') { + return Promise.resolve( + mockRestaurantData.map((d) => this.restaurantMock.build(d)) + ) + } + } + ) + + // 將 restController 中的 Restaurant db 取代成 Restaurant mock db + this.restController = proxyquire('../controllers/restController', { + '../models': { + Restaurant: this.restaurantMock, + }, + }) + + // 模擬 Favorite db 資料 + this.favoriteMock = dbMock.define('Favorite') + this.favoriteMock.create = this.favoriteMock.upsert + this.favoriteMock.$queryInterface.$useHandler( + (query, queryOptions, done) => { + if (query === 'upsert') { + // 新增 favortie 資料到模擬資料 + const { UserId, RestaurantId } = queryOptions[0] + const restaurant = mockRestaurantData.find( + (d) => d.id === RestaurantId + ) + restaurant.FavoritedUsers.push({ UserId: UserId }) + return Promise.resolve( + mockRestaurantData.map((d) => this.restaurantMock.build(d)) + ) + } else if (query === 'destroy') { + // 刪除模擬資料中的某一筆 favortie 資料 + const { UserId, RestaurantId } = queryOptions[0].where + const restaurant = mockRestaurantData.find( + (d) => d.id === RestaurantId + ) + restaurant.FavoritedUsers = restaurant.FavoritedUsers.filter( + (d) => !(d.UserId === UserId) + ) + return Promise.resolve( + mockRestaurantData.map((d) => this.restaurantMock.build(d)) + ) + } + } + ) + + // 將 userController 中的 Favorite db 取代成 Favorite mock db + this.userController = proxyquire('../controllers/userController', { + '../models': { Favorite: this.favoriteMock }, + }) }) - }) - - it(" POST favorite ", async () => { - // 模擬 request 新增 user id = 1, 喜愛 restaurant id = 2 - const req = mockRequest({user: { FavoritedRestaurants: []}, params: {restaurantId: 2}}); - const res = mockResponse(); - - // call addFavorite - await this.userController.addFavorite(req, res); - - // 確認 getTopRestaurant 取得餐廳 2 的 favorite 數量會不同 - await this.restController.getTopRestaurant(req, res); - res.render.getCall(0).args[1].restaurants[1].FavoritedCount.should.equal(1); - }) - - it(" DELETE favorite ", async() => { - // 模擬 request 新增 user id = 1, 不喜愛 restaurant id = 1 - const req = mockRequest({user: { FavoritedRestaurants: []}, params: {restaurantId: 1}}); - const res = mockResponse(); + it(' POST favorite ', async () => { + // 模擬 request 新增 user id = 1, 喜愛 restaurant id = 2 + const req = mockRequest({ + user: { FavoritedRestaurants: [] }, + params: { restaurantId: 2 }, + }) + const res = mockResponse() - // call removeFavorite - await this.userController.removeFavorite(req, res); - // 取得餐廳排序資料 - await this.restController.getTopRestaurant(req, res); + // call addFavorite + await this.userController.addFavorite(req, res) - // 確認餐廳排序有變,第一個餐廳資料 id = 2 - res.render.getCall(0).args[1].restaurants[0].id.should.equal(2); - }) + // 確認 getTopRestaurant 取得餐廳 2 的 favorite 數量會不同 + await this.restController.getTopRestaurant(req, res) - after(async () => { - // 清除模擬驗證資料 - this.ensureAuthenticated.restore(); - this.getUser.restore(); - }) + res.render + .getCall(0) + .args[1].restaurants[1].FavoritedCount.should.equal(1) + }) - }) + it(' DELETE favorite ', async () => { + // 模擬 request 新增 user id = 1, 不喜愛 restaurant id = 1 + const req = mockRequest({ + user: { FavoritedRestaurants: [] }, + params: { restaurantId: 1 }, + }) + const res = mockResponse() + + // call removeFavorite + await this.userController.removeFavorite(req, res) + // 取得餐廳排序資料 + await this.restController.getTopRestaurant(req, res) + + // 確認餐廳排序有變,第一個餐廳資料 id = 2 + res.render.getCall(0).args[1].restaurants[0].id.should.equal(2) + }) -}) \ No newline at end of file + after(async () => { + // 清除模擬驗證資料 + this.ensureAuthenticated.restore() + this.getUser.restore() + }) + } + ) +}) diff --git a/tests/index.js b/tests/index.js index b1d92960..57535e46 100644 --- a/tests/index.js +++ b/tests/index.js @@ -2,17 +2,14 @@ const request = require('supertest') const app = require('../app') -describe('# 測試環境初始化', function() { - +describe('# 測試環境初始化', function () { context('# First Test Case', () => { - - it(" GET /admin/users ", (done) => { - request(app) - .get('/') - .end(function(err, res) { - done() - }); - }); - + it(' GET /admin/users ', (done) => { + request(app) + .get('/') + .end(function (err, res) { + done() + }) + }) }) -}) \ No newline at end of file +}) From 39950b9594308b07a78471d1db7638fad7f7f0da Mon Sep 17 00:00:00 2001 From: Carrot7712 Date: Wed, 27 Oct 2021 22:17:00 +0800 Subject: [PATCH 014/135] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E8=AE=8A=E6=95=B8?= =?UTF-8?q?=E5=90=8D=E8=88=87=E8=A8=BB=E8=A7=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/A17.test.js | 77 +++++++++++++++++++++++++++++------------------ tests/A19.test.js | 64 +++++++++++++++++++++------------------ tests/A20.test.js | 15 ++++++--- tests/A21.test.js | 51 +++++++++++++++++-------------- tests/A22.test.js | 75 +++++++++++++++++++++++++-------------------- 5 files changed, 164 insertions(+), 118 deletions(-) diff --git a/tests/A17.test.js b/tests/A17.test.js index 6320dca3..03a6b21e 100644 --- a/tests/A17.test.js +++ b/tests/A17.test.js @@ -23,45 +23,54 @@ const mockResponse = () => { } describe('# A17', () => { - describe('登入測試: POST /signin', function () { - // 以下測試會發出真實的 request 測試資料庫是否有正確的 user 資料 - it('#1 密碼錯誤', function (done) { + describe('登入測試: POST /signin', function(){ + // 以下測試會發出請求,測試資料庫內是否有作業指定的使用者資料 + // 測試資料的來源是真實的資料庫 + it('#1 密碼錯誤', function(done){ request(app) + // 對 POST /signin 發出請求,參數是錯誤的密碼 .post('/signin') .type('urlencoded') .send('email=root@example.com&password=123') + // 期待登入驗證回應失敗,重新導向 /signin .expect('Location', '/signin') .expect(302, done) }) - it('#2 帳號錯誤', function (done) { + it('#2 帳號錯誤', function(done){ request(app) + // 對 POST /signin 發出請求,參數是錯誤的帳號 .post('/signin') .type('urlencoded') .send('email=tu&password=12345678') + // 期待登入驗證回應失敗,重新導向 /signin .expect('Location', '/signin') .expect(302, done) }) - it('#3 成功登入', function (done) { + it('#3 成功登入', function(done){ request(app) + // 對 POST /signin 發出請求,參數是作業指定的使用者帳號密碼 .post('/signin') .type('urlencoded') .send('email=root@example.com&password=12345678') + // 期待登入驗證成功,重新導向 /restaurants .expect('Location', '/restaurants') .expect(302, done) }) - }) + }); describe('# A17: 使用者權限管理', function () { before(() => { - // 製作假 db 資料: UserMock + // 製作假資料 + // 下個 context 會用這筆資料進行測試 this.UserMock = dbMock.define('User', { id: 1, email: 'root@example.com', name: 'admin', isAdmin: false, }) + // 模擬 Sequelize 行為 // 將 mock user db 中的 findByPK 用 findOne 取代 (sequelize mock not support findByPK) this.UserMock.findByPk = (id) => this.UserMock.findOne({ where: { id: id } }) @@ -74,26 +83,30 @@ describe('# A17', () => { context('# [顯示使用者清單]', () => { it(' GET /admin/users ', async () => { // 模擬 request & response - const req = mockRequest() + const req = mockRequest() // 對 GET /admin/users 發出請求 const res = mockResponse() - // 測試 adminController.getUsers function + // 測試作業指定的 adminController.getUsers 函式 await this.adminController.getUsers(req, res) - // render 裡的第二個參數,回傳了 users, 名稱必須跟假資料一樣是 admin + // getUser 執行完畢後,應呼叫 res.render + // res.render 的第 2 個參數應是 users + // 根據測試資料,users 中的第 1 筆資料,name 屬性值應該要是 'admin' res.render.getCall(0).args[1].users[0].name.should.equal('admin') }) }) context('# [修改使用者權限] for admin', () => { before(() => { - // 模擬 user db 資料: UserMock + // 製作假資料 + // 本 context 會用這筆資料進行測試 this.UserMock = dbMock.define('User', { id: 1, email: 'root@example.com', name: 'admin', - isAdmin: true, + isAdmin: true, // 是管理者 }) + // 模擬 Sequelize 行為 // 將 mock user db 中的 findByPK 用 findOne 取代 (sequelize mock not support findByPK) // 將 count 的 function 預設回傳假資料數目 1 this.UserMock.count = () => 1 @@ -106,35 +119,37 @@ describe('# A17', () => { }) it(' PUT /admin/users/:id/toggleAdmin ', async () => { - const req = mockRequest({ params: { id: 1 } }) + // 模擬 request & response + const req = mockRequest({ params: { id: 1 } }) // 帶入 params.id = 1,對 PUT /admin/users/1/toggleAdmin 發出請求 const res = mockResponse() - // 測試 adminController.toggleAdmin function + // 測試作業指定的 adminController.toggleAdmin 函式 await this.adminController.toggleAdmin(req, res) - // 執行完 toggleAdmin 後,res.flash 有被呼叫而且呼叫的訊息正確 - req.flash.calledWith( - 'error_messages', - 'core manager can not be changed' - ).should.be.true - // 執行完 toggleAmin 後 res.redirect 有被呼叫而且 redirect 到 back + // toggleAdmin 正確執行的話,應呼叫 req.flash + // req.flash 的參數應該要與下列字串一致 + req.flash.calledWith('error_messages','禁止變更管理者權限').should.be.true + + // toggleAdmin 執行完畢後,應呼叫 res.redirect 並重新導向上一頁 res.redirect.calledWith('back').should.be.true }) }) context('# [修改使用者權限] for user', () => { before(() => { + // 製作假資料 + // 本 context 會用這筆資料進行測試 this.UserMock = dbMock.define( 'User', { id: 1, email: 'user@example.com', name: 'user', - isAdmin: false, + isAdmin: false, // 非管理者 }, { instanceMethods: { - // 模擬 update 函數,並依據傳入的變數,跟著修正,如果傳入 {isAdmin: true} + // 模擬一個會改變 admin 權限的函式 update: (changes) => { this.UserMock._defaults = { ...changes } return Promise.resolve() @@ -142,7 +157,7 @@ describe('# A17', () => { }, } ) - + // 模擬 Sequelize 行為 this.UserMock.count = () => 1 this.UserMock.findByPk = (id) => this.UserMock.findOne({ where: { id: id } }) @@ -153,19 +168,21 @@ describe('# A17', () => { }) it(' PUT /admin/users/:id/toggleAdmin ', async (done) => { - const req = mockRequest({ params: { id: 1 } }) + // 模擬 request & response + const req = mockRequest({ params: { id: 1 } }) // 帶入 params.id = 1,對 PUT /admin/users/1/toggleAdmin 發出請求 const res = mockResponse() + // 測試作業指定的 adminController.toggleAdmin 函式 await this.adminController.toggleAdmin(req, res) - req.flash.calledWith( - 'success_messages', - 'user was successfully to update' - ).should.be.true + // toggleAdmin 正確執行的話,應呼叫 req.flash + // req.flash 的參數應與下列字串一致 + req.flash.calledWith('success_messages','使用者權限變更成功').should.be.true + // toggleAdmin 執行完畢後,應呼叫 res.redirect 並重新導向 /admin/users res.redirect.calledWith('/admin/users').should.be.true - // 執行完 toggleAmin 後,因為假資料中使用者是 user@example.com,因此可以修改權限 isAdmin 從 false -> true - // 所以這邊將假資料撈出,比對看是否有修改到 + // toggleAmin 執行完畢後,假資料中 id:1 使用者的應該要是 isAdmin:true + // 將假資料撈出,比對確認有成功修改到 const user = await this.UserMock.findOne({ where: { id: 1 } }) user.isAdmin.should.equal(true) diff --git a/tests/A19.test.js b/tests/A19.test.js index d00fa12f..5b2b8f29 100644 --- a/tests/A19.test.js +++ b/tests/A19.test.js @@ -28,18 +28,20 @@ describe('# A19', () => { describe('# A19: 建立 User Profile', function () { context('# [瀏覽 Profile]', () => { before(() => { - // 模擬驗證資料 + // 模擬登入驗證 this.ensureAuthenticated = sinon .stub(helpers, 'ensureAuthenticated') .returns(true) this.getUser = sinon.stub(helpers, 'getUser').returns({ id: 1 }) - // 模擬 User db 資料 + // 製作假資料 + // 本 context 會用這筆資料進行測試 this.UserMock = dbMock.define('User', { id: 1, email: 'root@example.com', name: 'admin', isAdmin: false, }) + // 模擬 Sequelize 行為 // 將 mock user db 中的 findByPK 用 findOne 取代 (sequelize mock not support findByPK) this.UserMock.findByPk = (id) => this.UserMock.findOne({ where: { id: id } }) @@ -50,18 +52,18 @@ describe('# A19', () => { }) it(' GET /users/:id ', async () => { - // 模擬發出 request, 帶入 params.id = 1 - const req = mockRequest({ params: { id: 1 } }) + // 模擬 request & response + const req = mockRequest({ params: { id: 1 } }) // 帶入 params.id = 1,對 GET /users/1 發出請求 const res = mockResponse() - // 測試 userController.getUser + // 測試作業指定的 userController.getUser 函式 await this.userController.getUser(req, res) - // 執行完後,call res.render 的參數測試 - // 1. 第一個參數是不是 profile - // 2. 第二個參數裡回傳的資料有 userData 而且 name 是 admin + // toggleAdmin 執行完畢後,應呼叫 res.render + // res.render 的第 1 個參數要是 'profile' + // res.render 的第 2 個參數要是 user,其 name 屬性的值應是 'admin' res.render.getCall(0).args[0].should.equal('profile') - res.render.getCall(0).args[1].userData.name.should.equal('admin') + res.render.getCall(0).args[1].user.name.should.equal('admin') }) after(async () => { @@ -73,19 +75,21 @@ describe('# A19', () => { context('# [瀏覽編輯 Profile 頁面]', () => { before(() => { - // 製作假驗證資料 + // 模擬登入驗證 this.ensureAuthenticated = sinon .stub(helpers, 'ensureAuthenticated') .returns(true) this.getUser = sinon.stub(helpers, 'getUser').returns({ id: 1 }) - // 模擬 User db 資料 + // 製作假資料 + // 本 context 會用這筆資料進行測試 this.UserMock = dbMock.define('User', { id: 1, email: 'root@example.com', name: 'admin', isAdmin: false, }) + // 模擬 Sequelize 行為 // 將 mock user db 中的 findByPK 用 findOne 取代 (sequelize mock not support findByPK) this.UserMock.findByPk = (id) => this.UserMock.findOne({ where: { id: id } }) @@ -98,15 +102,15 @@ describe('# A19', () => { it(' GET /users/:id/edit ', async () => { // 模擬 request & response - const req = mockRequest({ params: { id: 1 } }) + const req = mockRequest({ params: { id: 1 } }) // 帶入 params.id = 1,對 GET /users/1/edit 發出請求 const res = mockResponse() - // 測試 adminController.editUser function + // 測試作業指定的 adminController.editUser 函式 await this.userController.editUser(req, res) - // 執行完 editUser 後,call res.render 的參數測試 - // 1. 第一個參數是不是 edit - // 2. 第二個參數裡回傳的資料有 user 而且 name 是 admin + // editUser 執行完畢後,應呼叫 res.render + // res.render 的第 1 個參數要是 'edit' + // res.render 的第 2 個參數要是 user,其 name 屬性的值應是 'admin' res.render.getCall(0).args[0].should.equal('edit') res.render.getCall(0).args[1].user.name.should.equal('admin') }) @@ -120,12 +124,13 @@ describe('# A19', () => { context('# [編輯 Profile]', () => { before(async () => { - // 模擬 request & response + // 模擬登入驗證 this.ensureAuthenticated = sinon .stub(helpers, 'ensureAuthenticated') .returns(true) this.getUser = sinon.stub(helpers, 'getUser').returns({ id: 1 }) - // 製作假 db 資料: UserMock + // 製作假資料 + // 本 context 會用這筆資料進行測試 this.UserMock = dbMock.define( 'User', { @@ -136,7 +141,7 @@ describe('# A19', () => { }, { instanceMethods: { - // 模擬 update 函數,並依據傳入的變數,跟著修正,如果傳入 {isAdmin: true} + // 模擬一個會改變 admin 權限的函式 update: (changes) => { this.UserMock._defaults = { ...changes } return Promise.resolve() @@ -144,6 +149,7 @@ describe('# A19', () => { }, } ) + // 模擬 Sequelize 行為 // 將 mock user db 中的 findByPK 用 findOne 取代 (sequelize mock not support findByPK) this.UserMock.findByPk = (id) => this.UserMock.findOne({ where: { id: id } }) @@ -154,24 +160,24 @@ describe('# A19', () => { }) it(' PUT /users/:id ', async () => { - // 模擬發送 request, 帶了 params.id = 1, body.name = amdin2, body.email = admin_test@gmail.com + // 模擬 request & response + // 對 PUT /users/1 發出 request,並夾帶 body.name = amdin2, body.email = admin_test@gmail.com const req = mockRequest({ params: { id: 1 }, body: { name: 'admin2', email: 'admin_test@gmail.com' }, - }) + }) const res = mockResponse() - // 修改模擬資料, call putUser function + // 測試作業指定的 userController.putUser 函式 await this.userController.putUser(req, res) - // 測試成功修改 user 資料後,是否有回傳正確訊息 - req.flash.calledWith( - 'success_messages', - 'user was updated successfully' - ).should.be.true - // 測試成功修改 user 資料後,是否有導向正確 route + // putUser 正確執行的話,應呼叫 req.flash + // req.flash 的參數應與下列字串一致 + req.flash.calledWith('success_messages','使用者資料編輯成功').should.be.true + // putUser 執行完畢後,應呼叫 res.redirect 並重新導向 /users/1 res.redirect.calledWith('/users/1').should.be.true - // 修改後,測試模擬資料中是否有成功修正, name = amdin2, email = admin_test@gmail.com + // putUser 執行完畢後,id:1 使用者的 name 和 email 應該已被修改 + // 將假資料撈出,比對確認有成功修改到 const user = await this.UserMock.findOne({ where: { id: 1 } }) user.name.should.equal('admin2') user.email.should.equal('admin_test@gmail.com') diff --git a/tests/A20.test.js b/tests/A20.test.js index e1d908b3..3f922f0b 100644 --- a/tests/A20.test.js +++ b/tests/A20.test.js @@ -25,7 +25,8 @@ const mockResponse = () => { describe('# A20: 餐廳資訊整理:Dashboard', function () { context('# [Q1: Dashboard - 1 - controller / view / route]', () => { before(async () => { - // 模擬 user, restaurant, category, comment 資料 + // 製作假資料 + // 本 context 會用這筆資料進行測試 this.UserMock = dbMock.define('User', { id: 1, email: 'root@example.com', @@ -44,6 +45,7 @@ describe('# A20: 餐廳資訊整理:Dashboard', function () { id: 1, text: 'gogogo', }) + // 模擬 Sequelize 行為 // 將 mock user db 中的 findByPK 用 findOne 取代 (sequelize mock not support findByPK) this.RestaurantMock.findByPk = (id) => this.RestaurantMock.findOne({ where: { id: id } }) @@ -62,15 +64,18 @@ describe('# A20: 餐廳資訊整理:Dashboard', function () { }) it(' GET /restaurants/:id/dashboard ', async () => { - const req = mockRequest({ params: { id: 1 } }) + // 模擬 request & response + const req = mockRequest({ params: { id: 1 } }) // 帶入 params.id = 1,對 GET /restaurants/1/dashboard 發出請求 const res = mockResponse() - // call getDashBoard function + // 測試 restController.getDashBoard 函式 await this.restController.getDashBoard(req, res) - // 確認執行 getDasgBoard 之後,回傳的 res.render 的參數是否與模擬資料相同 + // getDashBoard 執行完畢後,應呼叫 res.render + // res.render 的第 1 個參數要是 'dashboard' + // res.render 的第 2 個參數要包含 restaurant,其 name 屬性的值應是 '銷魂麵' res.render.getCall(0).args[0].should.equal('dashboard') res.render.getCall(0).args[1].restaurant.name.should.equal('銷魂麵') - res.render.getCall(0).args[1].n_comments.should.equal(1) + res.render.getCall(0).args[1].n_comments.should.equal(1) // question** }) }) }) diff --git a/tests/A21.test.js b/tests/A21.test.js index f8a30bfa..b2a1f83e 100644 --- a/tests/A21.test.js +++ b/tests/A21.test.js @@ -23,37 +23,38 @@ const mockResponse = () => { } } -// 模擬 Like 資料 +// 建立模擬的 Like 資料 let mockLikeData = [ { - UserId: 1, - RestaurantId: 2, + userId: 1, + restaurantId: 2, }, ] describe('# A21: Like / Unlike', function () { context('# Q1: 使用者可以 Like 餐廳', () => { before(() => { - // 模擬驗證資料 + // 模擬登入驗證 this.ensureAuthenticated = sinon .stub(helpers, 'ensureAuthenticated') .returns(true) this.getUser = sinon.stub(helpers, 'getUser').returns({ id: 1 }) - // + // 建立了一個模擬的 Like table,裡面目前是空的 + // 模擬 Sequelize 行為 this.mockLikeData = [] this.likeMock = dbMock.define('Like') // 因為 mock 中的 create 有問題,因此指向 upsert function, 這樣可以在 useHandler 中取得 create 呼叫 this.likeMock.create = this.likeMock.upsert - // 模擬 Like.create and Like.finall 的 function + // 模擬 Like.create and Like.findall 的 function this.likeMock.$queryInterface.$useHandler((query, queryOptions, done) => { if (query === 'upsert') { - // create 時會帶 UserId 跟 RestaurantId (ex: Like.create({ UserId: 1, RestaurantId: 2})) - const { UserId, RestaurantId } = queryOptions[0] + // create 時會帶 userId 跟 restaurantId (ex: Like.create({ userId: 1, restaurantId: 2})) + const { userId, restaurantId } = queryOptions[0] // 新增這個 Like 的資訊到模擬資料裡 - this.mockLikeData.push({ UserId, RestaurantId }) + this.mockLikeData.push({ userId, restaurantId }) // 回傳模擬資料 return Promise.resolve(this.likeMock.build(this.mockLikeData)) @@ -69,14 +70,15 @@ describe('# A21: Like / Unlike', function () { }) it(' POST /like/:restaurantId ', async () => { - const req = mockRequest({ params: { id: 1, restaurantId: 2 } }) + // 模擬 request & response + const req = mockRequest({ params: { id: 1, restaurantId: 2 } }) // 帶入 params.id = 1,對 POST /like/2 發出請求 const res = mockResponse() - // 呼叫 userController 中的 addLike + // 測試 userController.addLike 函式 await this.userController.addLike(req, res) - + // 將模擬的 Like table 內的資料全數撈出 const likes = await this.likeMock.findAll() - // 確認呼叫 addLike 後,模擬資料中的 like 資料會多一個 + // addLike 執行完畢後,Like table 應會從空的 -> 變成有 1 筆資料 likes.should.have.lengthOf(1) }) @@ -89,25 +91,28 @@ describe('# A21: Like / Unlike', function () { context('# Q1: 使用者可以 unLike 餐廳', () => { before(() => { - // 模擬驗證資料 + // 模擬登入驗證 this.ensureAuthenticated = sinon .stub(helpers, 'ensureAuthenticated') .returns(true) this.getUser = sinon.stub(helpers, 'getUser').returns({ id: 1 }) - // 模擬 Like db 資料 + // 製作假資料 + // 下個 context 會用這筆資料進行測試 + // 模擬 Like table 裡目前有 1 筆資料如下 this.likeMock = dbMock.define('Like', { id: 1, - UserId: 1, - RestaurantId: 2, + userId: 1, + restaurantId: 2, }) + // 模擬 Sequelize 行為 // 模擬 Like.destroy and Like.finall 的 function this.likeMock.$queryInterface.$useHandler((query, queryOptions, done) => { if (query === 'destroy') { - const { UserId, RestaurantId } = queryOptions[0].where + const { userId, restaurantId } = queryOptions[0].where // destroy 可以從 where 取得要刪除的資料 // 因此就可以模擬將模擬資料中的資料刪除 mockLikeData = mockLikeData.filter( - (d) => !(d.UserId === UserId && d.RestaurantId === RestaurantId) + (d) => !(d.userId === userId && d.restaurantId === restaurantId) ) return Promise.resolve(this.likeMock.build(mockLikeData)) @@ -122,15 +127,17 @@ describe('# A21: Like / Unlike', function () { }) it(' DELETE /like/:restaurantId ', async () => { + // 模擬 request & response // 模擬發出 request, 帶入 params.id = 1, restaurantId = 2 - const req = mockRequest({ params: { id: 1, restaurantId: 2 } }) + const req = mockRequest({ params: { id: 1, restaurantId: 2 } }) // 帶入 params.id = 1,對 DELETE /like/2 發出請求 const res = mockResponse() - // call DELETE /like/:restaurantId route 對應的 userController.removeLike + // 測試作業指定的 userController.removeLike 函式 await this.userController.removeLike(req, res) - // 刪除後,模擬資料會是空的 + // 將模擬的 Like table 內的資料全數撈出 const likes = await this.likeMock.findAll() + // addLike 執行完畢後,Like table 應會從有 1 筆資料 -> 變成空的 likes.should.have.lengthOf(0) }) diff --git a/tests/A22.test.js b/tests/A22.test.js index 9791f74e..4d379460 100644 --- a/tests/A22.test.js +++ b/tests/A22.test.js @@ -22,7 +22,7 @@ const mockResponse = () => { render: sinon.spy(), } } -// 模擬的餐廳資料 +// 模擬 2 間餐廳資料 let mockRestaurantData = [ { id: 1, @@ -31,9 +31,9 @@ let mockRestaurantData = [ address: 'address', opening_hours: 'opening_hours', description: 'test description', - FavoritedUsers: [ + favoritedUsers: [ { - UserId: 1, + userId: 1, }, ], }, @@ -44,29 +44,33 @@ let mockRestaurantData = [ address: 'address', opening_hours: 'opening_hours', description: 'description', - CategoryId: 1, - FavoritedUsers: [], + categoryId: 1, + favoritedUsers: [], }, ] describe('# A22: TOP 10 人氣餐廳 ', function () { context('# [網址正確、畫面正常執行]', () => { before(async () => { - // 模擬驗證資料 + // 模擬登入驗證 this.ensureAuthenticated = sinon .stub(helpers, 'ensureAuthenticated') .returns(true) + // 模擬 getUser 函式,負責取得使用者資料 this.getUser = sinon .stub(helpers, 'getUser') - .returns({ id: 1, Followings: [], FavoritedRestaurants: [] }) + .returns({ id: 1, followings: [], favoritedRestaurants: [] }) }) it(' GET /restaurants/top ', (done) => { + // 對 GET /restaurants/top 發出請求 request(app) .get('/restaurants/top') .end(function (err, res) { - // 檢查回傳的資料中,是否有 Top 10 人氣餐廳資訊 - res.text.should.include('Top 10 人氣餐廳') // 可以正確執行,沒有 error 即可通過 + // 回應中應包含字串'Top 10 人氣餐廳' + // 若請求路徑正確,controller 執行後,會呼叫 res.render + // res.render 回傳的 view 樣板裡應包含字串'Top 10 人氣餐廳' + res.text.should.include('Top 10 人氣餐廳') done() }) }) @@ -82,15 +86,17 @@ describe('# A22: TOP 10 人氣餐廳 ', function () { '# [當你點擊畫面上的「加入最愛 / 移除最愛」按鈕時,會重新計算「收藏數」的數字]', () => { before(async () => { - // 模擬驗證資料 + // 模擬登入驗證 this.ensureAuthenticated = sinon .stub(helpers, 'ensureAuthenticated') .returns(true) + // 模擬 getUser 函式,負責取得使用者資料 this.getUser = sinon .stub(helpers, 'getUser') - .returns({ id: 1, Followings: [], FavoritedRestaurants: [] }) + .returns({ id: 1, followings: [], favoritedRestaurants: [] }) - // 模擬 Restaurant db 資料 + // 建立了一個模擬的 Restaurant table,裡面放入 2 間餐廳資料 + // 模擬 Sequelize 行為 this.restaurantMock = dbMock.define('Restaurant') this.restaurantMock.$queryInterface.$useHandler( (query, queryOptions, done) => { @@ -109,29 +115,29 @@ describe('# A22: TOP 10 人氣餐廳 ', function () { }, }) - // 模擬 Favorite db 資料 + // 建立了一個模擬的 Favorite table,裡面有 1 筆資料 this.favoriteMock = dbMock.define('Favorite') this.favoriteMock.create = this.favoriteMock.upsert this.favoriteMock.$queryInterface.$useHandler( (query, queryOptions, done) => { if (query === 'upsert') { // 新增 favortie 資料到模擬資料 - const { UserId, RestaurantId } = queryOptions[0] + const { userId, restaurantId } = queryOptions[0] const restaurant = mockRestaurantData.find( - (d) => d.id === RestaurantId + (d) => d.id === restaurantId ) - restaurant.FavoritedUsers.push({ UserId: UserId }) + restaurant.favoritedUsers.push({ userId: userId }) return Promise.resolve( mockRestaurantData.map((d) => this.restaurantMock.build(d)) ) } else if (query === 'destroy') { // 刪除模擬資料中的某一筆 favortie 資料 - const { UserId, RestaurantId } = queryOptions[0].where + const { userId, restaurantId } = queryOptions[0].where const restaurant = mockRestaurantData.find( - (d) => d.id === RestaurantId + (d) => d.id === restaurantId ) - restaurant.FavoritedUsers = restaurant.FavoritedUsers.filter( - (d) => !(d.UserId === UserId) + restaurant.favoritedUsers = restaurant.favoritedUsers.filter( + (d) => !(d.userId === userId) ) return Promise.resolve( mockRestaurantData.map((d) => this.restaurantMock.build(d)) @@ -147,38 +153,43 @@ describe('# A22: TOP 10 人氣餐廳 ', function () { }) it(' POST favorite ', async () => { - // 模擬 request 新增 user id = 1, 喜愛 restaurant id = 2 + // 模擬 request & response + // 對 POST /favorite/2 發出請求,夾帶 user.favoritedRestaurants const req = mockRequest({ - user: { FavoritedRestaurants: [] }, + user: { favoritedRestaurants: [] }, params: { restaurantId: 2 }, }) const res = mockResponse() - // call addFavorite + // 測試 userController.addFavorite 函式 await this.userController.addFavorite(req, res) - // 確認 getTopRestaurant 取得餐廳 2 的 favorite 數量會不同 + // 取得餐廳排序資料 await this.restController.getTopRestaurant(req, res) - - res.render - .getCall(0) - .args[1].restaurants[1].FavoritedCount.should.equal(1) + + // addFavorite 執行完畢後,應呼叫 res.render + // res.render 的第 2 個參數要包含 restaurants + // restaurant 當中的第 2 筆資料 favoritedCount 屬性的值應是 1 (被 1 個使用者加入最愛了) + res.render.getCall(0).args[1].restaurants[1].favoritedCount.should.equal(1) }) it(' DELETE favorite ', async () => { - // 模擬 request 新增 user id = 1, 不喜愛 restaurant id = 1 + // 模擬 request & response + // 對 DELETE /favorite/1 發出請求,夾入 user.favoritedRestaurants const req = mockRequest({ - user: { FavoritedRestaurants: [] }, + user: { favoritedRestaurants: [] }, params: { restaurantId: 1 }, }) const res = mockResponse() - // call removeFavorite + // 測試 userController.removeFavorite 函式 await this.userController.removeFavorite(req, res) // 取得餐廳排序資料 await this.restController.getTopRestaurant(req, res) - // 確認餐廳排序有變,第一個餐廳資料 id = 2 + // removeFavorite 執行完畢後,應呼叫 res.render + // res.render 的第 2 個參數要包含 restaurants + // restaurants 當中的第 1 筆資料 id 屬性值應是 2 (id:1 的那家餐廳被刪除了) res.render.getCall(0).args[1].restaurants[0].id.should.equal(2) }) From 82de6c86d86a736b5dec9aa6fde9b1be8168bb41 Mon Sep 17 00:00:00 2001 From: Stanney Date: Thu, 28 Oct 2021 23:57:34 +0800 Subject: [PATCH 015/135] refactor mock db in unit test / integrated into helpers/unitTestHelpers --- helpers/unitTestHelpers.js | 85 ++++++++++++++++++++++++++++++++++++++ tests/A17.test.js | 67 +++++++++--------------------- tests/A19.test.js | 50 ++++------------------ tests/A20.test.js | 37 ++++++----------- tests/A21.test.js | 58 ++++---------------------- tests/A22.test.js | 60 ++++----------------------- 6 files changed, 143 insertions(+), 214 deletions(-) create mode 100644 helpers/unitTestHelpers.js diff --git a/helpers/unitTestHelpers.js b/helpers/unitTestHelpers.js new file mode 100644 index 00000000..a7157681 --- /dev/null +++ b/helpers/unitTestHelpers.js @@ -0,0 +1,85 @@ +const SequelizeMock = require('sequelize-mock') +const proxyquire = require('proxyquire') + +const dbMock = new SequelizeMock() + +const createModelMock = (name, defaultValue, data, joinedTableName) => { + const mockModel = dbMock.define(name, defaultValue, { + instanceMethods: { + update: (changes) => { + mockModel._defaults = {...changes} + return Promise.resolve() + } + } + }); + + // 模擬 Sequelize 行為 + // 將 mock user db 中的 findByPK 用 findOne 取代 (sequelize mock not support findByPK) + mockModel.findByPk = (id) => mockModel.findOne({where: {id: id}}) + // 將 count 的 function 預設回傳假資料數目 1 + mockModel.count = () => 1 + // 因為 mock 中的 create 有問題,因此指向 upsert function, 這樣可以在 useHandler 中取得 create 呼叫 + mockModel.create = mockModel.upsert + + // modify middleware + if (joinedTableName) { + mockModel.$queryInterface.$useHandler((query, queryOptions) => { + if (query === 'upsert') { + // 新增 joinTable 資料到模擬資料 + const {UserId, RestaurantId} = queryOptions[0]; + const restaurant = data.find(d => d.id === RestaurantId) + restaurant[joinedTableName].push({UserId: UserId}); + return Promise.resolve(data.map(d => mockModel.build(d))) + } else if (query === 'findAll') { + // 回傳模擬資料 + return Promise.resolve(data.map(d => mockModel.build(d))) + }else if (query === 'destroy') { + // destroy 可以從 where 取得要刪除的資料 + // 因此就可以模擬將模擬資料中的資料刪除 + // 刪除模擬資料中的某一筆 joinTable 資料 + const {UserId, RestaurantId} = queryOptions[0].where; + const restaurant = data.find(d => d.id === RestaurantId) + restaurant[joinedTableName] = restaurant[joinedTableName].filter(d => !(d.UserId === UserId)) + return Promise.resolve(data.map(d => mockModel.build(d))) + } + }); + } else { + mockModel.$queryInterface.$useHandler((query, queryOptions,done) => { + if (query === 'upsert') { + // create 時會帶 userId 跟 restaurantId (ex: Like.create({ userId: 1, restaurantId: 2})) + const {UserId, RestaurantId} = queryOptions[0] + + // 新增這個 Like 的資訊到模擬資料裡 + data.push({ UserId, RestaurantId }) + + // 回傳模擬資料 + return Promise.resolve(mockModel.build(data)) + } else if (query === 'findAll') { + // 回傳模擬資料 + return Promise.resolve(data.map(d => mockModel.build(d))) + } else if (query === 'destroy') { + // destroy 可以從 where 取得要刪除的資料 + // 因此就可以模擬將模擬資料中的資料刪除 + const {UserId, RestaurantId} = queryOptions[0].where + data = data.filter(d => !(d.UserId === UserId && d.RestaurantId === RestaurantId)) + + return Promise.resolve(mockModel.build(data)) + } + }); + } + + return mockModel; +} + +const createControllerProxy = (path, model) => { + const controller = proxyquire(path, { + '../models': model + }); + + return controller; +} + +module.exports = { + createModelMock, + createControllerProxy +} \ No newline at end of file diff --git a/tests/A17.test.js b/tests/A17.test.js index 03a6b21e..3f0e633e 100644 --- a/tests/A17.test.js +++ b/tests/A17.test.js @@ -2,13 +2,10 @@ const chai = require('chai') const request = require('supertest') const sinon = require('sinon') const should = chai.should() -const SequelizeMock = require('sequelize-mock') -const proxyquire = require('proxyquire') - -const dbMock = new SequelizeMock() const app = require('../../app') const { classToInvokable } = require('sequelize/types/lib/utils') +const { createModelMock, createControllerProxy } = require('../helpers/unitTestHelpers'); const mockRequest = (query) => { return { @@ -64,20 +61,15 @@ describe('# A17', () => { before(() => { // 製作假資料 // 下個 context 會用這筆資料進行測試 - this.UserMock = dbMock.define('User', { + this.UserMock = createModelMock('User', { id: 1, email: 'root@example.com', name: 'admin', isAdmin: false, }) - // 模擬 Sequelize 行為 - // 將 mock user db 中的 findByPK 用 findOne 取代 (sequelize mock not support findByPK) - this.UserMock.findByPk = (id) => - this.UserMock.findOne({ where: { id: id } }) + // 將 adminController 中的 User db 取代成 User mock db - this.adminController = proxyquire('../../controllers/adminController', { - '../models': { User: this.UserMock }, - }) + this.adminController = createControllerProxy('../../controllers/adminController', { User: this.UserMock }) }) context('# [顯示使用者清單]', () => { @@ -100,22 +92,18 @@ describe('# A17', () => { before(() => { // 製作假資料 // 本 context 會用這筆資料進行測試 - this.UserMock = dbMock.define('User', { - id: 1, - email: 'root@example.com', - name: 'admin', - isAdmin: true, // 是管理者 - }) - // 模擬 Sequelize 行為 - // 將 mock user db 中的 findByPK 用 findOne 取代 (sequelize mock not support findByPK) - // 將 count 的 function 預設回傳假資料數目 1 - this.UserMock.count = () => 1 - this.UserMock.findByPk = (id) => - this.UserMock.findOne({ where: { id: id } }) + this.UserMock = createModelMock( + 'User', + { + id: 1, + email: 'root@example.com', + name: 'admin', + isAdmin: true, // 是管理者 + } + ) + // 將 adminController 中的 User db 取代成 User mock db - this.adminController = proxyquire('../../controllers/adminController', { - '../models': { User: this.UserMock }, - }) + this.adminController = createControllerProxy('../../controllers/adminController', { User: this.UserMock }) }) it(' PUT /admin/users/:id/toggleAdmin ', async () => { @@ -137,34 +125,19 @@ describe('# A17', () => { context('# [修改使用者權限] for user', () => { before(() => { - // 製作假資料 - // 本 context 會用這筆資料進行測試 - this.UserMock = dbMock.define( + // 製作假資料 + // 本 context 會用這筆資料進行測試 + this.UserMock = createModelMock( 'User', { id: 1, email: 'user@example.com', name: 'user', isAdmin: false, // 非管理者 - }, - { - instanceMethods: { - // 模擬一個會改變 admin 權限的函式 - update: (changes) => { - this.UserMock._defaults = { ...changes } - return Promise.resolve() - }, - }, } ) - // 模擬 Sequelize 行為 - this.UserMock.count = () => 1 - this.UserMock.findByPk = (id) => - this.UserMock.findOne({ where: { id: id } }) - - this.adminController = proxyquire('../../controllers/adminController', { - '../models': { User: this.UserMock }, - }) + // 將 adminController 中的 User db 取代成 User mock db + this.adminController = createControllerProxy('../../controllers/adminController', { User: this.UserMock }) }) it(' PUT /admin/users/:id/toggleAdmin ', async (done) => { diff --git a/tests/A19.test.js b/tests/A19.test.js index 5b2b8f29..d5caf3fd 100644 --- a/tests/A19.test.js +++ b/tests/A19.test.js @@ -3,14 +3,7 @@ const request = require('supertest') const sinon = require('sinon') const should = chai.should() -const app = require('../../app') -const routes = require('../../routes/index') -const db = require('../../models') -const helpers = require('../../_helpers') -const SequelizeMock = require('sequelize-mock') -const proxyquire = require('proxyquire') - -const dbMock = new SequelizeMock() +const { createModelMock, createControllerProxy } = require('../helpers/unitTestHelpers'); const mockRequest = (query) => { return { @@ -35,20 +28,15 @@ describe('# A19', () => { this.getUser = sinon.stub(helpers, 'getUser').returns({ id: 1 }) // 製作假資料 // 本 context 會用這筆資料進行測試 - this.UserMock = dbMock.define('User', { + this.UserMock = createModelMock('User', { id: 1, email: 'root@example.com', name: 'admin', isAdmin: false, }) - // 模擬 Sequelize 行為 - // 將 mock user db 中的 findByPK 用 findOne 取代 (sequelize mock not support findByPK) - this.UserMock.findByPk = (id) => - this.UserMock.findOne({ where: { id: id } }) + // 將 userController 中的 User db 取代成 User mock db - this.userController = proxyquire('../../controllers/userController', { - '../models': { User: this.UserMock }, - }) + this.userController = createControllerProxy('../../controllers/userController', { User: this.UserMock }) }) it(' GET /users/:id ', async () => { @@ -83,21 +71,15 @@ describe('# A19', () => { // 製作假資料 // 本 context 會用這筆資料進行測試 - this.UserMock = dbMock.define('User', { + this.UserMock = createModelMock('User', { id: 1, email: 'root@example.com', name: 'admin', isAdmin: false, }) - // 模擬 Sequelize 行為 - // 將 mock user db 中的 findByPK 用 findOne 取代 (sequelize mock not support findByPK) - this.UserMock.findByPk = (id) => - this.UserMock.findOne({ where: { id: id } }) // 將 userController 中的 User db 取代成 User mock db - this.userController = proxyquire('../../controllers/userController', { - '../models': { User: this.UserMock }, - }) + this.userController = createControllerProxy('../../controllers/userController', { User: this.UserMock }) }) it(' GET /users/:id/edit ', async () => { @@ -131,32 +113,18 @@ describe('# A19', () => { this.getUser = sinon.stub(helpers, 'getUser').returns({ id: 1 }) // 製作假資料 // 本 context 會用這筆資料進行測試 - this.UserMock = dbMock.define( + this.UserMock = createModelMock( 'User', { id: 1, email: 'root@example.com', name: 'admin', isAdmin: false, - }, - { - instanceMethods: { - // 模擬一個會改變 admin 權限的函式 - update: (changes) => { - this.UserMock._defaults = { ...changes } - return Promise.resolve() - }, - }, } ) - // 模擬 Sequelize 行為 - // 將 mock user db 中的 findByPK 用 findOne 取代 (sequelize mock not support findByPK) - this.UserMock.findByPk = (id) => - this.UserMock.findOne({ where: { id: id } }) + // 將 userController 中的 User db 取代成 User mock db - this.userController = proxyquire('../../controllers/userController', { - '../models': { User: this.UserMock }, - }) + this.userController = createControllerProxy('../../controllers/userController', { User: this.UserMock }) }) it(' PUT /users/:id ', async () => { diff --git a/tests/A20.test.js b/tests/A20.test.js index 3f922f0b..5fd74c83 100644 --- a/tests/A20.test.js +++ b/tests/A20.test.js @@ -4,10 +4,7 @@ const sinon = require('sinon') const should = chai.should() const helpers = require('../_helpers') -const SequelizeMock = require('sequelize-mock') -const proxyquire = require('proxyquire') - -const dbMock = new SequelizeMock() +const { createModelMock, createControllerProxy } = require('../helpers/unitTestHelpers'); const mockRequest = (query) => { return { @@ -27,39 +24,31 @@ describe('# A20: 餐廳資訊整理:Dashboard', function () { before(async () => { // 製作假資料 // 本 context 會用這筆資料進行測試 - this.UserMock = dbMock.define('User', { + this.UserMock = createModelMock('User', { id: 1, email: 'root@example.com', name: 'admin', isAdmin: false, }) - this.RestaurantMock = dbMock.define('Restaurant', { + this.RestaurantMock = createModelMock('Restaurant', { id: 1, - name: '銷魂麵', + name: '銷魂麵' }) - this.CategoryMock = dbMock.define('Category', { + this.CategoryMock = createModelMock('Category', { id: 1, - name: '食物', + name: '食物' }) - this.CommentMock = dbMock.define('Comment', { + this.CommentMock = createModelMock('Comment', { id: 1, - text: 'gogogo', + text: "gogogo" }) - // 模擬 Sequelize 行為 - // 將 mock user db 中的 findByPK 用 findOne 取代 (sequelize mock not support findByPK) - this.RestaurantMock.findByPk = (id) => - this.RestaurantMock.findOne({ where: { id: id } }) - // 將 count 的 function 預設回傳假資料數目 1 - this.CommentMock.count = () => 1 // 將 restController 中的 User,Category,Restaurant,Comment 都用模擬資料取代 - this.restController = proxyquire('../controllers/restController', { - '../models': { - User: this.UserMock, - Category: this.CategoryMock, - Restaurant: this.RestaurantMock, - Comment: this.CommentMock, - }, + this.restController = createControllerProxy('../controllers/restController', { + User: this.UserMock, + Category: this.CategoryMock, + Restaurant: this.RestaurantMock, + Comment: this.CommentMock, }) }) diff --git a/tests/A21.test.js b/tests/A21.test.js index b2a1f83e..6e7df3d9 100644 --- a/tests/A21.test.js +++ b/tests/A21.test.js @@ -5,10 +5,7 @@ const should = chai.should() const db = require('../models') const helpers = require('../_helpers') -const SequelizeMock = require('sequelize-mock') -const proxyquire = require('proxyquire') - -const dbMock = new SequelizeMock({ autoQueryFallback: false }) +const { createModelMock, createControllerProxy } = require('../helpers/unitTestHelpers') const mockRequest = (query) => { return { @@ -43,30 +40,9 @@ describe('# A21: Like / Unlike', function () { // 建立了一個模擬的 Like table,裡面目前是空的 // 模擬 Sequelize 行為 this.mockLikeData = [] - this.likeMock = dbMock.define('Like') - // 因為 mock 中的 create 有問題,因此指向 upsert function, 這樣可以在 useHandler 中取得 create 呼叫 - this.likeMock.create = this.likeMock.upsert - - // 模擬 Like.create and Like.findall 的 function - this.likeMock.$queryInterface.$useHandler((query, queryOptions, done) => { - if (query === 'upsert') { - // create 時會帶 userId 跟 restaurantId (ex: Like.create({ userId: 1, restaurantId: 2})) - const { userId, restaurantId } = queryOptions[0] - - // 新增這個 Like 的資訊到模擬資料裡 - this.mockLikeData.push({ userId, restaurantId }) + this.likeMock = createModelMock('Like', null, this.mockLikeData) - // 回傳模擬資料 - return Promise.resolve(this.likeMock.build(this.mockLikeData)) - } else if (query === 'findAll') { - // 回傳模擬資料 - return Promise.resolve(this.mockLikeData) - } - }) - - this.userController = proxyquire('../controllers/userController', { - '../models': { Like: this.likeMock }, - }) + this.userController = createControllerProxy('../controllers/userController', {Like: this.likeMock}) }) it(' POST /like/:restaurantId ', async () => { @@ -99,31 +75,13 @@ describe('# A21: Like / Unlike', function () { // 製作假資料 // 下個 context 會用這筆資料進行測試 // 模擬 Like table 裡目前有 1 筆資料如下 - this.likeMock = dbMock.define('Like', { + this.likeMock = createModelMock('Like', { id: 1, - userId: 1, - restaurantId: 2, - }) - // 模擬 Sequelize 行為 - // 模擬 Like.destroy and Like.finall 的 function - this.likeMock.$queryInterface.$useHandler((query, queryOptions, done) => { - if (query === 'destroy') { - const { userId, restaurantId } = queryOptions[0].where - // destroy 可以從 where 取得要刪除的資料 - // 因此就可以模擬將模擬資料中的資料刪除 - mockLikeData = mockLikeData.filter( - (d) => !(d.userId === userId && d.restaurantId === restaurantId) - ) - - return Promise.resolve(this.likeMock.build(mockLikeData)) - } else if (query === 'findAll') { - return Promise.resolve(mockLikeData) - } - }) + UserId: 1, + RestaurantId: 2, + }, mockLikeData); - this.userController = proxyquire('../controllers/userController', { - '../models': { Like: this.likeMock }, - }) + this.userController = createControllerProxy('../controllers/userController', { Like: this.likeMock }) }) it(' DELETE /like/:restaurantId ', async () => { diff --git a/tests/A22.test.js b/tests/A22.test.js index 4d379460..86cd3734 100644 --- a/tests/A22.test.js +++ b/tests/A22.test.js @@ -5,10 +5,7 @@ const should = chai.should() const app = require('../app') const helpers = require('../_helpers') -const SequelizeMock = require('sequelize-mock') -const proxyquire = require('proxyquire') - -const dbMock = new SequelizeMock({ autoQueryFallback: false }) +const { createModelMock, createControllerProxy } = require('../helpers/unitTestHelpers') const mockRequest = (query) => { return { @@ -95,61 +92,20 @@ describe('# A22: TOP 10 人氣餐廳 ', function () { .stub(helpers, 'getUser') .returns({ id: 1, followings: [], favoritedRestaurants: [] }) - // 建立了一個模擬的 Restaurant table,裡面放入 2 間餐廳資料 - // 模擬 Sequelize 行為 - this.restaurantMock = dbMock.define('Restaurant') - this.restaurantMock.$queryInterface.$useHandler( - (query, queryOptions, done) => { - if (query === 'findAll') { - return Promise.resolve( - mockRestaurantData.map((d) => this.restaurantMock.build(d)) - ) - } - } - ) + // 建立了一個模擬的 Restaurant table,裡面放入 2 間餐廳資料 + // 模擬 Sequelize 行為 + this.restaurantMock = createModelMock('Restaurant', null, mockRestaurantData) // 將 restController 中的 Restaurant db 取代成 Restaurant mock db - this.restController = proxyquire('../controllers/restController', { - '../models': { - Restaurant: this.restaurantMock, - }, + this.restController = createControllerProxy('../controllers/restController', { + Restaurant: this.restaurantMock, }) // 建立了一個模擬的 Favorite table,裡面有 1 筆資料 - this.favoriteMock = dbMock.define('Favorite') - this.favoriteMock.create = this.favoriteMock.upsert - this.favoriteMock.$queryInterface.$useHandler( - (query, queryOptions, done) => { - if (query === 'upsert') { - // 新增 favortie 資料到模擬資料 - const { userId, restaurantId } = queryOptions[0] - const restaurant = mockRestaurantData.find( - (d) => d.id === restaurantId - ) - restaurant.favoritedUsers.push({ userId: userId }) - return Promise.resolve( - mockRestaurantData.map((d) => this.restaurantMock.build(d)) - ) - } else if (query === 'destroy') { - // 刪除模擬資料中的某一筆 favortie 資料 - const { userId, restaurantId } = queryOptions[0].where - const restaurant = mockRestaurantData.find( - (d) => d.id === restaurantId - ) - restaurant.favoritedUsers = restaurant.favoritedUsers.filter( - (d) => !(d.userId === userId) - ) - return Promise.resolve( - mockRestaurantData.map((d) => this.restaurantMock.build(d)) - ) - } - } - ) + this.favoriteMock = createModelMock('Favorite', null, mockRestaurantData, 'FavoritedUsers') // 將 userController 中的 Favorite db 取代成 Favorite mock db - this.userController = proxyquire('../controllers/userController', { - '../models': { Favorite: this.favoriteMock }, - }) + this.userController = createControllerProxy('../controllers/userController', {Favorite: this.favoriteMock}) }) it(' POST favorite ', async () => { From c9b201e0bdb860c4b9f00692844311824fa0e789 Mon Sep 17 00:00:00 2001 From: Stanney Date: Fri, 29 Oct 2021 00:06:56 +0800 Subject: [PATCH 016/135] remove n_comments check due to follow model answer --- tests/A20.test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/A20.test.js b/tests/A20.test.js index 5fd74c83..aa78d28f 100644 --- a/tests/A20.test.js +++ b/tests/A20.test.js @@ -64,7 +64,6 @@ describe('# A20: 餐廳資訊整理:Dashboard', function () { // res.render 的第 2 個參數要包含 restaurant,其 name 屬性的值應是 '銷魂麵' res.render.getCall(0).args[0].should.equal('dashboard') res.render.getCall(0).args[1].restaurant.name.should.equal('銷魂麵') - res.render.getCall(0).args[1].n_comments.should.equal(1) // question** }) }) }) From 50476ab9b1f242ebee3f85e7774198c2a53eddae Mon Sep 17 00:00:00 2001 From: Carrot7712 Date: Fri, 29 Oct 2021 03:08:25 +0800 Subject: [PATCH 017/135] revise comments --- config/config.json | 2 +- tests/A17.test.js | 8 +++++--- tests/A19.test.js | 11 +++++++---- tests/A20.test.js | 2 +- tests/A21.test.js | 5 +++-- tests/A22.test.js | 5 ++--- 6 files changed, 19 insertions(+), 14 deletions(-) diff --git a/config/config.json b/config/config.json index bfb32f98..56636a1c 100644 --- a/config/config.json +++ b/config/config.json @@ -1,7 +1,7 @@ { "development": { "username": "root", - "password": "", + "password": "password", "database": "forum", "host": "127.0.0.1", "dialect": "mysql" diff --git a/tests/A17.test.js b/tests/A17.test.js index 3f0e633e..6065446e 100644 --- a/tests/A17.test.js +++ b/tests/A17.test.js @@ -58,9 +58,10 @@ describe('# A17', () => { }); describe('# A17: 使用者權限管理', function () { + // 前置準備 before(() => { // 製作假資料 - // 下個 context 會用這筆資料進行測試 + // 本 context 會用這筆資料進行測試 this.UserMock = createModelMock('User', { id: 1, email: 'root@example.com', @@ -68,10 +69,11 @@ describe('# A17', () => { isAdmin: false, }) - // 將 adminController 中的 User db 取代成 User mock db + // 修改 adminController 中的資料庫連線設定,由連向真實的資料庫 -> 改為連向模擬的 User table this.adminController = createControllerProxy('../../controllers/adminController', { User: this.UserMock }) }) - + + // 開始測試 context('# [顯示使用者清單]', () => { it(' GET /admin/users ', async () => { // 模擬 request & response diff --git a/tests/A19.test.js b/tests/A19.test.js index d5caf3fd..228aafad 100644 --- a/tests/A19.test.js +++ b/tests/A19.test.js @@ -20,6 +20,7 @@ const mockResponse = () => { describe('# A19', () => { describe('# A19: 建立 User Profile', function () { context('# [瀏覽 Profile]', () => { + // 前置準備 before(() => { // 模擬登入驗證 this.ensureAuthenticated = sinon @@ -35,10 +36,11 @@ describe('# A19', () => { isAdmin: false, }) - // 將 userController 中的 User db 取代成 User mock db + // 修改 userController 中的資料庫連線設定,由連向真實的資料庫 -> 改為連向模擬的 User table this.userController = createControllerProxy('../../controllers/userController', { User: this.UserMock }) }) + // 開始測試 it(' GET /users/:id ', async () => { // 模擬 request & response const req = mockRequest({ params: { id: 1 } }) // 帶入 params.id = 1,對 GET /users/1 發出請求 @@ -53,7 +55,8 @@ describe('# A19', () => { res.render.getCall(0).args[0].should.equal('profile') res.render.getCall(0).args[1].user.name.should.equal('admin') }) - + + // 測試完畢,清除資料 after(async () => { // 清除模擬驗證資料 this.ensureAuthenticated.restore() @@ -78,7 +81,7 @@ describe('# A19', () => { isAdmin: false, }) - // 將 userController 中的 User db 取代成 User mock db + // 連向模擬的 User table this.userController = createControllerProxy('../../controllers/userController', { User: this.UserMock }) }) @@ -123,7 +126,7 @@ describe('# A19', () => { } ) - // 將 userController 中的 User db 取代成 User mock db + // 連向模擬的 User table this.userController = createControllerProxy('../../controllers/userController', { User: this.UserMock }) }) diff --git a/tests/A20.test.js b/tests/A20.test.js index aa78d28f..42b5806a 100644 --- a/tests/A20.test.js +++ b/tests/A20.test.js @@ -43,7 +43,7 @@ describe('# A20: 餐廳資訊整理:Dashboard', function () { text: "gogogo" }) - // 將 restController 中的 User,Category,Restaurant,Comment 都用模擬資料取代 + // 連向模擬的 tables this.restController = createControllerProxy('../controllers/restController', { User: this.UserMock, Category: this.CategoryMock, diff --git a/tests/A21.test.js b/tests/A21.test.js index 6e7df3d9..8005a71b 100644 --- a/tests/A21.test.js +++ b/tests/A21.test.js @@ -38,10 +38,10 @@ describe('# A21: Like / Unlike', function () { this.getUser = sinon.stub(helpers, 'getUser').returns({ id: 1 }) // 建立了一個模擬的 Like table,裡面目前是空的 - // 模擬 Sequelize 行為 this.mockLikeData = [] this.likeMock = createModelMock('Like', null, this.mockLikeData) - + + // 連向模擬的 Like table this.userController = createControllerProxy('../controllers/userController', {Like: this.likeMock}) }) @@ -81,6 +81,7 @@ describe('# A21: Like / Unlike', function () { RestaurantId: 2, }, mockLikeData); + // 連向模擬的 Like table this.userController = createControllerProxy('../controllers/userController', { Like: this.likeMock }) }) diff --git a/tests/A22.test.js b/tests/A22.test.js index 86cd3734..793e6996 100644 --- a/tests/A22.test.js +++ b/tests/A22.test.js @@ -93,10 +93,9 @@ describe('# A22: TOP 10 人氣餐廳 ', function () { .returns({ id: 1, followings: [], favoritedRestaurants: [] }) // 建立了一個模擬的 Restaurant table,裡面放入 2 間餐廳資料 - // 模擬 Sequelize 行為 this.restaurantMock = createModelMock('Restaurant', null, mockRestaurantData) - // 將 restController 中的 Restaurant db 取代成 Restaurant mock db + // 連向模擬的 Restaurant table this.restController = createControllerProxy('../controllers/restController', { Restaurant: this.restaurantMock, }) @@ -104,7 +103,7 @@ describe('# A22: TOP 10 人氣餐廳 ', function () { // 建立了一個模擬的 Favorite table,裡面有 1 筆資料 this.favoriteMock = createModelMock('Favorite', null, mockRestaurantData, 'FavoritedUsers') - // 將 userController 中的 Favorite db 取代成 Favorite mock db + // 連向模擬的 Favorite table this.userController = createControllerProxy('../controllers/userController', {Favorite: this.favoriteMock}) }) From b3ddfcdbcb25410a54aad1f00131dbcf2437eee8 Mon Sep 17 00:00:00 2001 From: Stanney Date: Sat, 30 Oct 2021 00:01:32 +0800 Subject: [PATCH 018/135] add A21 test userId and restaurantId with addLike function --- tests/A21.test.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/A21.test.js b/tests/A21.test.js index 8005a71b..ee638370 100644 --- a/tests/A21.test.js +++ b/tests/A21.test.js @@ -47,7 +47,7 @@ describe('# A21: Like / Unlike', function () { it(' POST /like/:restaurantId ', async () => { // 模擬 request & response - const req = mockRequest({ params: { id: 1, restaurantId: 2 } }) // 帶入 params.id = 1,對 POST /like/2 發出請求 + const req = mockRequest({ params: { restaurantId: 2 } }) // 帶入 params.restaurantId = 2,對 POST /like/2 發出請求 const res = mockResponse() // 測試 userController.addLike 函式 @@ -56,6 +56,10 @@ describe('# A21: Like / Unlike', function () { const likes = await this.likeMock.findAll() // addLike 執行完畢後,Like table 應會從空的 -> 變成有 1 筆資料 likes.should.have.lengthOf(1) + // 資料裡的 UserId 應該會跟我們傳入的 user id 一樣 + likes[0].UserId.should.equal(1) + // 資料裡的 RestaurantId 會跟我們傳入的 params.restaurantId 一樣 + likes[0].RestaurantId.should.equal(2) }) after(async () => { From 6c5f774a8a66577c1e49751696d6a05d14a0262c Mon Sep 17 00:00:00 2001 From: Stanney Date: Sat, 30 Oct 2021 00:13:36 +0800 Subject: [PATCH 019/135] add viewCounts check in A20 --- tests/A20.test.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/A20.test.js b/tests/A20.test.js index 42b5806a..53f44d72 100644 --- a/tests/A20.test.js +++ b/tests/A20.test.js @@ -32,7 +32,8 @@ describe('# A20: 餐廳資訊整理:Dashboard', function () { }) this.RestaurantMock = createModelMock('Restaurant', { id: 1, - name: '銷魂麵' + name: '銷魂麵', + viewCounts: 3 }) this.CategoryMock = createModelMock('Category', { id: 1, @@ -64,6 +65,7 @@ describe('# A20: 餐廳資訊整理:Dashboard', function () { // res.render 的第 2 個參數要包含 restaurant,其 name 屬性的值應是 '銷魂麵' res.render.getCall(0).args[0].should.equal('dashboard') res.render.getCall(0).args[1].restaurant.name.should.equal('銷魂麵') + res.render.getCall(0).args[1].restaurant.viewCounts.should.equal(3) }) }) }) From 2ad4b59c4151c60300079f7143e49836ce1684e2 Mon Sep 17 00:00:00 2001 From: Stanney Date: Sat, 30 Oct 2021 00:17:26 +0800 Subject: [PATCH 020/135] add new test comment --- tests/A20.test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/A20.test.js b/tests/A20.test.js index 53f44d72..a832e034 100644 --- a/tests/A20.test.js +++ b/tests/A20.test.js @@ -63,6 +63,7 @@ describe('# A20: 餐廳資訊整理:Dashboard', function () { // getDashBoard 執行完畢後,應呼叫 res.render // res.render 的第 1 個參數要是 'dashboard' // res.render 的第 2 個參數要包含 restaurant,其 name 屬性的值應是 '銷魂麵' + // res.render 的地 3 個參數要包含 restaurant,其 viewCounts 值應該是 3 res.render.getCall(0).args[0].should.equal('dashboard') res.render.getCall(0).args[1].restaurant.name.should.equal('銷魂麵') res.render.getCall(0).args[1].restaurant.viewCounts.should.equal(3) From a2df6a46bdc38176dacc8cee1a2e28783fd9af53 Mon Sep 17 00:00:00 2001 From: Amber Yan Date: Sun, 31 Oct 2021 13:04:23 +0800 Subject: [PATCH 021/135] remove other test and rename A17 -> R01 --- tests/A19.test.js | 164 ----------------------------- tests/A20.test.js | 72 ------------- tests/A21.test.js | 113 -------------------- tests/A22.test.js | 158 --------------------------- tests/{A17.test.js => R01.test.js} | 4 +- 5 files changed, 2 insertions(+), 509 deletions(-) delete mode 100644 tests/A19.test.js delete mode 100644 tests/A20.test.js delete mode 100644 tests/A21.test.js delete mode 100644 tests/A22.test.js rename tests/{A17.test.js => R01.test.js} (98%) diff --git a/tests/A19.test.js b/tests/A19.test.js deleted file mode 100644 index 228aafad..00000000 --- a/tests/A19.test.js +++ /dev/null @@ -1,164 +0,0 @@ -const chai = require('chai') -const request = require('supertest') -const sinon = require('sinon') -const should = chai.should() - -const { createModelMock, createControllerProxy } = require('../helpers/unitTestHelpers'); - -const mockRequest = (query) => { - return { - ...query, - flash: sinon.spy(), - } -} -const mockResponse = () => { - return { - redirect: sinon.spy(), - render: sinon.spy(), - } -} -describe('# A19', () => { - describe('# A19: 建立 User Profile', function () { - context('# [瀏覽 Profile]', () => { - // 前置準備 - before(() => { - // 模擬登入驗證 - this.ensureAuthenticated = sinon - .stub(helpers, 'ensureAuthenticated') - .returns(true) - this.getUser = sinon.stub(helpers, 'getUser').returns({ id: 1 }) - // 製作假資料 - // 本 context 會用這筆資料進行測試 - this.UserMock = createModelMock('User', { - id: 1, - email: 'root@example.com', - name: 'admin', - isAdmin: false, - }) - - // 修改 userController 中的資料庫連線設定,由連向真實的資料庫 -> 改為連向模擬的 User table - this.userController = createControllerProxy('../../controllers/userController', { User: this.UserMock }) - }) - - // 開始測試 - it(' GET /users/:id ', async () => { - // 模擬 request & response - const req = mockRequest({ params: { id: 1 } }) // 帶入 params.id = 1,對 GET /users/1 發出請求 - const res = mockResponse() - - // 測試作業指定的 userController.getUser 函式 - await this.userController.getUser(req, res) - - // toggleAdmin 執行完畢後,應呼叫 res.render - // res.render 的第 1 個參數要是 'profile' - // res.render 的第 2 個參數要是 user,其 name 屬性的值應是 'admin' - res.render.getCall(0).args[0].should.equal('profile') - res.render.getCall(0).args[1].user.name.should.equal('admin') - }) - - // 測試完畢,清除資料 - after(async () => { - // 清除模擬驗證資料 - this.ensureAuthenticated.restore() - this.getUser.restore() - }) - }) - - context('# [瀏覽編輯 Profile 頁面]', () => { - before(() => { - // 模擬登入驗證 - this.ensureAuthenticated = sinon - .stub(helpers, 'ensureAuthenticated') - .returns(true) - this.getUser = sinon.stub(helpers, 'getUser').returns({ id: 1 }) - - // 製作假資料 - // 本 context 會用這筆資料進行測試 - this.UserMock = createModelMock('User', { - id: 1, - email: 'root@example.com', - name: 'admin', - isAdmin: false, - }) - - // 連向模擬的 User table - this.userController = createControllerProxy('../../controllers/userController', { User: this.UserMock }) - }) - - it(' GET /users/:id/edit ', async () => { - // 模擬 request & response - const req = mockRequest({ params: { id: 1 } }) // 帶入 params.id = 1,對 GET /users/1/edit 發出請求 - const res = mockResponse() - - // 測試作業指定的 adminController.editUser 函式 - await this.userController.editUser(req, res) - - // editUser 執行完畢後,應呼叫 res.render - // res.render 的第 1 個參數要是 'edit' - // res.render 的第 2 個參數要是 user,其 name 屬性的值應是 'admin' - res.render.getCall(0).args[0].should.equal('edit') - res.render.getCall(0).args[1].user.name.should.equal('admin') - }) - - after(async () => { - // 清除模擬驗證資料 - this.ensureAuthenticated.restore() - this.getUser.restore() - }) - }) - - context('# [編輯 Profile]', () => { - before(async () => { - // 模擬登入驗證 - this.ensureAuthenticated = sinon - .stub(helpers, 'ensureAuthenticated') - .returns(true) - this.getUser = sinon.stub(helpers, 'getUser').returns({ id: 1 }) - // 製作假資料 - // 本 context 會用這筆資料進行測試 - this.UserMock = createModelMock( - 'User', - { - id: 1, - email: 'root@example.com', - name: 'admin', - isAdmin: false, - } - ) - - // 連向模擬的 User table - this.userController = createControllerProxy('../../controllers/userController', { User: this.UserMock }) - }) - - it(' PUT /users/:id ', async () => { - // 模擬 request & response - // 對 PUT /users/1 發出 request,並夾帶 body.name = amdin2, body.email = admin_test@gmail.com - const req = mockRequest({ - params: { id: 1 }, - body: { name: 'admin2', email: 'admin_test@gmail.com' }, - }) - const res = mockResponse() - - // 測試作業指定的 userController.putUser 函式 - await this.userController.putUser(req, res) - - // putUser 正確執行的話,應呼叫 req.flash - // req.flash 的參數應與下列字串一致 - req.flash.calledWith('success_messages','使用者資料編輯成功').should.be.true - // putUser 執行完畢後,應呼叫 res.redirect 並重新導向 /users/1 - res.redirect.calledWith('/users/1').should.be.true - // putUser 執行完畢後,id:1 使用者的 name 和 email 應該已被修改 - // 將假資料撈出,比對確認有成功修改到 - const user = await this.UserMock.findOne({ where: { id: 1 } }) - user.name.should.equal('admin2') - user.email.should.equal('admin_test@gmail.com') - }) - - after(async () => { - // 清除模擬驗證資料 - this.ensureAuthenticated.restore() - this.getUser.restore() - }) - }) - }) -}) diff --git a/tests/A20.test.js b/tests/A20.test.js deleted file mode 100644 index a832e034..00000000 --- a/tests/A20.test.js +++ /dev/null @@ -1,72 +0,0 @@ -const chai = require('chai') -const request = require('supertest') -const sinon = require('sinon') -const should = chai.should() - -const helpers = require('../_helpers') -const { createModelMock, createControllerProxy } = require('../helpers/unitTestHelpers'); - -const mockRequest = (query) => { - return { - ...query, - flash: sinon.spy(), - } -} -const mockResponse = () => { - return { - redirect: sinon.spy(), - render: sinon.spy(), - } -} - -describe('# A20: 餐廳資訊整理:Dashboard', function () { - context('# [Q1: Dashboard - 1 - controller / view / route]', () => { - before(async () => { - // 製作假資料 - // 本 context 會用這筆資料進行測試 - this.UserMock = createModelMock('User', { - id: 1, - email: 'root@example.com', - name: 'admin', - isAdmin: false, - }) - this.RestaurantMock = createModelMock('Restaurant', { - id: 1, - name: '銷魂麵', - viewCounts: 3 - }) - this.CategoryMock = createModelMock('Category', { - id: 1, - name: '食物' - }) - this.CommentMock = createModelMock('Comment', { - id: 1, - text: "gogogo" - }) - - // 連向模擬的 tables - this.restController = createControllerProxy('../controllers/restController', { - User: this.UserMock, - Category: this.CategoryMock, - Restaurant: this.RestaurantMock, - Comment: this.CommentMock, - }) - }) - - it(' GET /restaurants/:id/dashboard ', async () => { - // 模擬 request & response - const req = mockRequest({ params: { id: 1 } }) // 帶入 params.id = 1,對 GET /restaurants/1/dashboard 發出請求 - const res = mockResponse() - // 測試 restController.getDashBoard 函式 - await this.restController.getDashBoard(req, res) - - // getDashBoard 執行完畢後,應呼叫 res.render - // res.render 的第 1 個參數要是 'dashboard' - // res.render 的第 2 個參數要包含 restaurant,其 name 屬性的值應是 '銷魂麵' - // res.render 的地 3 個參數要包含 restaurant,其 viewCounts 值應該是 3 - res.render.getCall(0).args[0].should.equal('dashboard') - res.render.getCall(0).args[1].restaurant.name.should.equal('銷魂麵') - res.render.getCall(0).args[1].restaurant.viewCounts.should.equal(3) - }) - }) -}) diff --git a/tests/A21.test.js b/tests/A21.test.js deleted file mode 100644 index ee638370..00000000 --- a/tests/A21.test.js +++ /dev/null @@ -1,113 +0,0 @@ -const chai = require('chai') -const request = require('supertest') -const sinon = require('sinon') -const should = chai.should() - -const db = require('../models') -const helpers = require('../_helpers') -const { createModelMock, createControllerProxy } = require('../helpers/unitTestHelpers') - -const mockRequest = (query) => { - return { - ...query, - flash: sinon.spy(), - } -} -const mockResponse = () => { - return { - redirect: sinon.spy(), - render: sinon.spy(), - } -} - -// 建立模擬的 Like 資料 -let mockLikeData = [ - { - userId: 1, - restaurantId: 2, - }, -] - -describe('# A21: Like / Unlike', function () { - context('# Q1: 使用者可以 Like 餐廳', () => { - before(() => { - // 模擬登入驗證 - this.ensureAuthenticated = sinon - .stub(helpers, 'ensureAuthenticated') - .returns(true) - this.getUser = sinon.stub(helpers, 'getUser').returns({ id: 1 }) - - // 建立了一個模擬的 Like table,裡面目前是空的 - this.mockLikeData = [] - this.likeMock = createModelMock('Like', null, this.mockLikeData) - - // 連向模擬的 Like table - this.userController = createControllerProxy('../controllers/userController', {Like: this.likeMock}) - }) - - it(' POST /like/:restaurantId ', async () => { - // 模擬 request & response - const req = mockRequest({ params: { restaurantId: 2 } }) // 帶入 params.restaurantId = 2,對 POST /like/2 發出請求 - const res = mockResponse() - - // 測試 userController.addLike 函式 - await this.userController.addLike(req, res) - // 將模擬的 Like table 內的資料全數撈出 - const likes = await this.likeMock.findAll() - // addLike 執行完畢後,Like table 應會從空的 -> 變成有 1 筆資料 - likes.should.have.lengthOf(1) - // 資料裡的 UserId 應該會跟我們傳入的 user id 一樣 - likes[0].UserId.should.equal(1) - // 資料裡的 RestaurantId 會跟我們傳入的 params.restaurantId 一樣 - likes[0].RestaurantId.should.equal(2) - }) - - after(async () => { - // 清除驗證資料 - this.ensureAuthenticated.restore() - this.getUser.restore() - }) - }) - - context('# Q1: 使用者可以 unLike 餐廳', () => { - before(() => { - // 模擬登入驗證 - this.ensureAuthenticated = sinon - .stub(helpers, 'ensureAuthenticated') - .returns(true) - this.getUser = sinon.stub(helpers, 'getUser').returns({ id: 1 }) - // 製作假資料 - // 下個 context 會用這筆資料進行測試 - // 模擬 Like table 裡目前有 1 筆資料如下 - this.likeMock = createModelMock('Like', { - id: 1, - UserId: 1, - RestaurantId: 2, - }, mockLikeData); - - // 連向模擬的 Like table - this.userController = createControllerProxy('../controllers/userController', { Like: this.likeMock }) - }) - - it(' DELETE /like/:restaurantId ', async () => { - // 模擬 request & response - // 模擬發出 request, 帶入 params.id = 1, restaurantId = 2 - const req = mockRequest({ params: { id: 1, restaurantId: 2 } }) // 帶入 params.id = 1,對 DELETE /like/2 發出請求 - const res = mockResponse() - - // 測試作業指定的 userController.removeLike 函式 - await this.userController.removeLike(req, res) - - // 將模擬的 Like table 內的資料全數撈出 - const likes = await this.likeMock.findAll() - // addLike 執行完畢後,Like table 應會從有 1 筆資料 -> 變成空的 - likes.should.have.lengthOf(0) - }) - - after(async () => { - // 清除模擬驗證資料 - this.ensureAuthenticated.restore() - this.getUser.restore() - }) - }) -}) diff --git a/tests/A22.test.js b/tests/A22.test.js deleted file mode 100644 index 793e6996..00000000 --- a/tests/A22.test.js +++ /dev/null @@ -1,158 +0,0 @@ -const chai = require('chai') -const request = require('supertest') -const sinon = require('sinon') -const should = chai.should() - -const app = require('../app') -const helpers = require('../_helpers') -const { createModelMock, createControllerProxy } = require('../helpers/unitTestHelpers') - -const mockRequest = (query) => { - return { - ...query, - flash: sinon.spy(), - } -} -const mockResponse = () => { - return { - redirect: sinon.spy(), - render: sinon.spy(), - } -} -// 模擬 2 間餐廳資料 -let mockRestaurantData = [ - { - id: 1, - name: 'Restaurant1', - tel: 'tel', - address: 'address', - opening_hours: 'opening_hours', - description: 'test description', - favoritedUsers: [ - { - userId: 1, - }, - ], - }, - { - id: 2, - name: 'Restaurant2', - tel: 'tel', - address: 'address', - opening_hours: 'opening_hours', - description: 'description', - categoryId: 1, - favoritedUsers: [], - }, -] - -describe('# A22: TOP 10 人氣餐廳 ', function () { - context('# [網址正確、畫面正常執行]', () => { - before(async () => { - // 模擬登入驗證 - this.ensureAuthenticated = sinon - .stub(helpers, 'ensureAuthenticated') - .returns(true) - // 模擬 getUser 函式,負責取得使用者資料 - this.getUser = sinon - .stub(helpers, 'getUser') - .returns({ id: 1, followings: [], favoritedRestaurants: [] }) - }) - - it(' GET /restaurants/top ', (done) => { - // 對 GET /restaurants/top 發出請求 - request(app) - .get('/restaurants/top') - .end(function (err, res) { - // 回應中應包含字串'Top 10 人氣餐廳' - // 若請求路徑正確,controller 執行後,會呼叫 res.render - // res.render 回傳的 view 樣板裡應包含字串'Top 10 人氣餐廳' - res.text.should.include('Top 10 人氣餐廳') - done() - }) - }) - - after(async () => { - // 清除模擬驗證資料 - this.ensureAuthenticated.restore() - this.getUser.restore() - }) - }) - - context( - '# [當你點擊畫面上的「加入最愛 / 移除最愛」按鈕時,會重新計算「收藏數」的數字]', - () => { - before(async () => { - // 模擬登入驗證 - this.ensureAuthenticated = sinon - .stub(helpers, 'ensureAuthenticated') - .returns(true) - // 模擬 getUser 函式,負責取得使用者資料 - this.getUser = sinon - .stub(helpers, 'getUser') - .returns({ id: 1, followings: [], favoritedRestaurants: [] }) - - // 建立了一個模擬的 Restaurant table,裡面放入 2 間餐廳資料 - this.restaurantMock = createModelMock('Restaurant', null, mockRestaurantData) - - // 連向模擬的 Restaurant table - this.restController = createControllerProxy('../controllers/restController', { - Restaurant: this.restaurantMock, - }) - - // 建立了一個模擬的 Favorite table,裡面有 1 筆資料 - this.favoriteMock = createModelMock('Favorite', null, mockRestaurantData, 'FavoritedUsers') - - // 連向模擬的 Favorite table - this.userController = createControllerProxy('../controllers/userController', {Favorite: this.favoriteMock}) - }) - - it(' POST favorite ', async () => { - // 模擬 request & response - // 對 POST /favorite/2 發出請求,夾帶 user.favoritedRestaurants - const req = mockRequest({ - user: { favoritedRestaurants: [] }, - params: { restaurantId: 2 }, - }) - const res = mockResponse() - - // 測試 userController.addFavorite 函式 - await this.userController.addFavorite(req, res) - - // 取得餐廳排序資料 - await this.restController.getTopRestaurant(req, res) - - // addFavorite 執行完畢後,應呼叫 res.render - // res.render 的第 2 個參數要包含 restaurants - // restaurant 當中的第 2 筆資料 favoritedCount 屬性的值應是 1 (被 1 個使用者加入最愛了) - res.render.getCall(0).args[1].restaurants[1].favoritedCount.should.equal(1) - }) - - it(' DELETE favorite ', async () => { - // 模擬 request & response - // 對 DELETE /favorite/1 發出請求,夾入 user.favoritedRestaurants - const req = mockRequest({ - user: { favoritedRestaurants: [] }, - params: { restaurantId: 1 }, - }) - const res = mockResponse() - - // 測試 userController.removeFavorite 函式 - await this.userController.removeFavorite(req, res) - // 取得餐廳排序資料 - await this.restController.getTopRestaurant(req, res) - - // removeFavorite 執行完畢後,應呼叫 res.render - // res.render 的第 2 個參數要包含 restaurants - // restaurants 當中的第 1 筆資料 id 屬性值應是 2 (id:1 的那家餐廳被刪除了) - res.render.getCall(0).args[1].restaurants[0].id.should.equal(2) - }) - - after(async () => { - // 清除模擬驗證資料 - this.ensureAuthenticated.restore() - this.getUser.restore() - }) - } - ) -}) diff --git a/tests/A17.test.js b/tests/R01.test.js similarity index 98% rename from tests/A17.test.js rename to tests/R01.test.js index 6065446e..38d41967 100644 --- a/tests/A17.test.js +++ b/tests/R01.test.js @@ -19,7 +19,7 @@ const mockResponse = () => { } } -describe('# A17', () => { +describe('# R01', () => { describe('登入測試: POST /signin', function(){ // 以下測試會發出請求,測試資料庫內是否有作業指定的使用者資料 // 測試資料的來源是真實的資料庫 @@ -57,7 +57,7 @@ describe('# A17', () => { }) }); - describe('# A17: 使用者權限管理', function () { + describe('# R01: 使用者權限管理', function () { // 前置準備 before(() => { // 製作假資料 From 2f9c683cab88eb95f6deb12f34ef83d1ae9c3e7d Mon Sep 17 00:00:00 2001 From: Amber Yan Date: Sun, 31 Oct 2021 13:07:46 +0800 Subject: [PATCH 022/135] changed all test file name --- tests/{A17.test.js => R01.test.js} | 4 ++-- tests/{A19.test.js => R02.test.js} | 4 ++-- tests/{A20.test.js => R03.test.js} | 2 +- tests/{A21.test.js => R04.test.js} | 2 +- tests/{A22.test.js => R05.test.js} | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) rename tests/{A17.test.js => R01.test.js} (98%) rename tests/{A19.test.js => R02.test.js} (98%) rename tests/{A20.test.js => R03.test.js} (97%) rename tests/{A21.test.js => R04.test.js} (98%) rename tests/{A22.test.js => R05.test.js} (98%) diff --git a/tests/A17.test.js b/tests/R01.test.js similarity index 98% rename from tests/A17.test.js rename to tests/R01.test.js index 6065446e..38d41967 100644 --- a/tests/A17.test.js +++ b/tests/R01.test.js @@ -19,7 +19,7 @@ const mockResponse = () => { } } -describe('# A17', () => { +describe('# R01', () => { describe('登入測試: POST /signin', function(){ // 以下測試會發出請求,測試資料庫內是否有作業指定的使用者資料 // 測試資料的來源是真實的資料庫 @@ -57,7 +57,7 @@ describe('# A17', () => { }) }); - describe('# A17: 使用者權限管理', function () { + describe('# R01: 使用者權限管理', function () { // 前置準備 before(() => { // 製作假資料 diff --git a/tests/A19.test.js b/tests/R02.test.js similarity index 98% rename from tests/A19.test.js rename to tests/R02.test.js index 228aafad..ea3739e9 100644 --- a/tests/A19.test.js +++ b/tests/R02.test.js @@ -17,8 +17,8 @@ const mockResponse = () => { render: sinon.spy(), } } -describe('# A19', () => { - describe('# A19: 建立 User Profile', function () { +describe('# R02', () => { + describe('# R02: 建立 User Profile', function () { context('# [瀏覽 Profile]', () => { // 前置準備 before(() => { diff --git a/tests/A20.test.js b/tests/R03.test.js similarity index 97% rename from tests/A20.test.js rename to tests/R03.test.js index a832e034..bc7d1ade 100644 --- a/tests/A20.test.js +++ b/tests/R03.test.js @@ -19,7 +19,7 @@ const mockResponse = () => { } } -describe('# A20: 餐廳資訊整理:Dashboard', function () { +describe('# R03: 餐廳資訊整理:Dashboard', function () { context('# [Q1: Dashboard - 1 - controller / view / route]', () => { before(async () => { // 製作假資料 diff --git a/tests/A21.test.js b/tests/R04.test.js similarity index 98% rename from tests/A21.test.js rename to tests/R04.test.js index ee638370..86bbb191 100644 --- a/tests/A21.test.js +++ b/tests/R04.test.js @@ -28,7 +28,7 @@ let mockLikeData = [ }, ] -describe('# A21: Like / Unlike', function () { +describe('# R04: Like / Unlike', function () { context('# Q1: 使用者可以 Like 餐廳', () => { before(() => { // 模擬登入驗證 diff --git a/tests/A22.test.js b/tests/R05.test.js similarity index 98% rename from tests/A22.test.js rename to tests/R05.test.js index 793e6996..a0ef79cc 100644 --- a/tests/A22.test.js +++ b/tests/R05.test.js @@ -46,7 +46,7 @@ let mockRestaurantData = [ }, ] -describe('# A22: TOP 10 人氣餐廳 ', function () { +describe('# R05: TOP 10 人氣餐廳 ', function () { context('# [網址正確、畫面正常執行]', () => { before(async () => { // 模擬登入驗證 From d3a66ddaea0ef1bf0b9deda1454cb2fa2505d0db Mon Sep 17 00:00:00 2001 From: Amber Yan Date: Sun, 31 Oct 2021 13:09:29 +0800 Subject: [PATCH 023/135] remove R03/04/05 test --- tests/R03.test.js | 72 --------------------- tests/R04.test.js | 113 --------------------------------- tests/R05.test.js | 158 ---------------------------------------------- 3 files changed, 343 deletions(-) delete mode 100644 tests/R03.test.js delete mode 100644 tests/R04.test.js delete mode 100644 tests/R05.test.js diff --git a/tests/R03.test.js b/tests/R03.test.js deleted file mode 100644 index bc7d1ade..00000000 --- a/tests/R03.test.js +++ /dev/null @@ -1,72 +0,0 @@ -const chai = require('chai') -const request = require('supertest') -const sinon = require('sinon') -const should = chai.should() - -const helpers = require('../_helpers') -const { createModelMock, createControllerProxy } = require('../helpers/unitTestHelpers'); - -const mockRequest = (query) => { - return { - ...query, - flash: sinon.spy(), - } -} -const mockResponse = () => { - return { - redirect: sinon.spy(), - render: sinon.spy(), - } -} - -describe('# R03: 餐廳資訊整理:Dashboard', function () { - context('# [Q1: Dashboard - 1 - controller / view / route]', () => { - before(async () => { - // 製作假資料 - // 本 context 會用這筆資料進行測試 - this.UserMock = createModelMock('User', { - id: 1, - email: 'root@example.com', - name: 'admin', - isAdmin: false, - }) - this.RestaurantMock = createModelMock('Restaurant', { - id: 1, - name: '銷魂麵', - viewCounts: 3 - }) - this.CategoryMock = createModelMock('Category', { - id: 1, - name: '食物' - }) - this.CommentMock = createModelMock('Comment', { - id: 1, - text: "gogogo" - }) - - // 連向模擬的 tables - this.restController = createControllerProxy('../controllers/restController', { - User: this.UserMock, - Category: this.CategoryMock, - Restaurant: this.RestaurantMock, - Comment: this.CommentMock, - }) - }) - - it(' GET /restaurants/:id/dashboard ', async () => { - // 模擬 request & response - const req = mockRequest({ params: { id: 1 } }) // 帶入 params.id = 1,對 GET /restaurants/1/dashboard 發出請求 - const res = mockResponse() - // 測試 restController.getDashBoard 函式 - await this.restController.getDashBoard(req, res) - - // getDashBoard 執行完畢後,應呼叫 res.render - // res.render 的第 1 個參數要是 'dashboard' - // res.render 的第 2 個參數要包含 restaurant,其 name 屬性的值應是 '銷魂麵' - // res.render 的地 3 個參數要包含 restaurant,其 viewCounts 值應該是 3 - res.render.getCall(0).args[0].should.equal('dashboard') - res.render.getCall(0).args[1].restaurant.name.should.equal('銷魂麵') - res.render.getCall(0).args[1].restaurant.viewCounts.should.equal(3) - }) - }) -}) diff --git a/tests/R04.test.js b/tests/R04.test.js deleted file mode 100644 index 86bbb191..00000000 --- a/tests/R04.test.js +++ /dev/null @@ -1,113 +0,0 @@ -const chai = require('chai') -const request = require('supertest') -const sinon = require('sinon') -const should = chai.should() - -const db = require('../models') -const helpers = require('../_helpers') -const { createModelMock, createControllerProxy } = require('../helpers/unitTestHelpers') - -const mockRequest = (query) => { - return { - ...query, - flash: sinon.spy(), - } -} -const mockResponse = () => { - return { - redirect: sinon.spy(), - render: sinon.spy(), - } -} - -// 建立模擬的 Like 資料 -let mockLikeData = [ - { - userId: 1, - restaurantId: 2, - }, -] - -describe('# R04: Like / Unlike', function () { - context('# Q1: 使用者可以 Like 餐廳', () => { - before(() => { - // 模擬登入驗證 - this.ensureAuthenticated = sinon - .stub(helpers, 'ensureAuthenticated') - .returns(true) - this.getUser = sinon.stub(helpers, 'getUser').returns({ id: 1 }) - - // 建立了一個模擬的 Like table,裡面目前是空的 - this.mockLikeData = [] - this.likeMock = createModelMock('Like', null, this.mockLikeData) - - // 連向模擬的 Like table - this.userController = createControllerProxy('../controllers/userController', {Like: this.likeMock}) - }) - - it(' POST /like/:restaurantId ', async () => { - // 模擬 request & response - const req = mockRequest({ params: { restaurantId: 2 } }) // 帶入 params.restaurantId = 2,對 POST /like/2 發出請求 - const res = mockResponse() - - // 測試 userController.addLike 函式 - await this.userController.addLike(req, res) - // 將模擬的 Like table 內的資料全數撈出 - const likes = await this.likeMock.findAll() - // addLike 執行完畢後,Like table 應會從空的 -> 變成有 1 筆資料 - likes.should.have.lengthOf(1) - // 資料裡的 UserId 應該會跟我們傳入的 user id 一樣 - likes[0].UserId.should.equal(1) - // 資料裡的 RestaurantId 會跟我們傳入的 params.restaurantId 一樣 - likes[0].RestaurantId.should.equal(2) - }) - - after(async () => { - // 清除驗證資料 - this.ensureAuthenticated.restore() - this.getUser.restore() - }) - }) - - context('# Q1: 使用者可以 unLike 餐廳', () => { - before(() => { - // 模擬登入驗證 - this.ensureAuthenticated = sinon - .stub(helpers, 'ensureAuthenticated') - .returns(true) - this.getUser = sinon.stub(helpers, 'getUser').returns({ id: 1 }) - // 製作假資料 - // 下個 context 會用這筆資料進行測試 - // 模擬 Like table 裡目前有 1 筆資料如下 - this.likeMock = createModelMock('Like', { - id: 1, - UserId: 1, - RestaurantId: 2, - }, mockLikeData); - - // 連向模擬的 Like table - this.userController = createControllerProxy('../controllers/userController', { Like: this.likeMock }) - }) - - it(' DELETE /like/:restaurantId ', async () => { - // 模擬 request & response - // 模擬發出 request, 帶入 params.id = 1, restaurantId = 2 - const req = mockRequest({ params: { id: 1, restaurantId: 2 } }) // 帶入 params.id = 1,對 DELETE /like/2 發出請求 - const res = mockResponse() - - // 測試作業指定的 userController.removeLike 函式 - await this.userController.removeLike(req, res) - - // 將模擬的 Like table 內的資料全數撈出 - const likes = await this.likeMock.findAll() - // addLike 執行完畢後,Like table 應會從有 1 筆資料 -> 變成空的 - likes.should.have.lengthOf(0) - }) - - after(async () => { - // 清除模擬驗證資料 - this.ensureAuthenticated.restore() - this.getUser.restore() - }) - }) -}) diff --git a/tests/R05.test.js b/tests/R05.test.js deleted file mode 100644 index a0ef79cc..00000000 --- a/tests/R05.test.js +++ /dev/null @@ -1,158 +0,0 @@ -const chai = require('chai') -const request = require('supertest') -const sinon = require('sinon') -const should = chai.should() - -const app = require('../app') -const helpers = require('../_helpers') -const { createModelMock, createControllerProxy } = require('../helpers/unitTestHelpers') - -const mockRequest = (query) => { - return { - ...query, - flash: sinon.spy(), - } -} -const mockResponse = () => { - return { - redirect: sinon.spy(), - render: sinon.spy(), - } -} -// 模擬 2 間餐廳資料 -let mockRestaurantData = [ - { - id: 1, - name: 'Restaurant1', - tel: 'tel', - address: 'address', - opening_hours: 'opening_hours', - description: 'test description', - favoritedUsers: [ - { - userId: 1, - }, - ], - }, - { - id: 2, - name: 'Restaurant2', - tel: 'tel', - address: 'address', - opening_hours: 'opening_hours', - description: 'description', - categoryId: 1, - favoritedUsers: [], - }, -] - -describe('# R05: TOP 10 人氣餐廳 ', function () { - context('# [網址正確、畫面正常執行]', () => { - before(async () => { - // 模擬登入驗證 - this.ensureAuthenticated = sinon - .stub(helpers, 'ensureAuthenticated') - .returns(true) - // 模擬 getUser 函式,負責取得使用者資料 - this.getUser = sinon - .stub(helpers, 'getUser') - .returns({ id: 1, followings: [], favoritedRestaurants: [] }) - }) - - it(' GET /restaurants/top ', (done) => { - // 對 GET /restaurants/top 發出請求 - request(app) - .get('/restaurants/top') - .end(function (err, res) { - // 回應中應包含字串'Top 10 人氣餐廳' - // 若請求路徑正確,controller 執行後,會呼叫 res.render - // res.render 回傳的 view 樣板裡應包含字串'Top 10 人氣餐廳' - res.text.should.include('Top 10 人氣餐廳') - done() - }) - }) - - after(async () => { - // 清除模擬驗證資料 - this.ensureAuthenticated.restore() - this.getUser.restore() - }) - }) - - context( - '# [當你點擊畫面上的「加入最愛 / 移除最愛」按鈕時,會重新計算「收藏數」的數字]', - () => { - before(async () => { - // 模擬登入驗證 - this.ensureAuthenticated = sinon - .stub(helpers, 'ensureAuthenticated') - .returns(true) - // 模擬 getUser 函式,負責取得使用者資料 - this.getUser = sinon - .stub(helpers, 'getUser') - .returns({ id: 1, followings: [], favoritedRestaurants: [] }) - - // 建立了一個模擬的 Restaurant table,裡面放入 2 間餐廳資料 - this.restaurantMock = createModelMock('Restaurant', null, mockRestaurantData) - - // 連向模擬的 Restaurant table - this.restController = createControllerProxy('../controllers/restController', { - Restaurant: this.restaurantMock, - }) - - // 建立了一個模擬的 Favorite table,裡面有 1 筆資料 - this.favoriteMock = createModelMock('Favorite', null, mockRestaurantData, 'FavoritedUsers') - - // 連向模擬的 Favorite table - this.userController = createControllerProxy('../controllers/userController', {Favorite: this.favoriteMock}) - }) - - it(' POST favorite ', async () => { - // 模擬 request & response - // 對 POST /favorite/2 發出請求,夾帶 user.favoritedRestaurants - const req = mockRequest({ - user: { favoritedRestaurants: [] }, - params: { restaurantId: 2 }, - }) - const res = mockResponse() - - // 測試 userController.addFavorite 函式 - await this.userController.addFavorite(req, res) - - // 取得餐廳排序資料 - await this.restController.getTopRestaurant(req, res) - - // addFavorite 執行完畢後,應呼叫 res.render - // res.render 的第 2 個參數要包含 restaurants - // restaurant 當中的第 2 筆資料 favoritedCount 屬性的值應是 1 (被 1 個使用者加入最愛了) - res.render.getCall(0).args[1].restaurants[1].favoritedCount.should.equal(1) - }) - - it(' DELETE favorite ', async () => { - // 模擬 request & response - // 對 DELETE /favorite/1 發出請求,夾入 user.favoritedRestaurants - const req = mockRequest({ - user: { favoritedRestaurants: [] }, - params: { restaurantId: 1 }, - }) - const res = mockResponse() - - // 測試 userController.removeFavorite 函式 - await this.userController.removeFavorite(req, res) - // 取得餐廳排序資料 - await this.restController.getTopRestaurant(req, res) - - // removeFavorite 執行完畢後,應呼叫 res.render - // res.render 的第 2 個參數要包含 restaurants - // restaurants 當中的第 1 筆資料 id 屬性值應是 2 (id:1 的那家餐廳被刪除了) - res.render.getCall(0).args[1].restaurants[0].id.should.equal(2) - }) - - after(async () => { - // 清除模擬驗證資料 - this.ensureAuthenticated.restore() - this.getUser.restore() - }) - } - ) -}) From e0dbcb62099ea60df1e6da8f56596b7190488f84 Mon Sep 17 00:00:00 2001 From: Amber Yan Date: Sun, 31 Oct 2021 13:10:14 +0800 Subject: [PATCH 024/135] remove R04/05 test --- tests/R04.test.js | 113 --------------------------------- tests/R05.test.js | 158 ---------------------------------------------- 2 files changed, 271 deletions(-) delete mode 100644 tests/R04.test.js delete mode 100644 tests/R05.test.js diff --git a/tests/R04.test.js b/tests/R04.test.js deleted file mode 100644 index 86bbb191..00000000 --- a/tests/R04.test.js +++ /dev/null @@ -1,113 +0,0 @@ -const chai = require('chai') -const request = require('supertest') -const sinon = require('sinon') -const should = chai.should() - -const db = require('../models') -const helpers = require('../_helpers') -const { createModelMock, createControllerProxy } = require('../helpers/unitTestHelpers') - -const mockRequest = (query) => { - return { - ...query, - flash: sinon.spy(), - } -} -const mockResponse = () => { - return { - redirect: sinon.spy(), - render: sinon.spy(), - } -} - -// 建立模擬的 Like 資料 -let mockLikeData = [ - { - userId: 1, - restaurantId: 2, - }, -] - -describe('# R04: Like / Unlike', function () { - context('# Q1: 使用者可以 Like 餐廳', () => { - before(() => { - // 模擬登入驗證 - this.ensureAuthenticated = sinon - .stub(helpers, 'ensureAuthenticated') - .returns(true) - this.getUser = sinon.stub(helpers, 'getUser').returns({ id: 1 }) - - // 建立了一個模擬的 Like table,裡面目前是空的 - this.mockLikeData = [] - this.likeMock = createModelMock('Like', null, this.mockLikeData) - - // 連向模擬的 Like table - this.userController = createControllerProxy('../controllers/userController', {Like: this.likeMock}) - }) - - it(' POST /like/:restaurantId ', async () => { - // 模擬 request & response - const req = mockRequest({ params: { restaurantId: 2 } }) // 帶入 params.restaurantId = 2,對 POST /like/2 發出請求 - const res = mockResponse() - - // 測試 userController.addLike 函式 - await this.userController.addLike(req, res) - // 將模擬的 Like table 內的資料全數撈出 - const likes = await this.likeMock.findAll() - // addLike 執行完畢後,Like table 應會從空的 -> 變成有 1 筆資料 - likes.should.have.lengthOf(1) - // 資料裡的 UserId 應該會跟我們傳入的 user id 一樣 - likes[0].UserId.should.equal(1) - // 資料裡的 RestaurantId 會跟我們傳入的 params.restaurantId 一樣 - likes[0].RestaurantId.should.equal(2) - }) - - after(async () => { - // 清除驗證資料 - this.ensureAuthenticated.restore() - this.getUser.restore() - }) - }) - - context('# Q1: 使用者可以 unLike 餐廳', () => { - before(() => { - // 模擬登入驗證 - this.ensureAuthenticated = sinon - .stub(helpers, 'ensureAuthenticated') - .returns(true) - this.getUser = sinon.stub(helpers, 'getUser').returns({ id: 1 }) - // 製作假資料 - // 下個 context 會用這筆資料進行測試 - // 模擬 Like table 裡目前有 1 筆資料如下 - this.likeMock = createModelMock('Like', { - id: 1, - UserId: 1, - RestaurantId: 2, - }, mockLikeData); - - // 連向模擬的 Like table - this.userController = createControllerProxy('../controllers/userController', { Like: this.likeMock }) - }) - - it(' DELETE /like/:restaurantId ', async () => { - // 模擬 request & response - // 模擬發出 request, 帶入 params.id = 1, restaurantId = 2 - const req = mockRequest({ params: { id: 1, restaurantId: 2 } }) // 帶入 params.id = 1,對 DELETE /like/2 發出請求 - const res = mockResponse() - - // 測試作業指定的 userController.removeLike 函式 - await this.userController.removeLike(req, res) - - // 將模擬的 Like table 內的資料全數撈出 - const likes = await this.likeMock.findAll() - // addLike 執行完畢後,Like table 應會從有 1 筆資料 -> 變成空的 - likes.should.have.lengthOf(0) - }) - - after(async () => { - // 清除模擬驗證資料 - this.ensureAuthenticated.restore() - this.getUser.restore() - }) - }) -}) diff --git a/tests/R05.test.js b/tests/R05.test.js deleted file mode 100644 index a0ef79cc..00000000 --- a/tests/R05.test.js +++ /dev/null @@ -1,158 +0,0 @@ -const chai = require('chai') -const request = require('supertest') -const sinon = require('sinon') -const should = chai.should() - -const app = require('../app') -const helpers = require('../_helpers') -const { createModelMock, createControllerProxy } = require('../helpers/unitTestHelpers') - -const mockRequest = (query) => { - return { - ...query, - flash: sinon.spy(), - } -} -const mockResponse = () => { - return { - redirect: sinon.spy(), - render: sinon.spy(), - } -} -// 模擬 2 間餐廳資料 -let mockRestaurantData = [ - { - id: 1, - name: 'Restaurant1', - tel: 'tel', - address: 'address', - opening_hours: 'opening_hours', - description: 'test description', - favoritedUsers: [ - { - userId: 1, - }, - ], - }, - { - id: 2, - name: 'Restaurant2', - tel: 'tel', - address: 'address', - opening_hours: 'opening_hours', - description: 'description', - categoryId: 1, - favoritedUsers: [], - }, -] - -describe('# R05: TOP 10 人氣餐廳 ', function () { - context('# [網址正確、畫面正常執行]', () => { - before(async () => { - // 模擬登入驗證 - this.ensureAuthenticated = sinon - .stub(helpers, 'ensureAuthenticated') - .returns(true) - // 模擬 getUser 函式,負責取得使用者資料 - this.getUser = sinon - .stub(helpers, 'getUser') - .returns({ id: 1, followings: [], favoritedRestaurants: [] }) - }) - - it(' GET /restaurants/top ', (done) => { - // 對 GET /restaurants/top 發出請求 - request(app) - .get('/restaurants/top') - .end(function (err, res) { - // 回應中應包含字串'Top 10 人氣餐廳' - // 若請求路徑正確,controller 執行後,會呼叫 res.render - // res.render 回傳的 view 樣板裡應包含字串'Top 10 人氣餐廳' - res.text.should.include('Top 10 人氣餐廳') - done() - }) - }) - - after(async () => { - // 清除模擬驗證資料 - this.ensureAuthenticated.restore() - this.getUser.restore() - }) - }) - - context( - '# [當你點擊畫面上的「加入最愛 / 移除最愛」按鈕時,會重新計算「收藏數」的數字]', - () => { - before(async () => { - // 模擬登入驗證 - this.ensureAuthenticated = sinon - .stub(helpers, 'ensureAuthenticated') - .returns(true) - // 模擬 getUser 函式,負責取得使用者資料 - this.getUser = sinon - .stub(helpers, 'getUser') - .returns({ id: 1, followings: [], favoritedRestaurants: [] }) - - // 建立了一個模擬的 Restaurant table,裡面放入 2 間餐廳資料 - this.restaurantMock = createModelMock('Restaurant', null, mockRestaurantData) - - // 連向模擬的 Restaurant table - this.restController = createControllerProxy('../controllers/restController', { - Restaurant: this.restaurantMock, - }) - - // 建立了一個模擬的 Favorite table,裡面有 1 筆資料 - this.favoriteMock = createModelMock('Favorite', null, mockRestaurantData, 'FavoritedUsers') - - // 連向模擬的 Favorite table - this.userController = createControllerProxy('../controllers/userController', {Favorite: this.favoriteMock}) - }) - - it(' POST favorite ', async () => { - // 模擬 request & response - // 對 POST /favorite/2 發出請求,夾帶 user.favoritedRestaurants - const req = mockRequest({ - user: { favoritedRestaurants: [] }, - params: { restaurantId: 2 }, - }) - const res = mockResponse() - - // 測試 userController.addFavorite 函式 - await this.userController.addFavorite(req, res) - - // 取得餐廳排序資料 - await this.restController.getTopRestaurant(req, res) - - // addFavorite 執行完畢後,應呼叫 res.render - // res.render 的第 2 個參數要包含 restaurants - // restaurant 當中的第 2 筆資料 favoritedCount 屬性的值應是 1 (被 1 個使用者加入最愛了) - res.render.getCall(0).args[1].restaurants[1].favoritedCount.should.equal(1) - }) - - it(' DELETE favorite ', async () => { - // 模擬 request & response - // 對 DELETE /favorite/1 發出請求,夾入 user.favoritedRestaurants - const req = mockRequest({ - user: { favoritedRestaurants: [] }, - params: { restaurantId: 1 }, - }) - const res = mockResponse() - - // 測試 userController.removeFavorite 函式 - await this.userController.removeFavorite(req, res) - // 取得餐廳排序資料 - await this.restController.getTopRestaurant(req, res) - - // removeFavorite 執行完畢後,應呼叫 res.render - // res.render 的第 2 個參數要包含 restaurants - // restaurants 當中的第 1 筆資料 id 屬性值應是 2 (id:1 的那家餐廳被刪除了) - res.render.getCall(0).args[1].restaurants[0].id.should.equal(2) - }) - - after(async () => { - // 清除模擬驗證資料 - this.ensureAuthenticated.restore() - this.getUser.restore() - }) - } - ) -}) From 5a83153e5ccf2e215b2a711792c3e8e5f383f1c5 Mon Sep 17 00:00:00 2001 From: Amber Yan Date: Sun, 31 Oct 2021 13:10:58 +0800 Subject: [PATCH 025/135] remove R05 test --- tests/R05.test.js | 158 ---------------------------------------------- 1 file changed, 158 deletions(-) delete mode 100644 tests/R05.test.js diff --git a/tests/R05.test.js b/tests/R05.test.js deleted file mode 100644 index a0ef79cc..00000000 --- a/tests/R05.test.js +++ /dev/null @@ -1,158 +0,0 @@ -const chai = require('chai') -const request = require('supertest') -const sinon = require('sinon') -const should = chai.should() - -const app = require('../app') -const helpers = require('../_helpers') -const { createModelMock, createControllerProxy } = require('../helpers/unitTestHelpers') - -const mockRequest = (query) => { - return { - ...query, - flash: sinon.spy(), - } -} -const mockResponse = () => { - return { - redirect: sinon.spy(), - render: sinon.spy(), - } -} -// 模擬 2 間餐廳資料 -let mockRestaurantData = [ - { - id: 1, - name: 'Restaurant1', - tel: 'tel', - address: 'address', - opening_hours: 'opening_hours', - description: 'test description', - favoritedUsers: [ - { - userId: 1, - }, - ], - }, - { - id: 2, - name: 'Restaurant2', - tel: 'tel', - address: 'address', - opening_hours: 'opening_hours', - description: 'description', - categoryId: 1, - favoritedUsers: [], - }, -] - -describe('# R05: TOP 10 人氣餐廳 ', function () { - context('# [網址正確、畫面正常執行]', () => { - before(async () => { - // 模擬登入驗證 - this.ensureAuthenticated = sinon - .stub(helpers, 'ensureAuthenticated') - .returns(true) - // 模擬 getUser 函式,負責取得使用者資料 - this.getUser = sinon - .stub(helpers, 'getUser') - .returns({ id: 1, followings: [], favoritedRestaurants: [] }) - }) - - it(' GET /restaurants/top ', (done) => { - // 對 GET /restaurants/top 發出請求 - request(app) - .get('/restaurants/top') - .end(function (err, res) { - // 回應中應包含字串'Top 10 人氣餐廳' - // 若請求路徑正確,controller 執行後,會呼叫 res.render - // res.render 回傳的 view 樣板裡應包含字串'Top 10 人氣餐廳' - res.text.should.include('Top 10 人氣餐廳') - done() - }) - }) - - after(async () => { - // 清除模擬驗證資料 - this.ensureAuthenticated.restore() - this.getUser.restore() - }) - }) - - context( - '# [當你點擊畫面上的「加入最愛 / 移除最愛」按鈕時,會重新計算「收藏數」的數字]', - () => { - before(async () => { - // 模擬登入驗證 - this.ensureAuthenticated = sinon - .stub(helpers, 'ensureAuthenticated') - .returns(true) - // 模擬 getUser 函式,負責取得使用者資料 - this.getUser = sinon - .stub(helpers, 'getUser') - .returns({ id: 1, followings: [], favoritedRestaurants: [] }) - - // 建立了一個模擬的 Restaurant table,裡面放入 2 間餐廳資料 - this.restaurantMock = createModelMock('Restaurant', null, mockRestaurantData) - - // 連向模擬的 Restaurant table - this.restController = createControllerProxy('../controllers/restController', { - Restaurant: this.restaurantMock, - }) - - // 建立了一個模擬的 Favorite table,裡面有 1 筆資料 - this.favoriteMock = createModelMock('Favorite', null, mockRestaurantData, 'FavoritedUsers') - - // 連向模擬的 Favorite table - this.userController = createControllerProxy('../controllers/userController', {Favorite: this.favoriteMock}) - }) - - it(' POST favorite ', async () => { - // 模擬 request & response - // 對 POST /favorite/2 發出請求,夾帶 user.favoritedRestaurants - const req = mockRequest({ - user: { favoritedRestaurants: [] }, - params: { restaurantId: 2 }, - }) - const res = mockResponse() - - // 測試 userController.addFavorite 函式 - await this.userController.addFavorite(req, res) - - // 取得餐廳排序資料 - await this.restController.getTopRestaurant(req, res) - - // addFavorite 執行完畢後,應呼叫 res.render - // res.render 的第 2 個參數要包含 restaurants - // restaurant 當中的第 2 筆資料 favoritedCount 屬性的值應是 1 (被 1 個使用者加入最愛了) - res.render.getCall(0).args[1].restaurants[1].favoritedCount.should.equal(1) - }) - - it(' DELETE favorite ', async () => { - // 模擬 request & response - // 對 DELETE /favorite/1 發出請求,夾入 user.favoritedRestaurants - const req = mockRequest({ - user: { favoritedRestaurants: [] }, - params: { restaurantId: 1 }, - }) - const res = mockResponse() - - // 測試 userController.removeFavorite 函式 - await this.userController.removeFavorite(req, res) - // 取得餐廳排序資料 - await this.restController.getTopRestaurant(req, res) - - // removeFavorite 執行完畢後,應呼叫 res.render - // res.render 的第 2 個參數要包含 restaurants - // restaurants 當中的第 1 筆資料 id 屬性值應是 2 (id:1 的那家餐廳被刪除了) - res.render.getCall(0).args[1].restaurants[0].id.should.equal(2) - }) - - after(async () => { - // 清除模擬驗證資料 - this.ensureAuthenticated.restore() - this.getUser.restore() - }) - } - ) -}) From 914871590b449f471147579952f39df72512e664 Mon Sep 17 00:00:00 2001 From: Amber Yan Date: Mon, 1 Nov 2021 15:14:53 +0800 Subject: [PATCH 026/135] fixed R01 ../../app issue & not found sequelize lib --- tests/R01.test.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/R01.test.js b/tests/R01.test.js index 38d41967..07778434 100644 --- a/tests/R01.test.js +++ b/tests/R01.test.js @@ -3,8 +3,7 @@ const request = require('supertest') const sinon = require('sinon') const should = chai.should() -const app = require('../../app') -const { classToInvokable } = require('sequelize/types/lib/utils') +const app = require('../app') const { createModelMock, createControllerProxy } = require('../helpers/unitTestHelpers'); const mockRequest = (query) => { From 154a12e2d4cba762c014fe35bfb60f6f3df16455 Mon Sep 17 00:00:00 2001 From: Amber Yan Date: Mon, 1 Nov 2021 15:14:53 +0800 Subject: [PATCH 027/135] fixed R01 ../../app issue & not found sequelize lib --- tests/R01.test.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/R01.test.js b/tests/R01.test.js index 38d41967..07778434 100644 --- a/tests/R01.test.js +++ b/tests/R01.test.js @@ -3,8 +3,7 @@ const request = require('supertest') const sinon = require('sinon') const should = chai.should() -const app = require('../../app') -const { classToInvokable } = require('sequelize/types/lib/utils') +const app = require('../app') const { createModelMock, createControllerProxy } = require('../helpers/unitTestHelpers'); const mockRequest = (query) => { From c3b664cfbf2217fb7b006dd920a53660c8f46f05 Mon Sep 17 00:00:00 2001 From: Amber Yan Date: Mon, 1 Nov 2021 15:14:53 +0800 Subject: [PATCH 028/135] fixed R01 ../../app issue & not found sequelize lib --- tests/R01.test.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/R01.test.js b/tests/R01.test.js index 38d41967..07778434 100644 --- a/tests/R01.test.js +++ b/tests/R01.test.js @@ -3,8 +3,7 @@ const request = require('supertest') const sinon = require('sinon') const should = chai.should() -const app = require('../../app') -const { classToInvokable } = require('sequelize/types/lib/utils') +const app = require('../app') const { createModelMock, createControllerProxy } = require('../helpers/unitTestHelpers'); const mockRequest = (query) => { From 67b9b325d614e911bcaf418e3d84b7a02e2b002d Mon Sep 17 00:00:00 2001 From: Amber Yan Date: Mon, 1 Nov 2021 15:14:53 +0800 Subject: [PATCH 029/135] fixed R01 ../../app issue & not found sequelize lib --- tests/R01.test.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/R01.test.js b/tests/R01.test.js index 38d41967..07778434 100644 --- a/tests/R01.test.js +++ b/tests/R01.test.js @@ -3,8 +3,7 @@ const request = require('supertest') const sinon = require('sinon') const should = chai.should() -const app = require('../../app') -const { classToInvokable } = require('sequelize/types/lib/utils') +const app = require('../app') const { createModelMock, createControllerProxy } = require('../helpers/unitTestHelpers'); const mockRequest = (query) => { From ba687334daaf8456d0585b52418ffbe090ad7ca0 Mon Sep 17 00:00:00 2001 From: Amber Yan Date: Mon, 1 Nov 2021 20:17:36 +0800 Subject: [PATCH 030/135] fixed controller path wrong issue / check data exist --- helpers/unitTestHelpers.js | 4 ++-- tests/R01.test.js | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/helpers/unitTestHelpers.js b/helpers/unitTestHelpers.js index a7157681..ea4cc7b1 100644 --- a/helpers/unitTestHelpers.js +++ b/helpers/unitTestHelpers.js @@ -32,7 +32,7 @@ const createModelMock = (name, defaultValue, data, joinedTableName) => { return Promise.resolve(data.map(d => mockModel.build(d))) } else if (query === 'findAll') { // 回傳模擬資料 - return Promise.resolve(data.map(d => mockModel.build(d))) + return Promise.resolve( data ? data.map(d => mockModel.build(d)) : []) }else if (query === 'destroy') { // destroy 可以從 where 取得要刪除的資料 // 因此就可以模擬將模擬資料中的資料刪除 @@ -56,7 +56,7 @@ const createModelMock = (name, defaultValue, data, joinedTableName) => { return Promise.resolve(mockModel.build(data)) } else if (query === 'findAll') { // 回傳模擬資料 - return Promise.resolve(data.map(d => mockModel.build(d))) + return Promise.resolve(data ? data.map(d => mockModel.build(d)) : []) } else if (query === 'destroy') { // destroy 可以從 where 取得要刪除的資料 // 因此就可以模擬將模擬資料中的資料刪除 diff --git a/tests/R01.test.js b/tests/R01.test.js index 07778434..f98a96ac 100644 --- a/tests/R01.test.js +++ b/tests/R01.test.js @@ -69,7 +69,7 @@ describe('# R01', () => { }) // 修改 adminController 中的資料庫連線設定,由連向真實的資料庫 -> 改為連向模擬的 User table - this.adminController = createControllerProxy('../../controllers/adminController', { User: this.UserMock }) + this.adminController = createControllerProxy('../controllers/adminController', { User: this.UserMock }) }) // 開始測試 @@ -104,7 +104,7 @@ describe('# R01', () => { ) // 將 adminController 中的 User db 取代成 User mock db - this.adminController = createControllerProxy('../../controllers/adminController', { User: this.UserMock }) + this.adminController = createControllerProxy('../controllers/adminController', { User: this.UserMock }) }) it(' PUT /admin/users/:id/toggleAdmin ', async () => { @@ -138,7 +138,7 @@ describe('# R01', () => { } ) // 將 adminController 中的 User db 取代成 User mock db - this.adminController = createControllerProxy('../../controllers/adminController', { User: this.UserMock }) + this.adminController = createControllerProxy('../controllers/adminController', { User: this.UserMock }) }) it(' PUT /admin/users/:id/toggleAdmin ', async (done) => { From 3f256dcc2ba68a58e22bf6ae1fd3cf95ee3c6ab3 Mon Sep 17 00:00:00 2001 From: Amber Yan Date: Mon, 1 Nov 2021 20:17:36 +0800 Subject: [PATCH 031/135] fixed controller path wrong issue / check data exist --- helpers/unitTestHelpers.js | 4 ++-- tests/R01.test.js | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/helpers/unitTestHelpers.js b/helpers/unitTestHelpers.js index a7157681..ea4cc7b1 100644 --- a/helpers/unitTestHelpers.js +++ b/helpers/unitTestHelpers.js @@ -32,7 +32,7 @@ const createModelMock = (name, defaultValue, data, joinedTableName) => { return Promise.resolve(data.map(d => mockModel.build(d))) } else if (query === 'findAll') { // 回傳模擬資料 - return Promise.resolve(data.map(d => mockModel.build(d))) + return Promise.resolve( data ? data.map(d => mockModel.build(d)) : []) }else if (query === 'destroy') { // destroy 可以從 where 取得要刪除的資料 // 因此就可以模擬將模擬資料中的資料刪除 @@ -56,7 +56,7 @@ const createModelMock = (name, defaultValue, data, joinedTableName) => { return Promise.resolve(mockModel.build(data)) } else if (query === 'findAll') { // 回傳模擬資料 - return Promise.resolve(data.map(d => mockModel.build(d))) + return Promise.resolve(data ? data.map(d => mockModel.build(d)) : []) } else if (query === 'destroy') { // destroy 可以從 where 取得要刪除的資料 // 因此就可以模擬將模擬資料中的資料刪除 diff --git a/tests/R01.test.js b/tests/R01.test.js index 07778434..f98a96ac 100644 --- a/tests/R01.test.js +++ b/tests/R01.test.js @@ -69,7 +69,7 @@ describe('# R01', () => { }) // 修改 adminController 中的資料庫連線設定,由連向真實的資料庫 -> 改為連向模擬的 User table - this.adminController = createControllerProxy('../../controllers/adminController', { User: this.UserMock }) + this.adminController = createControllerProxy('../controllers/adminController', { User: this.UserMock }) }) // 開始測試 @@ -104,7 +104,7 @@ describe('# R01', () => { ) // 將 adminController 中的 User db 取代成 User mock db - this.adminController = createControllerProxy('../../controllers/adminController', { User: this.UserMock }) + this.adminController = createControllerProxy('../controllers/adminController', { User: this.UserMock }) }) it(' PUT /admin/users/:id/toggleAdmin ', async () => { @@ -138,7 +138,7 @@ describe('# R01', () => { } ) // 將 adminController 中的 User db 取代成 User mock db - this.adminController = createControllerProxy('../../controllers/adminController', { User: this.UserMock }) + this.adminController = createControllerProxy('../controllers/adminController', { User: this.UserMock }) }) it(' PUT /admin/users/:id/toggleAdmin ', async (done) => { From 0ab85cd3943e1de42f1ef8992ade086c6b8f4680 Mon Sep 17 00:00:00 2001 From: Amber Yan Date: Mon, 1 Nov 2021 20:21:36 +0800 Subject: [PATCH 032/135] fixed wrong path --- tests/R02.test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/R02.test.js b/tests/R02.test.js index ea3739e9..5b7cadb2 100644 --- a/tests/R02.test.js +++ b/tests/R02.test.js @@ -37,7 +37,7 @@ describe('# R02', () => { }) // 修改 userController 中的資料庫連線設定,由連向真實的資料庫 -> 改為連向模擬的 User table - this.userController = createControllerProxy('../../controllers/userController', { User: this.UserMock }) + this.userController = createControllerProxy('../controllers/userController', { User: this.UserMock }) }) // 開始測試 @@ -82,7 +82,7 @@ describe('# R02', () => { }) // 連向模擬的 User table - this.userController = createControllerProxy('../../controllers/userController', { User: this.UserMock }) + this.userController = createControllerProxy('../controllers/userController', { User: this.UserMock }) }) it(' GET /users/:id/edit ', async () => { @@ -127,7 +127,7 @@ describe('# R02', () => { ) // 連向模擬的 User table - this.userController = createControllerProxy('../../controllers/userController', { User: this.UserMock }) + this.userController = createControllerProxy('../controllers/userController', { User: this.UserMock }) }) it(' PUT /users/:id ', async () => { From a342d2d97f2da6c14d7386ae1a8df939340da73f Mon Sep 17 00:00:00 2001 From: Amber Yan Date: Mon, 1 Nov 2021 20:17:36 +0800 Subject: [PATCH 033/135] fixed controller path wrong issue / check data exist --- helpers/unitTestHelpers.js | 4 ++-- tests/R01.test.js | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/helpers/unitTestHelpers.js b/helpers/unitTestHelpers.js index a7157681..ea4cc7b1 100644 --- a/helpers/unitTestHelpers.js +++ b/helpers/unitTestHelpers.js @@ -32,7 +32,7 @@ const createModelMock = (name, defaultValue, data, joinedTableName) => { return Promise.resolve(data.map(d => mockModel.build(d))) } else if (query === 'findAll') { // 回傳模擬資料 - return Promise.resolve(data.map(d => mockModel.build(d))) + return Promise.resolve( data ? data.map(d => mockModel.build(d)) : []) }else if (query === 'destroy') { // destroy 可以從 where 取得要刪除的資料 // 因此就可以模擬將模擬資料中的資料刪除 @@ -56,7 +56,7 @@ const createModelMock = (name, defaultValue, data, joinedTableName) => { return Promise.resolve(mockModel.build(data)) } else if (query === 'findAll') { // 回傳模擬資料 - return Promise.resolve(data.map(d => mockModel.build(d))) + return Promise.resolve(data ? data.map(d => mockModel.build(d)) : []) } else if (query === 'destroy') { // destroy 可以從 where 取得要刪除的資料 // 因此就可以模擬將模擬資料中的資料刪除 diff --git a/tests/R01.test.js b/tests/R01.test.js index 07778434..f98a96ac 100644 --- a/tests/R01.test.js +++ b/tests/R01.test.js @@ -69,7 +69,7 @@ describe('# R01', () => { }) // 修改 adminController 中的資料庫連線設定,由連向真實的資料庫 -> 改為連向模擬的 User table - this.adminController = createControllerProxy('../../controllers/adminController', { User: this.UserMock }) + this.adminController = createControllerProxy('../controllers/adminController', { User: this.UserMock }) }) // 開始測試 @@ -104,7 +104,7 @@ describe('# R01', () => { ) // 將 adminController 中的 User db 取代成 User mock db - this.adminController = createControllerProxy('../../controllers/adminController', { User: this.UserMock }) + this.adminController = createControllerProxy('../controllers/adminController', { User: this.UserMock }) }) it(' PUT /admin/users/:id/toggleAdmin ', async () => { @@ -138,7 +138,7 @@ describe('# R01', () => { } ) // 將 adminController 中的 User db 取代成 User mock db - this.adminController = createControllerProxy('../../controllers/adminController', { User: this.UserMock }) + this.adminController = createControllerProxy('../controllers/adminController', { User: this.UserMock }) }) it(' PUT /admin/users/:id/toggleAdmin ', async (done) => { From b10ee15ef5278be8d5b747177f00b3371fea90f2 Mon Sep 17 00:00:00 2001 From: Amber Yan Date: Mon, 1 Nov 2021 20:21:36 +0800 Subject: [PATCH 034/135] fixed wrong path --- tests/R02.test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/R02.test.js b/tests/R02.test.js index ea3739e9..5b7cadb2 100644 --- a/tests/R02.test.js +++ b/tests/R02.test.js @@ -37,7 +37,7 @@ describe('# R02', () => { }) // 修改 userController 中的資料庫連線設定,由連向真實的資料庫 -> 改為連向模擬的 User table - this.userController = createControllerProxy('../../controllers/userController', { User: this.UserMock }) + this.userController = createControllerProxy('../controllers/userController', { User: this.UserMock }) }) // 開始測試 @@ -82,7 +82,7 @@ describe('# R02', () => { }) // 連向模擬的 User table - this.userController = createControllerProxy('../../controllers/userController', { User: this.UserMock }) + this.userController = createControllerProxy('../controllers/userController', { User: this.UserMock }) }) it(' GET /users/:id/edit ', async () => { @@ -127,7 +127,7 @@ describe('# R02', () => { ) // 連向模擬的 User table - this.userController = createControllerProxy('../../controllers/userController', { User: this.UserMock }) + this.userController = createControllerProxy('../controllers/userController', { User: this.UserMock }) }) it(' PUT /users/:id ', async () => { From 28011ed1321de93890822ee380606614e03093c4 Mon Sep 17 00:00:00 2001 From: Amber Yan Date: Mon, 1 Nov 2021 20:17:36 +0800 Subject: [PATCH 035/135] fixed controller path wrong issue / check data exist --- helpers/unitTestHelpers.js | 4 ++-- tests/R01.test.js | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/helpers/unitTestHelpers.js b/helpers/unitTestHelpers.js index a7157681..ea4cc7b1 100644 --- a/helpers/unitTestHelpers.js +++ b/helpers/unitTestHelpers.js @@ -32,7 +32,7 @@ const createModelMock = (name, defaultValue, data, joinedTableName) => { return Promise.resolve(data.map(d => mockModel.build(d))) } else if (query === 'findAll') { // 回傳模擬資料 - return Promise.resolve(data.map(d => mockModel.build(d))) + return Promise.resolve( data ? data.map(d => mockModel.build(d)) : []) }else if (query === 'destroy') { // destroy 可以從 where 取得要刪除的資料 // 因此就可以模擬將模擬資料中的資料刪除 @@ -56,7 +56,7 @@ const createModelMock = (name, defaultValue, data, joinedTableName) => { return Promise.resolve(mockModel.build(data)) } else if (query === 'findAll') { // 回傳模擬資料 - return Promise.resolve(data.map(d => mockModel.build(d))) + return Promise.resolve(data ? data.map(d => mockModel.build(d)) : []) } else if (query === 'destroy') { // destroy 可以從 where 取得要刪除的資料 // 因此就可以模擬將模擬資料中的資料刪除 diff --git a/tests/R01.test.js b/tests/R01.test.js index 07778434..f98a96ac 100644 --- a/tests/R01.test.js +++ b/tests/R01.test.js @@ -69,7 +69,7 @@ describe('# R01', () => { }) // 修改 adminController 中的資料庫連線設定,由連向真實的資料庫 -> 改為連向模擬的 User table - this.adminController = createControllerProxy('../../controllers/adminController', { User: this.UserMock }) + this.adminController = createControllerProxy('../controllers/adminController', { User: this.UserMock }) }) // 開始測試 @@ -104,7 +104,7 @@ describe('# R01', () => { ) // 將 adminController 中的 User db 取代成 User mock db - this.adminController = createControllerProxy('../../controllers/adminController', { User: this.UserMock }) + this.adminController = createControllerProxy('../controllers/adminController', { User: this.UserMock }) }) it(' PUT /admin/users/:id/toggleAdmin ', async () => { @@ -138,7 +138,7 @@ describe('# R01', () => { } ) // 將 adminController 中的 User db 取代成 User mock db - this.adminController = createControllerProxy('../../controllers/adminController', { User: this.UserMock }) + this.adminController = createControllerProxy('../controllers/adminController', { User: this.UserMock }) }) it(' PUT /admin/users/:id/toggleAdmin ', async (done) => { From 9b8b4b1e11e58c64a2393bd56e2fbb467d2dc926 Mon Sep 17 00:00:00 2001 From: Amber Yan Date: Mon, 1 Nov 2021 20:21:36 +0800 Subject: [PATCH 036/135] fixed wrong path --- tests/R02.test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/R02.test.js b/tests/R02.test.js index ea3739e9..5b7cadb2 100644 --- a/tests/R02.test.js +++ b/tests/R02.test.js @@ -37,7 +37,7 @@ describe('# R02', () => { }) // 修改 userController 中的資料庫連線設定,由連向真實的資料庫 -> 改為連向模擬的 User table - this.userController = createControllerProxy('../../controllers/userController', { User: this.UserMock }) + this.userController = createControllerProxy('../controllers/userController', { User: this.UserMock }) }) // 開始測試 @@ -82,7 +82,7 @@ describe('# R02', () => { }) // 連向模擬的 User table - this.userController = createControllerProxy('../../controllers/userController', { User: this.UserMock }) + this.userController = createControllerProxy('../controllers/userController', { User: this.UserMock }) }) it(' GET /users/:id/edit ', async () => { @@ -127,7 +127,7 @@ describe('# R02', () => { ) // 連向模擬的 User table - this.userController = createControllerProxy('../../controllers/userController', { User: this.UserMock }) + this.userController = createControllerProxy('../controllers/userController', { User: this.UserMock }) }) it(' PUT /users/:id ', async () => { From e45367f2d4a0648f534bab260eee5080c624a7bf Mon Sep 17 00:00:00 2001 From: Amber Yan Date: Mon, 1 Nov 2021 21:50:30 +0800 Subject: [PATCH 037/135] add mockRequest / mockResponse --- helpers/unitTestHelpers.js | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/helpers/unitTestHelpers.js b/helpers/unitTestHelpers.js index ea4cc7b1..35719e1a 100644 --- a/helpers/unitTestHelpers.js +++ b/helpers/unitTestHelpers.js @@ -79,7 +79,22 @@ const createControllerProxy = (path, model) => { return controller; } +const mockRequest = (query) => { + return { + ...query, + flash: sinon.spy(), + } +} +const mockResponse = () => { + return { + redirect: sinon.spy(), + render: sinon.spy(), + } +} + module.exports = { createModelMock, - createControllerProxy + createControllerProxy, + mockRequest, + mockResponse } \ No newline at end of file From d487f4afcdfd27e247aa57eef3a5caadb84c6a00 Mon Sep 17 00:00:00 2001 From: Amber Yan Date: Mon, 1 Nov 2021 21:51:23 +0800 Subject: [PATCH 038/135] use new mockRequest / mockResponse --- tests/R01.test.js | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/tests/R01.test.js b/tests/R01.test.js index f98a96ac..e9024d9e 100644 --- a/tests/R01.test.js +++ b/tests/R01.test.js @@ -4,19 +4,7 @@ const sinon = require('sinon') const should = chai.should() const app = require('../app') -const { createModelMock, createControllerProxy } = require('../helpers/unitTestHelpers'); - -const mockRequest = (query) => { - return { - ...query, - flash: sinon.spy(), - } -} -const mockResponse = () => { - return { - redirect: sinon.spy(), - } -} +const { createModelMock, createControllerProxy, mockRequest, mockResponse } = require('../helpers/unitTestHelpers'); describe('# R01', () => { describe('登入測試: POST /signin', function(){ @@ -159,8 +147,6 @@ describe('# R01', () => { // 將假資料撈出,比對確認有成功修改到 const user = await this.UserMock.findOne({ where: { id: 1 } }) user.isAdmin.should.equal(true) - - done() }) }) }) From 73fc123d27ccec774163b66a9a3c1eca7fe59e42 Mon Sep 17 00:00:00 2001 From: Amber Yan Date: Mon, 1 Nov 2021 21:57:12 +0800 Subject: [PATCH 039/135] require sinon --- helpers/unitTestHelpers.js | 1 + 1 file changed, 1 insertion(+) diff --git a/helpers/unitTestHelpers.js b/helpers/unitTestHelpers.js index 35719e1a..b6e47239 100644 --- a/helpers/unitTestHelpers.js +++ b/helpers/unitTestHelpers.js @@ -1,5 +1,6 @@ const SequelizeMock = require('sequelize-mock') const proxyquire = require('proxyquire') +const sinon = require('sinon') const dbMock = new SequelizeMock() From 5224b9a3e0866d314dd5346067c0de7f7a1fc25b Mon Sep 17 00:00:00 2001 From: Amber Yan Date: Mon, 1 Nov 2021 21:57:25 +0800 Subject: [PATCH 040/135] remove sinon --- tests/R01.test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/R01.test.js b/tests/R01.test.js index e9024d9e..0a15875b 100644 --- a/tests/R01.test.js +++ b/tests/R01.test.js @@ -1,6 +1,5 @@ const chai = require('chai') const request = require('supertest') -const sinon = require('sinon') const should = chai.should() const app = require('../app') From 5d61a3029bd40bc0d0ae59f334e248e2a4c5b800 Mon Sep 17 00:00:00 2001 From: Amber Yan Date: Mon, 1 Nov 2021 21:50:30 +0800 Subject: [PATCH 041/135] add mockRequest / mockResponse --- helpers/unitTestHelpers.js | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/helpers/unitTestHelpers.js b/helpers/unitTestHelpers.js index ea4cc7b1..35719e1a 100644 --- a/helpers/unitTestHelpers.js +++ b/helpers/unitTestHelpers.js @@ -79,7 +79,22 @@ const createControllerProxy = (path, model) => { return controller; } +const mockRequest = (query) => { + return { + ...query, + flash: sinon.spy(), + } +} +const mockResponse = () => { + return { + redirect: sinon.spy(), + render: sinon.spy(), + } +} + module.exports = { createModelMock, - createControllerProxy + createControllerProxy, + mockRequest, + mockResponse } \ No newline at end of file From 51b22d50df8eff05fc26944bfc502d53151c7b76 Mon Sep 17 00:00:00 2001 From: Amber Yan Date: Mon, 1 Nov 2021 21:51:23 +0800 Subject: [PATCH 042/135] use new mockRequest / mockResponse --- tests/R01.test.js | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/tests/R01.test.js b/tests/R01.test.js index f98a96ac..e9024d9e 100644 --- a/tests/R01.test.js +++ b/tests/R01.test.js @@ -4,19 +4,7 @@ const sinon = require('sinon') const should = chai.should() const app = require('../app') -const { createModelMock, createControllerProxy } = require('../helpers/unitTestHelpers'); - -const mockRequest = (query) => { - return { - ...query, - flash: sinon.spy(), - } -} -const mockResponse = () => { - return { - redirect: sinon.spy(), - } -} +const { createModelMock, createControllerProxy, mockRequest, mockResponse } = require('../helpers/unitTestHelpers'); describe('# R01', () => { describe('登入測試: POST /signin', function(){ @@ -159,8 +147,6 @@ describe('# R01', () => { // 將假資料撈出,比對確認有成功修改到 const user = await this.UserMock.findOne({ where: { id: 1 } }) user.isAdmin.should.equal(true) - - done() }) }) }) From eba6e760aa83e13ba046d6fafeb17560152d00e8 Mon Sep 17 00:00:00 2001 From: Amber Yan Date: Mon, 1 Nov 2021 21:57:12 +0800 Subject: [PATCH 043/135] require sinon --- helpers/unitTestHelpers.js | 1 + 1 file changed, 1 insertion(+) diff --git a/helpers/unitTestHelpers.js b/helpers/unitTestHelpers.js index 35719e1a..b6e47239 100644 --- a/helpers/unitTestHelpers.js +++ b/helpers/unitTestHelpers.js @@ -1,5 +1,6 @@ const SequelizeMock = require('sequelize-mock') const proxyquire = require('proxyquire') +const sinon = require('sinon') const dbMock = new SequelizeMock() From 70db2a5a30afc5be1c5eaa83ffe6b71ced12d8dd Mon Sep 17 00:00:00 2001 From: Amber Yan Date: Mon, 1 Nov 2021 21:57:25 +0800 Subject: [PATCH 044/135] remove sinon --- tests/R01.test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/R01.test.js b/tests/R01.test.js index e9024d9e..0a15875b 100644 --- a/tests/R01.test.js +++ b/tests/R01.test.js @@ -1,6 +1,5 @@ const chai = require('chai') const request = require('supertest') -const sinon = require('sinon') const should = chai.should() const app = require('../app') From 94b4d563a28a8ed36dabb695ffce20c94659f7ba Mon Sep 17 00:00:00 2001 From: Amber Yan Date: Mon, 1 Nov 2021 21:57:25 +0800 Subject: [PATCH 045/135] remove sinon --- tests/R01.test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/R01.test.js b/tests/R01.test.js index f98a96ac..3d8c0e04 100644 --- a/tests/R01.test.js +++ b/tests/R01.test.js @@ -1,6 +1,5 @@ const chai = require('chai') const request = require('supertest') -const sinon = require('sinon') const should = chai.should() const app = require('../app') From 2d1863180f319ed2a536ee1f37facf0d90c5bfed Mon Sep 17 00:00:00 2001 From: Amber Yan Date: Mon, 1 Nov 2021 21:50:30 +0800 Subject: [PATCH 046/135] add mockRequest / mockResponse --- helpers/unitTestHelpers.js | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/helpers/unitTestHelpers.js b/helpers/unitTestHelpers.js index ea4cc7b1..35719e1a 100644 --- a/helpers/unitTestHelpers.js +++ b/helpers/unitTestHelpers.js @@ -79,7 +79,22 @@ const createControllerProxy = (path, model) => { return controller; } +const mockRequest = (query) => { + return { + ...query, + flash: sinon.spy(), + } +} +const mockResponse = () => { + return { + redirect: sinon.spy(), + render: sinon.spy(), + } +} + module.exports = { createModelMock, - createControllerProxy + createControllerProxy, + mockRequest, + mockResponse } \ No newline at end of file From a79fdd0149d0e127598ef85d97d692ff0e04c558 Mon Sep 17 00:00:00 2001 From: Amber Yan Date: Mon, 1 Nov 2021 21:51:23 +0800 Subject: [PATCH 047/135] use new mockRequest / mockResponse --- tests/R01.test.js | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/tests/R01.test.js b/tests/R01.test.js index 3d8c0e04..0a15875b 100644 --- a/tests/R01.test.js +++ b/tests/R01.test.js @@ -3,19 +3,7 @@ const request = require('supertest') const should = chai.should() const app = require('../app') -const { createModelMock, createControllerProxy } = require('../helpers/unitTestHelpers'); - -const mockRequest = (query) => { - return { - ...query, - flash: sinon.spy(), - } -} -const mockResponse = () => { - return { - redirect: sinon.spy(), - } -} +const { createModelMock, createControllerProxy, mockRequest, mockResponse } = require('../helpers/unitTestHelpers'); describe('# R01', () => { describe('登入測試: POST /signin', function(){ @@ -158,8 +146,6 @@ describe('# R01', () => { // 將假資料撈出,比對確認有成功修改到 const user = await this.UserMock.findOne({ where: { id: 1 } }) user.isAdmin.should.equal(true) - - done() }) }) }) From 7fef8c78760f41165f1ca6c0b7f884f73b862feb Mon Sep 17 00:00:00 2001 From: Amber Yan Date: Mon, 1 Nov 2021 21:57:12 +0800 Subject: [PATCH 048/135] require sinon --- helpers/unitTestHelpers.js | 1 + 1 file changed, 1 insertion(+) diff --git a/helpers/unitTestHelpers.js b/helpers/unitTestHelpers.js index 35719e1a..b6e47239 100644 --- a/helpers/unitTestHelpers.js +++ b/helpers/unitTestHelpers.js @@ -1,5 +1,6 @@ const SequelizeMock = require('sequelize-mock') const proxyquire = require('proxyquire') +const sinon = require('sinon') const dbMock = new SequelizeMock() From c8beeb246238b869815f97322ec374ca74c08007 Mon Sep 17 00:00:00 2001 From: Amber Yan Date: Mon, 1 Nov 2021 21:50:30 +0800 Subject: [PATCH 049/135] add mockRequest / mockResponse --- helpers/unitTestHelpers.js | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/helpers/unitTestHelpers.js b/helpers/unitTestHelpers.js index ea4cc7b1..35719e1a 100644 --- a/helpers/unitTestHelpers.js +++ b/helpers/unitTestHelpers.js @@ -79,7 +79,22 @@ const createControllerProxy = (path, model) => { return controller; } +const mockRequest = (query) => { + return { + ...query, + flash: sinon.spy(), + } +} +const mockResponse = () => { + return { + redirect: sinon.spy(), + render: sinon.spy(), + } +} + module.exports = { createModelMock, - createControllerProxy + createControllerProxy, + mockRequest, + mockResponse } \ No newline at end of file From 3a85cde88da61cc277afc5c97d49aea013f64bea Mon Sep 17 00:00:00 2001 From: Amber Yan Date: Mon, 1 Nov 2021 21:51:23 +0800 Subject: [PATCH 050/135] use new mockRequest / mockResponse --- tests/R01.test.js | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/tests/R01.test.js b/tests/R01.test.js index f98a96ac..e9024d9e 100644 --- a/tests/R01.test.js +++ b/tests/R01.test.js @@ -4,19 +4,7 @@ const sinon = require('sinon') const should = chai.should() const app = require('../app') -const { createModelMock, createControllerProxy } = require('../helpers/unitTestHelpers'); - -const mockRequest = (query) => { - return { - ...query, - flash: sinon.spy(), - } -} -const mockResponse = () => { - return { - redirect: sinon.spy(), - } -} +const { createModelMock, createControllerProxy, mockRequest, mockResponse } = require('../helpers/unitTestHelpers'); describe('# R01', () => { describe('登入測試: POST /signin', function(){ @@ -159,8 +147,6 @@ describe('# R01', () => { // 將假資料撈出,比對確認有成功修改到 const user = await this.UserMock.findOne({ where: { id: 1 } }) user.isAdmin.should.equal(true) - - done() }) }) }) From 61c6de70d674a847ed540826c75a2a3e5f24f79f Mon Sep 17 00:00:00 2001 From: Amber Yan Date: Mon, 1 Nov 2021 21:57:12 +0800 Subject: [PATCH 051/135] require sinon --- helpers/unitTestHelpers.js | 1 + 1 file changed, 1 insertion(+) diff --git a/helpers/unitTestHelpers.js b/helpers/unitTestHelpers.js index 35719e1a..b6e47239 100644 --- a/helpers/unitTestHelpers.js +++ b/helpers/unitTestHelpers.js @@ -1,5 +1,6 @@ const SequelizeMock = require('sequelize-mock') const proxyquire = require('proxyquire') +const sinon = require('sinon') const dbMock = new SequelizeMock() From 892762191bf197205484e6fd170b028eb64298a5 Mon Sep 17 00:00:00 2001 From: Amber Yan Date: Mon, 1 Nov 2021 21:57:25 +0800 Subject: [PATCH 052/135] remove sinon --- tests/R01.test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/R01.test.js b/tests/R01.test.js index e9024d9e..0a15875b 100644 --- a/tests/R01.test.js +++ b/tests/R01.test.js @@ -1,6 +1,5 @@ const chai = require('chai') const request = require('supertest') -const sinon = require('sinon') const should = chai.should() const app = require('../app') From 9bf30ca0089c2c21723f40d14d75ee768d209c98 Mon Sep 17 00:00:00 2001 From: Amber Yan Date: Mon, 1 Nov 2021 22:34:38 +0800 Subject: [PATCH 053/135] return [defaulvalue] when findall data empty --- helpers/unitTestHelpers.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/helpers/unitTestHelpers.js b/helpers/unitTestHelpers.js index b6e47239..4a777f4c 100644 --- a/helpers/unitTestHelpers.js +++ b/helpers/unitTestHelpers.js @@ -33,6 +33,9 @@ const createModelMock = (name, defaultValue, data, joinedTableName) => { return Promise.resolve(data.map(d => mockModel.build(d))) } else if (query === 'findAll') { // 回傳模擬資料 + if (!data) { + return mockModel.build([defaultValue]); + } return Promise.resolve( data ? data.map(d => mockModel.build(d)) : []) }else if (query === 'destroy') { // destroy 可以從 where 取得要刪除的資料 @@ -57,6 +60,9 @@ const createModelMock = (name, defaultValue, data, joinedTableName) => { return Promise.resolve(mockModel.build(data)) } else if (query === 'findAll') { // 回傳模擬資料 + if (!data) { + return mockModel.build([defaultValue]); + } return Promise.resolve(data ? data.map(d => mockModel.build(d)) : []) } else if (query === 'destroy') { // destroy 可以從 where 取得要刪除的資料 From 05b87a2915b4d920a79e74797bd3a74574740c0f Mon Sep 17 00:00:00 2001 From: Amber Yan Date: Tue, 2 Nov 2021 19:53:43 +0800 Subject: [PATCH 054/135] remove done param --- tests/R01.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/R01.test.js b/tests/R01.test.js index 0a15875b..2765ccfb 100644 --- a/tests/R01.test.js +++ b/tests/R01.test.js @@ -128,7 +128,7 @@ describe('# R01', () => { this.adminController = createControllerProxy('../controllers/adminController', { User: this.UserMock }) }) - it(' PUT /admin/users/:id/toggleAdmin ', async (done) => { + it(' PUT /admin/users/:id/toggleAdmin ', async () => { // 模擬 request & response const req = mockRequest({ params: { id: 1 } }) // 帶入 params.id = 1,對 PUT /admin/users/1/toggleAdmin 發出請求 const res = mockResponse() From c014106ac7ed2244dbdf154ab97ba867fdfbe076 Mon Sep 17 00:00:00 2001 From: Amber Yan Date: Tue, 2 Nov 2021 19:53:43 +0800 Subject: [PATCH 055/135] remove done param --- tests/R01.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/R01.test.js b/tests/R01.test.js index 0a15875b..2765ccfb 100644 --- a/tests/R01.test.js +++ b/tests/R01.test.js @@ -128,7 +128,7 @@ describe('# R01', () => { this.adminController = createControllerProxy('../controllers/adminController', { User: this.UserMock }) }) - it(' PUT /admin/users/:id/toggleAdmin ', async (done) => { + it(' PUT /admin/users/:id/toggleAdmin ', async () => { // 模擬 request & response const req = mockRequest({ params: { id: 1 } }) // 帶入 params.id = 1,對 PUT /admin/users/1/toggleAdmin 發出請求 const res = mockResponse() From 6eecc8ae14c26000f3a6cc22f2d0baa6b3df4dc3 Mon Sep 17 00:00:00 2001 From: Amber Yan Date: Tue, 2 Nov 2021 19:53:43 +0800 Subject: [PATCH 056/135] remove done param --- tests/R01.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/R01.test.js b/tests/R01.test.js index 0a15875b..2765ccfb 100644 --- a/tests/R01.test.js +++ b/tests/R01.test.js @@ -128,7 +128,7 @@ describe('# R01', () => { this.adminController = createControllerProxy('../controllers/adminController', { User: this.UserMock }) }) - it(' PUT /admin/users/:id/toggleAdmin ', async (done) => { + it(' PUT /admin/users/:id/toggleAdmin ', async () => { // 模擬 request & response const req = mockRequest({ params: { id: 1 } }) // 帶入 params.id = 1,對 PUT /admin/users/1/toggleAdmin 發出請求 const res = mockResponse() From a04125fba9446382179d3c3d3661219eda0975b4 Mon Sep 17 00:00:00 2001 From: Amber Yan Date: Tue, 2 Nov 2021 19:53:43 +0800 Subject: [PATCH 057/135] remove done param --- tests/R01.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/R01.test.js b/tests/R01.test.js index 0a15875b..2765ccfb 100644 --- a/tests/R01.test.js +++ b/tests/R01.test.js @@ -128,7 +128,7 @@ describe('# R01', () => { this.adminController = createControllerProxy('../controllers/adminController', { User: this.UserMock }) }) - it(' PUT /admin/users/:id/toggleAdmin ', async (done) => { + it(' PUT /admin/users/:id/toggleAdmin ', async () => { // 模擬 request & response const req = mockRequest({ params: { id: 1 } }) // 帶入 params.id = 1,對 PUT /admin/users/1/toggleAdmin 發出請求 const res = mockResponse() From a1cf9c3e517a11d3844a39377fe62f42ad2c3956 Mon Sep 17 00:00:00 2001 From: Carrot7712 Date: Wed, 3 Nov 2021 15:28:42 +0800 Subject: [PATCH 058/135] update readme config.json package.json --- README.md | 26 +- config/config.json | 14 +- package-lock.json | 2540 +------------------------------------------- package.json | 28 +- 4 files changed, 39 insertions(+), 2569 deletions(-) diff --git a/README.md b/README.md index e4cd70f1..9172af88 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,6 @@ 1. Fork 2. git clone -3. 更改專案名稱 ## 初始化 ### Initialize @@ -16,14 +15,6 @@ npm install ``` create database forum; -create database forum_test; -``` - -### 切換環境 - -``` -export NODE_ENV=test # 切換到測試環境,如果在等號後加其他的字串,則會切到其他的環境 -echo $NODE_ENV # 印出目前使用的環境 ``` ### 執行測試 @@ -32,11 +23,11 @@ npm run test ``` ## 下載作業規格 -以 A17 為例 +以 R01 為例 ``` -git checkout -b A17 # 開新分支 -git merge origin/A17-test # 下載作業規格 +git checkout -b R01 # 開新分支 +git merge origin/R01-test # 下載作業規格 npm run test # 直到綠燈全亮 git add . @@ -46,11 +37,16 @@ git commit -m "...." ## 繳交作業 ``` -git push origin A17 # 上傳本地進度 +git push origin R01 # 上傳本地進度 ``` 接著改成到 GitHub 來發 PR。 ## 共用帳號 -請一律設定一個共用的 root user -root@example.com,登入密碼 12345678 +請一律設定下面 2 組帳號以利驗收: +* 第一組帳號有 admin 權限: + * email: root@example.com + * password: 12345678 +* 第二組帳號沒有 admin 權限: + * email: user1@example.com + * password: 12345678 \ No newline at end of file diff --git a/config/config.json b/config/config.json index 56636a1c..2b8be8e7 100644 --- a/config/config.json +++ b/config/config.json @@ -6,16 +6,12 @@ "host": "127.0.0.1", "dialect": "mysql" }, - "test": { + "production": { "username": "root", - "password": "password", - "database": "forum_test", + "password": null, + "database": "database_production", "host": "127.0.0.1", - "dialect": "mysql", - "logging": false - }, - "production": { - "use_env_variable": "CLEARDB_SILVER_URL" + "dialect": "mysql" }, "travis": { "username": "travis", @@ -24,4 +20,4 @@ "dialect": "mysql", "logging": false } -} \ No newline at end of file +} diff --git a/package-lock.json b/package-lock.json index 7ebc04a3..bb00f848 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,2480 +1,8 @@ { "name": "forum-express-workspace", "version": "1.0.0", - "lockfileVersion": 2, + "lockfileVersion": 1, "requires": true, - "packages": { - "": { - "name": "forum-express-workspace", - "version": "1.0.0", - "license": "ISC", - "dependencies": { - "chai": "^4.2.0", - "express": "^4.17.1", - "mocha": "^8.2.0", - "mysql2": "^2.2.5", - "sequelize": "^6.3.5", - "sequelize-cli": "^6.2.0", - "sinon": "^9.2.0", - "supertest": "^5.0.0" - }, - "devDependencies": { - "proxyquire": "^2.1.3", - "sequelize-mock": "^0.10.2" - } - }, - "node_modules/@sinonjs/commons": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.1.tgz", - "integrity": "sha512-892K+kWUUi3cl+LlqEWIDrhvLgdL79tECi8JZUyq6IviKy/DNhuzCRlbHUjxK89f4ypPMMaFnFuR9Ie6DoIMsw==", - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@sinonjs/fake-timers": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", - "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", - "dependencies": { - "@sinonjs/commons": "^1.7.0" - } - }, - "node_modules/@sinonjs/formatio": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-5.0.1.tgz", - "integrity": "sha512-KaiQ5pBf1MpS09MuA0kp6KBQt2JUOQycqVG1NZXvzeaXe5LGFqAKueIS0bw4w0P9r7KuBSVdUk5QjXsUdu2CxQ==", - "dependencies": { - "@sinonjs/commons": "^1", - "@sinonjs/samsam": "^5.0.2" - } - }, - "node_modules/@sinonjs/samsam": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-5.2.0.tgz", - "integrity": "sha512-CaIcyX5cDsjcW/ab7HposFWzV1kC++4HNsfnEdFJa7cP1QIuILAKV+BgfeqRXhcnSAc76r/Rh/O5C+300BwUIw==", - "dependencies": { - "@sinonjs/commons": "^1.6.0", - "lodash.get": "^4.4.2", - "type-detect": "^4.0.8" - } - }, - "node_modules/@sinonjs/text-encoding": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", - "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==" - }, - "node_modules/@types/node": { - "version": "14.14.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.5.tgz", - "integrity": "sha512-H5Wn24s/ZOukBmDn03nnGTp18A60ny9AmCwnEcgJiTgSGsCO7k+NWP7zjCCbhlcnVCoI+co52dUAt9GMhOSULw==" - }, - "node_modules/@ungap/promise-all-settled": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", - "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==" - }, - "node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" - }, - "node_modules/accepts": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", - "dependencies": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=" - }, - "node_modules/anymatch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", - "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" - }, - "node_modules/assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "engines": { - "node": "*" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, - "node_modules/balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" - }, - "node_modules/binary-extensions": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", - "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" - }, - "node_modules/body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", - "dependencies": { - "bytes": "3.1.0", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.7.0", - "raw-body": "2.4.0", - "type-is": "~1.6.17" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==" - }, - "node_modules/bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/chai": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", - "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", - "dependencies": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.2", - "deep-eql": "^3.0.1", - "get-func-name": "^2.0.0", - "pathval": "^1.1.0", - "type-detect": "^4.0.5" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chalk/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/chalk/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/chalk/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/check-error": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", - "engines": { - "node": "*" - } - }, - "node_modules/chokidar": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz", - "integrity": "sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==", - "dependencies": { - "anymatch": "~3.1.1", - "braces": "~3.0.2", - "glob-parent": "~5.1.0", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.5.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.1.2" - } - }, - "node_modules/cli-color": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-1.4.0.tgz", - "integrity": "sha512-xu6RvQqqrWEo6MPR1eixqGPywhYBHRs653F9jfXB2Hx4jdM/3WxiNE1vppRmxtMIfl16SFYTpYlrnqH/HsK/2w==", - "dependencies": { - "ansi-regex": "^2.1.1", - "d": "1", - "es5-ext": "^0.10.46", - "es6-iterator": "^2.0.3", - "memoizee": "^0.4.14", - "timers-ext": "^0.1.5" - } - }, - "node_modules/cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", - "dependencies": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - }, - "node_modules/component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "node_modules/config-chain": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz", - "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==", - "dependencies": { - "ini": "^1.3.4", - "proto-list": "~1.2.1" - } - }, - "node_modules/content-disposition": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", - "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", - "dependencies": { - "safe-buffer": "5.1.2" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/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==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" - }, - "node_modules/cookiejar": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz", - "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==" - }, - "node_modules/d": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", - "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", - "dependencies": { - "es5-ext": "^0.10.50", - "type": "^1.0.1" - } - }, - "node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/deep-eql": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", - "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", - "dependencies": { - "type-detect": "^4.0.0" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/denque": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/denque/-/denque-1.4.1.tgz", - "integrity": "sha512-OfzPuSZKGcgr96rf1oODnfjqBFmr1DVoc/TrItj3Ohe0Ah1C5WX5Baquw/9U9KovnQ88EqmJbD66rKYUQYN1tQ==", - "engines": { - "node": ">=0.10" - } - }, - "node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" - }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/dottie": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.2.tgz", - "integrity": "sha512-fmrwR04lsniq/uSr8yikThDTrM7epXHBAAjH9TbeH3rEA8tdCO7mRzB9hdmdGyJCxF8KERo9CITcm3kGuoyMhg==" - }, - "node_modules/editorconfig": { - "version": "0.15.3", - "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz", - "integrity": "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==", - "dependencies": { - "commander": "^2.19.0", - "lru-cache": "^4.1.5", - "semver": "^5.6.0", - "sigmund": "^1.0.1" - }, - "bin": { - "editorconfig": "bin/editorconfig" - } - }, - "node_modules/editorconfig/node_modules/lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dependencies": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "node_modules/editorconfig/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/editorconfig/node_modules/yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" - }, - "node_modules/emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" - }, - "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/es5-ext": { - "version": "0.10.53", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", - "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", - "dependencies": { - "es6-iterator": "~2.0.3", - "es6-symbol": "~3.1.3", - "next-tick": "~1.0.0" - } - }, - "node_modules/es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", - "dependencies": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, - "node_modules/es6-symbol": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", - "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", - "dependencies": { - "d": "^1.0.1", - "ext": "^1.1.2" - } - }, - "node_modules/es6-weak-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", - "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", - "dependencies": { - "d": "1", - "es5-ext": "^0.10.46", - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.1" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/event-emitter": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", - "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", - "dependencies": { - "d": "1", - "es5-ext": "~0.10.14" - } - }, - "node_modules/express": { - "version": "4.17.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", - "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", - "dependencies": { - "accepts": "~1.3.7", - "array-flatten": "1.1.1", - "body-parser": "1.19.0", - "content-disposition": "0.5.3", - "content-type": "~1.0.4", - "cookie": "0.4.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "~1.1.2", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "~1.1.2", - "fresh": "0.5.2", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.5", - "qs": "6.7.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.1.2", - "send": "0.17.1", - "serve-static": "1.14.1", - "setprototypeof": "1.1.1", - "statuses": "~1.5.0", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/ext": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", - "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", - "dependencies": { - "type": "^2.0.0" - } - }, - "node_modules/ext/node_modules/type": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/type/-/type-2.1.0.tgz", - "integrity": "sha512-G9absDWvhAWCV2gmF1zKud3OyC61nZDwWvBL2DApaVFogI07CprggiQAOOjvp2NRjYWFzPyu7vwtDrQFq8jeSA==" - }, - "node_modules/fast-safe-stringify": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", - "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==" - }, - "node_modules/fill-keys": { - "version": "1.0.2", - "resolved": "http://npm.ooapi.com:4873/fill-keys/-/fill-keys-1.0.2.tgz", - "integrity": "sha1-mo+jb06K1jTjv2tPPIiCVRRS6yA=", - "dev": true, - "dependencies": { - "is-object": "~1.0.1", - "merge-descriptors": "~1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dependencies": { - "locate-path": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "bin": { - "flat": "cli.js" - } - }, - "node_modules/form-data": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.0.tgz", - "integrity": "sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/formidable": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.2.tgz", - "integrity": "sha512-V8gLm+41I/8kguQ4/o1D3RIHRmhYFG4pnNyonvua+40rqcEmT4+V71yaZ3B457xbbgCsCfjSPi65u/W6vK1U5Q==", - "funding": { - "url": "https://ko-fi.com/tunnckoCore/commissions" - } - }, - "node_modules/forwarded": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", - "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fs-extra": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", - "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", - "dependencies": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "node_modules/fsevents": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", - "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", - "deprecated": "\"Please update to latest v2.3 or v2.2\"", - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "node_modules/generate-function": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", - "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", - "dependencies": { - "is-property": "^1.0.2" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-func-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", - "engines": { - "node": "*" - } - }, - "node_modules/glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==" - }, - "node_modules/growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", - "engines": { - "node": ">=4.x" - } - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "bin": { - "he": "bin/he" - } - }, - "node_modules/http-errors": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", - "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/inflection": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz", - "integrity": "sha1-ogCTVlbW9fa8TcdQLhrstwMihBY=", - "engines": [ - "node >= 0.4.0" - ] - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "node_modules/ini": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", - "deprecated": "Please update to ini >=1.3.6 to avoid a prototype pollution issue", - "engines": { - "node": "*" - } - }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-core-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.0.0.tgz", - "integrity": "sha512-jq1AH6C8MuteOoBPwkxHafmByhL9j5q4OaPGdbuD+ZtQJVzH+i6E3BJDQcBA09k57i2Hh2yQbEG8yObZ0jdlWw==", - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "engines": { - "node": ">=4" - } - }, - "node_modules/is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-object": { - "version": "1.0.2", - "resolved": "http://npm.ooapi.com:4873/is-object/-/is-object-1.0.2.tgz", - "integrity": "sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-promise": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", - "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==" - }, - "node_modules/is-property": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", - "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=" - }, - "node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" - }, - "node_modules/js-beautify": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.13.0.tgz", - "integrity": "sha512-/Tbp1OVzZjbwzwJQFIlYLm9eWQ+3aYbBXLSaqb1mEJzhcQAfrqMMQYtjb6io+U6KpD0ID4F+Id3/xcjH3l/sqA==", - "dependencies": { - "config-chain": "^1.1.12", - "editorconfig": "^0.15.3", - "glob": "^7.1.3", - "mkdirp": "^1.0.4", - "nopt": "^5.0.0" - }, - "bin": { - "css-beautify": "js/bin/css-beautify.js", - "html-beautify": "js/bin/html-beautify.js", - "js-beautify": "js/bin/js-beautify.js" - } - }, - "node_modules/js-yaml": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", - "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/just-extend": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.1.1.tgz", - "integrity": "sha512-aWgeGFW67BP3e5181Ep1Fv2v8z//iBJfrvyTnq8wG86vEESwmonn1zPBJ0VfmT9CJq2FIT0VsETtrNFm2a+SHA==" - }, - "node_modules/locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/lodash": { - "version": "4.17.20", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", - "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" - }, - "node_modules/lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" - }, - "node_modules/log-symbols": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", - "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==", - "dependencies": { - "chalk": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/long": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", - "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/lru-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", - "integrity": "sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM=", - "dependencies": { - "es5-ext": "~0.10.2" - } - }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/memoizee": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.14.tgz", - "integrity": "sha512-/SWFvWegAIYAO4NQMpcX+gcra0yEZu4OntmUdrBaWrJncxOqAziGFlHxc7yjKVK2uu3lpPW27P27wkR82wA8mg==", - "dependencies": { - "d": "1", - "es5-ext": "^0.10.45", - "es6-weak-map": "^2.0.2", - "event-emitter": "^0.3.5", - "is-promise": "^2.1", - "lru-queue": "0.1", - "next-tick": "1", - "timers-ext": "^0.1.5" - } - }, - "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/mime-db": { - "version": "1.44.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", - "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.27", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", - "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", - "dependencies": { - "mime-db": "1.44.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mocha": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.2.0.tgz", - "integrity": "sha512-lEWEMq2LMfNJMKeuEwb5UELi+OgFDollXaytR5ggQcHpzG3NP/R7rvixAvF+9/lLsTWhWG+4yD2M70GsM06nxw==", - "dependencies": { - "@ungap/promise-all-settled": "1.1.2", - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.4.3", - "debug": "4.2.0", - "diff": "4.0.2", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.1.6", - "growl": "1.10.5", - "he": "1.2.0", - "js-yaml": "3.14.0", - "log-symbols": "4.0.0", - "minimatch": "3.0.4", - "ms": "2.1.2", - "nanoid": "3.1.12", - "serialize-javascript": "5.0.1", - "strip-json-comments": "3.1.1", - "supports-color": "7.2.0", - "which": "2.0.2", - "wide-align": "1.1.3", - "workerpool": "6.0.2", - "yargs": "13.3.2", - "yargs-parser": "13.1.2", - "yargs-unparser": "2.0.0" - }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha" - }, - "engines": { - "node": ">= 10.12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mochajs" - } - }, - "node_modules/mocha/node_modules/debug": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", - "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", - "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/mocha/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mocha/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mocha/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/mocha/node_modules/p-limit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.0.2.tgz", - "integrity": "sha512-iwqZSOoWIW+Ew4kAGUlN16J4M7OB3ysMLSZtnhmqx7njIHFPlxWBX8xo3lVTyFVq6mI/lL9qt2IsN1sHwaxJkg==", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mocha/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mocha/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "engines": { - "node": ">=8" - } - }, - "node_modules/module-not-found-error": { - "version": "1.0.1", - "resolved": "http://npm.ooapi.com:4873/module-not-found-error/-/module-not-found-error-1.0.1.tgz", - "integrity": "sha1-z4tP9PKWQGdNbN0CsOO8UjwrvcA=", - "dev": true - }, - "node_modules/moment": { - "version": "2.29.1", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", - "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==", - "engines": { - "node": "*" - } - }, - "node_modules/moment-timezone": { - "version": "0.5.31", - "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.31.tgz", - "integrity": "sha512-+GgHNg8xRhMXfEbv81iDtrVeTcWt0kWmTEY1XQK14dICTXnWJnT0dxdlPspwqF3keKMVPXwayEsk1DI0AA/jdA==", - "dependencies": { - "moment": ">= 2.9.0" - }, - "engines": { - "node": "*" - } - }, - "node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "node_modules/mysql2": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-2.2.5.tgz", - "integrity": "sha512-XRqPNxcZTpmFdXbJqb+/CtYVLCx14x1RTeNMD4954L331APu75IC74GDqnZMEt1kwaXy6TySo55rF2F3YJS78g==", - "dependencies": { - "denque": "^1.4.1", - "generate-function": "^2.3.1", - "iconv-lite": "^0.6.2", - "long": "^4.0.0", - "lru-cache": "^6.0.0", - "named-placeholders": "^1.1.2", - "seq-queue": "^0.0.5", - "sqlstring": "^2.3.2" - }, - "engines": { - "node": ">= 8.0" - } - }, - "node_modules/mysql2/node_modules/iconv-lite": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz", - "integrity": "sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/named-placeholders": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.2.tgz", - "integrity": "sha512-wiFWqxoLL3PGVReSZpjLVxyJ1bRqe+KKJVbr4hGs1KWfTZTQyezHFBbuKj9hsizHyGV2ne7EMjHdxEGAybD5SA==", - "dependencies": { - "lru-cache": "^4.1.3" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/named-placeholders/node_modules/lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dependencies": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "node_modules/named-placeholders/node_modules/yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" - }, - "node_modules/nanoid": { - "version": "3.1.12", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.12.tgz", - "integrity": "sha512-1qstj9z5+x491jfiC4Nelk+f8XBad7LN20PmyWINJEMRSf3wcAjAWysw1qaA8z6NSKe2sjq1hRSDpBH5paCb6A==", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || >=13.7" - } - }, - "node_modules/negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/next-tick": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", - "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" - }, - "node_modules/nise": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/nise/-/nise-4.0.4.tgz", - "integrity": "sha512-bTTRUNlemx6deJa+ZyoCUTRvH3liK5+N6VQZ4NIw90AgDXY6iPnsqplNFf6STcj+ePk0H/xqxnP75Lr0J0Fq3A==", - "dependencies": { - "@sinonjs/commons": "^1.7.0", - "@sinonjs/fake-timers": "^6.0.0", - "@sinonjs/text-encoding": "^0.7.1", - "just-extend": "^4.0.2", - "path-to-regexp": "^1.7.0" - } - }, - "node_modules/nise/node_modules/path-to-regexp": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", - "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", - "dependencies": { - "isarray": "0.0.1" - } - }, - "node_modules/nopt": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", - "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", - "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dependencies": { - "p-limit": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "engines": { - "node": ">=6" - } - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "engines": { - "node": ">=4" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" - }, - "node_modules/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=" - }, - "node_modules/pathval": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", - "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", - "engines": { - "node": "*" - } - }, - "node_modules/picomatch": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/proto-list": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", - "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=" - }, - "node_modules/proxy-addr": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", - "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", - "dependencies": { - "forwarded": "~0.1.2", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/proxyquire": { - "version": "2.1.3", - "resolved": "http://npm.ooapi.com:4873/proxyquire/-/proxyquire-2.1.3.tgz", - "integrity": "sha512-BQWfCqYM+QINd+yawJz23tbBM40VIGXOdDw3X344KcclI/gtBbdWF6SlQ4nK/bYhF9d27KYug9WzljHC6B9Ysg==", - "dev": true, - "dependencies": { - "fill-keys": "^1.0.2", - "module-not-found-error": "^1.0.1", - "resolve": "^1.11.1" - } - }, - "node_modules/pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" - }, - "node_modules/qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", - "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", - "dependencies": { - "bytes": "3.1.0", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/readdirp": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", - "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" - }, - "node_modules/resolve": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.18.1.tgz", - "integrity": "sha512-lDfCPaMKfOJXjy0dPayzPdF1phampNWr3qFCjAu+rw/qbQmr5jWH5xN2hwh9QKfw9E5v4hwV7A+jrCmL8yjjqA==", - "dependencies": { - "is-core-module": "^2.0.0", - "path-parse": "^1.0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/retry-as-promised": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/retry-as-promised/-/retry-as-promised-3.2.0.tgz", - "integrity": "sha512-CybGs60B7oYU/qSQ6kuaFmRd9sTZ6oXSc0toqePvV74Ac6/IFZSI1ReFQmtCN+uvW1Mtqdwpvt/LGOiCBAY2Mg==", - "dependencies": { - "any-promise": "^1.3.0" - } - }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "node_modules/semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/send": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", - "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", - "dependencies": { - "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "~1.7.2", - "mime": "1.6.0", - "ms": "2.1.1", - "on-finished": "~2.3.0", - "range-parser": "~1.2.1", - "statuses": "~1.5.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/send/node_modules/ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" - }, - "node_modules/seq-queue": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", - "integrity": "sha1-1WgS4cAXpuTnw+Ojeh2m143TyT4=" - }, - "node_modules/sequelize": { - "version": "6.3.5", - "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-6.3.5.tgz", - "integrity": "sha512-MiwiPkYSA8NWttRKAXdU9h0TxP6HAc1fl7qZmMO/VQqQOND83G4nZLXd0kWILtAoT9cxtZgFqeb/MPYgEeXwsw==", - "dependencies": { - "debug": "^4.1.1", - "dottie": "^2.0.0", - "inflection": "1.12.0", - "lodash": "^4.17.15", - "moment": "^2.26.0", - "moment-timezone": "^0.5.31", - "retry-as-promised": "^3.2.0", - "semver": "^7.3.2", - "sequelize-pool": "^6.0.0", - "toposort-class": "^1.0.1", - "uuid": "^8.1.0", - "validator": "^10.11.0", - "wkx": "^0.5.0" - }, - "engines": { - "node": ">=10.0.0" - }, - "peerDependenciesMeta": { - "mariadb": { - "optional": true - }, - "mysql2": { - "optional": true - }, - "pg": { - "optional": true - }, - "pg-hstore": { - "optional": true - }, - "sqlite3": { - "optional": true - }, - "tedious": { - "optional": true - } - } - }, - "node_modules/sequelize-cli": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/sequelize-cli/-/sequelize-cli-6.2.0.tgz", - "integrity": "sha512-6WQ2x91hg30dUn66mXHnzvHATZ4pyI1GHSNbS/TNN/vRR4BLRSLijadeMgC8zqmKDsL0VqzVVopJWfJakuP++Q==", - "dependencies": { - "cli-color": "^1.4.0", - "fs-extra": "^7.0.1", - "js-beautify": "^1.8.8", - "lodash": "^4.17.5", - "resolve": "^1.5.0", - "umzug": "^2.3.0", - "yargs": "^13.1.0" - }, - "bin": { - "sequelize": "lib/sequelize", - "sequelize-cli": "lib/sequelize" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/sequelize-mock": { - "version": "0.10.2", - "resolved": "http://npm.ooapi.com:4873/sequelize-mock/-/sequelize-mock-0.10.2.tgz", - "integrity": "sha1-GdOXHM2utbhkFwwkznkqinHxRL0=", - "dev": true, - "dependencies": { - "bluebird": "^3.4.6", - "inflection": "^1.10.0", - "lodash": "^4.16.4" - } - }, - "node_modules/sequelize-pool": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/sequelize-pool/-/sequelize-pool-6.1.0.tgz", - "integrity": "sha512-4YwEw3ZgK/tY/so+GfnSgXkdwIJJ1I32uZJztIEgZeAO6HMgj64OzySbWLgxj+tXhZCJnzRfkY9gINw8Ft8ZMg==", - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/sequelize/node_modules/debug": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", - "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", - "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/sequelize/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/serialize-javascript": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", - "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/serve-static": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", - "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", - "dependencies": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.17.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" - }, - "node_modules/setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" - }, - "node_modules/sigmund": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", - "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=" - }, - "node_modules/sinon": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-9.2.0.tgz", - "integrity": "sha512-eSNXz1XMcGEMHw08NJXSyTHIu6qTCOiN8x9ODACmZpNQpr0aXTBXBnI4xTzQzR+TEpOmLiKowGf9flCuKIzsbw==", - "dependencies": { - "@sinonjs/commons": "^1.8.1", - "@sinonjs/fake-timers": "^6.0.1", - "@sinonjs/formatio": "^5.0.1", - "@sinonjs/samsam": "^5.2.0", - "diff": "^4.0.2", - "nise": "^4.0.4", - "supports-color": "^7.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/sinon" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" - }, - "node_modules/sqlstring": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.2.tgz", - "integrity": "sha512-vF4ZbYdKS8OnoJAWBmMxCQDkiEBkGQYU7UZPtL8flbDRSNkhaXvRJ279ZtI6M+zDaQovVU4tuRgzK5fVhvFAhg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string_decoder/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dependencies": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dependencies": { - "ansi-regex": "^4.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-ansi/node_modules/ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/superagent": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/superagent/-/superagent-6.1.0.tgz", - "integrity": "sha512-OUDHEssirmplo3F+1HWKUrUjvnQuA+nZI6i/JJBdXb5eq9IyEQwPyPpqND+SSsxf6TygpBEkUjISVRN4/VOpeg==", - "dependencies": { - "component-emitter": "^1.3.0", - "cookiejar": "^2.1.2", - "debug": "^4.1.1", - "fast-safe-stringify": "^2.0.7", - "form-data": "^3.0.0", - "formidable": "^1.2.2", - "methods": "^1.1.2", - "mime": "^2.4.6", - "qs": "^6.9.4", - "readable-stream": "^3.6.0", - "semver": "^7.3.2" - }, - "engines": { - "node": ">= 7.0.0" - } - }, - "node_modules/superagent/node_modules/debug": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", - "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", - "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/superagent/node_modules/mime": { - "version": "2.4.6", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz", - "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/superagent/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/superagent/node_modules/qs": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz", - "integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==", - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/supertest": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/supertest/-/supertest-5.0.0.tgz", - "integrity": "sha512-2JAWpPrUOZF4hHH5ZTCN2xjKXvJS3AEwPNXl0HUseHsfcXFvMy9kcsufIHCNAmQ5hlGCvgeAqaR5PBEouN3hlQ==", - "dependencies": { - "methods": "1.1.2", - "superagent": "6.1.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/timers-ext": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz", - "integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==", - "dependencies": { - "es5-ext": "~0.10.46", - "next-tick": "1" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/toposort-class": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toposort-class/-/toposort-class-1.0.1.tgz", - "integrity": "sha1-f/0feMi+KMO6Rc1OGj9e4ZO9mYg=" - }, - "node_modules/type": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", - "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" - }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "engines": { - "node": ">=4" - } - }, - "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/umzug": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/umzug/-/umzug-2.3.0.tgz", - "integrity": "sha512-Z274K+e8goZK8QJxmbRPhl89HPO1K+ORFtm6rySPhFKfKc5GHhqdzD0SGhSWHkzoXasqJuItdhorSvY7/Cgflw==", - "dependencies": { - "bluebird": "^3.7.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/uuid": { - "version": "8.3.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.1.tgz", - "integrity": "sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg==", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/validator": { - "version": "10.11.0", - "resolved": "https://registry.npmjs.org/validator/-/validator-10.11.0.tgz", - "integrity": "sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw==", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" - }, - "node_modules/wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", - "dependencies": { - "string-width": "^1.0.2 || 2" - } - }, - "node_modules/wide-align/node_modules/ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "engines": { - "node": ">=4" - } - }, - "node_modules/wide-align/node_modules/string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dependencies": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/wide-align/node_modules/strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dependencies": { - "ansi-regex": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/wkx": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/wkx/-/wkx-0.5.0.tgz", - "integrity": "sha512-Xng/d4Ichh8uN4l0FToV/258EjMGU9MGcA0HV2d9B/ZpZB3lqQm7nkOdZdm5GhKtLLhAE7PiVQwN4eN+2YJJUg==", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/workerpool": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.0.2.tgz", - "integrity": "sha512-DSNyvOpFKrNusaaUwk+ej6cBj1bmhLcBfj80elGk+ZIo5JSkq+unB1dLKEOcNfJDZgjGICfhQ0Q5TbP0PvF4+Q==" - }, - "node_modules/wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", - "dependencies": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "node_modules/y18n": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", - "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==" - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "node_modules/yargs": { - "version": "13.3.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", - "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", - "dependencies": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.2" - } - }, - "node_modules/yargs-parser": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", - "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - }, - "node_modules/yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dependencies": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-unparser/node_modules/camelcase": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", - "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/yargs-unparser/node_modules/decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - }, "dependencies": { "@sinonjs/commons": { "version": "1.8.1", @@ -3053,16 +581,6 @@ "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==" }, - "fill-keys": { - "version": "1.0.2", - "resolved": "http://npm.ooapi.com:4873/fill-keys/-/fill-keys-1.0.2.tgz", - "integrity": "sha1-mo+jb06K1jTjv2tPPIiCVRRS6yA=", - "dev": true, - "requires": { - "is-object": "~1.0.1", - "merge-descriptors": "~1.0.0" - } - }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -3304,12 +822,6 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" }, - "is-object": { - "version": "1.0.2", - "resolved": "http://npm.ooapi.com:4873/is-object/-/is-object-1.0.2.tgz", - "integrity": "sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==", - "dev": true - }, "is-plain-obj": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", @@ -3563,12 +1075,6 @@ } } }, - "module-not-found-error": { - "version": "1.0.1", - "resolved": "http://npm.ooapi.com:4873/module-not-found-error/-/module-not-found-error-1.0.1.tgz", - "integrity": "sha1-z4tP9PKWQGdNbN0CsOO8UjwrvcA=", - "dev": true - }, "moment": { "version": "2.29.1", "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", @@ -3772,17 +1278,6 @@ "ipaddr.js": "1.9.1" } }, - "proxyquire": { - "version": "2.1.3", - "resolved": "http://npm.ooapi.com:4873/proxyquire/-/proxyquire-2.1.3.tgz", - "integrity": "sha512-BQWfCqYM+QINd+yawJz23tbBM40VIGXOdDw3X344KcclI/gtBbdWF6SlQ4nK/bYhF9d27KYug9WzljHC6B9Ysg==", - "dev": true, - "requires": { - "fill-keys": "^1.0.2", - "module-not-found-error": "^1.0.1", - "resolve": "^1.11.1" - } - }, "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", @@ -3958,17 +1453,6 @@ "yargs": "^13.1.0" } }, - "sequelize-mock": { - "version": "0.10.2", - "resolved": "http://npm.ooapi.com:4873/sequelize-mock/-/sequelize-mock-0.10.2.tgz", - "integrity": "sha1-GdOXHM2utbhkFwwkznkqinHxRL0=", - "dev": true, - "requires": { - "bluebird": "^3.4.6", - "inflection": "^1.10.0", - "lodash": "^4.16.4" - } - }, "sequelize-pool": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/sequelize-pool/-/sequelize-pool-6.1.0.tgz", @@ -4037,6 +1521,16 @@ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, "string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -4052,16 +1546,6 @@ } } }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, "strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", @@ -4364,4 +1848,4 @@ } } } -} +} \ No newline at end of file diff --git a/package.json b/package.json index c25bd055..5f6f1d0f 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,6 @@ { - "name": "forum-express-workspace", - "version": "1.0.0", - "description": "", + "name": "forum-express-grading", + "version": "2.0.0", "main": "_helpers.js", "scripts": { "start": "node app.js", @@ -10,26 +9,21 @@ }, "repository": { "type": "git", - "url": "git+https://github.com/v123582/forum-express-workspace.git" + "url": "git+https://github.com/ALPHACamp/forum-express-grading.git" }, - "author": "", - "license": "ISC", - "bugs": { - "url": "https://github.com/v123582/forum-express-workspace/issues" - }, - "homepage": "https://github.com/v123582/forum-express-workspace#readme", "dependencies": { - "chai": "^4.2.0", "express": "^4.17.1", - "mocha": "^8.2.0", "mysql2": "^2.2.5", + "nodemon": "^2.0.12", "sequelize": "^6.3.5", - "sequelize-cli": "^6.2.0", - "sinon": "^9.2.0", - "supertest": "^5.0.0" + "sequelize-cli": "^6.2.0" }, "devDependencies": { + "chai": "^4.2.0", + "mocha": "^8.2.0", "proxyquire": "^2.1.3", - "sequelize-mock": "^0.10.2" + "sequelize-mock": "^0.10.2", + "sinon": "^9.2.0", + "supertest": "^5.0.0" } -} +} \ No newline at end of file From 5e1573a5ba7da44df7530b009b8ed565a552a62a Mon Sep 17 00:00:00 2001 From: Serena Tseng <51045074+Carrot7712@users.noreply.github.com> Date: Sat, 6 Nov 2021 00:14:56 +0800 Subject: [PATCH 059/135] Update .travis.yml --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9635c20c..fdf50b79 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,9 +11,9 @@ env: # 在 install 前執行的指令 before_install: - - mysql -e 'CREATE DATABASE IF NOT EXISTS forum_test default character set utf8mb4 collate utf8mb4_unicode_ci;' + - mysql -e 'CREATE DATABASE IF NOT EXISTS forum default character set utf8mb4 collate utf8mb4_unicode_ci;' - npm install sequelize-cli -g # 在執行測試之前的指令 before_script: - - sequelize db:migrate \ No newline at end of file + - sequelize db:migrate From c71da4437577e06e72e85113c9ae4eb5726a3f6d Mon Sep 17 00:00:00 2001 From: Serena Tseng <51045074+Carrot7712@users.noreply.github.com> Date: Sat, 6 Nov 2021 00:29:51 +0800 Subject: [PATCH 060/135] Update .travis.yml --- .travis.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index fdf50b79..f08c1b5e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: node_js node_js: - - "10" + - "14" services: - mysql @@ -16,4 +16,5 @@ before_install: # 在執行測試之前的指令 before_script: - - sequelize db:migrate + - sequelize db:migrate + - sequelize db:seed:all From 1da8f648fee9345d65ebbf74d734448d28d7f869 Mon Sep 17 00:00:00 2001 From: Amber Yan Date: Mon, 1 Nov 2021 21:52:15 +0800 Subject: [PATCH 061/135] R02 use new mockRequest / mockResponse --- tests/R02.test.js | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/tests/R02.test.js b/tests/R02.test.js index 5b7cadb2..6463e997 100644 --- a/tests/R02.test.js +++ b/tests/R02.test.js @@ -3,20 +3,8 @@ const request = require('supertest') const sinon = require('sinon') const should = chai.should() -const { createModelMock, createControllerProxy } = require('../helpers/unitTestHelpers'); - -const mockRequest = (query) => { - return { - ...query, - flash: sinon.spy(), - } -} -const mockResponse = () => { - return { - redirect: sinon.spy(), - render: sinon.spy(), - } -} +const { createModelMock, createControllerProxy, mockRequest, mockResponse } = require('../helpers/unitTestHelpers'); + describe('# R02', () => { describe('# R02: 建立 User Profile', function () { context('# [瀏覽 Profile]', () => { From dcc8f0ea6ecedcd515f536bd5283b7e6bdced693 Mon Sep 17 00:00:00 2001 From: Amber Yan Date: Mon, 8 Nov 2021 01:15:19 +0800 Subject: [PATCH 062/135] add helper ref --- tests/R02.test.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/R02.test.js b/tests/R02.test.js index 6463e997..26c927b3 100644 --- a/tests/R02.test.js +++ b/tests/R02.test.js @@ -3,6 +3,8 @@ const request = require('supertest') const sinon = require('sinon') const should = chai.should() +const helpers = require('../_helpers'); + const { createModelMock, createControllerProxy, mockRequest, mockResponse } = require('../helpers/unitTestHelpers'); describe('# R02', () => { From 67998043646f14f7c8216a027e9fb0d3c8b1803a Mon Sep 17 00:00:00 2001 From: Amber Yan Date: Mon, 8 Nov 2021 01:33:03 +0800 Subject: [PATCH 063/135] remove mockRequest, mockResponse --- tests/R04.test.js | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/tests/R04.test.js b/tests/R04.test.js index 86bbb191..d736b2f3 100644 --- a/tests/R04.test.js +++ b/tests/R04.test.js @@ -5,20 +5,7 @@ const should = chai.should() const db = require('../models') const helpers = require('../_helpers') -const { createModelMock, createControllerProxy } = require('../helpers/unitTestHelpers') - -const mockRequest = (query) => { - return { - ...query, - flash: sinon.spy(), - } -} -const mockResponse = () => { - return { - redirect: sinon.spy(), - render: sinon.spy(), - } -} +const { createModelMock, createControllerProxy, mockRequest, mockResponse } = require('../helpers/unitTestHelpers') // 建立模擬的 Like 資料 let mockLikeData = [ From d54a7fd60d9ea2c09a52c8b690ad4e42c89d5379 Mon Sep 17 00:00:00 2001 From: Amber Yan Date: Mon, 1 Nov 2021 21:52:15 +0800 Subject: [PATCH 064/135] R02 use new mockRequest / mockResponse --- tests/R02.test.js | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/tests/R02.test.js b/tests/R02.test.js index 5b7cadb2..6463e997 100644 --- a/tests/R02.test.js +++ b/tests/R02.test.js @@ -3,20 +3,8 @@ const request = require('supertest') const sinon = require('sinon') const should = chai.should() -const { createModelMock, createControllerProxy } = require('../helpers/unitTestHelpers'); - -const mockRequest = (query) => { - return { - ...query, - flash: sinon.spy(), - } -} -const mockResponse = () => { - return { - redirect: sinon.spy(), - render: sinon.spy(), - } -} +const { createModelMock, createControllerProxy, mockRequest, mockResponse } = require('../helpers/unitTestHelpers'); + describe('# R02', () => { describe('# R02: 建立 User Profile', function () { context('# [瀏覽 Profile]', () => { From dde5d1d2e63bdb7e3ce4ead51f43da070411cdd3 Mon Sep 17 00:00:00 2001 From: Amber Yan Date: Mon, 8 Nov 2021 01:15:19 +0800 Subject: [PATCH 065/135] add helper ref --- tests/R02.test.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/R02.test.js b/tests/R02.test.js index 6463e997..26c927b3 100644 --- a/tests/R02.test.js +++ b/tests/R02.test.js @@ -3,6 +3,8 @@ const request = require('supertest') const sinon = require('sinon') const should = chai.should() +const helpers = require('../_helpers'); + const { createModelMock, createControllerProxy, mockRequest, mockResponse } = require('../helpers/unitTestHelpers'); describe('# R02', () => { From ec34393e3b61d8033d4c8d0f06d2e73943130600 Mon Sep 17 00:00:00 2001 From: Amber Yan Date: Mon, 1 Nov 2021 21:52:15 +0800 Subject: [PATCH 066/135] R02 use new mockRequest / mockResponse --- tests/R02.test.js | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/tests/R02.test.js b/tests/R02.test.js index 5b7cadb2..6463e997 100644 --- a/tests/R02.test.js +++ b/tests/R02.test.js @@ -3,20 +3,8 @@ const request = require('supertest') const sinon = require('sinon') const should = chai.should() -const { createModelMock, createControllerProxy } = require('../helpers/unitTestHelpers'); - -const mockRequest = (query) => { - return { - ...query, - flash: sinon.spy(), - } -} -const mockResponse = () => { - return { - redirect: sinon.spy(), - render: sinon.spy(), - } -} +const { createModelMock, createControllerProxy, mockRequest, mockResponse } = require('../helpers/unitTestHelpers'); + describe('# R02', () => { describe('# R02: 建立 User Profile', function () { context('# [瀏覽 Profile]', () => { From 8b395b251ea18469c3a8145f44dcd8f950b1273f Mon Sep 17 00:00:00 2001 From: Amber Yan Date: Mon, 8 Nov 2021 01:15:19 +0800 Subject: [PATCH 067/135] add helper ref --- tests/R02.test.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/R02.test.js b/tests/R02.test.js index 6463e997..26c927b3 100644 --- a/tests/R02.test.js +++ b/tests/R02.test.js @@ -3,6 +3,8 @@ const request = require('supertest') const sinon = require('sinon') const should = chai.should() +const helpers = require('../_helpers'); + const { createModelMock, createControllerProxy, mockRequest, mockResponse } = require('../helpers/unitTestHelpers'); describe('# R02', () => { From 049790e9f5dca0d19b8d23a59f7baed7f9df3667 Mon Sep 17 00:00:00 2001 From: Amber Yan Date: Mon, 8 Nov 2021 01:52:24 +0800 Subject: [PATCH 068/135] use new mockRequest, mockResponse --- tests/R03.test.js | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/tests/R03.test.js b/tests/R03.test.js index bc7d1ade..f415be50 100644 --- a/tests/R03.test.js +++ b/tests/R03.test.js @@ -4,20 +4,7 @@ const sinon = require('sinon') const should = chai.should() const helpers = require('../_helpers') -const { createModelMock, createControllerProxy } = require('../helpers/unitTestHelpers'); - -const mockRequest = (query) => { - return { - ...query, - flash: sinon.spy(), - } -} -const mockResponse = () => { - return { - redirect: sinon.spy(), - render: sinon.spy(), - } -} +const { createModelMock, createControllerProxy, mockRequest, mockResponse } = require('../helpers/unitTestHelpers'); describe('# R03: 餐廳資訊整理:Dashboard', function () { context('# [Q1: Dashboard - 1 - controller / view / route]', () => { From a9d40824ecd1c10d420cfec2465d9528d426252e Mon Sep 17 00:00:00 2001 From: Amber Yan Date: Mon, 8 Nov 2021 01:52:24 +0800 Subject: [PATCH 069/135] use new mockRequest, mockResponse --- tests/R03.test.js | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/tests/R03.test.js b/tests/R03.test.js index bc7d1ade..f415be50 100644 --- a/tests/R03.test.js +++ b/tests/R03.test.js @@ -4,20 +4,7 @@ const sinon = require('sinon') const should = chai.should() const helpers = require('../_helpers') -const { createModelMock, createControllerProxy } = require('../helpers/unitTestHelpers'); - -const mockRequest = (query) => { - return { - ...query, - flash: sinon.spy(), - } -} -const mockResponse = () => { - return { - redirect: sinon.spy(), - render: sinon.spy(), - } -} +const { createModelMock, createControllerProxy, mockRequest, mockResponse } = require('../helpers/unitTestHelpers'); describe('# R03: 餐廳資訊整理:Dashboard', function () { context('# [Q1: Dashboard - 1 - controller / view / route]', () => { From 72b97383c0e5c062469191ad96ee0b4ac1911861 Mon Sep 17 00:00:00 2001 From: Carrot7712 Date: Wed, 3 Nov 2021 15:28:42 +0800 Subject: [PATCH 070/135] update readme config.json package.json --- README.md | 26 +- config/config.json | 14 +- package-lock.json | 2540 +------------------------------------------- package.json | 28 +- 4 files changed, 39 insertions(+), 2569 deletions(-) diff --git a/README.md b/README.md index e4cd70f1..9172af88 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,6 @@ 1. Fork 2. git clone -3. 更改專案名稱 ## 初始化 ### Initialize @@ -16,14 +15,6 @@ npm install ``` create database forum; -create database forum_test; -``` - -### 切換環境 - -``` -export NODE_ENV=test # 切換到測試環境,如果在等號後加其他的字串,則會切到其他的環境 -echo $NODE_ENV # 印出目前使用的環境 ``` ### 執行測試 @@ -32,11 +23,11 @@ npm run test ``` ## 下載作業規格 -以 A17 為例 +以 R01 為例 ``` -git checkout -b A17 # 開新分支 -git merge origin/A17-test # 下載作業規格 +git checkout -b R01 # 開新分支 +git merge origin/R01-test # 下載作業規格 npm run test # 直到綠燈全亮 git add . @@ -46,11 +37,16 @@ git commit -m "...." ## 繳交作業 ``` -git push origin A17 # 上傳本地進度 +git push origin R01 # 上傳本地進度 ``` 接著改成到 GitHub 來發 PR。 ## 共用帳號 -請一律設定一個共用的 root user -root@example.com,登入密碼 12345678 +請一律設定下面 2 組帳號以利驗收: +* 第一組帳號有 admin 權限: + * email: root@example.com + * password: 12345678 +* 第二組帳號沒有 admin 權限: + * email: user1@example.com + * password: 12345678 \ No newline at end of file diff --git a/config/config.json b/config/config.json index 56636a1c..2b8be8e7 100644 --- a/config/config.json +++ b/config/config.json @@ -6,16 +6,12 @@ "host": "127.0.0.1", "dialect": "mysql" }, - "test": { + "production": { "username": "root", - "password": "password", - "database": "forum_test", + "password": null, + "database": "database_production", "host": "127.0.0.1", - "dialect": "mysql", - "logging": false - }, - "production": { - "use_env_variable": "CLEARDB_SILVER_URL" + "dialect": "mysql" }, "travis": { "username": "travis", @@ -24,4 +20,4 @@ "dialect": "mysql", "logging": false } -} \ No newline at end of file +} diff --git a/package-lock.json b/package-lock.json index 7ebc04a3..bb00f848 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,2480 +1,8 @@ { "name": "forum-express-workspace", "version": "1.0.0", - "lockfileVersion": 2, + "lockfileVersion": 1, "requires": true, - "packages": { - "": { - "name": "forum-express-workspace", - "version": "1.0.0", - "license": "ISC", - "dependencies": { - "chai": "^4.2.0", - "express": "^4.17.1", - "mocha": "^8.2.0", - "mysql2": "^2.2.5", - "sequelize": "^6.3.5", - "sequelize-cli": "^6.2.0", - "sinon": "^9.2.0", - "supertest": "^5.0.0" - }, - "devDependencies": { - "proxyquire": "^2.1.3", - "sequelize-mock": "^0.10.2" - } - }, - "node_modules/@sinonjs/commons": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.1.tgz", - "integrity": "sha512-892K+kWUUi3cl+LlqEWIDrhvLgdL79tECi8JZUyq6IviKy/DNhuzCRlbHUjxK89f4ypPMMaFnFuR9Ie6DoIMsw==", - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@sinonjs/fake-timers": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", - "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", - "dependencies": { - "@sinonjs/commons": "^1.7.0" - } - }, - "node_modules/@sinonjs/formatio": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-5.0.1.tgz", - "integrity": "sha512-KaiQ5pBf1MpS09MuA0kp6KBQt2JUOQycqVG1NZXvzeaXe5LGFqAKueIS0bw4w0P9r7KuBSVdUk5QjXsUdu2CxQ==", - "dependencies": { - "@sinonjs/commons": "^1", - "@sinonjs/samsam": "^5.0.2" - } - }, - "node_modules/@sinonjs/samsam": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-5.2.0.tgz", - "integrity": "sha512-CaIcyX5cDsjcW/ab7HposFWzV1kC++4HNsfnEdFJa7cP1QIuILAKV+BgfeqRXhcnSAc76r/Rh/O5C+300BwUIw==", - "dependencies": { - "@sinonjs/commons": "^1.6.0", - "lodash.get": "^4.4.2", - "type-detect": "^4.0.8" - } - }, - "node_modules/@sinonjs/text-encoding": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", - "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==" - }, - "node_modules/@types/node": { - "version": "14.14.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.5.tgz", - "integrity": "sha512-H5Wn24s/ZOukBmDn03nnGTp18A60ny9AmCwnEcgJiTgSGsCO7k+NWP7zjCCbhlcnVCoI+co52dUAt9GMhOSULw==" - }, - "node_modules/@ungap/promise-all-settled": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", - "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==" - }, - "node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" - }, - "node_modules/accepts": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", - "dependencies": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=" - }, - "node_modules/anymatch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", - "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" - }, - "node_modules/assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "engines": { - "node": "*" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, - "node_modules/balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" - }, - "node_modules/binary-extensions": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", - "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" - }, - "node_modules/body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", - "dependencies": { - "bytes": "3.1.0", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.7.0", - "raw-body": "2.4.0", - "type-is": "~1.6.17" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==" - }, - "node_modules/bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/chai": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", - "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", - "dependencies": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.2", - "deep-eql": "^3.0.1", - "get-func-name": "^2.0.0", - "pathval": "^1.1.0", - "type-detect": "^4.0.5" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chalk/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/chalk/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/chalk/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/check-error": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", - "engines": { - "node": "*" - } - }, - "node_modules/chokidar": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz", - "integrity": "sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==", - "dependencies": { - "anymatch": "~3.1.1", - "braces": "~3.0.2", - "glob-parent": "~5.1.0", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.5.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.1.2" - } - }, - "node_modules/cli-color": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-1.4.0.tgz", - "integrity": "sha512-xu6RvQqqrWEo6MPR1eixqGPywhYBHRs653F9jfXB2Hx4jdM/3WxiNE1vppRmxtMIfl16SFYTpYlrnqH/HsK/2w==", - "dependencies": { - "ansi-regex": "^2.1.1", - "d": "1", - "es5-ext": "^0.10.46", - "es6-iterator": "^2.0.3", - "memoizee": "^0.4.14", - "timers-ext": "^0.1.5" - } - }, - "node_modules/cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", - "dependencies": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - }, - "node_modules/component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "node_modules/config-chain": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz", - "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==", - "dependencies": { - "ini": "^1.3.4", - "proto-list": "~1.2.1" - } - }, - "node_modules/content-disposition": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", - "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", - "dependencies": { - "safe-buffer": "5.1.2" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/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==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" - }, - "node_modules/cookiejar": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz", - "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==" - }, - "node_modules/d": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", - "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", - "dependencies": { - "es5-ext": "^0.10.50", - "type": "^1.0.1" - } - }, - "node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/deep-eql": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", - "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", - "dependencies": { - "type-detect": "^4.0.0" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/denque": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/denque/-/denque-1.4.1.tgz", - "integrity": "sha512-OfzPuSZKGcgr96rf1oODnfjqBFmr1DVoc/TrItj3Ohe0Ah1C5WX5Baquw/9U9KovnQ88EqmJbD66rKYUQYN1tQ==", - "engines": { - "node": ">=0.10" - } - }, - "node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" - }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/dottie": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.2.tgz", - "integrity": "sha512-fmrwR04lsniq/uSr8yikThDTrM7epXHBAAjH9TbeH3rEA8tdCO7mRzB9hdmdGyJCxF8KERo9CITcm3kGuoyMhg==" - }, - "node_modules/editorconfig": { - "version": "0.15.3", - "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz", - "integrity": "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==", - "dependencies": { - "commander": "^2.19.0", - "lru-cache": "^4.1.5", - "semver": "^5.6.0", - "sigmund": "^1.0.1" - }, - "bin": { - "editorconfig": "bin/editorconfig" - } - }, - "node_modules/editorconfig/node_modules/lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dependencies": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "node_modules/editorconfig/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/editorconfig/node_modules/yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" - }, - "node_modules/emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" - }, - "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/es5-ext": { - "version": "0.10.53", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", - "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", - "dependencies": { - "es6-iterator": "~2.0.3", - "es6-symbol": "~3.1.3", - "next-tick": "~1.0.0" - } - }, - "node_modules/es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", - "dependencies": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, - "node_modules/es6-symbol": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", - "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", - "dependencies": { - "d": "^1.0.1", - "ext": "^1.1.2" - } - }, - "node_modules/es6-weak-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", - "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", - "dependencies": { - "d": "1", - "es5-ext": "^0.10.46", - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.1" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/event-emitter": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", - "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", - "dependencies": { - "d": "1", - "es5-ext": "~0.10.14" - } - }, - "node_modules/express": { - "version": "4.17.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", - "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", - "dependencies": { - "accepts": "~1.3.7", - "array-flatten": "1.1.1", - "body-parser": "1.19.0", - "content-disposition": "0.5.3", - "content-type": "~1.0.4", - "cookie": "0.4.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "~1.1.2", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "~1.1.2", - "fresh": "0.5.2", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.5", - "qs": "6.7.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.1.2", - "send": "0.17.1", - "serve-static": "1.14.1", - "setprototypeof": "1.1.1", - "statuses": "~1.5.0", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/ext": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", - "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", - "dependencies": { - "type": "^2.0.0" - } - }, - "node_modules/ext/node_modules/type": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/type/-/type-2.1.0.tgz", - "integrity": "sha512-G9absDWvhAWCV2gmF1zKud3OyC61nZDwWvBL2DApaVFogI07CprggiQAOOjvp2NRjYWFzPyu7vwtDrQFq8jeSA==" - }, - "node_modules/fast-safe-stringify": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", - "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==" - }, - "node_modules/fill-keys": { - "version": "1.0.2", - "resolved": "http://npm.ooapi.com:4873/fill-keys/-/fill-keys-1.0.2.tgz", - "integrity": "sha1-mo+jb06K1jTjv2tPPIiCVRRS6yA=", - "dev": true, - "dependencies": { - "is-object": "~1.0.1", - "merge-descriptors": "~1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dependencies": { - "locate-path": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "bin": { - "flat": "cli.js" - } - }, - "node_modules/form-data": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.0.tgz", - "integrity": "sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/formidable": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.2.tgz", - "integrity": "sha512-V8gLm+41I/8kguQ4/o1D3RIHRmhYFG4pnNyonvua+40rqcEmT4+V71yaZ3B457xbbgCsCfjSPi65u/W6vK1U5Q==", - "funding": { - "url": "https://ko-fi.com/tunnckoCore/commissions" - } - }, - "node_modules/forwarded": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", - "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fs-extra": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", - "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", - "dependencies": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "node_modules/fsevents": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", - "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", - "deprecated": "\"Please update to latest v2.3 or v2.2\"", - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "node_modules/generate-function": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", - "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", - "dependencies": { - "is-property": "^1.0.2" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-func-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", - "engines": { - "node": "*" - } - }, - "node_modules/glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==" - }, - "node_modules/growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", - "engines": { - "node": ">=4.x" - } - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "bin": { - "he": "bin/he" - } - }, - "node_modules/http-errors": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", - "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/inflection": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz", - "integrity": "sha1-ogCTVlbW9fa8TcdQLhrstwMihBY=", - "engines": [ - "node >= 0.4.0" - ] - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "node_modules/ini": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", - "deprecated": "Please update to ini >=1.3.6 to avoid a prototype pollution issue", - "engines": { - "node": "*" - } - }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-core-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.0.0.tgz", - "integrity": "sha512-jq1AH6C8MuteOoBPwkxHafmByhL9j5q4OaPGdbuD+ZtQJVzH+i6E3BJDQcBA09k57i2Hh2yQbEG8yObZ0jdlWw==", - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "engines": { - "node": ">=4" - } - }, - "node_modules/is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-object": { - "version": "1.0.2", - "resolved": "http://npm.ooapi.com:4873/is-object/-/is-object-1.0.2.tgz", - "integrity": "sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-promise": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", - "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==" - }, - "node_modules/is-property": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", - "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=" - }, - "node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" - }, - "node_modules/js-beautify": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.13.0.tgz", - "integrity": "sha512-/Tbp1OVzZjbwzwJQFIlYLm9eWQ+3aYbBXLSaqb1mEJzhcQAfrqMMQYtjb6io+U6KpD0ID4F+Id3/xcjH3l/sqA==", - "dependencies": { - "config-chain": "^1.1.12", - "editorconfig": "^0.15.3", - "glob": "^7.1.3", - "mkdirp": "^1.0.4", - "nopt": "^5.0.0" - }, - "bin": { - "css-beautify": "js/bin/css-beautify.js", - "html-beautify": "js/bin/html-beautify.js", - "js-beautify": "js/bin/js-beautify.js" - } - }, - "node_modules/js-yaml": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", - "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/just-extend": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.1.1.tgz", - "integrity": "sha512-aWgeGFW67BP3e5181Ep1Fv2v8z//iBJfrvyTnq8wG86vEESwmonn1zPBJ0VfmT9CJq2FIT0VsETtrNFm2a+SHA==" - }, - "node_modules/locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/lodash": { - "version": "4.17.20", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", - "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" - }, - "node_modules/lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" - }, - "node_modules/log-symbols": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", - "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==", - "dependencies": { - "chalk": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/long": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", - "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/lru-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", - "integrity": "sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM=", - "dependencies": { - "es5-ext": "~0.10.2" - } - }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/memoizee": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.14.tgz", - "integrity": "sha512-/SWFvWegAIYAO4NQMpcX+gcra0yEZu4OntmUdrBaWrJncxOqAziGFlHxc7yjKVK2uu3lpPW27P27wkR82wA8mg==", - "dependencies": { - "d": "1", - "es5-ext": "^0.10.45", - "es6-weak-map": "^2.0.2", - "event-emitter": "^0.3.5", - "is-promise": "^2.1", - "lru-queue": "0.1", - "next-tick": "1", - "timers-ext": "^0.1.5" - } - }, - "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/mime-db": { - "version": "1.44.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", - "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.27", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", - "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", - "dependencies": { - "mime-db": "1.44.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mocha": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.2.0.tgz", - "integrity": "sha512-lEWEMq2LMfNJMKeuEwb5UELi+OgFDollXaytR5ggQcHpzG3NP/R7rvixAvF+9/lLsTWhWG+4yD2M70GsM06nxw==", - "dependencies": { - "@ungap/promise-all-settled": "1.1.2", - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.4.3", - "debug": "4.2.0", - "diff": "4.0.2", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.1.6", - "growl": "1.10.5", - "he": "1.2.0", - "js-yaml": "3.14.0", - "log-symbols": "4.0.0", - "minimatch": "3.0.4", - "ms": "2.1.2", - "nanoid": "3.1.12", - "serialize-javascript": "5.0.1", - "strip-json-comments": "3.1.1", - "supports-color": "7.2.0", - "which": "2.0.2", - "wide-align": "1.1.3", - "workerpool": "6.0.2", - "yargs": "13.3.2", - "yargs-parser": "13.1.2", - "yargs-unparser": "2.0.0" - }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha" - }, - "engines": { - "node": ">= 10.12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mochajs" - } - }, - "node_modules/mocha/node_modules/debug": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", - "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", - "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/mocha/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mocha/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mocha/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/mocha/node_modules/p-limit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.0.2.tgz", - "integrity": "sha512-iwqZSOoWIW+Ew4kAGUlN16J4M7OB3ysMLSZtnhmqx7njIHFPlxWBX8xo3lVTyFVq6mI/lL9qt2IsN1sHwaxJkg==", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mocha/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mocha/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "engines": { - "node": ">=8" - } - }, - "node_modules/module-not-found-error": { - "version": "1.0.1", - "resolved": "http://npm.ooapi.com:4873/module-not-found-error/-/module-not-found-error-1.0.1.tgz", - "integrity": "sha1-z4tP9PKWQGdNbN0CsOO8UjwrvcA=", - "dev": true - }, - "node_modules/moment": { - "version": "2.29.1", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", - "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==", - "engines": { - "node": "*" - } - }, - "node_modules/moment-timezone": { - "version": "0.5.31", - "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.31.tgz", - "integrity": "sha512-+GgHNg8xRhMXfEbv81iDtrVeTcWt0kWmTEY1XQK14dICTXnWJnT0dxdlPspwqF3keKMVPXwayEsk1DI0AA/jdA==", - "dependencies": { - "moment": ">= 2.9.0" - }, - "engines": { - "node": "*" - } - }, - "node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "node_modules/mysql2": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-2.2.5.tgz", - "integrity": "sha512-XRqPNxcZTpmFdXbJqb+/CtYVLCx14x1RTeNMD4954L331APu75IC74GDqnZMEt1kwaXy6TySo55rF2F3YJS78g==", - "dependencies": { - "denque": "^1.4.1", - "generate-function": "^2.3.1", - "iconv-lite": "^0.6.2", - "long": "^4.0.0", - "lru-cache": "^6.0.0", - "named-placeholders": "^1.1.2", - "seq-queue": "^0.0.5", - "sqlstring": "^2.3.2" - }, - "engines": { - "node": ">= 8.0" - } - }, - "node_modules/mysql2/node_modules/iconv-lite": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz", - "integrity": "sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/named-placeholders": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.2.tgz", - "integrity": "sha512-wiFWqxoLL3PGVReSZpjLVxyJ1bRqe+KKJVbr4hGs1KWfTZTQyezHFBbuKj9hsizHyGV2ne7EMjHdxEGAybD5SA==", - "dependencies": { - "lru-cache": "^4.1.3" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/named-placeholders/node_modules/lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dependencies": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "node_modules/named-placeholders/node_modules/yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" - }, - "node_modules/nanoid": { - "version": "3.1.12", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.12.tgz", - "integrity": "sha512-1qstj9z5+x491jfiC4Nelk+f8XBad7LN20PmyWINJEMRSf3wcAjAWysw1qaA8z6NSKe2sjq1hRSDpBH5paCb6A==", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || >=13.7" - } - }, - "node_modules/negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/next-tick": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", - "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" - }, - "node_modules/nise": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/nise/-/nise-4.0.4.tgz", - "integrity": "sha512-bTTRUNlemx6deJa+ZyoCUTRvH3liK5+N6VQZ4NIw90AgDXY6iPnsqplNFf6STcj+ePk0H/xqxnP75Lr0J0Fq3A==", - "dependencies": { - "@sinonjs/commons": "^1.7.0", - "@sinonjs/fake-timers": "^6.0.0", - "@sinonjs/text-encoding": "^0.7.1", - "just-extend": "^4.0.2", - "path-to-regexp": "^1.7.0" - } - }, - "node_modules/nise/node_modules/path-to-regexp": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", - "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", - "dependencies": { - "isarray": "0.0.1" - } - }, - "node_modules/nopt": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", - "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", - "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dependencies": { - "p-limit": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "engines": { - "node": ">=6" - } - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "engines": { - "node": ">=4" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" - }, - "node_modules/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=" - }, - "node_modules/pathval": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", - "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", - "engines": { - "node": "*" - } - }, - "node_modules/picomatch": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/proto-list": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", - "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=" - }, - "node_modules/proxy-addr": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", - "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", - "dependencies": { - "forwarded": "~0.1.2", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/proxyquire": { - "version": "2.1.3", - "resolved": "http://npm.ooapi.com:4873/proxyquire/-/proxyquire-2.1.3.tgz", - "integrity": "sha512-BQWfCqYM+QINd+yawJz23tbBM40VIGXOdDw3X344KcclI/gtBbdWF6SlQ4nK/bYhF9d27KYug9WzljHC6B9Ysg==", - "dev": true, - "dependencies": { - "fill-keys": "^1.0.2", - "module-not-found-error": "^1.0.1", - "resolve": "^1.11.1" - } - }, - "node_modules/pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" - }, - "node_modules/qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", - "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", - "dependencies": { - "bytes": "3.1.0", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/readdirp": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", - "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" - }, - "node_modules/resolve": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.18.1.tgz", - "integrity": "sha512-lDfCPaMKfOJXjy0dPayzPdF1phampNWr3qFCjAu+rw/qbQmr5jWH5xN2hwh9QKfw9E5v4hwV7A+jrCmL8yjjqA==", - "dependencies": { - "is-core-module": "^2.0.0", - "path-parse": "^1.0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/retry-as-promised": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/retry-as-promised/-/retry-as-promised-3.2.0.tgz", - "integrity": "sha512-CybGs60B7oYU/qSQ6kuaFmRd9sTZ6oXSc0toqePvV74Ac6/IFZSI1ReFQmtCN+uvW1Mtqdwpvt/LGOiCBAY2Mg==", - "dependencies": { - "any-promise": "^1.3.0" - } - }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "node_modules/semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/send": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", - "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", - "dependencies": { - "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "~1.7.2", - "mime": "1.6.0", - "ms": "2.1.1", - "on-finished": "~2.3.0", - "range-parser": "~1.2.1", - "statuses": "~1.5.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/send/node_modules/ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" - }, - "node_modules/seq-queue": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", - "integrity": "sha1-1WgS4cAXpuTnw+Ojeh2m143TyT4=" - }, - "node_modules/sequelize": { - "version": "6.3.5", - "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-6.3.5.tgz", - "integrity": "sha512-MiwiPkYSA8NWttRKAXdU9h0TxP6HAc1fl7qZmMO/VQqQOND83G4nZLXd0kWILtAoT9cxtZgFqeb/MPYgEeXwsw==", - "dependencies": { - "debug": "^4.1.1", - "dottie": "^2.0.0", - "inflection": "1.12.0", - "lodash": "^4.17.15", - "moment": "^2.26.0", - "moment-timezone": "^0.5.31", - "retry-as-promised": "^3.2.0", - "semver": "^7.3.2", - "sequelize-pool": "^6.0.0", - "toposort-class": "^1.0.1", - "uuid": "^8.1.0", - "validator": "^10.11.0", - "wkx": "^0.5.0" - }, - "engines": { - "node": ">=10.0.0" - }, - "peerDependenciesMeta": { - "mariadb": { - "optional": true - }, - "mysql2": { - "optional": true - }, - "pg": { - "optional": true - }, - "pg-hstore": { - "optional": true - }, - "sqlite3": { - "optional": true - }, - "tedious": { - "optional": true - } - } - }, - "node_modules/sequelize-cli": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/sequelize-cli/-/sequelize-cli-6.2.0.tgz", - "integrity": "sha512-6WQ2x91hg30dUn66mXHnzvHATZ4pyI1GHSNbS/TNN/vRR4BLRSLijadeMgC8zqmKDsL0VqzVVopJWfJakuP++Q==", - "dependencies": { - "cli-color": "^1.4.0", - "fs-extra": "^7.0.1", - "js-beautify": "^1.8.8", - "lodash": "^4.17.5", - "resolve": "^1.5.0", - "umzug": "^2.3.0", - "yargs": "^13.1.0" - }, - "bin": { - "sequelize": "lib/sequelize", - "sequelize-cli": "lib/sequelize" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/sequelize-mock": { - "version": "0.10.2", - "resolved": "http://npm.ooapi.com:4873/sequelize-mock/-/sequelize-mock-0.10.2.tgz", - "integrity": "sha1-GdOXHM2utbhkFwwkznkqinHxRL0=", - "dev": true, - "dependencies": { - "bluebird": "^3.4.6", - "inflection": "^1.10.0", - "lodash": "^4.16.4" - } - }, - "node_modules/sequelize-pool": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/sequelize-pool/-/sequelize-pool-6.1.0.tgz", - "integrity": "sha512-4YwEw3ZgK/tY/so+GfnSgXkdwIJJ1I32uZJztIEgZeAO6HMgj64OzySbWLgxj+tXhZCJnzRfkY9gINw8Ft8ZMg==", - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/sequelize/node_modules/debug": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", - "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", - "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/sequelize/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/serialize-javascript": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", - "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/serve-static": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", - "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", - "dependencies": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.17.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" - }, - "node_modules/setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" - }, - "node_modules/sigmund": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", - "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=" - }, - "node_modules/sinon": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-9.2.0.tgz", - "integrity": "sha512-eSNXz1XMcGEMHw08NJXSyTHIu6qTCOiN8x9ODACmZpNQpr0aXTBXBnI4xTzQzR+TEpOmLiKowGf9flCuKIzsbw==", - "dependencies": { - "@sinonjs/commons": "^1.8.1", - "@sinonjs/fake-timers": "^6.0.1", - "@sinonjs/formatio": "^5.0.1", - "@sinonjs/samsam": "^5.2.0", - "diff": "^4.0.2", - "nise": "^4.0.4", - "supports-color": "^7.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/sinon" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" - }, - "node_modules/sqlstring": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.2.tgz", - "integrity": "sha512-vF4ZbYdKS8OnoJAWBmMxCQDkiEBkGQYU7UZPtL8flbDRSNkhaXvRJ279ZtI6M+zDaQovVU4tuRgzK5fVhvFAhg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string_decoder/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dependencies": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dependencies": { - "ansi-regex": "^4.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-ansi/node_modules/ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/superagent": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/superagent/-/superagent-6.1.0.tgz", - "integrity": "sha512-OUDHEssirmplo3F+1HWKUrUjvnQuA+nZI6i/JJBdXb5eq9IyEQwPyPpqND+SSsxf6TygpBEkUjISVRN4/VOpeg==", - "dependencies": { - "component-emitter": "^1.3.0", - "cookiejar": "^2.1.2", - "debug": "^4.1.1", - "fast-safe-stringify": "^2.0.7", - "form-data": "^3.0.0", - "formidable": "^1.2.2", - "methods": "^1.1.2", - "mime": "^2.4.6", - "qs": "^6.9.4", - "readable-stream": "^3.6.0", - "semver": "^7.3.2" - }, - "engines": { - "node": ">= 7.0.0" - } - }, - "node_modules/superagent/node_modules/debug": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", - "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", - "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/superagent/node_modules/mime": { - "version": "2.4.6", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz", - "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/superagent/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/superagent/node_modules/qs": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz", - "integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==", - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/supertest": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/supertest/-/supertest-5.0.0.tgz", - "integrity": "sha512-2JAWpPrUOZF4hHH5ZTCN2xjKXvJS3AEwPNXl0HUseHsfcXFvMy9kcsufIHCNAmQ5hlGCvgeAqaR5PBEouN3hlQ==", - "dependencies": { - "methods": "1.1.2", - "superagent": "6.1.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/timers-ext": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz", - "integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==", - "dependencies": { - "es5-ext": "~0.10.46", - "next-tick": "1" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/toposort-class": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toposort-class/-/toposort-class-1.0.1.tgz", - "integrity": "sha1-f/0feMi+KMO6Rc1OGj9e4ZO9mYg=" - }, - "node_modules/type": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", - "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" - }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "engines": { - "node": ">=4" - } - }, - "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/umzug": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/umzug/-/umzug-2.3.0.tgz", - "integrity": "sha512-Z274K+e8goZK8QJxmbRPhl89HPO1K+ORFtm6rySPhFKfKc5GHhqdzD0SGhSWHkzoXasqJuItdhorSvY7/Cgflw==", - "dependencies": { - "bluebird": "^3.7.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/uuid": { - "version": "8.3.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.1.tgz", - "integrity": "sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg==", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/validator": { - "version": "10.11.0", - "resolved": "https://registry.npmjs.org/validator/-/validator-10.11.0.tgz", - "integrity": "sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw==", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" - }, - "node_modules/wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", - "dependencies": { - "string-width": "^1.0.2 || 2" - } - }, - "node_modules/wide-align/node_modules/ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "engines": { - "node": ">=4" - } - }, - "node_modules/wide-align/node_modules/string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dependencies": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/wide-align/node_modules/strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dependencies": { - "ansi-regex": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/wkx": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/wkx/-/wkx-0.5.0.tgz", - "integrity": "sha512-Xng/d4Ichh8uN4l0FToV/258EjMGU9MGcA0HV2d9B/ZpZB3lqQm7nkOdZdm5GhKtLLhAE7PiVQwN4eN+2YJJUg==", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/workerpool": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.0.2.tgz", - "integrity": "sha512-DSNyvOpFKrNusaaUwk+ej6cBj1bmhLcBfj80elGk+ZIo5JSkq+unB1dLKEOcNfJDZgjGICfhQ0Q5TbP0PvF4+Q==" - }, - "node_modules/wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", - "dependencies": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "node_modules/y18n": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", - "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==" - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "node_modules/yargs": { - "version": "13.3.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", - "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", - "dependencies": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.2" - } - }, - "node_modules/yargs-parser": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", - "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - }, - "node_modules/yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dependencies": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-unparser/node_modules/camelcase": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", - "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/yargs-unparser/node_modules/decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - }, "dependencies": { "@sinonjs/commons": { "version": "1.8.1", @@ -3053,16 +581,6 @@ "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==" }, - "fill-keys": { - "version": "1.0.2", - "resolved": "http://npm.ooapi.com:4873/fill-keys/-/fill-keys-1.0.2.tgz", - "integrity": "sha1-mo+jb06K1jTjv2tPPIiCVRRS6yA=", - "dev": true, - "requires": { - "is-object": "~1.0.1", - "merge-descriptors": "~1.0.0" - } - }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -3304,12 +822,6 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" }, - "is-object": { - "version": "1.0.2", - "resolved": "http://npm.ooapi.com:4873/is-object/-/is-object-1.0.2.tgz", - "integrity": "sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==", - "dev": true - }, "is-plain-obj": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", @@ -3563,12 +1075,6 @@ } } }, - "module-not-found-error": { - "version": "1.0.1", - "resolved": "http://npm.ooapi.com:4873/module-not-found-error/-/module-not-found-error-1.0.1.tgz", - "integrity": "sha1-z4tP9PKWQGdNbN0CsOO8UjwrvcA=", - "dev": true - }, "moment": { "version": "2.29.1", "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", @@ -3772,17 +1278,6 @@ "ipaddr.js": "1.9.1" } }, - "proxyquire": { - "version": "2.1.3", - "resolved": "http://npm.ooapi.com:4873/proxyquire/-/proxyquire-2.1.3.tgz", - "integrity": "sha512-BQWfCqYM+QINd+yawJz23tbBM40VIGXOdDw3X344KcclI/gtBbdWF6SlQ4nK/bYhF9d27KYug9WzljHC6B9Ysg==", - "dev": true, - "requires": { - "fill-keys": "^1.0.2", - "module-not-found-error": "^1.0.1", - "resolve": "^1.11.1" - } - }, "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", @@ -3958,17 +1453,6 @@ "yargs": "^13.1.0" } }, - "sequelize-mock": { - "version": "0.10.2", - "resolved": "http://npm.ooapi.com:4873/sequelize-mock/-/sequelize-mock-0.10.2.tgz", - "integrity": "sha1-GdOXHM2utbhkFwwkznkqinHxRL0=", - "dev": true, - "requires": { - "bluebird": "^3.4.6", - "inflection": "^1.10.0", - "lodash": "^4.16.4" - } - }, "sequelize-pool": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/sequelize-pool/-/sequelize-pool-6.1.0.tgz", @@ -4037,6 +1521,16 @@ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, "string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -4052,16 +1546,6 @@ } } }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, "strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", @@ -4364,4 +1848,4 @@ } } } -} +} \ No newline at end of file diff --git a/package.json b/package.json index c25bd055..5f6f1d0f 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,6 @@ { - "name": "forum-express-workspace", - "version": "1.0.0", - "description": "", + "name": "forum-express-grading", + "version": "2.0.0", "main": "_helpers.js", "scripts": { "start": "node app.js", @@ -10,26 +9,21 @@ }, "repository": { "type": "git", - "url": "git+https://github.com/v123582/forum-express-workspace.git" + "url": "git+https://github.com/ALPHACamp/forum-express-grading.git" }, - "author": "", - "license": "ISC", - "bugs": { - "url": "https://github.com/v123582/forum-express-workspace/issues" - }, - "homepage": "https://github.com/v123582/forum-express-workspace#readme", "dependencies": { - "chai": "^4.2.0", "express": "^4.17.1", - "mocha": "^8.2.0", "mysql2": "^2.2.5", + "nodemon": "^2.0.12", "sequelize": "^6.3.5", - "sequelize-cli": "^6.2.0", - "sinon": "^9.2.0", - "supertest": "^5.0.0" + "sequelize-cli": "^6.2.0" }, "devDependencies": { + "chai": "^4.2.0", + "mocha": "^8.2.0", "proxyquire": "^2.1.3", - "sequelize-mock": "^0.10.2" + "sequelize-mock": "^0.10.2", + "sinon": "^9.2.0", + "supertest": "^5.0.0" } -} +} \ No newline at end of file From 8c88719874fe6693bfbd7888c51aa3b6fe61ce2e Mon Sep 17 00:00:00 2001 From: Serena Tseng <51045074+Carrot7712@users.noreply.github.com> Date: Sat, 6 Nov 2021 00:14:56 +0800 Subject: [PATCH 071/135] Update .travis.yml --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9635c20c..fdf50b79 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,9 +11,9 @@ env: # 在 install 前執行的指令 before_install: - - mysql -e 'CREATE DATABASE IF NOT EXISTS forum_test default character set utf8mb4 collate utf8mb4_unicode_ci;' + - mysql -e 'CREATE DATABASE IF NOT EXISTS forum default character set utf8mb4 collate utf8mb4_unicode_ci;' - npm install sequelize-cli -g # 在執行測試之前的指令 before_script: - - sequelize db:migrate \ No newline at end of file + - sequelize db:migrate From ec2c6dfa2008eeafedabd2335ae7b81a08fdb0b8 Mon Sep 17 00:00:00 2001 From: Serena Tseng <51045074+Carrot7712@users.noreply.github.com> Date: Sat, 6 Nov 2021 00:29:51 +0800 Subject: [PATCH 072/135] Update .travis.yml --- .travis.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index fdf50b79..f08c1b5e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: node_js node_js: - - "10" + - "14" services: - mysql @@ -16,4 +16,5 @@ before_install: # 在執行測試之前的指令 before_script: - - sequelize db:migrate + - sequelize db:migrate + - sequelize db:seed:all From 80d4dd130931d520be0ebe7b31e772c9bf6dbf04 Mon Sep 17 00:00:00 2001 From: Carrot7712 Date: Wed, 3 Nov 2021 15:28:42 +0800 Subject: [PATCH 073/135] update readme config.json package.json --- README.md | 26 +- config/config.json | 14 +- package-lock.json | 2540 +------------------------------------------- package.json | 28 +- 4 files changed, 39 insertions(+), 2569 deletions(-) diff --git a/README.md b/README.md index e4cd70f1..9172af88 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,6 @@ 1. Fork 2. git clone -3. 更改專案名稱 ## 初始化 ### Initialize @@ -16,14 +15,6 @@ npm install ``` create database forum; -create database forum_test; -``` - -### 切換環境 - -``` -export NODE_ENV=test # 切換到測試環境,如果在等號後加其他的字串,則會切到其他的環境 -echo $NODE_ENV # 印出目前使用的環境 ``` ### 執行測試 @@ -32,11 +23,11 @@ npm run test ``` ## 下載作業規格 -以 A17 為例 +以 R01 為例 ``` -git checkout -b A17 # 開新分支 -git merge origin/A17-test # 下載作業規格 +git checkout -b R01 # 開新分支 +git merge origin/R01-test # 下載作業規格 npm run test # 直到綠燈全亮 git add . @@ -46,11 +37,16 @@ git commit -m "...." ## 繳交作業 ``` -git push origin A17 # 上傳本地進度 +git push origin R01 # 上傳本地進度 ``` 接著改成到 GitHub 來發 PR。 ## 共用帳號 -請一律設定一個共用的 root user -root@example.com,登入密碼 12345678 +請一律設定下面 2 組帳號以利驗收: +* 第一組帳號有 admin 權限: + * email: root@example.com + * password: 12345678 +* 第二組帳號沒有 admin 權限: + * email: user1@example.com + * password: 12345678 \ No newline at end of file diff --git a/config/config.json b/config/config.json index 56636a1c..2b8be8e7 100644 --- a/config/config.json +++ b/config/config.json @@ -6,16 +6,12 @@ "host": "127.0.0.1", "dialect": "mysql" }, - "test": { + "production": { "username": "root", - "password": "password", - "database": "forum_test", + "password": null, + "database": "database_production", "host": "127.0.0.1", - "dialect": "mysql", - "logging": false - }, - "production": { - "use_env_variable": "CLEARDB_SILVER_URL" + "dialect": "mysql" }, "travis": { "username": "travis", @@ -24,4 +20,4 @@ "dialect": "mysql", "logging": false } -} \ No newline at end of file +} diff --git a/package-lock.json b/package-lock.json index 7ebc04a3..bb00f848 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,2480 +1,8 @@ { "name": "forum-express-workspace", "version": "1.0.0", - "lockfileVersion": 2, + "lockfileVersion": 1, "requires": true, - "packages": { - "": { - "name": "forum-express-workspace", - "version": "1.0.0", - "license": "ISC", - "dependencies": { - "chai": "^4.2.0", - "express": "^4.17.1", - "mocha": "^8.2.0", - "mysql2": "^2.2.5", - "sequelize": "^6.3.5", - "sequelize-cli": "^6.2.0", - "sinon": "^9.2.0", - "supertest": "^5.0.0" - }, - "devDependencies": { - "proxyquire": "^2.1.3", - "sequelize-mock": "^0.10.2" - } - }, - "node_modules/@sinonjs/commons": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.1.tgz", - "integrity": "sha512-892K+kWUUi3cl+LlqEWIDrhvLgdL79tECi8JZUyq6IviKy/DNhuzCRlbHUjxK89f4ypPMMaFnFuR9Ie6DoIMsw==", - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@sinonjs/fake-timers": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", - "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", - "dependencies": { - "@sinonjs/commons": "^1.7.0" - } - }, - "node_modules/@sinonjs/formatio": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-5.0.1.tgz", - "integrity": "sha512-KaiQ5pBf1MpS09MuA0kp6KBQt2JUOQycqVG1NZXvzeaXe5LGFqAKueIS0bw4w0P9r7KuBSVdUk5QjXsUdu2CxQ==", - "dependencies": { - "@sinonjs/commons": "^1", - "@sinonjs/samsam": "^5.0.2" - } - }, - "node_modules/@sinonjs/samsam": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-5.2.0.tgz", - "integrity": "sha512-CaIcyX5cDsjcW/ab7HposFWzV1kC++4HNsfnEdFJa7cP1QIuILAKV+BgfeqRXhcnSAc76r/Rh/O5C+300BwUIw==", - "dependencies": { - "@sinonjs/commons": "^1.6.0", - "lodash.get": "^4.4.2", - "type-detect": "^4.0.8" - } - }, - "node_modules/@sinonjs/text-encoding": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", - "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==" - }, - "node_modules/@types/node": { - "version": "14.14.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.5.tgz", - "integrity": "sha512-H5Wn24s/ZOukBmDn03nnGTp18A60ny9AmCwnEcgJiTgSGsCO7k+NWP7zjCCbhlcnVCoI+co52dUAt9GMhOSULw==" - }, - "node_modules/@ungap/promise-all-settled": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", - "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==" - }, - "node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" - }, - "node_modules/accepts": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", - "dependencies": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=" - }, - "node_modules/anymatch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", - "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" - }, - "node_modules/assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "engines": { - "node": "*" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, - "node_modules/balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" - }, - "node_modules/binary-extensions": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", - "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" - }, - "node_modules/body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", - "dependencies": { - "bytes": "3.1.0", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.7.0", - "raw-body": "2.4.0", - "type-is": "~1.6.17" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==" - }, - "node_modules/bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/chai": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", - "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", - "dependencies": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.2", - "deep-eql": "^3.0.1", - "get-func-name": "^2.0.0", - "pathval": "^1.1.0", - "type-detect": "^4.0.5" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chalk/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/chalk/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/chalk/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/check-error": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", - "engines": { - "node": "*" - } - }, - "node_modules/chokidar": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz", - "integrity": "sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==", - "dependencies": { - "anymatch": "~3.1.1", - "braces": "~3.0.2", - "glob-parent": "~5.1.0", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.5.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.1.2" - } - }, - "node_modules/cli-color": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-1.4.0.tgz", - "integrity": "sha512-xu6RvQqqrWEo6MPR1eixqGPywhYBHRs653F9jfXB2Hx4jdM/3WxiNE1vppRmxtMIfl16SFYTpYlrnqH/HsK/2w==", - "dependencies": { - "ansi-regex": "^2.1.1", - "d": "1", - "es5-ext": "^0.10.46", - "es6-iterator": "^2.0.3", - "memoizee": "^0.4.14", - "timers-ext": "^0.1.5" - } - }, - "node_modules/cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", - "dependencies": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - }, - "node_modules/component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "node_modules/config-chain": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz", - "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==", - "dependencies": { - "ini": "^1.3.4", - "proto-list": "~1.2.1" - } - }, - "node_modules/content-disposition": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", - "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", - "dependencies": { - "safe-buffer": "5.1.2" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/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==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" - }, - "node_modules/cookiejar": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz", - "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==" - }, - "node_modules/d": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", - "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", - "dependencies": { - "es5-ext": "^0.10.50", - "type": "^1.0.1" - } - }, - "node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/deep-eql": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", - "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", - "dependencies": { - "type-detect": "^4.0.0" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/denque": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/denque/-/denque-1.4.1.tgz", - "integrity": "sha512-OfzPuSZKGcgr96rf1oODnfjqBFmr1DVoc/TrItj3Ohe0Ah1C5WX5Baquw/9U9KovnQ88EqmJbD66rKYUQYN1tQ==", - "engines": { - "node": ">=0.10" - } - }, - "node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" - }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/dottie": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.2.tgz", - "integrity": "sha512-fmrwR04lsniq/uSr8yikThDTrM7epXHBAAjH9TbeH3rEA8tdCO7mRzB9hdmdGyJCxF8KERo9CITcm3kGuoyMhg==" - }, - "node_modules/editorconfig": { - "version": "0.15.3", - "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz", - "integrity": "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==", - "dependencies": { - "commander": "^2.19.0", - "lru-cache": "^4.1.5", - "semver": "^5.6.0", - "sigmund": "^1.0.1" - }, - "bin": { - "editorconfig": "bin/editorconfig" - } - }, - "node_modules/editorconfig/node_modules/lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dependencies": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "node_modules/editorconfig/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/editorconfig/node_modules/yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" - }, - "node_modules/emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" - }, - "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/es5-ext": { - "version": "0.10.53", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", - "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", - "dependencies": { - "es6-iterator": "~2.0.3", - "es6-symbol": "~3.1.3", - "next-tick": "~1.0.0" - } - }, - "node_modules/es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", - "dependencies": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, - "node_modules/es6-symbol": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", - "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", - "dependencies": { - "d": "^1.0.1", - "ext": "^1.1.2" - } - }, - "node_modules/es6-weak-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", - "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", - "dependencies": { - "d": "1", - "es5-ext": "^0.10.46", - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.1" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/event-emitter": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", - "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", - "dependencies": { - "d": "1", - "es5-ext": "~0.10.14" - } - }, - "node_modules/express": { - "version": "4.17.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", - "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", - "dependencies": { - "accepts": "~1.3.7", - "array-flatten": "1.1.1", - "body-parser": "1.19.0", - "content-disposition": "0.5.3", - "content-type": "~1.0.4", - "cookie": "0.4.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "~1.1.2", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "~1.1.2", - "fresh": "0.5.2", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.5", - "qs": "6.7.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.1.2", - "send": "0.17.1", - "serve-static": "1.14.1", - "setprototypeof": "1.1.1", - "statuses": "~1.5.0", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/ext": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", - "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", - "dependencies": { - "type": "^2.0.0" - } - }, - "node_modules/ext/node_modules/type": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/type/-/type-2.1.0.tgz", - "integrity": "sha512-G9absDWvhAWCV2gmF1zKud3OyC61nZDwWvBL2DApaVFogI07CprggiQAOOjvp2NRjYWFzPyu7vwtDrQFq8jeSA==" - }, - "node_modules/fast-safe-stringify": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", - "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==" - }, - "node_modules/fill-keys": { - "version": "1.0.2", - "resolved": "http://npm.ooapi.com:4873/fill-keys/-/fill-keys-1.0.2.tgz", - "integrity": "sha1-mo+jb06K1jTjv2tPPIiCVRRS6yA=", - "dev": true, - "dependencies": { - "is-object": "~1.0.1", - "merge-descriptors": "~1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dependencies": { - "locate-path": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "bin": { - "flat": "cli.js" - } - }, - "node_modules/form-data": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.0.tgz", - "integrity": "sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/formidable": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.2.tgz", - "integrity": "sha512-V8gLm+41I/8kguQ4/o1D3RIHRmhYFG4pnNyonvua+40rqcEmT4+V71yaZ3B457xbbgCsCfjSPi65u/W6vK1U5Q==", - "funding": { - "url": "https://ko-fi.com/tunnckoCore/commissions" - } - }, - "node_modules/forwarded": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", - "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fs-extra": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", - "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", - "dependencies": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "node_modules/fsevents": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", - "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", - "deprecated": "\"Please update to latest v2.3 or v2.2\"", - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "node_modules/generate-function": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", - "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", - "dependencies": { - "is-property": "^1.0.2" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-func-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", - "engines": { - "node": "*" - } - }, - "node_modules/glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==" - }, - "node_modules/growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", - "engines": { - "node": ">=4.x" - } - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "bin": { - "he": "bin/he" - } - }, - "node_modules/http-errors": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", - "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/inflection": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz", - "integrity": "sha1-ogCTVlbW9fa8TcdQLhrstwMihBY=", - "engines": [ - "node >= 0.4.0" - ] - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "node_modules/ini": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", - "deprecated": "Please update to ini >=1.3.6 to avoid a prototype pollution issue", - "engines": { - "node": "*" - } - }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-core-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.0.0.tgz", - "integrity": "sha512-jq1AH6C8MuteOoBPwkxHafmByhL9j5q4OaPGdbuD+ZtQJVzH+i6E3BJDQcBA09k57i2Hh2yQbEG8yObZ0jdlWw==", - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "engines": { - "node": ">=4" - } - }, - "node_modules/is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-object": { - "version": "1.0.2", - "resolved": "http://npm.ooapi.com:4873/is-object/-/is-object-1.0.2.tgz", - "integrity": "sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-promise": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", - "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==" - }, - "node_modules/is-property": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", - "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=" - }, - "node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" - }, - "node_modules/js-beautify": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.13.0.tgz", - "integrity": "sha512-/Tbp1OVzZjbwzwJQFIlYLm9eWQ+3aYbBXLSaqb1mEJzhcQAfrqMMQYtjb6io+U6KpD0ID4F+Id3/xcjH3l/sqA==", - "dependencies": { - "config-chain": "^1.1.12", - "editorconfig": "^0.15.3", - "glob": "^7.1.3", - "mkdirp": "^1.0.4", - "nopt": "^5.0.0" - }, - "bin": { - "css-beautify": "js/bin/css-beautify.js", - "html-beautify": "js/bin/html-beautify.js", - "js-beautify": "js/bin/js-beautify.js" - } - }, - "node_modules/js-yaml": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", - "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/just-extend": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.1.1.tgz", - "integrity": "sha512-aWgeGFW67BP3e5181Ep1Fv2v8z//iBJfrvyTnq8wG86vEESwmonn1zPBJ0VfmT9CJq2FIT0VsETtrNFm2a+SHA==" - }, - "node_modules/locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/lodash": { - "version": "4.17.20", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", - "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" - }, - "node_modules/lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" - }, - "node_modules/log-symbols": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", - "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==", - "dependencies": { - "chalk": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/long": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", - "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/lru-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", - "integrity": "sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM=", - "dependencies": { - "es5-ext": "~0.10.2" - } - }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/memoizee": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.14.tgz", - "integrity": "sha512-/SWFvWegAIYAO4NQMpcX+gcra0yEZu4OntmUdrBaWrJncxOqAziGFlHxc7yjKVK2uu3lpPW27P27wkR82wA8mg==", - "dependencies": { - "d": "1", - "es5-ext": "^0.10.45", - "es6-weak-map": "^2.0.2", - "event-emitter": "^0.3.5", - "is-promise": "^2.1", - "lru-queue": "0.1", - "next-tick": "1", - "timers-ext": "^0.1.5" - } - }, - "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/mime-db": { - "version": "1.44.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", - "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.27", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", - "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", - "dependencies": { - "mime-db": "1.44.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mocha": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.2.0.tgz", - "integrity": "sha512-lEWEMq2LMfNJMKeuEwb5UELi+OgFDollXaytR5ggQcHpzG3NP/R7rvixAvF+9/lLsTWhWG+4yD2M70GsM06nxw==", - "dependencies": { - "@ungap/promise-all-settled": "1.1.2", - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.4.3", - "debug": "4.2.0", - "diff": "4.0.2", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.1.6", - "growl": "1.10.5", - "he": "1.2.0", - "js-yaml": "3.14.0", - "log-symbols": "4.0.0", - "minimatch": "3.0.4", - "ms": "2.1.2", - "nanoid": "3.1.12", - "serialize-javascript": "5.0.1", - "strip-json-comments": "3.1.1", - "supports-color": "7.2.0", - "which": "2.0.2", - "wide-align": "1.1.3", - "workerpool": "6.0.2", - "yargs": "13.3.2", - "yargs-parser": "13.1.2", - "yargs-unparser": "2.0.0" - }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha" - }, - "engines": { - "node": ">= 10.12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mochajs" - } - }, - "node_modules/mocha/node_modules/debug": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", - "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", - "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/mocha/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mocha/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mocha/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/mocha/node_modules/p-limit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.0.2.tgz", - "integrity": "sha512-iwqZSOoWIW+Ew4kAGUlN16J4M7OB3ysMLSZtnhmqx7njIHFPlxWBX8xo3lVTyFVq6mI/lL9qt2IsN1sHwaxJkg==", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mocha/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mocha/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "engines": { - "node": ">=8" - } - }, - "node_modules/module-not-found-error": { - "version": "1.0.1", - "resolved": "http://npm.ooapi.com:4873/module-not-found-error/-/module-not-found-error-1.0.1.tgz", - "integrity": "sha1-z4tP9PKWQGdNbN0CsOO8UjwrvcA=", - "dev": true - }, - "node_modules/moment": { - "version": "2.29.1", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", - "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==", - "engines": { - "node": "*" - } - }, - "node_modules/moment-timezone": { - "version": "0.5.31", - "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.31.tgz", - "integrity": "sha512-+GgHNg8xRhMXfEbv81iDtrVeTcWt0kWmTEY1XQK14dICTXnWJnT0dxdlPspwqF3keKMVPXwayEsk1DI0AA/jdA==", - "dependencies": { - "moment": ">= 2.9.0" - }, - "engines": { - "node": "*" - } - }, - "node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "node_modules/mysql2": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-2.2.5.tgz", - "integrity": "sha512-XRqPNxcZTpmFdXbJqb+/CtYVLCx14x1RTeNMD4954L331APu75IC74GDqnZMEt1kwaXy6TySo55rF2F3YJS78g==", - "dependencies": { - "denque": "^1.4.1", - "generate-function": "^2.3.1", - "iconv-lite": "^0.6.2", - "long": "^4.0.0", - "lru-cache": "^6.0.0", - "named-placeholders": "^1.1.2", - "seq-queue": "^0.0.5", - "sqlstring": "^2.3.2" - }, - "engines": { - "node": ">= 8.0" - } - }, - "node_modules/mysql2/node_modules/iconv-lite": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz", - "integrity": "sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/named-placeholders": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.2.tgz", - "integrity": "sha512-wiFWqxoLL3PGVReSZpjLVxyJ1bRqe+KKJVbr4hGs1KWfTZTQyezHFBbuKj9hsizHyGV2ne7EMjHdxEGAybD5SA==", - "dependencies": { - "lru-cache": "^4.1.3" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/named-placeholders/node_modules/lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dependencies": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "node_modules/named-placeholders/node_modules/yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" - }, - "node_modules/nanoid": { - "version": "3.1.12", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.12.tgz", - "integrity": "sha512-1qstj9z5+x491jfiC4Nelk+f8XBad7LN20PmyWINJEMRSf3wcAjAWysw1qaA8z6NSKe2sjq1hRSDpBH5paCb6A==", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || >=13.7" - } - }, - "node_modules/negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/next-tick": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", - "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" - }, - "node_modules/nise": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/nise/-/nise-4.0.4.tgz", - "integrity": "sha512-bTTRUNlemx6deJa+ZyoCUTRvH3liK5+N6VQZ4NIw90AgDXY6iPnsqplNFf6STcj+ePk0H/xqxnP75Lr0J0Fq3A==", - "dependencies": { - "@sinonjs/commons": "^1.7.0", - "@sinonjs/fake-timers": "^6.0.0", - "@sinonjs/text-encoding": "^0.7.1", - "just-extend": "^4.0.2", - "path-to-regexp": "^1.7.0" - } - }, - "node_modules/nise/node_modules/path-to-regexp": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", - "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", - "dependencies": { - "isarray": "0.0.1" - } - }, - "node_modules/nopt": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", - "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", - "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dependencies": { - "p-limit": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "engines": { - "node": ">=6" - } - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "engines": { - "node": ">=4" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" - }, - "node_modules/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=" - }, - "node_modules/pathval": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", - "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", - "engines": { - "node": "*" - } - }, - "node_modules/picomatch": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/proto-list": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", - "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=" - }, - "node_modules/proxy-addr": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", - "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", - "dependencies": { - "forwarded": "~0.1.2", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/proxyquire": { - "version": "2.1.3", - "resolved": "http://npm.ooapi.com:4873/proxyquire/-/proxyquire-2.1.3.tgz", - "integrity": "sha512-BQWfCqYM+QINd+yawJz23tbBM40VIGXOdDw3X344KcclI/gtBbdWF6SlQ4nK/bYhF9d27KYug9WzljHC6B9Ysg==", - "dev": true, - "dependencies": { - "fill-keys": "^1.0.2", - "module-not-found-error": "^1.0.1", - "resolve": "^1.11.1" - } - }, - "node_modules/pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" - }, - "node_modules/qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", - "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", - "dependencies": { - "bytes": "3.1.0", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/readdirp": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", - "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" - }, - "node_modules/resolve": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.18.1.tgz", - "integrity": "sha512-lDfCPaMKfOJXjy0dPayzPdF1phampNWr3qFCjAu+rw/qbQmr5jWH5xN2hwh9QKfw9E5v4hwV7A+jrCmL8yjjqA==", - "dependencies": { - "is-core-module": "^2.0.0", - "path-parse": "^1.0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/retry-as-promised": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/retry-as-promised/-/retry-as-promised-3.2.0.tgz", - "integrity": "sha512-CybGs60B7oYU/qSQ6kuaFmRd9sTZ6oXSc0toqePvV74Ac6/IFZSI1ReFQmtCN+uvW1Mtqdwpvt/LGOiCBAY2Mg==", - "dependencies": { - "any-promise": "^1.3.0" - } - }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "node_modules/semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/send": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", - "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", - "dependencies": { - "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "~1.7.2", - "mime": "1.6.0", - "ms": "2.1.1", - "on-finished": "~2.3.0", - "range-parser": "~1.2.1", - "statuses": "~1.5.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/send/node_modules/ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" - }, - "node_modules/seq-queue": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", - "integrity": "sha1-1WgS4cAXpuTnw+Ojeh2m143TyT4=" - }, - "node_modules/sequelize": { - "version": "6.3.5", - "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-6.3.5.tgz", - "integrity": "sha512-MiwiPkYSA8NWttRKAXdU9h0TxP6HAc1fl7qZmMO/VQqQOND83G4nZLXd0kWILtAoT9cxtZgFqeb/MPYgEeXwsw==", - "dependencies": { - "debug": "^4.1.1", - "dottie": "^2.0.0", - "inflection": "1.12.0", - "lodash": "^4.17.15", - "moment": "^2.26.0", - "moment-timezone": "^0.5.31", - "retry-as-promised": "^3.2.0", - "semver": "^7.3.2", - "sequelize-pool": "^6.0.0", - "toposort-class": "^1.0.1", - "uuid": "^8.1.0", - "validator": "^10.11.0", - "wkx": "^0.5.0" - }, - "engines": { - "node": ">=10.0.0" - }, - "peerDependenciesMeta": { - "mariadb": { - "optional": true - }, - "mysql2": { - "optional": true - }, - "pg": { - "optional": true - }, - "pg-hstore": { - "optional": true - }, - "sqlite3": { - "optional": true - }, - "tedious": { - "optional": true - } - } - }, - "node_modules/sequelize-cli": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/sequelize-cli/-/sequelize-cli-6.2.0.tgz", - "integrity": "sha512-6WQ2x91hg30dUn66mXHnzvHATZ4pyI1GHSNbS/TNN/vRR4BLRSLijadeMgC8zqmKDsL0VqzVVopJWfJakuP++Q==", - "dependencies": { - "cli-color": "^1.4.0", - "fs-extra": "^7.0.1", - "js-beautify": "^1.8.8", - "lodash": "^4.17.5", - "resolve": "^1.5.0", - "umzug": "^2.3.0", - "yargs": "^13.1.0" - }, - "bin": { - "sequelize": "lib/sequelize", - "sequelize-cli": "lib/sequelize" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/sequelize-mock": { - "version": "0.10.2", - "resolved": "http://npm.ooapi.com:4873/sequelize-mock/-/sequelize-mock-0.10.2.tgz", - "integrity": "sha1-GdOXHM2utbhkFwwkznkqinHxRL0=", - "dev": true, - "dependencies": { - "bluebird": "^3.4.6", - "inflection": "^1.10.0", - "lodash": "^4.16.4" - } - }, - "node_modules/sequelize-pool": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/sequelize-pool/-/sequelize-pool-6.1.0.tgz", - "integrity": "sha512-4YwEw3ZgK/tY/so+GfnSgXkdwIJJ1I32uZJztIEgZeAO6HMgj64OzySbWLgxj+tXhZCJnzRfkY9gINw8Ft8ZMg==", - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/sequelize/node_modules/debug": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", - "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", - "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/sequelize/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/serialize-javascript": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", - "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/serve-static": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", - "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", - "dependencies": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.17.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" - }, - "node_modules/setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" - }, - "node_modules/sigmund": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", - "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=" - }, - "node_modules/sinon": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-9.2.0.tgz", - "integrity": "sha512-eSNXz1XMcGEMHw08NJXSyTHIu6qTCOiN8x9ODACmZpNQpr0aXTBXBnI4xTzQzR+TEpOmLiKowGf9flCuKIzsbw==", - "dependencies": { - "@sinonjs/commons": "^1.8.1", - "@sinonjs/fake-timers": "^6.0.1", - "@sinonjs/formatio": "^5.0.1", - "@sinonjs/samsam": "^5.2.0", - "diff": "^4.0.2", - "nise": "^4.0.4", - "supports-color": "^7.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/sinon" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" - }, - "node_modules/sqlstring": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.2.tgz", - "integrity": "sha512-vF4ZbYdKS8OnoJAWBmMxCQDkiEBkGQYU7UZPtL8flbDRSNkhaXvRJ279ZtI6M+zDaQovVU4tuRgzK5fVhvFAhg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string_decoder/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dependencies": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dependencies": { - "ansi-regex": "^4.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-ansi/node_modules/ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/superagent": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/superagent/-/superagent-6.1.0.tgz", - "integrity": "sha512-OUDHEssirmplo3F+1HWKUrUjvnQuA+nZI6i/JJBdXb5eq9IyEQwPyPpqND+SSsxf6TygpBEkUjISVRN4/VOpeg==", - "dependencies": { - "component-emitter": "^1.3.0", - "cookiejar": "^2.1.2", - "debug": "^4.1.1", - "fast-safe-stringify": "^2.0.7", - "form-data": "^3.0.0", - "formidable": "^1.2.2", - "methods": "^1.1.2", - "mime": "^2.4.6", - "qs": "^6.9.4", - "readable-stream": "^3.6.0", - "semver": "^7.3.2" - }, - "engines": { - "node": ">= 7.0.0" - } - }, - "node_modules/superagent/node_modules/debug": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", - "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", - "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/superagent/node_modules/mime": { - "version": "2.4.6", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz", - "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/superagent/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/superagent/node_modules/qs": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz", - "integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==", - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/supertest": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/supertest/-/supertest-5.0.0.tgz", - "integrity": "sha512-2JAWpPrUOZF4hHH5ZTCN2xjKXvJS3AEwPNXl0HUseHsfcXFvMy9kcsufIHCNAmQ5hlGCvgeAqaR5PBEouN3hlQ==", - "dependencies": { - "methods": "1.1.2", - "superagent": "6.1.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/timers-ext": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz", - "integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==", - "dependencies": { - "es5-ext": "~0.10.46", - "next-tick": "1" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/toposort-class": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toposort-class/-/toposort-class-1.0.1.tgz", - "integrity": "sha1-f/0feMi+KMO6Rc1OGj9e4ZO9mYg=" - }, - "node_modules/type": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", - "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" - }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "engines": { - "node": ">=4" - } - }, - "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/umzug": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/umzug/-/umzug-2.3.0.tgz", - "integrity": "sha512-Z274K+e8goZK8QJxmbRPhl89HPO1K+ORFtm6rySPhFKfKc5GHhqdzD0SGhSWHkzoXasqJuItdhorSvY7/Cgflw==", - "dependencies": { - "bluebird": "^3.7.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/uuid": { - "version": "8.3.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.1.tgz", - "integrity": "sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg==", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/validator": { - "version": "10.11.0", - "resolved": "https://registry.npmjs.org/validator/-/validator-10.11.0.tgz", - "integrity": "sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw==", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" - }, - "node_modules/wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", - "dependencies": { - "string-width": "^1.0.2 || 2" - } - }, - "node_modules/wide-align/node_modules/ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "engines": { - "node": ">=4" - } - }, - "node_modules/wide-align/node_modules/string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dependencies": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/wide-align/node_modules/strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dependencies": { - "ansi-regex": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/wkx": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/wkx/-/wkx-0.5.0.tgz", - "integrity": "sha512-Xng/d4Ichh8uN4l0FToV/258EjMGU9MGcA0HV2d9B/ZpZB3lqQm7nkOdZdm5GhKtLLhAE7PiVQwN4eN+2YJJUg==", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/workerpool": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.0.2.tgz", - "integrity": "sha512-DSNyvOpFKrNusaaUwk+ej6cBj1bmhLcBfj80elGk+ZIo5JSkq+unB1dLKEOcNfJDZgjGICfhQ0Q5TbP0PvF4+Q==" - }, - "node_modules/wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", - "dependencies": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "node_modules/y18n": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", - "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==" - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "node_modules/yargs": { - "version": "13.3.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", - "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", - "dependencies": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.2" - } - }, - "node_modules/yargs-parser": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", - "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - }, - "node_modules/yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dependencies": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-unparser/node_modules/camelcase": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", - "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/yargs-unparser/node_modules/decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - }, "dependencies": { "@sinonjs/commons": { "version": "1.8.1", @@ -3053,16 +581,6 @@ "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==" }, - "fill-keys": { - "version": "1.0.2", - "resolved": "http://npm.ooapi.com:4873/fill-keys/-/fill-keys-1.0.2.tgz", - "integrity": "sha1-mo+jb06K1jTjv2tPPIiCVRRS6yA=", - "dev": true, - "requires": { - "is-object": "~1.0.1", - "merge-descriptors": "~1.0.0" - } - }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -3304,12 +822,6 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" }, - "is-object": { - "version": "1.0.2", - "resolved": "http://npm.ooapi.com:4873/is-object/-/is-object-1.0.2.tgz", - "integrity": "sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==", - "dev": true - }, "is-plain-obj": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", @@ -3563,12 +1075,6 @@ } } }, - "module-not-found-error": { - "version": "1.0.1", - "resolved": "http://npm.ooapi.com:4873/module-not-found-error/-/module-not-found-error-1.0.1.tgz", - "integrity": "sha1-z4tP9PKWQGdNbN0CsOO8UjwrvcA=", - "dev": true - }, "moment": { "version": "2.29.1", "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", @@ -3772,17 +1278,6 @@ "ipaddr.js": "1.9.1" } }, - "proxyquire": { - "version": "2.1.3", - "resolved": "http://npm.ooapi.com:4873/proxyquire/-/proxyquire-2.1.3.tgz", - "integrity": "sha512-BQWfCqYM+QINd+yawJz23tbBM40VIGXOdDw3X344KcclI/gtBbdWF6SlQ4nK/bYhF9d27KYug9WzljHC6B9Ysg==", - "dev": true, - "requires": { - "fill-keys": "^1.0.2", - "module-not-found-error": "^1.0.1", - "resolve": "^1.11.1" - } - }, "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", @@ -3958,17 +1453,6 @@ "yargs": "^13.1.0" } }, - "sequelize-mock": { - "version": "0.10.2", - "resolved": "http://npm.ooapi.com:4873/sequelize-mock/-/sequelize-mock-0.10.2.tgz", - "integrity": "sha1-GdOXHM2utbhkFwwkznkqinHxRL0=", - "dev": true, - "requires": { - "bluebird": "^3.4.6", - "inflection": "^1.10.0", - "lodash": "^4.16.4" - } - }, "sequelize-pool": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/sequelize-pool/-/sequelize-pool-6.1.0.tgz", @@ -4037,6 +1521,16 @@ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, "string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -4052,16 +1546,6 @@ } } }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, "strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", @@ -4364,4 +1848,4 @@ } } } -} +} \ No newline at end of file diff --git a/package.json b/package.json index c25bd055..5f6f1d0f 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,6 @@ { - "name": "forum-express-workspace", - "version": "1.0.0", - "description": "", + "name": "forum-express-grading", + "version": "2.0.0", "main": "_helpers.js", "scripts": { "start": "node app.js", @@ -10,26 +9,21 @@ }, "repository": { "type": "git", - "url": "git+https://github.com/v123582/forum-express-workspace.git" + "url": "git+https://github.com/ALPHACamp/forum-express-grading.git" }, - "author": "", - "license": "ISC", - "bugs": { - "url": "https://github.com/v123582/forum-express-workspace/issues" - }, - "homepage": "https://github.com/v123582/forum-express-workspace#readme", "dependencies": { - "chai": "^4.2.0", "express": "^4.17.1", - "mocha": "^8.2.0", "mysql2": "^2.2.5", + "nodemon": "^2.0.12", "sequelize": "^6.3.5", - "sequelize-cli": "^6.2.0", - "sinon": "^9.2.0", - "supertest": "^5.0.0" + "sequelize-cli": "^6.2.0" }, "devDependencies": { + "chai": "^4.2.0", + "mocha": "^8.2.0", "proxyquire": "^2.1.3", - "sequelize-mock": "^0.10.2" + "sequelize-mock": "^0.10.2", + "sinon": "^9.2.0", + "supertest": "^5.0.0" } -} +} \ No newline at end of file From 7dc7a56d0d7dea94585dd0f47db7143139dce60c Mon Sep 17 00:00:00 2001 From: Serena Tseng <51045074+Carrot7712@users.noreply.github.com> Date: Sat, 6 Nov 2021 00:14:56 +0800 Subject: [PATCH 074/135] Update .travis.yml --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9635c20c..fdf50b79 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,9 +11,9 @@ env: # 在 install 前執行的指令 before_install: - - mysql -e 'CREATE DATABASE IF NOT EXISTS forum_test default character set utf8mb4 collate utf8mb4_unicode_ci;' + - mysql -e 'CREATE DATABASE IF NOT EXISTS forum default character set utf8mb4 collate utf8mb4_unicode_ci;' - npm install sequelize-cli -g # 在執行測試之前的指令 before_script: - - sequelize db:migrate \ No newline at end of file + - sequelize db:migrate From 88575dacb96db474e35bd8386b962cc25bed5ca6 Mon Sep 17 00:00:00 2001 From: Serena Tseng <51045074+Carrot7712@users.noreply.github.com> Date: Sat, 6 Nov 2021 00:29:51 +0800 Subject: [PATCH 075/135] Update .travis.yml --- .travis.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index fdf50b79..f08c1b5e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: node_js node_js: - - "10" + - "14" services: - mysql @@ -16,4 +16,5 @@ before_install: # 在執行測試之前的指令 before_script: - - sequelize db:migrate + - sequelize db:migrate + - sequelize db:seed:all From dd4522bd69820fa0fdd7e30080ee89310bebbbbd Mon Sep 17 00:00:00 2001 From: Carrot7712 Date: Wed, 3 Nov 2021 15:28:42 +0800 Subject: [PATCH 076/135] update readme config.json package.json --- README.md | 26 +- config/config.json | 14 +- package-lock.json | 2540 +------------------------------------------- package.json | 28 +- 4 files changed, 39 insertions(+), 2569 deletions(-) diff --git a/README.md b/README.md index e4cd70f1..9172af88 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,6 @@ 1. Fork 2. git clone -3. 更改專案名稱 ## 初始化 ### Initialize @@ -16,14 +15,6 @@ npm install ``` create database forum; -create database forum_test; -``` - -### 切換環境 - -``` -export NODE_ENV=test # 切換到測試環境,如果在等號後加其他的字串,則會切到其他的環境 -echo $NODE_ENV # 印出目前使用的環境 ``` ### 執行測試 @@ -32,11 +23,11 @@ npm run test ``` ## 下載作業規格 -以 A17 為例 +以 R01 為例 ``` -git checkout -b A17 # 開新分支 -git merge origin/A17-test # 下載作業規格 +git checkout -b R01 # 開新分支 +git merge origin/R01-test # 下載作業規格 npm run test # 直到綠燈全亮 git add . @@ -46,11 +37,16 @@ git commit -m "...." ## 繳交作業 ``` -git push origin A17 # 上傳本地進度 +git push origin R01 # 上傳本地進度 ``` 接著改成到 GitHub 來發 PR。 ## 共用帳號 -請一律設定一個共用的 root user -root@example.com,登入密碼 12345678 +請一律設定下面 2 組帳號以利驗收: +* 第一組帳號有 admin 權限: + * email: root@example.com + * password: 12345678 +* 第二組帳號沒有 admin 權限: + * email: user1@example.com + * password: 12345678 \ No newline at end of file diff --git a/config/config.json b/config/config.json index 56636a1c..2b8be8e7 100644 --- a/config/config.json +++ b/config/config.json @@ -6,16 +6,12 @@ "host": "127.0.0.1", "dialect": "mysql" }, - "test": { + "production": { "username": "root", - "password": "password", - "database": "forum_test", + "password": null, + "database": "database_production", "host": "127.0.0.1", - "dialect": "mysql", - "logging": false - }, - "production": { - "use_env_variable": "CLEARDB_SILVER_URL" + "dialect": "mysql" }, "travis": { "username": "travis", @@ -24,4 +20,4 @@ "dialect": "mysql", "logging": false } -} \ No newline at end of file +} diff --git a/package-lock.json b/package-lock.json index 7ebc04a3..bb00f848 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,2480 +1,8 @@ { "name": "forum-express-workspace", "version": "1.0.0", - "lockfileVersion": 2, + "lockfileVersion": 1, "requires": true, - "packages": { - "": { - "name": "forum-express-workspace", - "version": "1.0.0", - "license": "ISC", - "dependencies": { - "chai": "^4.2.0", - "express": "^4.17.1", - "mocha": "^8.2.0", - "mysql2": "^2.2.5", - "sequelize": "^6.3.5", - "sequelize-cli": "^6.2.0", - "sinon": "^9.2.0", - "supertest": "^5.0.0" - }, - "devDependencies": { - "proxyquire": "^2.1.3", - "sequelize-mock": "^0.10.2" - } - }, - "node_modules/@sinonjs/commons": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.1.tgz", - "integrity": "sha512-892K+kWUUi3cl+LlqEWIDrhvLgdL79tECi8JZUyq6IviKy/DNhuzCRlbHUjxK89f4ypPMMaFnFuR9Ie6DoIMsw==", - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@sinonjs/fake-timers": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", - "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", - "dependencies": { - "@sinonjs/commons": "^1.7.0" - } - }, - "node_modules/@sinonjs/formatio": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-5.0.1.tgz", - "integrity": "sha512-KaiQ5pBf1MpS09MuA0kp6KBQt2JUOQycqVG1NZXvzeaXe5LGFqAKueIS0bw4w0P9r7KuBSVdUk5QjXsUdu2CxQ==", - "dependencies": { - "@sinonjs/commons": "^1", - "@sinonjs/samsam": "^5.0.2" - } - }, - "node_modules/@sinonjs/samsam": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-5.2.0.tgz", - "integrity": "sha512-CaIcyX5cDsjcW/ab7HposFWzV1kC++4HNsfnEdFJa7cP1QIuILAKV+BgfeqRXhcnSAc76r/Rh/O5C+300BwUIw==", - "dependencies": { - "@sinonjs/commons": "^1.6.0", - "lodash.get": "^4.4.2", - "type-detect": "^4.0.8" - } - }, - "node_modules/@sinonjs/text-encoding": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", - "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==" - }, - "node_modules/@types/node": { - "version": "14.14.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.5.tgz", - "integrity": "sha512-H5Wn24s/ZOukBmDn03nnGTp18A60ny9AmCwnEcgJiTgSGsCO7k+NWP7zjCCbhlcnVCoI+co52dUAt9GMhOSULw==" - }, - "node_modules/@ungap/promise-all-settled": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", - "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==" - }, - "node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" - }, - "node_modules/accepts": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", - "dependencies": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=" - }, - "node_modules/anymatch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", - "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" - }, - "node_modules/assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "engines": { - "node": "*" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, - "node_modules/balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" - }, - "node_modules/binary-extensions": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", - "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" - }, - "node_modules/body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", - "dependencies": { - "bytes": "3.1.0", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.7.0", - "raw-body": "2.4.0", - "type-is": "~1.6.17" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==" - }, - "node_modules/bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/chai": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", - "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", - "dependencies": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.2", - "deep-eql": "^3.0.1", - "get-func-name": "^2.0.0", - "pathval": "^1.1.0", - "type-detect": "^4.0.5" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chalk/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/chalk/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/chalk/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/check-error": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", - "engines": { - "node": "*" - } - }, - "node_modules/chokidar": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz", - "integrity": "sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==", - "dependencies": { - "anymatch": "~3.1.1", - "braces": "~3.0.2", - "glob-parent": "~5.1.0", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.5.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.1.2" - } - }, - "node_modules/cli-color": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-1.4.0.tgz", - "integrity": "sha512-xu6RvQqqrWEo6MPR1eixqGPywhYBHRs653F9jfXB2Hx4jdM/3WxiNE1vppRmxtMIfl16SFYTpYlrnqH/HsK/2w==", - "dependencies": { - "ansi-regex": "^2.1.1", - "d": "1", - "es5-ext": "^0.10.46", - "es6-iterator": "^2.0.3", - "memoizee": "^0.4.14", - "timers-ext": "^0.1.5" - } - }, - "node_modules/cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", - "dependencies": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - }, - "node_modules/component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "node_modules/config-chain": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz", - "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==", - "dependencies": { - "ini": "^1.3.4", - "proto-list": "~1.2.1" - } - }, - "node_modules/content-disposition": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", - "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", - "dependencies": { - "safe-buffer": "5.1.2" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/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==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" - }, - "node_modules/cookiejar": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz", - "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==" - }, - "node_modules/d": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", - "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", - "dependencies": { - "es5-ext": "^0.10.50", - "type": "^1.0.1" - } - }, - "node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/deep-eql": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", - "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", - "dependencies": { - "type-detect": "^4.0.0" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/denque": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/denque/-/denque-1.4.1.tgz", - "integrity": "sha512-OfzPuSZKGcgr96rf1oODnfjqBFmr1DVoc/TrItj3Ohe0Ah1C5WX5Baquw/9U9KovnQ88EqmJbD66rKYUQYN1tQ==", - "engines": { - "node": ">=0.10" - } - }, - "node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" - }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/dottie": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.2.tgz", - "integrity": "sha512-fmrwR04lsniq/uSr8yikThDTrM7epXHBAAjH9TbeH3rEA8tdCO7mRzB9hdmdGyJCxF8KERo9CITcm3kGuoyMhg==" - }, - "node_modules/editorconfig": { - "version": "0.15.3", - "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz", - "integrity": "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==", - "dependencies": { - "commander": "^2.19.0", - "lru-cache": "^4.1.5", - "semver": "^5.6.0", - "sigmund": "^1.0.1" - }, - "bin": { - "editorconfig": "bin/editorconfig" - } - }, - "node_modules/editorconfig/node_modules/lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dependencies": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "node_modules/editorconfig/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/editorconfig/node_modules/yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" - }, - "node_modules/emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" - }, - "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/es5-ext": { - "version": "0.10.53", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", - "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", - "dependencies": { - "es6-iterator": "~2.0.3", - "es6-symbol": "~3.1.3", - "next-tick": "~1.0.0" - } - }, - "node_modules/es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", - "dependencies": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, - "node_modules/es6-symbol": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", - "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", - "dependencies": { - "d": "^1.0.1", - "ext": "^1.1.2" - } - }, - "node_modules/es6-weak-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", - "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", - "dependencies": { - "d": "1", - "es5-ext": "^0.10.46", - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.1" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/event-emitter": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", - "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", - "dependencies": { - "d": "1", - "es5-ext": "~0.10.14" - } - }, - "node_modules/express": { - "version": "4.17.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", - "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", - "dependencies": { - "accepts": "~1.3.7", - "array-flatten": "1.1.1", - "body-parser": "1.19.0", - "content-disposition": "0.5.3", - "content-type": "~1.0.4", - "cookie": "0.4.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "~1.1.2", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "~1.1.2", - "fresh": "0.5.2", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.5", - "qs": "6.7.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.1.2", - "send": "0.17.1", - "serve-static": "1.14.1", - "setprototypeof": "1.1.1", - "statuses": "~1.5.0", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/ext": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", - "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", - "dependencies": { - "type": "^2.0.0" - } - }, - "node_modules/ext/node_modules/type": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/type/-/type-2.1.0.tgz", - "integrity": "sha512-G9absDWvhAWCV2gmF1zKud3OyC61nZDwWvBL2DApaVFogI07CprggiQAOOjvp2NRjYWFzPyu7vwtDrQFq8jeSA==" - }, - "node_modules/fast-safe-stringify": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", - "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==" - }, - "node_modules/fill-keys": { - "version": "1.0.2", - "resolved": "http://npm.ooapi.com:4873/fill-keys/-/fill-keys-1.0.2.tgz", - "integrity": "sha1-mo+jb06K1jTjv2tPPIiCVRRS6yA=", - "dev": true, - "dependencies": { - "is-object": "~1.0.1", - "merge-descriptors": "~1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dependencies": { - "locate-path": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "bin": { - "flat": "cli.js" - } - }, - "node_modules/form-data": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.0.tgz", - "integrity": "sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/formidable": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.2.tgz", - "integrity": "sha512-V8gLm+41I/8kguQ4/o1D3RIHRmhYFG4pnNyonvua+40rqcEmT4+V71yaZ3B457xbbgCsCfjSPi65u/W6vK1U5Q==", - "funding": { - "url": "https://ko-fi.com/tunnckoCore/commissions" - } - }, - "node_modules/forwarded": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", - "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fs-extra": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", - "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", - "dependencies": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "node_modules/fsevents": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", - "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", - "deprecated": "\"Please update to latest v2.3 or v2.2\"", - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "node_modules/generate-function": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", - "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", - "dependencies": { - "is-property": "^1.0.2" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-func-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", - "engines": { - "node": "*" - } - }, - "node_modules/glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==" - }, - "node_modules/growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", - "engines": { - "node": ">=4.x" - } - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "bin": { - "he": "bin/he" - } - }, - "node_modules/http-errors": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", - "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/inflection": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz", - "integrity": "sha1-ogCTVlbW9fa8TcdQLhrstwMihBY=", - "engines": [ - "node >= 0.4.0" - ] - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "node_modules/ini": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", - "deprecated": "Please update to ini >=1.3.6 to avoid a prototype pollution issue", - "engines": { - "node": "*" - } - }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-core-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.0.0.tgz", - "integrity": "sha512-jq1AH6C8MuteOoBPwkxHafmByhL9j5q4OaPGdbuD+ZtQJVzH+i6E3BJDQcBA09k57i2Hh2yQbEG8yObZ0jdlWw==", - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "engines": { - "node": ">=4" - } - }, - "node_modules/is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-object": { - "version": "1.0.2", - "resolved": "http://npm.ooapi.com:4873/is-object/-/is-object-1.0.2.tgz", - "integrity": "sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-promise": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", - "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==" - }, - "node_modules/is-property": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", - "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=" - }, - "node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" - }, - "node_modules/js-beautify": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.13.0.tgz", - "integrity": "sha512-/Tbp1OVzZjbwzwJQFIlYLm9eWQ+3aYbBXLSaqb1mEJzhcQAfrqMMQYtjb6io+U6KpD0ID4F+Id3/xcjH3l/sqA==", - "dependencies": { - "config-chain": "^1.1.12", - "editorconfig": "^0.15.3", - "glob": "^7.1.3", - "mkdirp": "^1.0.4", - "nopt": "^5.0.0" - }, - "bin": { - "css-beautify": "js/bin/css-beautify.js", - "html-beautify": "js/bin/html-beautify.js", - "js-beautify": "js/bin/js-beautify.js" - } - }, - "node_modules/js-yaml": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", - "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/just-extend": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.1.1.tgz", - "integrity": "sha512-aWgeGFW67BP3e5181Ep1Fv2v8z//iBJfrvyTnq8wG86vEESwmonn1zPBJ0VfmT9CJq2FIT0VsETtrNFm2a+SHA==" - }, - "node_modules/locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/lodash": { - "version": "4.17.20", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", - "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" - }, - "node_modules/lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" - }, - "node_modules/log-symbols": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", - "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==", - "dependencies": { - "chalk": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/long": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", - "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/lru-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", - "integrity": "sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM=", - "dependencies": { - "es5-ext": "~0.10.2" - } - }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/memoizee": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.14.tgz", - "integrity": "sha512-/SWFvWegAIYAO4NQMpcX+gcra0yEZu4OntmUdrBaWrJncxOqAziGFlHxc7yjKVK2uu3lpPW27P27wkR82wA8mg==", - "dependencies": { - "d": "1", - "es5-ext": "^0.10.45", - "es6-weak-map": "^2.0.2", - "event-emitter": "^0.3.5", - "is-promise": "^2.1", - "lru-queue": "0.1", - "next-tick": "1", - "timers-ext": "^0.1.5" - } - }, - "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/mime-db": { - "version": "1.44.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", - "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.27", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", - "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", - "dependencies": { - "mime-db": "1.44.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mocha": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.2.0.tgz", - "integrity": "sha512-lEWEMq2LMfNJMKeuEwb5UELi+OgFDollXaytR5ggQcHpzG3NP/R7rvixAvF+9/lLsTWhWG+4yD2M70GsM06nxw==", - "dependencies": { - "@ungap/promise-all-settled": "1.1.2", - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.4.3", - "debug": "4.2.0", - "diff": "4.0.2", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.1.6", - "growl": "1.10.5", - "he": "1.2.0", - "js-yaml": "3.14.0", - "log-symbols": "4.0.0", - "minimatch": "3.0.4", - "ms": "2.1.2", - "nanoid": "3.1.12", - "serialize-javascript": "5.0.1", - "strip-json-comments": "3.1.1", - "supports-color": "7.2.0", - "which": "2.0.2", - "wide-align": "1.1.3", - "workerpool": "6.0.2", - "yargs": "13.3.2", - "yargs-parser": "13.1.2", - "yargs-unparser": "2.0.0" - }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha" - }, - "engines": { - "node": ">= 10.12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mochajs" - } - }, - "node_modules/mocha/node_modules/debug": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", - "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", - "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/mocha/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mocha/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mocha/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/mocha/node_modules/p-limit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.0.2.tgz", - "integrity": "sha512-iwqZSOoWIW+Ew4kAGUlN16J4M7OB3ysMLSZtnhmqx7njIHFPlxWBX8xo3lVTyFVq6mI/lL9qt2IsN1sHwaxJkg==", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mocha/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mocha/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "engines": { - "node": ">=8" - } - }, - "node_modules/module-not-found-error": { - "version": "1.0.1", - "resolved": "http://npm.ooapi.com:4873/module-not-found-error/-/module-not-found-error-1.0.1.tgz", - "integrity": "sha1-z4tP9PKWQGdNbN0CsOO8UjwrvcA=", - "dev": true - }, - "node_modules/moment": { - "version": "2.29.1", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", - "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==", - "engines": { - "node": "*" - } - }, - "node_modules/moment-timezone": { - "version": "0.5.31", - "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.31.tgz", - "integrity": "sha512-+GgHNg8xRhMXfEbv81iDtrVeTcWt0kWmTEY1XQK14dICTXnWJnT0dxdlPspwqF3keKMVPXwayEsk1DI0AA/jdA==", - "dependencies": { - "moment": ">= 2.9.0" - }, - "engines": { - "node": "*" - } - }, - "node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "node_modules/mysql2": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-2.2.5.tgz", - "integrity": "sha512-XRqPNxcZTpmFdXbJqb+/CtYVLCx14x1RTeNMD4954L331APu75IC74GDqnZMEt1kwaXy6TySo55rF2F3YJS78g==", - "dependencies": { - "denque": "^1.4.1", - "generate-function": "^2.3.1", - "iconv-lite": "^0.6.2", - "long": "^4.0.0", - "lru-cache": "^6.0.0", - "named-placeholders": "^1.1.2", - "seq-queue": "^0.0.5", - "sqlstring": "^2.3.2" - }, - "engines": { - "node": ">= 8.0" - } - }, - "node_modules/mysql2/node_modules/iconv-lite": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz", - "integrity": "sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/named-placeholders": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.2.tgz", - "integrity": "sha512-wiFWqxoLL3PGVReSZpjLVxyJ1bRqe+KKJVbr4hGs1KWfTZTQyezHFBbuKj9hsizHyGV2ne7EMjHdxEGAybD5SA==", - "dependencies": { - "lru-cache": "^4.1.3" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/named-placeholders/node_modules/lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dependencies": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "node_modules/named-placeholders/node_modules/yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" - }, - "node_modules/nanoid": { - "version": "3.1.12", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.12.tgz", - "integrity": "sha512-1qstj9z5+x491jfiC4Nelk+f8XBad7LN20PmyWINJEMRSf3wcAjAWysw1qaA8z6NSKe2sjq1hRSDpBH5paCb6A==", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || >=13.7" - } - }, - "node_modules/negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/next-tick": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", - "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" - }, - "node_modules/nise": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/nise/-/nise-4.0.4.tgz", - "integrity": "sha512-bTTRUNlemx6deJa+ZyoCUTRvH3liK5+N6VQZ4NIw90AgDXY6iPnsqplNFf6STcj+ePk0H/xqxnP75Lr0J0Fq3A==", - "dependencies": { - "@sinonjs/commons": "^1.7.0", - "@sinonjs/fake-timers": "^6.0.0", - "@sinonjs/text-encoding": "^0.7.1", - "just-extend": "^4.0.2", - "path-to-regexp": "^1.7.0" - } - }, - "node_modules/nise/node_modules/path-to-regexp": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", - "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", - "dependencies": { - "isarray": "0.0.1" - } - }, - "node_modules/nopt": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", - "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", - "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dependencies": { - "p-limit": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "engines": { - "node": ">=6" - } - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "engines": { - "node": ">=4" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" - }, - "node_modules/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=" - }, - "node_modules/pathval": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", - "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", - "engines": { - "node": "*" - } - }, - "node_modules/picomatch": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/proto-list": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", - "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=" - }, - "node_modules/proxy-addr": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", - "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", - "dependencies": { - "forwarded": "~0.1.2", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/proxyquire": { - "version": "2.1.3", - "resolved": "http://npm.ooapi.com:4873/proxyquire/-/proxyquire-2.1.3.tgz", - "integrity": "sha512-BQWfCqYM+QINd+yawJz23tbBM40VIGXOdDw3X344KcclI/gtBbdWF6SlQ4nK/bYhF9d27KYug9WzljHC6B9Ysg==", - "dev": true, - "dependencies": { - "fill-keys": "^1.0.2", - "module-not-found-error": "^1.0.1", - "resolve": "^1.11.1" - } - }, - "node_modules/pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" - }, - "node_modules/qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", - "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", - "dependencies": { - "bytes": "3.1.0", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/readdirp": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", - "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" - }, - "node_modules/resolve": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.18.1.tgz", - "integrity": "sha512-lDfCPaMKfOJXjy0dPayzPdF1phampNWr3qFCjAu+rw/qbQmr5jWH5xN2hwh9QKfw9E5v4hwV7A+jrCmL8yjjqA==", - "dependencies": { - "is-core-module": "^2.0.0", - "path-parse": "^1.0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/retry-as-promised": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/retry-as-promised/-/retry-as-promised-3.2.0.tgz", - "integrity": "sha512-CybGs60B7oYU/qSQ6kuaFmRd9sTZ6oXSc0toqePvV74Ac6/IFZSI1ReFQmtCN+uvW1Mtqdwpvt/LGOiCBAY2Mg==", - "dependencies": { - "any-promise": "^1.3.0" - } - }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "node_modules/semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/send": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", - "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", - "dependencies": { - "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "~1.7.2", - "mime": "1.6.0", - "ms": "2.1.1", - "on-finished": "~2.3.0", - "range-parser": "~1.2.1", - "statuses": "~1.5.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/send/node_modules/ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" - }, - "node_modules/seq-queue": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", - "integrity": "sha1-1WgS4cAXpuTnw+Ojeh2m143TyT4=" - }, - "node_modules/sequelize": { - "version": "6.3.5", - "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-6.3.5.tgz", - "integrity": "sha512-MiwiPkYSA8NWttRKAXdU9h0TxP6HAc1fl7qZmMO/VQqQOND83G4nZLXd0kWILtAoT9cxtZgFqeb/MPYgEeXwsw==", - "dependencies": { - "debug": "^4.1.1", - "dottie": "^2.0.0", - "inflection": "1.12.0", - "lodash": "^4.17.15", - "moment": "^2.26.0", - "moment-timezone": "^0.5.31", - "retry-as-promised": "^3.2.0", - "semver": "^7.3.2", - "sequelize-pool": "^6.0.0", - "toposort-class": "^1.0.1", - "uuid": "^8.1.0", - "validator": "^10.11.0", - "wkx": "^0.5.0" - }, - "engines": { - "node": ">=10.0.0" - }, - "peerDependenciesMeta": { - "mariadb": { - "optional": true - }, - "mysql2": { - "optional": true - }, - "pg": { - "optional": true - }, - "pg-hstore": { - "optional": true - }, - "sqlite3": { - "optional": true - }, - "tedious": { - "optional": true - } - } - }, - "node_modules/sequelize-cli": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/sequelize-cli/-/sequelize-cli-6.2.0.tgz", - "integrity": "sha512-6WQ2x91hg30dUn66mXHnzvHATZ4pyI1GHSNbS/TNN/vRR4BLRSLijadeMgC8zqmKDsL0VqzVVopJWfJakuP++Q==", - "dependencies": { - "cli-color": "^1.4.0", - "fs-extra": "^7.0.1", - "js-beautify": "^1.8.8", - "lodash": "^4.17.5", - "resolve": "^1.5.0", - "umzug": "^2.3.0", - "yargs": "^13.1.0" - }, - "bin": { - "sequelize": "lib/sequelize", - "sequelize-cli": "lib/sequelize" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/sequelize-mock": { - "version": "0.10.2", - "resolved": "http://npm.ooapi.com:4873/sequelize-mock/-/sequelize-mock-0.10.2.tgz", - "integrity": "sha1-GdOXHM2utbhkFwwkznkqinHxRL0=", - "dev": true, - "dependencies": { - "bluebird": "^3.4.6", - "inflection": "^1.10.0", - "lodash": "^4.16.4" - } - }, - "node_modules/sequelize-pool": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/sequelize-pool/-/sequelize-pool-6.1.0.tgz", - "integrity": "sha512-4YwEw3ZgK/tY/so+GfnSgXkdwIJJ1I32uZJztIEgZeAO6HMgj64OzySbWLgxj+tXhZCJnzRfkY9gINw8Ft8ZMg==", - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/sequelize/node_modules/debug": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", - "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", - "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/sequelize/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/serialize-javascript": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", - "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/serve-static": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", - "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", - "dependencies": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.17.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" - }, - "node_modules/setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" - }, - "node_modules/sigmund": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", - "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=" - }, - "node_modules/sinon": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-9.2.0.tgz", - "integrity": "sha512-eSNXz1XMcGEMHw08NJXSyTHIu6qTCOiN8x9ODACmZpNQpr0aXTBXBnI4xTzQzR+TEpOmLiKowGf9flCuKIzsbw==", - "dependencies": { - "@sinonjs/commons": "^1.8.1", - "@sinonjs/fake-timers": "^6.0.1", - "@sinonjs/formatio": "^5.0.1", - "@sinonjs/samsam": "^5.2.0", - "diff": "^4.0.2", - "nise": "^4.0.4", - "supports-color": "^7.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/sinon" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" - }, - "node_modules/sqlstring": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.2.tgz", - "integrity": "sha512-vF4ZbYdKS8OnoJAWBmMxCQDkiEBkGQYU7UZPtL8flbDRSNkhaXvRJ279ZtI6M+zDaQovVU4tuRgzK5fVhvFAhg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string_decoder/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dependencies": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dependencies": { - "ansi-regex": "^4.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-ansi/node_modules/ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/superagent": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/superagent/-/superagent-6.1.0.tgz", - "integrity": "sha512-OUDHEssirmplo3F+1HWKUrUjvnQuA+nZI6i/JJBdXb5eq9IyEQwPyPpqND+SSsxf6TygpBEkUjISVRN4/VOpeg==", - "dependencies": { - "component-emitter": "^1.3.0", - "cookiejar": "^2.1.2", - "debug": "^4.1.1", - "fast-safe-stringify": "^2.0.7", - "form-data": "^3.0.0", - "formidable": "^1.2.2", - "methods": "^1.1.2", - "mime": "^2.4.6", - "qs": "^6.9.4", - "readable-stream": "^3.6.0", - "semver": "^7.3.2" - }, - "engines": { - "node": ">= 7.0.0" - } - }, - "node_modules/superagent/node_modules/debug": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", - "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", - "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/superagent/node_modules/mime": { - "version": "2.4.6", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz", - "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/superagent/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/superagent/node_modules/qs": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz", - "integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==", - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/supertest": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/supertest/-/supertest-5.0.0.tgz", - "integrity": "sha512-2JAWpPrUOZF4hHH5ZTCN2xjKXvJS3AEwPNXl0HUseHsfcXFvMy9kcsufIHCNAmQ5hlGCvgeAqaR5PBEouN3hlQ==", - "dependencies": { - "methods": "1.1.2", - "superagent": "6.1.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/timers-ext": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz", - "integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==", - "dependencies": { - "es5-ext": "~0.10.46", - "next-tick": "1" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/toposort-class": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toposort-class/-/toposort-class-1.0.1.tgz", - "integrity": "sha1-f/0feMi+KMO6Rc1OGj9e4ZO9mYg=" - }, - "node_modules/type": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", - "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" - }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "engines": { - "node": ">=4" - } - }, - "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/umzug": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/umzug/-/umzug-2.3.0.tgz", - "integrity": "sha512-Z274K+e8goZK8QJxmbRPhl89HPO1K+ORFtm6rySPhFKfKc5GHhqdzD0SGhSWHkzoXasqJuItdhorSvY7/Cgflw==", - "dependencies": { - "bluebird": "^3.7.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/uuid": { - "version": "8.3.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.1.tgz", - "integrity": "sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg==", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/validator": { - "version": "10.11.0", - "resolved": "https://registry.npmjs.org/validator/-/validator-10.11.0.tgz", - "integrity": "sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw==", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" - }, - "node_modules/wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", - "dependencies": { - "string-width": "^1.0.2 || 2" - } - }, - "node_modules/wide-align/node_modules/ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "engines": { - "node": ">=4" - } - }, - "node_modules/wide-align/node_modules/string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dependencies": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/wide-align/node_modules/strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dependencies": { - "ansi-regex": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/wkx": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/wkx/-/wkx-0.5.0.tgz", - "integrity": "sha512-Xng/d4Ichh8uN4l0FToV/258EjMGU9MGcA0HV2d9B/ZpZB3lqQm7nkOdZdm5GhKtLLhAE7PiVQwN4eN+2YJJUg==", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/workerpool": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.0.2.tgz", - "integrity": "sha512-DSNyvOpFKrNusaaUwk+ej6cBj1bmhLcBfj80elGk+ZIo5JSkq+unB1dLKEOcNfJDZgjGICfhQ0Q5TbP0PvF4+Q==" - }, - "node_modules/wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", - "dependencies": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "node_modules/y18n": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", - "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==" - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "node_modules/yargs": { - "version": "13.3.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", - "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", - "dependencies": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.2" - } - }, - "node_modules/yargs-parser": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", - "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - }, - "node_modules/yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dependencies": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-unparser/node_modules/camelcase": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", - "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/yargs-unparser/node_modules/decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - }, "dependencies": { "@sinonjs/commons": { "version": "1.8.1", @@ -3053,16 +581,6 @@ "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==" }, - "fill-keys": { - "version": "1.0.2", - "resolved": "http://npm.ooapi.com:4873/fill-keys/-/fill-keys-1.0.2.tgz", - "integrity": "sha1-mo+jb06K1jTjv2tPPIiCVRRS6yA=", - "dev": true, - "requires": { - "is-object": "~1.0.1", - "merge-descriptors": "~1.0.0" - } - }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -3304,12 +822,6 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" }, - "is-object": { - "version": "1.0.2", - "resolved": "http://npm.ooapi.com:4873/is-object/-/is-object-1.0.2.tgz", - "integrity": "sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==", - "dev": true - }, "is-plain-obj": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", @@ -3563,12 +1075,6 @@ } } }, - "module-not-found-error": { - "version": "1.0.1", - "resolved": "http://npm.ooapi.com:4873/module-not-found-error/-/module-not-found-error-1.0.1.tgz", - "integrity": "sha1-z4tP9PKWQGdNbN0CsOO8UjwrvcA=", - "dev": true - }, "moment": { "version": "2.29.1", "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", @@ -3772,17 +1278,6 @@ "ipaddr.js": "1.9.1" } }, - "proxyquire": { - "version": "2.1.3", - "resolved": "http://npm.ooapi.com:4873/proxyquire/-/proxyquire-2.1.3.tgz", - "integrity": "sha512-BQWfCqYM+QINd+yawJz23tbBM40VIGXOdDw3X344KcclI/gtBbdWF6SlQ4nK/bYhF9d27KYug9WzljHC6B9Ysg==", - "dev": true, - "requires": { - "fill-keys": "^1.0.2", - "module-not-found-error": "^1.0.1", - "resolve": "^1.11.1" - } - }, "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", @@ -3958,17 +1453,6 @@ "yargs": "^13.1.0" } }, - "sequelize-mock": { - "version": "0.10.2", - "resolved": "http://npm.ooapi.com:4873/sequelize-mock/-/sequelize-mock-0.10.2.tgz", - "integrity": "sha1-GdOXHM2utbhkFwwkznkqinHxRL0=", - "dev": true, - "requires": { - "bluebird": "^3.4.6", - "inflection": "^1.10.0", - "lodash": "^4.16.4" - } - }, "sequelize-pool": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/sequelize-pool/-/sequelize-pool-6.1.0.tgz", @@ -4037,6 +1521,16 @@ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, "string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -4052,16 +1546,6 @@ } } }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, "strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", @@ -4364,4 +1848,4 @@ } } } -} +} \ No newline at end of file diff --git a/package.json b/package.json index c25bd055..5f6f1d0f 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,6 @@ { - "name": "forum-express-workspace", - "version": "1.0.0", - "description": "", + "name": "forum-express-grading", + "version": "2.0.0", "main": "_helpers.js", "scripts": { "start": "node app.js", @@ -10,26 +9,21 @@ }, "repository": { "type": "git", - "url": "git+https://github.com/v123582/forum-express-workspace.git" + "url": "git+https://github.com/ALPHACamp/forum-express-grading.git" }, - "author": "", - "license": "ISC", - "bugs": { - "url": "https://github.com/v123582/forum-express-workspace/issues" - }, - "homepage": "https://github.com/v123582/forum-express-workspace#readme", "dependencies": { - "chai": "^4.2.0", "express": "^4.17.1", - "mocha": "^8.2.0", "mysql2": "^2.2.5", + "nodemon": "^2.0.12", "sequelize": "^6.3.5", - "sequelize-cli": "^6.2.0", - "sinon": "^9.2.0", - "supertest": "^5.0.0" + "sequelize-cli": "^6.2.0" }, "devDependencies": { + "chai": "^4.2.0", + "mocha": "^8.2.0", "proxyquire": "^2.1.3", - "sequelize-mock": "^0.10.2" + "sequelize-mock": "^0.10.2", + "sinon": "^9.2.0", + "supertest": "^5.0.0" } -} +} \ No newline at end of file From 894675fa3114515bbc9c80ec5984ff03d53713a6 Mon Sep 17 00:00:00 2001 From: Serena Tseng <51045074+Carrot7712@users.noreply.github.com> Date: Sat, 6 Nov 2021 00:14:56 +0800 Subject: [PATCH 077/135] Update .travis.yml --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9635c20c..fdf50b79 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,9 +11,9 @@ env: # 在 install 前執行的指令 before_install: - - mysql -e 'CREATE DATABASE IF NOT EXISTS forum_test default character set utf8mb4 collate utf8mb4_unicode_ci;' + - mysql -e 'CREATE DATABASE IF NOT EXISTS forum default character set utf8mb4 collate utf8mb4_unicode_ci;' - npm install sequelize-cli -g # 在執行測試之前的指令 before_script: - - sequelize db:migrate \ No newline at end of file + - sequelize db:migrate From da3a406d34be4f6e2cf149af3433045b77f853e0 Mon Sep 17 00:00:00 2001 From: Serena Tseng <51045074+Carrot7712@users.noreply.github.com> Date: Sat, 6 Nov 2021 00:29:51 +0800 Subject: [PATCH 078/135] Update .travis.yml --- .travis.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index fdf50b79..f08c1b5e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: node_js node_js: - - "10" + - "14" services: - mysql @@ -16,4 +16,5 @@ before_install: # 在執行測試之前的指令 before_script: - - sequelize db:migrate + - sequelize db:migrate + - sequelize db:seed:all From 29dd8254ee1454a11186f04363fe81af086df7a0 Mon Sep 17 00:00:00 2001 From: Serena Tseng <51045074+Carrot7712@users.noreply.github.com> Date: Mon, 8 Nov 2021 22:37:30 +0800 Subject: [PATCH 079/135] Update config.json --- config/config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/config.json b/config/config.json index 2b8be8e7..93cd6cd8 100644 --- a/config/config.json +++ b/config/config.json @@ -15,7 +15,7 @@ }, "travis": { "username": "travis", - "database": "forum_test", + "database": "forum", "host": "127.0.0.1", "dialect": "mysql", "logging": false From 20cab63518224dcd6e0a973fe29e573b79295680 Mon Sep 17 00:00:00 2001 From: Serena Tseng <51045074+Carrot7712@users.noreply.github.com> Date: Mon, 8 Nov 2021 22:37:42 +0800 Subject: [PATCH 080/135] Update config.json --- config/config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/config.json b/config/config.json index 2b8be8e7..93cd6cd8 100644 --- a/config/config.json +++ b/config/config.json @@ -15,7 +15,7 @@ }, "travis": { "username": "travis", - "database": "forum_test", + "database": "forum", "host": "127.0.0.1", "dialect": "mysql", "logging": false From 844162a4a6c7ab05f36e7a0d4cd32f7cad92bce9 Mon Sep 17 00:00:00 2001 From: Serena Tseng <51045074+Carrot7712@users.noreply.github.com> Date: Mon, 8 Nov 2021 22:37:54 +0800 Subject: [PATCH 081/135] Update config.json --- config/config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/config.json b/config/config.json index 2b8be8e7..93cd6cd8 100644 --- a/config/config.json +++ b/config/config.json @@ -15,7 +15,7 @@ }, "travis": { "username": "travis", - "database": "forum_test", + "database": "forum", "host": "127.0.0.1", "dialect": "mysql", "logging": false From 32a6374cdb77fdb1754c7adee2e7a6ffe8e5082f Mon Sep 17 00:00:00 2001 From: Serena Tseng <51045074+Carrot7712@users.noreply.github.com> Date: Mon, 8 Nov 2021 22:38:06 +0800 Subject: [PATCH 082/135] Update config.json --- config/config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/config.json b/config/config.json index 2b8be8e7..93cd6cd8 100644 --- a/config/config.json +++ b/config/config.json @@ -15,7 +15,7 @@ }, "travis": { "username": "travis", - "database": "forum_test", + "database": "forum", "host": "127.0.0.1", "dialect": "mysql", "logging": false From 9300404b9129acabf74e64fa7d150d390e92b614 Mon Sep 17 00:00:00 2001 From: area268457913 Date: Tue, 9 Nov 2021 03:00:11 +0800 Subject: [PATCH 083/135] Initialize project --- app.js | 3 +++ package-lock.json | 68 +++++++++++++++++++++++++++++++++++++++++++++++ package.json | 1 + 3 files changed, 72 insertions(+) diff --git a/app.js b/app.js index f70e64d6..ae096122 100644 --- a/app.js +++ b/app.js @@ -1,7 +1,10 @@ const express = require('express') +const handlebars = require('express-handlebars') // 引入 handlebars const app = express() const port = 3000 +app.engine('handlebars', handlebars()) // Handlebars 註冊樣板引擎 +app.set('view engine', 'handlebars') // 設定使用 Handlebars 做為樣板引擎 app.listen(port, () => { console.log(`Example app listening at http://localhost:${port}`) }) diff --git a/package-lock.json b/package-lock.json index 6cdb461e..f8fe7fd8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -561,6 +561,36 @@ "vary": "~1.1.2" } }, + "express-handlebars": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/express-handlebars/-/express-handlebars-5.3.4.tgz", + "integrity": "sha512-b36grfkbXZItLLQV6cwzA20o6Zg4Eckke3PjHF4EGQIQLGs5IPMjpAxepdGb45A/bECekXzA9STzNqvEgrdRPw==", + "requires": { + "glob": "^7.2.0", + "graceful-fs": "^4.2.7", + "handlebars": "^4.7.7" + }, + "dependencies": { + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "graceful-fs": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", + "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==" + } + } + }, "ext": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", @@ -716,6 +746,18 @@ "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==" }, + "handlebars": { + "version": "4.7.7", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", + "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", + "requires": { + "minimist": "^1.2.5", + "neo-async": "^2.6.0", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4", + "wordwrap": "^1.0.0" + } + }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -985,6 +1027,11 @@ "brace-expansion": "^1.1.7" } }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, "mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", @@ -1152,6 +1199,11 @@ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" + }, "next-tick": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", @@ -1506,6 +1558,11 @@ "supports-color": "^7.1.0" } }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -1672,6 +1729,12 @@ "mime-types": "~2.1.24" } }, + "uglify-js": { + "version": "3.14.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.14.3.tgz", + "integrity": "sha512-mic3aOdiq01DuSVx0TseaEzMIVqebMZ0Z3vaeDhFEh9bsc24hV1TFvN74reA2vs08D0ZWfNjAcJ3UbVLaBss+g==", + "optional": true + }, "umzug": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/umzug/-/umzug-2.3.0.tgz", @@ -1768,6 +1831,11 @@ "@types/node": "*" } }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=" + }, "workerpool": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.0.2.tgz", diff --git a/package.json b/package.json index dd99a5f1..1ac12175 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "dependencies": { "chai": "^4.2.0", "express": "^4.17.1", + "express-handlebars": "^5.3.4", "mocha": "^8.2.0", "mysql2": "^2.2.5", "sequelize": "^6.3.5", From 28f8ed509672dc5e7913dc5155a281a2067d288b Mon Sep 17 00:00:00 2001 From: area268457913 Date: Tue, 9 Nov 2021 03:40:49 +0800 Subject: [PATCH 084/135] add restaurant index page --- app.js | 3 ++- controllers/restController.js | 6 ++++++ routes/index.js | 10 +++++++--- views/layouts/main.handlebars | 29 +++++++++++++++++++++++++++++ views/restaurants.handlebars | 3 +++ 5 files changed, 47 insertions(+), 4 deletions(-) create mode 100644 controllers/restController.js create mode 100644 views/layouts/main.handlebars create mode 100644 views/restaurants.handlebars diff --git a/app.js b/app.js index ae096122..b9b0cde1 100644 --- a/app.js +++ b/app.js @@ -3,11 +3,12 @@ const handlebars = require('express-handlebars') // 引入 handlebars const app = express() const port = 3000 -app.engine('handlebars', handlebars()) // Handlebars 註冊樣板引擎 +app.engine('handlebars', handlebars({ defaultLayout: 'main' })) // Handlebars 註冊樣板引擎 app.set('view engine', 'handlebars') // 設定使用 Handlebars 做為樣板引擎 app.listen(port, () => { console.log(`Example app listening at http://localhost:${port}`) }) +// 引入 routes 並將 app 傳進去,讓 routes 可以用 app 這個物件來指定路由 require('./routes')(app) diff --git a/controllers/restController.js b/controllers/restController.js new file mode 100644 index 00000000..3c0c76c6 --- /dev/null +++ b/controllers/restController.js @@ -0,0 +1,6 @@ +const restController = { + getRestaurants: (req, res) => { + return res.render('restaurants') + } +} +module.exports = restController \ No newline at end of file diff --git a/routes/index.js b/routes/index.js index fc55e842..11f97957 100644 --- a/routes/index.js +++ b/routes/index.js @@ -1,6 +1,10 @@ +const restController = require('../controllers/restController.js') + + module.exports = (app) => { - app.get('/', (req, res) => { - res.send('Hello World!') - }) + //如果使用者訪問首頁,就導向 /restaurants 的頁面 + app.get('/', (req, res) => res.redirect('/restaurants')) + //在 /restaurants 底下則交給 restController.getRestaurants 來處理 + app.get('/restaurants', restController.getRestaurants) } diff --git a/views/layouts/main.handlebars b/views/layouts/main.handlebars new file mode 100644 index 00000000..df891dff --- /dev/null +++ b/views/layouts/main.handlebars @@ -0,0 +1,29 @@ + + + + + + + 餐廳評論網 + + + + + +
+
+
+ {{{body}}} +
+
+
+ + + + + + \ No newline at end of file diff --git a/views/restaurants.handlebars b/views/restaurants.handlebars new file mode 100644 index 00000000..97b6e76e --- /dev/null +++ b/views/restaurants.handlebars @@ -0,0 +1,3 @@ +
+ restaurants +
\ No newline at end of file From b0d4dcf3f93d8721d9575253bd67dfcf8d81c287 Mon Sep 17 00:00:00 2001 From: area268457913 Date: Tue, 9 Nov 2021 15:11:33 +0800 Subject: [PATCH 085/135] add admin restaurant indexpage --- controllers/adminController.js | 7 +++++++ routes/index.js | 7 ++++++- views/admin/restaurants.handlebars | 3 +++ 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 controllers/adminController.js create mode 100644 views/admin/restaurants.handlebars diff --git a/controllers/adminController.js b/controllers/adminController.js new file mode 100644 index 00000000..b220f29a --- /dev/null +++ b/controllers/adminController.js @@ -0,0 +1,7 @@ +const adminController = { + getRestaurants: (req, res) => { + return res.render('admin/restaurants') + } +} + +module.exports = adminController \ No newline at end of file diff --git a/routes/index.js b/routes/index.js index 11f97957..26414466 100644 --- a/routes/index.js +++ b/routes/index.js @@ -1,5 +1,6 @@ const restController = require('../controllers/restController.js') - +const adminController = require('../controllers/adminController.js') +const { get } = require('superagent') module.exports = (app) => { @@ -7,4 +8,8 @@ module.exports = (app) => { app.get('/', (req, res) => res.redirect('/restaurants')) //在 /restaurants 底下則交給 restController.getRestaurants 來處理 app.get('/restaurants', restController.getRestaurants) + // 連到 /admin 頁面就轉到 /admin/restaurants + app.get('/admin', (req, res) => res.redirect('/admin/restaurants')) + // 在 /admin/restaurants 底下則交給 adminController.getRestaurants 處理 + app.get('/admin/restaurants', adminController.getRestaurants) } diff --git a/views/admin/restaurants.handlebars b/views/admin/restaurants.handlebars new file mode 100644 index 00000000..c1e24fc9 --- /dev/null +++ b/views/admin/restaurants.handlebars @@ -0,0 +1,3 @@ +
+ admin restaurants +
\ No newline at end of file From 19e21bee198c1b12cb7e18dddb251d396d486085 Mon Sep 17 00:00:00 2001 From: area268457913 Date: Tue, 9 Nov 2021 16:13:16 +0800 Subject: [PATCH 086/135] Initialize sequelize and connect to database --- app.js | 1 + 1 file changed, 1 insertion(+) diff --git a/app.js b/app.js index b9b0cde1..dc9c2341 100644 --- a/app.js +++ b/app.js @@ -1,5 +1,6 @@ const express = require('express') const handlebars = require('express-handlebars') // 引入 handlebars +const db = require('./models') // 引入資料庫 const app = express() const port = 3000 From 347a81e607c76d5e5c196653546b6b8cad02c03e Mon Sep 17 00:00:00 2001 From: area268457913 Date: Wed, 10 Nov 2021 02:06:55 +0800 Subject: [PATCH 087/135] Create user model --- migrations/20211109174638-create-user.js | 33 ++++++++++++++++++++++++ models/index.js | 2 +- models/user.js | 25 ++++++++++++++++++ 3 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 migrations/20211109174638-create-user.js create mode 100644 models/user.js diff --git a/migrations/20211109174638-create-user.js b/migrations/20211109174638-create-user.js new file mode 100644 index 00000000..58a162b2 --- /dev/null +++ b/migrations/20211109174638-create-user.js @@ -0,0 +1,33 @@ +'use strict'; +module.exports = { + up: async (queryInterface, Sequelize) => { + await queryInterface.createTable('Users', { + id: { + allowNull: false, + autoIncrement: true, + primaryKey: true, + type: Sequelize.INTEGER + }, + name: { + type: Sequelize.STRING + }, + email: { + type: Sequelize.STRING + }, + password: { + type: Sequelize.STRING + }, + createdAt: { + allowNull: false, + type: Sequelize.DATE + }, + updatedAt: { + allowNull: false, + type: Sequelize.DATE + } + }); + }, + down: async (queryInterface, Sequelize) => { + await queryInterface.dropTable('Users'); + } +}; \ No newline at end of file diff --git a/models/index.js b/models/index.js index 66860356..916d369a 100644 --- a/models/index.js +++ b/models/index.js @@ -23,7 +23,7 @@ fs return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js') }) .forEach(file => { - const model = sequelize['import'](path.join(__dirname, file)) + const model = require(path.join(__dirname, file))(sequelize, Sequelize.DataTypes) db[model.name] = model }) diff --git a/models/user.js b/models/user.js new file mode 100644 index 00000000..90c48b43 --- /dev/null +++ b/models/user.js @@ -0,0 +1,25 @@ +'use strict'; +const { + Model +} = require('sequelize'); +module.exports = (sequelize, DataTypes) => { + class User extends Model { + /** + * Helper method for defining associations. + * This method is not a part of Sequelize lifecycle. + * The `models/index` file will call this method automatically. + */ + static associate(models) { + // define association here + } + }; + User.init({ + name: DataTypes.STRING, + email: DataTypes.STRING, + password: DataTypes.STRING + }, { + sequelize, + modelName: 'User', + }); + return User; +}; \ No newline at end of file From 6da840ab0f6dd1e7f52142c75d937819f114ab6e Mon Sep 17 00:00:00 2001 From: area268457913 Date: Wed, 10 Nov 2021 02:47:49 +0800 Subject: [PATCH 088/135] Install bcryptjs & Add userController and signup page & Install body-parser --- app.js | 4 ++++ controllers/userController.js | 22 ++++++++++++++++++++++ package-lock.json | 5 +++++ package.json | 2 ++ routes/index.js | 4 ++++ views/signup.handlebars | 27 +++++++++++++++++++++++++++ 6 files changed, 64 insertions(+) create mode 100644 controllers/userController.js create mode 100644 views/signup.handlebars diff --git a/app.js b/app.js index dc9c2341..6e35261d 100644 --- a/app.js +++ b/app.js @@ -1,11 +1,15 @@ const express = require('express') const handlebars = require('express-handlebars') // 引入 handlebars +const bodyParser = require('body-parser') const db = require('./models') // 引入資料庫 const app = express() const port = 3000 + app.engine('handlebars', handlebars({ defaultLayout: 'main' })) // Handlebars 註冊樣板引擎 app.set('view engine', 'handlebars') // 設定使用 Handlebars 做為樣板引擎 +app.use(express.urlencoded({ extended: true })) + app.listen(port, () => { console.log(`Example app listening at http://localhost:${port}`) }) diff --git a/controllers/userController.js b/controllers/userController.js new file mode 100644 index 00000000..f3b8a2c5 --- /dev/null +++ b/controllers/userController.js @@ -0,0 +1,22 @@ +const bcrypt = require('bcryptjs') +const db = require('../models') +const User = db.User + +const userController = { + signUpPage: (req, res) => { + return res.render('signup') + }, + signUp: (req, res) => { + console.log(req.body) + User.create({ + name: req.body.name, + email: req.body.email, + password: bcrypt.hashSync(req.body.password, bcrypt.genSaltSync(10), null) + }) + .then(user => { + return res.redirect('/signin') + }) + } +} + +module.exports = userController \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index f8fe7fd8..c51f5b6a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -128,6 +128,11 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, + "bcryptjs": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", + "integrity": "sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms=" + }, "binary-extensions": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", diff --git a/package.json b/package.json index 1ac12175..cc250602 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,8 @@ }, "homepage": "https://github.com/v123582/forum-express-workspace#readme", "dependencies": { + "bcryptjs": "^2.4.3", + "body-parser": "^1.19.0", "chai": "^4.2.0", "express": "^4.17.1", "express-handlebars": "^5.3.4", diff --git a/routes/index.js b/routes/index.js index 26414466..716550fc 100644 --- a/routes/index.js +++ b/routes/index.js @@ -1,5 +1,6 @@ const restController = require('../controllers/restController.js') const adminController = require('../controllers/adminController.js') +const userController = require('../controllers/userController.js') const { get } = require('superagent') module.exports = (app) => { @@ -12,4 +13,7 @@ module.exports = (app) => { app.get('/admin', (req, res) => res.redirect('/admin/restaurants')) // 在 /admin/restaurants 底下則交給 adminController.getRestaurants 處理 app.get('/admin/restaurants', adminController.getRestaurants) + + app.get('/signup', userController.signUpPage) + app.post('/signup', userController.signUp) } diff --git a/views/signup.handlebars b/views/signup.handlebars new file mode 100644 index 00000000..37ccf4f5 --- /dev/null +++ b/views/signup.handlebars @@ -0,0 +1,27 @@ + \ No newline at end of file From 083555d5f879e397a82f4ea1e7dc3815bbc4201b Mon Sep 17 00:00:00 2001 From: area268457913 Date: Wed, 10 Nov 2021 03:01:32 +0800 Subject: [PATCH 089/135] Install bcryptjs & Add userController and signup page & Install body-parser --- app.js | 2 +- controllers/userController.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app.js b/app.js index 6e35261d..d6afd843 100644 --- a/app.js +++ b/app.js @@ -1,6 +1,6 @@ const express = require('express') const handlebars = require('express-handlebars') // 引入 handlebars -const bodyParser = require('body-parser') +const bodyParser = require('body-parser')// Express 升級到了 4.17.1 之後,不用額外載入 body-parser,這行程式碼便不用寫 const db = require('./models') // 引入資料庫 const app = express() const port = 3000 diff --git a/controllers/userController.js b/controllers/userController.js index f3b8a2c5..f4b6d533 100644 --- a/controllers/userController.js +++ b/controllers/userController.js @@ -1,6 +1,6 @@ const bcrypt = require('bcryptjs') const db = require('../models') -const User = db.User +const User = db.User //存取到之前建立的User model const userController = { signUpPage: (req, res) => { From b83c195c22198aef2d76af5f399cfe2cc1590d3e Mon Sep 17 00:00:00 2001 From: area268457913 Date: Wed, 10 Nov 2021 03:29:38 +0800 Subject: [PATCH 090/135] Install express-session connect-flash & Confirm user password and unique email --- app.js | 12 ++++++++ controllers/userController.js | 29 +++++++++++++----- package-lock.json | 55 +++++++++++++++++++++++++++++++++++ package.json | 2 ++ views/layouts/main.handlebars | 11 +++++++ 5 files changed, 101 insertions(+), 8 deletions(-) diff --git a/app.js b/app.js index d6afd843..e83b3a04 100644 --- a/app.js +++ b/app.js @@ -1,6 +1,8 @@ const express = require('express') const handlebars = require('express-handlebars') // 引入 handlebars const bodyParser = require('body-parser')// Express 升級到了 4.17.1 之後,不用額外載入 body-parser,這行程式碼便不用寫 +const flash = require('connect-flash') +const session = require('express-session') const db = require('./models') // 引入資料庫 const app = express() const port = 3000 @@ -10,6 +12,16 @@ app.engine('handlebars', handlebars({ defaultLayout: 'main' })) // Handlebars app.set('view engine', 'handlebars') // 設定使用 Handlebars 做為樣板引擎 app.use(express.urlencoded({ extended: true })) +app.use(session({ secret: 'secret', resave: false, saveUninitialized: false })) +app.use(flash()) + +// 把 req.flash 放到 res.locals 裡面 +app.use((req, res, next) => { + res.locals.success_messages = req.flash('success_messages') + res.locals.error_messages = req.flash('error_messages') + next() +}) + app.listen(port, () => { console.log(`Example app listening at http://localhost:${port}`) }) diff --git a/controllers/userController.js b/controllers/userController.js index f4b6d533..e975c0a3 100644 --- a/controllers/userController.js +++ b/controllers/userController.js @@ -7,15 +7,28 @@ const userController = { return res.render('signup') }, signUp: (req, res) => { - console.log(req.body) - User.create({ - name: req.body.name, - email: req.body.email, - password: bcrypt.hashSync(req.body.password, bcrypt.genSaltSync(10), null) - }) - .then(user => { - return res.redirect('/signin') + // confirm password + if (req.body.passwordCheck !== req.body.password) { + req.flash('error_messages', '兩次密碼輸入不同!') + return res.redirect('/signup') + } else { + // confirm unique user + User.findOne({ where: { email: req.body.email } }).then(user => { + if (user) { + req.flash('error_messages', '信箱重複!') + return res.redirect('/signup') + } else { + User.create({ + name: req.body.name, + email: req.body.email, + password: bcrypt.hashSync(req.body.password, bcrypt.genSaltSync(10), null) + }).then(user => { + req.flash('success_messages', '成功註冊帳號!') + return res.redirect('/signin') + }) + } }) + } } } diff --git a/package-lock.json b/package-lock.json index c51f5b6a..e91abd9d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -325,6 +325,11 @@ "proto-list": "~1.2.1" } }, + "connect-flash": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/connect-flash/-/connect-flash-0.1.1.tgz", + "integrity": "sha1-2GMPJtlaf4UfmVax6MxnMvO2qjA=" + }, "content-disposition": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", @@ -596,6 +601,38 @@ } } }, + "express-session": { + "version": "1.17.2", + "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.17.2.tgz", + "integrity": "sha512-mPcYcLA0lvh7D4Oqr5aNJFMtBMKPLl++OKKxkHzZ0U0oDq1rpKBnkR5f5vCHR26VeArlTOEF9td4x5IjICksRQ==", + "requires": { + "cookie": "0.4.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-headers": "~1.0.2", + "parseurl": "~1.3.3", + "safe-buffer": "5.2.1", + "uid-safe": "~2.1.5" + }, + "dependencies": { + "cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==" + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } + } + }, "ext": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", @@ -1257,6 +1294,11 @@ "ee-first": "1.1.1" } }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -1345,6 +1387,11 @@ "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" }, + "random-bytes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", + "integrity": "sha1-T2ih3Arli9P7lYSMMDJNt11kNgs=" + }, "randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -1740,6 +1787,14 @@ "integrity": "sha512-mic3aOdiq01DuSVx0TseaEzMIVqebMZ0Z3vaeDhFEh9bsc24hV1TFvN74reA2vs08D0ZWfNjAcJ3UbVLaBss+g==", "optional": true }, + "uid-safe": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", + "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==", + "requires": { + "random-bytes": "~1.0.0" + } + }, "umzug": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/umzug/-/umzug-2.3.0.tgz", diff --git a/package.json b/package.json index cc250602..7aacd2bd 100644 --- a/package.json +++ b/package.json @@ -22,8 +22,10 @@ "bcryptjs": "^2.4.3", "body-parser": "^1.19.0", "chai": "^4.2.0", + "connect-flash": "^0.1.1", "express": "^4.17.1", "express-handlebars": "^5.3.4", + "express-session": "^1.17.2", "mocha": "^8.2.0", "mysql2": "^2.2.5", "sequelize": "^6.3.5", diff --git a/views/layouts/main.handlebars b/views/layouts/main.handlebars index df891dff..ed292f3b 100644 --- a/views/layouts/main.handlebars +++ b/views/layouts/main.handlebars @@ -14,6 +14,17 @@
+ {{#if success_messages}} + + {{/if}} + {{#if error_messages}} + + {{/if}} + {{{body}}}
From fad1ca4b52a401f848c97fd8da925fe1c81b9a66 Mon Sep 17 00:00:00 2001 From: area268457913 Date: Wed, 10 Nov 2021 04:01:18 +0800 Subject: [PATCH 091/135] Install passport and passport-local & Add feature: signInPage, signIn and logout --- app.js | 6 +++++- config/passport.js | 37 +++++++++++++++++++++++++++++++++++ controllers/userController.js | 17 ++++++++++++++++ package-lock.json | 27 +++++++++++++++++++++++++ package.json | 2 ++ routes/index.js | 6 +++++- views/signin.handlebars | 19 ++++++++++++++++++ 7 files changed, 112 insertions(+), 2 deletions(-) create mode 100644 config/passport.js create mode 100644 views/signin.handlebars diff --git a/app.js b/app.js index e83b3a04..3882b612 100644 --- a/app.js +++ b/app.js @@ -3,6 +3,8 @@ const handlebars = require('express-handlebars') // 引入 handlebars const bodyParser = require('body-parser')// Express 升級到了 4.17.1 之後,不用額外載入 body-parser,這行程式碼便不用寫 const flash = require('connect-flash') const session = require('express-session') +const passport = require('./config/passport') + const db = require('./models') // 引入資料庫 const app = express() const port = 3000 @@ -13,6 +15,8 @@ app.set('view engine', 'handlebars') // 設定使用 Handlebars 做為樣板引 app.use(express.urlencoded({ extended: true })) app.use(session({ secret: 'secret', resave: false, saveUninitialized: false })) +app.use(passport.initialize()) +app.use(passport.session()) app.use(flash()) // 把 req.flash 放到 res.locals 裡面 @@ -27,6 +31,6 @@ app.listen(port, () => { }) // 引入 routes 並將 app 傳進去,讓 routes 可以用 app 這個物件來指定路由 -require('./routes')(app) +require('./routes')(app, passport) module.exports = app diff --git a/config/passport.js b/config/passport.js new file mode 100644 index 00000000..09fd01fb --- /dev/null +++ b/config/passport.js @@ -0,0 +1,37 @@ +const passport = require('passport') +const LocalStrategy = require('passport-local') +const bcrypt = require('bcryptjs') +const db = require('../models') +const User = db.User + + +// setup passport strategy +passport.use(new LocalStrategy( + // customize user field + { + usernameField: 'email', + passwordField: 'password', + passReqToCallback: true + }, + // authenticate user + (req, username, password, cb) => { + User.findOne({ where: { email: username } }).then(user => { + if (!user) return cb(null, false, req.flash('error_messages', '帳號或密碼輸入錯誤')) + if (!bcrypt.compareSync(password, user.password)) return cb(null, false, req.flash('error_messages', '帳號或密碼輸入錯誤!')) + return cb(null, user) + }) + } +)) + +// serialize and deserialize user +passport.serializeUser((user, cb) => { + cb(null, user.id) +}) +passport.deserializeUser((id, cb) => { + User.findByPk(id).then(user => { + user = user.toJSON() // 此處與影片示範不同 + return cb(null, user) + }) +}) + +module.exports = passport \ No newline at end of file diff --git a/controllers/userController.js b/controllers/userController.js index e975c0a3..a93a1510 100644 --- a/controllers/userController.js +++ b/controllers/userController.js @@ -6,6 +6,7 @@ const userController = { signUpPage: (req, res) => { return res.render('signup') }, + signUp: (req, res) => { // confirm password if (req.body.passwordCheck !== req.body.password) { @@ -29,7 +30,23 @@ const userController = { } }) } + }, + + signInPage: (req, res) => { + return res.render('signin') + }, + + signIn: (req, res) => { + req.flash('success_messages', '成功登入!') + res.redirect('/restaurants') + }, + + logout: (req, res) => { + req.flash('success_messages', '登出成功!') + req.logout() + res.redirect('/signin') } + } module.exports = userController \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index e91abd9d..944a27a3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1333,6 +1333,28 @@ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" }, + "passport": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/passport/-/passport-0.5.0.tgz", + "integrity": "sha512-ln+ue5YaNDS+fes6O5PCzXKSseY5u8MYhX9H5Co4s+HfYI5oqvnHKoOORLYDUPh+8tHvrxugF2GFcUA1Q1Gqfg==", + "requires": { + "passport-strategy": "1.x.x", + "pause": "0.0.1" + } + }, + "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.x.x" + } + }, + "passport-strategy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", + "integrity": "sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ=" + }, "path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", @@ -1358,6 +1380,11 @@ "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=" }, + "pause": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", + "integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10=" + }, "picomatch": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", diff --git a/package.json b/package.json index 7aacd2bd..b1dc0f91 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,8 @@ "express-session": "^1.17.2", "mocha": "^8.2.0", "mysql2": "^2.2.5", + "passport": "^0.5.0", + "passport-local": "^1.0.0", "sequelize": "^6.3.5", "sequelize-cli": "^6.2.0", "sinon": "^9.2.0", diff --git a/routes/index.js b/routes/index.js index 716550fc..9a16a7ae 100644 --- a/routes/index.js +++ b/routes/index.js @@ -3,7 +3,7 @@ const adminController = require('../controllers/adminController.js') const userController = require('../controllers/userController.js') const { get } = require('superagent') -module.exports = (app) => { +module.exports = (app, passport) => { //如果使用者訪問首頁,就導向 /restaurants 的頁面 app.get('/', (req, res) => res.redirect('/restaurants')) @@ -16,4 +16,8 @@ module.exports = (app) => { app.get('/signup', userController.signUpPage) app.post('/signup', userController.signUp) + + app.get('/signin', userController.signInPage) + app.post('/signin', passport.authenticate('local', { failureRedirect: '/signin', failureFlash: true }), userController.signIn) + app.get('/logout', userController.logout) } diff --git a/views/signin.handlebars b/views/signin.handlebars new file mode 100644 index 00000000..cd17904d --- /dev/null +++ b/views/signin.handlebars @@ -0,0 +1,19 @@ + \ No newline at end of file From e315016d115b840a83e8703d4b47d8854f9c8588 Mon Sep 17 00:00:00 2001 From: area268457913 Date: Wed, 10 Nov 2021 04:09:22 +0800 Subject: [PATCH 092/135] Add navbar to show login status --- app.js | 1 + views/layouts/main.handlebars | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/app.js b/app.js index 3882b612..5b968a26 100644 --- a/app.js +++ b/app.js @@ -23,6 +23,7 @@ app.use(flash()) app.use((req, res, next) => { res.locals.success_messages = req.flash('success_messages') res.locals.error_messages = req.flash('error_messages') + res.locals.user = req.user //讓views能存取user next() }) diff --git a/views/layouts/main.handlebars b/views/layouts/main.handlebars index ed292f3b..fda68a96 100644 --- a/views/layouts/main.handlebars +++ b/views/layouts/main.handlebars @@ -11,6 +11,25 @@ + {{!-- Navbar --}} + +
From a9708ec547213d7bf6edb556d96da8556e568cfe Mon Sep 17 00:00:00 2001 From: area268457913 Date: Wed, 10 Nov 2021 15:20:34 +0800 Subject: [PATCH 093/135] Add isAdmin to users table & Add authentication before rendering pages --- .../20211110065754-add-isAdmin-to-users.js | 14 +++++++++++ models/user.js | 3 ++- routes/index.js | 23 +++++++++++++++---- 3 files changed, 35 insertions(+), 5 deletions(-) create mode 100644 migrations/20211110065754-add-isAdmin-to-users.js diff --git a/migrations/20211110065754-add-isAdmin-to-users.js b/migrations/20211110065754-add-isAdmin-to-users.js new file mode 100644 index 00000000..60e6fe08 --- /dev/null +++ b/migrations/20211110065754-add-isAdmin-to-users.js @@ -0,0 +1,14 @@ +'use strict'; + +module.exports = { + up: async (queryInterface, Sequelize) => { + await queryInterface.addColumn('Users', 'isAdmin', { + type: Sequelize.BOOLEAN, + defaultValue: false, + }); + }, + + down: async (queryInterface, Sequelize) => { + await queryInterface.removeColumn('Users', 'isAdmin'); + } +}; diff --git a/models/user.js b/models/user.js index 90c48b43..abe49066 100644 --- a/models/user.js +++ b/models/user.js @@ -16,7 +16,8 @@ module.exports = (sequelize, DataTypes) => { User.init({ name: DataTypes.STRING, email: DataTypes.STRING, - password: DataTypes.STRING + password: DataTypes.STRING, + isAdmin: DataTypes.BOOLEAN }, { sequelize, modelName: 'User', diff --git a/routes/index.js b/routes/index.js index 9a16a7ae..251c2df7 100644 --- a/routes/index.js +++ b/routes/index.js @@ -5,14 +5,29 @@ const { get } = require('superagent') module.exports = (app, passport) => { + const authenticated = (req, res, next) => { + if (req.isAuthenticated()) { + return next() + } + res.redirect('/signin') + } + const authenticatedAdmin = (req, res, next) => { + if (req.isAuthenticated()) { + if (req.user.isAdmin) { return next() } + return res.redirect('/') + } + res.redirect('/signin') + } + + //如果使用者訪問首頁,就導向 /restaurants 的頁面 - app.get('/', (req, res) => res.redirect('/restaurants')) + app.get('/', authenticated, (req, res) => res.redirect('/restaurants')) //在 /restaurants 底下則交給 restController.getRestaurants 來處理 - app.get('/restaurants', restController.getRestaurants) + app.get('/restaurants', authenticated, restController.getRestaurants) // 連到 /admin 頁面就轉到 /admin/restaurants - app.get('/admin', (req, res) => res.redirect('/admin/restaurants')) + app.get('/admin', authenticatedAdmin, (req, res) => res.redirect('/admin/restaurants')) // 在 /admin/restaurants 底下則交給 adminController.getRestaurants 處理 - app.get('/admin/restaurants', adminController.getRestaurants) + app.get('/admin/restaurants', authenticatedAdmin, adminController.getRestaurants) app.get('/signup', userController.signUpPage) app.post('/signup', userController.signUp) From 06d07af013b2ad4fdd95cdd34e5bf467c8f13116 Mon Sep 17 00:00:00 2001 From: area268457913 Date: Thu, 11 Nov 2021 02:06:05 +0800 Subject: [PATCH 094/135] Create restaurant model --- .../20211110180411-create-restaurant.js | 39 +++++++++++++++++++ models/restaurant.js | 27 +++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 migrations/20211110180411-create-restaurant.js create mode 100644 models/restaurant.js diff --git a/migrations/20211110180411-create-restaurant.js b/migrations/20211110180411-create-restaurant.js new file mode 100644 index 00000000..9ae279d5 --- /dev/null +++ b/migrations/20211110180411-create-restaurant.js @@ -0,0 +1,39 @@ +'use strict'; +module.exports = { + up: async (queryInterface, Sequelize) => { + await queryInterface.createTable('Restaurants', { + id: { + allowNull: false, + autoIncrement: true, + primaryKey: true, + type: Sequelize.INTEGER + }, + name: { + type: Sequelize.STRING + }, + tel: { + type: Sequelize.STRING + }, + address: { + type: Sequelize.STRING + }, + opening_hours: { + type: Sequelize.STRING + }, + description: { + type: Sequelize.TEXT + }, + createdAt: { + allowNull: false, + type: Sequelize.DATE + }, + updatedAt: { + allowNull: false, + type: Sequelize.DATE + } + }); + }, + down: async (queryInterface, Sequelize) => { + await queryInterface.dropTable('Restaurants'); + } +}; \ No newline at end of file diff --git a/models/restaurant.js b/models/restaurant.js new file mode 100644 index 00000000..b9db8597 --- /dev/null +++ b/models/restaurant.js @@ -0,0 +1,27 @@ +'use strict'; +const { + Model +} = require('sequelize'); +module.exports = (sequelize, DataTypes) => { + class Restaurant extends Model { + /** + * Helper method for defining associations. + * This method is not a part of Sequelize lifecycle. + * The `models/index` file will call this method automatically. + */ + static associate(models) { + // define association here + } + }; + Restaurant.init({ + name: DataTypes.STRING, + tel: DataTypes.STRING, + address: DataTypes.STRING, + opening_hours: DataTypes.STRING, + description: DataTypes.TEXT + }, { + sequelize, + modelName: 'Restaurant', + }); + return Restaurant; +}; \ No newline at end of file From 33288808a0cdc76acf8904400c8f401665055f88 Mon Sep 17 00:00:00 2001 From: area268457913 Date: Thu, 11 Nov 2021 02:23:22 +0800 Subject: [PATCH 095/135] Add admin restaurant index page --- controllers/adminController.js | 7 ++++- views/admin/restaurants.handlebars | 44 ++++++++++++++++++++++++++++-- 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/controllers/adminController.js b/controllers/adminController.js index b220f29a..86ec90cd 100644 --- a/controllers/adminController.js +++ b/controllers/adminController.js @@ -1,6 +1,11 @@ +const db = require('../models') +const Restaurant = db.Restaurant + const adminController = { getRestaurants: (req, res) => { - return res.render('admin/restaurants') + return Restaurant.findAll({ raw: true }).then(restaurants => { + return res.render('admin/restaurants', { restaurants: restaurants }) + }) } } diff --git a/views/admin/restaurants.handlebars b/views/admin/restaurants.handlebars index c1e24fc9..bb48b147 100644 --- a/views/admin/restaurants.handlebars +++ b/views/admin/restaurants.handlebars @@ -1,3 +1,41 @@ -
- admin restaurants -
\ No newline at end of file +

餐廳後台

+ + + + + +
+
+ + + + + + + + + + + {{#each restaurants}} + + + + + + {{/each}} + +
#Name#
{{this.id}}{{this.name}} + + +
+ +
+
\ No newline at end of file From 9ed480ee267057f9c1ea6baba5c3a3d025be64b4 Mon Sep 17 00:00:00 2001 From: area268457913 Date: Thu, 11 Nov 2021 02:39:13 +0800 Subject: [PATCH 096/135] Add admin restaurant create form & Add admin restaurant post feature --- controllers/adminController.js | 23 +++++++++++++++++++++++ routes/index.js | 3 +++ views/admin/create.handlebars | 28 ++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+) create mode 100644 views/admin/create.handlebars diff --git a/controllers/adminController.js b/controllers/adminController.js index 86ec90cd..c58fa40f 100644 --- a/controllers/adminController.js +++ b/controllers/adminController.js @@ -6,6 +6,29 @@ const adminController = { return Restaurant.findAll({ raw: true }).then(restaurants => { return res.render('admin/restaurants', { restaurants: restaurants }) }) + }, + + createRestaurant: (req, res) => { + return res.render('admin/create') + }, + + postRestaurant: (req, res) => { + // 如果沒填餐廳名字 + if (!req.body.name) { + req.flash('error_messages', "name didn't exist") + return res.redirect('back') + } + return Restaurant.create({ + name: req.body.name, + tel: req.body.tel, + address: req.body.address, + opening_hours: req.body.opening_hours, + description: req.body.description + }) + .then((restaurant) => { + req.flash('success_messages', 'restaurant was successfully created') + res.redirect('/admin/restaurants') + }) } } diff --git a/routes/index.js b/routes/index.js index 251c2df7..68bdf452 100644 --- a/routes/index.js +++ b/routes/index.js @@ -35,4 +35,7 @@ module.exports = (app, passport) => { app.get('/signin', userController.signInPage) app.post('/signin', passport.authenticate('local', { failureRedirect: '/signin', failureFlash: true }), userController.signIn) app.get('/logout', userController.logout) + + app.get('/admin/restaurants/create', authenticatedAdmin, adminController.createRestaurant) + app.post('/admin/restaurants', authenticatedAdmin, adminController.postRestaurant) } diff --git a/views/admin/create.handlebars b/views/admin/create.handlebars new file mode 100644 index 00000000..83881311 --- /dev/null +++ b/views/admin/create.handlebars @@ -0,0 +1,28 @@ +
+
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ + +
\ No newline at end of file From 7fd8fff8ee204c4d69821af5aaf297977aa526be Mon Sep 17 00:00:00 2001 From: area268457913 Date: Thu, 11 Nov 2021 03:02:12 +0800 Subject: [PATCH 097/135] Add admin restaurant page --- controllers/adminController.js | 10 ++++++++++ routes/index.js | 7 +++++-- views/admin/restaurant.handlebars | 26 ++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 views/admin/restaurant.handlebars diff --git a/controllers/adminController.js b/controllers/adminController.js index c58fa40f..3f327d04 100644 --- a/controllers/adminController.js +++ b/controllers/adminController.js @@ -29,6 +29,16 @@ const adminController = { req.flash('success_messages', 'restaurant was successfully created') res.redirect('/admin/restaurants') }) + }, + + getRestaurant: (req, res) => { + return Restaurant.findByPk(req.params.id, { raw: true }).then( + restaurant => { + return res.render('admin/restaurant', { + restaurant: restaurant + }) + } + ) } } diff --git a/routes/index.js b/routes/index.js index 68bdf452..252c5a25 100644 --- a/routes/index.js +++ b/routes/index.js @@ -28,6 +28,10 @@ module.exports = (app, passport) => { app.get('/admin', authenticatedAdmin, (req, res) => res.redirect('/admin/restaurants')) // 在 /admin/restaurants 底下則交給 adminController.getRestaurants 處理 app.get('/admin/restaurants', authenticatedAdmin, adminController.getRestaurants) + app.get('/admin/restaurants/create', authenticatedAdmin, adminController.createRestaurant) + app.post('/admin/restaurants', authenticatedAdmin, adminController.postRestaurant) + app.get('/admin/restaurants/:id', authenticatedAdmin, adminController.getRestaurant) + app.get('/signup', userController.signUpPage) app.post('/signup', userController.signUp) @@ -36,6 +40,5 @@ module.exports = (app, passport) => { app.post('/signin', passport.authenticate('local', { failureRedirect: '/signin', failureFlash: true }), userController.signIn) app.get('/logout', userController.logout) - app.get('/admin/restaurants/create', authenticatedAdmin, adminController.createRestaurant) - app.post('/admin/restaurants', authenticatedAdmin, adminController.postRestaurant) + } diff --git a/views/admin/restaurant.handlebars b/views/admin/restaurant.handlebars new file mode 100644 index 00000000..ccd9b7a3 --- /dev/null +++ b/views/admin/restaurant.handlebars @@ -0,0 +1,26 @@ +
+
+

{{restaurant.name}}

+
+ +
+
+
+
    +
  • Opening Hour: {{restaurant.opening_hours}}
  • +
  • Tel: {{restaurant.tel}}
  • +
  • Address: {{restaurant.address}}
  • +
+
+
+
+

{{restaurant.description}}

+
+
+
+ +
+ +
+
+回上一頁 \ No newline at end of file From 30a4f64ff16a9a6228a0de4e9cb6ecb466bcf7b0 Mon Sep 17 00:00:00 2001 From: area268457913 Date: Thu, 11 Nov 2021 03:31:53 +0800 Subject: [PATCH 098/135] Update admin create page for editing usage & Install method-override & Add admin restaurant put feature --- app.js | 4 +++ controllers/adminController.js | 30 ++++++++++++++++++- package-lock.json | 21 +++++++++++++ package.json | 1 + routes/index.js | 3 +- views/admin/create.handlebars | 54 +++++++++++++++++++--------------- 6 files changed, 88 insertions(+), 25 deletions(-) diff --git a/app.js b/app.js index 5b968a26..b05cfe71 100644 --- a/app.js +++ b/app.js @@ -4,6 +4,7 @@ const bodyParser = require('body-parser')// Express 升級到了 4.17.1 之後 const flash = require('connect-flash') const session = require('express-session') const passport = require('./config/passport') +const methodOverride = require('method-override') const db = require('./models') // 引入資料庫 const app = express() @@ -27,6 +28,9 @@ app.use((req, res, next) => { next() }) +app.use(methodOverride('_method')) + + app.listen(port, () => { console.log(`Example app listening at http://localhost:${port}`) }) diff --git a/controllers/adminController.js b/controllers/adminController.js index 3f327d04..40a6a40c 100644 --- a/controllers/adminController.js +++ b/controllers/adminController.js @@ -39,7 +39,35 @@ const adminController = { }) } ) - } + }, + + editRestaurant: (req, res) => { + return Restaurant.findByPk(req.params.id, { raw: true }).then(restaurant => { + return res.render('admin/create', { restaurant: restaurant }) + }) + }, + + putRestaurant: (req, res) => { + if (!req.body.name) { + req.flash('error_messages', "name didn't exist") + return res.redirect('back') + } + + return Restaurant.findByPk(req.params.id) + .then((restaurant) => { + restaurant.update({ + name: req.body.name, + tel: req.body.tel, + address: req.body.address, + opening_hours: req.body.opening_hours, + description: req.body.description + }) + .then((restaurant) => { + req.flash('success_messages', 'restaurant was successfully to update') + res.redirect('/admin/restaurants') + }) + }) + }, } module.exports = adminController \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 944a27a3..5d7a100f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1038,6 +1038,27 @@ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" }, + "method-override": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/method-override/-/method-override-3.0.0.tgz", + "integrity": "sha512-IJ2NNN/mSl9w3kzWB92rcdHpz+HjkxhDJWNDBqSlas+zQdP8wBiJzITPg08M/k2uVvMow7Sk41atndNtt/PHSA==", + "requires": { + "debug": "3.1.0", + "methods": "~1.1.2", + "parseurl": "~1.3.2", + "vary": "~1.1.2" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, "methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", diff --git a/package.json b/package.json index b1dc0f91..d7a3122d 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "express": "^4.17.1", "express-handlebars": "^5.3.4", "express-session": "^1.17.2", + "method-override": "^3.0.0", "mocha": "^8.2.0", "mysql2": "^2.2.5", "passport": "^0.5.0", diff --git a/routes/index.js b/routes/index.js index 252c5a25..dfc457b4 100644 --- a/routes/index.js +++ b/routes/index.js @@ -31,7 +31,8 @@ module.exports = (app, passport) => { app.get('/admin/restaurants/create', authenticatedAdmin, adminController.createRestaurant) app.post('/admin/restaurants', authenticatedAdmin, adminController.postRestaurant) app.get('/admin/restaurants/:id', authenticatedAdmin, adminController.getRestaurant) - + app.get('/admin/restaurants/:id/edit', authenticatedAdmin, adminController.editRestaurant) + app.put('/admin/restaurants/:id', authenticatedAdmin, adminController.putRestaurant) app.get('/signup', userController.signUpPage) app.post('/signup', userController.signUp) diff --git a/views/admin/create.handlebars b/views/admin/create.handlebars index 83881311..e412f6f3 100644 --- a/views/admin/create.handlebars +++ b/views/admin/create.handlebars @@ -1,28 +1,36 @@ -
-
- - -
+{{#if restaurant}} + + {{else}} + + {{/if}} -
- - -
+
+ + +
-
- - -
+
+ + +
-
- - -
+
+ + +
-
- - -
+
+ + +
- -
\ No newline at end of file +
+ + +
+ + + \ No newline at end of file From a5fb3f3e4637988e28787207bea24ebd2bf6837d Mon Sep 17 00:00:00 2001 From: area268457913 Date: Thu, 11 Nov 2021 03:39:12 +0800 Subject: [PATCH 099/135] Add admin restaurant delete feature --- controllers/adminController.js | 11 +++++++++++ routes/index.js | 1 + 2 files changed, 12 insertions(+) diff --git a/controllers/adminController.js b/controllers/adminController.js index 40a6a40c..d5b30174 100644 --- a/controllers/adminController.js +++ b/controllers/adminController.js @@ -68,6 +68,17 @@ const adminController = { }) }) }, + + deleteRestaurant: (req, res) => { + return Restaurant.findByPk(req.params.id) + .then((restaurant) => { + restaurant.destroy() + .then((restaurant) => { + res.redirect('/admin/restaurants') + }) + }) + } + } module.exports = adminController \ No newline at end of file diff --git a/routes/index.js b/routes/index.js index dfc457b4..985426af 100644 --- a/routes/index.js +++ b/routes/index.js @@ -33,6 +33,7 @@ module.exports = (app, passport) => { app.get('/admin/restaurants/:id', authenticatedAdmin, adminController.getRestaurant) app.get('/admin/restaurants/:id/edit', authenticatedAdmin, adminController.editRestaurant) app.put('/admin/restaurants/:id', authenticatedAdmin, adminController.putRestaurant) + app.delete('/admin/restaurants/:id', authenticatedAdmin, adminController.deleteRestaurant) app.get('/signup', userController.signUpPage) app.post('/signup', userController.signUp) From a423fc67d7ea6ed4d10dda182d2220a83560f9b6 Mon Sep 17 00:00:00 2001 From: area268457913 Date: Thu, 11 Nov 2021 15:55:10 +0800 Subject: [PATCH 100/135] Add image to restaurants & Install multer and add image upload feature --- app.js | 1 + controllers/adminController.js | 85 +++++++--- ...20211111070245-add-image-to-restaurants.js | 11 ++ models/restaurant.js | 4 +- package-lock.json | 159 ++++++++++++++++++ package.json | 1 + routes/index.js | 6 +- views/admin/create.handlebars | 9 +- views/admin/restaurant.handlebars | 1 + 9 files changed, 252 insertions(+), 25 deletions(-) create mode 100644 migrations/20211111070245-add-image-to-restaurants.js diff --git a/app.js b/app.js index b05cfe71..797f3785 100644 --- a/app.js +++ b/app.js @@ -29,6 +29,7 @@ app.use((req, res, next) => { }) app.use(methodOverride('_method')) +app.use('/upload', express.static(__dirname + '/upload')) app.listen(port, () => { diff --git a/controllers/adminController.js b/controllers/adminController.js index d5b30174..1e3ca23c 100644 --- a/controllers/adminController.js +++ b/controllers/adminController.js @@ -1,5 +1,7 @@ const db = require('../models') const Restaurant = db.Restaurant +const fs = require('fs') + const adminController = { getRestaurants: (req, res) => { @@ -13,22 +15,42 @@ const adminController = { }, postRestaurant: (req, res) => { - // 如果沒填餐廳名字 if (!req.body.name) { req.flash('error_messages', "name didn't exist") return res.redirect('back') } - return Restaurant.create({ - name: req.body.name, - tel: req.body.tel, - address: req.body.address, - opening_hours: req.body.opening_hours, - description: req.body.description - }) - .then((restaurant) => { + + const { file } = req // equal to const file = req.file + if (file) { + fs.readFile(file.path, (err, data) => { + if (err) console.log('Error: ', err) + fs.writeFile(`upload/${file.originalname}`, data, () => { + return Restaurant.create({ + name: req.body.name, + tel: req.body.tel, + address: req.body.address, + opening_hours: req.body.opening_hours, + description: req.body.description, + image: file ? `/upload/${file.originalname}` : null + }).then((restaurant) => { + req.flash('success_messages', 'restaurant was successfully created') + return res.redirect('/admin/restaurants') + }) + }) + }) + } else { + return Restaurant.create({ + name: req.body.name, + tel: req.body.tel, + address: req.body.address, + opening_hours: req.body.opening_hours, + description: req.body.description, + image: null + }).then((restaurant) => { req.flash('success_messages', 'restaurant was successfully created') - res.redirect('/admin/restaurants') + return res.redirect('/admin/restaurants') }) + } }, getRestaurant: (req, res) => { @@ -53,20 +75,43 @@ const adminController = { return res.redirect('back') } - return Restaurant.findByPk(req.params.id) - .then((restaurant) => { - restaurant.update({ - name: req.body.name, - tel: req.body.tel, - address: req.body.address, - opening_hours: req.body.opening_hours, - description: req.body.description + const { file } = req + if (file) { + fs.readFile(file.path, (err, data) => { + if (err) console.log('Error: ', err) + fs.writeFile(`upload/${file.originalname}`, data, () => { + return Restaurant.findByPk(req.params.id) + .then((restaurant) => { + restaurant.update({ + name: req.body.name, + tel: req.body.tel, + address: req.body.address, + opening_hours: req.body.opening_hours, + description: req.body.description, + image: file ? `/upload/${file.originalname}` : restaurant.image + }).then((restaurant) => { + req.flash('success_messages', 'restaurant was successfully to update') + res.redirect('/admin/restaurants') + }) + }) }) - .then((restaurant) => { + }) + } else { + return Restaurant.findByPk(req.params.id) + .then((restaurant) => { + restaurant.update({ + name: req.body.name, + tel: req.body.tel, + address: req.body.address, + opening_hours: req.body.opening_hours, + description: req.body.description, + image: restaurant.image + }).then((restaurant) => { req.flash('success_messages', 'restaurant was successfully to update') res.redirect('/admin/restaurants') }) - }) + }) + } }, deleteRestaurant: (req, res) => { diff --git a/migrations/20211111070245-add-image-to-restaurants.js b/migrations/20211111070245-add-image-to-restaurants.js new file mode 100644 index 00000000..91125e87 --- /dev/null +++ b/migrations/20211111070245-add-image-to-restaurants.js @@ -0,0 +1,11 @@ +'use strict'; +module.exports = { + up: async (queryInterface, Sequelize) => { + await queryInterface.addColumn('Restaurants', 'image', { + type: Sequelize.STRING + }); + }, + down: async (queryInterface, Sequelize) => { + await queryInterface.removeColumn('Restaurants', 'image'); + } +}; diff --git a/models/restaurant.js b/models/restaurant.js index b9db8597..bebed0be 100644 --- a/models/restaurant.js +++ b/models/restaurant.js @@ -18,7 +18,9 @@ module.exports = (sequelize, DataTypes) => { tel: DataTypes.STRING, address: DataTypes.STRING, opening_hours: DataTypes.STRING, - description: DataTypes.TEXT + description: DataTypes.TEXT, + image: DataTypes.STRING + }, { sequelize, modelName: 'Restaurant', diff --git a/package-lock.json b/package-lock.json index 5d7a100f..fb36ca7d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -100,6 +100,11 @@ "picomatch": "^2.0.4" } }, + "append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY=" + }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -182,6 +187,38 @@ "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==" }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "busboy": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz", + "integrity": "sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=", + "requires": { + "dicer": "0.2.5", + "readable-stream": "1.1.x" + }, + "dependencies": { + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + } + } + }, "bytes": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", @@ -316,6 +353,46 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, "config-chain": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz", @@ -358,6 +435,11 @@ "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz", "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==" }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, "d": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", @@ -408,6 +490,33 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" }, + "dicer": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz", + "integrity": "sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=", + "requires": { + "readable-stream": "1.1.x", + "streamsearch": "0.1.2" + }, + "dependencies": { + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + } + } + }, "diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", @@ -1203,6 +1312,31 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, + "multer": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.3.tgz", + "integrity": "sha512-np0YLKncuZoTzufbkM6wEKp68EhWJXcU6fq6QqrSwkckd2LlMgd1UqhUJLj6NS/5sZ8dE8LYDWslsltJznnXlg==", + "requires": { + "append-field": "^1.0.0", + "busboy": "^0.2.11", + "concat-stream": "^1.5.2", + "mkdirp": "^0.5.4", + "object-assign": "^4.1.1", + "on-finished": "^2.3.0", + "type-is": "^1.6.4", + "xtend": "^4.0.0" + }, + "dependencies": { + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "requires": { + "minimist": "^1.2.5" + } + } + } + }, "mysql2": { "version": "2.2.5", "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-2.2.5.tgz", @@ -1307,6 +1441,11 @@ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, "on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", @@ -1411,6 +1550,11 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==" }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, "proto-list": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", @@ -1678,6 +1822,11 @@ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" }, + "streamsearch": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", + "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=" + }, "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", @@ -1829,6 +1978,11 @@ "mime-types": "~2.1.24" } }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, "uglify-js": { "version": "3.14.3", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.14.3.tgz", @@ -1964,6 +2118,11 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + }, "y18n": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", diff --git a/package.json b/package.json index d7a3122d..2415a1c1 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "express-session": "^1.17.2", "method-override": "^3.0.0", "mocha": "^8.2.0", + "multer": "^1.4.3", "mysql2": "^2.2.5", "passport": "^0.5.0", "passport-local": "^1.0.0", diff --git a/routes/index.js b/routes/index.js index 985426af..b464c240 100644 --- a/routes/index.js +++ b/routes/index.js @@ -2,6 +2,8 @@ const restController = require('../controllers/restController.js') const adminController = require('../controllers/adminController.js') const userController = require('../controllers/userController.js') const { get } = require('superagent') +const multer = require('multer') +const upload = multer({ dest: 'temp/' }) module.exports = (app, passport) => { @@ -29,10 +31,10 @@ module.exports = (app, passport) => { // 在 /admin/restaurants 底下則交給 adminController.getRestaurants 處理 app.get('/admin/restaurants', authenticatedAdmin, adminController.getRestaurants) app.get('/admin/restaurants/create', authenticatedAdmin, adminController.createRestaurant) - app.post('/admin/restaurants', authenticatedAdmin, adminController.postRestaurant) + app.post('/admin/restaurants', authenticatedAdmin, upload.single('image'), adminController.postRestaurant) app.get('/admin/restaurants/:id', authenticatedAdmin, adminController.getRestaurant) app.get('/admin/restaurants/:id/edit', authenticatedAdmin, adminController.editRestaurant) - app.put('/admin/restaurants/:id', authenticatedAdmin, adminController.putRestaurant) + app.put('/admin/restaurants/:id', authenticatedAdmin, upload.single('image'), adminController.putRestaurant) app.delete('/admin/restaurants/:id', authenticatedAdmin, adminController.deleteRestaurant) app.get('/signup', userController.signUpPage) diff --git a/views/admin/create.handlebars b/views/admin/create.handlebars index e412f6f3..09fe06fa 100644 --- a/views/admin/create.handlebars +++ b/views/admin/create.handlebars @@ -1,7 +1,7 @@ {{#if restaurant}} -
+ {{else}} - + {{/if}}
@@ -32,5 +32,10 @@
+
+ + +
+
\ No newline at end of file diff --git a/views/admin/restaurant.handlebars b/views/admin/restaurant.handlebars index ccd9b7a3..e6b1fa59 100644 --- a/views/admin/restaurant.handlebars +++ b/views/admin/restaurant.handlebars @@ -4,6 +4,7 @@
+
    From 9500c87e76c3399e8c7f8a08b27eed5f03a91b75 Mon Sep 17 00:00:00 2001 From: area268457913 Date: Fri, 12 Nov 2021 03:31:10 +0800 Subject: [PATCH 101/135] Add user seed data & Install faker and add restaurant seed data --- package-lock.json | 5 +++ package.json | 1 + seeders/20211111180715-users-seed-file.js | 31 +++++++++++++++++++ .../20211111191015-restaurants-seed-file.js | 24 ++++++++++++++ 4 files changed, 61 insertions(+) create mode 100644 seeders/20211111180715-users-seed-file.js create mode 100644 seeders/20211111191015-restaurants-seed-file.js diff --git a/package-lock.json b/package-lock.json index fb36ca7d..36855a18 100644 --- a/package-lock.json +++ b/package-lock.json @@ -757,6 +757,11 @@ } } }, + "faker": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/faker/-/faker-5.5.3.tgz", + "integrity": "sha512-wLTv2a28wjUyWkbnX7u/ABZBkUkIF2fCd73V6P2oFqEGEktDfzWx4UxrSqtPRw0xPRAcjeAOIiJWqZm3pP4u3g==" + }, "fast-safe-stringify": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", diff --git a/package.json b/package.json index 2415a1c1..60d446a3 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "express": "^4.17.1", "express-handlebars": "^5.3.4", "express-session": "^1.17.2", + "faker": "^5.5.3", "method-override": "^3.0.0", "mocha": "^8.2.0", "multer": "^1.4.3", diff --git a/seeders/20211111180715-users-seed-file.js b/seeders/20211111180715-users-seed-file.js new file mode 100644 index 00000000..be1f6ff7 --- /dev/null +++ b/seeders/20211111180715-users-seed-file.js @@ -0,0 +1,31 @@ +'use strict' +const bcrypt = require('bcryptjs') +module.exports = { + up: async (queryInterface, Sequelize) => { + await queryInterface.bulkInsert('Users', [{ + email: 'root@example.com', + password: bcrypt.hashSync('12345678', bcrypt.genSaltSync(10), null), + isAdmin: true, + name: 'root', + createdAt: new Date(), + updatedAt: new Date() + }, { + email: 'user1@example.com', + password: bcrypt.hashSync('12345678', bcrypt.genSaltSync(10), null), + isAdmin: false, + name: 'user1', + createdAt: new Date(), + updatedAt: new Date() + }, { + email: 'user2@example.com', + password: bcrypt.hashSync('12345678', bcrypt.genSaltSync(10), null), + isAdmin: false, + name: 'user2', + createdAt: new Date(), + updatedAt: new Date() + }], {}) + }, + down: async (queryInterface, Sequelize) => { + await queryInterface.bulkDelete('Users', null, {}) + } +} \ No newline at end of file diff --git a/seeders/20211111191015-restaurants-seed-file.js b/seeders/20211111191015-restaurants-seed-file.js new file mode 100644 index 00000000..3db3efb1 --- /dev/null +++ b/seeders/20211111191015-restaurants-seed-file.js @@ -0,0 +1,24 @@ +'use strict' +const faker = require('faker') + +module.exports = { + up: async (queryInterface, Sequelize) => { + await queryInterface.bulkInsert('Restaurants', + Array.from({ length: 50 }).map((d, i) => + ({ + name: faker.name.findName(), + tel: faker.phone.phoneNumber(), + address: faker.address.streetAddress(), + opening_hours: '08:00', + image: `https://loremflickr.com/320/240/restaurant,food/?random=${Math.random() * 100}`, + description: faker.lorem.text(), + createdAt: new Date(), + updatedAt: new Date() + }) + ), {}) + }, + + down: async (queryInterface, Sequelize) => { + await queryInterface.bulkDelete('Restaurants', null, {}) + } +} \ No newline at end of file From 91bd4f8496e847d3202c98aa78b4b186779882b0 Mon Sep 17 00:00:00 2001 From: area268457913 Date: Fri, 12 Nov 2021 14:17:15 +0800 Subject: [PATCH 102/135] Install pg and update production config --- config/config.json | 9 ++++- package-lock.json | 95 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 1 + 3 files changed, 104 insertions(+), 1 deletion(-) diff --git a/config/config.json b/config/config.json index 56636a1c..94fc0637 100644 --- a/config/config.json +++ b/config/config.json @@ -15,7 +15,14 @@ "logging": false }, "production": { - "use_env_variable": "CLEARDB_SILVER_URL" + "use_env_variable": "DATABASE_URL", + "dialect": "postgres", + "protocol": "postgres", + "dialectOptions": { + "ssl": { + "rejectUnauthorized": false + } + } }, "travis": { "username": "travis", diff --git a/package-lock.json b/package-lock.json index 36855a18..63dfe3ac 100644 --- a/package-lock.json +++ b/package-lock.json @@ -192,6 +192,11 @@ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" }, + "buffer-writer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", + "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==" + }, "busboy": { "version": "0.2.14", "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz", @@ -1493,6 +1498,11 @@ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" }, + "packet-reader": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", + "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" + }, "parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -1550,11 +1560,88 @@ "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", "integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10=" }, + "pg": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.7.1.tgz", + "integrity": "sha512-7bdYcv7V6U3KAtWjpQJJBww0UEsWuh4yQ/EjNf2HeO/NnvKjpvhEIe/A/TleP6wtmSKnUnghs5A9jUoK6iDdkA==", + "requires": { + "buffer-writer": "2.0.0", + "packet-reader": "1.0.0", + "pg-connection-string": "^2.5.0", + "pg-pool": "^3.4.1", + "pg-protocol": "^1.5.0", + "pg-types": "^2.1.0", + "pgpass": "1.x" + } + }, + "pg-connection-string": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz", + "integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==" + }, + "pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==" + }, + "pg-pool": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.4.1.tgz", + "integrity": "sha512-TVHxR/gf3MeJRvchgNHxsYsTCHQ+4wm3VIHSS19z8NC0+gioEhq1okDY1sm/TYbfoP6JLFx01s0ShvZ3puP/iQ==" + }, + "pg-protocol": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.5.0.tgz", + "integrity": "sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ==" + }, + "pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "requires": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + } + }, + "pgpass": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.4.tgz", + "integrity": "sha512-YmuA56alyBq7M59vxVBfPJrGSozru8QAdoNlWuW3cz8l+UX3cWge0vTvjKhsSHSJpo3Bom8/Mm6hf0TR5GY0+w==", + "requires": { + "split2": "^3.1.1" + } + }, "picomatch": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==" }, + "postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==" + }, + "postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha1-AntTPAqokOJtFy1Hz5zOzFIazTU=" + }, + "postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==" + }, + "postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "requires": { + "xtend": "^4.0.0" + } + }, "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -1812,6 +1899,14 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" }, + "split2": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", + "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", + "requires": { + "readable-stream": "^3.0.0" + } + }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", diff --git a/package.json b/package.json index 60d446a3..215b7130 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "mysql2": "^2.2.5", "passport": "^0.5.0", "passport-local": "^1.0.0", + "pg": "^8.7.1", "sequelize": "^6.3.5", "sequelize-cli": "^6.2.0", "sinon": "^9.2.0", From 51d97941a9e32a41bb6bc022fde0c3f18bbd7e49 Mon Sep 17 00:00:00 2001 From: area268457913 Date: Fri, 12 Nov 2021 14:55:07 +0800 Subject: [PATCH 103/135] updata port & add Procfile --- Procfile | 1 + app.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 Procfile diff --git a/Procfile b/Procfile new file mode 100644 index 00000000..2cbe96df --- /dev/null +++ b/Procfile @@ -0,0 +1 @@ +web: NODE_ENV=production node app.js diff --git a/app.js b/app.js index 797f3785..3c69dc5f 100644 --- a/app.js +++ b/app.js @@ -8,7 +8,7 @@ const methodOverride = require('method-override') const db = require('./models') // 引入資料庫 const app = express() -const port = 3000 +const port = process.env.PORT || 3000 app.engine('handlebars', handlebars({ defaultLayout: 'main' })) // Handlebars 註冊樣板引擎 From 16306d395deee5f5210aba04e04723577bfe57e6 Mon Sep 17 00:00:00 2001 From: area268457913 Date: Fri, 12 Nov 2021 15:30:06 +0800 Subject: [PATCH 104/135] Install Imgur api and update admin POST and PUT & Add dotenv --- .env.example | 1 + app.js | 5 ++ controllers/adminController.js | 74 ++++++++--------- package-lock.json | 146 +++++++++++++++++++++++++++++++++ package.json | 2 + 5 files changed, 191 insertions(+), 37 deletions(-) create mode 100644 .env.example diff --git a/.env.example b/.env.example new file mode 100644 index 00000000..541a886c --- /dev/null +++ b/.env.example @@ -0,0 +1 @@ +IMGUR_CLIENT_ID=SKIP diff --git a/app.js b/app.js index 3c69dc5f..397b1e2e 100644 --- a/app.js +++ b/app.js @@ -2,6 +2,11 @@ const express = require('express') const handlebars = require('express-handlebars') // 引入 handlebars const bodyParser = require('body-parser')// Express 升級到了 4.17.1 之後,不用額外載入 body-parser,這行程式碼便不用寫 const flash = require('connect-flash') + +if (process.env.NODE_ENV !== 'production') { + require('dotenv').config() +} + const session = require('express-session') const passport = require('./config/passport') const methodOverride = require('method-override') diff --git a/controllers/adminController.js b/controllers/adminController.js index 1e3ca23c..76273709 100644 --- a/controllers/adminController.js +++ b/controllers/adminController.js @@ -1,7 +1,8 @@ const db = require('../models') const Restaurant = db.Restaurant const fs = require('fs') - +const imgur = require('imgur-node-api') +const IMGUR_CLIENT_ID = process.env.IMGUR_CLIENT_ID const adminController = { getRestaurants: (req, res) => { @@ -20,25 +21,24 @@ const adminController = { return res.redirect('back') } - const { file } = req // equal to const file = req.file + const { file } = req if (file) { - fs.readFile(file.path, (err, data) => { - if (err) console.log('Error: ', err) - fs.writeFile(`upload/${file.originalname}`, data, () => { - return Restaurant.create({ - name: req.body.name, - tel: req.body.tel, - address: req.body.address, - opening_hours: req.body.opening_hours, - description: req.body.description, - image: file ? `/upload/${file.originalname}` : null - }).then((restaurant) => { - req.flash('success_messages', 'restaurant was successfully created') - return res.redirect('/admin/restaurants') - }) + imgur.setClientID(IMGUR_CLIENT_ID); + imgur.upload(file.path, (err, img) => { + return Restaurant.create({ + name: req.body.name, + tel: req.body.tel, + address: req.body.address, + opening_hours: req.body.opening_hours, + description: req.body.description, + image: file ? img.data.link : null, + }).then((restaurant) => { + req.flash('success_messages', 'restaurant was successfully created') + return res.redirect('/admin/restaurants') }) }) - } else { + } + else { return Restaurant.create({ name: req.body.name, tel: req.body.tel, @@ -52,7 +52,6 @@ const adminController = { }) } }, - getRestaurant: (req, res) => { return Restaurant.findByPk(req.params.id, { raw: true }).then( restaurant => { @@ -77,26 +76,26 @@ const adminController = { const { file } = req if (file) { - fs.readFile(file.path, (err, data) => { - if (err) console.log('Error: ', err) - fs.writeFile(`upload/${file.originalname}`, data, () => { - return Restaurant.findByPk(req.params.id) - .then((restaurant) => { - restaurant.update({ - name: req.body.name, - tel: req.body.tel, - address: req.body.address, - opening_hours: req.body.opening_hours, - description: req.body.description, - image: file ? `/upload/${file.originalname}` : restaurant.image - }).then((restaurant) => { + imgur.setClientID(IMGUR_CLIENT_ID); + imgur.upload(file.path, (err, img) => { + return Restaurant.findByPk(req.params.id) + .then((restaurant) => { + restaurant.update({ + name: req.body.name, + tel: req.body.tel, + address: req.body.address, + opening_hours: req.body.opening_hours, + description: req.body.description, + image: file ? img.data.link : restaurant.image, + }) + .then((restaurant) => { req.flash('success_messages', 'restaurant was successfully to update') res.redirect('/admin/restaurants') }) - }) - }) + }) }) - } else { + } + else { return Restaurant.findByPk(req.params.id) .then((restaurant) => { restaurant.update({ @@ -106,10 +105,11 @@ const adminController = { opening_hours: req.body.opening_hours, description: req.body.description, image: restaurant.image - }).then((restaurant) => { - req.flash('success_messages', 'restaurant was successfully to update') - res.redirect('/admin/restaurants') }) + .then((restaurant) => { + req.flash('success_messages', 'restaurant was successfully to update') + res.redirect('/admin/restaurants') + }) }) } }, diff --git a/package-lock.json b/package-lock.json index 63dfe3ac..6fd560cc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -123,11 +123,21 @@ "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==" }, + "async": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", + "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=" + }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, + "aws-sign": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/aws-sign/-/aws-sign-0.2.0.tgz", + "integrity": "sha1-xVAThWyBlOyFSgy+yQqrWgTOOsU=" + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -165,6 +175,14 @@ "type-is": "~1.6.17" } }, + "boom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/boom/-/boom-0.3.8.tgz", + "integrity": "sha1-yM2wQUNZEnQWKMBE7Mcy0dF8Ceo=", + "requires": { + "hoek": "0.7.x" + } + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -430,6 +448,11 @@ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" }, + "cookie-jar": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/cookie-jar/-/cookie-jar-0.2.0.tgz", + "integrity": "sha1-ZOzAasl423leS1KQy+SLo3gUAPo=" + }, "cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", @@ -445,6 +468,14 @@ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" }, + "cryptiles": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-0.1.3.tgz", + "integrity": "sha1-GlVnNPBtJLo0hirpy55wmjr7/xw=", + "requires": { + "boom": "0.3.x" + } + }, "d": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", @@ -527,6 +558,11 @@ "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==" }, + "dotenv": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", + "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==" + }, "dottie": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.2.tgz", @@ -807,6 +843,11 @@ "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==" }, + "forever-agent": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.2.0.tgz", + "integrity": "sha1-4cJcetROCcOPIzh2x2/MJP+EOx8=" + }, "form-data": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.0.tgz", @@ -932,11 +973,27 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, + "hawk": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-0.10.2.tgz", + "integrity": "sha1-mzYd7pWpMWQObVBOBWCaj8OsRdI=", + "requires": { + "boom": "0.3.x", + "cryptiles": "0.1.x", + "hoek": "0.7.x", + "sntp": "0.1.x" + } + }, "he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" }, + "hoek": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-0.7.6.tgz", + "integrity": "sha1-YPvZBFV1Qc0rh5Wr8wihs3cOFVo=" + }, "http-errors": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", @@ -957,6 +1014,14 @@ "safer-buffer": ">= 2.1.2 < 3" } }, + "imgur-node-api": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/imgur-node-api/-/imgur-node-api-0.1.0.tgz", + "integrity": "sha1-iJU25/x9/FyYXHtVeMGuwxyzwYY=", + "requires": { + "request": "~2.16.6" + } + }, "inflection": { "version": "1.12.0", "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz", @@ -1071,6 +1136,11 @@ "esprima": "^4.0.0" } }, + "json-stringify-safe": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-3.0.0.tgz", + "integrity": "sha1-nbew5TDH8onF6MhDKvGRwv91pbM=" + }, "jsonfile": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", @@ -1451,6 +1521,11 @@ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" }, + "oauth-sign": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.2.0.tgz", + "integrity": "sha1-oOahcV2u0GLzIrYit/5a/RA1tuI=" + }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -1718,6 +1793,64 @@ "picomatch": "^2.2.1" } }, + "request": { + "version": "2.16.6", + "resolved": "https://registry.npmjs.org/request/-/request-2.16.6.tgz", + "integrity": "sha1-hy/kRa5y3iZrN4edatfclI+gHK0=", + "requires": { + "aws-sign": "~0.2.0", + "cookie-jar": "~0.2.0", + "forever-agent": "~0.2.0", + "form-data": "~0.0.3", + "hawk": "~0.10.2", + "json-stringify-safe": "~3.0.0", + "mime": "~1.2.7", + "node-uuid": "~1.4.0", + "oauth-sign": "~0.2.0", + "qs": "~0.5.4", + "tunnel-agent": "~0.2.0" + }, + "dependencies": { + "combined-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz", + "integrity": "sha1-ATfmV7qlp1QcV6w3rF/AfXO03B8=", + "requires": { + "delayed-stream": "0.0.5" + } + }, + "delayed-stream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz", + "integrity": "sha1-1LH0OpPoKW3+AmlPRoC8N6MTxz8=" + }, + "form-data": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-0.0.10.tgz", + "integrity": "sha1-2zRaU3jYau6x7V1VO4aawZLS9e0=", + "requires": { + "async": "~0.2.7", + "combined-stream": "~0.0.4", + "mime": "~1.2.2" + } + }, + "mime": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz", + "integrity": "sha1-WCA+7Ybjpe8XrtK32evUfwpg3RA=" + }, + "node-uuid": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz", + "integrity": "sha1-sEDrCSOWivq/jTL7HxfxFn/auQc=" + }, + "qs": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/qs/-/qs-0.5.6.tgz", + "integrity": "sha1-MbGtBYVnZRxSaSFQa5qHk5EaA4Q=" + } + } + }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -1894,6 +2027,14 @@ "supports-color": "^7.1.0" } }, + "sntp": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-0.1.4.tgz", + "integrity": "sha1-XvSBuVGnspr/30r9fyaDj8ESD4Q=", + "requires": { + "hoek": "0.7.x" + } + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -2059,6 +2200,11 @@ "resolved": "https://registry.npmjs.org/toposort-class/-/toposort-class-1.0.1.tgz", "integrity": "sha1-f/0feMi+KMO6Rc1OGj9e4ZO9mYg=" }, + "tunnel-agent": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.2.0.tgz", + "integrity": "sha1-aFPCr7GyEJ5FYp5JK9419Fnqaeg=" + }, "type": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", diff --git a/package.json b/package.json index 215b7130..249df4cb 100644 --- a/package.json +++ b/package.json @@ -23,10 +23,12 @@ "body-parser": "^1.19.0", "chai": "^4.2.0", "connect-flash": "^0.1.1", + "dotenv": "^10.0.0", "express": "^4.17.1", "express-handlebars": "^5.3.4", "express-session": "^1.17.2", "faker": "^5.5.3", + "imgur-node-api": "^0.1.0", "method-override": "^3.0.0", "mocha": "^8.2.0", "multer": "^1.4.3", From 67ebf54226b31c155432dd606a8cbd51911f80f1 Mon Sep 17 00:00:00 2001 From: area268457913 Date: Fri, 12 Nov 2021 15:36:46 +0800 Subject: [PATCH 105/135] heroku PG switch to ClearDB mysql --- config/config.json | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/config/config.json b/config/config.json index 94fc0637..6f8a7df8 100644 --- a/config/config.json +++ b/config/config.json @@ -15,14 +15,7 @@ "logging": false }, "production": { - "use_env_variable": "DATABASE_URL", - "dialect": "postgres", - "protocol": "postgres", - "dialectOptions": { - "ssl": { - "rejectUnauthorized": false - } - } + "use_env_variable": "CLEARDB_DATABASE_URL" }, "travis": { "username": "travis", From a43c2d9993ada74ea1acce08f98765ea32084adc Mon Sep 17 00:00:00 2001 From: area268457913 Date: Sat, 13 Nov 2021 01:52:16 +0800 Subject: [PATCH 106/135] [Assignment Preparation] ensureAuthenticated & getUser --- app.js | 5 +++-- routes/index.js | 7 ++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/app.js b/app.js index 397b1e2e..db531443 100644 --- a/app.js +++ b/app.js @@ -2,7 +2,7 @@ const express = require('express') const handlebars = require('express-handlebars') // 引入 handlebars const bodyParser = require('body-parser')// Express 升級到了 4.17.1 之後,不用額外載入 body-parser,這行程式碼便不用寫 const flash = require('connect-flash') - +const helpers = require('./_helpers') if (process.env.NODE_ENV !== 'production') { require('dotenv').config() } @@ -29,7 +29,8 @@ app.use(flash()) app.use((req, res, next) => { res.locals.success_messages = req.flash('success_messages') res.locals.error_messages = req.flash('error_messages') - res.locals.user = req.user //讓views能存取user + //res.locals.user = req.user //讓views能存取user + res.locals.user = helpers.getUser(req) // 取代 req.user next() }) diff --git a/routes/index.js b/routes/index.js index 4895d793..f227b22b 100644 --- a/routes/index.js +++ b/routes/index.js @@ -4,18 +4,19 @@ const userController = require('../controllers/userController.js') const { get } = require('superagent') const multer = require('multer') const upload = multer({ dest: 'temp/' }) +const helpers = require('../_helpers') module.exports = (app, passport) => { const authenticated = (req, res, next) => { - if (req.isAuthenticated()) { + if (helpers.ensureAuthenticated(req)) { return next() } res.redirect('/signin') } const authenticatedAdmin = (req, res, next) => { - if (req.isAuthenticated()) { - if (req.user.isAdmin) { return next() } + if (helpers.ensureAuthenticated(req)) { + if (helpers.getUser(req).isAdmin) { return next() } return res.redirect('/') } res.redirect('/signin') From 14a4d4d3ef52db6d64edd71c3fdff49390605928 Mon Sep 17 00:00:00 2001 From: area268457913 Date: Sat, 13 Nov 2021 22:13:29 +0800 Subject: [PATCH 107/135] adminController.getUser & adminController.toggleAdmin --- controllers/adminController.js | 23 +++++++++++++- package-lock.json | 41 ++++++++++++++++++++++++- package.json | 4 ++- routes/index.js | 2 ++ views/admin/restaurants.handlebars | 9 +++++- views/admin/users.handlebars | 48 ++++++++++++++++++++++++++++++ 6 files changed, 123 insertions(+), 4 deletions(-) create mode 100644 views/admin/users.handlebars diff --git a/controllers/adminController.js b/controllers/adminController.js index 76273709..bc5803f6 100644 --- a/controllers/adminController.js +++ b/controllers/adminController.js @@ -3,6 +3,7 @@ const Restaurant = db.Restaurant const fs = require('fs') const imgur = require('imgur-node-api') const IMGUR_CLIENT_ID = process.env.IMGUR_CLIENT_ID +const User = db.User const adminController = { getRestaurants: (req, res) => { @@ -122,8 +123,28 @@ const adminController = { res.redirect('/admin/restaurants') }) }) - } + }, + + getUsers: (req, res) => { + return User.findAll({ raw: true }).then(users => { + return res.render('admin/users', { users: users }) + }) + }, + toggleAdmin: (req, res) => { + return User.findByPk(req.params.id).then((user) => { + const { isAdmin, email } = user.toJSON(); + if (email === "root@example.com") { + req.flash("error_messages", "禁止變更管理者權限"); + return res.redirect("back"); + } else { + user.update({ isAdmin: !isAdmin }).then((user) => { + req.flash("success_messages", "使用者權限變更成功"); + res.redirect("/admin/users"); + }); + } + }); + }, } module.exports = adminController \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 18ef08a5..a8f30725 100644 --- a/package-lock.json +++ b/package-lock.json @@ -808,6 +808,15 @@ "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==" }, + "fill-keys": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/fill-keys/-/fill-keys-1.0.2.tgz", + "integrity": "sha1-mo+jb06K1jTjv2tPPIiCVRRS6yA=", + "requires": { + "is-object": "~1.0.1", + "merge-descriptors": "~1.0.0" + } + }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -1090,6 +1099,11 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" }, + "is-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.2.tgz", + "integrity": "sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==" + }, "is-plain-obj": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", @@ -1374,6 +1388,11 @@ } } }, + "module-not-found-error": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/module-not-found-error/-/module-not-found-error-1.0.1.tgz", + "integrity": "sha1-z4tP9PKWQGdNbN0CsOO8UjwrvcA=" + }, "moment": { "version": "2.29.1", "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", @@ -1736,6 +1755,16 @@ "ipaddr.js": "1.9.1" } }, + "proxyquire": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/proxyquire/-/proxyquire-2.1.3.tgz", + "integrity": "sha512-BQWfCqYM+QINd+yawJz23tbBM40VIGXOdDw3X344KcclI/gtBbdWF6SlQ4nK/bYhF9d27KYug9WzljHC6B9Ysg==", + "requires": { + "fill-keys": "^1.0.2", + "module-not-found-error": "^1.0.1", + "resolve": "^1.11.1" + } + }, "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", @@ -1974,6 +2003,16 @@ "yargs": "^13.1.0" } }, + "sequelize-mock": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/sequelize-mock/-/sequelize-mock-0.10.2.tgz", + "integrity": "sha1-GdOXHM2utbhkFwwkznkqinHxRL0=", + "requires": { + "bluebird": "^3.4.6", + "inflection": "^1.10.0", + "lodash": "^4.16.4" + } + }, "sequelize-pool": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/sequelize-pool/-/sequelize-pool-6.1.0.tgz", @@ -2429,4 +2468,4 @@ } } } -} \ No newline at end of file +} diff --git a/package.json b/package.json index c541e707..0cda91e1 100644 --- a/package.json +++ b/package.json @@ -36,9 +36,11 @@ "passport": "^0.5.0", "passport-local": "^1.0.0", "pg": "^8.7.1", + "proxyquire": "^2.1.3", "sequelize": "^6.3.5", "sequelize-cli": "^6.2.0", + "sequelize-mock": "^0.10.2", "sinon": "^9.2.0", "supertest": "^5.0.0" } -} \ No newline at end of file +} diff --git a/routes/index.js b/routes/index.js index f227b22b..4c4b9147 100644 --- a/routes/index.js +++ b/routes/index.js @@ -37,6 +37,8 @@ module.exports = (app, passport) => { app.get('/admin/restaurants/:id/edit', authenticatedAdmin, adminController.editRestaurant) app.put('/admin/restaurants/:id', authenticatedAdmin, upload.single('image'), adminController.putRestaurant) app.delete('/admin/restaurants/:id', authenticatedAdmin, adminController.deleteRestaurant) + app.get('/admin/users', authenticatedAdmin, adminController.getUsers) + app.put('/admin/users/:id/toggleAdmin', authenticatedAdmin, adminController.toggleAdmin) app.get('/signup', userController.signUpPage) app.post('/signup', userController.signUp) diff --git a/views/admin/restaurants.handlebars b/views/admin/restaurants.handlebars index bb48b147..f4705e20 100644 --- a/views/admin/restaurants.handlebars +++ b/views/admin/restaurants.handlebars @@ -1,9 +1,16 @@

    餐廳後台

    +Restaurant + | +User +
    + - + + +

    diff --git a/views/admin/users.handlebars b/views/admin/users.handlebars new file mode 100644 index 00000000..0e303bfb --- /dev/null +++ b/views/admin/users.handlebars @@ -0,0 +1,48 @@ +

    餐廳後台

    + + +Restaurant + | +User + +
    +
    + + + + + + + + + + + + + + {{#each users}} + + + + + + > + + + + {{/each}} + +
    #NameEmailRole#
    {{this.id}}{{this.name}}{{this.email}} {{#if this.isAdmin}}admin{{else}}user{{/if}} + +
    + {{#if this.isAdmin}} + + {{else}} + + {{/if}} +
    +
    \ No newline at end of file From ac321f970eaae3338ee2b1cbb171818558c30cab Mon Sep 17 00:00:00 2001 From: area268457913 Date: Sun, 14 Nov 2021 12:05:53 +0800 Subject: [PATCH 108/135] ... --- config/config.json | 8 -------- 1 file changed, 8 deletions(-) diff --git a/config/config.json b/config/config.json index 6f8a7df8..3d08024f 100644 --- a/config/config.json +++ b/config/config.json @@ -6,14 +6,6 @@ "host": "127.0.0.1", "dialect": "mysql" }, - "test": { - "username": "root", - "password": "password", - "database": "forum_test", - "host": "127.0.0.1", - "dialect": "mysql", - "logging": false - }, "production": { "use_env_variable": "CLEARDB_DATABASE_URL" }, From 0503e531973baf118a27e9e469ca85ac3b20d760 Mon Sep 17 00:00:00 2001 From: area268457913 Date: Sun, 14 Nov 2021 12:21:35 +0800 Subject: [PATCH 109/135] ... --- config/config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/config.json b/config/config.json index 3d08024f..3b298c28 100644 --- a/config/config.json +++ b/config/config.json @@ -11,7 +11,7 @@ }, "travis": { "username": "travis", - "database": "forum_test", + "database": "forum", "host": "127.0.0.1", "dialect": "mysql", "logging": false From 390e073ff2132c7fd962e7cd2144ad06c2d7d2f2 Mon Sep 17 00:00:00 2001 From: area268457913 Date: Tue, 16 Nov 2021 02:35:05 +0800 Subject: [PATCH 110/135] Create category model & Add restaurant.CategoryId and association --- migrations/20211115180800-create-category.js | 27 +++++++++++++++++++ ...1115181845-add-categoryId-to-restaurant.js | 18 +++++++++++++ models/category.js | 18 +++++++++++++ models/restaurant.js | 5 +++- 4 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 migrations/20211115180800-create-category.js create mode 100644 migrations/20211115181845-add-categoryId-to-restaurant.js create mode 100644 models/category.js diff --git a/migrations/20211115180800-create-category.js b/migrations/20211115180800-create-category.js new file mode 100644 index 00000000..ab0ee89a --- /dev/null +++ b/migrations/20211115180800-create-category.js @@ -0,0 +1,27 @@ +'use strict'; +module.exports = { + up: async (queryInterface, Sequelize) => { + await queryInterface.createTable('Categories', { + id: { + allowNull: false, + autoIncrement: true, + primaryKey: true, + type: Sequelize.INTEGER + }, + name: { + type: Sequelize.STRING + }, + createdAt: { + allowNull: false, + type: Sequelize.DATE + }, + updatedAt: { + allowNull: false, + type: Sequelize.DATE + } + }); + }, + down: async (queryInterface, Sequelize) => { + await queryInterface.dropTable('Categories'); + } +}; \ No newline at end of file diff --git a/migrations/20211115181845-add-categoryId-to-restaurant.js b/migrations/20211115181845-add-categoryId-to-restaurant.js new file mode 100644 index 00000000..3cb7a30a --- /dev/null +++ b/migrations/20211115181845-add-categoryId-to-restaurant.js @@ -0,0 +1,18 @@ +'use strict' + +module.exports = { + up: async (queryInterface, Sequelize) => { + await queryInterface.addColumn('Restaurants', 'CategoryId', { + type: Sequelize.INTEGER, + allowNull: false, + references: { + model: 'Categories', + key: 'id' + } + }) + }, + + down: async (queryInterface, Sequelize) => { + await queryInterface.removeColumn('Restaurants', 'CategoryId') + } +} diff --git a/models/category.js b/models/category.js new file mode 100644 index 00000000..dfd3c793 --- /dev/null +++ b/models/category.js @@ -0,0 +1,18 @@ +'use strict' +const { + Model +} = require('sequelize') +module.exports = (sequelize, DataTypes) => { + class Category extends Model { + static associate(models) { + Category.hasMany(models.Restaurant) + } + }; + Category.init({ + name: DataTypes.STRING + }, { + sequelize, + modelName: 'Category' + }) + return Category +} \ No newline at end of file diff --git a/models/restaurant.js b/models/restaurant.js index bebed0be..fbb75e1b 100644 --- a/models/restaurant.js +++ b/models/restaurant.js @@ -11,6 +11,7 @@ module.exports = (sequelize, DataTypes) => { */ static associate(models) { // define association here + Restaurant.belongsTo(models.Category) // 加入關聯設定 } }; Restaurant.init({ @@ -19,7 +20,9 @@ module.exports = (sequelize, DataTypes) => { address: DataTypes.STRING, opening_hours: DataTypes.STRING, description: DataTypes.TEXT, - image: DataTypes.STRING + image: DataTypes.STRING, + CategoryId: DataTypes.INTEGER // 更新欄位清單 + }, { sequelize, From 5e8775eaf5863ba15a9abf2265fc00d2f3ffcf06 Mon Sep 17 00:00:00 2001 From: area268457913 Date: Tue, 16 Nov 2021 03:28:36 +0800 Subject: [PATCH 111/135] Add category seed data --- .../20211115192526-categories-seed-file.js | 20 +++++++++++++++++++ ...> 20211115192606-restaurants-seed-file.js} | 7 +++---- 2 files changed, 23 insertions(+), 4 deletions(-) create mode 100644 seeders/20211115192526-categories-seed-file.js rename seeders/{20211111191015-restaurants-seed-file.js => 20211115192606-restaurants-seed-file.js} (87%) diff --git a/seeders/20211115192526-categories-seed-file.js b/seeders/20211115192526-categories-seed-file.js new file mode 100644 index 00000000..846e6a50 --- /dev/null +++ b/seeders/20211115192526-categories-seed-file.js @@ -0,0 +1,20 @@ +'use strict' + +module.exports = { + up: async (queryInterface, Sequelize) => { + await queryInterface.bulkInsert('Categories', + ['中式料理', '日本料理', '義大利料理', '墨西哥料理', '素食料理', '美式料理', '複合式料理'] + .map((item, index) => + ({ + id: index * 10 + 1, + name: item, + createdAt: new Date(), + updatedAt: new Date() + }) + ), {}) + }, + + down: async (queryInterface, Sequelize) => { + await queryInterface.bulkDelete('Categories', null, {}) + } +} diff --git a/seeders/20211111191015-restaurants-seed-file.js b/seeders/20211115192606-restaurants-seed-file.js similarity index 87% rename from seeders/20211111191015-restaurants-seed-file.js rename to seeders/20211115192606-restaurants-seed-file.js index 3db3efb1..efe84379 100644 --- a/seeders/20211111191015-restaurants-seed-file.js +++ b/seeders/20211115192606-restaurants-seed-file.js @@ -1,6 +1,5 @@ 'use strict' const faker = require('faker') - module.exports = { up: async (queryInterface, Sequelize) => { await queryInterface.bulkInsert('Restaurants', @@ -13,12 +12,12 @@ module.exports = { image: `https://loremflickr.com/320/240/restaurant,food/?random=${Math.random() * 100}`, description: faker.lorem.text(), createdAt: new Date(), - updatedAt: new Date() + updatedAt: new Date(), + CategoryId: (Math.floor(Math.random() * 6)) * 10 + 1 }) ), {}) }, - down: async (queryInterface, Sequelize) => { await queryInterface.bulkDelete('Restaurants', null, {}) } -} \ No newline at end of file +}; From a984021642035a67b1881fe0be4522eca25d1385 Mon Sep 17 00:00:00 2001 From: area268457913 Date: Tue, 16 Nov 2021 03:59:41 +0800 Subject: [PATCH 112/135] Show category name on admin/restaurants & Show category name on admin/restaurant --- controllers/adminController.js | 15 ++++++++++++--- views/admin/restaurant.handlebars | 2 ++ views/admin/restaurants.handlebars | 2 ++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/controllers/adminController.js b/controllers/adminController.js index bc5803f6..aef57032 100644 --- a/controllers/adminController.js +++ b/controllers/adminController.js @@ -2,12 +2,20 @@ const db = require('../models') const Restaurant = db.Restaurant const fs = require('fs') const imgur = require('imgur-node-api') +const category = require('../models/category') const IMGUR_CLIENT_ID = process.env.IMGUR_CLIENT_ID const User = db.User +const Category = db.Category + const adminController = { getRestaurants: (req, res) => { - return Restaurant.findAll({ raw: true }).then(restaurants => { + return Restaurant.findAll({ + raw: true, + nest: true, + include: [Category] + }).then(restaurants => { + // console.log(restaurants) return res.render('admin/restaurants', { restaurants: restaurants }) }) }, @@ -54,10 +62,11 @@ const adminController = { } }, getRestaurant: (req, res) => { - return Restaurant.findByPk(req.params.id, { raw: true }).then( + return Restaurant.findByPk(req.params.id, { include: [Category] }).then( restaurant => { + console.log(restaurant) return res.render('admin/restaurant', { - restaurant: restaurant + restaurant: restaurant.toJSON() }) } ) diff --git a/views/admin/restaurant.handlebars b/views/admin/restaurant.handlebars index e6b1fa59..c2d43e91 100644 --- a/views/admin/restaurant.handlebars +++ b/views/admin/restaurant.handlebars @@ -1,6 +1,8 @@

    {{restaurant.name}}

    +

    [{{ restaurant.Category.name}}] +

    diff --git a/views/admin/restaurants.handlebars b/views/admin/restaurants.handlebars index f4705e20..59a36ea3 100644 --- a/views/admin/restaurants.handlebars +++ b/views/admin/restaurants.handlebars @@ -19,6 +19,7 @@ # Name + Category # @@ -27,6 +28,7 @@ {{this.id}} {{this.name}} + {{this.Category.name}}
    +
    + + +
    +
    From cec4721bc23532d3a154afb813d1bfd1f89ccd19 Mon Sep 17 00:00:00 2001 From: area268457913 Date: Tue, 16 Nov 2021 16:17:06 +0800 Subject: [PATCH 114/135] Update category select in edit page using ifCond-helper --- app.js | 5 ++++- config/handlebars-helpers.js | 8 ++++++++ views/admin/create.handlebars | 3 ++- 3 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 config/handlebars-helpers.js diff --git a/app.js b/app.js index db531443..0d83131e 100644 --- a/app.js +++ b/app.js @@ -16,7 +16,10 @@ const app = express() const port = process.env.PORT || 3000 -app.engine('handlebars', handlebars({ defaultLayout: 'main' })) // Handlebars 註冊樣板引擎 +app.engine('handlebars', handlebars({ + defaultLayout: 'main', + helpers: require('./config/handlebars-helpers') +})) // Handlebars 註冊樣板引擎 app.set('view engine', 'handlebars') // 設定使用 Handlebars 做為樣板引擎 app.use(express.urlencoded({ extended: true })) diff --git a/config/handlebars-helpers.js b/config/handlebars-helpers.js new file mode 100644 index 00000000..a90066a0 --- /dev/null +++ b/config/handlebars-helpers.js @@ -0,0 +1,8 @@ +module.exports = { + ifCond: function (a, b, options) { + if (a === b) { + return options.fn(this) + } + return options.inverse(this) + } +} \ No newline at end of file diff --git a/views/admin/create.handlebars b/views/admin/create.handlebars index a92f1e8b..2df45ef8 100644 --- a/views/admin/create.handlebars +++ b/views/admin/create.handlebars @@ -14,7 +14,8 @@
    From bee35a6da52fbac566fdb326bf776de3b382d1a9 Mon Sep 17 00:00:00 2001 From: area268457913 Date: Wed, 17 Nov 2021 02:09:26 +0800 Subject: [PATCH 115/135] Add admin categories page --- controllers/categoryController.js | 12 +++++++++ routes/index.js | 4 ++- views/admin/categories.handlebars | 43 ++++++++++++++++++++++++++++++ views/admin/restaurants.handlebars | 7 ++--- 4 files changed, 62 insertions(+), 4 deletions(-) create mode 100644 controllers/categoryController.js create mode 100644 views/admin/categories.handlebars diff --git a/controllers/categoryController.js b/controllers/categoryController.js new file mode 100644 index 00000000..03fbcba1 --- /dev/null +++ b/controllers/categoryController.js @@ -0,0 +1,12 @@ +const db = require('../models') +const Category = db.Category + +let categoryController = { + getCategories: (req, res) => { + return Category.findAll({ raw: true, nest: true }).then(categories => { + return res.render('admin/categories', { categories: categories }) + }) + } +} + +module.exports = categoryController \ No newline at end of file diff --git a/routes/index.js b/routes/index.js index 4c4b9147..0a7b65c0 100644 --- a/routes/index.js +++ b/routes/index.js @@ -1,6 +1,7 @@ const restController = require('../controllers/restController.js') const adminController = require('../controllers/adminController.js') const userController = require('../controllers/userController.js') +const categoryController = require('../controllers/categoryController.js') const { get } = require('superagent') const multer = require('multer') const upload = multer({ dest: 'temp/' }) @@ -47,5 +48,6 @@ module.exports = (app, passport) => { app.post('/signin', passport.authenticate('local', { failureRedirect: '/signin', failureFlash: true }), userController.signIn) app.get('/logout', userController.logout) - + // categories admin + app.get('/admin/categories', authenticatedAdmin, categoryController.getCategories) } \ No newline at end of file diff --git a/views/admin/categories.handlebars b/views/admin/categories.handlebars new file mode 100644 index 00000000..38403d36 --- /dev/null +++ b/views/admin/categories.handlebars @@ -0,0 +1,43 @@ +

    餐廳後台

    +
    Restaurants | +User | +Categories +
    +
    +
    +
    + + +
    +
    +
    +
    + + + + + + + + + + {{#each categories}} + + + + + + {{/each}} + +
    #Category Name#
    {{this.id}}{{this.name}} + +
    + +
    +
    +
    +
    \ No newline at end of file diff --git a/views/admin/restaurants.handlebars b/views/admin/restaurants.handlebars index 59a36ea3..ee4750a2 100644 --- a/views/admin/restaurants.handlebars +++ b/views/admin/restaurants.handlebars @@ -1,8 +1,9 @@

    餐廳後台

    -Restaurant - | -User +Restaurant | +User | +Categories +

    From b86876ac2a8a51529b21a9cdf2ce65475f8c1d86 Mon Sep 17 00:00:00 2001 From: area268457913 Date: Wed, 17 Nov 2021 02:22:48 +0800 Subject: [PATCH 116/135] Add admin categories post feature --- controllers/categoryController.js | 14 ++++++++++++++ routes/index.js | 1 + 2 files changed, 15 insertions(+) diff --git a/controllers/categoryController.js b/controllers/categoryController.js index 03fbcba1..67648c8f 100644 --- a/controllers/categoryController.js +++ b/controllers/categoryController.js @@ -6,6 +6,20 @@ let categoryController = { return Category.findAll({ raw: true, nest: true }).then(categories => { return res.render('admin/categories', { categories: categories }) }) + }, + postCategories: (req, res) => { + if (!req.body.name) { + req.flash('error_messages', 'name didn\'t exist') + return res.redirect('back') + } else { + return Category.create({ + name: req.body.name + }) + .then((category) => { + res.redirect('/admin/categories') + + }) + } } } diff --git a/routes/index.js b/routes/index.js index 0a7b65c0..b4e8a38c 100644 --- a/routes/index.js +++ b/routes/index.js @@ -50,4 +50,5 @@ module.exports = (app, passport) => { // categories admin app.get('/admin/categories', authenticatedAdmin, categoryController.getCategories) + app.post('/admin/categories', authenticatedAdmin, categoryController.postCategories) } \ No newline at end of file From f546890aa308e3187bd0c0e529129ee727452d04 Mon Sep 17 00:00:00 2001 From: area268457913 Date: Wed, 17 Nov 2021 02:44:11 +0800 Subject: [PATCH 117/135] Add admin categories edit and put feature --- controllers/categoryController.js | 32 ++++++++++++++++++++++++++++-- routes/index.js | 2 ++ views/admin/categories.handlebars | 11 +++++++++- views/admin/restaurants.handlebars | 4 ++-- views/admin/users.handlebars | 9 +++------ 5 files changed, 47 insertions(+), 11 deletions(-) diff --git a/controllers/categoryController.js b/controllers/categoryController.js index 67648c8f..9fb934f0 100644 --- a/controllers/categoryController.js +++ b/controllers/categoryController.js @@ -1,10 +1,24 @@ const db = require('../models') +const category = require('../models/category') const Category = db.Category let categoryController = { getCategories: (req, res) => { - return Category.findAll({ raw: true, nest: true }).then(categories => { - return res.render('admin/categories', { categories: categories }) + return Category.findAll({ + raw: true, + nest: true + }).then(categories => { + if (req.params.id) { + Category.findByPk(req.params.id) + .then((category) => { + return res.render('admin/categories', { + categories: categories, + category: category.toJSON() + }) + }) + } else { + return res.render('admin/categories', { categories: categories }) + } }) }, postCategories: (req, res) => { @@ -20,6 +34,20 @@ let categoryController = { }) } + }, + putCategory: (req, res) => { + if (!req.body.name) { + req.flash('error_messages', 'name didn\'t exist') + return res.redirect('back') + } else { + return Category.findByPk(req.params.id) + .then((category) => { + category.update(req.body) + .then((category) => { + res.redirect('/admin/categories') + }) + }) + } } } diff --git a/routes/index.js b/routes/index.js index b4e8a38c..4c83fdce 100644 --- a/routes/index.js +++ b/routes/index.js @@ -51,4 +51,6 @@ module.exports = (app, passport) => { // categories admin app.get('/admin/categories', authenticatedAdmin, categoryController.getCategories) app.post('/admin/categories', authenticatedAdmin, categoryController.postCategories) + app.get('/admin/categories/:id', authenticatedAdmin, categoryController.getCategories) + app.put('/admin/categories/:id', authenticatedAdmin, categoryController.putCategory) } \ No newline at end of file diff --git a/views/admin/categories.handlebars b/views/admin/categories.handlebars index 38403d36..da36dd91 100644 --- a/views/admin/categories.handlebars +++ b/views/admin/categories.handlebars @@ -1,15 +1,24 @@

    餐廳後台

    Restaurants | -User | +Users | Categories

    + {{#if category}} +
    + + + or Create New +
    + {{else}}
    + {{/if}}
    +

    diff --git a/views/admin/restaurants.handlebars b/views/admin/restaurants.handlebars index ee4750a2..05ad3afe 100644 --- a/views/admin/restaurants.handlebars +++ b/views/admin/restaurants.handlebars @@ -1,7 +1,7 @@

    餐廳後台

    -Restaurant | -User | +Restaurants | +Users | Categories

    diff --git a/views/admin/users.handlebars b/views/admin/users.handlebars index 0e303bfb..43e6908f 100644 --- a/views/admin/users.handlebars +++ b/views/admin/users.handlebars @@ -1,10 +1,7 @@

    餐廳後台

    - - -Restaurant - | -User - +Restaurants | +Users | +Categories

    From bce9c34c14759a721495a550f9543172cb7fb4ed Mon Sep 17 00:00:00 2001 From: area268457913 Date: Wed, 17 Nov 2021 02:51:39 +0800 Subject: [PATCH 118/135] Add admin categories delete feature --- controllers/categoryController.js | 8 ++++++++ routes/index.js | 1 + 2 files changed, 9 insertions(+) diff --git a/controllers/categoryController.js b/controllers/categoryController.js index 9fb934f0..de629466 100644 --- a/controllers/categoryController.js +++ b/controllers/categoryController.js @@ -48,6 +48,14 @@ let categoryController = { }) }) } + }, + deleteCategory: (req, res) => { + return Category.findByPk(req.params.id).then((category) => { + category.destroy() + .then((category) => { + res.redirect('/admin/categories') + }) + }) } } diff --git a/routes/index.js b/routes/index.js index 4c83fdce..1df3c633 100644 --- a/routes/index.js +++ b/routes/index.js @@ -53,4 +53,5 @@ module.exports = (app, passport) => { app.post('/admin/categories', authenticatedAdmin, categoryController.postCategories) app.get('/admin/categories/:id', authenticatedAdmin, categoryController.getCategories) app.put('/admin/categories/:id', authenticatedAdmin, categoryController.putCategory) + app.delete('/admin/categories/:id', authenticatedAdmin, categoryController.deleteCategory) } \ No newline at end of file From 5480a394cbf19d745540740dbfbb22b9fee8d34f Mon Sep 17 00:00:00 2001 From: area268457913 Date: Wed, 17 Nov 2021 03:33:15 +0800 Subject: [PATCH 119/135] Add restaurants index page --- controllers/restController.js | 18 +++++++++++++++++- views/restaurants.handlebars | 23 ++++++++++++++++++++--- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/controllers/restController.js b/controllers/restController.js index 3c0c76c6..694af823 100644 --- a/controllers/restController.js +++ b/controllers/restController.js @@ -1,6 +1,22 @@ +const db = require('../models') +const Restaurant = db.Restaurant +const Category = db.Category + + + const restController = { getRestaurants: (req, res) => { - return res.render('restaurants') + Restaurant.findAll({ include: Category }).then((restaurants) => { + const data = restaurants.map(r => ({ + ...r.dataValues, + // 複寫 description 內容,使內容控制在最多50字 + description: r.dataValues.description.substring(0, 50), + categoryName: r.Category.name + })) + return res.render('restaurants', { + restaurants: data + }) + }) } } module.exports = restController \ No newline at end of file diff --git a/views/restaurants.handlebars b/views/restaurants.handlebars index 97b6e76e..c4ea3538 100644 --- a/views/restaurants.handlebars +++ b/views/restaurants.handlebars @@ -1,3 +1,20 @@ -
    - restaurants -
    \ No newline at end of file +
    + {{#each restaurants}} +
    +
    + Card image cap +
    +

    + + {{this.name}} + +

    + {{this.categoryName}} +

    {{this.description}}

    +
    +
    +
    + {{/each}} +
    +
    +
    \ No newline at end of file From b23ab88aa719f5f47957afbe4a0c1aaa88a6683f Mon Sep 17 00:00:00 2001 From: area268457913 Date: Wed, 17 Nov 2021 14:54:56 +0800 Subject: [PATCH 120/135] Add restaurants show page --- controllers/restController.js | 5 +++++ routes/index.js | 4 ++++ views/restaurant.handlebars | 23 +++++++++++++++++++++++ 3 files changed, 32 insertions(+) create mode 100644 views/restaurant.handlebars diff --git a/controllers/restController.js b/controllers/restController.js index 694af823..8871885b 100644 --- a/controllers/restController.js +++ b/controllers/restController.js @@ -17,6 +17,11 @@ const restController = { restaurants: data }) }) + }, + getRestaurant: (req, res) => { + return Restaurant.findByPk(req.params.id, { include: Category }).then( + restaurant => { return res.render('restaurant', { restaurant: restaurant.toJSON() }) } + ) } } module.exports = restController \ No newline at end of file diff --git a/routes/index.js b/routes/index.js index 1df3c633..f082992c 100644 --- a/routes/index.js +++ b/routes/index.js @@ -28,6 +28,10 @@ module.exports = (app, passport) => { app.get('/', authenticated, (req, res) => res.redirect('/restaurants')) //在 /restaurants 底下則交給 restController.getRestaurants 來處理 app.get('/restaurants', authenticated, restController.getRestaurants) + app.get('/restaurants/:id', authenticated, restController.getRestaurant) + + + // 連到 /admin 頁面就轉到 /admin/restaurants app.get('/admin', authenticatedAdmin, (req, res) => res.redirect('/admin/restaurants')) // 在 /admin/restaurants 底下則交給 adminController.getRestaurants 處理 diff --git a/views/restaurant.handlebars b/views/restaurant.handlebars new file mode 100644 index 00000000..67543990 --- /dev/null +++ b/views/restaurant.handlebars @@ -0,0 +1,23 @@ +
    +
    +

    {{restaurant.name}}

    +

    [{{restaurant.Category.name}}]

    +
    +
    + +
    +
      +
    • Opening Hour: {{restaurant.opening_hours}}
    • +
    • Tel: {{restaurant.tel}}
    • +
    • Address: {{restaurant.address}}
    • +
    +
    +
    +
    +

    {{restaurant.description}}

    +
    +
    +
    +
    +
    +回上一頁 \ No newline at end of file From 1fdff6724cd1ab9559e08fbd59263011ed56fc3d Mon Sep 17 00:00:00 2001 From: area268457913 Date: Wed, 17 Nov 2021 15:39:27 +0800 Subject: [PATCH 121/135] Add categories navbar on restaurants index page --- controllers/restController.js | 20 +++++++++++++++++--- views/restaurants.handlebars | 14 ++++++++++++++ 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/controllers/restController.js b/controllers/restController.js index 8871885b..c8fcd287 100644 --- a/controllers/restController.js +++ b/controllers/restController.js @@ -6,15 +6,29 @@ const Category = db.Category const restController = { getRestaurants: (req, res) => { - Restaurant.findAll({ include: Category }).then((restaurants) => { + const whereQuery = {} + let categoryId = '' + if (req.query.categoryId) { + categoryId = Number(req.query.categoryId) + whereQuery.CategoryId = categoryId + } + Restaurant.findAll({ include: Category, where: whereQuery }).then((restaurants) => { const data = restaurants.map(r => ({ ...r.dataValues, // 複寫 description 內容,使內容控制在最多50字 description: r.dataValues.description.substring(0, 50), categoryName: r.Category.name })) - return res.render('restaurants', { - restaurants: data + Category.findAll({ + raw: true, + nest: true + }).then(categories => { + // 取出 categoies + return res.render('restaurants', { + restaurants: data, + categories: categories, + categoryId: categoryId + }) }) }) }, diff --git a/views/restaurants.handlebars b/views/restaurants.handlebars index c4ea3538..04a5dc88 100644 --- a/views/restaurants.handlebars +++ b/views/restaurants.handlebars @@ -1,3 +1,17 @@ + +
    +
    {{#each restaurants}}
    From 959fffa12fad70f468d83ed143e061178b3304c5 Mon Sep 17 00:00:00 2001 From: area268457913 Date: Thu, 18 Nov 2021 02:37:31 +0800 Subject: [PATCH 122/135] Add pagination on restaurants index --- controllers/restController.js | 32 ++++++++++++++++++++++++++------ views/restaurants.handlebars | 25 ++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 7 deletions(-) diff --git a/controllers/restController.js b/controllers/restController.js index c8fcd287..5633f281 100644 --- a/controllers/restController.js +++ b/controllers/restController.js @@ -1,33 +1,53 @@ const db = require('../models') const Restaurant = db.Restaurant const Category = db.Category +const pageLimit = 10 const restController = { getRestaurants: (req, res) => { + let offset = 0 const whereQuery = {} let categoryId = '' + if (req.query.page) { + offset = (req.query.page - 1) * pageLimit + } if (req.query.categoryId) { categoryId = Number(req.query.categoryId) whereQuery.CategoryId = categoryId } - Restaurant.findAll({ include: Category, where: whereQuery }).then((restaurants) => { - const data = restaurants.map(r => ({ + Restaurant.findAndCountAll({ + include: Category, + where: whereQuery, + offset: offset, + limit: pageLimit + }).then((result) => { + // data for pagination + const page = Number(req.query.page) || 1 + const pages = Math.ceil(result.count / pageLimit) + const totalPage = Array.from({ length: pages }).map((item, index) => index + 1) + const prev = page - 1 < 1 ? 1 : page - 1 + const next = page + 1 > pages ? pages : page + 1 + + // clean up restaurant data + const data = result.rows.map(r => ({ ...r.dataValues, - // 複寫 description 內容,使內容控制在最多50字 description: r.dataValues.description.substring(0, 50), - categoryName: r.Category.name + categoryName: r.dataValues.Category.name })) Category.findAll({ raw: true, nest: true }).then(categories => { - // 取出 categoies return res.render('restaurants', { restaurants: data, categories: categories, - categoryId: categoryId + categoryId: categoryId, + page: page, + totalPage: totalPage, + prev: prev, + next: next }) }) }) diff --git a/views/restaurants.handlebars b/views/restaurants.handlebars index 04a5dc88..6a4e9527 100644 --- a/views/restaurants.handlebars +++ b/views/restaurants.handlebars @@ -31,4 +31,27 @@ {{/each}}

    -
    \ No newline at end of file +
    + + \ No newline at end of file From 16e160e328791d4c48ccd9eb64ab8b06d2b72037 Mon Sep 17 00:00:00 2001 From: area268457913 Date: Thu, 18 Nov 2021 03:07:52 +0800 Subject: [PATCH 123/135] Create comment model & add association among users, comment, restaurants --- migrations/20211117190223-create-comment.js | 33 +++++++++++++++++++++ models/comment.js | 27 +++++++++++++++++ models/restaurant.js | 1 + models/user.js | 1 + 4 files changed, 62 insertions(+) create mode 100644 migrations/20211117190223-create-comment.js create mode 100644 models/comment.js diff --git a/migrations/20211117190223-create-comment.js b/migrations/20211117190223-create-comment.js new file mode 100644 index 00000000..8e42b57c --- /dev/null +++ b/migrations/20211117190223-create-comment.js @@ -0,0 +1,33 @@ +'use strict'; +module.exports = { + up: async (queryInterface, Sequelize) => { + await queryInterface.createTable('Comments', { + id: { + allowNull: false, + autoIncrement: true, + primaryKey: true, + type: Sequelize.INTEGER + }, + text: { + type: Sequelize.STRING + }, + UserId: { + type: Sequelize.INTEGER + }, + RestaurantId: { + type: Sequelize.INTEGER + }, + createdAt: { + allowNull: false, + type: Sequelize.DATE + }, + updatedAt: { + allowNull: false, + type: Sequelize.DATE + } + }); + }, + down: async (queryInterface, Sequelize) => { + await queryInterface.dropTable('Comments'); + } +}; \ No newline at end of file diff --git a/models/comment.js b/models/comment.js new file mode 100644 index 00000000..fea7e034 --- /dev/null +++ b/models/comment.js @@ -0,0 +1,27 @@ +'use strict'; +const { + Model +} = require('sequelize'); +module.exports = (sequelize, DataTypes) => { + class Comment extends Model { + /** + * Helper method for defining associations. + * This method is not a part of Sequelize lifecycle. + * The `models/index` file will call this method automatically. + */ + static associate(models) { + // define association here + Comment.belongsTo(models.Restaurant) + Comment.belongsTo(models.User) + } + }; + Comment.init({ + text: DataTypes.STRING, + UserId: DataTypes.INTEGER, + RestaurantId: DataTypes.INTEGER + }, { + sequelize, + modelName: 'Comment', + }); + return Comment; +}; \ No newline at end of file diff --git a/models/restaurant.js b/models/restaurant.js index fbb75e1b..bf39aa68 100644 --- a/models/restaurant.js +++ b/models/restaurant.js @@ -12,6 +12,7 @@ module.exports = (sequelize, DataTypes) => { static associate(models) { // define association here Restaurant.belongsTo(models.Category) // 加入關聯設定 + Restaurant.hasMany(models.Comment) } }; Restaurant.init({ diff --git a/models/user.js b/models/user.js index abe49066..38b3143a 100644 --- a/models/user.js +++ b/models/user.js @@ -11,6 +11,7 @@ module.exports = (sequelize, DataTypes) => { */ static associate(models) { // define association here + User.hasMany(models.Comment) } }; User.init({ From 7b9cd249684069dae9211b07fcd9e8442894cf78 Mon Sep 17 00:00:00 2001 From: area268457913 Date: Thu, 18 Nov 2021 03:24:25 +0800 Subject: [PATCH 124/135] Add post comment feature on restaurant page --- controllers/commentController.js | 16 ++++++++++++++++ routes/index.js | 5 +++++ views/restaurant.handlebars | 8 ++++++++ 3 files changed, 29 insertions(+) create mode 100644 controllers/commentController.js diff --git a/controllers/commentController.js b/controllers/commentController.js new file mode 100644 index 00000000..21688fe9 --- /dev/null +++ b/controllers/commentController.js @@ -0,0 +1,16 @@ +const db = require('../models') +const Comment = db.Comment + +const commentController = { + postComment: (req, res) => { + return Comment.create({ + text: req.body.text, + RestaurantId: req.body.restaurantId, + UserId: req.user.id + }).then((comment) => { + res.redirect(`/restaurants/${req.body.restaurantId}`) + }) + } +} + +module.exports = commentController \ No newline at end of file diff --git a/routes/index.js b/routes/index.js index f082992c..e58c40bf 100644 --- a/routes/index.js +++ b/routes/index.js @@ -2,6 +2,7 @@ const restController = require('../controllers/restController.js') const adminController = require('../controllers/adminController.js') const userController = require('../controllers/userController.js') const categoryController = require('../controllers/categoryController.js') +const commentController = require('../controllers/commentController.js') const { get } = require('superagent') const multer = require('multer') const upload = multer({ dest: 'temp/' }) @@ -58,4 +59,8 @@ module.exports = (app, passport) => { app.get('/admin/categories/:id', authenticatedAdmin, categoryController.getCategories) app.put('/admin/categories/:id', authenticatedAdmin, categoryController.putCategory) app.delete('/admin/categories/:id', authenticatedAdmin, categoryController.deleteCategory) + + // comment + + app.post('/comments', authenticated, commentController.postComment) } \ No newline at end of file diff --git a/views/restaurant.handlebars b/views/restaurant.handlebars index 67543990..7682c076 100644 --- a/views/restaurant.handlebars +++ b/views/restaurant.handlebars @@ -20,4 +20,12 @@


    +
    +
    + + +
    + + + 回上一頁 \ No newline at end of file From 0f516e66f94d9f3c9e334dbe081c2ed6de008b66 Mon Sep 17 00:00:00 2001 From: area268457913 Date: Thu, 18 Nov 2021 03:36:03 +0800 Subject: [PATCH 125/135] Show related comments on restaurant page & Convert time format using moment --- config/handlebars-helpers.js | 6 ++++++ controllers/restController.js | 17 +++++++++++++---- package.json | 1 + views/restaurant.handlebars | 11 +++++++++++ 4 files changed, 31 insertions(+), 4 deletions(-) diff --git a/config/handlebars-helpers.js b/config/handlebars-helpers.js index a90066a0..4e956036 100644 --- a/config/handlebars-helpers.js +++ b/config/handlebars-helpers.js @@ -1,8 +1,14 @@ +const moment = require('moment') + + module.exports = { ifCond: function (a, b, options) { if (a === b) { return options.fn(this) } return options.inverse(this) + }, + moment: function (a) { + return moment(a).fromNow() } } \ No newline at end of file diff --git a/controllers/restController.js b/controllers/restController.js index 5633f281..7bf88fb9 100644 --- a/controllers/restController.js +++ b/controllers/restController.js @@ -2,7 +2,8 @@ const db = require('../models') const Restaurant = db.Restaurant const Category = db.Category const pageLimit = 10 - +const Comment = db.Comment +const User = db.User const restController = { @@ -53,9 +54,17 @@ const restController = { }) }, getRestaurant: (req, res) => { - return Restaurant.findByPk(req.params.id, { include: Category }).then( - restaurant => { return res.render('restaurant', { restaurant: restaurant.toJSON() }) } - ) + return Restaurant.findByPk(req.params.id, { + include: [ + Category, + { model: Comment, include: [User] } + ] + }).then(restaurant => { + console.log(restaurant.Comments[0].dataValues) + return res.render('restaurant', { + restaurant: restaurant.toJSON(), + }) + }) } } module.exports = restController \ No newline at end of file diff --git a/package.json b/package.json index 0cda91e1..cbc40f87 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "imgur-node-api": "^0.1.0", "method-override": "^3.0.0", "mocha": "^8.2.0", + "moment": "^2.29.1", "multer": "^1.4.3", "mysql2": "^2.2.5", "passport": "^0.5.0", diff --git a/views/restaurant.handlebars b/views/restaurant.handlebars index 7682c076..dc5003e3 100644 --- a/views/restaurant.handlebars +++ b/views/restaurant.handlebars @@ -20,6 +20,17 @@

    +

    +

    所有評論:

    +{{#each restaurant.Comments}} +
    +

    {{this.User.name}}

    +

    {{this.text}}

    +
    {{moment this.createdAt}} +
    +
    +
    +{{/each}}
    From 0bb34552dc7220a100d62e80f84c48962c54d204 Mon Sep 17 00:00:00 2001 From: area268457913 Date: Thu, 18 Nov 2021 03:48:23 +0800 Subject: [PATCH 126/135] Add delete comment feature for admin --- controllers/commentController.js | 9 +++++++++ routes/index.js | 2 ++ views/restaurant.handlebars | 10 +++++++++- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/controllers/commentController.js b/controllers/commentController.js index 21688fe9..e74b1a34 100644 --- a/controllers/commentController.js +++ b/controllers/commentController.js @@ -10,6 +10,15 @@ const commentController = { }).then((comment) => { res.redirect(`/restaurants/${req.body.restaurantId}`) }) + }, + deleteComment: (req, res) => { + return Comment.findByPk(req.params.id) + .then((comment) => { + comment.destroy() + .then((comment) => { + res.redirect(`/restaurants/${comment.RestaurantId}`) + }) + }) } } diff --git a/routes/index.js b/routes/index.js index e58c40bf..cd738b85 100644 --- a/routes/index.js +++ b/routes/index.js @@ -63,4 +63,6 @@ module.exports = (app, passport) => { // comment app.post('/comments', authenticated, commentController.postComment) + app.delete('/comments/:id', authenticatedAdmin, commentController.deleteComment) + } \ No newline at end of file diff --git a/views/restaurant.handlebars b/views/restaurant.handlebars index dc5003e3..0277a9ec 100644 --- a/views/restaurant.handlebars +++ b/views/restaurant.handlebars @@ -20,9 +20,13 @@


    -

    所有評論:

    {{#each restaurant.Comments}} +{{#if ../user.isAdmin}} + + + +{{/if}}

    {{this.User.name}}

    {{this.text}}

    @@ -31,6 +35,8 @@

    {{/each}} +

    +
    @@ -39,4 +45,6 @@ +

    + 回上一頁 \ No newline at end of file From 5b37329b245c280382df16678ba5c17941c38ba9 Mon Sep 17 00:00:00 2001 From: area268457913 Date: Sat, 20 Nov 2021 15:49:32 +0800 Subject: [PATCH 127/135] create profile page --- controllers/userController.js | 60 ++++++++++++++++++- .../20211118071339-add-image-to-user.js | 14 +++++ models/user.js | 4 +- package-lock.json | 6 +- package.json | 2 +- routes/index.js | 5 ++ views/edit.handlebars | 18 ++++++ views/profile.handlebars | 11 ++++ 8 files changed, 114 insertions(+), 6 deletions(-) create mode 100644 migrations/20211118071339-add-image-to-user.js create mode 100644 views/edit.handlebars create mode 100644 views/profile.handlebars diff --git a/controllers/userController.js b/controllers/userController.js index a93a1510..e93e671d 100644 --- a/controllers/userController.js +++ b/controllers/userController.js @@ -1,6 +1,9 @@ const bcrypt = require('bcryptjs') const db = require('../models') const User = db.User //存取到之前建立的User model +const imgur = require('imgur-node-api') +const IMGUR_CLIENT_ID = process.env.IMGUR_CLIENT_ID + const userController = { signUpPage: (req, res) => { @@ -45,8 +48,63 @@ const userController = { req.flash('success_messages', '登出成功!') req.logout() res.redirect('/signin') - } + }, + + getUser: (req, res) => { + return User.findByPk(req.params.id).then((user) => { + res.render('profile', { user: user.toJSON() }) + }) + }, + editUser: (req, res) => { + return User.findByPk(req.params.id).then( + user => { + return res.render('edit', { user: user.toJSON() }) + } + ) + }, + putUser: (req, res) => { + + if (!req.body.name || !req.body.email) { + req.flash('error_messages', "name or email didn't exist") + return res.redirect('back') + + } + const { file } = req + if (file) { + imgur.setClientID(IMGUR_CLIENT_ID); + imgur.upload(file.path, (err, img) => { + return User.findByPk(req.params.id).then((user) => { + user.update({ + name: req.body.name, + email: req.body.email, + image: file ? img.data.link : user.image, + }) + .then((user) => { + req.flash('success_messages', '使用者資料編輯成功') + res.redirect(`/users/${req.params.id}`) + }) + }) + }) + + } else { + return User.findByPk(req.params.id).then((user) => { + user.update({ + name: req.body.name, + email: req.body.email, + image: user.image + + }) + .then((user) => { + req.flash('success_messages', '使用者資料編輯成功') + res.redirect(`/users/${req.params.id}`) + }) + }) + + } + + } } + module.exports = userController \ No newline at end of file diff --git a/migrations/20211118071339-add-image-to-user.js b/migrations/20211118071339-add-image-to-user.js new file mode 100644 index 00000000..1acc1f54 --- /dev/null +++ b/migrations/20211118071339-add-image-to-user.js @@ -0,0 +1,14 @@ +'use strict' + +module.exports = { + up: async (queryInterface, Sequelize) => { + await queryInterface.addColumn('Users', 'image', { + type: Sequelize.STRING, + + }) + }, + + down: async (queryInterface, Sequelize) => { + await queryInterface.removeColumn('Users', 'image') + } +} \ No newline at end of file diff --git a/models/user.js b/models/user.js index 38b3143a..bcdcc869 100644 --- a/models/user.js +++ b/models/user.js @@ -18,7 +18,9 @@ module.exports = (sequelize, DataTypes) => { name: DataTypes.STRING, email: DataTypes.STRING, password: DataTypes.STRING, - isAdmin: DataTypes.BOOLEAN + isAdmin: DataTypes.BOOLEAN, + image: DataTypes.STRING + }, { sequelize, modelName: 'User', diff --git a/package-lock.json b/package-lock.json index 106bb3ab..b5d4e437 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { - "name": "forum-express-workspace", - "version": "1.0.0", + "name": "forum-express-grading", + "version": "2.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -2468,4 +2468,4 @@ } } } -} \ No newline at end of file +} diff --git a/package.json b/package.json index 5fd95e91..55ace577 100644 --- a/package.json +++ b/package.json @@ -37,4 +37,4 @@ "sinon": "^9.2.0", "supertest": "^5.0.0" } -} \ No newline at end of file +} diff --git a/routes/index.js b/routes/index.js index cd738b85..effc131a 100644 --- a/routes/index.js +++ b/routes/index.js @@ -65,4 +65,9 @@ module.exports = (app, passport) => { app.post('/comments', authenticated, commentController.postComment) app.delete('/comments/:id', authenticatedAdmin, commentController.deleteComment) + // profile + + app.get('/users/:id', authenticated, userController.getUser) + app.get('/users/:id/edit', authenticated, userController.editUser) + app.put('/users/:id', authenticated, upload.single('image'), userController.putUser) } \ No newline at end of file diff --git a/views/edit.handlebars b/views/edit.handlebars new file mode 100644 index 00000000..29578469 --- /dev/null +++ b/views/edit.handlebars @@ -0,0 +1,18 @@ +
    +
    + + +
    + +
    + + +
    + +
    + + +
    + + + \ No newline at end of file diff --git a/views/profile.handlebars b/views/profile.handlebars new file mode 100644 index 00000000..24798aef --- /dev/null +++ b/views/profile.handlebars @@ -0,0 +1,11 @@ +
    +
    +
    + +
    +

    {{user.name}}

    +

    {{user.email}}

    + edit +
    +
    +
    \ No newline at end of file From db4e0b95e979c1f75f30c89e85560d1125a014a8 Mon Sep 17 00:00:00 2001 From: area268457913 Date: Sat, 20 Nov 2021 20:47:32 +0800 Subject: [PATCH 128/135] add update profile & seed --- controllers/restController.js | 2 +- controllers/userController.js | 22 +++++++++++++++++-- seeders/20211111180715-users-seed-file.js | 3 +++ .../20211115192606-restaurants-seed-file.js | 1 + seeders/20211120120220-comments-seed-file.js | 21 ++++++++++++++++++ views/profile.handlebars | 16 ++++++++++++++ 6 files changed, 62 insertions(+), 3 deletions(-) create mode 100644 seeders/20211120120220-comments-seed-file.js diff --git a/controllers/restController.js b/controllers/restController.js index 7bf88fb9..ca9ac2e3 100644 --- a/controllers/restController.js +++ b/controllers/restController.js @@ -60,7 +60,7 @@ const restController = { { model: Comment, include: [User] } ] }).then(restaurant => { - console.log(restaurant.Comments[0].dataValues) + // console.log(restaurant.Comments[0].dataValues) return res.render('restaurant', { restaurant: restaurant.toJSON(), }) diff --git a/controllers/userController.js b/controllers/userController.js index e93e671d..bf55f04c 100644 --- a/controllers/userController.js +++ b/controllers/userController.js @@ -1,11 +1,14 @@ const bcrypt = require('bcryptjs') const db = require('../models') const User = db.User //存取到之前建立的User model +const Restaurant = db.Restaurant +const Comment = db.Comment const imgur = require('imgur-node-api') const IMGUR_CLIENT_ID = process.env.IMGUR_CLIENT_ID const userController = { + signUpPage: (req, res) => { return res.render('signup') }, @@ -51,11 +54,25 @@ const userController = { }, getUser: (req, res) => { - return User.findByPk(req.params.id).then((user) => { - res.render('profile', { user: user.toJSON() }) + + return User.findByPk(req.params.id, { + include: [ + { model: Comment, include: [Restaurant] } + ] + }).then((user) => { + // console.log(user.toJSON().Comments) + const comment = user.toJSON().Comments + res.render('profile', { user: user.toJSON(), comment }) + }) }, editUser: (req, res) => { + + if (Number(req.params.id) !== req.user.id) { + req.flash('error_messages', "只能修改自己資料") + return res.redirect('back') + } + return User.findByPk(req.params.id).then( user => { return res.render('edit', { user: user.toJSON() }) @@ -70,6 +87,7 @@ const userController = { return res.redirect('back') } + const { file } = req if (file) { imgur.setClientID(IMGUR_CLIENT_ID); diff --git a/seeders/20211111180715-users-seed-file.js b/seeders/20211111180715-users-seed-file.js index be1f6ff7..cb31a38a 100644 --- a/seeders/20211111180715-users-seed-file.js +++ b/seeders/20211111180715-users-seed-file.js @@ -3,6 +3,7 @@ const bcrypt = require('bcryptjs') module.exports = { up: async (queryInterface, Sequelize) => { await queryInterface.bulkInsert('Users', [{ + id: 1, email: 'root@example.com', password: bcrypt.hashSync('12345678', bcrypt.genSaltSync(10), null), isAdmin: true, @@ -10,6 +11,7 @@ module.exports = { createdAt: new Date(), updatedAt: new Date() }, { + id: 2, email: 'user1@example.com', password: bcrypt.hashSync('12345678', bcrypt.genSaltSync(10), null), isAdmin: false, @@ -17,6 +19,7 @@ module.exports = { createdAt: new Date(), updatedAt: new Date() }, { + id: 3, email: 'user2@example.com', password: bcrypt.hashSync('12345678', bcrypt.genSaltSync(10), null), isAdmin: false, diff --git a/seeders/20211115192606-restaurants-seed-file.js b/seeders/20211115192606-restaurants-seed-file.js index efe84379..ef9d9ff5 100644 --- a/seeders/20211115192606-restaurants-seed-file.js +++ b/seeders/20211115192606-restaurants-seed-file.js @@ -5,6 +5,7 @@ module.exports = { await queryInterface.bulkInsert('Restaurants', Array.from({ length: 50 }).map((d, i) => ({ + id: i * 10 + 1, name: faker.name.findName(), tel: faker.phone.phoneNumber(), address: faker.address.streetAddress(), diff --git a/seeders/20211120120220-comments-seed-file.js b/seeders/20211120120220-comments-seed-file.js new file mode 100644 index 00000000..5fd354c6 --- /dev/null +++ b/seeders/20211120120220-comments-seed-file.js @@ -0,0 +1,21 @@ +'use strict' +const faker = require('faker') + +module.exports = { + up: async (queryInterface, Sequelize) => { + await queryInterface.bulkInsert('Comments', + Array.from({ length: 10 }).map((d, i) => + ({ + text: faker.name.findName(), + createdAt: new Date(), + updatedAt: new Date(), + UserId: (Math.floor(Math.random() * 3)) + 1, + RestaurantId: (Math.floor(Math.random() * 10)) * 10 + 1, + }) + ), {}) + }, + + down: async (queryInterface, Sequelize) => { + await queryInterface.bulkDelete('Comments', null, {}) + } +} \ No newline at end of file diff --git a/views/profile.handlebars b/views/profile.handlebars index 24798aef..a73ecdd2 100644 --- a/views/profile.handlebars +++ b/views/profile.handlebars @@ -5,7 +5,23 @@

    {{user.name}}

    {{user.email}}

    +

    {{comment.length}} 已評論餐廳

    edit
    +
    +
    +
    + {{comment.length}} 已評論餐廳 +
    +
    + {{#each comment}} + + + {{/each}} +
    \ No newline at end of file From 4e100709de54550b7b8ed8ef85c78f3e78cfd685 Mon Sep 17 00:00:00 2001 From: area268457913 Date: Sat, 20 Nov 2021 21:24:00 +0800 Subject: [PATCH 129/135] update editUser --- controllers/userController.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/controllers/userController.js b/controllers/userController.js index bf55f04c..4bb0cd7c 100644 --- a/controllers/userController.js +++ b/controllers/userController.js @@ -3,6 +3,7 @@ const db = require('../models') const User = db.User //存取到之前建立的User model const Restaurant = db.Restaurant const Comment = db.Comment +const helpers = require('../_helpers') const imgur = require('imgur-node-api') const IMGUR_CLIENT_ID = process.env.IMGUR_CLIENT_ID @@ -68,7 +69,7 @@ const userController = { }, editUser: (req, res) => { - if (Number(req.params.id) !== req.user.id) { + if (Number(req.params.id) !== helpers.getUser(req).id) { req.flash('error_messages', "只能修改自己資料") return res.redirect('back') } @@ -82,6 +83,8 @@ const userController = { putUser: (req, res) => { + + if (!req.body.name || !req.body.email) { req.flash('error_messages', "name or email didn't exist") return res.redirect('back') From 45211eafcefa30c0424e7e4c56dc7af4db7e406b Mon Sep 17 00:00:00 2001 From: area268457913 Date: Sun, 21 Nov 2021 02:25:39 +0800 Subject: [PATCH 130/135] Add feeds page & Update getFeeds to Promise.all --- controllers/restController.js | 43 ++++++++++++++++++++++++++++ routes/index.js | 1 + views/feeds.handlebars | 53 +++++++++++++++++++++++++++++++++++ views/restaurants.handlebars | 10 +++++++ 4 files changed, 107 insertions(+) create mode 100644 views/feeds.handlebars diff --git a/controllers/restController.js b/controllers/restController.js index ca9ac2e3..b2aa64d5 100644 --- a/controllers/restController.js +++ b/controllers/restController.js @@ -65,6 +65,49 @@ const restController = { restaurant: restaurant.toJSON(), }) }) + }, + + // getFeeds: (req, res) => { + // return Restaurant.findAll({ + // limit: 10, + // raw: true, + // nest: true, + // order: [['createdAt', 'DESC']], + // include: [Category] + // }).then((restaurants) => { + // return Comment.findAll({ + // limit: 10, + // raw: true, + // nest: true, + // order: [['createdAt', 'DESC']], + // include: [User, Restaurant] + // }).then((comments) => { + // return res.render('feeds', { restaurants, comments }) + // }) + // }) + // } + + // Promise.all 寫法 + getFeeds: (req, res) => { + return Promise.all([ + Restaurant.findAll({ + limit: 10, + raw: true, + nest: true, + order: [['createdAt', 'DESC']], + include: [Category] + }), + Comment.findAll({ + limit: 10, + raw: true, + nest: true, + order: [['createdAt', 'DESC']], + include: [User, Restaurant] + }) + ]).then(([restaurants, comments]) => { + return res.render('feeds', { restaurants, comments }) + }) } + } module.exports = restController \ No newline at end of file diff --git a/routes/index.js b/routes/index.js index effc131a..b0b04be0 100644 --- a/routes/index.js +++ b/routes/index.js @@ -29,6 +29,7 @@ module.exports = (app, passport) => { app.get('/', authenticated, (req, res) => res.redirect('/restaurants')) //在 /restaurants 底下則交給 restController.getRestaurants 來處理 app.get('/restaurants', authenticated, restController.getRestaurants) + app.get('/restaurants/feeds', authenticated, restController.getFeeds) app.get('/restaurants/:id', authenticated, restController.getRestaurant) diff --git a/views/feeds.handlebars b/views/feeds.handlebars new file mode 100644 index 00000000..89dc70ad --- /dev/null +++ b/views/feeds.handlebars @@ -0,0 +1,53 @@ + +

    +

    最新動態

    +
    +
    +
    +
    +
    + 最新餐廳 +
    +
    + {{#each restaurants}} +
    +

    + {{this.name}} + {{this.Category.name}} +

    +

    {{this.description}}

    + {{moment this.createdAt}} +
    +
    + {{/each}} +
    +
    +
    +
    +
    +
    + 最新評論 +
    +
    + {{#each comments}} +
    +

    + {{this.Restaurant.name}} +

    +

    {{this.text}}

    + by {{this.User.name}} + at {{moment this.createdAt}} +
    +
    + {{/each}} +
    +
    +
    +
    \ No newline at end of file diff --git a/views/restaurants.handlebars b/views/restaurants.handlebars index 6a4e9527..94d5fc05 100644 --- a/views/restaurants.handlebars +++ b/views/restaurants.handlebars @@ -1,3 +1,13 @@ + +
    +