diff --git a/database/auracle_db_create.sql b/database/auracle_db_create.sql index f36cf18..9e5d75e 100644 --- a/database/auracle_db_create.sql +++ b/database/auracle_db_create.sql @@ -29,15 +29,16 @@ CREATE TABLE IF NOT EXISTS `school` ( `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, `name` VARCHAR(255) NOT NULL DEFAULT "Nom de l'école", `description` VARCHAR(255) DEFAULT "Description de l'école", - `id_meta_school` INT UNSIGNED NOT NULL, + `meta_school_id` INT UNSIGNED NOT NULL, PRIMARY KEY (`id`), - FOREIGN KEY(`id_meta_school`) REFERENCES meta_school(`id`) + FOREIGN KEY(`meta_school_id`) REFERENCES meta_school(`id`) ); /* COMMON INGREDIENTS */ CREATE TABLE IF NOT EXISTS `ingredient` ( `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, `name` VARCHAR(255) NOT NULL DEFAULT "Langue de salamandre", + `description` VARCHAR(255) NOT NULL DEFAULT "Une langue de salamandre de feu qui bouge encore un peu.", PRIMARY KEY (`id`) ); @@ -63,30 +64,30 @@ CREATE TABLE IF NOT EXISTS `user` ( /* SPELLS' SCHOOLS */ /* One spell can have multiple (up to 3) schools */ -CREATE TABLE IF NOT EXISTS `spells_schools` ( - `id_spell` INT UNSIGNED NOT NULL, - `id_school` INT UNSIGNED NOT NULL, - PRIMARY KEY (`id_spell`, `id_school`), - FOREIGN KEY(`id_spell`) REFERENCES spell(`id`), - FOREIGN KEY(`id_school`) REFERENCES school(`id`) +CREATE TABLE IF NOT EXISTS `spell_school` ( + `spell_id` INT UNSIGNED NOT NULL, + `school_id` INT UNSIGNED NOT NULL, + PRIMARY KEY (`spell_id`, `school_id`), + FOREIGN KEY(`spell_id`) REFERENCES spell(`id`), + FOREIGN KEY(`school_id`) REFERENCES school(`id`) ); /* SPELLS' VARIABLES */ /* One spell can have multiple (up to 2) variables of cost */ -CREATE TABLE IF NOT EXISTS `spells_variables` ( - `id_spell` INT UNSIGNED NOT NULL, - `id_variable` INT UNSIGNED NOT NULL, - PRIMARY KEY (`id_spell`, `id_variable`), - FOREIGN KEY(`id_spell`) REFERENCES spell(`id`), - FOREIGN KEY(`id_variable`) REFERENCES variable(`id`) +CREATE TABLE IF NOT EXISTS `spell_variable` ( + `spell_id` INT UNSIGNED NOT NULL, + `variable_id` INT UNSIGNED NOT NULL, + PRIMARY KEY (`spell_id`, `variable_id`), + FOREIGN KEY(`spell_id`) REFERENCES spell(`id`), + FOREIGN KEY(`variable_id`) REFERENCES variable(`id`) ); /* SPELLS' VARIABLES */ /* One spell can have multiple ingredients */ -CREATE TABLE IF NOT EXISTS `spells_ingredients` ( - `id_spell` INT UNSIGNED NOT NULL, - `id_ingredient` INT UNSIGNED NOT NULL, - PRIMARY KEY (`id_spell`, `id_ingredient`), - FOREIGN KEY(`id_spell`) REFERENCES spell(`id`), - FOREIGN KEY(`id_ingredient`) REFERENCES ingredient(`id`) +CREATE TABLE IF NOT EXISTS `spell_ingredient` ( + `spell_id` INT UNSIGNED NOT NULL, + `ingredient_id` INT UNSIGNED NOT NULL, + PRIMARY KEY (`spell_id`, `ingredient_id`), + FOREIGN KEY(`spell_id`) REFERENCES spell(`id`), + FOREIGN KEY(`ingredient_id`) REFERENCES ingredient(`id`) ); diff --git a/database/auracle_db_data.sql b/database/auracle_db_data.sql index 350946c..b58cb4d 100644 --- a/database/auracle_db_data.sql +++ b/database/auracle_db_data.sql @@ -12,7 +12,7 @@ INSERT INTO `meta_school` (name, description) VALUES ('Magies autres', 'Magies trop spécifiques et ne rentrant dans aucune autre grande école.'); -- SCHOOLS -INSERT INTO `school` (name, description, id_meta_school) VALUES +INSERT INTO `school` (name, description, meta_school_id) VALUES ('Lumomancie', 'Discipline arcanique de la lumière.', 1), ('Vitamancie', 'Discipline arcanique de la guérison et de l\'énergie vitale.', 1), ('Obstrumancie', 'Discipline arcanique de la protection et des sceaux.', 1), @@ -207,9 +207,9 @@ INSERT INTO `user` (name, mail, password) VALUES ('Kevin', '35.alexis.mail@gmail.com', 'sept777'); -- INGREDIENTS -INSERT INTO `ingredient` (name) VALUES -('Volonté'), -('Geste'); +INSERT INTO `ingredient` (name, description) VALUES +('Volonté', 'La force de volonté du lanceur, concentrée sur un objectif'), +('Geste', 'Un geste précis facilitant la canalisation magique'); -- VARIABLES INSERT INTO `variable` (description) VALUES @@ -223,11 +223,11 @@ SCHEMA */ DELIMITER $$ -CREATE PROCEDURE insertIntoSchoolRange(IN delimiter_start INT, IN delimiter_end INT, IN school_id INT) +CREATE PROCEDURE insertIntoSchoolRange(IN delimiter_start INT, IN delimiter_end INT, IN id_school INT) BEGIN SET @i = delimiter_start; WHILE @i <= delimiter_end DO - INSERT INTO spells_schools (id_spell, id_school) VALUES (@i, school_id); + INSERT INTO spell_school (spell_id, school_id) VALUES (@i, id_school); SET @i = @i + 1; END WHILE; END$$ diff --git a/database/bookshelf.js b/database/bookshelf.js new file mode 100644 index 0000000..1ffb0ac --- /dev/null +++ b/database/bookshelf.js @@ -0,0 +1,23 @@ +// MODULES +const fs = require('fs') +const mysql = require('mysql') + +// Fetches and parses credentials file +let credentials_data = fs.readFileSync('./database/credentials.json') +let credentials = JSON.parse(credentials_data) + +// Setting up the database connection +const knex = require('knex')({ + client: credentials.client, + connection: { + host : credentials.host, + user : credentials.user, + password : credentials.password, + database : credentials.database, + charset : credentials.charset + }, + debug: true +}) +const bookshelf = require('bookshelf')(knex) + +module.exports = { bookshelf } \ No newline at end of file diff --git a/database/connection.js b/database/connection.js deleted file mode 100644 index 3084136..0000000 --- a/database/connection.js +++ /dev/null @@ -1,22 +0,0 @@ -// MODULES -const fs = require('fs') -const mysql = require('mysql') - -// Fetches and parses credentials file -let credentials_data = fs.readFileSync('./database/credentials.json') -let credentials = JSON.parse(credentials_data) - -const db = mysql.createConnection({ - host: credentials.host, - user: credentials.user, - password: credentials.password, - database: credentials.database, -}) - -db.on('error', err => { - if (err.errno == 'ECONNRESET') { - console.log("The connection was reset during your request. Please try again later."); - } -}) - -module.exports = { db } \ No newline at end of file diff --git a/index.js b/index.js index a6b9cc1..4ae5ffd 100644 --- a/index.js +++ b/index.js @@ -8,7 +8,7 @@ const morgan = require('morgan') const cors = require('cors') // module to format the json response // Creates instances of database connections -const connection = require('./database/connection') +const connection = require('./database/bookshelf') const db = connection.db // CONSTANTS @@ -30,4 +30,7 @@ const server = app.listen( port, () => {console.log(`App listening on port ${por // Routing app.use('/api/spells', routes.spells) app.use('/api/schools', routes.schools) -app.use('/api/users', routes.users) \ No newline at end of file +app.use('/api/meta_schools', routes.meta_schools) +app.use('/api/variables', routes.variables) +app.use('/api/ingredients', routes.ingredients) +app.use('/api/users', routes.users) diff --git a/models/ingredient-model.js b/models/ingredient-model.js new file mode 100644 index 0000000..cdb8ded --- /dev/null +++ b/models/ingredient-model.js @@ -0,0 +1,13 @@ +'use strict' +const bookshelf = require('../database/bookshelf').bookshelf + +require('./spell-model') + +let Ingredient = bookshelf.Model.extend({ + tableName: 'ingredient', + spells() { + return this.belongsToMany( 'Spell', 'spell_ingredient') + } +}) + +module.exports = bookshelf.model('Ingredient', Ingredient) \ No newline at end of file diff --git a/models/meta-school-model.js b/models/meta-school-model.js new file mode 100644 index 0000000..e52ea7e --- /dev/null +++ b/models/meta-school-model.js @@ -0,0 +1,13 @@ +'use strict' +const bookshelf = require('../database/bookshelf').bookshelf + +require('./school-model') + +let MetaSchool = bookshelf.Model.extend({ + tableName: 'meta_school', + schools() { + return this.hasMany( 'School' ) + } +}) + +module.exports = bookshelf.model('MetaSchool', MetaSchool) \ No newline at end of file diff --git a/models/school-model.js b/models/school-model.js new file mode 100644 index 0000000..2d3ef63 --- /dev/null +++ b/models/school-model.js @@ -0,0 +1,17 @@ +'use strict' +const bookshelf = require('../database/bookshelf').bookshelf + +require('./spell-model') +require('./meta-school-model') + +let School = bookshelf.Model.extend({ + tableName: 'school', + spells() { + return this.belongsToMany( 'Spell', 'spell_school') + }, + meta_schools() { + return this.belongsTo( 'MetaSchool', 'meta_school_id') + } +}) + +module.exports = bookshelf.model('School', School) \ No newline at end of file diff --git a/models/spell-model.js b/models/spell-model.js new file mode 100644 index 0000000..96100a5 --- /dev/null +++ b/models/spell-model.js @@ -0,0 +1,21 @@ +'use strict' +const bookshelf = require('../database/bookshelf').bookshelf + +require('./school-model') +require('./variable-model') +require('./ingredient-model') + +let Spell = bookshelf.Model.extend({ + tableName: 'spell', + schools() { + return this.belongsToMany( 'School', 'spell_school' ) + }, + variables() { + return this.belongsToMany( 'Variable', 'spell_variable' ) + }, + ingredients() { + return this.belongsToMany( 'Ingredient', 'spell_ingredient' ) + } +}) + +module.exports = bookshelf.model('Spell', Spell) \ No newline at end of file diff --git a/models/user-model.js b/models/user-model.js new file mode 100644 index 0000000..60b5c64 --- /dev/null +++ b/models/user-model.js @@ -0,0 +1,8 @@ +'use strict' +const bookshelf = require('../database/bookshelf').bookshelf + +let User = bookshelf.Model.extend({ + tableName: 'user', +}) + +module.exports = bookshelf.model('User', User) \ No newline at end of file diff --git a/models/variable-model.js b/models/variable-model.js new file mode 100644 index 0000000..ba020c9 --- /dev/null +++ b/models/variable-model.js @@ -0,0 +1,13 @@ +'use strict' +const bookshelf = require('../database/bookshelf').bookshelf + +require('./spell-model') + +let Variable = bookshelf.Model.extend({ + tableName: 'variable', + spells() { + return this.belongsToMany( 'Spell', 'spell_variable') + } +}) + +module.exports = bookshelf.model('Variable', Variable) \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 6d450b8..1a368bc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -37,16 +37,106 @@ "readable-stream": "^2.0.6" } }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=" + }, + "array-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", + "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=" + }, "array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, + "array-slice": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", + "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==" + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, "basic-auth": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", @@ -69,6 +159,11 @@ "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==" }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + }, "body-parser": { "version": "1.19.0", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", @@ -86,6 +181,17 @@ "type-is": "~1.6.17" } }, + "bookshelf": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/bookshelf/-/bookshelf-1.1.1.tgz", + "integrity": "sha512-swHlUoCSBv7lS5P6Sbc3zTo64L8Yal98H7v/d1pJLrQLZjiJYjzsdEwnBmnbIr2zDEAZhJW3OZSJFj8ps6o9pQ==", + "requires": { + "bluebird": "^3.7.2", + "create-error": "~0.3.1", + "inflection": "^1.12.0", + "lodash": "^4.17.15" + } + }, "bowser": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.9.0.tgz", @@ -100,6 +206,33 @@ "concat-map": "0.0.1" } }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, "buffer-equal-constant-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", @@ -110,6 +243,22 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, "camelize": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz", @@ -120,11 +269,56 @@ "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, "code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "colorette": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.1.0.tgz", + "integrity": "sha512-6S062WDQUXi6hOfkO/sBPVwE5ASXY4G2+b4atvhJfSsuUUhIaUKlkjLe9692Ipyt5/a+IPF5aVTu3V5gvXq5cg==" + }, + "commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==" + }, + "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==" + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -163,6 +357,11 @@ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" + }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -177,6 +376,11 @@ "vary": "^1" } }, + "create-error": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/create-error/-/create-error-0.3.1.tgz", + "integrity": "sha1-aYECRaYp5lRDK/BDdzYAA6U1GiM=" + }, "dasherize": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/dasherize/-/dasherize-2.0.0.tgz", @@ -190,11 +394,53 @@ "ms": "2.0.0" } }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" + }, "deep-extend": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, "delegates": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", @@ -210,6 +456,11 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" }, + "detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=" + }, "detect-libc": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", @@ -248,11 +499,56 @@ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" }, + "esm": { + "version": "3.2.25", + "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", + "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==" + }, "etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", + "requires": { + "homedir-polyfill": "^1.0.1" + } + }, "expect-ct": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/expect-ct/-/expect-ct-0.2.0.tgz", @@ -295,11 +591,115 @@ "vary": "~1.1.2" } }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, "feature-policy": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/feature-policy/-/feature-policy-0.3.0.tgz", "integrity": "sha512-ZtijOTFN7TzCujt1fnNhfWPFPSHeZkesff9AXZj+UEjYBynWNUIYpC87Ve4wHzyexQsImicLu7WsC2LHq7/xrQ==" }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, "finalhandler": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", @@ -314,11 +714,60 @@ "unpipe": "~1.0.0" } }, + "findup-sync": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", + "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", + "requires": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + } + }, + "fined": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", + "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", + "requires": { + "expand-tilde": "^2.0.2", + "is-plain-object": "^2.0.3", + "object.defaults": "^1.1.0", + "object.pick": "^1.2.0", + "parse-filepath": "^1.0.1" + } + }, + "flagged-respawn": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", + "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==" + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" + }, + "for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", + "requires": { + "for-in": "^1.0.1" + } + }, "forwarded": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "requires": { + "map-cache": "^0.2.2" + } + }, "frameguard": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/frameguard/-/frameguard-3.1.0.tgz", @@ -357,6 +806,16 @@ "wide-align": "^1.1.0" } }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=" + }, + "getopts": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/getopts/-/getopts-2.2.5.tgz", + "integrity": "sha512-9jb7AW5p3in+IiJWhQiZmmwkpLaR/ccTWdWQCtZM66HJcHHLegowh4q4tSD7gouUyeNvFWRavfK9GXosQHDpFA==" + }, "glob": { "version": "7.1.6", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", @@ -370,11 +829,62 @@ "path-is-absolute": "^1.0.0" } }, + "global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "requires": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + } + }, + "global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", + "requires": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + } + }, "has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, "helmet": { "version": "3.22.0", "resolved": "https://registry.npmjs.org/helmet/-/helmet-3.22.0.tgz", @@ -425,6 +935,14 @@ "resolved": "https://registry.npmjs.org/hide-powered-by/-/hide-powered-by-1.1.0.tgz", "integrity": "sha512-Io1zA2yOA1YJslkr+AJlWSf2yWFkKjvkcL9Ni1XSUqnGLr/qRQe2UI3Cn/J9MsJht7yEVCe0SscY1HgVMujbgg==" }, + "homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "requires": { + "parse-passwd": "^1.0.0" + } + }, "hpkp": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/hpkp/-/hpkp-2.0.0.tgz", @@ -478,6 +996,11 @@ "minimatch": "^3.0.4" } }, + "inflection": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz", + "integrity": "sha1-ogCTVlbW9fa8TcdQLhrstwMihBY=" + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -497,11 +1020,93 @@ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" }, + "interpret": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.0.0.tgz", + "integrity": "sha512-e0/LknJ8wpMMhTiWcjivB+ESwIuvHnBSlBbmP/pSb8CQJldoj1p2qv7xGZ/+BtbTziYRFSz8OsvdbiX45LtYQA==" + }, "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==" }, + "is-absolute": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", + "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", + "requires": { + "is-relative": "^1.0.0", + "is-windows": "^1.0.1" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + } + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + }, "is-fullwidth-code-point": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", @@ -510,11 +1115,76 @@ "number-is-nan": "^1.0.0" } }, + "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==", + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "requires": { + "isobject": "^3.0.1" + } + }, + "is-relative": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", + "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", + "requires": { + "is-unc-path": "^1.0.0" + } + }, + "is-unc-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", + "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "requires": { + "unc-path-regex": "^0.1.2" + } + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" + }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + }, "jsonschema": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.2.6.tgz", @@ -563,6 +1233,78 @@ "safe-buffer": "^5.0.1" } }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" + }, + "knex": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/knex/-/knex-0.21.1.tgz", + "integrity": "sha512-uWszXC2DPaLn/YznGT9wFTWUG9+kqbL4DMz+hCH789GLcLuYzq8werHPDKBJxtKvxrW/S1XIXgrTWdMypiVvsw==", + "requires": { + "colorette": "1.1.0", + "commander": "^5.1.0", + "debug": "4.1.1", + "esm": "^3.2.25", + "getopts": "2.2.5", + "inherits": "~2.0.4", + "interpret": "^2.0.0", + "liftoff": "3.1.0", + "lodash": "^4.17.15", + "mkdirp": "^1.0.4", + "pg-connection-string": "2.2.0", + "tarn": "^3.0.0", + "tildify": "2.0.0", + "uuid": "^7.0.3", + "v8flags": "^3.1.3" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "liftoff": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz", + "integrity": "sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog==", + "requires": { + "extend": "^3.0.0", + "findup-sync": "^3.0.0", + "fined": "^1.0.1", + "flagged-respawn": "^1.0.0", + "is-plain-object": "^2.0.4", + "object.map": "^1.0.0", + "rechoir": "^0.6.2", + "resolve": "^1.1.7" + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + }, "lodash.includes": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", @@ -598,6 +1340,27 @@ "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" }, + "make-iterator": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", + "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", + "requires": { + "kind-of": "^6.0.2" + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=" + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "requires": { + "object-visit": "^1.0.0" + } + }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -613,6 +1376,26 @@ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, "mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", @@ -661,6 +1444,25 @@ "minipass": "^2.9.0" } }, + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, "mkdirp": { "version": "0.5.5", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", @@ -704,6 +1506,24 @@ "sqlstring": "2.3.1" } }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + } + }, "needle": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/needle/-/needle-2.5.0.tgz", @@ -814,6 +1634,70 @@ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "requires": { + "isobject": "^3.0.0" + } + }, + "object.defaults": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", + "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=", + "requires": { + "array-each": "^1.0.1", + "array-slice": "^1.0.0", + "for-own": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "object.map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", + "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=", + "requires": { + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "requires": { + "isobject": "^3.0.1" + } + }, "on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", @@ -854,21 +1738,69 @@ "os-tmpdir": "^1.0.0" } }, + "parse-filepath": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", + "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=", + "requires": { + "is-absolute": "^1.0.0", + "map-cache": "^0.2.0", + "path-root": "^0.1.1" + } + }, + "parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=" + }, "parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=" + }, "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=" }, + "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==" + }, + "path-root": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", + "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=", + "requires": { + "path-root-regex": "^0.1.0" + } + }, + "path-root-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", + "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=" + }, "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=" }, + "pg-connection-string": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.2.0.tgz", + "integrity": "sha512-xB/+wxcpFipUZOQcSzcgkjcNOosGhEoPSjz06jC89lv1dj7mc9bZv6wLVy8M2fVjP0a/xN0N988YDq1L0FhK3A==" + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" + }, "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -929,11 +1861,65 @@ "util-deprecate": "~1.0.1" } }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "requires": { + "resolve": "^1.1.6" + } + }, "referrer-policy": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/referrer-policy/-/referrer-policy-1.2.0.tgz", "integrity": "sha512-LgQJIuS6nAy1Jd88DCQRemyE3mS+ispwlqMk3b0yjZ257fI1v9c+/p6SD5gP5FGyXUIgrNOAfmyioHwZtYv2VA==" }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==" + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" + }, + "resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "requires": { + "path-parse": "^1.0.6" + } + }, + "resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", + "requires": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + } + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==" + }, "rimraf": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", @@ -947,6 +1933,14 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "requires": { + "ret": "~0.1.10" + } + }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -1005,6 +1999,27 @@ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, "setprototypeof": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", @@ -1015,11 +2030,157 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "requires": { + "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + }, + "source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "requires": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=" + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "requires": { + "extend-shallow": "^3.0.0" + } + }, "sqlstring": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz", "integrity": "sha1-R1OT/56RR5rqYtyvDKPRSYOn+0A=" }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, "statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", @@ -1070,6 +2231,54 @@ "yallist": "^3.0.3" } }, + "tarn": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tarn/-/tarn-3.0.0.tgz", + "integrity": "sha512-PKUnlDFODZueoA8owLehl8vLcgtA8u4dRuVbZc92tspDYZixjJL6TqYOmryf/PfP/EBX+2rgNcrj96NO+RPkdQ==" + }, + "tildify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tildify/-/tildify-2.0.0.tgz", + "integrity": "sha512-Cc+OraorugtXNfs50hU9KS369rFXCfgGLpfCfvlc+Ud5u6VWmUQsOAa9HbTvheQdYnrdJqqv1e5oIqXppMYnSw==" + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, "toidentifier": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", @@ -1084,11 +2293,73 @@ "mime-types": "~2.1.24" } }, + "unc-path-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", + "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=" + }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=" + } + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=" + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -1099,11 +2370,32 @@ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, + "uuid": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz", + "integrity": "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==" + }, + "v8flags": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.1.3.tgz", + "integrity": "sha512-amh9CCg3ZxkzQ48Mhcb8iX7xpAfYJgePHxWMQCBWECpOSqJUXgY26ncA61UTV0BkPqfhcy6mzwCIoP4ygxpW8w==", + "requires": { + "homedir-polyfill": "^1.0.1" + } + }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "requires": { + "isexe": "^2.0.0" + } + }, "wide-align": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", diff --git a/package.json b/package.json index 688d1af..7e3086c 100644 --- a/package.json +++ b/package.json @@ -28,11 +28,13 @@ "homepage": "https://github.com/AlexisNP/spellsaurus#readme", "dependencies": { "bcrypt": "^4.0.1", + "bookshelf": "^1.1.1", "cors": "^2.8.5", "express": "^4.17.1", "helmet": "^3.22.0", "jsonschema": "^1.2.6", "jsonwebtoken": "^8.5.1", + "knex": "^0.21.1", "morgan": "^1.10.0", "mysql": "^2.18.1" } diff --git a/repositories/ingredient-repository.js b/repositories/ingredient-repository.js new file mode 100644 index 0000000..d6cc682 --- /dev/null +++ b/repositories/ingredient-repository.js @@ -0,0 +1,173 @@ +'use strict' +// Bookshelf +const bookshelf = require('../database/bookshelf').bookshelf +const model = require('../models/ingredient-model') + +// Model validation +const Validator = require('jsonschema').Validator +const v = new Validator() +const IngredientValidation = require("../validations/IngredientValidation") +v.addSchema(IngredientValidation, "/IngredientValidation") + +// Validations +const regexXSS = RegExp(/<[^>]*script/) + +// Error handling +const { HttpError } = require('../validations/Errors') + +class IngredientRepository { + + constructor() { + } + + getAll() { + return new Promise((resolve, reject) => { + model.forge() + .fetchAll({ withRelated: ['spells'] }) + .then(v => { + resolve(v.toJSON({ omitPivot: true })) + }) + .catch(err => { + console.log(err) + reject(new HttpError(500, "Couldn't get ingredients")) + }) + }) + } + + + getOne(id) { + return new Promise((resolve, reject) => { + model.forge() + .where({ 'id' : id }) + .fetch({ withRelated: ['spells']}) + .then(v => { + resolve(v.toJSON({ omitPivot: true })) + }) + .catch(err => { + console.log(err) + reject(new HttpError(500, "Couldn't get ingredient")) + }) + }) + } + + addOne(igr) { + return new Promise((resolve, reject) => { + // Checks if body exists and if the model fits, and throws errors if it doesn't + if (this.isEmptyObject(igr)) { + reject(new HttpError(403, "Error: Ingredient cannot be nothing !")) + } else if (!v.validate(igr, IngredientValidation).valid) { + reject(new HttpError(403, "Error: Schema is not valid - " + v.validate(igr, IngredientValidation).errors)) + } else if (this.isXSSAttempt(igr.description)) { + reject(new HttpError(403, 'Injection attempt detected, aborting the request.')) + } else { + bookshelf.transaction(t => { + return model.forge({ + 'name': igr.name, + 'description': igr.description, + }).save(null, { + transacting: t + }) + .catch(err => { + throw err + }) + }) + .then(v => { + return v.load(['spells']) + }) + .then(v => { + resolve(this.getOne(v.id)) + }) + .catch(err => { + console.log(err) + reject(new HttpError(500, "Insert Ingredient error")) + }) + } + }) + } + + updateOne(id, igr) { + return new Promise((resolve, reject) => { + // Checks if body exists and if the model fits, and throws errors if it doesn't + if (this.isEmptyObject(igr)) { + reject(new HttpError(403, "Error: Ingredient cannot be nothing !")) + } else if (!v.validate(igr, IngredientValidation).valid) { + reject(new HttpError(403, "Error: Schema is not valid - " + v.validate(igr, IngredientValidation).errors)) + } else if (this.isXSSAttempt(igr.description)) { + reject(new HttpError(403, 'Injection attempt detected, aborting the request.')) + } else { + model.forge({id: id}) + .fetch({require: true, withRelated: ['spells']}) + .then(v => { + bookshelf.transaction(t => { + return v.save({ + 'name': igr.name, + 'description': igr.description, + }, { + method: 'update', + transacting: t + }) + .catch(err => { + console.log(err) + throw err + }) + }) + .then(v => { + return v.load(['spells']) + }) + .then(v => { + resolve(this.getOne(v.id)) + }) + .catch(err => { + console.log(err) + reject(new HttpError(500, "Update Ingredient error")) + }) + }) + .catch(err => { + console.log(err) + reject(new HttpError(404, "Couldn't get ingredient")) + }) + } + }) + } + + deleteOne(id) { + return new Promise((resolve, reject) => { + model.forge() + .where({ 'id' : id }) + .fetch({require: true, withRelated: ['spells']}) + .then(v => { + v.spells().detach() + v.destroy() + }) + .then(() => { + resolve({ + 'message': 'Ingredient with ID ' + id + ' successfully deleted !' + }) + }) + .catch(err => { + console.log(err) + reject(new HttpError(404, "Couldn't get ingredient")) + }) + }) + } + + // Check if object is null + isEmptyObject = (obj) => { + if (Object.keys(obj).length === 0 && obj.constructor === Object) { + return true + } else { + return false + } + } + + // Check if script injection attempt + isXSSAttempt = (string) => { + if (regexXSS.test(string)) { + return true + } else { + return false + } + } +} + +module.exports = IngredientRepository \ No newline at end of file diff --git a/repositories/meta-school-repository.js b/repositories/meta-school-repository.js new file mode 100644 index 0000000..f2eb7bc --- /dev/null +++ b/repositories/meta-school-repository.js @@ -0,0 +1,72 @@ +'use strict' +// Bookshelf +const bookshelf = require('../database/bookshelf').bookshelf +const model = require('../models/meta-school-model') + +// Model validation +const Validator = require('jsonschema').Validator +const v = new Validator() +const MetaSchoolValidation = require("../validations/MetaSchoolValidation") +v.addSchema(MetaSchoolValidation, "/MetaSchoolValidation") + +// Validations +const regexXSS = RegExp(/<[^>]*script/) + +// Error handling +const { HttpError } = require('../validations/Errors') + +class MetaSchoolRepository { + + constructor() { + } + + getAll() { + return new Promise((resolve, reject) => { + model.forge() + .fetchAll({ withRelated: ['schools'] }) + .then(v => { + resolve(v.toJSON({ omitPivot: true })) + }) + .catch(err => { + console.log(err) + reject(new HttpError(500, "Couldn't get meta schools")) + }) + }) + } + + getOne(id) { + return new Promise((resolve, reject) => { + model.forge() + .where({ 'id' : id }) + .fetch({ withRelated: ['schools']}) + .then(v => { + resolve(v.toJSON({ omitPivot: true })) + }) + .catch(err => { + console.log(err) + reject(new HttpError(500, "Couldn't get meta school")) + }) + }) + } + + // Check if object is null + isEmptyObject = (obj) => { + if (Object.keys(obj).length === 0 && obj.constructor === Object) { + return true + } else { + return false + } + } + + // Check if script injection attempt + isXSSAttempt = (string) => { + if (regexXSS.test(string)) { + return true + } else { + return false + } + } + +} + +module.exports = MetaSchoolRepository \ No newline at end of file diff --git a/repositories/school-repository.js b/repositories/school-repository.js new file mode 100644 index 0000000..2ffa311 --- /dev/null +++ b/repositories/school-repository.js @@ -0,0 +1,174 @@ +'use strict' +// Bookshelf +const bookshelf = require('../database/bookshelf').bookshelf +const model = require('../models/school-model') + +// Model validation +const Validator = require('jsonschema').Validator +const v = new Validator() +const SchoolValidation = require("../validations/SchoolValidation") +v.addSchema(SchoolValidation, "/SchoolValidation") + +// Validations +const regexXSS = RegExp(/<[^>]*script/) + +// Error handling +const { HttpError } = require('../validations/Errors') + +class SchoolRepository { + + constructor() { + } + + getAll() { + return new Promise((resolve, reject) => { + model.forge() + .fetchAll({ withRelated: ['meta_schools'] }) + .then(v => { + resolve(v.toJSON({ omitPivot: true })) + }) + .catch(err => { + console.log(err) + reject(new HttpError(500, "Couldn't get schools")) + }) + }) + } + + getOne(id) { + return new Promise((resolve, reject) => { + model.forge() + .where({ 'id' : id }) + .fetch({ withRelated: ['meta_schools']}) + .then(v => { + resolve(v.toJSON({ omitPivot: true })) + }) + .catch(err => { + console.log(err) + reject(new HttpError(500, "Couldn't get school")) + }) + }) + } + + addOne(s) { + return new Promise((resolve, reject) => { + // Checks if body exists and if the model fits, and throws errors if it doesn't + if (this.isEmptyObject(s)) { + reject(new HttpError(403, "Error: School cannot be nothing !")) + } else if (!v.validate(s, SchoolValidation).valid) { + reject(new HttpError(403, "Error: Schema is not valid - " + v.validate(s, SchoolValidation).errors)) + } else if (this.isXSSAttempt(s.name) || this.isXSSAttempt(s.description)) { + reject(new HttpError(403, 'Injection attempt detected, aborting the request.')) + } else { + bookshelf.transaction(t => { + return model.forge({ + 'name': s.name, + 'description': s.description, + 'meta_school_id': s.meta_school_id, + }).save(null, { + transacting: t + }) + .catch(err => { + throw err + }) + }) + .then(v => { + return v.load(['meta_schools']) + }) + .then(v => { + resolve(this.getOne(v.id)) + }) + .catch(err => { + console.log(err) + reject(new HttpError(500, "Insert School error")) + }) + } + }) + } + + updateOne(id, s) { + return new Promise((resolve, reject) => { + // Checks if body exists and if the model fits, and throws errors if it doesn't + if (this.isEmptyObject(s)) { + reject(new HttpError(403, "Error: School cannot be nothing !")) + } else if (!v.validate(s, SchoolValidation).valid) { + reject(new HttpError(403, "Error: Schema is not valid - " + v.validate(s, SchoolValidation).errors)) + } else if (this.isXSSAttempt(s.name) || this.isXSSAttempt(s.description)) { + reject(new HttpError(403, 'Injection attempt detected, aborting the request.')) + } else { + model.forge({id: id}) + .fetch({require: true, withRelated: ['meta_schools']}) + .then(v => { + bookshelf.transaction(t => { + return v.save({ + 'name': s.name, + 'description': s.description, + 'meta_school_id': s.meta_school_id + }, { + method: 'update', + transacting: t + }) + .catch(err => { + console.log(err) + throw err + }) + }) + .then(v => { + return v.load(['meta_schools']) + }) + .then(v => { + resolve(this.getOne(v.id)) + }) + .catch(err => { + console.log(err) + reject(new HttpError(500, "Update School error")) + }) + }) + .catch(err => { + console.log(err) + reject(new HttpError(404, "Couldn't get school")) + }) + } + }) + } + + deleteOne(id) { + return new Promise((resolve, reject) => { + model.forge() + .where({ 'id' : id }) + .fetch({require: true, withRelated: ['spells', 'meta_schools']}) + .then(v => { + v.spells().detach() + v.destroy() + }) + .then(() => { + resolve({ + 'message': 'School with ID ' + id + ' successfully deleted !' + }) + }) + .catch(err => { + console.log(err) + reject(new HttpError(404, "Couldn't get school")) + }) + }) + } + + // Check if object is null + isEmptyObject = (obj) => { + if (Object.keys(obj).length === 0 && obj.constructor === Object) { + return true + } else { + return false + } + } + + // Check if script injection attempt + isXSSAttempt = (string) => { + if (regexXSS.test(string)) { + return true + } else { + return false + } + } +} + +module.exports = SchoolRepository \ No newline at end of file diff --git a/repositories/spell-repository.js b/repositories/spell-repository.js new file mode 100644 index 0000000..cc14d8f --- /dev/null +++ b/repositories/spell-repository.js @@ -0,0 +1,245 @@ +'use strict' +// Bookshelf +const bookshelf = require('../database/bookshelf').bookshelf +const model = require('../models/spell-model') + +// Model validation +const Validator = require('jsonschema').Validator +const v = new Validator() +const SpellValidation = require("../validations/SpellValidation") +v.addSchema(SpellValidation, "/SpellValidation") + +// Validations +const regexXSS = RegExp(/<[^>]*script/) + +// Error handling +const { HttpError } = require('../validations/Errors') + +class SpellRepository { + + constructor() { + } + + getAll() { + return new Promise((resolve, reject) => { + model.forge() + .fetchAll({ withRelated: ['schools.meta_schools', 'variables', 'ingredients'] }) + .then(v => { + resolve(v.toJSON({ omitPivot: true })) + }) + .catch(err => { + console.log(err) + reject(new HttpError(500, "Couldn't get spells")) + }) + }) + } + + getOne(id) { + return new Promise((resolve, reject) => { + model.forge() + .where({ 'id' : id }) + .fetch({ withRelated: ['schools.meta_schools', 'variables', 'ingredients']}) + .then(v => { + resolve(v.toJSON({ omitPivot: true })) + }) + .catch(err => { + console.log(err) + reject(new HttpError(500, "Couldn't get spell")) + }) + }) + } + + addOne(s) { + return new Promise((resolve, reject) => { + // Checks if body exists and if the model fits, and throws errors if it doesn't + if (this.isEmptyObject(s)) { + reject(new HttpError(403, "Error: Spell cannot be nothing !")) + } else if (!v.validate(s, SpellValidation).valid) { + reject(new HttpError(403, "Error: Schema is not valid - " + v.validate(s, SpellValidation).errors)) + } else if (this.isXSSAttempt(s.name) || this.isXSSAttempt(s.description) || this.isXSSAttempt(s.cost)) { + reject(new HttpError(403, 'Injection attempt detected, aborting the request.')) + } else { + bookshelf.transaction(t => { + return model.forge({ + 'name': s.name, + 'description': s.description, + 'level': s.level, + 'charge' : s.charge, + 'cost' : s.cost, + 'is_ritual' : s.is_ritual + }).save(null, { + transacting: t + }) + .tap(spell => { + return spell + .schools() + .attach(s.schools, { + transacting: t + }); + }) + .tap(spell => { + return spell + .variables() + .attach(s.variables, { + transacting: t + }); + }) + .tap(spell => { + return spell + .ingredients() + .attach(s.ingredients, { + transacting: t + }); + }) + .catch(err => { + throw err + }) + }) + .then(v => { + return v.load(['schools.meta_schools', 'variables', 'ingredients']) + }) + .then(v => { + resolve(this.getOne(v.id)) + }) + .catch(err => { + console.log(err) + reject(new HttpError(500, "Insert Spell error")) + }) + } + }) + } + + updateOne(id, s) { + return new Promise((resolve, reject) => { + // Checks if body exists and if the model fits, and throws errors if it doesn't + if (this.isEmptyObject(s)) { + reject(new HttpError(403, "Error: Spell cannot be nothing !")) + } else if (!v.validate(s, SpellValidation).valid) { + reject(new HttpError(403, "Error: Schema is not valid - " + v.validate(s, SpellValidation).errors)) + } else if (this.isXSSAttempt(s.name) || this.isXSSAttempt(s.description) || this.isXSSAttempt(s.cost)) { + reject(new HttpError(403, 'Injection attempt detected, aborting the request.')) + } else { + model.forge({id: id}) + .fetch({require: true, withRelated: ['schools.meta_schools', 'variables', 'ingredients']}) + .then(v => { + bookshelf.transaction(t => { + return v.save({ + 'name': s.name, + 'description': s.description, + 'level': s.level, + 'charge' : s.charge, + 'cost' : s.cost, + 'is_ritual' : s.is_ritual + }, { + method: 'update', + transacting: t + }) + // Detaches AND attaches pivot tables, dw about it + .tap(spell => { + if (s.schools) { + let schools = spell.related('school'); + return spell.schools().detach(schools, { transacting: t}); + } + return + }) + .tap(spell => { + if (s.variables) { + let variables = spell.related('variable'); + return spell.variables().detach(variables, { transacting: t}); + } + return + }) + .tap(spell => { + if (s.ingredients) { + let ingredients = spell.related('ingredient'); + return spell.ingredients().detach(ingredients, { transacting: t}); + } + }) + .tap(spell => { + return spell + .schools() + .attach(s.schools, { + transacting: t + }); + }) + .tap(spell => { + return spell + .variables() + .attach(s.variables, { + transacting: t + }); + }) + .tap(spell => { + return spell + .ingredients() + .attach(s.ingredients, { + transacting: t + }); + }) + .catch(err => { + console.log(err) + throw err + }) + }) + .then(v => { + return v.load(['schools.meta_schools', 'variables', 'ingredients']) + }) + .then(v => { + resolve(this.getOne(v.id)) + }) + .catch(err => { + console.log(err) + reject(new HttpError(500, "Update Spell error")) + }) + }) + .catch(err => { + console.log(err) + reject(new HttpError(404, "Couldn't get spell")) + }) + } + }) + } + + deleteOne(id) { + return new Promise((resolve, reject) => { + model.forge() + .where({ 'id' : id }) + .fetch({require: true, withRelated: ['schools.meta_schools', 'variables', 'ingredients']}) + .then(v => { + v.schools().detach() + v.variables().detach() + v.ingredients().detach() + v.destroy() + }) + .then(() => { + resolve({ + 'message': 'Spell with ID ' + id + ' successfully deleted !' + }) + }) + .catch(err => { + console.log(err) + reject(new HttpError(404, "Couldn't get spell")) + }) + }) + } + + // Check if object is null + isEmptyObject = (obj) => { + if (Object.keys(obj).length === 0 && obj.constructor === Object) { + return true + } else { + return false + } + } + + // Check if script injection attempt + isXSSAttempt = (string) => { + if (regexXSS.test(string)) { + return true + } else { + return false + } + } +} + +module.exports = SpellRepository \ No newline at end of file diff --git a/repositories/user-repository.js b/repositories/user-repository.js new file mode 100644 index 0000000..292e5fa --- /dev/null +++ b/repositories/user-repository.js @@ -0,0 +1,74 @@ +'use strict' +// Bookshelf +const bookshelf = require('../database/bookshelf').bookshelf +const model = require('../models/user-model') + +// Hashing and passwords +const bcrypt = require('bcrypt') + +// Model validation +const Validator = require('jsonschema').Validator +const v = new Validator() +const UserValidation = require("../validations/UserValidation") +v.addSchema(UserValidation, "/UserValidation") + +// Validations +const regexXSS = RegExp(/<[^>]*script/) + +// Error handling +const { HttpError } = require('../validations/Errors') + +class UserRepository { + + constructor() { + } + + getAll() { + return new Promise((resolve, reject) => { + this._model.forge() + .fetchAll() + .then(v => { + resolve(v.toJSON({ omitPivot: true })) + }) + .catch(err => { + console.log(err) + reject(new HttpError(500, "Couldn't get users")) + }) + }) + } + + getOne(id) { + return new Promise((resolve, reject) => { + this._model.forge() + .where({ 'id' : id }) + .fetch() + .then(v => { + resolve(v.toJSON({ omitPivot: true })) + }) + .catch(err => { + console.log(err) + reject(new HttpError(500, "Couldn't get user")) + }) + }) + } + + // Check if object is null + isEmptyObject = (obj) => { + if (Object.keys(obj).length === 0 && obj.constructor === Object) { + return true + } else { + return false + } + } + + // Check if script injection attempt + isXSSAttempt = (string) => { + if (regexXSS.test(string)) { + return true + } else { + return false + } + } +} + +module.exports = UserRepository \ No newline at end of file diff --git a/repositories/variable-repository.js b/repositories/variable-repository.js new file mode 100644 index 0000000..517a672 --- /dev/null +++ b/repositories/variable-repository.js @@ -0,0 +1,170 @@ +'use strict' +// Bookshelf +const bookshelf = require('../database/bookshelf').bookshelf +const model = require('../models/variable-model') + +// Model validation +const Validator = require('jsonschema').Validator +const v = new Validator() +const VariableValidation = require("../validations/VariableValidation") +v.addSchema(VariableValidation, "/VariableValidation") + +// Validations +const regexXSS = RegExp(/<[^>]*script/) + +// Error handling +const { HttpError } = require('../validations/Errors') +class VariableRepository { + + constructor() { + } + + getAll() { + return new Promise((resolve, reject) => { + model.forge() + .fetchAll({ withRelated: ['spells'] }) + .then(v => { + resolve(v.toJSON({ omitPivot: true })) + }) + .catch(err => { + console.log(err) + reject(new HttpError(500, "Couldn't get variables")) + }) + }) + } + + + getOne(id) { + return new Promise((resolve, reject) => { + model.forge() + .where({ 'id' : id }) + .fetch({ withRelated: ['spells']}) + .then(v => { + resolve(v.toJSON({ omitPivot: true })) + }) + .catch(err => { + console.log(err) + reject(new HttpError(500, "Couldn't get variable")) + }) + }) + } + + addOne(vr) { + return new Promise((resolve, reject) => { + // Checks if body exists and if the model fits, and throws errors if it doesn't + if (this.isEmptyObject(vr)) { + reject(new HttpError(403, "Error: Variable cannot be nothing !")) + } else if (!v.validate(vr, VariableValidation).valid) { + reject(new HttpError(403, "Error: Schema is not valid - " + v.validate(vr, VariableValidation).errors)) + } else if (this.isXSSAttempt(vr.description)) { + reject(new HttpError(403, 'Injection attempt detected, aborting the request.')) + } else { + bookshelf.transaction(t => { + return model.forge({ + 'description': vr.description, + }).save(null, { + transacting: t + }) + .catch(err => { + throw err + }) + }) + .then(v => { + return v.load(['spells']) + }) + .then(v => { + resolve(this.getOne(v.id)) + }) + .catch(err => { + console.log(err) + reject(new HttpError(500, "Insert Variable error")) + }) + } + }) + } + + updateOne(id, vr) { + return new Promise((resolve, reject) => { + // Checks if body exists and if the model fits, and throws errors if it doesn't + if (this.isEmptyObject(vr)) { + reject(new HttpError(403, "Error: Variable cannot be nothing !")) + } else if (!v.validate(vr, VariableValidation).valid) { + reject(new HttpError(403, "Error: Schema is not valid - " + v.validate(vr, VariableValidation).errors)) + } else if (this.isXSSAttempt(vr.description)) { + reject(new HttpError(403, 'Injection attempt detected, aborting the request.')) + } else { + model.forge({id: id}) + .fetch({require: true, withRelated: ['spells']}) + .then(v => { + bookshelf.transaction(t => { + return v.save({ + 'description': vr.description, + }, { + method: 'update', + transacting: t + }) + .catch(err => { + console.log(err) + throw err + }) + }) + .then(v => { + return v.load(['spells']) + }) + .then(v => { + resolve(this.getOne(v.id)) + }) + .catch(err => { + console.log(err) + reject(new HttpError(500, "Update Variable error")) + }) + }) + .catch(err => { + console.log(err) + reject(new HttpError(404, "Couldn't get variable")) + }) + } + }) + } + + deleteOne(id) { + return new Promise((resolve, reject) => { + model.forge() + .where({ 'id' : id }) + .fetch({require: true, withRelated: ['spells']}) + .then(v => { + v.spells().detach() + v.destroy() + }) + .then(() => { + resolve({ + 'message': 'Variable with ID ' + id + ' successfully deleted !' + }) + }) + .catch(err => { + console.log(err) + reject(new HttpError(404, "Couldn't get variable")) + }) + }) + } + + // Check if object is null + isEmptyObject = (obj) => { + if (Object.keys(obj).length === 0 && obj.constructor === Object) { + return true + } else { + return false + } + } + + // Check if script injection attempt + isXSSAttempt = (string) => { + if (regexXSS.test(string)) { + return true + } else { + return false + } + } +} + +module.exports = VariableRepository \ No newline at end of file diff --git a/routes/index.js b/routes/index.js index 021e2b2..f2a3aa5 100644 --- a/routes/index.js +++ b/routes/index.js @@ -1,9 +1,15 @@ -const users = require('./users') const spells = require('./spells') const schools = require('./schools') +const meta_schools = require('./meta_schools') +const variables = require('./variables') +const ingredients = require('./ingredients') +const users = require('./users') module.exports = { spells, schools, - users + meta_schools, + ingredients, + variables, + users, } \ No newline at end of file diff --git a/routes/ingredients.js b/routes/ingredients.js new file mode 100644 index 0000000..057b2f3 --- /dev/null +++ b/routes/ingredients.js @@ -0,0 +1,165 @@ +'use strict' + +// Router +const express = require('express') +let router = express.Router() + +// Connection +const connection = require('../database/bookshelf') +const db = connection.db + +// Repository +const IngredientRepository = require('../repositories/ingredient-repository'); +const Ingredients = new IngredientRepository(); + +const regexInt = RegExp(/^[1-9]\d*$/) + +// Error handling +const { HttpError } = require('../validations/Errors') + +// ROUTES +// GET ALL ------------------ +const getIngredients = () => { + return Ingredients.getAll() + .catch(err => { + console.log(err) + throw err + }) +} +router.get('/', async (req, res) => { + getIngredients() + .then(v => { + res.setHeader('Content-Type', 'application/json;charset=utf-8') + res.end(JSON.stringify(v)) + }) + .catch(err => { + res.status(err.code).send(JSON.stringify( + { + "error": err.message, + "code": err.code + }) + ) + }) +}) + + +// GET ONE ------------------ +const getIngredient = (id) => { + return Ingredients.getOne(id) + .catch(err => { + console.log(err) + throw err + }) +} +router.get('/:id/', async (req, res) => { + getIngredient(req.params.id) + .then(v => { + res.setHeader('Content-Type', 'application/json;charset=utf-8') + res.end(JSON.stringify(v)) + }) + .catch(err => { + res.status(err.code).send(JSON.stringify( + { + "error": err.message, + "code": err.code + }) + ) + }) +}) + + +// CREATE ONE ------------------ +const addIngredient = (igr) => { + return Ingredients.addOne(igr) + .catch(err => { + console.log(err) + throw err + }) +} +router.post('/', async (req, res) => { + addIngredient(req.body) + .then(v => { + res.setHeader('Content-Type', 'application/json;charset=utf-8') + res.send(JSON.stringify(v)) + }) + .catch(err => { + res.status(err.code).send(JSON.stringify( + { + "error": err.message, + "code": err.code + }) + ) + }) +}) + + +// UPDATE ONE ------------------ +const updateIngredient = (id, igr) => { + return Ingredients.updateOne(id, igr) + .catch(err => { + console.log(err) + throw err + }) +} +router.put('/:id/', async (req, res) => { + updateIngredient(req.params.id, req.body) + .then(v => { + res.setHeader('Content-Type', 'application/json;charset=utf-8') + res.send(JSON.stringify(v)) + }) + .catch(err => { + res.status(err.code).send(JSON.stringify( + { + "error": err.message, + "code": err.code + }) + ) + }) +}) + + +// DELETE ONE ------------------ +const deleteIngredient = (id) => { + return Ingredients.deleteOne(id) + .catch(err => { + console.log(err) + throw err + }) +} +router.delete('/:id/', async (req, res) => { + deleteIngredient(req.params.id) + .then(v => { + res.setHeader('Content-Type', 'application/json;charset=utf-8') + res.send(JSON.stringify(v)) + }) + .catch(err => { + res.status(err.code).send(JSON.stringify( + { + "error": err.message, + "code": err.code + }) + ) + }) +}) + +// Param validation for ID +// (check if id is int) (could be refactored) +router.param('id', (req, res, next, id) => { + try { + if (regexInt.test(id)) { + next() + } else { + throw new Error; + } + } catch (err) { + err = new HttpError(403, 'Provided ID must be an integer and not zero') + res.status(err.code).send(JSON.stringify( + { + "error": err.message, + "code": err.code + }) + ) + } +}) + +module.exports = router \ No newline at end of file diff --git a/routes/meta_schools.js b/routes/meta_schools.js new file mode 100644 index 0000000..4639c36 --- /dev/null +++ b/routes/meta_schools.js @@ -0,0 +1,91 @@ +'use strict' + +// Router +const express = require('express') +let router = express.Router() + +// Connection +const connection = require('../database/bookshelf') +const db = connection.db + +// Repository +const MetaSchoolRepository = require('../repositories/meta-school-repository'); +const MetaSchools = new MetaSchoolRepository(); + +const regexInt = RegExp(/^[1-9]\d*$/) + +// Error handling +const { HttpError } = require('../validations/Errors') + +// ROUTES +// GET ALL ------------------ +const getMetaSchools = () => { + return MetaSchools.getAll() + .catch(err => { + console.log(err) + throw err + }) +} +router.get('/', async (req, res) => { + getMetaSchools() + .then(v => { + res.setHeader('Content-Type', 'application/json;charset=utf-8') + res.end(JSON.stringify(v)) + }) + .catch(err => { + res.status(err.code).send(JSON.stringify( + { + "error": err.message, + "code": err.code + }) + ) + }) +}) + + +// GET ONE ------------------ +const getMetaSchool = (id) => { + return MetaSchools.getOne(id) + .catch(err => { + console.log(err) + throw err + }) +} +router.get('/:id/', async (req, res) => { + getMetaSchool(req.params.id) + .then(v => { + res.setHeader('Content-Type', 'application/json;charset=utf-8') + res.end(JSON.stringify(v)) + }) + .catch(err => { + res.status(err.code).send(JSON.stringify( + { + "error": err.message, + "code": err.code + }) + ) + }) +}) + + +// Param validation for ID +// (check if id is int) (could be refactored) +router.param('id', (req, res, next, id) => { + try { + if (regexInt.test(id)) { + next() + } else { + throw new Error; + } + } catch (err) { + err = new HttpError(403, 'Provided ID must be an integer and not zero') + res.status(err.code).send(JSON.stringify( + { + "error": err.message, + "code": err.code + }) + ) + } +}) + +module.exports = router \ No newline at end of file diff --git a/routes/schools.js b/routes/schools.js index cb5b825..4b228e0 100644 --- a/routes/schools.js +++ b/routes/schools.js @@ -5,49 +5,24 @@ const express = require('express') let router = express.Router() // Connection -const connection = require('../database/connection') +const connection = require('../database/bookshelf') const db = connection.db -// Validations -const regexInt = RegExp(/^[1-9]\d*$/) -const regexXSS = RegExp(/<[^>]*script/) +// Repository +const SchoolRepository = require('../repositories/school-repository'); +const Schools = new SchoolRepository(); -// Model validation -const Validator = require('jsonschema').Validator -const v = new Validator() -const School = require("../models/School") -v.addSchema(School, "/SchoolModel") +const regexInt = RegExp(/^[1-9]\d*$/) // Error handling -const { HttpError } = require('../models/Errors') - +const { HttpError } = require('../validations/Errors') // ROUTES // GET ALL ------------------ const getSchools = () => { - return new Promise((resolve, reject) => { - - let query = "SELECT DISTINCT * FROM school" - - db.query(query, async (err, result) => { - if (err) { - reject(new HttpError(500, 'Database error')) - } else if (result.length == 0) { - reject(new HttpError(404, 'No schools were found')) - } - - // Loops over the results to fetch the associated tables - for (let i = 0; i < result.length; i++) { - try { - result[i] = await buildSchool(result[i]) - } catch (err) { - reject(err) - } - } - resolve(result) - }) - }) + return Schools.getAll() .catch(err => { + console.log(err) throw err }) } @@ -70,23 +45,9 @@ router.get('/', async (req, res) => { // GET ONE ------------------ const getSchool = (id) => { - return new Promise((resolve, reject) => { - - let query = "SELECT * FROM school WHERE id = " + db.escape(id) - - db.query(query, async (err, result) => { - if (err) { - reject(new HttpError(500, 'Database error')) - } - try { - result = buildSchool(result[0]) - resolve(result) - } catch (err) { - reject(err) - } - }) - }) + return Schools.getOne(id) .catch(err => { + console.log(err) throw err }) } @@ -109,41 +70,9 @@ router.get('/:id/', async (req, res) => { // CREATE ONE ------------------ const addSchool = (s) => { - return new Promise(async (resolve, reject) => { - - // Checks if body exists and if the model fits, and throws errors if it doesn't - if (isEmptyObject(s)) { - reject(new HttpError(403, "Error: School cannot be nothing !")) - } else if (!v.validate(s, School).valid) { - reject(new HttpError(403, "Error: Schema is not valid - " + v.validate(s, School).errors)) - } else if (isXSSAttempt(s.name) || isXSSAttempt(s.description)) { - reject(new HttpError(403, 'Injection attempt detected, aborting the request.')) - } else { - let query = `INSERT INTO school (name, description, id_meta_school) VALUES (${db.escape(s.name)}, ${db.escape(s.description)}, ${db.escape(s.id_meta_school)})` - - db.query(query, (err, result) => { - if (err) { - if (err.errno == 1452) { - reject(new HttpError(404, "Error: No meta school matching this ID")) - } else { - reject(new HttpError(500, 'Database error')) - } - } else { - console.log(`Inserted "${s.name}" with ID ${result.insertId}, affecting ${result.affectedRows} row(s)`) - - const new_school_id = result.insertId - - getSchool(new_school_id) - .then(v => { - resolve(v) - }) - .catch(err => { - reject(err) - }) - } - }) - } - }).catch(err => { + return Schools.addOne(s) + .catch(err => { + console.log(err) throw err }) } @@ -163,17 +92,66 @@ router.post('/', async (req, res) => { }) }) -// Param validation for single school +// UPDATE ONE ------------------ +const updateSchool = (id, s) => { + return Schools.updateOne(id, s) + .catch(err => { + console.log(err) + throw err + }) +} +router.put('/:id/', async (req, res) => { + updateSchool(req.params.id, req.body) + .then(v => { + res.setHeader('Content-Type', 'application/json;charset=utf-8') + res.send(JSON.stringify(v)) + }) + .catch(err => { + res.status(err.code).send(JSON.stringify( + { + "error": err.message, + "code": err.code + }) + ) + }) +}) + + +// DELETE ONE ------------------ +const deleteSchool = (id) => { + return Schools.deleteOne(id) + .catch(err => { + console.log(err) + throw err + }) +} +router.delete('/:id/', async (req, res) => { + deleteSchool(req.params.id) + .then(v => { + res.setHeader('Content-Type', 'application/json;charset=utf-8') + res.send(JSON.stringify(v)) + }) + .catch(err => { + res.status(err.code).send(JSON.stringify( + { + "error": err.message, + "code": err.code + }) + ) + }) +}) + +// Param validation for ID // (check if id is int) (could be refactored) router.param('id', (req, res, next, id) => { - const regex = RegExp(/^[1-9]\d*$/); try { - if (regex.test(id)) { + if (regexInt.test(id)) { next() } else { - throw new HttpError(403, 'Provided ID must be an integer') + throw new Error; } } catch (err) { + err = new HttpError(403, 'Provided ID must be an integer and not zero') res.status(err.code).send(JSON.stringify( { "error": err.message, @@ -183,59 +161,4 @@ router.param('id', (req, res, next, id) => { } }) -// SHARED FUNCTIONS ------------------ - -// Builds the associated infos for a given school object -const buildSchool = async (school) => { - - // Fetches the school's parent school - let fetchMetaSchoolData = (s) => { - return new Promise((resolve, reject) => { - - if (s == null) { reject(new HttpError(404, "Error: No school matching this ID"))} - - let query = - "SELECT ms.id, ms.name " + - "FROM meta_school AS ms " + - "WHERE ms.id = " + s.id_meta_school - - - db.query(query, (err, result) => { - if (err) { - reject(new HttpError(500, 'Database error')) - } else { - delete s.id_meta_school - s.meta_school = result - resolve(s) - } - }) - }) - } - - let s = fetchMetaSchoolData(school) - .catch(err => { - throw err - }) - - return s -} - -// Check if object is null -const isEmptyObject = (obj) => { - if (Object.keys(obj).length === 0 && obj.constructor === Object) { - return true - } else { - return false - } -} - -// Check if script injection attempt -const isXSSAttempt = (string) => { - if (regexXSS.test(string)) { - return true - } else { - return false - } -} - module.exports = router \ No newline at end of file diff --git a/routes/spells.js b/routes/spells.js index d208043..2d3ea4f 100644 --- a/routes/spells.js +++ b/routes/spells.js @@ -5,48 +5,24 @@ const express = require('express') let router = express.Router() // Connection -const connection = require('../database/connection') +const connection = require('../database/bookshelf') const db = connection.db -// Validations -const regexInt = RegExp(/^[1-9]\d*$/) -const regexXSS = RegExp(/<[^>]*script/) +// Repository +const SpellReposity = require('../repositories/spell-repository'); +const Spells = new SpellReposity(); -// Model validation -const Validator = require('jsonschema').Validator -const v = new Validator() -const Spell = require("../models/Spell") -v.addSchema(Spell, "/SpellModel") +const regexInt = RegExp(/^[1-9]\d*$/) // Error handling -const { HttpError } = require('../models/Errors') +const { HttpError } = require('../validations/Errors') // ROUTES // GET ALL ------------------ const getSpells = () => { - return new Promise((resolve, reject) => { - - let query = "SELECT DISTINCT * FROM spell" - - db.query(query, async (err, result) => { - if (err) { - reject(new HttpError(500, 'Database error')) - } else if (result.length == 0) { - reject(new HttpError(404, 'No spells were found')) - } - - // Loops over the results to fetch the associated tables - for (let i = 0; i < result.length; i++) { - try { - result[i] = await buildSpell(result[i]) - } catch (err) { - reject(err) - } - } - resolve(result) - }) - }) + return Spells.getAll() .catch(err => { + console.log(err) throw err }) } @@ -69,23 +45,9 @@ router.get('/', async (req, res) => { // GET ONE ------------------ const getSpell = (id) => { - return new Promise((resolve, reject) => { - - let query = "SELECT * FROM spell WHERE id = " + db.escape(id) - - db.query(query, async (err, result) => { - if (err) { - reject(new HttpError(500, 'Database error')) - } - try { - result = buildSpell(result[0]) - resolve(result) - } catch (err) { - reject(err) - } - }) - }) + return Spells.getOne(id) .catch(err => { + console.log(err) throw err }) } @@ -108,136 +70,9 @@ router.get('/:id/', async (req, res) => { // CREATE ONE ------------------ const addSpell = (s) => { - return new Promise(async (resolve, reject) => { - - // Checks if body exists and if the model fits, and throws errors if it doesn't - if (isEmptyObject(s)) { - reject(new HttpError(403, "Error: Spell cannot be nothing !")) - } else if (!v.validate(s, Spell).valid) { - reject(new HttpError(403, "Error: Schema is not valid - " + v.validate(s, Spell).errors)) - } else if (isXSSAttempt(s.name) || isXSSAttempt(s.description) || isXSSAttempt(s.cost)) { - reject(new HttpError(403, 'Injection attempt detected, aborting the request.')) - } else { - let query = - 'INSERT INTO spell (name, description' - - if (s.level !== null) { query += ', level' } - if (s.charge !== null) { query += ', charge' } - if (s.cost !== null) { query += ', cost' } - if (s.is_ritual !== null) { query += ', is_ritual' } - - query += `) VALUES (${db.escape(s.name)}, ${db.escape(s.description)}` - - if (s.level !== null) { query += `, ${s.level}` } - if (s.charge !== null) { query += `, ${s.charge}` } - if (s.cost !== null) { query += `, ${db.escape(s.cost)}` } - if (s.is_ritual !== null) { query += `, ${s.is_ritual}` } - - query += ')' - - db.query(query, async (err, result) => { - if (err) { - reject(new HttpError(500, 'Database error')) - } - console.log(`Inserted "${s.name}" with ID ${result.insertId}, affecting ${result.affectedRows} row(s)`) - - const new_spell_id = result.insertId - - let addSchoolsData = () => { - return new Promise((resolve, reject) => { - if (s.schools !== null) { - if (s.schools.length > 0) { - for (let i = 0; i < s.schools.length; i++) { - if (!regexInt.test(s.schools[i].id)) { - reject(new HttpError(403, 'Query error - School ID should be an integer !')) - } - - let insert_schools_query = `INSERT INTO spells_schools (id_spell, id_school) VALUES (${new_spell_id}, ${s.schools[i].id})` - - db.query(insert_schools_query, async (err, result) => { - if (err) { - reject(new HttpError(404, 'Database error - No schools matching this ID')) - } else { - console.log(`Associated school ID ${s.schools[i].id} to spell ID ${new_spell_id}, affecting ${result.affectedRows} row(s)`) - resolve() - } - }) - } - } else { - resolve() - } - } else { - resolve() - } - }) - } - - let addVariablesData = () => { - return new Promise((resolve, reject) => { - if (s.variables !== null) { - if (s.variables.length > 0) { - for (let i = 0; i < s.variables.length; i++) { - if (!regexInt.test(s.variables[i].id)) { - reject(new HttpError(403, 'Query error - Variable ID should be an integer !')) - } - - let insert_variables_query = `INSERT INTO spells_variables (id_spell, id_variable) VALUES (${new_spell_id}, ${s.variables[i].id})` - db.query(insert_variables_query, async (err, result) => { - if (err) { - reject(new HttpError(404, 'Database error - No variables matching this ID')) - } else { - console.log(`Associated variable ID ${s.variables[i].id} to spell ID ${new_spell_id}, affecting ${result.affectedRows} row(s)`) - resolve() - } - }) - } - } else { - resolve() - } - } else { - resolve() - } - }) - } - - let addIngredientsData = () => { - return new Promise((resolve, reject) => { - if (s.ingredients !== null) { - if (s.ingredients.length > 0) { - for (let i = 0; i < s.ingredients.length; i++) { - if (!regexInt.test(s.ingredients[i].id)) { - reject(new HttpError(403, 'Query error - Ingredient ID should be an integer !')) - } - - let insert_ingredients_query = `INSERT INTO spells_ingredients (id_spell, id_ingredient) VALUES (${new_spell_id}, ${s.ingredients[i].id})` - db.query(insert_ingredients_query, async (err, result) => { - if (err) { - reject(new HttpError(404, 'Database error - No ingredients matching this ID')) - } else { - console.log(`Associated ingredient ID ${s.ingredients[i].id} to spell ID ${new_spell_id}, affecting ${result.affectedRows} row(s)`) - resolve() - } - }) - } - } else { - resolve() - } - } else { - resolve() - } - }) - } - - Promise.all([addSchoolsData(), addVariablesData(), addIngredientsData()]) - .then(() => { - resolve(getSpell(new_spell_id)) - }) - .catch(err => { - reject(err) - }) - }) - } - }).catch(err => { + return Spells.addOne(s) + .catch(err => { + console.log(err) throw err }) } @@ -259,186 +94,15 @@ router.post('/', async (req, res) => { // UPDATE ONE ------------------ -const updateSpell = (s, id) => { - return new Promise( async (resolve, reject) => { - - // Check if spell exists - let old_spell = await getSpell(id) - .catch(err => { - reject(err) - }) - - // Checks if body exists and if the model fits, and throws errors if it doesn't - if (isEmptyObject(s)) { - reject(new HttpError(403, "Error: Spell cannot be nothing !")) - } else if (!v.validate(s, Spell).valid) { - reject(new HttpError(403, "Error: Schema is not valid - " + v.validate(s, Spell).errors)) - } else if (isXSSAttempt(s.name) || isXSSAttempt(s.description) || isXSSAttempt(s.cost)) { - reject(new HttpError(403, 'Injection attempt detected, aborting the request.')) - } else { - - let updateSchoolsData = () => { - return new Promise((resolve, reject) => { - if (s.schools !== null) { - if (s.schools.length > 0) { - let delete_schools_query = - `DELETE FROM spells_schools WHERE id_spell = ${old_spell.id}` - - db.query(delete_schools_query, async (err, result) => { - if (err) { - reject(new HttpError(500, 'Database error - Spell school deletion failed.')) - } - }) - - for (let i = 0; i < s.schools.length; i++) { - if (!regexInt.test(s.schools[i].id)) { - reject(new HttpError(403, 'Query error - School ID should be an integer !')) - } else {} - - let update_schools_query = `INSERT INTO spells_schools (id_spell, id_school) VALUES (${old_spell.id}, ${s.schools[i].id})` - db.query(update_schools_query, async (err, result) => { - if (err) { - reject(new HttpError(404, 'Database error - No schools matching this ID')) - } else { - console.log(`Updated association school ID ${s.schools[i].id} to spell ID ${old_spell.id}`) - resolve() - } - }) - } - } else { - resolve() - } - } else { - resolve() - } - }) - } - - let updateVariablesData = () => { - return new Promise((resolve, reject) => { - if (s.variables !== null) { - if (s.variables.length > 0) { - let delete_variables_query = - `DELETE FROM spells_variables WHERE id_spell = ${old_spell.id}` - - db.query(delete_variables_query, async (err, result) => { - if (err) { - reject(new HttpError(500, 'Database error - Spell variable deletion failed.')) - } - }) - - for (let i = 0; i < s.variables.length; i++) { - if (!regexInt.test(s.variables[i].id)) { - reject(new HttpError(403, 'Query error - Variable ID should be an integer !')) - } - - let update_variables_query = `INSERT INTO spells_variables (id_spell, id_variable) VALUES (${old_spell.id}, ${s.variables[i].id})` - db.query(update_variables_query, async (err, result) => { - if (err) { - reject(new HttpError(404, 'Database error - No variables matching this ID')) - } else { - console.log(`Updated variable ID "${s.variables[i].id}" to spell ID ${old_spell.id}`) - resolve() - } - }) - } - } else { - resolve() - } - } else { - resolve() - } - }) - } - - let updateIngredientsData = () => { - return new Promise((resolve, reject) => { - if (s.ingredients !== null) { - if (s.ingredients.length > 0) { - let delete_ingredients_query = - `DELETE FROM spells_ingredients WHERE id_spell = ${old_spell.id}` - - db.query(delete_ingredients_query, async (err, result) => { - if (err) { - reject(new HttpError(500, 'Database error - Spell ingredients deletion failed.')) - } - console.log(result) - }) - - // Loops over ingredients query - for (let i = 0; i < s.ingredients.length; i++) { - if (!regexInt.test(s.ingredients[i].id)) { - reject(new HttpError(403, 'Query error - Ingredient ID should be an integer !')) - } - - let update_ingredients_query = `INSERT INTO spells_ingredients (id_spell, id_ingredient) VALUES (${old_spell.id}, ${s.ingredients[i].id})` - db.query(update_ingredients_query, async (err, result) => { - if (err) { - reject(new HttpError(404, 'Database error - No ingredients matching this ID')) - } else { - console.log(`Updated ingredient ID "${s.ingredients[i].id}" to spell ID ${old_spell.id}`) - resolve() - } - }) - } - } else { - resolve() - } - } else { - resolve() - } - }) - } - - let updateSpellData = () => { - return new Promise((resolve, reject) => { - let update_spell_query = - 'UPDATE spell SET ' - - if (s.name !== null) { update_spell_query += `name = "${s.name}" ` } - if (s.description !== null) { update_spell_query += `, description = "${s.description}" ` } - if (s.level !== null) { update_spell_query += `, level = ${s.level} ` } - if (s.charge !== null) { update_spell_query += `, charge = ${s.charge} ` } - if (s.cost !== null) { update_spell_query += `, cost = "${s.cost}" ` } - if (s.is_ritual !== null) { update_spell_query += `, is_ritual = ${s.is_ritual} ` } - - update_spell_query += ` WHERE id = ${db.escape(id)}` - - db.query(update_spell_query, async (err, result) => { - if (err) { - reject(new HttpError(500, 'Database error - Spell update failed')) - } else { - console.log(`Updated "${s.name}" on ID ${old_spell.id}, affecting ${result.affectedRows} row(s)`) - resolve() - } - }) - }) - } - - const sub_promises = [ - updateSchoolsData(), - updateVariablesData(), - updateIngredientsData() - ] - - Promise.all(sub_promises) - .then(() => { - updateSpellData() - }) - .then(() => { - resolve(getSpell(old_spell.id)) - }) - .catch(err => { - reject(err) - }) - } - }) +const updateSpell = (id, s) => { + return Spells.updateOne(id, s) .catch(err => { + console.log(err) throw err }) } router.put('/:id/', async (req, res) => { - updateSpell(req.body, req.params.id) + updateSpell(req.params.id, req.body) .then(v => { res.setHeader('Content-Type', 'application/json;charset=utf-8') res.send(JSON.stringify(v)) @@ -456,92 +120,9 @@ router.put('/:id/', async (req, res) => { // DELETE ONE ------------------ const deleteSpell = (id) => { - return new Promise(async (resolve, reject) => { - - // Check if spell exists - let old_spell = await getSpell(id) - .catch(() => { - reject((new HttpError(404, 'No spell matching this ID'))) - }) - - let deleteSchoolsData = () => { - return new Promise((resolve, reject) => { - let delete_schools_query = `DELETE FROM spells_schools WHERE id_spell = ${db.escape(id)}` - db.query(delete_schools_query, async (err, result) => { - if (err) { - reject(new HttpError(500, 'Spell schools deletion failed')) - } else { - console.log(`Deleted schools associated to spell ID ${db.escape(id)}`) - resolve() - } - }) - }) - } - - let deleteVariablesData = () => { - return new Promise((resolve, reject) => { - let delete_variables_query = `DELETE FROM spells_variables WHERE id_spell = ${db.escape(id)}` - db.query(delete_variables_query, async (err, result) => { - if (err) { - console.log(err) - reject(new HttpError(500, 'Spell variables deletion failed')) - } else { - console.log(`Deleted variables associated to spell ID ${db.escape(id)}`) - resolve() - } - }) - }) - } - - let deleteIngredientsData = () => { - return new Promise((resolve, reject) => { - let delete_ingredients_query = `DELETE FROM spells_ingredients WHERE id_spell = ${db.escape(id)}` - db.query(delete_ingredients_query, async (err, result) => { - if (err) { - console.log(err) - reject(new HttpError(500, 'Spell ingredients deletion failed')) - } else { - console.log(`Deleted ingredients associated to spell ID ${db.escape(id)}`) - resolve() - } - }) - }) - } - - let deleteSpellData = () => { - return new Promise((resolve, reject) => { - let delete_spell_query = `DELETE FROM spell WHERE id = ${db.escape(id)}` - db.query(delete_spell_query, async (err, result) => { - if (err) { - console.log(err) - reject(new HttpError(500, 'Spell deletion failed')) - } else { - console.log(`Deleted spell ID ${db.escape(id)}, affecting ${result.affectedRows} rows`) - resolve() - } - }) - }) - } - - const promises = [ - deleteSchoolsData(), - deleteVariablesData(), - deleteIngredientsData() - ] - - Promise.all(promises) - .then(() => { - deleteSpellData() - let response = { - message: `Spell ID ${id} was successfully deleted.` - } - resolve(response) - }) - .catch(err => { - reject(err) - }) - }) + return Spells.deleteOne(id) .catch(err => { + console.log(err) throw err }) } @@ -562,16 +143,17 @@ router.delete('/:id/', async (req, res) => { }) -// Param validation for single spell +// Param validation for ID // (check if id is int) (could be refactored) router.param('id', (req, res, next, id) => { try { if (regexInt.test(id)) { next() } else { - throw new HttpError(403, 'Provided ID must be an integer and not zero') + throw new Error; } } catch (err) { + err = new HttpError(403, 'Provided ID must be an integer and not zero') res.status(err.code).send(JSON.stringify( { "error": err.message, @@ -581,107 +163,4 @@ router.param('id', (req, res, next, id) => { } }) -// SHARED FUNCTIONS ------------------ - -// Builds the associated infos for a given spell object -const buildSpell = async (spell) => { - - // Fetches the spell's schools - let fetchSpellSchoolData = (s) => { - return new Promise((resolve, reject) => { - - if (s == null) { reject(new HttpError(404, "Error: No spell matching this ID"))} - - let query = - "SELECT school.id, school.name " + - "FROM spells_schools AS sc " + - "INNER JOIN school AS school ON sc.id_school = school.id " + - "WHERE sc.id_spell = " + s.id - - db.query(query, (err, result) => { - if (err) { - reject(new HttpError(500, 'Database error')) - } else { - s.schools = result - resolve(s) - } - }) - }) - } - - // Fetches the spell's variables - let fetchSpellVariablesData = (s) => { - return new Promise((resolve, reject) => { - - if (s == null) { reject(new HttpError(404, "Error: No spell matching this ID"))} - - let query = - "SELECT variable.id, variable.description " + - "FROM spells_variables AS sv " + - "INNER JOIN variable AS variable ON sv.id_variable = variable.id " + - "WHERE sv.id_spell = " + s.id - - db.query(query, (err, result) => { - if (err) { - reject(new HttpError(500, 'Database error')) - } else { - s.variables = result - resolve(s) - } - }) - }) - } - - // Fetches the spell's ingredients - let fetchSpellIngredientsData = (s) => { - return new Promise((resolve, reject) => { - - if (s == null) { reject(new HttpError(404, "Error: No spell matching this ID"))} - - let query = - "SELECT ingredient.id, ingredient.name " + - "FROM spells_ingredients AS si " + - "INNER JOIN ingredient AS ingredient ON si.id_ingredient = ingredient.id " + - "WHERE si.id_spell = " + s.id - - db.query(query, (err, result) => { - if (err) { - reject(new HttpError(500, 'Database error')) - } else { - s.ingredients = result - resolve(s) - } - }) - }) - } - - // Builds the spell and returns it - let s = await fetchSpellSchoolData(spell) - .then(s => { return fetchSpellVariablesData(s) }) - .then(s => { return fetchSpellIngredientsData(s) }) - .catch(err => { - throw err - }) - - return s -} - -// Check if object is null -const isEmptyObject = (obj) => { - if (Object.keys(obj).length === 0 && obj.constructor === Object) { - return true - } else { - return false - } -} - -// Check if script injection attempt -const isXSSAttempt = (string) => { - if (regexXSS.test(string)) { - return true - } else { - return false - } -} - module.exports = router diff --git a/routes/users.js b/routes/users.js index e62360a..951aab9 100644 --- a/routes/users.js +++ b/routes/users.js @@ -1,45 +1,28 @@ +'use strict' + // Router const express = require('express') let router = express.Router() // Connection -const connection = require('../database/connection') +const connection = require('../database/bookshelf') const db = connection.db -// Hashing and passwords -const bcrypt = require('bcrypt') +// Repository +const UserRepository = require('../repositories/user-repository'); +const Users = new UserRepository(); -// Validations const regexInt = RegExp(/^[1-9]\d*$/) -const regexXSS = RegExp(/<[^>]*script/) - -// Model validation -const Validator = require('jsonschema').Validator -const v = new Validator() -const User = require("../models/User") -v.addSchema(User, "/UserModel") // Error handling -const { HttpError } = require('../models/Errors') +const { HttpError } = require('../validations/Errors') // ROUTES // GET ALL ------------------ const getUsers = () => { - return new Promise((resolve, reject) => { - - let query = "SELECT DISTINCT * FROM user" - - db.query(query, async (err, result) => { - if (err) { - reject(new HttpError(500, 'Database error')) - } else if (result.length == 0) { - reject(new HttpError(404, 'No users were found')) - } else { - resolve(result) - } - }) - }) + return Users.getAll() .catch(err => { + console.log(err) throw err }) } @@ -62,21 +45,9 @@ router.get('/', async (req, res) => { // GET ONE ------------------ const getUser = (id) => { - return new Promise((resolve, reject) => { - - let query = "SELECT * FROM user WHERE id = " + db.escape(id) - - db.query(query, async (err, result) => { - if (err) { - reject(new HttpError(500, 'Database error')) - } else if (result.length == 0) { - reject(new HttpError(404, 'No User matching this ID')) - } else { - resolve(result) - } - }) - }) + return Users.getOne(id) .catch(err => { + console.log(err) throw err }) } @@ -211,33 +182,11 @@ router.param('id', (req, res, next, id) => { if (regexInt.test(id)) { next() } else { - throw new HttpError(403, 'Provided ID must be an integer and not zero') + new Error } } catch (err) { - res.status(err.code).send(JSON.stringify( - { - "error": err.message, - }) - ) + throw new HttpError(403, 'Provided ID must be an integer and not zero') } }) -// Check if object is null -const isEmptyObject = (obj) => { - if (Object.keys(obj).length === 0 && obj.constructor === Object) { - return true - } else { - return false - } -} - -// Check if script injection attempt -const isXSSAttempt = (string) => { - if (regexXSS.test(string)) { - return true - } else { - return false - } -} - module.exports = router \ No newline at end of file diff --git a/routes/variables.js b/routes/variables.js new file mode 100644 index 0000000..a4e649a --- /dev/null +++ b/routes/variables.js @@ -0,0 +1,165 @@ +'use strict' + +// Router +const express = require('express') +let router = express.Router() + +// Connection +const connection = require('../database/bookshelf') +const db = connection.db + +// Repository +const VariableRepository = require('../repositories/variable-repository'); +const Variables = new VariableRepository(); + +const regexInt = RegExp(/^[1-9]\d*$/) + +// Error handling +const { HttpError } = require('../validations/Errors') + +// ROUTES +// GET ALL ------------------ +const getvariables = () => { + return Variables.getAll() + .catch(err => { + console.log(err) + throw err + }) +} +router.get('/', async (req, res) => { + getvariables() + .then(v => { + res.setHeader('Content-Type', 'application/json;charset=utf-8') + res.end(JSON.stringify(v)) + }) + .catch(err => { + res.status(err.code).send(JSON.stringify( + { + "error": err.message, + "code": err.code + }) + ) + }) +}) + + +// GET ONE ------------------ +const getVariable = (id) => { + return Variables.getOne(id) + .catch(err => { + console.log(err) + throw err + }) +} +router.get('/:id/', async (req, res) => { + getVariable(req.params.id) + .then(v => { + res.setHeader('Content-Type', 'application/json;charset=utf-8') + res.end(JSON.stringify(v)) + }) + .catch(err => { + res.status(err.code).send(JSON.stringify( + { + "error": err.message, + "code": err.code + }) + ) + }) +}) + + +// CREATE ONE ------------------ +const addVariable = (vr) => { + return Variables.addOne(vr) + .catch(err => { + console.log(err) + throw err + }) +} +router.post('/', async (req, res) => { + addVariable(req.body) + .then(v => { + res.setHeader('Content-Type', 'application/json;charset=utf-8') + res.send(JSON.stringify(v)) + }) + .catch(err => { + res.status(err.code).send(JSON.stringify( + { + "error": err.message, + "code": err.code + }) + ) + }) +}) + + +// UPDATE ONE ------------------ +const updateVariable = (id, vr) => { + return Variables.updateOne(id, vr) + .catch(err => { + console.log(err) + throw err + }) +} +router.put('/:id/', async (req, res) => { + updateVariable(req.params.id, req.body) + .then(v => { + res.setHeader('Content-Type', 'application/json;charset=utf-8') + res.send(JSON.stringify(v)) + }) + .catch(err => { + res.status(err.code).send(JSON.stringify( + { + "error": err.message, + "code": err.code + }) + ) + }) +}) + + +// DELETE ONE ------------------ +const deleteVariable = (id) => { + return Variables.deleteOne(id) + .catch(err => { + console.log(err) + throw err + }) +} +router.delete('/:id/', async (req, res) => { + deleteVariable(req.params.id) + .then(v => { + res.setHeader('Content-Type', 'application/json;charset=utf-8') + res.send(JSON.stringify(v)) + }) + .catch(err => { + res.status(err.code).send(JSON.stringify( + { + "error": err.message, + "code": err.code + }) + ) + }) +}) + +// Param validation for ID +// (check if id is int) (could be refactored) +router.param('id', (req, res, next, id) => { + try { + if (regexInt.test(id)) { + next() + } else { + throw new Error; + } + } catch (err) { + err = new HttpError(403, 'Provided ID must be an integer and not zero') + res.status(err.code).send(JSON.stringify( + { + "error": err.message, + "code": err.code + }) + ) + } +}) + +module.exports = router \ No newline at end of file diff --git a/models/Errors.js b/validations/Errors.js similarity index 100% rename from models/Errors.js rename to validations/Errors.js diff --git a/validations/IngredientValidation.js b/validations/IngredientValidation.js new file mode 100644 index 0000000..7e7ef68 --- /dev/null +++ b/validations/IngredientValidation.js @@ -0,0 +1,11 @@ +const Ingredient = { + "id": "/IngredientValidation", + "type": Object, + "properties": { + "name": { "type": "string" }, + "description": { "type": "string" } + }, + "required": ["name", "description"] +} + +module.exports = Ingredient \ No newline at end of file diff --git a/validations/MetaSchoolValidation.js b/validations/MetaSchoolValidation.js new file mode 100644 index 0000000..0bbcf23 --- /dev/null +++ b/validations/MetaSchoolValidation.js @@ -0,0 +1,12 @@ +const MetaSchool = { + "id": "/MetaSchoolValidation", + "type": Object, + "properties": { + "name": { "type": "string" }, + "description": { "type": "string" }, + "schools": { "type": "array" } + }, + "required": ["name", "description"] +} + +module.exports = MetaSchool \ No newline at end of file diff --git a/models/School.js b/validations/SchoolValidation.js similarity index 55% rename from models/School.js rename to validations/SchoolValidation.js index fe1067c..f2dd21d 100644 --- a/models/School.js +++ b/validations/SchoolValidation.js @@ -1,12 +1,12 @@ const School = { - "id": "/SchoolModel", + "id": "/SchoolValidation", "type": Object, "properties": { "name": { "type": "string" }, "description": { "type": "string" }, - "id_meta_school": { "type": "number" }, + "meta_school_id": { "type": "number" }, }, - "required": ["name", "description", "id_meta_school"] + "required": ["name", "description", "meta_school_id"] } module.exports = School \ No newline at end of file diff --git a/models/Spell.js b/validations/SpellValidation.js similarity index 97% rename from models/Spell.js rename to validations/SpellValidation.js index 38284fb..4ae434b 100644 --- a/models/Spell.js +++ b/validations/SpellValidation.js @@ -1,5 +1,5 @@ const Spell = { - "id": "/SpellModel", + "id": "/SpellValidation", "type": Object, "properties": { "name": { "type": "string" }, diff --git a/models/User.js b/validations/UserValidation.js similarity index 90% rename from models/User.js rename to validations/UserValidation.js index 451adad..1dc9290 100644 --- a/models/User.js +++ b/validations/UserValidation.js @@ -1,5 +1,5 @@ const User = { - "id": "/UserModel", + "id": "/UserValidation", "type": Object, "properties": { "name": { "type": "string" }, diff --git a/validations/VariableValidation.js b/validations/VariableValidation.js new file mode 100644 index 0000000..29cf829 --- /dev/null +++ b/validations/VariableValidation.js @@ -0,0 +1,10 @@ +const Variable = { + "id": "/VariableValidation", + "type": Object, + "properties": { + "description": { "type": "string" }, + }, + "required": ["description"] +} + +module.exports = Variable \ No newline at end of file