diff --git a/config/custom-environment-variables.json b/config/custom-environment-variables.json index 3e0b0287..82606743 100644 --- a/config/custom-environment-variables.json +++ b/config/custom-environment-variables.json @@ -38,5 +38,6 @@ "AUTH0_CLIENT_ID": "AUTH0_CLIENT_ID", "AUTH0_CLIENT_SECRET": "AUTH0_CLIENT_SECRET", "AUTH0_AUDIENCE": "AUTH0_AUDIENCE", - "TOKEN_CACHE_TIME" : "TOKEN_CACHE_TIME" + "TOKEN_CACHE_TIME" : "TOKEN_CACHE_TIME", + "whitelistedOriginsForUserIdAuth": "WHITELISTED_ORIGINS_FOR_USERID_AUTH" } diff --git a/config/default.json b/config/default.json index 556a5a10..e2b2d11d 100644 --- a/config/default.json +++ b/config/default.json @@ -46,5 +46,6 @@ "AUTH0_CLIENT_SECRET": "", "AUTH0_AUDIENCE": "", "AUTH0_URL": "", - "TOKEN_CACHE_TIME": "" + "TOKEN_CACHE_TIME": "", + "whitelistedOriginsForUserIdAuth": "[\"https:\/\/topcoder-newauth.auth0.com\/\",\"https:\/\/api.topcoder-dev.com\"]" } diff --git a/config/sample.local.js b/config/sample.local.js index 058f9089..7a1b2a69 100644 --- a/config/sample.local.js +++ b/config/sample.local.js @@ -28,6 +28,7 @@ if (process.env.NODE_ENV === 'test') { indexName: 'projects', docType: 'projectV4' }, + whitelistedOriginsForUserIdAuth: "[\"\"]", }; } module.exports = config; diff --git a/config/test.json b/config/test.json index ab652133..23ca972e 100644 --- a/config/test.json +++ b/config/test.json @@ -18,5 +18,6 @@ "maxPoolSize": 50, "minPoolSize": 4, "idleTimeout": 1000 - } + }, + "whitelistedOriginsForUserIdAuth": "[\"\"]" } diff --git a/migrations/20180824_milestone_templates_metadata.sql b/migrations/20180824_milestone_templates_metadata.sql new file mode 100644 index 00000000..8962f98e --- /dev/null +++ b/migrations/20180824_milestone_templates_metadata.sql @@ -0,0 +1,27 @@ +-- +-- UPDATE EXISTING TABLES: +-- product_milestone_templates: +-- removed constraint `product_milestone_templates_productTemplateId_fkey` +-- changed column `productTemplateId` to `referenceId` +-- added column `reference` +-- added column `metadata` +-- changed table name to `milestone_templates` + +-- +-- product_milestone_templates +-- +ALTER TABLE product_milestone_templates DROP CONSTRAINT "product_milestone_templates_productTemplateId_fkey"; + +ALTER TABLE product_milestone_templates RENAME COLUMN "productTemplateId" TO referenceId; + +ALTER TABLE product_milestone_templates ADD COLUMN "reference" character varying(45); +UPDATE product_milestone_templates set reference='productTemplate' where reference is null; +ALTER TABLE product_milestone_templates ALTER COLUMN "reference" SET NOT NULL; + +ALTER TABLE product_milestone_templates ADD COLUMN "metadata" json; +UPDATE product_milestone_templates set metadata='{}' where metadata is null; +ALTER TABLE product_milestone_templates ALTER COLUMN "metadata" SET NOT NULL; + +ALTER TABLE product_milestone_templates RENAME TO milestone_templates; + + diff --git a/migrations/20180827_project_phases_order.sql b/migrations/20180827_project_phases_order.sql new file mode 100644 index 00000000..4049c15a --- /dev/null +++ b/migrations/20180827_project_phases_order.sql @@ -0,0 +1,9 @@ +-- +-- UPDATE EXISTING TABLES: +-- project_phases: +-- added column `order` + +-- +-- project_phases +-- +ALTER TABLE project_phases ADD COLUMN "order" integer NULL; diff --git a/package-lock.json b/package-lock.json index 88934335..ccc64298 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,8 +9,8 @@ "resolved": "https://registry.npmjs.org/@segment/loosely-validate-event/-/loosely-validate-event-1.1.2.tgz", "integrity": "sha1-13hAmZ4/fkPnSzsNQzkcFSb3k7g=", "requires": { - "component-type": "1.2.1", - "join-component": "1.1.0" + "component-type": "^1.2.1", + "join-component": "^1.1.0" } }, "@types/body-parser": { @@ -18,8 +18,8 @@ "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.16.8.tgz", "integrity": "sha512-BdN2PXxOFnTXFcyONPW6t0fHjz2fvRZHVMFpaS0wYr+Y8fWEaNOs4V8LEu/fpzQlMx+ahdndgTaGTwPC+J/EeA==", "requires": { - "@types/express": "4.0.39", - "@types/node": "8.5.1" + "@types/express": "*", + "@types/node": "*" } }, "@types/express": { @@ -27,9 +27,9 @@ "resolved": "https://registry.npmjs.org/@types/express/-/express-4.0.39.tgz", "integrity": "sha512-dBUam7jEjyuEofigUXCtublUHknRZvcRgITlGsTbFgPvnTwtQUt2NgLakbsf+PsGo/Nupqr3IXCYsOpBpofyrA==", "requires": { - "@types/body-parser": "1.16.8", - "@types/express-serve-static-core": "4.0.57", - "@types/serve-static": "1.13.1" + "@types/body-parser": "*", + "@types/express-serve-static-core": "*", + "@types/serve-static": "*" } }, "@types/express-jwt": { @@ -37,8 +37,8 @@ "resolved": "https://registry.npmjs.org/@types/express-jwt/-/express-jwt-0.0.34.tgz", "integrity": "sha1-/b7kxq9cCiRu8qkz9VGZc8dxfwI=", "requires": { - "@types/express": "4.0.39", - "@types/express-unless": "0.0.32" + "@types/express": "*", + "@types/express-unless": "*" } }, "@types/express-serve-static-core": { @@ -46,7 +46,7 @@ "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.0.57.tgz", "integrity": "sha512-QLAHjdLwEICm3thVbXSKRoisjfgMVI4xJH/HU8F385BR2HI7PmM6ax4ELXf8Du6sLmSpySXMYaI+xc//oQ/IFw==", "requires": { - "@types/node": "8.5.1" + "@types/node": "*" } }, "@types/express-unless": { @@ -54,7 +54,7 @@ "resolved": "https://registry.npmjs.org/@types/express-unless/-/express-unless-0.0.32.tgz", "integrity": "sha512-6YpJyFNlDDnPnRjMOvJCoDYlSDDmG/OEEUsPk7yhNkL4G9hUYtgab6vi1CcWsGSSSM0CsvNlWTG+ywAGnvF03g==", "requires": { - "@types/express": "4.0.39" + "@types/express": "*" } }, "@types/geojson": { @@ -77,8 +77,8 @@ "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.1.tgz", "integrity": "sha512-jDMH+3BQPtvqZVIcsH700Dfi8Q3MIcEx16g/VdxjoqiGR/NntekB10xdBpirMKnPe9z2C5cBmL0vte0YttOr3Q==", "requires": { - "@types/express-serve-static-core": "4.0.57", - "@types/mime": "2.0.0" + "@types/express-serve-static-core": "*", + "@types/mime": "*" } }, "abbrev": { @@ -92,7 +92,7 @@ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.4.tgz", "integrity": "sha1-hiRnWMfdbSGmR0/whKR0DsBesh8=", "requires": { - "mime-types": "2.1.17", + "mime-types": "~2.1.16", "negotiator": "0.6.1" } }, @@ -108,7 +108,7 @@ "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", "dev": true, "requires": { - "acorn": "3.3.0" + "acorn": "^3.0.4" }, "dependencies": { "acorn": { @@ -125,8 +125,8 @@ "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", "dev": true, "requires": { - "co": "4.6.0", - "json-stable-stringify": "1.0.1" + "co": "^4.6.0", + "json-stable-stringify": "^1.0.1" } }, "ajv-keywords": { @@ -141,9 +141,9 @@ "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", "dev": true, "requires": { - "kind-of": "3.2.2", - "longest": "1.0.1", - "repeat-string": "1.6.1" + "kind-of": "^3.0.2", + "longest": "^1.0.1", + "repeat-string": "^1.5.2" } }, "amdefine": { @@ -157,10 +157,10 @@ "resolved": "https://registry.npmjs.org/amqplib/-/amqplib-0.5.1.tgz", "integrity": "sha1-fMz+ur5WwumE6noiQ/fO/m+/xs8=", "requires": { - "bitsyntax": "0.0.4", - "bluebird": "3.5.1", + "bitsyntax": "~0.0.4", + "bluebird": "^3.4.6", "buffer-more-ints": "0.0.2", - "readable-stream": "1.1.14" + "readable-stream": "1.x >=1.1.9" } }, "analytics-node": { @@ -168,15 +168,15 @@ "resolved": "https://registry.npmjs.org/analytics-node/-/analytics-node-2.4.1.tgz", "integrity": "sha1-H5bI64h7bEdpEESsf8mhIx+wIPc=", "requires": { - "@segment/loosely-validate-event": "1.1.2", - "clone": "2.1.1", - "commander": "2.11.0", - "crypto-token": "1.0.1", - "debug": "2.6.9", - "lodash": "4.17.4", - "remove-trailing-slash": "0.1.0", - "superagent": "3.8.0", - "superagent-retry": "0.6.0" + "@segment/loosely-validate-event": "^1.1.2", + "clone": "^2.1.1", + "commander": "^2.9.0", + "crypto-token": "^1.0.1", + "debug": "^2.6.2", + "lodash": "^4.17.4", + "remove-trailing-slash": "^0.1.0", + "superagent": "^3.5.0", + "superagent-retry": "^0.6.0" } }, "ansi-align": { @@ -185,7 +185,7 @@ "integrity": "sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=", "dev": true, "requires": { - "string-width": "2.1.1" + "string-width": "^2.0.0" }, "dependencies": { "ansi-regex": { @@ -206,8 +206,8 @@ "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "4.0.0" + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" } }, "strip-ansi": { @@ -216,7 +216,7 @@ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { - "ansi-regex": "3.0.0" + "ansi-regex": "^3.0.0" } } } @@ -243,8 +243,8 @@ "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", "dev": true, "requires": { - "micromatch": "2.3.11", - "normalize-path": "2.1.1" + "micromatch": "^2.1.5", + "normalize-path": "^2.0.0" } }, "app-module-path": { @@ -258,7 +258,7 @@ "integrity": "sha1-126/jKlNJ24keja61EpLdKthGZE=", "dev": true, "requires": { - "default-require-extensions": "1.0.0" + "default-require-extensions": "^1.0.0" } }, "archy": { @@ -273,7 +273,7 @@ "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", "dev": true, "requires": { - "sprintf-js": "1.0.3" + "sprintf-js": "~1.0.2" } }, "arr-diff": { @@ -282,7 +282,7 @@ "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", "dev": true, "requires": { - "arr-flatten": "1.1.0" + "arr-flatten": "^1.0.1" } }, "arr-flatten": { @@ -320,7 +320,7 @@ "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", "dev": true, "requires": { - "array-uniq": "1.0.3" + "array-uniq": "^1.0.1" } }, "array-uniq": { @@ -379,8 +379,8 @@ "resolved": "https://registry.npmjs.org/async-listener/-/async-listener-0.6.8.tgz", "integrity": "sha512-1Sy1jDhjlgxcSd9/ICHqiAHT8VSJ9R1lzEyWwP/4Hm9p8nVTNtU0SxG/Z15XHD/aZvQraSw9BpDU3EBcFnOVrw==", "requires": { - "semver": "5.4.1", - "shimmer": "1.1.0" + "semver": "^5.3.0", + "shimmer": "^1.1.0" } }, "asynckit": { @@ -393,13 +393,13 @@ "resolved": "https://registry.npmjs.org/auth0-js/-/auth0-js-9.6.0.tgz", "integrity": "sha1-2a4wFIBzZtO0ecKtGKNTfz4Mlpk=", "requires": { - "base64-js": "1.2.1", - "idtoken-verifier": "1.2.0", - "js-cookie": "2.2.0", - "qs": "6.5.1", - "superagent": "3.8.3", - "url-join": "1.1.0", - "winchan": "0.2.0" + "base64-js": "^1.2.0", + "idtoken-verifier": "^1.2.0", + "js-cookie": "^2.2.0", + "qs": "^6.4.0", + "superagent": "^3.8.2", + "url-join": "^1.1.0", + "winchan": "^0.2.0" }, "dependencies": { "debug": { @@ -430,13 +430,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.1", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "string_decoder": { @@ -444,7 +444,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "5.1.1" + "safe-buffer": "~5.1.0" } }, "superagent": { @@ -452,16 +452,16 @@ "resolved": "https://registry.npmjs.org/superagent/-/superagent-3.8.3.tgz", "integrity": "sha512-GLQtLMCoEIK4eDv6OGtkOoSMt3D+oq0y3dsxMuYuDvaNUvuT8eFBuLmfR0iYYzHC1e8hpzC6ZsxbuP6DIalMFA==", "requires": { - "component-emitter": "1.2.1", - "cookiejar": "2.1.1", - "debug": "3.1.0", - "extend": "3.0.1", - "form-data": "2.3.1", - "formidable": "1.2.1", - "methods": "1.1.2", - "mime": "1.4.1", - "qs": "6.5.1", - "readable-stream": "2.3.6" + "component-emitter": "^1.2.0", + "cookiejar": "^2.1.0", + "debug": "^3.1.0", + "extend": "^3.0.0", + "form-data": "^2.3.1", + "formidable": "^1.2.0", + "methods": "^1.1.1", + "mime": "^1.4.1", + "qs": "^6.5.1", + "readable-stream": "^2.3.5" } } } @@ -473,7 +473,7 @@ "requires": { "buffer": "4.9.1", "crypto-browserify": "1.0.9", - "events": "1.1.1", + "events": "^1.1.1", "jmespath": "0.15.0", "querystring": "0.2.0", "sax": "1.2.1", @@ -498,8 +498,8 @@ "resolved": "https://registry.npmjs.org/axios/-/axios-0.17.1.tgz", "integrity": "sha1-LY4+XQvb1zJ/kbyBT1xXZg+Bgk0=", "requires": { - "follow-redirects": "1.2.6", - "is-buffer": "1.1.6" + "follow-redirects": "^1.2.5", + "is-buffer": "^1.1.5" } }, "babel-cli": { @@ -508,21 +508,21 @@ "integrity": "sha1-UCq1SHTX24itALiHoGODzgPQAvE=", "dev": true, "requires": { - "babel-core": "6.26.0", - "babel-polyfill": "6.26.0", - "babel-register": "6.26.0", - "babel-runtime": "6.26.0", - "chokidar": "1.7.0", - "commander": "2.11.0", - "convert-source-map": "1.5.0", - "fs-readdir-recursive": "1.0.0", - "glob": "7.1.2", - "lodash": "4.17.4", - "output-file-sync": "1.1.2", - "path-is-absolute": "1.0.1", - "slash": "1.0.0", - "source-map": "0.5.7", - "v8flags": "2.1.1" + "babel-core": "^6.26.0", + "babel-polyfill": "^6.26.0", + "babel-register": "^6.26.0", + "babel-runtime": "^6.26.0", + "chokidar": "^1.6.1", + "commander": "^2.11.0", + "convert-source-map": "^1.5.0", + "fs-readdir-recursive": "^1.0.0", + "glob": "^7.1.2", + "lodash": "^4.17.4", + "output-file-sync": "^1.1.2", + "path-is-absolute": "^1.0.1", + "slash": "^1.0.0", + "source-map": "^0.5.6", + "v8flags": "^2.1.1" }, "dependencies": { "babel-runtime": { @@ -531,8 +531,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.1", - "regenerator-runtime": "0.11.0" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } }, "glob": { @@ -541,12 +541,12 @@ "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } } } @@ -557,9 +557,9 @@ "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", "dev": true, "requires": { - "chalk": "1.1.3", - "esutils": "2.0.2", - "js-tokens": "3.0.2" + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" } }, "babel-core": { @@ -568,25 +568,25 @@ "integrity": "sha1-rzL3izGm/O8RnIew/Y2XU/A6C7g=", "dev": true, "requires": { - "babel-code-frame": "6.26.0", - "babel-generator": "6.26.0", - "babel-helpers": "6.24.1", - "babel-messages": "6.23.0", - "babel-register": "6.26.0", - "babel-runtime": "6.26.0", - "babel-template": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0", - "convert-source-map": "1.5.0", - "debug": "2.6.9", - "json5": "0.5.1", - "lodash": "4.17.4", - "minimatch": "3.0.4", - "path-is-absolute": "1.0.1", - "private": "0.1.8", - "slash": "1.0.0", - "source-map": "0.5.7" + "babel-code-frame": "^6.26.0", + "babel-generator": "^6.26.0", + "babel-helpers": "^6.24.1", + "babel-messages": "^6.23.0", + "babel-register": "^6.26.0", + "babel-runtime": "^6.26.0", + "babel-template": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "convert-source-map": "^1.5.0", + "debug": "^2.6.8", + "json5": "^0.5.1", + "lodash": "^4.17.4", + "minimatch": "^3.0.4", + "path-is-absolute": "^1.0.1", + "private": "^0.1.7", + "slash": "^1.0.0", + "source-map": "^0.5.6" }, "dependencies": { "babel-runtime": { @@ -595,8 +595,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.1", - "regenerator-runtime": "0.11.0" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } }, "json5": { @@ -613,10 +613,10 @@ "integrity": "sha1-sv4tgBJkcPXBlELcdXJTqJdxCCc=", "dev": true, "requires": { - "babel-code-frame": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0" + "babel-code-frame": "^6.22.0", + "babel-traverse": "^6.23.1", + "babel-types": "^6.23.0", + "babylon": "^6.17.0" } }, "babel-generator": { @@ -625,14 +625,14 @@ "integrity": "sha1-rBriAHC3n248odMmlhMFN3TyDcU=", "dev": true, "requires": { - "babel-messages": "6.23.0", - "babel-runtime": "6.26.0", - "babel-types": "6.26.0", - "detect-indent": "4.0.0", - "jsesc": "1.3.0", - "lodash": "4.17.4", - "source-map": "0.5.7", - "trim-right": "1.0.1" + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "detect-indent": "^4.0.0", + "jsesc": "^1.3.0", + "lodash": "^4.17.4", + "source-map": "^0.5.6", + "trim-right": "^1.0.1" }, "dependencies": { "babel-runtime": { @@ -641,8 +641,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.1", - "regenerator-runtime": "0.11.0" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } } } @@ -653,10 +653,10 @@ "integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=", "dev": true, "requires": { - "babel-helper-hoist-variables": "6.24.1", - "babel-runtime": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0" + "babel-helper-hoist-variables": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" }, "dependencies": { "babel-runtime": { @@ -665,8 +665,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.1", - "regenerator-runtime": "0.11.0" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } } } @@ -677,10 +677,10 @@ "integrity": "sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=", "dev": true, "requires": { - "babel-helper-function-name": "6.24.1", - "babel-runtime": "6.26.0", - "babel-types": "6.26.0", - "lodash": "4.17.4" + "babel-helper-function-name": "^6.24.1", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "lodash": "^4.17.4" }, "dependencies": { "babel-runtime": { @@ -689,8 +689,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.1", - "regenerator-runtime": "0.11.0" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } } } @@ -701,11 +701,11 @@ "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=", "dev": true, "requires": { - "babel-helper-get-function-arity": "6.24.1", - "babel-runtime": "6.26.0", - "babel-template": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0" + "babel-helper-get-function-arity": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" }, "dependencies": { "babel-runtime": { @@ -714,8 +714,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.1", - "regenerator-runtime": "0.11.0" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } } } @@ -726,8 +726,8 @@ "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=", "dev": true, "requires": { - "babel-runtime": "6.26.0", - "babel-types": "6.26.0" + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" }, "dependencies": { "babel-runtime": { @@ -736,8 +736,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.1", - "regenerator-runtime": "0.11.0" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } } } @@ -748,8 +748,8 @@ "integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=", "dev": true, "requires": { - "babel-runtime": "6.26.0", - "babel-types": "6.26.0" + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" }, "dependencies": { "babel-runtime": { @@ -758,8 +758,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.1", - "regenerator-runtime": "0.11.0" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } } } @@ -770,8 +770,8 @@ "integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=", "dev": true, "requires": { - "babel-runtime": "6.26.0", - "babel-types": "6.26.0" + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" }, "dependencies": { "babel-runtime": { @@ -780,8 +780,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.1", - "regenerator-runtime": "0.11.0" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } } } @@ -792,9 +792,9 @@ "integrity": "sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI=", "dev": true, "requires": { - "babel-runtime": "6.26.0", - "babel-types": "6.26.0", - "lodash": "4.17.4" + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "lodash": "^4.17.4" }, "dependencies": { "babel-runtime": { @@ -803,8 +803,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.1", - "regenerator-runtime": "0.11.0" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } } } @@ -815,12 +815,12 @@ "integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=", "dev": true, "requires": { - "babel-helper-optimise-call-expression": "6.24.1", - "babel-messages": "6.23.0", - "babel-runtime": "6.26.0", - "babel-template": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0" + "babel-helper-optimise-call-expression": "^6.24.1", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" }, "dependencies": { "babel-runtime": { @@ -829,8 +829,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.1", - "regenerator-runtime": "0.11.0" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } } } @@ -841,8 +841,8 @@ "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", "dev": true, "requires": { - "babel-runtime": "6.26.0", - "babel-template": "6.26.0" + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" }, "dependencies": { "babel-runtime": { @@ -851,8 +851,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.1", - "regenerator-runtime": "0.11.0" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } } } @@ -863,7 +863,7 @@ "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", "dev": true, "requires": { - "babel-runtime": "6.26.0" + "babel-runtime": "^6.22.0" }, "dependencies": { "babel-runtime": { @@ -872,8 +872,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.1", - "regenerator-runtime": "0.11.0" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } } } @@ -890,7 +890,7 @@ "integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=", "dev": true, "requires": { - "babel-runtime": "6.26.0" + "babel-runtime": "^6.22.0" }, "dependencies": { "babel-runtime": { @@ -899,8 +899,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.1", - "regenerator-runtime": "0.11.0" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } } } @@ -911,7 +911,7 @@ "integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=", "dev": true, "requires": { - "babel-runtime": "6.26.0" + "babel-runtime": "^6.22.0" }, "dependencies": { "babel-runtime": { @@ -920,8 +920,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.1", - "regenerator-runtime": "0.11.0" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } } } @@ -932,7 +932,7 @@ "integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=", "dev": true, "requires": { - "babel-runtime": "6.26.0" + "babel-runtime": "^6.22.0" }, "dependencies": { "babel-runtime": { @@ -941,8 +941,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.1", - "regenerator-runtime": "0.11.0" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } } } @@ -953,11 +953,11 @@ "integrity": "sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=", "dev": true, "requires": { - "babel-runtime": "6.26.0", - "babel-template": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0", - "lodash": "4.17.4" + "babel-runtime": "^6.26.0", + "babel-template": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "lodash": "^4.17.4" }, "dependencies": { "babel-runtime": { @@ -966,8 +966,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.1", - "regenerator-runtime": "0.11.0" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } } } @@ -978,15 +978,15 @@ "integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=", "dev": true, "requires": { - "babel-helper-define-map": "6.26.0", - "babel-helper-function-name": "6.24.1", - "babel-helper-optimise-call-expression": "6.24.1", - "babel-helper-replace-supers": "6.24.1", - "babel-messages": "6.23.0", - "babel-runtime": "6.26.0", - "babel-template": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0" + "babel-helper-define-map": "^6.24.1", + "babel-helper-function-name": "^6.24.1", + "babel-helper-optimise-call-expression": "^6.24.1", + "babel-helper-replace-supers": "^6.24.1", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" }, "dependencies": { "babel-runtime": { @@ -995,8 +995,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.1", - "regenerator-runtime": "0.11.0" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } } } @@ -1007,8 +1007,8 @@ "integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=", "dev": true, "requires": { - "babel-runtime": "6.26.0", - "babel-template": "6.26.0" + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" }, "dependencies": { "babel-runtime": { @@ -1017,8 +1017,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.1", - "regenerator-runtime": "0.11.0" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } } } @@ -1029,7 +1029,7 @@ "integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=", "dev": true, "requires": { - "babel-runtime": "6.26.0" + "babel-runtime": "^6.22.0" }, "dependencies": { "babel-runtime": { @@ -1038,8 +1038,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.1", - "regenerator-runtime": "0.11.0" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } } } @@ -1050,8 +1050,8 @@ "integrity": "sha1-c+s9MQypaePvnskcU3QabxV2Qj4=", "dev": true, "requires": { - "babel-runtime": "6.26.0", - "babel-types": "6.26.0" + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" }, "dependencies": { "babel-runtime": { @@ -1060,8 +1060,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.1", - "regenerator-runtime": "0.11.0" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } } } @@ -1072,7 +1072,7 @@ "integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=", "dev": true, "requires": { - "babel-runtime": "6.26.0" + "babel-runtime": "^6.22.0" }, "dependencies": { "babel-runtime": { @@ -1081,8 +1081,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.1", - "regenerator-runtime": "0.11.0" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } } } @@ -1093,9 +1093,9 @@ "integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=", "dev": true, "requires": { - "babel-helper-function-name": "6.24.1", - "babel-runtime": "6.26.0", - "babel-types": "6.26.0" + "babel-helper-function-name": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" }, "dependencies": { "babel-runtime": { @@ -1104,8 +1104,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.1", - "regenerator-runtime": "0.11.0" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } } } @@ -1116,7 +1116,7 @@ "integrity": "sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=", "dev": true, "requires": { - "babel-runtime": "6.26.0" + "babel-runtime": "^6.22.0" }, "dependencies": { "babel-runtime": { @@ -1125,8 +1125,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.1", - "regenerator-runtime": "0.11.0" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } } } @@ -1137,9 +1137,9 @@ "integrity": "sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ=", "dev": true, "requires": { - "babel-plugin-transform-es2015-modules-commonjs": "6.26.0", - "babel-runtime": "6.26.0", - "babel-template": "6.26.0" + "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" }, "dependencies": { "babel-runtime": { @@ -1148,8 +1148,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.1", - "regenerator-runtime": "0.11.0" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } } } @@ -1160,10 +1160,10 @@ "integrity": "sha1-DYOUApt9xqvhqX7xgeAHWN0uXYo=", "dev": true, "requires": { - "babel-plugin-transform-strict-mode": "6.24.1", - "babel-runtime": "6.26.0", - "babel-template": "6.26.0", - "babel-types": "6.26.0" + "babel-plugin-transform-strict-mode": "^6.24.1", + "babel-runtime": "^6.26.0", + "babel-template": "^6.26.0", + "babel-types": "^6.26.0" }, "dependencies": { "babel-runtime": { @@ -1172,8 +1172,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.1", - "regenerator-runtime": "0.11.0" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } } } @@ -1184,9 +1184,9 @@ "integrity": "sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM=", "dev": true, "requires": { - "babel-helper-hoist-variables": "6.24.1", - "babel-runtime": "6.26.0", - "babel-template": "6.26.0" + "babel-helper-hoist-variables": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" }, "dependencies": { "babel-runtime": { @@ -1195,8 +1195,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.1", - "regenerator-runtime": "0.11.0" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } } } @@ -1207,9 +1207,9 @@ "integrity": "sha1-rJl+YoXNGO1hdq22B9YCNErThGg=", "dev": true, "requires": { - "babel-plugin-transform-es2015-modules-amd": "6.24.1", - "babel-runtime": "6.26.0", - "babel-template": "6.26.0" + "babel-plugin-transform-es2015-modules-amd": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" }, "dependencies": { "babel-runtime": { @@ -1218,8 +1218,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.1", - "regenerator-runtime": "0.11.0" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } } } @@ -1230,8 +1230,8 @@ "integrity": "sha1-JM72muIcuDp/hgPa0CH1cusnj40=", "dev": true, "requires": { - "babel-helper-replace-supers": "6.24.1", - "babel-runtime": "6.26.0" + "babel-helper-replace-supers": "^6.24.1", + "babel-runtime": "^6.22.0" }, "dependencies": { "babel-runtime": { @@ -1240,8 +1240,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.1", - "regenerator-runtime": "0.11.0" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } } } @@ -1252,12 +1252,12 @@ "integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=", "dev": true, "requires": { - "babel-helper-call-delegate": "6.24.1", - "babel-helper-get-function-arity": "6.24.1", - "babel-runtime": "6.26.0", - "babel-template": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0" + "babel-helper-call-delegate": "^6.24.1", + "babel-helper-get-function-arity": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" }, "dependencies": { "babel-runtime": { @@ -1266,8 +1266,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.1", - "regenerator-runtime": "0.11.0" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } } } @@ -1278,8 +1278,8 @@ "integrity": "sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=", "dev": true, "requires": { - "babel-runtime": "6.26.0", - "babel-types": "6.26.0" + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" }, "dependencies": { "babel-runtime": { @@ -1288,8 +1288,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.1", - "regenerator-runtime": "0.11.0" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } } } @@ -1300,7 +1300,7 @@ "integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=", "dev": true, "requires": { - "babel-runtime": "6.26.0" + "babel-runtime": "^6.22.0" }, "dependencies": { "babel-runtime": { @@ -1309,8 +1309,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.1", - "regenerator-runtime": "0.11.0" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } } } @@ -1321,9 +1321,9 @@ "integrity": "sha1-AMHNsaynERLN8M9hJsLta0V8zbw=", "dev": true, "requires": { - "babel-helper-regex": "6.26.0", - "babel-runtime": "6.26.0", - "babel-types": "6.26.0" + "babel-helper-regex": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" }, "dependencies": { "babel-runtime": { @@ -1332,8 +1332,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.1", - "regenerator-runtime": "0.11.0" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } } } @@ -1344,7 +1344,7 @@ "integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=", "dev": true, "requires": { - "babel-runtime": "6.26.0" + "babel-runtime": "^6.22.0" }, "dependencies": { "babel-runtime": { @@ -1353,8 +1353,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.1", - "regenerator-runtime": "0.11.0" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } } } @@ -1365,7 +1365,7 @@ "integrity": "sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I=", "dev": true, "requires": { - "babel-runtime": "6.26.0" + "babel-runtime": "^6.22.0" }, "dependencies": { "babel-runtime": { @@ -1374,8 +1374,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.1", - "regenerator-runtime": "0.11.0" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } } } @@ -1386,9 +1386,9 @@ "integrity": "sha1-04sS9C6nMj9yk4fxinxa4frrNek=", "dev": true, "requires": { - "babel-helper-regex": "6.26.0", - "babel-runtime": "6.26.0", - "regexpu-core": "2.0.0" + "babel-helper-regex": "^6.24.1", + "babel-runtime": "^6.22.0", + "regexpu-core": "^2.0.0" }, "dependencies": { "babel-runtime": { @@ -1397,8 +1397,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.1", - "regenerator-runtime": "0.11.0" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } } } @@ -1409,7 +1409,7 @@ "integrity": "sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8=", "dev": true, "requires": { - "regenerator-transform": "0.10.1" + "regenerator-transform": "^0.10.0" } }, "babel-plugin-transform-runtime": { @@ -1418,7 +1418,7 @@ "integrity": "sha1-iEkNRGUC6puOfvsP4J7E2ZR5se4=", "dev": true, "requires": { - "babel-runtime": "6.26.0" + "babel-runtime": "^6.22.0" }, "dependencies": { "babel-runtime": { @@ -1427,8 +1427,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.1", - "regenerator-runtime": "0.11.0" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } } } @@ -1439,8 +1439,8 @@ "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=", "dev": true, "requires": { - "babel-runtime": "6.26.0", - "babel-types": "6.26.0" + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" }, "dependencies": { "babel-runtime": { @@ -1449,8 +1449,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.1", - "regenerator-runtime": "0.11.0" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } } } @@ -1461,9 +1461,9 @@ "integrity": "sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM=", "dev": true, "requires": { - "babel-runtime": "6.26.0", - "core-js": "2.5.1", - "regenerator-runtime": "0.10.5" + "babel-runtime": "^6.26.0", + "core-js": "^2.5.0", + "regenerator-runtime": "^0.10.5" }, "dependencies": { "babel-runtime": { @@ -1472,8 +1472,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.1", - "regenerator-runtime": "0.11.0" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" }, "dependencies": { "regenerator-runtime": { @@ -1498,30 +1498,30 @@ "integrity": "sha1-1EBQ1rwsn+6nAqrzjXJ6AhBTiTk=", "dev": true, "requires": { - "babel-plugin-check-es2015-constants": "6.22.0", - "babel-plugin-transform-es2015-arrow-functions": "6.22.0", - "babel-plugin-transform-es2015-block-scoped-functions": "6.22.0", - "babel-plugin-transform-es2015-block-scoping": "6.26.0", - "babel-plugin-transform-es2015-classes": "6.24.1", - "babel-plugin-transform-es2015-computed-properties": "6.24.1", - "babel-plugin-transform-es2015-destructuring": "6.23.0", - "babel-plugin-transform-es2015-duplicate-keys": "6.24.1", - "babel-plugin-transform-es2015-for-of": "6.23.0", - "babel-plugin-transform-es2015-function-name": "6.24.1", - "babel-plugin-transform-es2015-literals": "6.22.0", - "babel-plugin-transform-es2015-modules-amd": "6.24.1", - "babel-plugin-transform-es2015-modules-commonjs": "6.26.0", - "babel-plugin-transform-es2015-modules-systemjs": "6.24.1", - "babel-plugin-transform-es2015-modules-umd": "6.24.1", - "babel-plugin-transform-es2015-object-super": "6.24.1", - "babel-plugin-transform-es2015-parameters": "6.24.1", - "babel-plugin-transform-es2015-shorthand-properties": "6.24.1", - "babel-plugin-transform-es2015-spread": "6.22.0", - "babel-plugin-transform-es2015-sticky-regex": "6.24.1", - "babel-plugin-transform-es2015-template-literals": "6.22.0", - "babel-plugin-transform-es2015-typeof-symbol": "6.23.0", - "babel-plugin-transform-es2015-unicode-regex": "6.24.1", - "babel-plugin-transform-regenerator": "6.26.0" + "babel-plugin-check-es2015-constants": "^6.22.0", + "babel-plugin-transform-es2015-arrow-functions": "^6.22.0", + "babel-plugin-transform-es2015-block-scoped-functions": "^6.22.0", + "babel-plugin-transform-es2015-block-scoping": "^6.24.1", + "babel-plugin-transform-es2015-classes": "^6.24.1", + "babel-plugin-transform-es2015-computed-properties": "^6.24.1", + "babel-plugin-transform-es2015-destructuring": "^6.22.0", + "babel-plugin-transform-es2015-duplicate-keys": "^6.24.1", + "babel-plugin-transform-es2015-for-of": "^6.22.0", + "babel-plugin-transform-es2015-function-name": "^6.24.1", + "babel-plugin-transform-es2015-literals": "^6.22.0", + "babel-plugin-transform-es2015-modules-amd": "^6.24.1", + "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1", + "babel-plugin-transform-es2015-modules-systemjs": "^6.24.1", + "babel-plugin-transform-es2015-modules-umd": "^6.24.1", + "babel-plugin-transform-es2015-object-super": "^6.24.1", + "babel-plugin-transform-es2015-parameters": "^6.24.1", + "babel-plugin-transform-es2015-shorthand-properties": "^6.24.1", + "babel-plugin-transform-es2015-spread": "^6.22.0", + "babel-plugin-transform-es2015-sticky-regex": "^6.24.1", + "babel-plugin-transform-es2015-template-literals": "^6.22.0", + "babel-plugin-transform-es2015-typeof-symbol": "^6.22.0", + "babel-plugin-transform-es2015-unicode-regex": "^6.24.1", + "babel-plugin-transform-regenerator": "^6.24.1" } }, "babel-register": { @@ -1530,13 +1530,13 @@ "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", "dev": true, "requires": { - "babel-core": "6.26.0", - "babel-runtime": "6.26.0", - "core-js": "2.5.1", - "home-or-tmp": "2.0.0", - "lodash": "4.17.4", - "mkdirp": "0.5.1", - "source-map-support": "0.4.18" + "babel-core": "^6.26.0", + "babel-runtime": "^6.26.0", + "core-js": "^2.5.0", + "home-or-tmp": "^2.0.0", + "lodash": "^4.17.4", + "mkdirp": "^0.5.1", + "source-map-support": "^0.4.15" }, "dependencies": { "babel-runtime": { @@ -1545,8 +1545,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.1", - "regenerator-runtime": "0.11.0" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } } } @@ -1556,7 +1556,7 @@ "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.6.1.tgz", "integrity": "sha1-eIuUtvY04luRvWxd9y1GdFevsAA=", "requires": { - "core-js": "2.5.1" + "core-js": "^2.1.0" } }, "babel-template": { @@ -1565,11 +1565,11 @@ "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", "dev": true, "requires": { - "babel-runtime": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0", - "lodash": "4.17.4" + "babel-runtime": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "lodash": "^4.17.4" }, "dependencies": { "babel-runtime": { @@ -1578,8 +1578,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.1", - "regenerator-runtime": "0.11.0" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } } } @@ -1590,15 +1590,15 @@ "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", "dev": true, "requires": { - "babel-code-frame": "6.26.0", - "babel-messages": "6.23.0", - "babel-runtime": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0", - "debug": "2.6.9", - "globals": "9.18.0", - "invariant": "2.2.2", - "lodash": "4.17.4" + "babel-code-frame": "^6.26.0", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "debug": "^2.6.8", + "globals": "^9.18.0", + "invariant": "^2.2.2", + "lodash": "^4.17.4" }, "dependencies": { "babel-runtime": { @@ -1607,8 +1607,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.1", - "regenerator-runtime": "0.11.0" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } } } @@ -1619,10 +1619,10 @@ "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", "dev": true, "requires": { - "babel-runtime": "6.26.0", - "esutils": "2.0.2", - "lodash": "4.17.4", - "to-fast-properties": "1.0.3" + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" }, "dependencies": { "babel-runtime": { @@ -1631,8 +1631,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.1", - "regenerator-runtime": "0.11.0" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } } } @@ -1648,7 +1648,7 @@ "resolved": "https://registry.npmjs.org/backoff/-/backoff-2.5.0.tgz", "integrity": "sha1-9hbtqdPktmuMp/ynn2lXIsX44m8=", "requires": { - "precond": "0.2.3" + "precond": "0.2" } }, "balanced-match": { @@ -1667,7 +1667,7 @@ "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", "optional": true, "requires": { - "tweetnacl": "0.14.5" + "tweetnacl": "^0.14.3" } }, "beeper": { @@ -1706,15 +1706,15 @@ "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", "requires": { "bytes": "3.0.0", - "content-type": "1.0.4", + "content-type": "~1.0.4", "debug": "2.6.9", - "depd": "1.1.1", - "http-errors": "1.6.2", + "depd": "~1.1.1", + "http-errors": "~1.6.2", "iconv-lite": "0.4.19", - "on-finished": "2.3.0", + "on-finished": "~2.3.0", "qs": "6.5.1", "raw-body": "2.3.2", - "type-is": "1.6.15" + "type-is": "~1.6.15" } }, "boom": { @@ -1722,7 +1722,7 @@ "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", "requires": { - "hoek": "4.2.0" + "hoek": "4.x.x" } }, "boxen": { @@ -1731,13 +1731,13 @@ "integrity": "sha1-Px1AMsMP/qnUsCwyLq8up0HcvOU=", "dev": true, "requires": { - "ansi-align": "2.0.0", - "camelcase": "4.1.0", - "chalk": "2.3.0", - "cli-boxes": "1.0.0", - "string-width": "2.1.1", - "term-size": "1.2.0", - "widest-line": "1.0.0" + "ansi-align": "^2.0.0", + "camelcase": "^4.0.0", + "chalk": "^2.0.1", + "cli-boxes": "^1.0.0", + "string-width": "^2.0.0", + "term-size": "^1.2.0", + "widest-line": "^1.0.0" }, "dependencies": { "ansi-regex": { @@ -1752,7 +1752,7 @@ "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", "dev": true, "requires": { - "color-convert": "1.9.0" + "color-convert": "^1.9.0" } }, "camelcase": { @@ -1767,9 +1767,9 @@ "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", "dev": true, "requires": { - "ansi-styles": "3.2.0", - "escape-string-regexp": "1.0.5", - "supports-color": "4.5.0" + "ansi-styles": "^3.1.0", + "escape-string-regexp": "^1.0.5", + "supports-color": "^4.0.0" } }, "has-flag": { @@ -1790,8 +1790,8 @@ "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "4.0.0" + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" } }, "strip-ansi": { @@ -1800,7 +1800,7 @@ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { - "ansi-regex": "3.0.0" + "ansi-regex": "^3.0.0" } }, "supports-color": { @@ -1809,7 +1809,7 @@ "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", "dev": true, "requires": { - "has-flag": "2.0.0" + "has-flag": "^2.0.0" } } } @@ -1819,7 +1819,7 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", "requires": { - "balanced-match": "1.0.0", + "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, @@ -1829,9 +1829,9 @@ "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", "dev": true, "requires": { - "expand-range": "1.8.2", - "preserve": "0.2.0", - "repeat-element": "1.1.2" + "expand-range": "^1.8.1", + "preserve": "^0.2.0", + "repeat-element": "^1.1.2" } }, "buffer": { @@ -1839,9 +1839,9 @@ "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", "requires": { - "base64-js": "1.2.1", - "ieee754": "1.1.8", - "isarray": "1.0.0" + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" }, "dependencies": { "isarray": { @@ -1877,10 +1877,10 @@ "resolved": "https://registry.npmjs.org/bunyan/-/bunyan-1.8.12.tgz", "integrity": "sha1-8VDw9nSKvdcq6uhPBEA74u8RN5c=", "requires": { - "dtrace-provider": "0.8.5", - "moment": "2.22.2", - "mv": "2.1.1", - "safe-json-stringify": "1.0.4" + "dtrace-provider": "~0.8", + "moment": "^2.10.6", + "mv": "~2", + "safe-json-stringify": "~1" } }, "bytes": { @@ -1894,7 +1894,7 @@ "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", "dev": true, "requires": { - "callsites": "0.2.0" + "callsites": "^0.2.0" } }, "callsites": { @@ -1928,8 +1928,8 @@ "dev": true, "optional": true, "requires": { - "align-text": "0.1.4", - "lazy-cache": "1.0.4" + "align-text": "^0.1.3", + "lazy-cache": "^1.0.3" } }, "chai": { @@ -1938,9 +1938,9 @@ "integrity": "sha1-TQJjewZ/6Vi9v906QOxW/vc3Mkc=", "dev": true, "requires": { - "assertion-error": "1.0.2", - "deep-eql": "0.1.3", - "type-detect": "1.0.0" + "assertion-error": "^1.0.1", + "deep-eql": "^0.1.3", + "type-detect": "^1.0.0" } }, "chalk": { @@ -1948,11 +1948,11 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" } }, "check-more-types": { @@ -1967,14 +1967,15 @@ "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=", "dev": true, "requires": { - "anymatch": "1.3.2", - "async-each": "1.0.1", - "glob-parent": "2.0.0", - "inherits": "2.0.3", - "is-binary-path": "1.0.1", - "is-glob": "2.0.1", - "path-is-absolute": "1.0.1", - "readdirp": "2.1.0" + "anymatch": "^1.3.0", + "async-each": "^1.0.0", + "fsevents": "^1.0.0", + "glob-parent": "^2.0.0", + "inherits": "^2.0.1", + "is-binary-path": "^1.0.0", + "is-glob": "^2.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.0.0" } }, "circular-json": { @@ -1995,12 +1996,12 @@ "integrity": "sha1-OlrnT9drYmevZm5p4q+70B3vNNE=", "dev": true, "requires": { - "ansi-regex": "2.1.1", - "d": "1.0.0", - "es5-ext": "0.10.35", - "es6-iterator": "2.0.3", - "memoizee": "0.4.11", - "timers-ext": "0.1.2" + "ansi-regex": "^2.1.1", + "d": "1", + "es5-ext": "^0.10.12", + "es6-iterator": "2", + "memoizee": "^0.4.3", + "timers-ext": "0.1" } }, "cli-cursor": { @@ -2009,7 +2010,7 @@ "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", "dev": true, "requires": { - "restore-cursor": "1.0.1" + "restore-cursor": "^1.0.1" } }, "cli-width": { @@ -2025,8 +2026,8 @@ "dev": true, "optional": true, "requires": { - "center-align": "0.1.3", - "right-align": "0.1.3", + "center-align": "^0.1.1", + "right-align": "^0.1.1", "wordwrap": "0.0.2" }, "dependencies": { @@ -2082,7 +2083,7 @@ "integrity": "sha1-Gsz5fdc5uYO/mU1W/sj5WFNkG3o=", "dev": true, "requires": { - "color-name": "1.1.3" + "color-name": "^1.1.1" } }, "color-name": { @@ -2101,7 +2102,7 @@ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", "requires": { - "delayed-stream": "1.0.0" + "delayed-stream": "~1.0.0" } }, "commander": { @@ -2130,9 +2131,9 @@ "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", "dev": true, "requires": { - "inherits": "2.0.3", - "readable-stream": "2.3.3", - "typedarray": "0.0.6" + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" }, "dependencies": { "isarray": { @@ -2147,13 +2148,13 @@ "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", "dev": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "safe-buffer": "5.1.1", - "string_decoder": "1.0.3", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.0.3", + "util-deprecate": "~1.0.1" } }, "string_decoder": { @@ -2162,7 +2163,7 @@ "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", "dev": true, "requires": { - "safe-buffer": "5.1.1" + "safe-buffer": "~5.1.0" } } } @@ -2182,8 +2183,8 @@ "integrity": "sha1-q6CXR9++TD5w52am5BWG4YWfxvI=", "dev": true, "requires": { - "ini": "1.3.4", - "proto-list": "1.2.4" + "ini": "^1.3.4", + "proto-list": "~1.2.1" } }, "configstore": { @@ -2192,12 +2193,12 @@ "integrity": "sha512-5oNkD/L++l0O6xGXxb1EWS7SivtjfGQlRyxJsYgE0Z495/L81e2h4/d3r969hoPXuFItzNOKMtsXgYG4c7dYvw==", "dev": true, "requires": { - "dot-prop": "4.2.0", - "graceful-fs": "4.1.11", - "make-dir": "1.1.0", - "unique-string": "1.0.0", - "write-file-atomic": "2.3.0", - "xdg-basedir": "3.0.0" + "dot-prop": "^4.1.0", + "graceful-fs": "^4.1.2", + "make-dir": "^1.0.0", + "unique-string": "^1.0.0", + "write-file-atomic": "^2.0.0", + "xdg-basedir": "^3.0.0" } }, "contains-path": { @@ -2221,8 +2222,8 @@ "resolved": "https://registry.npmjs.org/continuation-local-storage/-/continuation-local-storage-3.2.0.tgz", "integrity": "sha1-4Z/Da1lwkKXU5KOy6j68XilpSiQ=", "requires": { - "async-listener": "0.6.8", - "emitter-listener": "1.0.1" + "async-listener": "^0.6.0", + "emitter-listener": "^1.0.1" } }, "convert-source-map": { @@ -2261,8 +2262,8 @@ "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.4.tgz", "integrity": "sha1-K9OB8usgECAQXNUOpZ2mMJBpRoY=", "requires": { - "object-assign": "4.1.1", - "vary": "1.1.2" + "object-assign": "^4", + "vary": "^1" } }, "create-error-class": { @@ -2271,7 +2272,7 @@ "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", "dev": true, "requires": { - "capture-stack-trace": "1.0.0" + "capture-stack-trace": "^1.0.0" } }, "cross-spawn": { @@ -2280,9 +2281,9 @@ "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", "dev": true, "requires": { - "lru-cache": "4.1.1", - "shebang-command": "1.2.0", - "which": "1.3.0" + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" }, "dependencies": { "lru-cache": { @@ -2291,8 +2292,8 @@ "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==", "dev": true, "requires": { - "pseudomap": "1.0.2", - "yallist": "2.1.2" + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" } } } @@ -2302,7 +2303,7 @@ "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", "requires": { - "boom": "5.2.0" + "boom": "5.x.x" }, "dependencies": { "boom": { @@ -2310,7 +2311,7 @@ "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", "requires": { - "hoek": "4.2.0" + "hoek": "4.x.x" } } } @@ -2342,7 +2343,7 @@ "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", "dev": true, "requires": { - "es5-ext": "0.10.35" + "es5-ext": "^0.10.9" } }, "dashdash": { @@ -2350,7 +2351,7 @@ "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", "requires": { - "assert-plus": "1.0.0" + "assert-plus": "^1.0.0" } }, "dateformat": { @@ -2408,7 +2409,7 @@ "integrity": "sha1-836hXT4T/9m0N9M+GnW1+5eHTLg=", "dev": true, "requires": { - "strip-bom": "2.0.0" + "strip-bom": "^2.0.0" }, "dependencies": { "strip-bom": { @@ -2417,7 +2418,7 @@ "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", "dev": true, "requires": { - "is-utf8": "0.2.1" + "is-utf8": "^0.2.0" } } } @@ -2428,7 +2429,7 @@ "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", "dev": true, "requires": { - "clone": "1.0.2" + "clone": "^1.0.2" }, "dependencies": { "clone": { @@ -2445,13 +2446,13 @@ "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", "dev": true, "requires": { - "globby": "5.0.0", - "is-path-cwd": "1.0.0", - "is-path-in-cwd": "1.0.0", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1", - "rimraf": "2.4.5" + "globby": "^5.0.0", + "is-path-cwd": "^1.0.0", + "is-path-in-cwd": "^1.0.0", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "rimraf": "^2.2.8" } }, "delayed-stream": { @@ -2481,7 +2482,7 @@ "integrity": "sha1-STXe39lIhkjgBrASlWbpOGcR6mM=", "dev": true, "requires": { - "fs-exists-sync": "0.1.0" + "fs-exists-sync": "^0.1.0" } }, "detect-indent": { @@ -2490,7 +2491,7 @@ "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", "dev": true, "requires": { - "repeating": "2.0.1" + "repeating": "^2.0.0" } }, "diff": { @@ -2505,8 +2506,8 @@ "integrity": "sha1-xz2NKQnSIpHhoAejlYBNqLZl/mM=", "dev": true, "requires": { - "esutils": "2.0.2", - "isarray": "1.0.0" + "esutils": "^2.0.2", + "isarray": "^1.0.0" }, "dependencies": { "isarray": { @@ -2523,7 +2524,7 @@ "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", "dev": true, "requires": { - "is-obj": "1.0.1" + "is-obj": "^1.0.0" } }, "dottie": { @@ -2537,7 +2538,7 @@ "integrity": "sha1-mOu6Ihr6xG4cOf02hY2Pk2dSS5I=", "optional": true, "requires": { - "nan": "2.7.0" + "nan": "^2.3.3" } }, "duplexer": { @@ -2552,7 +2553,7 @@ "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=", "dev": true, "requires": { - "readable-stream": "1.1.14" + "readable-stream": "~1.1.9" } }, "duplexer3": { @@ -2567,7 +2568,7 @@ "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", "optional": true, "requires": { - "jsbn": "0.1.1" + "jsbn": "~0.1.0" } }, "ecdsa-sig-formatter": { @@ -2575,7 +2576,7 @@ "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.10.tgz", "integrity": "sha1-HFlQAPBKiJffuFAAiSoPTDOvhsM=", "requires": { - "safe-buffer": "5.1.1" + "safe-buffer": "^5.0.1" } }, "editorconfig": { @@ -2584,11 +2585,11 @@ "integrity": "sha512-WkjsUNVCu+ITKDj73QDvi0trvpdDWdkDyHybDGSXPfekLCqwmpD7CP7iPbvBgosNuLcI96XTDwNa75JyFl7tEQ==", "dev": true, "requires": { - "bluebird": "3.5.1", - "commander": "2.11.0", - "lru-cache": "3.2.0", - "semver": "5.4.1", - "sigmund": "1.0.1" + "bluebird": "^3.0.5", + "commander": "^2.9.0", + "lru-cache": "^3.2.0", + "semver": "^5.1.0", + "sigmund": "^1.0.1" }, "dependencies": { "lru-cache": { @@ -2597,7 +2598,7 @@ "integrity": "sha1-cXibO39Tmb7IVl3aOKow0qCX7+4=", "dev": true, "requires": { - "pseudomap": "1.0.2" + "pseudomap": "^1.0.1" } } } @@ -2612,11 +2613,11 @@ "resolved": "https://registry.npmjs.org/elasticsearch/-/elasticsearch-11.0.1.tgz", "integrity": "sha1-0YBoTGvefs+g+iTmL6HIcu6uCOc=", "requires": { - "chalk": "1.1.3", - "forever-agent": "0.6.1", - "lodash": "3.10.1", - "lodash-compat": "3.10.2", - "promise": "7.3.1" + "chalk": "^1.0.0", + "forever-agent": "^0.6.0", + "lodash": "^3.10.0", + "lodash-compat": "^3.0.0", + "promise": "^7.1.1" }, "dependencies": { "lodash": { @@ -2652,7 +2653,7 @@ "integrity": "sha1-jhdyBsPICDfYVjLouTWd/osvbq8=", "dev": true, "requires": { - "once": "1.3.3" + "once": "~1.3.0" }, "dependencies": { "once": { @@ -2661,7 +2662,7 @@ "integrity": "sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA=", "dev": true, "requires": { - "wrappy": "1.0.2" + "wrappy": "1" } } } @@ -2672,7 +2673,7 @@ "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", "dev": true, "requires": { - "is-arrayish": "0.2.1" + "is-arrayish": "^0.2.1" } }, "es5-ext": { @@ -2681,8 +2682,8 @@ "integrity": "sha1-GO6FjOajxFx9eekcFfzKnsVoSU8=", "dev": true, "requires": { - "es6-iterator": "2.0.3", - "es6-symbol": "3.1.1" + "es6-iterator": "~2.0.1", + "es6-symbol": "~3.1.1" } }, "es6-iterator": { @@ -2691,9 +2692,9 @@ "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", "dev": true, "requires": { - "d": "1.0.0", - "es5-ext": "0.10.35", - "es6-symbol": "3.1.1" + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" } }, "es6-map": { @@ -2702,12 +2703,12 @@ "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", "dev": true, "requires": { - "d": "1.0.0", - "es5-ext": "0.10.35", - "es6-iterator": "2.0.3", - "es6-set": "0.1.5", - "es6-symbol": "3.1.1", - "event-emitter": "0.3.5" + "d": "1", + "es5-ext": "~0.10.14", + "es6-iterator": "~2.0.1", + "es6-set": "~0.1.5", + "es6-symbol": "~3.1.1", + "event-emitter": "~0.3.5" } }, "es6-promise": { @@ -2722,11 +2723,11 @@ "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", "dev": true, "requires": { - "d": "1.0.0", - "es5-ext": "0.10.35", - "es6-iterator": "2.0.3", + "d": "1", + "es5-ext": "~0.10.14", + "es6-iterator": "~2.0.1", "es6-symbol": "3.1.1", - "event-emitter": "0.3.5" + "event-emitter": "~0.3.5" } }, "es6-symbol": { @@ -2735,8 +2736,8 @@ "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", "dev": true, "requires": { - "d": "1.0.0", - "es5-ext": "0.10.35" + "d": "1", + "es5-ext": "~0.10.14" } }, "es6-weak-map": { @@ -2745,10 +2746,10 @@ "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=", "dev": true, "requires": { - "d": "1.0.0", - "es5-ext": "0.10.35", - "es6-iterator": "2.0.3", - "es6-symbol": "3.1.1" + "d": "1", + "es5-ext": "^0.10.14", + "es6-iterator": "^2.0.1", + "es6-symbol": "^3.1.1" } }, "escape-html": { @@ -2767,10 +2768,10 @@ "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=", "dev": true, "requires": { - "es6-map": "0.1.5", - "es6-weak-map": "2.0.2", - "esrecurse": "4.2.0", - "estraverse": "4.2.0" + "es6-map": "^0.1.3", + "es6-weak-map": "^2.0.1", + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" } }, "eslint": { @@ -2779,41 +2780,41 @@ "integrity": "sha1-yPxiAcf0DdCJQbh8CFdnOGpnmsw=", "dev": true, "requires": { - "babel-code-frame": "6.26.0", - "chalk": "1.1.3", - "concat-stream": "1.6.0", - "debug": "2.6.9", - "doctrine": "2.0.0", - "escope": "3.6.0", - "espree": "3.5.1", - "esquery": "1.0.0", - "estraverse": "4.2.0", - "esutils": "2.0.2", - "file-entry-cache": "2.0.0", - "glob": "7.1.2", - "globals": "9.18.0", - "ignore": "3.3.7", - "imurmurhash": "0.1.4", - "inquirer": "0.12.0", - "is-my-json-valid": "2.16.1", - "is-resolvable": "1.0.0", - "js-yaml": "3.10.0", - "json-stable-stringify": "1.0.1", - "levn": "0.3.0", - "lodash": "4.17.4", - "mkdirp": "0.5.1", - "natural-compare": "1.4.0", - "optionator": "0.8.2", - "path-is-inside": "1.0.2", - "pluralize": "1.2.1", - "progress": "1.1.8", - "require-uncached": "1.0.3", - "shelljs": "0.7.8", - "strip-bom": "3.0.0", - "strip-json-comments": "2.0.1", - "table": "3.8.3", - "text-table": "0.2.0", - "user-home": "2.0.0" + "babel-code-frame": "^6.16.0", + "chalk": "^1.1.3", + "concat-stream": "^1.5.2", + "debug": "^2.1.1", + "doctrine": "^2.0.0", + "escope": "^3.6.0", + "espree": "^3.4.0", + "esquery": "^1.0.0", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "file-entry-cache": "^2.0.0", + "glob": "^7.0.3", + "globals": "^9.14.0", + "ignore": "^3.2.0", + "imurmurhash": "^0.1.4", + "inquirer": "^0.12.0", + "is-my-json-valid": "^2.10.0", + "is-resolvable": "^1.0.0", + "js-yaml": "^3.5.1", + "json-stable-stringify": "^1.0.0", + "levn": "^0.3.0", + "lodash": "^4.0.0", + "mkdirp": "^0.5.0", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "path-is-inside": "^1.0.1", + "pluralize": "^1.2.1", + "progress": "^1.1.8", + "require-uncached": "^1.0.2", + "shelljs": "^0.7.5", + "strip-bom": "^3.0.0", + "strip-json-comments": "~2.0.1", + "table": "^3.7.8", + "text-table": "~0.2.0", + "user-home": "^2.0.0" }, "dependencies": { "glob": { @@ -2822,12 +2823,12 @@ "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, "user-home": { @@ -2836,7 +2837,7 @@ "integrity": "sha1-nHC/2Babwdy/SGBODwS4tJzenp8=", "dev": true, "requires": { - "os-homedir": "1.0.2" + "os-homedir": "^1.0.0" } } } @@ -2847,7 +2848,7 @@ "integrity": "sha512-/fhjt/VqzBA2SRsx7ErDtv6Ayf+XLw9LIOqmpBuHFCVwyJo2EtzGWMB9fYRFBoWWQLxmNmCpenNiH0RxyeS41w==", "dev": true, "requires": { - "eslint-restricted-globals": "0.1.1" + "eslint-restricted-globals": "^0.1.1" } }, "eslint-import-resolver-node": { @@ -2856,8 +2857,8 @@ "integrity": "sha512-yUtXS15gIcij68NmXmP9Ni77AQuCN0itXbCc/jWd8C6/yKZaSNXicpC8cgvjnxVdmfsosIXrjpzFq7GcDryb6A==", "dev": true, "requires": { - "debug": "2.6.9", - "resolve": "1.5.0" + "debug": "^2.6.8", + "resolve": "^1.2.0" } }, "eslint-module-utils": { @@ -2866,8 +2867,8 @@ "integrity": "sha512-jDI/X5l/6D1rRD/3T43q8Qgbls2nq5km5KSqiwlyUbGo5+04fXhMKdCPhjwbqAa6HXWaMxj8Q4hQDIh7IadJQw==", "dev": true, "requires": { - "debug": "2.6.9", - "pkg-dir": "1.0.0" + "debug": "^2.6.8", + "pkg-dir": "^1.0.0" } }, "eslint-plugin-import": { @@ -2876,16 +2877,16 @@ "integrity": "sha512-Rf7dfKJxZ16QuTgVv1OYNxkZcsu/hULFnC+e+w0Gzi6jMC3guQoWQgxYxc54IDRinlb6/0v5z/PxxIKmVctN+g==", "dev": true, "requires": { - "builtin-modules": "1.1.1", - "contains-path": "0.1.0", - "debug": "2.6.9", + "builtin-modules": "^1.1.1", + "contains-path": "^0.1.0", + "debug": "^2.6.8", "doctrine": "1.5.0", - "eslint-import-resolver-node": "0.3.1", - "eslint-module-utils": "2.1.1", - "has": "1.0.1", - "lodash.cond": "4.5.2", - "minimatch": "3.0.4", - "read-pkg-up": "2.0.0" + "eslint-import-resolver-node": "^0.3.1", + "eslint-module-utils": "^2.1.1", + "has": "^1.0.1", + "lodash.cond": "^4.3.0", + "minimatch": "^3.0.3", + "read-pkg-up": "^2.0.0" }, "dependencies": { "doctrine": { @@ -2894,8 +2895,8 @@ "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", "dev": true, "requires": { - "esutils": "2.0.2", - "isarray": "1.0.0" + "esutils": "^2.0.2", + "isarray": "^1.0.0" } }, "isarray": { @@ -2918,8 +2919,8 @@ "integrity": "sha1-DJiLirRttTEAoZVK5LqZXd0n2H4=", "dev": true, "requires": { - "acorn": "5.2.1", - "acorn-jsx": "3.0.1" + "acorn": "^5.1.1", + "acorn-jsx": "^3.0.0" } }, "esprima": { @@ -2934,7 +2935,7 @@ "integrity": "sha1-z7qLV9f7qT8XKYqKAGoEzaE9gPo=", "dev": true, "requires": { - "estraverse": "4.2.0" + "estraverse": "^4.0.0" } }, "esrecurse": { @@ -2943,8 +2944,8 @@ "integrity": "sha1-+pVo2Y04I/mkHZHpAtyrnqblsWM=", "dev": true, "requires": { - "estraverse": "4.2.0", - "object-assign": "4.1.1" + "estraverse": "^4.1.0", + "object-assign": "^4.0.1" } }, "estraverse": { @@ -2970,8 +2971,8 @@ "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", "dev": true, "requires": { - "d": "1.0.0", - "es5-ext": "0.10.35" + "d": "1", + "es5-ext": "~0.10.14" } }, "event-stream": { @@ -2980,13 +2981,13 @@ "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", "dev": true, "requires": { - "duplexer": "0.1.1", - "from": "0.1.7", - "map-stream": "0.1.0", + "duplexer": "~0.1.1", + "from": "~0", + "map-stream": "~0.1.0", "pause-stream": "0.0.11", - "split": "0.3.3", - "stream-combiner": "0.0.4", - "through": "2.3.8" + "split": "0.3", + "stream-combiner": "~0.0.4", + "through": "~2.3.1" } }, "events": { @@ -3000,13 +3001,13 @@ "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", "dev": true, "requires": { - "cross-spawn": "5.1.0", - "get-stream": "3.0.0", - "is-stream": "1.1.0", - "npm-run-path": "2.0.2", - "p-finally": "1.0.0", - "signal-exit": "3.0.2", - "strip-eof": "1.0.0" + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" } }, "exit-hook": { @@ -3021,7 +3022,7 @@ "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", "dev": true, "requires": { - "is-posix-bracket": "0.1.1" + "is-posix-bracket": "^0.1.0" } }, "expand-range": { @@ -3030,7 +3031,7 @@ "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", "dev": true, "requires": { - "fill-range": "2.2.3" + "fill-range": "^2.1.0" } }, "expand-tilde": { @@ -3039,7 +3040,7 @@ "integrity": "sha1-C4HrqJflo9MdHD0QL48BRB5VlEk=", "dev": true, "requires": { - "os-homedir": "1.0.2" + "os-homedir": "^1.0.1" } }, "express": { @@ -3047,36 +3048,36 @@ "resolved": "https://registry.npmjs.org/express/-/express-4.16.2.tgz", "integrity": "sha1-41xt/i1kt9ygpc1PIXgb4ymeB2w=", "requires": { - "accepts": "1.3.4", + "accepts": "~1.3.4", "array-flatten": "1.1.1", "body-parser": "1.18.2", "content-disposition": "0.5.2", - "content-type": "1.0.4", + "content-type": "~1.0.4", "cookie": "0.3.1", "cookie-signature": "1.0.6", "debug": "2.6.9", - "depd": "1.1.1", - "encodeurl": "1.0.1", - "escape-html": "1.0.3", - "etag": "1.8.1", + "depd": "~1.1.1", + "encodeurl": "~1.0.1", + "escape-html": "~1.0.3", + "etag": "~1.8.1", "finalhandler": "1.1.0", "fresh": "0.5.2", "merge-descriptors": "1.0.1", - "methods": "1.1.2", - "on-finished": "2.3.0", - "parseurl": "1.3.2", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", "path-to-regexp": "0.1.7", - "proxy-addr": "2.0.2", + "proxy-addr": "~2.0.2", "qs": "6.5.1", - "range-parser": "1.2.0", + "range-parser": "~1.2.0", "safe-buffer": "5.1.1", "send": "0.16.1", "serve-static": "1.13.1", "setprototypeof": "1.1.0", - "statuses": "1.3.1", - "type-is": "1.6.15", + "statuses": "~1.3.1", + "type-is": "~1.6.15", "utils-merge": "1.0.1", - "vary": "1.1.2" + "vary": "~1.1.2" }, "dependencies": { "setprototypeof": { @@ -3096,8 +3097,8 @@ "resolved": "https://registry.npmjs.org/express-list-routes/-/express-list-routes-0.1.4.tgz", "integrity": "sha1-xlwxw/thnHnAVD97TsToMFbs5hY=", "requires": { - "colors": "1.1.2", - "lodash": "3.10.1" + "colors": "^1.0.3", + "lodash": "^3.0.0" }, "dependencies": { "lodash": { @@ -3112,7 +3113,7 @@ "resolved": "https://registry.npmjs.org/express-request-id/-/express-request-id-1.4.0.tgz", "integrity": "sha1-J3ssCUmAPmgQTJ1Fw+aJNPlr9aI=", "requires": { - "uuid": "3.1.0" + "uuid": "^3.0.1" } }, "express-sanitizer": { @@ -3128,7 +3129,7 @@ "resolved": "https://registry.npmjs.org/express-validation/-/express-validation-0.6.0.tgz", "integrity": "sha1-DXf0r8flixIBat7FmzJb7v2dwmg=", "requires": { - "lodash": "4.17.4" + "lodash": "^4.9.0" } }, "extend": { @@ -3142,7 +3143,7 @@ "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", "dev": true, "requires": { - "is-extglob": "1.0.0" + "is-extglob": "^1.0.0" } }, "extsprintf": { @@ -3156,8 +3157,8 @@ "integrity": "sha1-Rb4X0Cu5kX1gzP/UmVyZnmyMmUg=", "dev": true, "requires": { - "chalk": "1.1.3", - "time-stamp": "1.1.0" + "chalk": "^1.1.1", + "time-stamp": "^1.0.0" } }, "fast-deep-equal": { @@ -3182,8 +3183,8 @@ "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", "dev": true, "requires": { - "escape-string-regexp": "1.0.5", - "object-assign": "4.1.1" + "escape-string-regexp": "^1.0.5", + "object-assign": "^4.1.0" } }, "file-entry-cache": { @@ -3192,8 +3193,8 @@ "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", "dev": true, "requires": { - "flat-cache": "1.3.0", - "object-assign": "4.1.1" + "flat-cache": "^1.2.1", + "object-assign": "^4.0.1" } }, "filename-regex": { @@ -3208,8 +3209,8 @@ "integrity": "sha1-jnVIqW08wjJ+5eZ0FocjozO7oqA=", "dev": true, "requires": { - "glob": "7.1.2", - "minimatch": "3.0.4" + "glob": "^7.0.3", + "minimatch": "^3.0.3" }, "dependencies": { "glob": { @@ -3218,12 +3219,12 @@ "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } } } @@ -3234,11 +3235,11 @@ "integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=", "dev": true, "requires": { - "is-number": "2.1.0", - "isobject": "2.1.0", - "randomatic": "1.1.7", - "repeat-element": "1.1.2", - "repeat-string": "1.6.1" + "is-number": "^2.1.0", + "isobject": "^2.0.0", + "randomatic": "^1.1.3", + "repeat-element": "^1.1.2", + "repeat-string": "^1.5.2" } }, "finalhandler": { @@ -3247,12 +3248,12 @@ "integrity": "sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=", "requires": { "debug": "2.6.9", - "encodeurl": "1.0.1", - "escape-html": "1.0.3", - "on-finished": "2.3.0", - "parseurl": "1.3.2", - "statuses": "1.3.1", - "unpipe": "1.0.0" + "encodeurl": "~1.0.1", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.3.1", + "unpipe": "~1.0.0" }, "dependencies": { "statuses": { @@ -3274,8 +3275,8 @@ "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", "dev": true, "requires": { - "path-exists": "2.1.0", - "pinkie-promise": "2.0.1" + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" } }, "findup-sync": { @@ -3284,10 +3285,10 @@ "integrity": "sha1-b35LV7buOkA3tEFOrt6j9Y9x4Ow=", "dev": true, "requires": { - "detect-file": "0.1.0", - "is-glob": "2.0.1", - "micromatch": "2.3.11", - "resolve-dir": "0.1.1" + "detect-file": "^0.1.0", + "is-glob": "^2.0.1", + "micromatch": "^2.3.7", + "resolve-dir": "^0.1.0" } }, "fined": { @@ -3296,11 +3297,11 @@ "integrity": "sha1-s33IRLdqL15wgeiE98CuNE8VNHY=", "dev": true, "requires": { - "expand-tilde": "2.0.2", - "is-plain-object": "2.0.4", - "object.defaults": "1.1.0", - "object.pick": "1.3.0", - "parse-filepath": "1.0.1" + "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" }, "dependencies": { "expand-tilde": { @@ -3309,7 +3310,7 @@ "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", "dev": true, "requires": { - "homedir-polyfill": "1.0.1" + "homedir-polyfill": "^1.0.1" } } } @@ -3332,10 +3333,10 @@ "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=", "dev": true, "requires": { - "circular-json": "0.3.3", - "del": "2.2.2", - "graceful-fs": "4.1.11", - "write": "0.2.1" + "circular-json": "^0.3.1", + "del": "^2.0.2", + "graceful-fs": "^4.1.2", + "write": "^0.2.1" } }, "follow-redirects": { @@ -3343,7 +3344,7 @@ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.2.6.tgz", "integrity": "sha512-FrMqZ/FONtHnbqO651UPpfRUVukIEwJhXMfdr/JWAmrDbeYBu773b1J6gdWDyRIj4hvvzQEHoEOTrdR8o6KLYA==", "requires": { - "debug": "3.1.0" + "debug": "^3.1.0" }, "dependencies": { "debug": { @@ -3368,7 +3369,7 @@ "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", "dev": true, "requires": { - "for-in": "1.0.2" + "for-in": "^1.0.1" } }, "forever-agent": { @@ -3381,9 +3382,9 @@ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.1.tgz", "integrity": "sha1-b7lPvXGIUwbXPRXMSX/kzE7NRL8=", "requires": { - "asynckit": "0.4.0", - "combined-stream": "1.0.5", - "mime-types": "2.1.17" + "asynckit": "^0.4.0", + "combined-stream": "^1.0.5", + "mime-types": "^2.1.12" } }, "formatio": { @@ -3392,7 +3393,7 @@ "integrity": "sha1-XtPM1jZVEJc4NGXZlhmRAOhhYek=", "dev": true, "requires": { - "samsam": "1.1.2" + "samsam": "~1.1" } }, "formidable": { @@ -3428,9 +3429,9 @@ "integrity": "sha1-+RcExT0bRh+JNFKwwwfZmXZHq2s=", "dev": true, "requires": { - "graceful-fs": "4.1.11", - "jsonfile": "4.0.0", - "universalify": "0.1.1" + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" } }, "fs-readdir-recursive": { @@ -3445,6 +3446,542 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, + "fsevents": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.4.tgz", + "integrity": "sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg==", + "dev": true, + "optional": true, + "requires": { + "nan": "^2.9.2", + "node-pre-gyp": "^0.10.0" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "aproba": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "chownr": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "debug": { + "version": "2.6.9", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ms": "2.0.0" + } + }, + "deep-extend": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "optional": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "detect-libc": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "fs-minipass": { + "version": "1.2.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "glob": { + "version": "7.1.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "iconv-lite": { + "version": "0.4.21", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safer-buffer": "^2.1.0" + } + }, + "ignore-walk": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true, + "dev": true + }, + "ini": { + "version": "1.3.5", + "bundled": true, + "dev": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true + }, + "minipass": { + "version": "2.2.4", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "^5.1.1", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "nan": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.11.0.tgz", + "integrity": "sha512-F4miItu2rGnV2ySkXOQoA8FKz/SR2Q2sWP0sbTxNxz/tuokeC8WxOhPMcwi0qIyGtVn/rrSeLbvVkznqCdwYnw==", + "dev": true, + "optional": true + }, + "needle": { + "version": "2.2.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "debug": "^2.1.2", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, + "node-pre-gyp": { + "version": "0.10.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.0", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.1.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "npm-bundled": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "npm-packlist": { + "version": "1.1.10", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "osenv": { + "version": "0.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "process-nextick-args": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "rc": { + "version": "1.2.7", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "deep-extend": "^0.5.1", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "rimraf": { + "version": "2.6.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "glob": "^7.0.5" + } + }, + "safe-buffer": { + "version": "5.1.1", + "bundled": true, + "dev": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "sax": { + "version": "1.2.4", + "bundled": true, + "dev": true, + "optional": true + }, + "semver": { + "version": "5.5.0", + "bundled": true, + "dev": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "tar": { + "version": "4.4.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "chownr": "^1.0.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.2.4", + "minizlib": "^1.1.0", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.1", + "yallist": "^3.0.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "wide-align": { + "version": "1.1.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "string-width": "^1.0.2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "yallist": { + "version": "3.0.2", + "bundled": true, + "dev": true + } + } + }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -3457,7 +3994,7 @@ "integrity": "sha1-QLcJU30k0dRXZ9takIaJ3+aaxE8=", "dev": true, "requires": { - "globule": "0.1.0" + "globule": "~0.1.0" } }, "generate-function": { @@ -3472,7 +4009,7 @@ "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", "dev": true, "requires": { - "is-property": "1.0.2" + "is-property": "^1.0.0" } }, "generic-pool": { @@ -3497,7 +4034,7 @@ "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", "requires": { - "assert-plus": "1.0.0" + "assert-plus": "^1.0.0" } }, "glob": { @@ -3505,11 +4042,11 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", "requires": { - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, "glob-base": { @@ -3518,8 +4055,8 @@ "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", "dev": true, "requires": { - "glob-parent": "2.0.0", - "is-glob": "2.0.1" + "glob-parent": "^2.0.0", + "is-glob": "^2.0.0" } }, "glob-parent": { @@ -3528,7 +4065,7 @@ "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", "dev": true, "requires": { - "is-glob": "2.0.1" + "is-glob": "^2.0.0" } }, "glob-stream": { @@ -3537,12 +4074,12 @@ "integrity": "sha1-kXCl8St5Awb9/lmPMT+PeVT9FDs=", "dev": true, "requires": { - "glob": "4.5.3", - "glob2base": "0.0.12", - "minimatch": "2.0.10", - "ordered-read-streams": "0.1.0", - "through2": "0.6.5", - "unique-stream": "1.0.0" + "glob": "^4.3.1", + "glob2base": "^0.0.12", + "minimatch": "^2.0.1", + "ordered-read-streams": "^0.1.0", + "through2": "^0.6.1", + "unique-stream": "^1.0.0" }, "dependencies": { "glob": { @@ -3551,10 +4088,10 @@ "integrity": "sha1-xstz0yJsHv7wTePFbQEvAzd+4V8=", "dev": true, "requires": { - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "2.0.10", - "once": "1.4.0" + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^2.0.1", + "once": "^1.3.0" } }, "minimatch": { @@ -3563,7 +4100,7 @@ "integrity": "sha1-jQh8OcazjAAbl/ynzm0OHoCvusc=", "dev": true, "requires": { - "brace-expansion": "1.1.8" + "brace-expansion": "^1.0.0" } }, "readable-stream": { @@ -3572,10 +4109,10 @@ "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", "dev": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", "isarray": "0.0.1", - "string_decoder": "0.10.31" + "string_decoder": "~0.10.x" } }, "through2": { @@ -3584,8 +4121,8 @@ "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", "dev": true, "requires": { - "readable-stream": "1.0.34", - "xtend": "4.0.1" + "readable-stream": ">=1.0.33-1 <1.1.0-0", + "xtend": ">=4.0.0 <4.1.0-0" } } } @@ -3596,7 +4133,7 @@ "integrity": "sha1-uVtKjfdLOcgymLDAXJeLTZo7cQs=", "dev": true, "requires": { - "gaze": "0.5.2" + "gaze": "^0.5.1" } }, "glob2base": { @@ -3605,7 +4142,7 @@ "integrity": "sha1-nUGbPijxLoOjYhZKJ3BVkiycDVY=", "dev": true, "requires": { - "find-index": "0.1.1" + "find-index": "^0.1.1" } }, "global-dirs": { @@ -3614,7 +4151,7 @@ "integrity": "sha1-ENNAOeDfBCcuJizyQiT3IJQ0308=", "dev": true, "requires": { - "ini": "1.3.4" + "ini": "^1.3.4" } }, "global-modules": { @@ -3623,8 +4160,8 @@ "integrity": "sha1-6lo77ULG1s6ZWk+KEmm12uIjgo0=", "dev": true, "requires": { - "global-prefix": "0.1.5", - "is-windows": "0.2.0" + "global-prefix": "^0.1.4", + "is-windows": "^0.2.0" } }, "global-prefix": { @@ -3633,10 +4170,10 @@ "integrity": "sha1-jTvGuNo8qBEqFg2NSW/wRiv+948=", "dev": true, "requires": { - "homedir-polyfill": "1.0.1", - "ini": "1.3.4", - "is-windows": "0.2.0", - "which": "1.3.0" + "homedir-polyfill": "^1.0.0", + "ini": "^1.3.4", + "is-windows": "^0.2.0", + "which": "^1.2.12" } }, "globals": { @@ -3651,12 +4188,12 @@ "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", "dev": true, "requires": { - "array-union": "1.0.2", - "arrify": "1.0.1", - "glob": "7.1.2", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1" + "array-union": "^1.0.1", + "arrify": "^1.0.0", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" }, "dependencies": { "glob": { @@ -3665,12 +4202,12 @@ "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } } } @@ -3681,9 +4218,9 @@ "integrity": "sha1-2cjt3h2nnRJaFRt5UzuXhnY0auU=", "dev": true, "requires": { - "glob": "3.1.21", - "lodash": "1.0.2", - "minimatch": "0.2.14" + "glob": "~3.1.21", + "lodash": "~1.0.1", + "minimatch": "~0.2.11" }, "dependencies": { "glob": { @@ -3692,9 +4229,9 @@ "integrity": "sha1-0p4KBV3qUTj00H7UDomC6DwgZs0=", "dev": true, "requires": { - "graceful-fs": "1.2.3", - "inherits": "1.0.2", - "minimatch": "0.2.14" + "graceful-fs": "~1.2.0", + "inherits": "1", + "minimatch": "~0.2.11" } }, "graceful-fs": { @@ -3721,8 +4258,8 @@ "integrity": "sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=", "dev": true, "requires": { - "lru-cache": "2.7.3", - "sigmund": "1.0.1" + "lru-cache": "2", + "sigmund": "~1.0.0" } } } @@ -3733,7 +4270,7 @@ "integrity": "sha1-f+DxmfV6yQbPUS/urY+Q7kooT8U=", "dev": true, "requires": { - "sparkles": "1.0.0" + "sparkles": "^1.0.0" } }, "got": { @@ -3742,17 +4279,17 @@ "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", "dev": true, "requires": { - "create-error-class": "3.0.2", - "duplexer3": "0.1.4", - "get-stream": "3.0.0", - "is-redirect": "1.0.0", - "is-retry-allowed": "1.1.0", - "is-stream": "1.1.0", - "lowercase-keys": "1.0.0", - "safe-buffer": "5.1.1", - "timed-out": "4.0.1", - "unzip-response": "2.0.1", - "url-parse-lax": "1.0.0" + "create-error-class": "^3.0.0", + "duplexer3": "^0.1.4", + "get-stream": "^3.0.0", + "is-redirect": "^1.0.0", + "is-retry-allowed": "^1.0.0", + "is-stream": "^1.0.0", + "lowercase-keys": "^1.0.0", + "safe-buffer": "^5.0.1", + "timed-out": "^4.0.0", + "unzip-response": "^2.0.1", + "url-parse-lax": "^1.0.0" } }, "graceful-fs": { @@ -3773,19 +4310,19 @@ "integrity": "sha1-VxzkWSjdQK9lFPxAEYZgFsE4RbQ=", "dev": true, "requires": { - "archy": "1.0.0", - "chalk": "1.1.3", - "deprecated": "0.0.1", - "gulp-util": "3.0.8", - "interpret": "1.0.4", - "liftoff": "2.3.0", - "minimist": "1.2.0", - "orchestrator": "0.3.8", - "pretty-hrtime": "1.0.3", - "semver": "4.3.6", - "tildify": "1.2.0", - "v8flags": "2.1.1", - "vinyl-fs": "0.3.14" + "archy": "^1.0.0", + "chalk": "^1.0.0", + "deprecated": "^0.0.1", + "gulp-util": "^3.0.0", + "interpret": "^1.0.0", + "liftoff": "^2.1.0", + "minimist": "^1.1.0", + "orchestrator": "^0.3.0", + "pretty-hrtime": "^1.0.0", + "semver": "^4.1.0", + "tildify": "^1.0.0", + "v8flags": "^2.0.2", + "vinyl-fs": "^0.3.0" }, "dependencies": { "minimist": { @@ -3808,8 +4345,8 @@ "integrity": "sha1-Jh2xhuGDl/7z9qLCLpwxW/qIrgw=", "dev": true, "requires": { - "chalk": "1.1.3", - "object-assign": "3.0.0" + "chalk": "^1.0.0", + "object-assign": "^3.0.0" }, "dependencies": { "object-assign": { @@ -3826,24 +4363,24 @@ "integrity": "sha1-AFTh50RQLifATBh8PsxQXdVLu08=", "dev": true, "requires": { - "array-differ": "1.0.0", - "array-uniq": "1.0.3", - "beeper": "1.1.1", - "chalk": "1.1.3", - "dateformat": "2.2.0", - "fancy-log": "1.3.0", - "gulplog": "1.0.0", - "has-gulplog": "0.1.0", - "lodash._reescape": "3.0.0", - "lodash._reevaluate": "3.0.0", - "lodash._reinterpolate": "3.0.0", - "lodash.template": "3.6.2", - "minimist": "1.2.0", - "multipipe": "0.1.2", - "object-assign": "3.0.0", + "array-differ": "^1.0.0", + "array-uniq": "^1.0.2", + "beeper": "^1.0.0", + "chalk": "^1.0.0", + "dateformat": "^2.0.0", + "fancy-log": "^1.1.0", + "gulplog": "^1.0.0", + "has-gulplog": "^0.1.0", + "lodash._reescape": "^3.0.0", + "lodash._reevaluate": "^3.0.0", + "lodash._reinterpolate": "^3.0.0", + "lodash.template": "^3.0.0", + "minimist": "^1.1.0", + "multipipe": "^0.1.2", + "object-assign": "^3.0.0", "replace-ext": "0.0.1", - "through2": "2.0.3", - "vinyl": "0.5.3" + "through2": "^2.0.0", + "vinyl": "^0.5.0" }, "dependencies": { "minimist": { @@ -3866,7 +4403,7 @@ "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=", "dev": true, "requires": { - "glogg": "1.0.0" + "glogg": "^1.0.0" } }, "handlebars": { @@ -3875,10 +4412,10 @@ "integrity": "sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw=", "dev": true, "requires": { - "async": "1.5.2", - "optimist": "0.6.1", - "source-map": "0.4.4", - "uglify-js": "2.8.29" + "async": "^1.4.0", + "optimist": "^0.6.1", + "source-map": "^0.4.4", + "uglify-js": "^2.6" }, "dependencies": { "source-map": { @@ -3887,7 +4424,7 @@ "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", "dev": true, "requires": { - "amdefine": "1.0.1" + "amdefine": ">=0.0.4" } } } @@ -3902,8 +4439,8 @@ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", "requires": { - "ajv": "5.5.1", - "har-schema": "2.0.0" + "ajv": "^5.1.0", + "har-schema": "^2.0.0" }, "dependencies": { "ajv": { @@ -3911,10 +4448,10 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.1.tgz", "integrity": "sha1-s4u4h22ehr7plJVqBOch6IskjrI=", "requires": { - "co": "4.6.0", - "fast-deep-equal": "1.0.0", - "fast-json-stable-stringify": "2.0.0", - "json-schema-traverse": "0.3.1" + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" } } } @@ -3925,7 +4462,7 @@ "integrity": "sha1-hGFzP1OLCDfJNh45qauelwTcLyg=", "dev": true, "requires": { - "function-bind": "1.1.1" + "function-bind": "^1.0.2" } }, "has-ansi": { @@ -3933,7 +4470,7 @@ "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "has-flag": { @@ -3948,7 +4485,7 @@ "integrity": "sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4=", "dev": true, "requires": { - "sparkles": "1.0.0" + "sparkles": "^1.0.0" } }, "hawk": { @@ -3956,10 +4493,10 @@ "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==", "requires": { - "boom": "4.3.1", - "cryptiles": "3.1.2", - "hoek": "4.2.0", - "sntp": "2.1.0" + "boom": "4.x.x", + "cryptiles": "3.x.x", + "hoek": "4.x.x", + "sntp": "2.x.x" } }, "hoek": { @@ -3973,8 +4510,8 @@ "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", "dev": true, "requires": { - "os-homedir": "1.0.2", - "os-tmpdir": "1.0.2" + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.1" } }, "homedir-polyfill": { @@ -3983,7 +4520,7 @@ "integrity": "sha1-TCu8inWJmP7r9e1oWA921GdotLw=", "dev": true, "requires": { - "parse-passwd": "1.0.0" + "parse-passwd": "^1.0.0" } }, "hosted-git-info": { @@ -3997,7 +4534,7 @@ "resolved": "https://registry.npmjs.org/http-aws-es/-/http-aws-es-1.1.3.tgz", "integrity": "sha1-ZJUYQ7XFETBQclcNfCxQn3gUTWs=", "requires": { - "aws-sdk": "2.143.0" + "aws-sdk": "^2.2.19" } }, "http-errors": { @@ -4008,7 +4545,7 @@ "depd": "1.1.1", "inherits": "2.0.3", "setprototypeof": "1.0.3", - "statuses": "1.4.0" + "statuses": ">= 1.3.1 < 2" } }, "http-signature": { @@ -4016,9 +4553,9 @@ "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", "requires": { - "assert-plus": "1.0.0", - "jsprim": "1.4.1", - "sshpk": "1.13.1" + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" } }, "iconv-lite": { @@ -4031,11 +4568,11 @@ "resolved": "https://registry.npmjs.org/idtoken-verifier/-/idtoken-verifier-1.2.0.tgz", "integrity": "sha512-8jmmFHwdPz8L73zGNAXHHOV9yXNC+Z0TUBN5rafpoaFaLFltlIFr1JkQa3FYAETP23eSsulVw0sBiwrE8jqbUg==", "requires": { - "base64-js": "1.2.1", - "crypto-js": "3.1.9-1", - "jsbn": "0.1.1", - "superagent": "3.8.3", - "url-join": "1.1.0" + "base64-js": "^1.2.0", + "crypto-js": "^3.1.9-1", + "jsbn": "^0.1.0", + "superagent": "^3.8.2", + "url-join": "^1.1.0" }, "dependencies": { "debug": { @@ -4066,13 +4603,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.1", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "string_decoder": { @@ -4080,7 +4617,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "5.1.1" + "safe-buffer": "~5.1.0" } }, "superagent": { @@ -4088,16 +4625,16 @@ "resolved": "https://registry.npmjs.org/superagent/-/superagent-3.8.3.tgz", "integrity": "sha512-GLQtLMCoEIK4eDv6OGtkOoSMt3D+oq0y3dsxMuYuDvaNUvuT8eFBuLmfR0iYYzHC1e8hpzC6ZsxbuP6DIalMFA==", "requires": { - "component-emitter": "1.2.1", - "cookiejar": "2.1.1", - "debug": "3.1.0", - "extend": "3.0.1", - "form-data": "2.3.1", - "formidable": "1.2.1", - "methods": "1.1.2", - "mime": "1.4.1", - "qs": "6.5.1", - "readable-stream": "2.3.6" + "component-emitter": "^1.2.0", + "cookiejar": "^2.1.0", + "debug": "^3.1.0", + "extend": "^3.0.0", + "form-data": "^2.3.1", + "formidable": "^1.2.0", + "methods": "^1.1.1", + "mime": "^1.4.1", + "qs": "^6.5.1", + "readable-stream": "^2.3.5" } } } @@ -4141,8 +4678,8 @@ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" + "once": "^1.3.0", + "wrappy": "1" } }, "inherits": { @@ -4162,19 +4699,19 @@ "integrity": "sha1-HvK/1jUE3wvHV4X/+MLEHfEvB34=", "dev": true, "requires": { - "ansi-escapes": "1.4.0", - "ansi-regex": "2.1.1", - "chalk": "1.1.3", - "cli-cursor": "1.0.2", - "cli-width": "2.2.0", - "figures": "1.7.0", - "lodash": "4.17.4", - "readline2": "1.0.1", - "run-async": "0.1.0", - "rx-lite": "3.1.2", - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "through": "2.3.8" + "ansi-escapes": "^1.1.0", + "ansi-regex": "^2.0.0", + "chalk": "^1.0.0", + "cli-cursor": "^1.0.1", + "cli-width": "^2.0.0", + "figures": "^1.3.5", + "lodash": "^4.3.0", + "readline2": "^1.0.1", + "run-async": "^0.1.0", + "rx-lite": "^3.1.2", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.0", + "through": "^2.3.6" } }, "interpret": { @@ -4189,7 +4726,7 @@ "integrity": "sha1-nh9WrArNtr8wMwbzOL47IErmA2A=", "dev": true, "requires": { - "loose-envify": "1.3.1" + "loose-envify": "^1.0.0" } }, "invert-kv": { @@ -4209,8 +4746,8 @@ "integrity": "sha1-IN5p89uULvLYe5wto28XIjWxtes=", "dev": true, "requires": { - "is-relative": "0.2.1", - "is-windows": "0.2.0" + "is-relative": "^0.2.1", + "is-windows": "^0.2.0" } }, "is-arrayish": { @@ -4225,7 +4762,7 @@ "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", "dev": true, "requires": { - "binary-extensions": "1.10.0" + "binary-extensions": "^1.0.0" } }, "is-buffer": { @@ -4239,7 +4776,7 @@ "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", "dev": true, "requires": { - "builtin-modules": "1.1.1" + "builtin-modules": "^1.0.0" } }, "is-dotfile": { @@ -4254,7 +4791,7 @@ "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", "dev": true, "requires": { - "is-primitive": "2.0.0" + "is-primitive": "^2.0.0" } }, "is-extendable": { @@ -4275,7 +4812,7 @@ "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", "dev": true, "requires": { - "number-is-nan": "1.0.1" + "number-is-nan": "^1.0.0" } }, "is-fullwidth-code-point": { @@ -4284,7 +4821,7 @@ "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, "requires": { - "number-is-nan": "1.0.1" + "number-is-nan": "^1.0.0" } }, "is-glob": { @@ -4293,7 +4830,7 @@ "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", "dev": true, "requires": { - "is-extglob": "1.0.0" + "is-extglob": "^1.0.0" } }, "is-installed-globally": { @@ -4302,8 +4839,8 @@ "integrity": "sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=", "dev": true, "requires": { - "global-dirs": "0.1.0", - "is-path-inside": "1.0.0" + "global-dirs": "^0.1.0", + "is-path-inside": "^1.0.0" } }, "is-my-json-valid": { @@ -4312,10 +4849,10 @@ "integrity": "sha512-ochPsqWS1WXj8ZnMIV0vnNXooaMhp7cyL4FMSIPKTtnV0Ha/T19G2b9kkhcNsabV9bxYkze7/aLZJb/bYuFduQ==", "dev": true, "requires": { - "generate-function": "2.0.0", - "generate-object-property": "1.2.0", - "jsonpointer": "4.0.1", - "xtend": "4.0.1" + "generate-function": "^2.0.0", + "generate-object-property": "^1.1.0", + "jsonpointer": "^4.0.0", + "xtend": "^4.0.0" } }, "is-npm": { @@ -4330,7 +4867,7 @@ "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" } }, "is-obj": { @@ -4351,7 +4888,7 @@ "integrity": "sha1-ZHdYK4IU1gI0YJRWcAO+ip6sBNw=", "dev": true, "requires": { - "is-path-inside": "1.0.0" + "is-path-inside": "^1.0.0" } }, "is-path-inside": { @@ -4360,7 +4897,7 @@ "integrity": "sha1-/AbloWg/vaE95mev9xe7wQpI838=", "dev": true, "requires": { - "path-is-inside": "1.0.2" + "path-is-inside": "^1.0.1" } }, "is-plain-object": { @@ -4369,7 +4906,7 @@ "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "dev": true, "requires": { - "isobject": "3.0.1" + "isobject": "^3.0.1" }, "dependencies": { "isobject": { @@ -4416,7 +4953,7 @@ "integrity": "sha1-0n9MfVFtF1+2ENuEu+7yPDvJeqU=", "dev": true, "requires": { - "is-unc-path": "0.1.2" + "is-unc-path": "^0.1.1" } }, "is-resolvable": { @@ -4425,7 +4962,7 @@ "integrity": "sha1-jfV8YeouPFAUCNEA+wE8+NbgzGI=", "dev": true, "requires": { - "tryit": "1.0.3" + "tryit": "^1.0.1" } }, "is-retry-allowed": { @@ -4451,7 +4988,7 @@ "integrity": "sha1-arBTpyVzwQJQ/0FqOBTDUXivObk=", "dev": true, "requires": { - "unc-path-regex": "0.1.2" + "unc-path-regex": "^0.1.0" } }, "is-utf8": { @@ -4510,14 +5047,14 @@ "integrity": "sha1-BglrwI6Yuq10Sq5Gli2N+frGPQg=", "dev": true, "requires": { - "abbrev": "1.0.9", - "async": "1.5.2", - "istanbul-api": "1.2.1", - "js-yaml": "3.10.0", - "mkdirp": "0.5.1", - "nopt": "3.0.6", - "which": "1.3.0", - "wordwrap": "1.0.0" + "abbrev": "1.0.x", + "async": "1.x", + "istanbul-api": "^1.0.0-alpha", + "js-yaml": "3.x", + "mkdirp": "0.5.x", + "nopt": "3.x", + "which": "^1.1.1", + "wordwrap": "^1.0.0" } }, "istanbul-api": { @@ -4526,17 +5063,17 @@ "integrity": "sha512-oFCwXvd65amgaPCzqrR+a2XjanS1MvpXN6l/MlMUTv6uiA1NOgGX+I0uyq8Lg3GDxsxPsaP1049krz3hIJ5+KA==", "dev": true, "requires": { - "async": "2.5.0", - "fileset": "2.0.3", - "istanbul-lib-coverage": "1.1.1", - "istanbul-lib-hook": "1.1.0", - "istanbul-lib-instrument": "1.9.1", - "istanbul-lib-report": "1.1.2", - "istanbul-lib-source-maps": "1.2.2", - "istanbul-reports": "1.1.3", - "js-yaml": "3.10.0", - "mkdirp": "0.5.1", - "once": "1.4.0" + "async": "^2.1.4", + "fileset": "^2.0.2", + "istanbul-lib-coverage": "^1.1.1", + "istanbul-lib-hook": "^1.1.0", + "istanbul-lib-instrument": "^1.9.1", + "istanbul-lib-report": "^1.1.2", + "istanbul-lib-source-maps": "^1.2.2", + "istanbul-reports": "^1.1.3", + "js-yaml": "^3.7.0", + "mkdirp": "^0.5.1", + "once": "^1.4.0" }, "dependencies": { "async": { @@ -4545,7 +5082,7 @@ "integrity": "sha512-e+lJAJeNWuPCNyxZKOBdaJGyLGHugXVQtrAwtuAe2vhxTYxFTKE73p8JuTmdH0qdQZtDvI4dhJwjZc5zsfIsYw==", "dev": true, "requires": { - "lodash": "4.17.4" + "lodash": "^4.14.0" } } } @@ -4562,7 +5099,7 @@ "integrity": "sha512-U3qEgwVDUerZ0bt8cfl3dSP3S6opBoOtk3ROO5f2EfBr/SRiD9FQqzwaZBqFORu8W7O0EXpai+k7kxHK13beRg==", "dev": true, "requires": { - "append-transform": "0.4.0" + "append-transform": "^0.4.0" } }, "istanbul-lib-instrument": { @@ -4571,13 +5108,13 @@ "integrity": "sha512-RQmXeQ7sphar7k7O1wTNzVczF9igKpaeGQAG9qR2L+BS4DCJNTI9nytRmIVYevwO0bbq+2CXvJmYDuz0gMrywA==", "dev": true, "requires": { - "babel-generator": "6.26.0", - "babel-template": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0", - "istanbul-lib-coverage": "1.1.1", - "semver": "5.4.1" + "babel-generator": "^6.18.0", + "babel-template": "^6.16.0", + "babel-traverse": "^6.18.0", + "babel-types": "^6.18.0", + "babylon": "^6.18.0", + "istanbul-lib-coverage": "^1.1.1", + "semver": "^5.3.0" } }, "istanbul-lib-report": { @@ -4586,10 +5123,10 @@ "integrity": "sha512-UTv4VGx+HZivJQwAo1wnRwe1KTvFpfi/NYwN7DcsrdzMXwpRT/Yb6r4SBPoHWj4VuQPakR32g4PUUeyKkdDkBA==", "dev": true, "requires": { - "istanbul-lib-coverage": "1.1.1", - "mkdirp": "0.5.1", - "path-parse": "1.0.5", - "supports-color": "3.2.3" + "istanbul-lib-coverage": "^1.1.1", + "mkdirp": "^0.5.1", + "path-parse": "^1.0.5", + "supports-color": "^3.1.2" }, "dependencies": { "supports-color": { @@ -4598,7 +5135,7 @@ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", "dev": true, "requires": { - "has-flag": "1.0.0" + "has-flag": "^1.0.0" } } } @@ -4609,11 +5146,11 @@ "integrity": "sha512-8BfdqSfEdtip7/wo1RnrvLpHVEd8zMZEDmOFEnpC6dg0vXflHt9nvoAyQUzig2uMSXfF2OBEYBV3CVjIL9JvaQ==", "dev": true, "requires": { - "debug": "3.1.0", - "istanbul-lib-coverage": "1.1.1", - "mkdirp": "0.5.1", - "rimraf": "2.6.2", - "source-map": "0.5.7" + "debug": "^3.1.0", + "istanbul-lib-coverage": "^1.1.1", + "mkdirp": "^0.5.1", + "rimraf": "^2.6.1", + "source-map": "^0.5.3" }, "dependencies": { "debug": { @@ -4631,12 +5168,12 @@ "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, "rimraf": { @@ -4645,7 +5182,7 @@ "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", "dev": true, "requires": { - "glob": "7.1.2" + "glob": "^7.0.5" } } } @@ -4656,7 +5193,7 @@ "integrity": "sha512-ZEelkHh8hrZNI5xDaKwPMFwDsUf5wIEI2bXAFGp1e6deR2mnEKBPhLJEgr4ZBt8Gi6Mj38E/C8kcy9XLggVO2Q==", "dev": true, "requires": { - "handlebars": "4.0.11" + "handlebars": "^4.0.3" } }, "jade": { @@ -4693,10 +5230,10 @@ "resolved": "https://registry.npmjs.org/joi/-/joi-8.4.2.tgz", "integrity": "sha1-vXd0ZY/pkFjYmU7R1LmWJITruFk=", "requires": { - "hoek": "4.2.0", - "isemail": "2.2.1", - "moment": "2.22.2", - "topo": "2.0.2" + "hoek": "4.x.x", + "isemail": "2.x.x", + "moment": "2.x.x", + "topo": "2.x.x" } }, "join-component": { @@ -4710,10 +5247,10 @@ "integrity": "sha512-6YX1g+lIl0/JDxjFFbgj7fz6i0bWFa2Hdc7PfGqFhynaEiYe1NJ3R1nda0VGaRiGU82OllR+EGDoWFpGr3k5Kg==", "dev": true, "requires": { - "config-chain": "1.1.11", - "editorconfig": "0.13.3", - "mkdirp": "0.5.1", - "nopt": "3.0.6" + "config-chain": "~1.1.5", + "editorconfig": "^0.13.2", + "mkdirp": "~0.5.0", + "nopt": "~3.0.1" } }, "js-cookie": { @@ -4738,8 +5275,8 @@ "integrity": "sha512-O2v52ffjLa9VeM43J4XocZE//WT9N0IiwDa3KSHH7Tu8CtH+1qM8SIZvnsTh6v+4yFy5KUY3BHUVwjpfAWsjIA==", "dev": true, "requires": { - "argparse": "1.0.9", - "esprima": "4.0.0" + "argparse": "^1.0.7", + "esprima": "^4.0.0" } }, "jsbn": { @@ -4769,7 +5306,7 @@ "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", "dev": true, "requires": { - "jsonify": "0.0.0" + "jsonify": "~0.0.0" } }, "json-stringify-safe": { @@ -4788,7 +5325,7 @@ "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", "dev": true, "requires": { - "graceful-fs": "4.1.11" + "graceful-fs": "^4.1.6" } }, "jsonify": { @@ -4808,15 +5345,15 @@ "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.3.0.tgz", "integrity": "sha512-oge/hvlmeJCH+iIz1DwcO7vKPkNGJHhgkspk8OH3VKlw+mbi42WtD4ig1+VXRln765vxptAv+xT26Fd3cteqag==", "requires": { - "jws": "3.1.5", - "lodash.includes": "4.3.0", - "lodash.isboolean": "3.0.3", - "lodash.isinteger": "4.0.4", - "lodash.isnumber": "3.0.3", - "lodash.isplainobject": "4.0.6", - "lodash.isstring": "4.0.1", - "lodash.once": "4.1.1", - "ms": "2.1.1" + "jws": "^3.1.5", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1" }, "dependencies": { "ms": { @@ -4844,7 +5381,7 @@ "requires": { "buffer-equal-constant-time": "1.0.1", "ecdsa-sig-formatter": "1.0.10", - "safe-buffer": "5.1.1" + "safe-buffer": "^5.0.1" } }, "jwks-rsa": { @@ -4853,11 +5390,11 @@ "integrity": "sha512-xg+fw7FOV4eGdDIEMqQJvPLmFv85h4uN+j/GKwJZAxlCrDQpM8ov1F709xKGEp/dG3l4TUxoSOeN6YK7+KpinQ==", "requires": { "@types/express-jwt": "0.0.34", - "debug": "2.6.9", - "limiter": "1.1.2", - "lru-memoizer": "1.11.1", - "ms": "2.0.0", - "request": "2.83.0" + "debug": "^2.2.0", + "limiter": "^1.1.0", + "lru-memoizer": "^1.6.0", + "ms": "^2.0.0", + "request": "^2.73.0" } }, "jws": { @@ -4865,8 +5402,8 @@ "resolved": "https://registry.npmjs.org/jws/-/jws-3.1.5.tgz", "integrity": "sha512-GsCSexFADNQUr8T5HPJvayTjvPIfoyJPtLQBwn5a4WZQchcrPMPMAWcC1AzJVRDKyD6ZPROPAxgv6rfHViO4uQ==", "requires": { - "jwa": "1.1.6", - "safe-buffer": "5.1.1" + "jwa": "^1.1.5", + "safe-buffer": "^5.0.1" } }, "kind-of": { @@ -4875,7 +5412,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } }, "latest-version": { @@ -4884,7 +5421,7 @@ "integrity": "sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=", "dev": true, "requires": { - "package-json": "4.0.1" + "package-json": "^4.0.0" } }, "lazy-ass": { @@ -4906,7 +5443,7 @@ "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", "dev": true, "requires": { - "invert-kv": "1.0.0" + "invert-kv": "^1.0.0" } }, "le_node": { @@ -4940,8 +5477,8 @@ "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", "dev": true, "requires": { - "prelude-ls": "1.1.2", - "type-check": "0.3.2" + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" } }, "libpq": { @@ -4950,7 +5487,7 @@ "integrity": "sha1-wt6xIeKPf4S9OyRRr/9otmY+dPk=", "requires": { "bindings": "1.2.1", - "nan": "2.7.0" + "nan": "^2.3.0" } }, "liftoff": { @@ -4959,15 +5496,15 @@ "integrity": "sha1-qY8v9nGD2Lp8+soQVIvX/wVQs4U=", "dev": true, "requires": { - "extend": "3.0.1", - "findup-sync": "0.4.3", - "fined": "1.1.0", - "flagged-respawn": "0.3.2", - "lodash.isplainobject": "4.0.6", - "lodash.isstring": "4.0.1", - "lodash.mapvalues": "4.6.0", - "rechoir": "0.6.2", - "resolve": "1.5.0" + "extend": "^3.0.0", + "findup-sync": "^0.4.2", + "fined": "^1.0.1", + "flagged-respawn": "^0.3.2", + "lodash.isplainobject": "^4.0.4", + "lodash.isstring": "^4.0.1", + "lodash.mapvalues": "^4.4.0", + "rechoir": "^0.6.2", + "resolve": "^1.1.7" }, "dependencies": { "findup-sync": { @@ -4976,10 +5513,10 @@ "integrity": "sha1-QAQ5Kee8YK3wt/SCfExudaDeyhI=", "dev": true, "requires": { - "detect-file": "0.1.0", - "is-glob": "2.0.1", - "micromatch": "2.3.11", - "resolve-dir": "0.1.1" + "detect-file": "^0.1.0", + "is-glob": "^2.0.1", + "micromatch": "^2.3.7", + "resolve-dir": "^0.1.0" } } } @@ -4995,10 +5532,10 @@ "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", "dev": true, "requires": { - "graceful-fs": "4.1.11", - "parse-json": "2.2.0", - "pify": "2.3.0", - "strip-bom": "3.0.0" + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" } }, "locate-path": { @@ -5007,8 +5544,8 @@ "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", "dev": true, "requires": { - "p-locate": "2.0.0", - "path-exists": "3.0.0" + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" }, "dependencies": { "path-exists": { @@ -5040,8 +5577,8 @@ "integrity": "sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=", "dev": true, "requires": { - "lodash._basecopy": "3.0.1", - "lodash.keys": "3.1.2" + "lodash._basecopy": "^3.0.0", + "lodash.keys": "^3.0.0" } }, "lodash._basecopy": { @@ -5074,9 +5611,9 @@ "integrity": "sha1-g4pbri/aymOsIt7o4Z+k5taXCxE=", "dev": true, "requires": { - "lodash._bindcallback": "3.0.1", - "lodash._isiterateecall": "3.0.9", - "lodash.restparam": "3.6.1" + "lodash._bindcallback": "^3.0.0", + "lodash._isiterateecall": "^3.0.0", + "lodash.restparam": "^3.0.0" } }, "lodash._getnative": { @@ -5121,9 +5658,9 @@ "integrity": "sha1-POnwI0tLIiPilrj6CsH+6OvKZPo=", "dev": true, "requires": { - "lodash._baseassign": "3.2.0", - "lodash._createassigner": "3.1.1", - "lodash.keys": "3.1.2" + "lodash._baseassign": "^3.0.0", + "lodash._createassigner": "^3.0.0", + "lodash.keys": "^3.0.0" } }, "lodash.cond": { @@ -5138,8 +5675,8 @@ "integrity": "sha1-xzCLGNv4vJNy1wGnNJPGEZK9Liw=", "dev": true, "requires": { - "lodash.assign": "3.2.0", - "lodash.restparam": "3.6.1" + "lodash.assign": "^3.0.0", + "lodash.restparam": "^3.0.0" } }, "lodash.escape": { @@ -5148,7 +5685,7 @@ "integrity": "sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg=", "dev": true, "requires": { - "lodash._root": "3.0.1" + "lodash._root": "^3.0.0" } }, "lodash.includes": { @@ -5199,9 +5736,9 @@ "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", "dev": true, "requires": { - "lodash._getnative": "3.9.1", - "lodash.isarguments": "3.1.0", - "lodash.isarray": "3.0.4" + "lodash._getnative": "^3.0.0", + "lodash.isarguments": "^3.0.0", + "lodash.isarray": "^3.0.0" } }, "lodash.mapvalues": { @@ -5227,15 +5764,15 @@ "integrity": "sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8=", "dev": true, "requires": { - "lodash._basecopy": "3.0.1", - "lodash._basetostring": "3.0.1", - "lodash._basevalues": "3.0.0", - "lodash._isiterateecall": "3.0.9", - "lodash._reinterpolate": "3.0.0", - "lodash.escape": "3.2.0", - "lodash.keys": "3.1.2", - "lodash.restparam": "3.6.1", - "lodash.templatesettings": "3.1.1" + "lodash._basecopy": "^3.0.0", + "lodash._basetostring": "^3.0.0", + "lodash._basevalues": "^3.0.0", + "lodash._isiterateecall": "^3.0.0", + "lodash._reinterpolate": "^3.0.0", + "lodash.escape": "^3.0.0", + "lodash.keys": "^3.0.0", + "lodash.restparam": "^3.0.0", + "lodash.templatesettings": "^3.0.0" } }, "lodash.templatesettings": { @@ -5244,8 +5781,8 @@ "integrity": "sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU=", "dev": true, "requires": { - "lodash._reinterpolate": "3.0.0", - "lodash.escape": "3.2.0" + "lodash._reinterpolate": "^3.0.0", + "lodash.escape": "^3.0.0" } }, "lolex": { @@ -5266,7 +5803,7 @@ "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", "dev": true, "requires": { - "js-tokens": "3.0.2" + "js-tokens": "^3.0.0" } }, "lowercase-keys": { @@ -5286,10 +5823,10 @@ "resolved": "https://registry.npmjs.org/lru-memoizer/-/lru-memoizer-1.11.1.tgz", "integrity": "sha1-BpP2EAWTkUwC4ZK/m42TiEy/UNM=", "requires": { - "lock": "0.1.4", - "lodash": "4.5.1", - "lru-cache": "4.0.2", - "very-fast-args": "1.1.0" + "lock": "~0.1.2", + "lodash": "~4.5.1", + "lru-cache": "~4.0.0", + "very-fast-args": "^1.1.0" }, "dependencies": { "lodash": { @@ -5302,8 +5839,8 @@ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.0.2.tgz", "integrity": "sha1-HRdnnAac2l0ECZGgnbwsDbN35V4=", "requires": { - "pseudomap": "1.0.2", - "yallist": "2.1.2" + "pseudomap": "^1.0.1", + "yallist": "^2.0.0" } } } @@ -5314,7 +5851,7 @@ "integrity": "sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM=", "dev": true, "requires": { - "es5-ext": "0.10.35" + "es5-ext": "~0.10.2" } }, "make-dir": { @@ -5323,7 +5860,7 @@ "integrity": "sha512-0Pkui4wLJ7rxvmfUvs87skoEaxmu0hCUApF8nonzpl7q//FWp9zu8W61Scz4sd/kUiqDxvUhtoam2efDyiBzcA==", "dev": true, "requires": { - "pify": "3.0.0" + "pify": "^3.0.0" }, "dependencies": { "pify": { @@ -5357,7 +5894,7 @@ "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", "dev": true, "requires": { - "mimic-fn": "1.1.0" + "mimic-fn": "^1.0.0" } }, "memoizee": { @@ -5366,14 +5903,23 @@ "integrity": "sha1-vemBdmPJ5A/bKk6hw2cpYIeujI8=", "dev": true, "requires": { - "d": "1.0.0", - "es5-ext": "0.10.35", - "es6-weak-map": "2.0.2", - "event-emitter": "0.3.5", - "is-promise": "2.1.0", - "lru-queue": "0.1.0", - "next-tick": "1.0.0", - "timers-ext": "0.1.2" + "d": "1", + "es5-ext": "^0.10.30", + "es6-weak-map": "^2.0.2", + "event-emitter": "^0.3.5", + "is-promise": "^2.1", + "lru-queue": "0.1", + "next-tick": "1", + "timers-ext": "^0.1.2" + } + }, + "memwatch-next": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/memwatch-next/-/memwatch-next-0.3.0.tgz", + "integrity": "sha1-IREFD5qQbgqi1ypOwPAInHhyb48=", + "requires": { + "bindings": "^1.2.1", + "nan": "^2.3.2" } }, "merge-descriptors": { @@ -5387,9 +5933,9 @@ "integrity": "sha1-49r41d7hDdLc59SuiNYrvud0drQ=", "requires": { "debug": "2.6.9", - "methods": "1.1.2", - "parseurl": "1.3.2", - "vary": "1.1.2" + "methods": "~1.1.2", + "parseurl": "~1.3.2", + "vary": "~1.1.2" } }, "methods": { @@ -5403,19 +5949,19 @@ "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", "dev": true, "requires": { - "arr-diff": "2.0.0", - "array-unique": "0.2.1", - "braces": "1.8.5", - "expand-brackets": "0.1.5", - "extglob": "0.3.2", - "filename-regex": "2.0.1", - "is-extglob": "1.0.0", - "is-glob": "2.0.1", - "kind-of": "3.2.2", - "normalize-path": "2.1.1", - "object.omit": "2.0.1", - "parse-glob": "3.0.4", - "regex-cache": "0.4.4" + "arr-diff": "^2.0.0", + "array-unique": "^0.2.1", + "braces": "^1.8.2", + "expand-brackets": "^0.1.4", + "extglob": "^0.3.1", + "filename-regex": "^2.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.1", + "kind-of": "^3.0.2", + "normalize-path": "^2.0.1", + "object.omit": "^2.0.0", + "parse-glob": "^3.0.4", + "regex-cache": "^0.4.2" } }, "millisecond": { @@ -5438,7 +5984,7 @@ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", "requires": { - "mime-db": "1.30.0" + "mime-db": "~1.30.0" } }, "mimic-fn": { @@ -5452,7 +5998,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "requires": { - "brace-expansion": "1.1.8" + "brace-expansion": "^1.1.7" } }, "minimist": { @@ -5513,8 +6059,8 @@ "integrity": "sha1-Spc/Y1uRkPcV0QmH1cAP0oFevj0=", "dev": true, "requires": { - "inherits": "2.0.3", - "minimatch": "0.3.0" + "inherits": "2", + "minimatch": "0.3" } }, "minimatch": { @@ -5523,8 +6069,8 @@ "integrity": "sha1-J12O2qxPG7MyZHIInnlJyDlGmd0=", "dev": true, "requires": { - "lru-cache": "2.7.3", - "sigmund": "1.0.1" + "lru-cache": "2", + "sigmund": "~1.0.0" } }, "ms": { @@ -5551,7 +6097,7 @@ "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.14.tgz", "integrity": "sha1-TrOP+VOLgBCLpGekWPPtQmjM/LE=", "requires": { - "moment": "2.22.2" + "moment": ">= 2.9.0" } }, "ms": { @@ -5580,9 +6126,9 @@ "integrity": "sha1-rmzg1vbV4KT32JN5jQPB6pVZtqI=", "optional": true, "requires": { - "mkdirp": "0.5.1", - "ncp": "2.0.0", - "rimraf": "2.4.5" + "mkdirp": "~0.5.1", + "ncp": "~2.0.0", + "rimraf": "~2.4.0" } }, "nan": { @@ -5625,16 +6171,16 @@ "integrity": "sha1-mWpW3EnZ8Wu/G3ik3gjxNjSzh40=", "dev": true, "requires": { - "chokidar": "1.7.0", - "debug": "2.6.9", - "es6-promise": "3.3.1", - "ignore-by-default": "1.0.1", - "lodash.defaults": "3.1.2", - "minimatch": "3.0.4", - "ps-tree": "1.1.0", - "touch": "3.1.0", + "chokidar": "^1.7.0", + "debug": "^2.6.8", + "es6-promise": "^3.3.1", + "ignore-by-default": "^1.0.1", + "lodash.defaults": "^3.1.2", + "minimatch": "^3.0.4", + "ps-tree": "^1.1.0", + "touch": "^3.1.0", "undefsafe": "0.0.3", - "update-notifier": "2.3.0" + "update-notifier": "^2.2.0" } }, "nopt": { @@ -5643,7 +6189,7 @@ "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", "dev": true, "requires": { - "abbrev": "1.0.9" + "abbrev": "1" } }, "normalize-package-data": { @@ -5652,10 +6198,10 @@ "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", "dev": true, "requires": { - "hosted-git-info": "2.5.0", - "is-builtin-module": "1.0.0", - "semver": "5.4.1", - "validate-npm-package-license": "3.0.1" + "hosted-git-info": "^2.1.4", + "is-builtin-module": "^1.0.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" } }, "normalize-path": { @@ -5664,7 +6210,7 @@ "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", "dev": true, "requires": { - "remove-trailing-separator": "1.1.0" + "remove-trailing-separator": "^1.0.1" } }, "npm-run-path": { @@ -5673,7 +6219,7 @@ "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", "dev": true, "requires": { - "path-key": "2.0.1" + "path-key": "^2.0.0" } }, "number-is-nan": { @@ -5698,10 +6244,10 @@ "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=", "dev": true, "requires": { - "array-each": "1.0.1", - "array-slice": "1.0.0", - "for-own": "1.0.0", - "isobject": "3.0.1" + "array-each": "^1.0.1", + "array-slice": "^1.0.0", + "for-own": "^1.0.0", + "isobject": "^3.0.0" }, "dependencies": { "for-own": { @@ -5710,7 +6256,7 @@ "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", "dev": true, "requires": { - "for-in": "1.0.2" + "for-in": "^1.0.1" } }, "isobject": { @@ -5727,8 +6273,8 @@ "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", "dev": true, "requires": { - "for-own": "0.1.5", - "is-extendable": "0.1.1" + "for-own": "^0.1.4", + "is-extendable": "^0.1.1" } }, "object.pick": { @@ -5737,7 +6283,7 @@ "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", "dev": true, "requires": { - "isobject": "3.0.1" + "isobject": "^3.0.1" }, "dependencies": { "isobject": { @@ -5761,7 +6307,7 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "requires": { - "wrappy": "1.0.2" + "wrappy": "1" } }, "onetime": { @@ -5776,8 +6322,8 @@ "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", "dev": true, "requires": { - "minimist": "0.0.8", - "wordwrap": "0.0.3" + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" }, "dependencies": { "wordwrap": { @@ -5794,12 +6340,12 @@ "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", "dev": true, "requires": { - "deep-is": "0.1.3", - "fast-levenshtein": "2.0.6", - "levn": "0.3.0", - "prelude-ls": "1.1.2", - "type-check": "0.3.2", - "wordwrap": "1.0.0" + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.4", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "wordwrap": "~1.0.0" } }, "orchestrator": { @@ -5808,9 +6354,9 @@ "integrity": "sha1-FOfp4nZPcxX7rBhOUGx6pt+UrX4=", "dev": true, "requires": { - "end-of-stream": "0.1.5", - "sequencify": "0.0.7", - "stream-consume": "0.1.0" + "end-of-stream": "~0.1.5", + "sequencify": "~0.0.7", + "stream-consume": "~0.1.0" } }, "ordered-read-streams": { @@ -5830,9 +6376,9 @@ "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", "dev": true, "requires": { - "execa": "0.7.0", - "lcid": "1.0.0", - "mem": "1.1.0" + "execa": "^0.7.0", + "lcid": "^1.0.0", + "mem": "^1.1.0" } }, "os-tmpdir": { @@ -5847,9 +6393,9 @@ "integrity": "sha1-0KM+7+YaIF+suQCS6CZZjVJFznY=", "dev": true, "requires": { - "graceful-fs": "4.1.11", - "mkdirp": "0.5.1", - "object-assign": "4.1.1" + "graceful-fs": "^4.1.4", + "mkdirp": "^0.5.1", + "object-assign": "^4.1.0" } }, "p-finally": { @@ -5870,7 +6416,7 @@ "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", "dev": true, "requires": { - "p-limit": "1.1.0" + "p-limit": "^1.1.0" } }, "package-json": { @@ -5879,10 +6425,10 @@ "integrity": "sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=", "dev": true, "requires": { - "got": "6.7.1", - "registry-auth-token": "3.3.1", - "registry-url": "3.1.0", - "semver": "5.4.1" + "got": "^6.7.1", + "registry-auth-token": "^3.0.1", + "registry-url": "^3.0.3", + "semver": "^5.1.0" } }, "packet-reader": { @@ -5896,9 +6442,9 @@ "integrity": "sha1-FZ1hVdQ5BNFsEO9piRHaHpGWm3M=", "dev": true, "requires": { - "is-absolute": "0.2.6", - "map-cache": "0.2.2", - "path-root": "0.1.1" + "is-absolute": "^0.2.3", + "map-cache": "^0.2.0", + "path-root": "^0.1.1" } }, "parse-glob": { @@ -5907,10 +6453,10 @@ "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", "dev": true, "requires": { - "glob-base": "0.3.0", - "is-dotfile": "1.0.3", - "is-extglob": "1.0.0", - "is-glob": "2.0.1" + "glob-base": "^0.3.0", + "is-dotfile": "^1.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.0" } }, "parse-json": { @@ -5919,7 +6465,7 @@ "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", "dev": true, "requires": { - "error-ex": "1.3.1" + "error-ex": "^1.2.0" } }, "parse-passwd": { @@ -5939,7 +6485,7 @@ "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", "dev": true, "requires": { - "pinkie-promise": "2.0.1" + "pinkie-promise": "^2.0.0" } }, "path-is-absolute": { @@ -5971,7 +6517,7 @@ "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=", "dev": true, "requires": { - "path-root-regex": "0.1.2" + "path-root-regex": "^0.1.0" } }, "path-root-regex": { @@ -5991,7 +6537,7 @@ "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", "dev": true, "requires": { - "pify": "2.3.0" + "pify": "^2.0.0" } }, "pause-stream": { @@ -6000,7 +6546,7 @@ "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", "dev": true, "requires": { - "through": "2.3.8" + "through": "~2.3" } }, "performance-now": { @@ -6018,9 +6564,9 @@ "js-string-escape": "1.0.1", "packet-reader": "0.2.0", "pg-connection-string": "0.1.3", - "pg-types": "1.12.1", + "pg-types": "1.*", "pgpass": "0.0.3", - "semver": "4.3.6" + "semver": "^4.1.0" }, "dependencies": { "semver": { @@ -6040,7 +6586,7 @@ "resolved": "https://registry.npmjs.org/pg-native/-/pg-native-1.10.1.tgz", "integrity": "sha1-lOYcy7hafzQ2suUmMVx1gRB/5Aw=", "requires": { - "libpq": "1.8.7", + "libpq": "^1.7.0", "pg-types": "1.6.0", "readable-stream": "1.0.31" }, @@ -6055,10 +6601,10 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.31.tgz", "integrity": "sha1-jyUC4LyeOw2huUUgqrtOJgPsr64=", "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", "isarray": "0.0.1", - "string_decoder": "0.10.31" + "string_decoder": "~0.10.x" } } } @@ -6068,10 +6614,10 @@ "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-1.12.1.tgz", "integrity": "sha1-1kCH45A7WP+q0nnnWVxSIIoUw9I=", "requires": { - "postgres-array": "1.0.2", - "postgres-bytea": "1.0.0", - "postgres-date": "1.0.3", - "postgres-interval": "1.1.1" + "postgres-array": "~1.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.0", + "postgres-interval": "^1.1.0" } }, "pgpass": { @@ -6079,7 +6625,7 @@ "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-0.0.3.tgz", "integrity": "sha1-EuZ+NDsxicLzEgbrycwL7//PkUA=", "requires": { - "split": "0.3.3" + "split": "~0.3" } }, "pify": { @@ -6100,7 +6646,7 @@ "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", "dev": true, "requires": { - "pinkie": "2.0.4" + "pinkie": "^2.0.0" } }, "pkg-dir": { @@ -6109,7 +6655,7 @@ "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", "dev": true, "requires": { - "find-up": "1.1.2" + "find-up": "^1.0.0" } }, "pluralize": { @@ -6138,7 +6684,7 @@ "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.1.1.tgz", "integrity": "sha512-OkuCi9t/3CZmeQreutGgx/OVNv9MKHGIT5jH8KldQ4NLYXkvmT9nDVxEuCENlNwhlGPE374oA/xMqn05G49pHA==", "requires": { - "xtend": "4.0.1" + "xtend": "^4.0.0" } }, "precond": { @@ -6192,7 +6738,7 @@ "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", "requires": { - "asap": "2.0.6" + "asap": "~2.0.3" } }, "proto-list": { @@ -6206,7 +6752,7 @@ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.2.tgz", "integrity": "sha1-ZXFQT0e7mI7IGAJT+F3X4UlSvew=", "requires": { - "forwarded": "0.1.2", + "forwarded": "~0.1.2", "ipaddr.js": "1.5.2" } }, @@ -6216,7 +6762,7 @@ "integrity": "sha1-tCGyQUDWID8e08dplrRCewjowBQ=", "dev": true, "requires": { - "event-stream": "3.3.4" + "event-stream": "~3.3.0" } }, "pseudomap": { @@ -6245,8 +6791,8 @@ "integrity": "sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==", "dev": true, "requires": { - "is-number": "3.0.0", - "kind-of": "4.0.0" + "is-number": "^3.0.0", + "kind-of": "^4.0.0" }, "dependencies": { "is-number": { @@ -6255,7 +6801,7 @@ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -6264,7 +6810,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -6275,7 +6821,7 @@ "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -6302,10 +6848,10 @@ "integrity": "sha1-2M6ctX6NZNnHut2YdsfDTL48cHc=", "dev": true, "requires": { - "deep-extend": "0.4.2", - "ini": "1.3.4", - "minimist": "1.2.0", - "strip-json-comments": "2.0.1" + "deep-extend": "~0.4.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" }, "dependencies": { "minimist": { @@ -6322,9 +6868,9 @@ "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", "dev": true, "requires": { - "load-json-file": "2.0.0", - "normalize-package-data": "2.4.0", - "path-type": "2.0.0" + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" } }, "read-pkg-up": { @@ -6333,8 +6879,8 @@ "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", "dev": true, "requires": { - "find-up": "2.1.0", - "read-pkg": "2.0.0" + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" }, "dependencies": { "find-up": { @@ -6343,7 +6889,7 @@ "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", "dev": true, "requires": { - "locate-path": "2.0.0" + "locate-path": "^2.0.0" } } } @@ -6353,10 +6899,10 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", "isarray": "0.0.1", - "string_decoder": "0.10.31" + "string_decoder": "~0.10.x" } }, "readdirp": { @@ -6365,10 +6911,10 @@ "integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=", "dev": true, "requires": { - "graceful-fs": "4.1.11", - "minimatch": "3.0.4", - "readable-stream": "2.3.3", - "set-immediate-shim": "1.0.1" + "graceful-fs": "^4.1.2", + "minimatch": "^3.0.2", + "readable-stream": "^2.0.2", + "set-immediate-shim": "^1.0.1" }, "dependencies": { "isarray": { @@ -6383,13 +6929,13 @@ "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", "dev": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "safe-buffer": "5.1.1", - "string_decoder": "1.0.3", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.0.3", + "util-deprecate": "~1.0.1" } }, "string_decoder": { @@ -6398,7 +6944,7 @@ "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", "dev": true, "requires": { - "safe-buffer": "5.1.1" + "safe-buffer": "~5.1.0" } } } @@ -6409,8 +6955,8 @@ "integrity": "sha1-QQWWCP/BVHV7cV2ZidGZ/783LjU=", "dev": true, "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", "mute-stream": "0.0.5" } }, @@ -6430,7 +6976,7 @@ "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", "dev": true, "requires": { - "resolve": "1.5.0" + "resolve": "^1.1.6" } }, "reconnect-core": { @@ -6438,7 +6984,7 @@ "resolved": "https://registry.npmjs.org/reconnect-core/-/reconnect-core-1.3.0.tgz", "integrity": "sha1-+65SkZp4d9hE4yRtAaLyZwHIM8g=", "requires": { - "backoff": "2.5.0" + "backoff": "~2.5.0" } }, "redefine": { @@ -6465,9 +7011,9 @@ "integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==", "dev": true, "requires": { - "babel-runtime": "6.26.0", - "babel-types": "6.26.0", - "private": "0.1.8" + "babel-runtime": "^6.18.0", + "babel-types": "^6.19.0", + "private": "^0.1.6" }, "dependencies": { "babel-runtime": { @@ -6476,8 +7022,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.1", - "regenerator-runtime": "0.11.0" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } } } @@ -6488,7 +7034,7 @@ "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", "dev": true, "requires": { - "is-equal-shallow": "0.1.3" + "is-equal-shallow": "^0.1.3" } }, "regexpu-core": { @@ -6497,9 +7043,9 @@ "integrity": "sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA=", "dev": true, "requires": { - "regenerate": "1.3.3", - "regjsgen": "0.2.0", - "regjsparser": "0.1.5" + "regenerate": "^1.2.1", + "regjsgen": "^0.2.0", + "regjsparser": "^0.1.4" } }, "registry-auth-token": { @@ -6508,8 +7054,8 @@ "integrity": "sha1-+w0yie4Nmtosu1KvXf5mywcNMAY=", "dev": true, "requires": { - "rc": "1.2.2", - "safe-buffer": "5.1.1" + "rc": "^1.1.6", + "safe-buffer": "^5.0.1" } }, "registry-url": { @@ -6518,7 +7064,7 @@ "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=", "dev": true, "requires": { - "rc": "1.2.2" + "rc": "^1.0.1" } }, "regjsgen": { @@ -6533,7 +7079,7 @@ "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", "dev": true, "requires": { - "jsesc": "0.5.0" + "jsesc": "~0.5.0" }, "dependencies": { "jsesc": { @@ -6573,7 +7119,7 @@ "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", "dev": true, "requires": { - "is-finite": "1.0.2" + "is-finite": "^1.0.0" } }, "replace-ext": { @@ -6587,28 +7133,28 @@ "resolved": "https://registry.npmjs.org/request/-/request-2.83.0.tgz", "integrity": "sha512-lR3gD69osqm6EYLk9wB/G1W/laGWjzH90t1vEa2xuxHD5KUrSzp9pUSfTm+YC5Nxt2T8nMPEvKlhbQayU7bgFw==", "requires": { - "aws-sign2": "0.7.0", - "aws4": "1.6.0", - "caseless": "0.12.0", - "combined-stream": "1.0.5", - "extend": "3.0.1", - "forever-agent": "0.6.1", - "form-data": "2.3.1", - "har-validator": "5.0.3", - "hawk": "6.0.2", - "http-signature": "1.2.0", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.17", - "oauth-sign": "0.8.2", - "performance-now": "2.1.0", - "qs": "6.5.1", - "safe-buffer": "5.1.1", - "stringstream": "0.0.5", - "tough-cookie": "2.3.3", - "tunnel-agent": "0.6.0", - "uuid": "3.1.0" + "aws-sign2": "~0.7.0", + "aws4": "^1.6.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.5", + "extend": "~3.0.1", + "forever-agent": "~0.6.1", + "form-data": "~2.3.1", + "har-validator": "~5.0.3", + "hawk": "~6.0.2", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.17", + "oauth-sign": "~0.8.2", + "performance-now": "^2.1.0", + "qs": "~6.5.1", + "safe-buffer": "^5.1.1", + "stringstream": "~0.0.5", + "tough-cookie": "~2.3.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.1.0" } }, "require-directory": { @@ -6629,8 +7175,8 @@ "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", "dev": true, "requires": { - "caller-path": "0.1.0", - "resolve-from": "1.0.1" + "caller-path": "^0.1.0", + "resolve-from": "^1.0.0" } }, "resolve": { @@ -6639,7 +7185,7 @@ "integrity": "sha512-hgoSGrc3pjzAPHNBg+KnFcK2HwlHTs/YrAGUr6qgTVUZmXv1UEXXl0bZNBKMA9fud6lRYFdPGz0xXxycPzmmiw==", "dev": true, "requires": { - "path-parse": "1.0.5" + "path-parse": "^1.0.5" } }, "resolve-dir": { @@ -6648,8 +7194,8 @@ "integrity": "sha1-shklmlYC+sXFxJatiUpujMQwJh4=", "dev": true, "requires": { - "expand-tilde": "1.2.2", - "global-modules": "0.2.3" + "expand-tilde": "^1.2.2", + "global-modules": "^0.2.3" } }, "resolve-from": { @@ -6664,8 +7210,8 @@ "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", "dev": true, "requires": { - "exit-hook": "1.1.1", - "onetime": "1.1.0" + "exit-hook": "^1.0.0", + "onetime": "^1.0.0" } }, "retry-as-promised": { @@ -6673,8 +7219,8 @@ "resolved": "https://registry.npmjs.org/retry-as-promised/-/retry-as-promised-2.3.2.tgz", "integrity": "sha1-zZdO5P2bX+A8vzGHHuSCIcB3N7c=", "requires": { - "bluebird": "3.5.1", - "debug": "2.6.9" + "bluebird": "^3.4.6", + "debug": "^2.6.9" } }, "right-align": { @@ -6684,7 +7230,7 @@ "dev": true, "optional": true, "requires": { - "align-text": "0.1.4" + "align-text": "^0.1.1" } }, "rimraf": { @@ -6692,7 +7238,7 @@ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz", "integrity": "sha1-7nEM5dk6j9uFb7Xqj/Di11k0sto=", "requires": { - "glob": "6.0.4" + "glob": "^6.0.1" } }, "run-async": { @@ -6701,7 +7247,7 @@ "integrity": "sha1-yK1KXhEGYeQCp9IbUw4AnyX444k=", "dev": true, "requires": { - "once": "1.4.0" + "once": "^1.3.0" } }, "rx-lite": { @@ -6748,7 +7294,7 @@ "integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=", "dev": true, "requires": { - "semver": "5.4.1" + "semver": "^5.0.3" } }, "send": { @@ -6757,18 +7303,18 @@ "integrity": "sha512-ElCLJdJIKPk6ux/Hocwhk7NFHpI3pVm/IZOYWqUmoxcgeyM+MpxHHKhb8QmlJDX1pU6WrgaHBkVNm73Sv7uc2A==", "requires": { "debug": "2.6.9", - "depd": "1.1.1", - "destroy": "1.0.4", - "encodeurl": "1.0.1", - "escape-html": "1.0.3", - "etag": "1.8.1", + "depd": "~1.1.1", + "destroy": "~1.0.4", + "encodeurl": "~1.0.1", + "escape-html": "~1.0.3", + "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "1.6.2", + "http-errors": "~1.6.2", "mime": "1.4.1", "ms": "2.0.0", - "on-finished": "2.3.0", - "range-parser": "1.2.0", - "statuses": "1.3.1" + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.3.1" }, "dependencies": { "statuses": { @@ -6783,21 +7329,21 @@ "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-3.30.4.tgz", "integrity": "sha1-vaLfHjGFSwmeQUmhEen8Clyh0aQ=", "requires": { - "bluebird": "3.5.1", - "depd": "1.1.1", - "dottie": "1.1.1", + "bluebird": "^3.3.4", + "depd": "^1.1.0", + "dottie": "^1.0.0", "generic-pool": "2.4.2", - "inflection": "1.12.0", + "inflection": "^1.6.0", "lodash": "4.12.0", - "moment": "2.22.2", - "moment-timezone": "0.5.14", - "retry-as-promised": "2.3.2", - "semver": "5.4.1", + "moment": "^2.13.0", + "moment-timezone": "^0.5.4", + "retry-as-promised": "^2.0.0", + "semver": "^5.0.1", "shimmer": "1.1.0", - "terraformer-wkt-parser": "1.1.2", - "toposort-class": "1.0.1", - "uuid": "3.1.0", - "validator": "5.7.0", + "terraformer-wkt-parser": "^1.1.0", + "toposort-class": "^1.0.1", + "uuid": "^3.0.0", + "validator": "^5.2.0", "wkx": "0.2.0" }, "dependencies": { @@ -6814,18 +7360,18 @@ "integrity": "sha1-QwTM5g5JkWlgP4ON7bq0IcmEnnQ=", "dev": true, "requires": { - "bluebird": "3.5.1", - "cli-color": "1.2.0", - "findup-sync": "1.0.0", - "fs-extra": "4.0.2", - "gulp": "3.9.1", - "gulp-help": "1.6.1", - "js-beautify": "1.7.4", - "lodash": "4.17.4", - "moment": "2.22.2", - "resolve": "1.5.0", - "umzug": "1.12.0", - "yargs": "8.0.2" + "bluebird": "^3.5.0", + "cli-color": "~1.2.0", + "findup-sync": "^1.0.0", + "fs-extra": "^4.0.1", + "gulp": "^3.9.1", + "gulp-help": "~1.6.1", + "js-beautify": "^1.6.11", + "lodash": "^4.17.4", + "moment": "^2.17.1", + "resolve": "^1.3.3", + "umzug": "^1.12.0", + "yargs": "^8.0.1" }, "dependencies": { "ansi-regex": { @@ -6846,9 +7392,9 @@ "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", "dev": true, "requires": { - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "wrap-ansi": "2.1.0" + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" }, "dependencies": { "string-width": { @@ -6857,9 +7403,9 @@ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" } } } @@ -6870,8 +7416,8 @@ "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "4.0.0" + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" }, "dependencies": { "is-fullwidth-code-point": { @@ -6886,7 +7432,7 @@ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { - "ansi-regex": "3.0.0" + "ansi-regex": "^3.0.0" } } } @@ -6897,19 +7443,19 @@ "integrity": "sha1-YpmpBVsc78lp/355wdkY3Osiw2A=", "dev": true, "requires": { - "camelcase": "4.1.0", - "cliui": "3.2.0", - "decamelize": "1.2.0", - "get-caller-file": "1.0.2", - "os-locale": "2.1.0", - "read-pkg-up": "2.0.0", - "require-directory": "2.1.1", - "require-main-filename": "1.0.1", - "set-blocking": "2.0.0", - "string-width": "2.1.1", - "which-module": "2.0.0", - "y18n": "3.2.1", - "yargs-parser": "7.0.0" + "camelcase": "^4.1.0", + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "os-locale": "^2.0.0", + "read-pkg-up": "^2.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^7.0.0" } } } @@ -6925,9 +7471,9 @@ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.1.tgz", "integrity": "sha512-hSMUZrsPa/I09VYFJwa627JJkNs0NrfL1Uzuup+GqHfToR2KcsXFymXSV90hoyw3M+msjFuQly+YzIH/q0MGlQ==", "requires": { - "encodeurl": "1.0.1", - "escape-html": "1.0.3", - "parseurl": "1.3.2", + "encodeurl": "~1.0.1", + "escape-html": "~1.0.3", + "parseurl": "~1.3.2", "send": "0.16.1" } }, @@ -6954,7 +7500,7 @@ "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "dev": true, "requires": { - "shebang-regex": "1.0.0" + "shebang-regex": "^1.0.0" } }, "shebang-regex": { @@ -6969,9 +7515,9 @@ "integrity": "sha1-3svPh0sNHl+3LhSxZKloMEjprLM=", "dev": true, "requires": { - "glob": "7.1.2", - "interpret": "1.0.4", - "rechoir": "0.6.2" + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" }, "dependencies": { "glob": { @@ -6980,12 +7526,12 @@ "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } } } @@ -7016,7 +7562,7 @@ "formatio": "1.1.1", "lolex": "1.3.2", "samsam": "1.1.2", - "util": "0.10.3" + "util": ">=0.10.3 <1" } }, "sinon-chai": { @@ -7037,7 +7583,7 @@ "integrity": "sha1-h4+h1E0I7rDyb7IBjvhinrGjq5Q=", "dev": true, "requires": { - "nan": "2.7.0" + "nan": ">=2.5.1" } }, "slice-ansi": { @@ -7051,7 +7597,7 @@ "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", "integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==", "requires": { - "hoek": "4.2.0" + "hoek": "4.x.x" } }, "source-map": { @@ -7066,7 +7612,7 @@ "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", "dev": true, "requires": { - "source-map": "0.5.7" + "source-map": "^0.5.6" } }, "sparkles": { @@ -7081,7 +7627,7 @@ "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=", "dev": true, "requires": { - "spdx-license-ids": "1.2.2" + "spdx-license-ids": "^1.0.2" } }, "spdx-expression-parse": { @@ -7101,7 +7647,7 @@ "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz", "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=", "requires": { - "through": "2.3.8" + "through": "2" } }, "sprintf-js": { @@ -7115,14 +7661,14 @@ "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", "requires": { - "asn1": "0.2.3", - "assert-plus": "1.0.0", - "bcrypt-pbkdf": "1.0.1", - "dashdash": "1.14.1", - "ecc-jsbn": "0.1.1", - "getpass": "0.1.7", - "jsbn": "0.1.1", - "tweetnacl": "0.14.5" + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "tweetnacl": "~0.14.0" } }, "statuses": { @@ -7136,7 +7682,7 @@ "integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=", "dev": true, "requires": { - "duplexer": "0.1.1" + "duplexer": "~0.1.1" } }, "stream-consume": { @@ -7144,22 +7690,22 @@ "resolved": "https://registry.npmjs.org/stream-consume/-/stream-consume-0.1.0.tgz", "integrity": "sha1-pB6tGm1ggc63n2WwYZAbbY89HQ8=" }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - }, "string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" } }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + }, "stringstream": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", @@ -7170,7 +7716,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "strip-bom": { @@ -7196,16 +7742,16 @@ "resolved": "https://registry.npmjs.org/superagent/-/superagent-3.8.0.tgz", "integrity": "sha512-71XGWgtn70TNwgmgYa69dPOYg55aU9FCahjUNY03rOrKvaTCaU3b9MeZmqonmf9Od96SCxr3vGfEAnhM7dtxCw==", "requires": { - "component-emitter": "1.2.1", - "cookiejar": "2.1.1", - "debug": "3.1.0", - "extend": "3.0.1", - "form-data": "2.3.1", - "formidable": "1.1.1", - "methods": "1.1.2", - "mime": "1.4.1", - "qs": "6.5.1", - "readable-stream": "2.3.3" + "component-emitter": "^1.2.0", + "cookiejar": "^2.1.0", + "debug": "^3.1.0", + "extend": "^3.0.0", + "form-data": "^2.3.1", + "formidable": "^1.1.1", + "methods": "^1.1.1", + "mime": "^1.4.1", + "qs": "^6.5.1", + "readable-stream": "^2.0.5" }, "dependencies": { "debug": { @@ -7226,13 +7772,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "safe-buffer": "5.1.1", - "string_decoder": "1.0.3", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.0.3", + "util-deprecate": "~1.0.1" } }, "string_decoder": { @@ -7240,7 +7786,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", "requires": { - "safe-buffer": "5.1.1" + "safe-buffer": "~5.1.0" } } } @@ -7256,8 +7802,8 @@ "integrity": "sha1-oFgIHXiPFRXUcA11Aogea3WeRM0=", "dev": true, "requires": { - "methods": "1.1.2", - "superagent": "2.3.0" + "methods": "1.x", + "superagent": "^2.0.0" }, "dependencies": { "form-data": { @@ -7266,9 +7812,9 @@ "integrity": "sha1-BaxrwiIntD5EYfSIFhVUaZ1Pi14=", "dev": true, "requires": { - "async": "1.5.2", - "combined-stream": "1.0.5", - "mime-types": "2.1.17" + "async": "^1.5.2", + "combined-stream": "^1.0.5", + "mime-types": "^2.1.10" } }, "isarray": { @@ -7283,13 +7829,13 @@ "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", "dev": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "safe-buffer": "5.1.1", - "string_decoder": "1.0.3", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.0.3", + "util-deprecate": "~1.0.1" } }, "string_decoder": { @@ -7298,7 +7844,7 @@ "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", "dev": true, "requires": { - "safe-buffer": "5.1.1" + "safe-buffer": "~5.1.0" } }, "superagent": { @@ -7307,16 +7853,16 @@ "integrity": "sha1-cDUpoHFOV+EjlZ3e+84ZOy5Q0RU=", "dev": true, "requires": { - "component-emitter": "1.2.1", - "cookiejar": "2.1.1", - "debug": "2.6.9", - "extend": "3.0.1", + "component-emitter": "^1.2.0", + "cookiejar": "^2.0.6", + "debug": "^2.2.0", + "extend": "^3.0.0", "form-data": "1.0.0-rc4", - "formidable": "1.1.1", - "methods": "1.1.2", - "mime": "1.4.1", - "qs": "6.5.1", - "readable-stream": "2.3.3" + "formidable": "^1.0.17", + "methods": "^1.1.1", + "mime": "^1.3.4", + "qs": "^6.1.0", + "readable-stream": "^2.0.5" } } } @@ -7332,12 +7878,12 @@ "integrity": "sha1-K7xULw/amGGnVdOUf+/Ys/UThV8=", "dev": true, "requires": { - "ajv": "4.11.8", - "ajv-keywords": "1.5.1", - "chalk": "1.1.3", - "lodash": "4.17.4", + "ajv": "^4.7.0", + "ajv-keywords": "^1.0.0", + "chalk": "^1.1.1", + "lodash": "^4.0.0", "slice-ansi": "0.0.4", - "string-width": "2.1.1" + "string-width": "^2.0.0" }, "dependencies": { "ansi-regex": { @@ -7358,8 +7904,8 @@ "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "4.0.0" + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" } }, "strip-ansi": { @@ -7368,23 +7914,24 @@ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { - "ansi-regex": "3.0.0" + "ansi-regex": "^3.0.0" } } } }, "tc-core-library-js": { "version": "github:appirio-tech/tc-core-library-js#df1f5c1a5578d3d1e475bfb4a7413d9dec25525a", - "requires": { - "auth0-js": "9.6.0", - "axios": "0.12.0", - "bunyan": "1.8.12", - "config": "1.27.0", - "jsonwebtoken": "7.4.3", - "jwks-rsa": "1.2.1", - "le_node": "1.7.1", - "lodash": "4.17.4", - "millisecond": "0.1.2" + "from": "github:appirio-tech/tc-core-library-js#v2.3", + "requires": { + "auth0-js": "^9.4.2", + "axios": "^0.12.0", + "bunyan": "^1.8.1", + "config": "^1.21.0", + "jsonwebtoken": "^7.0.0", + "jwks-rsa": "^1.2.1", + "le_node": "^1.3.1", + "lodash": "^4.13.1", + "millisecond": "^0.1.2" }, "dependencies": { "axios": { @@ -7400,8 +7947,8 @@ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-0.0.7.tgz", "integrity": "sha1-NLkLqyqRGqNHVx2pDyK9NuzYqRk=", "requires": { - "debug": "2.6.9", - "stream-consume": "0.1.0" + "debug": "^2.2.0", + "stream-consume": "^0.1.0" } }, "hoek": { @@ -7419,10 +7966,10 @@ "resolved": "https://registry.npmjs.org/joi/-/joi-6.10.1.tgz", "integrity": "sha1-TVDDGAeRIgAP5fFq8f+OGRe3fgY=", "requires": { - "hoek": "2.16.3", - "isemail": "1.2.0", - "moment": "2.22.2", - "topo": "1.1.0" + "hoek": "2.x.x", + "isemail": "1.x.x", + "moment": "2.x.x", + "topo": "1.x.x" } }, "jsonwebtoken": { @@ -7430,11 +7977,11 @@ "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-7.4.3.tgz", "integrity": "sha1-d/UCHeBYtgWheD+hKD6ZgS5kVjg=", "requires": { - "joi": "6.10.1", - "jws": "3.1.5", - "lodash.once": "4.1.1", - "ms": "2.0.0", - "xtend": "4.0.1" + "joi": "^6.10.1", + "jws": "^3.1.4", + "lodash.once": "^4.0.0", + "ms": "^2.0.0", + "xtend": "^4.0.1" } }, "topo": { @@ -7442,7 +7989,7 @@ "resolved": "https://registry.npmjs.org/topo/-/topo-1.1.0.tgz", "integrity": "sha1-6ddRYV0buH3IZdsYL6HKCl71NtU=", "requires": { - "hoek": "2.16.3" + "hoek": "2.x.x" } } } @@ -7453,7 +8000,7 @@ "integrity": "sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=", "dev": true, "requires": { - "execa": "0.7.0" + "execa": "^0.7.0" } }, "terraformer": { @@ -7461,7 +8008,7 @@ "resolved": "https://registry.npmjs.org/terraformer/-/terraformer-1.0.8.tgz", "integrity": "sha1-UeCtiXRvzyFh3G9lqnDkI3fItZM=", "requires": { - "@types/geojson": "1.0.6" + "@types/geojson": "^1.0.0" } }, "terraformer-wkt-parser": { @@ -7469,7 +8016,7 @@ "resolved": "https://registry.npmjs.org/terraformer-wkt-parser/-/terraformer-wkt-parser-1.1.2.tgz", "integrity": "sha1-M2oMj8gglKWv+DKI9prt7NNpvww=", "requires": { - "terraformer": "1.0.8" + "terraformer": "~1.0.5" } }, "text-table": { @@ -7489,8 +8036,8 @@ "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", "dev": true, "requires": { - "readable-stream": "2.3.3", - "xtend": "4.0.1" + "readable-stream": "^2.1.5", + "xtend": "~4.0.1" }, "dependencies": { "isarray": { @@ -7505,13 +8052,13 @@ "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", "dev": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "safe-buffer": "5.1.1", - "string_decoder": "1.0.3", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.0.3", + "util-deprecate": "~1.0.1" } }, "string_decoder": { @@ -7520,7 +8067,7 @@ "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", "dev": true, "requires": { - "safe-buffer": "5.1.1" + "safe-buffer": "~5.1.0" } } } @@ -7531,7 +8078,7 @@ "integrity": "sha1-3OwD9V3Km3qj5bBPIYF+tW5jWIo=", "dev": true, "requires": { - "os-homedir": "1.0.2" + "os-homedir": "^1.0.0" } }, "time-stamp": { @@ -7552,8 +8099,8 @@ "integrity": "sha1-YcxHp2wavTGV8UUn+XjViulMUgQ=", "dev": true, "requires": { - "es5-ext": "0.10.35", - "next-tick": "1.0.0" + "es5-ext": "~0.10.14", + "next-tick": "1" } }, "to-fast-properties": { @@ -7573,7 +8120,7 @@ "resolved": "https://registry.npmjs.org/topo/-/topo-2.0.2.tgz", "integrity": "sha1-zVYVdSU5BXwNwEkaYhw7xvvh0YI=", "requires": { - "hoek": "4.2.0" + "hoek": "4.x.x" } }, "toposort-class": { @@ -7587,7 +8134,7 @@ "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", "dev": true, "requires": { - "nopt": "1.0.10" + "nopt": "~1.0.10" }, "dependencies": { "nopt": { @@ -7596,7 +8143,7 @@ "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", "dev": true, "requires": { - "abbrev": "1.0.9" + "abbrev": "1" } } } @@ -7606,7 +8153,7 @@ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz", "integrity": "sha1-C2GKVWW23qkL80JdBNVe3EdadWE=", "requires": { - "punycode": "1.4.1" + "punycode": "^1.4.1" }, "dependencies": { "punycode": { @@ -7638,7 +8185,7 @@ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", "requires": { - "safe-buffer": "5.1.1" + "safe-buffer": "^5.0.1" } }, "tweetnacl": { @@ -7653,7 +8200,7 @@ "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", "dev": true, "requires": { - "prelude-ls": "1.1.2" + "prelude-ls": "~1.1.2" } }, "type-detect": { @@ -7668,7 +8215,7 @@ "integrity": "sha1-yrEPtJCeRByChC6v4a1kbIGARBA=", "requires": { "media-typer": "0.3.0", - "mime-types": "2.1.17" + "mime-types": "~2.1.15" } }, "typedarray": { @@ -7684,9 +8231,9 @@ "dev": true, "optional": true, "requires": { - "source-map": "0.5.7", - "uglify-to-browserify": "1.0.2", - "yargs": "3.10.0" + "source-map": "~0.5.1", + "uglify-to-browserify": "~1.0.0", + "yargs": "~3.10.0" } }, "uglify-to-browserify": { @@ -7702,11 +8249,11 @@ "integrity": "sha1-p5yR8oYu7jEwxsNH8rkK1opm6Lg=", "dev": true, "requires": { - "bluebird": "3.5.1", - "lodash": "4.17.4", - "moment": "2.22.2", - "redefine": "0.2.1", - "resolve": "1.5.0" + "bluebird": "^3.4.1", + "lodash": "^4.17.0", + "moment": "^2.16.0", + "redefine": "^0.2.0", + "resolve": "^1.0.0" } }, "unc-path-regex": { @@ -7733,7 +8280,7 @@ "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=", "dev": true, "requires": { - "crypto-random-string": "1.0.0" + "crypto-random-string": "^1.0.0" } }, "universalify": { @@ -7759,15 +8306,15 @@ "integrity": "sha1-TognpruRUUCrCTVZ1wFOPruDdFE=", "dev": true, "requires": { - "boxen": "1.2.2", - "chalk": "2.3.0", - "configstore": "3.1.1", - "import-lazy": "2.1.0", - "is-installed-globally": "0.1.0", - "is-npm": "1.0.0", - "latest-version": "3.1.0", - "semver-diff": "2.1.0", - "xdg-basedir": "3.0.0" + "boxen": "^1.2.1", + "chalk": "^2.0.1", + "configstore": "^3.0.0", + "import-lazy": "^2.1.0", + "is-installed-globally": "^0.1.0", + "is-npm": "^1.0.0", + "latest-version": "^3.0.0", + "semver-diff": "^2.0.0", + "xdg-basedir": "^3.0.0" }, "dependencies": { "ansi-styles": { @@ -7776,7 +8323,7 @@ "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", "dev": true, "requires": { - "color-convert": "1.9.0" + "color-convert": "^1.9.0" } }, "chalk": { @@ -7785,9 +8332,9 @@ "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", "dev": true, "requires": { - "ansi-styles": "3.2.0", - "escape-string-regexp": "1.0.5", - "supports-color": "4.5.0" + "ansi-styles": "^3.1.0", + "escape-string-regexp": "^1.0.5", + "supports-color": "^4.0.0" } }, "has-flag": { @@ -7802,7 +8349,7 @@ "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", "dev": true, "requires": { - "has-flag": "2.0.0" + "has-flag": "^2.0.0" } } } @@ -7827,7 +8374,7 @@ "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", "dev": true, "requires": { - "prepend-http": "1.0.4" + "prepend-http": "^1.0.1" } }, "urlencode": { @@ -7835,7 +8382,7 @@ "resolved": "https://registry.npmjs.org/urlencode/-/urlencode-1.1.0.tgz", "integrity": "sha1-HyuibwE8hfATP3o61v8nMK33y7c=", "requires": { - "iconv-lite": "0.4.19" + "iconv-lite": "~0.4.11" } }, "user-home": { @@ -7882,7 +8429,7 @@ "integrity": "sha1-qrGh+jDUX4jdMhFIh1rALAtV5bQ=", "dev": true, "requires": { - "user-home": "1.1.1" + "user-home": "^1.1.1" } }, "validate-npm-package-license": { @@ -7891,8 +8438,8 @@ "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=", "dev": true, "requires": { - "spdx-correct": "1.0.2", - "spdx-expression-parse": "1.0.4" + "spdx-correct": "~1.0.0", + "spdx-expression-parse": "~1.0.0" } }, "validator": { @@ -7910,9 +8457,9 @@ "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", "requires": { - "assert-plus": "1.0.0", + "assert-plus": "^1.0.0", "core-util-is": "1.0.2", - "extsprintf": "1.3.0" + "extsprintf": "^1.2.0" } }, "very-fast-args": { @@ -7926,8 +8473,8 @@ "integrity": "sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4=", "dev": true, "requires": { - "clone": "1.0.2", - "clone-stats": "0.0.1", + "clone": "^1.0.0", + "clone-stats": "^0.0.1", "replace-ext": "0.0.1" }, "dependencies": { @@ -7945,14 +8492,14 @@ "integrity": "sha1-mmhRzhysHBzqX+hsCTHWIMLPqeY=", "dev": true, "requires": { - "defaults": "1.0.3", - "glob-stream": "3.1.18", - "glob-watcher": "0.0.6", - "graceful-fs": "3.0.11", - "mkdirp": "0.5.1", - "strip-bom": "1.0.0", - "through2": "0.6.5", - "vinyl": "0.4.6" + "defaults": "^1.0.0", + "glob-stream": "^3.1.5", + "glob-watcher": "^0.0.6", + "graceful-fs": "^3.0.0", + "mkdirp": "^0.5.0", + "strip-bom": "^1.0.0", + "through2": "^0.6.1", + "vinyl": "^0.4.0" }, "dependencies": { "clone": { @@ -7967,7 +8514,7 @@ "integrity": "sha1-dhPHeKGv6mLyXGMKCG1/Osu92Bg=", "dev": true, "requires": { - "natives": "1.1.0" + "natives": "^1.1.0" } }, "readable-stream": { @@ -7976,10 +8523,10 @@ "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", "dev": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", "isarray": "0.0.1", - "string_decoder": "0.10.31" + "string_decoder": "~0.10.x" } }, "strip-bom": { @@ -7988,8 +8535,8 @@ "integrity": "sha1-hbiGLzhEtabV7IRnqTWYFzo295Q=", "dev": true, "requires": { - "first-chunk-stream": "1.0.0", - "is-utf8": "0.2.1" + "first-chunk-stream": "^1.0.0", + "is-utf8": "^0.2.0" } }, "through2": { @@ -7998,8 +8545,8 @@ "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", "dev": true, "requires": { - "readable-stream": "1.0.34", - "xtend": "4.0.1" + "readable-stream": ">=1.0.33-1 <1.1.0-0", + "xtend": ">=4.0.0 <4.1.0-0" } }, "vinyl": { @@ -8008,8 +8555,8 @@ "integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=", "dev": true, "requires": { - "clone": "0.2.0", - "clone-stats": "0.0.1" + "clone": "^0.2.0", + "clone-stats": "^0.0.1" } } } @@ -8020,7 +8567,7 @@ "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", "dev": true, "requires": { - "isexe": "2.0.0" + "isexe": "^2.0.0" } }, "which-module": { @@ -8035,7 +8582,7 @@ "integrity": "sha1-DAnIXCqUaD0Nfq+O4JfVZL8OEFw=", "dev": true, "requires": { - "string-width": "1.0.2" + "string-width": "^1.0.1" } }, "winchan": { @@ -8067,8 +8614,8 @@ "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "dev": true, "requires": { - "string-width": "1.0.2", - "strip-ansi": "3.0.1" + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" } }, "wrappy": { @@ -8082,7 +8629,7 @@ "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", "dev": true, "requires": { - "mkdirp": "0.5.1" + "mkdirp": "^0.5.1" } }, "write-file-atomic": { @@ -8091,9 +8638,9 @@ "integrity": "sha512-xuPeK4OdjWqtfi59ylvVL0Yn35SF3zgcAcv7rBPFHVaEapaDr4GdGgm3j7ckTwH9wHL7fGmgfAnb0+THrHb8tA==", "dev": true, "requires": { - "graceful-fs": "4.1.11", - "imurmurhash": "0.1.4", - "signal-exit": "3.0.2" + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" } }, "xdg-basedir": { @@ -8107,8 +8654,8 @@ "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.17.tgz", "integrity": "sha1-F76T6q4/O3eTWceVtBlwWogX6Gg=", "requires": { - "sax": "1.2.1", - "xmlbuilder": "4.2.1" + "sax": ">=0.6.0", + "xmlbuilder": "^4.1.0" } }, "xmlbuilder": { @@ -8116,7 +8663,7 @@ "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-4.2.1.tgz", "integrity": "sha1-qlijBBoGb5DqoWwvU4n/GfP0YaU=", "requires": { - "lodash": "4.17.4" + "lodash": "^4.0.0" } }, "xtend": { @@ -8142,9 +8689,9 @@ "dev": true, "optional": true, "requires": { - "camelcase": "1.2.1", - "cliui": "2.1.0", - "decamelize": "1.2.0", + "camelcase": "^1.0.2", + "cliui": "^2.1.0", + "decamelize": "^1.0.0", "window-size": "0.1.0" } }, @@ -8154,7 +8701,7 @@ "integrity": "sha1-jQrELxbqVd69MyyvTEA4s+P139k=", "dev": true, "requires": { - "camelcase": "4.1.0" + "camelcase": "^4.1.0" }, "dependencies": { "camelcase": { diff --git a/package.json b/package.json index 459d09cc..eab997b8 100644 --- a/package.json +++ b/package.json @@ -52,6 +52,7 @@ "joi": "^8.0.5", "jsonwebtoken": "^8.3.0", "lodash": "^4.16.4", + "memwatch-next": "^0.3.0", "method-override": "^2.3.9", "moment": "^2.22.2", "pg": "^4.5.5", diff --git a/postman.json b/postman.json index ed8a690f..8f6bdcc6 100644 --- a/postman.json +++ b/postman.json @@ -1,8 +1,7 @@ { "info": { + "_postman_id": "160fcac7-f74a-4047-a4e4-b53f08d991c5", "name": "tc-project-service", - "_postman_id": "63bb8939-b1c0-0c3c-ad9d-68e63063eda7", - "description": "", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" }, "item": [ @@ -371,7 +370,6 @@ }, { "name": "Project With TemplateId issue", - "description": "", "item": [ { "name": "Create project with templateId (not existed)", @@ -821,7 +819,6 @@ }, { "name": "Projects", - "description": "Requests for all things projects.", "item": [ { "name": "Create project without payload", @@ -919,6 +916,38 @@ }, "response": [] }, + { + "name": "Create project by inactive user", + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer userId_{{inactive-userId}}" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"param\": {\n\t\t\"name\": \"test project\",\n\t\t\"description\": \"Hello I am a test project\",\n\t\t\"type\": \"generic\"\n\t}\n}" + }, + "url": { + "raw": "{{api-url}}/v4/projects", + "host": [ + "{{api-url}}" + ], + "path": [ + "v4", + "projects" + ] + }, + "description": "Valid request body. Project should be created successfully." + }, + "response": [] + }, { "name": "Get project by id", "request": { @@ -1732,7 +1761,8 @@ }, "response": [] } - ] + ], + "description": "Requests for all things projects." }, { "name": "EventHandling and Integration with Direct Project API", @@ -2029,6 +2059,72 @@ }, "response": [] }, + { + "name": "Create Phase with order", + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{jwt-token}}" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"param\": {\n\t\t\"name\": \"test project phase\",\n\t\t\"status\": \"active\",\n\t\t\"startDate\": \"2018-05-15T00:00:00\",\n\t\t\"endDate\": \"2018-05-16T00:00:00\",\n\t\t\"budget\": 20,\n\t\t\"details\": {\n\t\t\t\"aDetails\": \"a details\"\n\t\t},\n\t\t\"order\": 1\n\t}\n}" + }, + "url": { + "raw": "{{api-url}}/v4/projects/1/phases", + "host": [ + "{{api-url}}" + ], + "path": [ + "v4", + "projects", + "1", + "phases" + ] + } + }, + "response": [] + }, + { + "name": "Create Phase with productTemplateId", + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{jwt-token}}" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"param\": {\n\t\t\"name\": \"test project phase\",\n\t\t\"status\": \"active\",\n\t\t\"startDate\": \"2018-05-15T00:00:00\",\n\t\t\"endDate\": \"2018-05-16T00:00:00\",\n\t\t\"budget\": 20,\n\t\t\"details\": {\n\t\t\t\"aDetails\": \"a details\"\n\t\t},\n\t\t\"order\": 1,\n\t\t\"productTemplateId\": 1\n\t}\n}" + }, + "url": { + "raw": "{{api-url}}/v4/projects/1/phases", + "host": [ + "{{api-url}}" + ], + "path": [ + "v4", + "projects", + "1", + "phases" + ] + } + }, + "response": [] + }, { "name": "List Phase", "request": { @@ -2140,6 +2236,45 @@ }, "response": [] }, + { + "name": "List Phase with sort by order", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{jwt-token}}" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"param\": {\n\t\t\"name\": \"test project phase\",\n\t\t\"status\": \"active\",\n\t\t\"startDate\": \"2018-05-15T00:00:00\",\n\t\t\"endDate\": \"2018-05-16T00:00:00\",\n\t\t\"budget\": 20\n\t}\n}" + }, + "url": { + "raw": "{{api-url}}/v4/projects/1/phases?sort=order desc", + "host": [ + "{{api-url}}" + ], + "path": [ + "v4", + "projects", + "1", + "phases" + ], + "query": [ + { + "key": "sort", + "value": "order desc" + } + ] + } + }, + "response": [] + }, { "name": "Get Phase", "request": { @@ -2208,6 +2343,40 @@ }, "response": [] }, + { + "name": "Update Phase with order", + "request": { + "method": "PATCH", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{jwt-token}}" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"param\": {\n\t\t\"name\": \"test project phase xxx\",\n\t\t\"status\": \"inactive\",\n\t\t\"startDate\": \"2018-05-14T00:00:00\",\n\t\t\"endDate\": \"2018-05-15T00:00:00\",\n\t\t\"budget\": 30,\n\t\t\"progress\": 15,\n\t\t\"details\": {\n\t\t\t\"message\": \"phase details\"\n\t\t},\n\t\t\"order\": 1\n\t}\n}" + }, + "url": { + "raw": "{{api-url}}/v4/projects/1/phases/1", + "host": [ + "{{api-url}}" + ], + "path": [ + "v4", + "projects", + "1", + "phases", + "1" + ] + } + }, + "response": [] + }, { "name": "Delete Phase", "request": { @@ -2437,12 +2606,14 @@ "raw": "{\r\n \"param\":{\r\n \"name\":\"new name\",\r\n \"key\":\"new key\",\r\n \"category\":\"app\",\r\n \"icon\": \"http://example.com/icon1.ico\",\r\n \"question\": \"question 1\",\r\n \"info\": \"info 1\",\r\n \"aliases\": [\"key-1\", \"key_1\"],\r\n \"scope\":{\r\n \"scope1\":\"scope 1\"\r\n },\r\n \"phases\":{\r\n \"phase1\":\"phase 1\"\r\n }\r\n }\r\n}" }, "url": { - "raw": "{{api-url}}/v4/projectTemplates", + "raw": "{{api-url}}/v4/projects/metadata/projectTemplates", "host": [ "{{api-url}}" ], "path": [ "v4", + "projects", + "metadata", "projectTemplates" ] } @@ -2468,12 +2639,14 @@ "raw": "{\r\n \"param\":{\r\n \"name\":\"new name\",\r\n \"key\":\"new key\",\r\n \"category\":\"new category\",\r\n \"scope\":{\r\n \"scope1\":\"scope 1\"\r\n },\r\n \"phases\":{\r\n \"phase1\":\"phase 1\"\r\n }\r\n }\r\n}" }, "url": { - "raw": "{{api-url}}/v4/projectTemplates", + "raw": "{{api-url}}/v4/projects/metadata/projectTemplates", "host": [ "{{api-url}}" ], "path": [ "v4", + "projects", + "metadata", "projectTemplates" ] } @@ -2499,12 +2672,14 @@ "raw": "{\r\n \"param\":{\r\n \"name\":\"new name\",\r\n \"key\":\"new key\",\r\n \"category\":\"new category\",\r\n \"scope\":{\r\n \"scope1\":\"scope 1\"\r\n },\r\n \"phases\":{\r\n \"phase1\":\"phase 1\"\r\n }\r\n }\r\n}" }, "url": { - "raw": "{{api-url}}/v4/projectTemplates/1", + "raw": "{{api-url}}/v4/projects/metadata/projectTemplates/1", "host": [ "{{api-url}}" ], "path": [ "v4", + "projects", + "metadata", "projectTemplates", "1" ] @@ -2531,12 +2706,14 @@ "raw": "{\r\n \"param\":{\r\n \"name\":\"new name\",\r\n \"key\":\"new key\",\r\n \"category\":\"app\",\r\n \"scope\":{\r\n \"scope1\":\"scope 1\",\r\n \"scope2\": [\"a\"]\r\n },\r\n \"phases\":{\r\n \"phase1\":\"phase 1\",\r\n \"phase2\": {\r\n \t\"another\": \"another\"\r\n }\r\n }\r\n }\r\n}" }, "url": { - "raw": "{{api-url}}/v4/projectTemplates/1", + "raw": "{{api-url}}/v4/projects/metadata/projectTemplates/1", "host": [ "{{api-url}}" ], "path": [ "v4", + "projects", + "metadata", "projectTemplates", "1" ] @@ -2563,12 +2740,14 @@ "raw": "{\r\n \"param\":{\r\n \"name\":\"new name\",\r\n \"key\":\"new key\",\r\n \"category\":\"new category\",\r\n \"scope\":{\r\n \"scope1\":\"scope 1\",\r\n \"scope2\": [\"a\"]\r\n },\r\n \"phases\":{\r\n \"phase1\":\"phase 1\",\r\n \"phase2\": {\r\n \t\"another\": \"another\"\r\n }\r\n }\r\n }\r\n}" }, "url": { - "raw": "{{api-url}}/v4/projectTemplates/2", + "raw": "{{api-url}}/v4/projects/metadata/projectTemplates/2", "host": [ "{{api-url}}" ], "path": [ "v4", + "projects", + "metadata", "projectTemplates", "2" ] @@ -2600,12 +2779,14 @@ "raw": "{\r\n \"param\": {\r\n \"name\": \"name 1\",\r\n \"productKey\": \"productKey 1\",\r\n \"category\": \"key1\",\r\n \"icon\": \"http://example.com/icon1.ico\",\r\n \"brief\": \"brief 1\",\r\n \"details\": \"details 1\",\r\n \"aliases\": [\"product key 1\", \"product_key_1\"],\r\n \"template\": {\r\n \"template1\": {\r\n \"name\": \"template 1\",\r\n \"details\": {\r\n \"anyDetails\": \"any details 1\"\r\n },\r\n \"others\": [\"others 11\", \"others 12\"]\r\n },\r\n \"template2\": {\r\n \"name\": \"template 2\",\r\n \"details\": {\r\n \"anyDetails\": \"any details 2\"\r\n },\r\n \"others\": [\"others 21\", \"others 22\"]\r\n }\r\n }\r\n }\r\n }" }, "url": { - "raw": "{{api-url}}/v4/productTemplates", + "raw": "{{api-url}}/v4/projects/metadata/productTemplates", "host": [ "{{api-url}}" ], "path": [ "v4", + "projects", + "metadata", "productTemplates" ] } @@ -2631,12 +2812,14 @@ "raw": "{\r\n \"param\":{\r\n \"name\":\"new name\",\r\n \"key\":\"new key\",\r\n \"category\":\"new category\",\r\n \"scope\":{\r\n \"scope1\":\"scope 1\"\r\n },\r\n \"phases\":{\r\n \"phase1\":\"phase 1\"\r\n }\r\n }\r\n}" }, "url": { - "raw": "{{api-url}}/v4/productTemplates", + "raw": "{{api-url}}/v4/projects/metadata/productTemplates", "host": [ "{{api-url}}" ], "path": [ "v4", + "projects", + "metadata", "productTemplates" ] } @@ -2662,12 +2845,14 @@ "raw": "{\r\n \"param\":{\r\n \"name\":\"new name\",\r\n \"key\":\"new key\",\r\n \"category\":\"new category\",\r\n \"scope\":{\r\n \"scope1\":\"scope 1\"\r\n },\r\n \"phases\":{\r\n \"phase1\":\"phase 1\"\r\n }\r\n }\r\n}" }, "url": { - "raw": "{{api-url}}/v4/productTemplates/3", + "raw": "{{api-url}}/v4/projects/metadata/productTemplates/3", "host": [ "{{api-url}}" ], "path": [ "v4", + "projects", + "metadata", "productTemplates", "3" ] @@ -2694,12 +2879,14 @@ "raw": "{\r\n \"param\":{\r\n \"name\":\"new name\",\r\n \"productKey\":\"new productKey\",\r\n \"category\":\"key1\",\r\n \"icon\":\"http://example.com/icon-new.ico\",\r\n \"brief\": \"new brief\",\r\n \"details\": \"new details\",\r\n \"aliases\":{\r\n \"alias1\":\"scope 1\",\r\n \"alias2\": [\"a\"]\r\n },\r\n \"template\":{\r\n \"template1\":\"template 1\",\r\n \"template2\": {\r\n \t\"another\": \"another\"\r\n }\r\n }\r\n }\r\n}" }, "url": { - "raw": "{{api-url}}/v4/productTemplates/1", + "raw": "{{api-url}}/v4/projects/metadata/productTemplates/1", "host": [ "{{api-url}}" ], "path": [ "v4", + "projects", + "metadata", "productTemplates", "1" ] @@ -2726,12 +2913,14 @@ "raw": "" }, "url": { - "raw": "{{api-url}}/v4/productTemplates/1", + "raw": "{{api-url}}/v4/projects/metadata/productTemplates/1", "host": [ "{{api-url}}" ], "path": [ "v4", + "projects", + "metadata", "productTemplates", "1" ] @@ -2760,15 +2949,17 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"param\":{\r\n \"key\": \"new key\",\r\n \"displayName\": \"new displayName\",\r\n \"icon\": \"http://example.com/icon4.ico\",\r\n \t\"question\": \"question 4\",\r\n \t\"info\": \"info 4\",\r\n \t\"aliases\": [\"key-41\", \"key_42\"]\r\n }\r\n}" + "raw": "{\r\n \"param\":{\r\n \"key\": \"new key\",\r\n \"displayName\": \"new displayName\",\r\n \"icon\": \"http://example.com/icon4.ico\",\r\n \t\"question\": \"question 4\",\r\n \t\"info\": \"info 4\",\r\n \t\"aliases\": [\"key-41\", \"key_42\"],\r\n \t\"metadata\": {}\r\n }\r\n}" }, "url": { - "raw": "{{api-url}}/v4/projectTypes", + "raw": "{{api-url}}/v4/projects/metadata/projectTypes", "host": [ "{{api-url}}" ], "path": [ "v4", + "projects", + "metadata", "projectTypes" ] } @@ -2794,12 +2985,14 @@ "raw": "{\r\n \"param\":{\r\n \"name\":\"new name\",\r\n \"key\":\"new key\",\r\n \"category\":\"new category\",\r\n \"scope\":{\r\n \"scope1\":\"scope 1\"\r\n },\r\n \"phases\":{\r\n \"phase1\":\"phase 1\"\r\n }\r\n }\r\n}" }, "url": { - "raw": "{{api-url}}/v4/projectTypes", + "raw": "{{api-url}}/v4/projects/metadata/projectTypes", "host": [ "{{api-url}}" ], "path": [ "v4", + "projects", + "metadata", "projectTypes" ] } @@ -2825,12 +3018,14 @@ "raw": "{\r\n \"param\":{\r\n \"name\":\"new name\",\r\n \"key\":\"new key\",\r\n \"category\":\"new category\",\r\n \"scope\":{\r\n \"scope1\":\"scope 1\"\r\n },\r\n \"phases\":{\r\n \"phase1\":\"phase 1\"\r\n }\r\n }\r\n}" }, "url": { - "raw": "{{api-url}}/v4/projectTypes/generic", + "raw": "{{api-url}}/v4/projects/metadata/projectTypes/generic", "host": [ "{{api-url}}" ], "path": [ "v4", + "projects", + "metadata", "projectTypes", "generic" ] @@ -2857,12 +3052,14 @@ "raw": "{\r\n \"param\":{\r\n \"displayName\": \"Chatbot-updated\"\r\n }\r\n}" }, "url": { - "raw": "{{api-url}}/v4/projectTypes/chatbot", + "raw": "{{api-url}}/v4/projects/metadata/projectTypes/chatbot", "host": [ "{{api-url}}" ], "path": [ "v4", + "projects", + "metadata", "projectTypes", "chatbot" ] @@ -2889,12 +3086,14 @@ "raw": "" }, "url": { - "raw": "{{api-url}}/v4/projectTypes/chatbot", + "raw": "{{api-url}}/v4/projects/metadata/projectTypes/chatbot", "host": [ "{{api-url}}" ], "path": [ "v4", + "projects", + "metadata", "projectTypes", "chatbot" ] @@ -2926,12 +3125,14 @@ "raw": "{\r\n \"param\":{\r\n \"key\": \"generic\",\r\n \"displayName\": \"new displayName\",\r\n \"icon\": \"icon\",\r\n \"question\": \"question\",\r\n \"info\": \"info\",\r\n \"aliases\": [\"key-1\", \"key-2\"]\r\n }\r\n}" }, "url": { - "raw": "{{api-url}}/v4/productCategories", + "raw": "{{api-url}}/v4/projects/metadata/productCategories", "host": [ "{{api-url}}" ], "path": [ "v4", + "projects", + "metadata", "productCategories" ] } @@ -2957,12 +3158,14 @@ "raw": "{\r\n \"param\":{\r\n \"name\":\"new name\",\r\n \"key\":\"new key\",\r\n \"category\":\"new category\",\r\n \"scope\":{\r\n \"scope1\":\"scope 1\"\r\n },\r\n \"phases\":{\r\n \"phase1\":\"phase 1\"\r\n }\r\n }\r\n}" }, "url": { - "raw": "{{api-url}}/v4/productCategories", + "raw": "{{api-url}}/v4/projects/metadata/productCategories", "host": [ "{{api-url}}" ], "path": [ "v4", + "projects", + "metadata", "productCategories" ] } @@ -2988,12 +3191,14 @@ "raw": "{\r\n \"param\":{\r\n \"name\":\"new name\",\r\n \"key\":\"new key\",\r\n \"category\":\"new category\",\r\n \"scope\":{\r\n \"scope1\":\"scope 1\"\r\n },\r\n \"phases\":{\r\n \"phase1\":\"phase 1\"\r\n }\r\n }\r\n}" }, "url": { - "raw": "{{api-url}}/v4/productCategories/generic", + "raw": "{{api-url}}/v4/projects/metadata/productCategories/generic", "host": [ "{{api-url}}" ], "path": [ "v4", + "projects", + "metadata", "productCategories", "generic" ] @@ -3020,12 +3225,14 @@ "raw": "{\r\n \"param\":{\r\n \"displayName\": \"Chatbot-updated\"\r\n }\r\n}" }, "url": { - "raw": "{{api-url}}/v4/productCategories/generic", + "raw": "{{api-url}}/v4/projects/metadata/productCategories/generic", "host": [ "{{api-url}}" ], "path": [ "v4", + "projects", + "metadata", "productCategories", "generic" ] @@ -3052,12 +3259,14 @@ "raw": "{\r\n \"param\":{\r\n \"name\":\"new name\",\r\n \"key\":\"new key\",\r\n \"category\":\"new category\",\r\n \"scope\":{\r\n \"scope1\":\"scope 1\",\r\n \"scope2\": [\"a\"]\r\n },\r\n \"phases\":{\r\n \"phase1\":\"phase 1\",\r\n \"phase2\": {\r\n \t\"another\": \"another\"\r\n }\r\n }\r\n }\r\n}" }, "url": { - "raw": "{{api-url}}/v4/productCategories/generic", + "raw": "{{api-url}}/v4/projects/metadata/productCategories/generic", "host": [ "{{api-url}}" ], "path": [ "v4", + "projects", + "metadata", "productCategories", "generic" ] @@ -3101,7 +3310,6 @@ }, { "name": "Project upgrade", - "description": "Request to migrate projects.", "item": [ { "name": "Migrate project", @@ -3235,7 +3443,8 @@ }, "response": [] } - ] + ], + "description": "Request to migrate projects." }, { "name": "Timeline", @@ -3271,6 +3480,37 @@ }, "response": [] }, + { + "name": "Create timeline with templateId", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Authorization", + "value": "Bearer {{jwt-token-connectAdmin-40051336}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"param\":{\r\n \"name\":\"new name\",\r\n \"description\":\"new description\",\r\n \"startDate\":\"2018-05-29T00:00:00.000Z\",\r\n \"endDate\": \"2018-05-30T00:00:00.000Z\",\r\n \"reference\": \"project\",\r\n \"referenceId\": 1,\r\n \"templateId\": 1\r\n }\r\n}" + }, + "url": { + "raw": "{{api-url}}/v4/timelines", + "host": [ + "{{api-url}}" + ], + "path": [ + "v4", + "timelines" + ] + } + }, + "response": [] + }, { "name": "Create timeline with invalid data", "request": { @@ -3332,8 +3572,7 @@ "query": [ { "key": "filter", - "value": "reference%3Dphase%26referenceId%3D1", - "equals": true + "value": "reference%3Dphase%26referenceId%3D1" } ] } @@ -3693,7 +3932,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"param\":{\r\n \"name\": \"milestone 1-updated\",\r\n \"description\": \"description-updated\",\r\n \"duration\": 3,\r\n \"completionDate\": \"2018-05-07T00:00:00.000Z\",\r\n \"status\": \"closed\",\r\n \"type\": \"type2\",\r\n \"details\": {\r\n \"detail1\": {\r\n \"subDetail1C\": 3\r\n },\r\n \"detail2\": [\r\n 4\r\n ]\r\n },\r\n \"order\": 1,\r\n \"plannedText\": \"plannedText 1-updated\",\r\n \"activeText\": \"activeText 1-updated\",\r\n \"completedText\": \"completedText 1-updated\",\r\n \"blockedText\": \"blockedText 1-updated\"\r\n }\r\n}" + "raw": "{\r\n \"param\":{\r\n \"name\": \"milestone 1-updated\",\r\n \"description\": \"description-updated\",\r\n \"duration\": 3,\r\n \"completionDate\": \"2018-09-28T00:00:00.000Z\",\r\n \"status\": \"closed\",\r\n \"type\": \"type2\",\r\n \"details\": {\r\n \"detail1\": {\r\n \"subDetail1C\": 3\r\n },\r\n \"detail2\": [\r\n 4\r\n ]\r\n },\r\n \"order\": 1,\r\n \"plannedText\": \"plannedText 1-updated\",\r\n \"activeText\": \"activeText 1-updated\",\r\n \"completedText\": \"completedText 1-updated\",\r\n \"blockedText\": \"blockedText 1-updated\"\r\n }\r\n}" }, "url": { "raw": "{{api-url}}/v4/timelines/1/milestones/1", @@ -3711,6 +3950,74 @@ }, "response": [] }, + { + "name": "Update milestone (active)", + "request": { + "method": "PATCH", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Authorization", + "value": "Bearer {{jwt-token}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"param\":{\r\n \"name\": \"milestone 2-updated\",\r\n \"description\": \"description-updated\",\r\n \"duration\": 3,\r\n \"completionDate\": \"2018-10-28T00:00:00.000Z\",\r\n \"status\": \"active\",\r\n \"type\": \"type2\",\r\n \"details\": {\r\n \"detail1\": {\r\n \"subDetail1C\": 3\r\n },\r\n \"detail2\": [\r\n 4\r\n ]\r\n },\r\n \"order\": 1,\r\n \"plannedText\": \"plannedText 1-updated\",\r\n \"activeText\": \"activeText 1-updated\",\r\n \"completedText\": \"completedText 1-updated\",\r\n \"blockedText\": \"blockedText 1-updated\"\r\n }\r\n}" + }, + "url": { + "raw": "{{api-url}}/v4/timelines/1/milestones/2", + "host": [ + "{{api-url}}" + ], + "path": [ + "v4", + "timelines", + "1", + "milestones", + "2" + ] + } + }, + "response": [] + }, + { + "name": "Update milestone (completed)", + "request": { + "method": "PATCH", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Authorization", + "value": "Bearer {{jwt-token}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"param\":{\r\n \"name\": \"milestone 2-updated\",\r\n \"description\": \"description-updated\",\r\n \"duration\": 3,\r\n \"completionDate\": \"2018-10-28T00:00:00.000Z\",\r\n \"status\": \"completed\",\r\n \"type\": \"type2\",\r\n \"details\": {\r\n \"detail1\": {\r\n \"subDetail1C\": 3\r\n },\r\n \"detail2\": [\r\n 4\r\n ]\r\n },\r\n \"order\": 1,\r\n \"plannedText\": \"plannedText 1-updated\",\r\n \"activeText\": \"activeText 1-updated\",\r\n \"completedText\": \"completedText 1-updated\",\r\n \"blockedText\": \"blockedText 1-updated\"\r\n }\r\n}" + }, + "url": { + "raw": "{{api-url}}/v4/timelines/1/milestones/2", + "host": [ + "{{api-url}}" + ], + "path": [ + "v4", + "timelines", + "1", + "milestones", + "2" + ] + } + }, + "response": [] + }, { "name": "Update milestone (order 1 => 2)", "request": { @@ -3902,18 +4209,51 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"param\":{\r\n \"name\": \"milestoneTemplate 3\",\r\n \"description\": \"description 3\",\r\n \"duration\": 33,\r\n \"type\": \"type3\",\r\n \"order\": 1,\r\n \"activeText\": \"activeText 1\",\r\n \"completedText\": \"completedText 1\",\r\n \"blockedText\": \"blockedText 1\",\r\n \"plannedText\": \"planned Text 1\"\r\n\r\n }\r\n}" + "raw": "{\r\n \"param\":{\r\n \"name\": \"milestoneTemplate 3\",\r\n \"description\": \"description 3\",\r\n \"duration\": 33,\r\n \"type\": \"type3\",\r\n \"order\": 1,\r\n \"activeText\": \"activeText 1\",\r\n \"completedText\": \"completedText 1\",\r\n \"blockedText\": \"blockedText 1\",\r\n \"plannedText\": \"planned Text 1\",\r\n\t\"reference\": \"productTemplate\",\r\n\t\"referenceId\": 1,\r\n\t\"metadata\": {}\r\n }\r\n}" }, "url": { - "raw": "{{api-url}}/v4/productTemplates/1/milestones", + "raw": "{{api-url}}/v4/timelines/metadata/milestoneTemplates", "host": [ "{{api-url}}" ], "path": [ "v4", - "productTemplates", - "1", - "milestones" + "timelines", + "metadata", + "milestoneTemplates" + ] + } + }, + "response": [] + }, + { + "name": "Create milestone template with invalid referenceId", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Authorization", + "value": "Bearer {{jwt-token-admin-40051333}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"param\":{\r\n \"name\": \"milestoneTemplate 3\",\r\n \"description\": \"description 3\",\r\n \"duration\": 33,\r\n \"type\": \"type3\",\r\n \"order\": 1,\r\n \"activeText\": \"activeText 1\",\r\n \"completedText\": \"completedText 1\",\r\n \"blockedText\": \"blockedText 1\",\r\n \"plannedText\": \"planned Text 1\",\r\n\t\"reference\": \"productTemplate\",\r\n\t\"referenceId\": 1000,\r\n\t\"metadata\": {}\r\n }\r\n}" + }, + "url": { + "raw": "{{api-url}}/v4/timelines/metadata/milestoneTemplates", + "host": [ + "{{api-url}}" + ], + "path": [ + "v4", + "timelines", + "metadata", + "milestoneTemplates" ] } }, @@ -3938,15 +4278,15 @@ "raw": "{\r\n \"param\":{\r\n\r\n }\r\n}" }, "url": { - "raw": "{{api-url}}/v4/productTemplates/1/milestones", + "raw": "{{api-url}}/v4/timelines/metadata/milestoneTemplates", "host": [ "{{api-url}}" ], "path": [ "v4", - "productTemplates", - "1", - "milestones" + "timelines", + "metadata", + "milestoneTemplates" ] } }, @@ -3968,18 +4308,18 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"param\":{\r\n \"sourceTemplateId\": 1\r\n }\r\n}" + "raw": "{\r\n \"param\":{\r\n \"sourceReference\": \"productTemplate\",\r\n \"sourceReferenceId\": 1,\r\n \"reference\": \"productTemplate\",\r\n \"referenceId\": 2\r\n }\r\n}" }, "url": { - "raw": "{{api-url}}/v4/productTemplates/2/milestones/clone", + "raw": "{{api-url}}/v4/timelines/metadata/milestoneTemplates/clone", "host": [ "{{api-url}}" ], "path": [ "v4", - "productTemplates", - "2", - "milestones", + "timelines", + "metadata", + "milestoneTemplates", "clone" ] } @@ -3987,7 +4327,7 @@ "response": [] }, { - "name": "Clone milestone template with invalid product template id", + "name": "Clone milestone template with invalid referenceId", "request": { "method": "POST", "header": [ @@ -4002,18 +4342,18 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"param\":{\r\n \"sourceTemplateId\": 1\r\n }\r\n}" + "raw": "{\r\n \"param\":{\r\n \"sourceReference\": \"productTemplate\",\r\n \"sourceReferenceId\": 1,\r\n \"reference\": \"productTemplate\",\r\n \"referenceId\": 2000\r\n }\r\n}" }, "url": { - "raw": "{{api-url}}/v4/productTemplates/5/milestones/clone", + "raw": "{{api-url}}/v4/timelines/metadata/milestoneTemplates/clone", "host": [ "{{api-url}}" ], "path": [ "v4", - "productTemplates", - "5", - "milestones", + "timelines", + "metadata", + "milestoneTemplates", "clone" ] } @@ -4021,7 +4361,7 @@ "response": [] }, { - "name": "Clone milestone template with invalid source product template id", + "name": "Clone milestone template with invalid sourceReferenceId", "request": { "method": "POST", "header": [ @@ -4036,18 +4376,18 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"param\":{\r\n \"sourceTemplateId\": 6\r\n }\r\n}" + "raw": "{\r\n \"param\":{\r\n \"sourceReference\": \"productTemplate\",\r\n \"sourceReferenceId\": 1000,\r\n \"reference\": \"productTemplate\",\r\n \"referenceId\": 2\r\n }\r\n}" }, "url": { - "raw": "{{api-url}}/v4/productTemplates/2/milestones/clone", + "raw": "{{api-url}}/v4/timelines/metadata/milestoneTemplates/clone", "host": [ "{{api-url}}" ], "path": [ "v4", - "productTemplates", - "2", - "milestones", + "timelines", + "metadata", + "milestoneTemplates", "clone" ] } @@ -4073,15 +4413,54 @@ "raw": "{\r\n \"param\":{\r\n \"name\":\"new name\",\r\n \"key\":\"new key\",\r\n \"category\":\"new category\",\r\n \"scope\":{\r\n \"scope1\":\"scope 1\"\r\n },\r\n \"phases\":{\r\n \"phase1\":\"phase 1\"\r\n }\r\n }\r\n}" }, "url": { - "raw": "{{api-url}}/v4/productTemplates/1/milestones", + "raw": "{{api-url}}/v4/timelines/metadata/milestoneTemplates", "host": [ "{{api-url}}" ], "path": [ "v4", - "productTemplates", - "1", - "milestones" + "timelines", + "metadata", + "milestoneTemplates" + ] + } + }, + "response": [] + }, + { + "name": "List milestone templates (filter)", + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Authorization", + "value": "Bearer {{jwt-token-copilot-40051332}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"param\":{\r\n \"name\":\"new name\",\r\n \"key\":\"new key\",\r\n \"category\":\"new category\",\r\n \"scope\":{\r\n \"scope1\":\"scope 1\"\r\n },\r\n \"phases\":{\r\n \"phase1\":\"phase 1\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{api-url}}/v4/timelines/metadata/milestoneTemplates?filter=reference%3DproductTemplate%26referenceId%3D1", + "host": [ + "{{api-url}}" + ], + "path": [ + "v4", + "timelines", + "metadata", + "milestoneTemplates" + ], + "query": [ + { + "key": "filter", + "value": "reference%3DproductTemplate%26referenceId%3D1" + } ] } }, @@ -4106,17 +4485,21 @@ "raw": "{\r\n \"param\":{\r\n \"name\":\"new name\",\r\n \"key\":\"new key\",\r\n \"category\":\"new category\",\r\n \"scope\":{\r\n \"scope1\":\"scope 1\"\r\n },\r\n \"phases\":{\r\n \"phase1\":\"phase 1\"\r\n }\r\n }\r\n}" }, "url": { - "raw": "{{api-url}}/v4/productTemplates/1/milestones?sort=order desc", + "raw": "{{api-url}}/v4/timelines/metadata/milestoneTemplates?filter=reference%3DproductTemplate%26referenceId%3D1&sort=order desc", "host": [ "{{api-url}}" ], "path": [ "v4", - "productTemplates", - "1", - "milestones" + "timelines", + "metadata", + "milestoneTemplates" ], "query": [ + { + "key": "filter", + "value": "reference%3DproductTemplate%26referenceId%3D1" + }, { "key": "sort", "value": "order desc" @@ -4145,15 +4528,15 @@ "raw": "{\r\n \"param\":{\r\n \"name\":\"new name\",\r\n \"key\":\"new key\",\r\n \"category\":\"new category\",\r\n \"scope\":{\r\n \"scope1\":\"scope 1\"\r\n },\r\n \"phases\":{\r\n \"phase1\":\"phase 1\"\r\n }\r\n }\r\n}" }, "url": { - "raw": "{{api-url}}/v4/productTemplates/1/milestones/1", + "raw": "{{api-url}}/v4/timelines/metadata/milestoneTemplates/1", "host": [ "{{api-url}}" ], "path": [ "v4", - "productTemplates", - "1", - "milestones", + "timelines", + "metadata", + "milestoneTemplates", "1" ] } @@ -4176,18 +4559,18 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"param\":{\r\n\t\"name\": \"milestoneTemplate 1-updated\",\r\n\t\"description\": \"description 1-updated\",\r\n\t\"duration\": 34,\r\n\t\"type\": \"type1-updated\",\r\n\t\"order\": 1\r\n }\r\n}" + "raw": "{\r\n \"param\":{\r\n\t\"name\": \"milestoneTemplate 1-updated\",\r\n\t\"description\": \"description 1-updated\",\r\n\t\"duration\": 34,\r\n\t\"type\": \"type1-updated\",\r\n\t\"order\": 1,\r\n\t\"reference\": \"productTemplate\",\r\n\t\"referenceId\": 1\r\n }\r\n}" }, "url": { - "raw": "{{api-url}}/v4/productTemplates/1/milestones/1", + "raw": "{{api-url}}/v4/timelines/metadata/milestoneTemplates/1", "host": [ "{{api-url}}" ], "path": [ "v4", - "productTemplates", - "1", - "milestones", + "timelines", + "metadata", + "milestoneTemplates", "1" ] } @@ -4210,18 +4593,18 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"param\":{\r\n \"name\": \"milestoneTemplate 1-updated\",\r\n \"description\": \"description 1-updated\",\r\n \"duration\": 34,\r\n \"type\": \"type1-updated\",\r\n \"order\": 2\r\n }\r\n}" + "raw": "{\r\n \"param\":{\r\n \"name\": \"milestoneTemplate 1-updated\",\r\n \"description\": \"description 1-updated\",\r\n \"duration\": 34,\r\n \"type\": \"type1-updated\",\r\n \"order\": 2,\r\n\t\"reference\": \"productTemplate\",\r\n\t\"referenceId\": 1\r\n }\r\n}" }, "url": { - "raw": "{{api-url}}/v4/productTemplates/1/milestones/1", + "raw": "{{api-url}}/v4/timelines/metadata/milestoneTemplates/1", "host": [ "{{api-url}}" ], "path": [ "v4", - "productTemplates", - "1", - "milestones", + "timelines", + "metadata", + "milestoneTemplates", "1" ] } @@ -4244,18 +4627,18 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"param\":{\r\n\t\"name\": \"milestoneTemplate 1-updated\",\r\n\t\"description\": \"description 1-updated\",\r\n\t\"duration\": 34,\r\n\t\"type\": \"type1-updated\",\r\n\t\"order\": 1\r\n }\r\n}" + "raw": "{\r\n \"param\":{\r\n\t\"name\": \"milestoneTemplate 1-updated\",\r\n\t\"description\": \"description 1-updated\",\r\n\t\"duration\": 34,\r\n\t\"type\": \"type1-updated\",\r\n\t\"order\": 1,\r\n\t\"reference\": \"productTemplate\",\r\n\t\"referenceId\": 1\r\n }\r\n}" }, "url": { - "raw": "{{api-url}}/v4/productTemplates/1/milestones/1", + "raw": "{{api-url}}/v4/timelines/metadata/milestoneTemplates/1", "host": [ "{{api-url}}" ], "path": [ "v4", - "productTemplates", - "1", - "milestones", + "timelines", + "metadata", + "milestoneTemplates", "1" ] } @@ -4278,18 +4661,18 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"param\":{\r\n \"name\": \"milestoneTemplate 1-updated\",\r\n \"description\": \"description 1-updated\",\r\n \"duration\": 34,\r\n \"type\": \"type1-updated\",\r\n \"order\": 3\r\n }\r\n}" + "raw": "{\r\n \"param\":{\r\n \"name\": \"milestoneTemplate 1-updated\",\r\n \"description\": \"description 1-updated\",\r\n \"duration\": 34,\r\n \"type\": \"type1-updated\",\r\n \"order\": 3,\r\n\t\"reference\": \"productTemplate\",\r\n\t\"referenceId\": 1\r\n }\r\n}" }, "url": { - "raw": "{{api-url}}/v4/productTemplates/1/milestones/1", + "raw": "{{api-url}}/v4/timelines/metadata/milestoneTemplates/1", "host": [ "{{api-url}}" ], "path": [ "v4", - "productTemplates", - "1", - "milestones", + "timelines", + "metadata", + "milestoneTemplates", "1" ] } @@ -4312,18 +4695,52 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"param\":{\r\n \"name\": \"milestoneTemplate 1-updated\",\r\n \"description\": \"description 1-updated\",\r\n \"duration\": 34,\r\n \"type\": \"type1-updated\",\r\n \"order\": 1\r\n }\r\n}" + "raw": "{\r\n \"param\":{\r\n \"name\": \"milestoneTemplate 1-updated\",\r\n \"description\": \"description 1-updated\",\r\n \"duration\": 34,\r\n \"type\": \"type1-updated\",\r\n \"order\": 1,\r\n\t\"reference\": \"productTemplate\",\r\n\t\"referenceId\": 1\r\n }\r\n}" }, "url": { - "raw": "{{api-url}}/v4/productTemplates/1/milestones/1", + "raw": "{{api-url}}/v4/timelines/metadata/milestoneTemplates/1", "host": [ "{{api-url}}" ], "path": [ "v4", - "productTemplates", - "1", - "milestones", + "timelines", + "metadata", + "milestoneTemplates", + "1" + ] + } + }, + "response": [] + }, + { + "name": "Update milestone with metadata", + "request": { + "method": "PATCH", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Authorization", + "value": "Bearer {{jwt-token}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"param\":{\r\n\t\"name\": \"milestoneTemplate 5-updated\",\r\n\t\"description\": \"description 5-updated\",\r\n\t\"duration\": 34,\r\n\t\"type\": \"type5-updated\",\r\n\t\"order\": 5,\r\n\t\"reference\": \"productTemplate\",\r\n\t\"referenceId\": 1,\r\n\t\"metadata\": {\r\n \"metadata1\": {\r\n \"name\": \"metadata 1 - update\",\r\n \"details\": {\r\n \"anyDetails\": \"any details 1 - update\",\r\n \"newDetails\": \"new\"\r\n },\r\n \"others\": [\"others new\"]\r\n },\r\n \"metadata3\": {\r\n \"name\": \"metadata 3\",\r\n \"details\": {\r\n \"anyDetails\": \"any details 3\"\r\n },\r\n \"others\": [\"others 31\", \"others 32\"]\r\n }\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{api-url}}/v4/timelines/metadata/milestoneTemplates/1", + "host": [ + "{{api-url}}" + ], + "path": [ + "v4", + "timelines", + "metadata", + "milestoneTemplates", "1" ] } @@ -4349,15 +4766,15 @@ "raw": "" }, "url": { - "raw": "{{api-url}}/v4/productTemplates/1/milestones/2", + "raw": "{{api-url}}/v4/timelines/metadata/milestoneTemplates/2", "host": [ "{{api-url}}" ], "path": [ "v4", - "productTemplates", - "1", - "milestones", + "timelines", + "metadata", + "milestoneTemplates", "2" ] } @@ -4365,6 +4782,34 @@ "response": [] } ] + }, + { + "name": "Metadata", + "item": [ + { + "name": "Get all metadata", + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{api-url}}/v4/projects/metadata", + "host": [ + "{{api-url}}" + ], + "path": [ + "v4", + "projects", + "metadata" + ] + } + }, + "response": [] + } + ] } ] } \ No newline at end of file diff --git a/postman_environment.json b/postman_environment.json index d1ccbbd4..261834ae 100644 --- a/postman_environment.json +++ b/postman_environment.json @@ -1,65 +1,63 @@ { - "id": "e6b30b4b-1388-4622-8314-bc49ba1d752b", + "id": "53925cd5-ff42-43a2-bb87-29f9aa73ffd9", "name": "tc-project-service", "values": [ { "key": "api-url", "value": "http://localhost:3000", "description": "", - "type": "text", "enabled": true }, { "key": "jwt-token", - "value": "", + "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiYWRtaW5pc3RyYXRvciJdLCJpc3MiOiJodHRwczovL2FwaS50b3Bjb2Rlci1kZXYuY29tIiwiaGFuZGxlIjoidGVzdDEiLCJleHAiOjI1NjMwNzY2ODksInVzZXJJZCI6IjQwMDUxMzMzIiwiaWF0IjoxNDYzMDc2MDg5LCJlbWFpbCI6InRlc3RAdG9wY29kZXIuY29tIiwianRpIjoiYjMzYjc3Y2QtYjUyZS00MGZlLTgzN2UtYmViOGUwYWU2YTRhIn0.wKWUe0-SaiFVN-VR_-GwgFlvWaDkSbc8H55ktb9LAVw", "description": "", - "type": "text", "enabled": true }, { "key": "jwt-token-admin-40051333", - "value": "", + "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiYWRtaW5pc3RyYXRvciJdLCJpc3MiOiJodHRwczovL2FwaS50b3Bjb2Rlci1kZXYuY29tIiwiaGFuZGxlIjoidGVzdDEiLCJleHAiOjI1NjMwNzY2ODksInVzZXJJZCI6IjQwMDUxMzMzIiwiaWF0IjoxNDYzMDc2MDg5LCJlbWFpbCI6InRlc3RAdG9wY29kZXIuY29tIiwianRpIjoiYjMzYjc3Y2QtYjUyZS00MGZlLTgzN2UtYmViOGUwYWU2YTRhIn0.wKWUe0-SaiFVN-VR_-GwgFlvWaDkSbc8H55ktb9LAVw", "description": "", - "type": "text", "enabled": true }, { "key": "jwt-token-member-40051331", - "value": "", + "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIl0sImlzcyI6Imh0dHBzOi8vYXBpLnRvcGNvZGVyLWRldi5jb20iLCJoYW5kbGUiOiJ0ZXN0MSIsImV4cCI6MjU2MzA3NjY4OSwidXNlcklkIjoiNDAwNTEzMzEiLCJpYXQiOjE0NjMwNzYwODksImVtYWlsIjoidGVzdEB0b3Bjb2Rlci5jb20iLCJqdGkiOiJiMzNiNzdjZC1iNTJlLTQwZmUtODM3ZS1iZWI4ZTBhZTZhNGEifQ.pDtRzcGQjgCBD6aLsW-1OFhzmrv5mXhb8YLDWbGAnKo", "description": "", - "type": "text", "enabled": true }, { "key": "jwt-token-copilot-40051332", - "value": "", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiQ29ubmVjdCBDb3BpbG90Il0sImlzcyI6Imh0dHBzOi8vYXBpLnRvcGNvZGVyLWRldi5jb20iLCJoYW5kbGUiOiJ0ZXN0MSIsImV4cCI6MjU2MzA3NjY4OSwidXNlcklkIjo0MDA1MTMzMiwiZW1haWwiOiJ0ZXN0QHRvcGNvZGVyLmNvbSIsImlhdCI6MTQ3MDYyMDA0NH0.DnX17gBaVF2JTuRai-C2BDSdEjij9da_s4eYcMIjP0c", "description": "", - "type": "text", "enabled": true }, { "key": "jwt-token-manager-40051334", - "value": "", + "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiQ29ubmVjdCBNYW5hZ2VyIl0sImlzcyI6Imh0dHBzOi8vYXBpLnRvcGNvZGVyLWRldi5jb20iLCJoYW5kbGUiOiJ0ZXN0MSIsImV4cCI6MjU2MzA3NjY4OSwidXNlcklkIjoiNDAwNTEzMzQiLCJpYXQiOjE0NjMwNzYwODksImVtYWlsIjoidGVzdEB0b3Bjb2Rlci5jb20iLCJqdGkiOiJiMzNiNzdjZC1iNTJlLTQwZmUtODM3ZS1iZWI4ZTBhZTZhNGEifQ.J5VtOEQVph5jfe2Ji-NH7txEDcx_5gthhFeD-MzX9ck", "description": "", - "type": "text", "enabled": true }, { "key": "jwt-token-member2-40051335", - "value": "", + "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIl0sImlzcyI6Imh0dHBzOi8vYXBpLnRvcGNvZGVyLWRldi5jb20iLCJoYW5kbGUiOiJtZW1iZXIyIiwiZXhwIjoyNTYzMDc2Njg5LCJ1c2VySWQiOiI0MDA1MTMzNSIsImlhdCI6MTQ2MzA3NjA4OSwiZW1haWwiOiJ0ZXN0QHRvcGNvZGVyLmNvbSIsImp0aSI6ImIzM2I3N2NkLWI1MmUtNDBmZS04MzdlLWJlYjhlMGFlNmE0YSJ9.Mh4bw3wm-cn5Kcf96gLFVlD0kySOqqk4xN3qnreAKL4", "description": "", - "type": "text", "enabled": true }, { "key": "jwt-token-connectAdmin-40051336", - "value": "", + "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJDb25uZWN0IEFkbWluIl0sImlzcyI6Imh0dHBzOi8vYXBpLnRvcGNvZGVyLWRldi5jb20iLCJoYW5kbGUiOiJjb25uZWN0X2FkbWluMSIsImV4cCI6MjU2MzA3NjY4OSwidXNlcklkIjoiNDAwNTEzMzYiLCJpYXQiOjE0NjMwNzYwODksImVtYWlsIjoiY29ubmVjdF9hZG1pbjFAdG9wY29kZXIuY29tIiwianRpIjoiYjMzYjc3Y2QtYjUyZS00MGZlLTgzN2UtYmViOGUwYWU2YTRhIn0.nSGfXMl02NZ90ZKLiEKPg75iAjU92mfteaY6xgqkM30", + "description": "", + "enabled": true + }, + { + "key": "inactive-userId", + "value": "1800075", "description": "", - "type": "text", "enabled": true } ], "_postman_variable_scope": "environment", - "_postman_exported_at": "2018-05-18T18:54:18.167Z", - "_postman_exported_using": "Postman/6.0.10" + "_postman_exported_at": "2018-08-28T10:28:37.251Z", + "_postman_exported_using": "Postman/6.2.5" } \ No newline at end of file diff --git a/src/app.js b/src/app.js index 864fb0e6..8687aab5 100644 --- a/src/app.js +++ b/src/app.js @@ -6,7 +6,9 @@ import expressSanitizer from 'express-sanitizer'; import config from 'config'; import cors from 'cors'; import coreLib from 'tc-core-library-js'; +import performanceRequestLogger from './middlewares/performanceRequestLogger'; import expressRequestId from 'express-request-id'; +import memWatch from 'memwatch-next'; import router from './routes'; import permissions from './permissions'; import models from './models'; @@ -61,9 +63,35 @@ const logger = coreLib.logger({ captureLogs: config.get('captureLogs'), logentriesToken: _.get(config, 'logentriesToken', null), }); -app.use(coreLib.middleware.logger(null, logger)); +app.use(performanceRequestLogger(logger)); app.logger = logger; +// ======================== +// Memory leak detection +// ======================== +if (process.env.NODE_ENV.toLowerCase() === 'development') { + let heapDiff = null; + + // A leak event will be emitted when the heap usage has increased + // for five consecutive garbage collections + memWatch.on('leak', (info) => { + logger.error('memwatch::leak=>', info); + + if (!heapDiff) { + heapDiff = new memWatch.HeapDiff(); + } else { + const diff = heapDiff.end(); + logger.error('memwatch::diff=>', diff); + heapDiff = null; + } + }); + + // When V8 performs a garbage collection, memwatch will emit a stats event + memWatch.on('stats', (stats) => { + logger.debug('memwatch::stats=>', stats); + }); +} + // ======================= // CORS ================ // ======================= diff --git a/src/constants.js b/src/constants.js index 91e539f1..90248b1f 100644 --- a/src/constants.js +++ b/src/constants.js @@ -98,6 +98,13 @@ export const BUS_API_EVENT = { // When specification of a product is modified PROJECT_PRODUCT_SPECIFICATION_MODIFIED: 'notifications.connect.project.productSpecificationModified', + + // When milestone is marked as active + MILESTONE_TRANSITION_ACTIVE: 'notifications.connect.project.phase.milestone.transition.active', + // When milestone is marked as completed + MILESTONE_TRANSITION_COMPLETED: 'notifications.connect.project.phase.milestone.transition.completed', + // When milestone is waiting for customers's input + MILESTONE_WAITING_CUSTOMER: 'notifications.connect.project.phase.milestone.waiting.customer', }; export const REGEX = { @@ -113,3 +120,8 @@ export const TIMELINE_REFERENCES = { PHASE: 'phase', PRODUCT: 'product', }; + +export const MILESTONE_TEMPLATE_REFERENCES = { + PRODUCT_TEMPLATE: 'productTemplate', +}; + diff --git a/src/events/busApi.js b/src/events/busApi.js index c10613bc..7e5167bf 100644 --- a/src/events/busApi.js +++ b/src/events/busApi.js @@ -1,6 +1,7 @@ import _ from 'lodash'; import config from 'config'; -import { EVENT, BUS_API_EVENT, PROJECT_STATUS, PROJECT_PHASE_STATUS, PROJECT_MEMBER_ROLE } from '../constants'; +import { EVENT, BUS_API_EVENT, PROJECT_STATUS, PROJECT_PHASE_STATUS, PROJECT_MEMBER_ROLE, MILESTONE_STATUS } + from '../constants'; import { createEvent } from '../services/busApi'; import models from '../models'; @@ -414,4 +415,92 @@ module.exports = (app, logger) => { } }).catch(err => null); // eslint-disable-line no-unused-vars }); + + /** + * Send milestone notification if needed. + * @param {Object} req the request + * @param {Object} original the original milestone + * @param {Object} updated the updated milestone + * @param {Object} project the project + * @returns {Promise} void + */ + function sendMilestoneNotification(req, original, updated, project) { + // Send transition events + if (original.status !== updated.status) { + let event; + if (updated.status === MILESTONE_STATUS.COMPLETED) { + event = BUS_API_EVENT.MILESTONE_TRANSITION_COMPLETED; + } else if (updated.status === MILESTONE_STATUS.ACTIVE) { + event = BUS_API_EVENT.MILESTONE_TRANSITION_ACTIVE; + } + + if (event) { + createEvent(event, { + projectId: project.id, + projectName: project.name, + projectUrl: connectProjectUrl(project.id), + timelineId: req.timeline.id, + timelineName: req.timeline.name, + originalMilestone: original, + updatedMilestone: updated, + userId: req.authUser.userId, + initiatorUserId: req.authUser.userId, + }, logger); + } + } + + // Send notifications.connect.project.phase.milestone.waiting.customer event + const originalWaiting = _.get(original, 'details.metadata.waitingForCustomer', false); + const updatedWaiting = _.get(updated, 'details.metadata.waitingForCustomer', false); + if (!originalWaiting && updatedWaiting) { + createEvent(BUS_API_EVENT.MILESTONE_WAITING_CUSTOMER, { + projectId: project.id, + projectName: project.name, + projectUrl: connectProjectUrl(project.id), + timelineId: req.timeline.id, + timelineName: req.timeline.name, + originalMilestone: original, + updatedMilestone: updated, + userId: req.authUser.userId, + initiatorUserId: req.authUser.userId, + }, logger); + } + } + + /** + * MILESTONE_ADDED. + */ + app.on(EVENT.ROUTING_KEY.MILESTONE_ADDED, ({ req, created }) => { + logger.debug('receive MILESTONE_ADDED event'); + + const projectId = _.parseInt(req.params.projectId); + + models.Project.findOne({ + where: { id: projectId }, + }) + .then(project => sendMilestoneNotification(req, {}, created, project)) + .catch(err => null); // eslint-disable-line no-unused-vars + }); + + /** + * MILESTONE_UPDATED. + */ + // eslint-disable-next-line no-unused-vars + app.on(EVENT.ROUTING_KEY.MILESTONE_UPDATED, ({ req, original, updated, cascadedUpdates }) => { + logger.debug('receive MILESTONE_UPDATED event'); + + const projectId = _.parseInt(req.params.projectId); + + models.Project.findOne({ + where: { id: projectId }, + }) + .then((project) => { + sendMilestoneNotification(req, original, updated, project); + + _.each(cascadedUpdates, cascadedUpdate => + sendMilestoneNotification(req, cascadedUpdate.original, cascadedUpdate.updated, project), + ); + }) + .catch(err => null); // eslint-disable-line no-unused-vars + }); }; diff --git a/src/events/projectPhases/index.js b/src/events/projectPhases/index.js index 656dcfb1..09e964cb 100644 --- a/src/events/projectPhases/index.js +++ b/src/events/projectPhases/index.js @@ -29,6 +29,14 @@ const indexProjectPhase = Promise.coroutine(function* (logger, phase) { // eslin const existingPhaseIndex = _.findIndex(phases, p => p.id === phase.id); // if phase does not exists already if (existingPhaseIndex === -1) { + // Increase the order of the other phases in the same project, + // which have `order` >= this phase order + _.each(phases, (_phase) => { + if (!_.isNil(_phase.order) && !_.isNil(phase.order) && _phase.order >= phase.order) { + _phase.order += 1; // eslint-disable-line no-param-reassign + } + }); + phases.push(_.omit(phase, ['deletedAt', 'deletedBy'])); } else { // if phase already exists, ideally we should never land here, but code handles the buggy indexing // replaces the old inconsistent index where previously phase was not removed from the index but deleted @@ -109,12 +117,7 @@ const projectPhaseUpdatedHandler = Promise.coroutine(function* (logger, msg, cha try { const data = JSON.parse(msg.content.toString()); const doc = yield eClient.get({ index: ES_PROJECT_INDEX, type: ES_PROJECT_TYPE, id: data.original.projectId }); - const phases = _.map(doc._source.phases, (single) => { // eslint-disable-line no-underscore-dangle - if (single.id === data.original.id) { - return _.assign(single, _.omit(data.updated, ['deletedAt', 'deletedBy'])); - } - return single; - }); + const phases = _.map(data.allPhases, single => _.omit(single, ['deletedAt', 'deletedBy'])); const merged = _.assign(doc._source, { phases }); // eslint-disable-line no-underscore-dangle yield eClient.update({ index: ES_PROJECT_INDEX, diff --git a/src/middlewares/performanceRequestLogger.js b/src/middlewares/performanceRequestLogger.js new file mode 100644 index 00000000..2b8f9d55 --- /dev/null +++ b/src/middlewares/performanceRequestLogger.js @@ -0,0 +1,37 @@ +import coreLib from 'tc-core-library-js'; + +module.exports = function logRequest(logger) { + if (!logger) { + throw new Error('Logger must be provided') + } + + // Use the logger from core lib for non-dev environment + if (process.env.NODE_ENV.toLowerCase() !== 'development') { + return coreLib.middleware.logger(null, logger); + } + + // Use the logger with memory usage info + return (req, res, next) => { + var startOpts = { + method: req.method, + url: req.url, + }; + // Create a per-request child + req.log = res.log = logger.child({ requestId: req.id }); + req.log.info('start request', startOpts); + const time = process.hrtime(); + res.on('finish', function responseSent() { + const diff = process.hrtime(time); + res.log.info('end request', { + method: startOpts.method, + url: startOpts.url, + statusCode: res.statusCode, + statusMessage: res.statusMessage, + duration: diff[0] * 1e3 + diff[1] * 1e-6, + heapUsed: process.memoryUsage().heapUsed + }); + }); + + next(); + }; +}; diff --git a/src/middlewares/userIdAuth.js b/src/middlewares/userIdAuth.js new file mode 100644 index 00000000..20f90c9d --- /dev/null +++ b/src/middlewares/userIdAuth.js @@ -0,0 +1,72 @@ +/** + * The userId authentication middleware. + */ +import config from 'config'; +import _ from 'lodash'; +import util from '../util'; + +const whitelistedOrigins = JSON.parse(config.get('whitelistedOriginsForUserIdAuth')); + +/** + * The userId authentication middleware. + * @param {Object} req the request + * @param {Object} res the response + * @param {Function} next the next middleware + * @returns {Promise} void + */ +module.exports = function userIdAuth(req, res, next) { // eslint-disable-line consistent-return + req.log.debug('Enter userIdAuth middleware'); + + const bearerUserId = 'Bearer userId_'; + + if (!req.headers.authorization || + !req.headers.authorization.startsWith(bearerUserId) || + req.headers.authorization.length === bearerUserId.length) { + res.status(403) + .json(util.wrapErrorResponse(req.id, 403, 'No userId provided.')); + return res.send(); + } + + // Check origin + const origin = req.header('Origin') || ' '; + if (!_.some(whitelistedOrigins, whitelistedOrigin => origin.startsWith(whitelistedOrigin))) { + res.status(403).json( + util.wrapErrorResponse(req.id, 403, `Origin ${origin} is not allowed to access this authentication scheme`)); + return res.end(); + } + + const userId = req.headers.authorization.split(bearerUserId)[1]; + + req.log.debug('Get m2m token'); + util.getM2MToken() + .then((token) => { + req.log.debug(`Get topcoder user from identity service, userId = ${userId}`); + + return util.getTopcoderUser(userId, token, req.log) + .then((user) => { + if (!user) { + res.status(403) + .json(util.wrapErrorResponse(req.id, 403, 'User does not exist.')); + return res.end(); + } + + if (user.active) { + res.status(403) + .json(util.wrapErrorResponse(req.id, 403, 'User is not inactive.')); + return res.end(); + } + + // Store user into the request + req.authUser = user; + req.authUser.userId = user.id; + req.authUser.roles = req.authUser.roles || []; + req.log.debug('req.authUser=>', req.authUser); + + return next(); + }); + }) + .catch((err) => { + req.log.error('Failed to get m2m token', err); + next(err); + }); +}; diff --git a/src/middlewares/validateMilestoneTemplate.js b/src/middlewares/validateMilestoneTemplate.js new file mode 100644 index 00000000..1aea3ace --- /dev/null +++ b/src/middlewares/validateMilestoneTemplate.js @@ -0,0 +1,136 @@ +import _ from 'lodash'; +import { MILESTONE_TEMPLATE_REFERENCES } from '../constants'; +import models from '../models'; +import util from '../util'; + +// eslint-disable-next-line valid-jsdoc +/** + * Common validation code for types of milestone template references. + * @param {{ reference: string, referenceId: string|number }} sourceObject + * @returns {Promise} + */ +async function validateReference(sourceObject) { + // The source object refers to a product template + if (sourceObject.reference === MILESTONE_TEMPLATE_REFERENCES.PRODUCT_TEMPLATE) { + // Validate ProductTemplate to be existed + const productTemplate = await models.ProductTemplate.findOne({ + where: { + id: sourceObject.referenceId, + deletedAt: { $eq: null }, + }, + }); + if (!productTemplate) { + const apiErr = new Error( + `Product template not found for product template id ${sourceObject.referenceId}`); + apiErr.status = 422; + throw apiErr; + } + } +} + +const validateMilestoneTemplate = { + + /** + * The middleware to validate MilestoneTemplate request object. + * This should be called after the validate() middleware, + * and before the permissions() middleware. + * @param {Object} req the express request instance + * @param {Object} res the express response instance + * @param {Function} next the express next middleware + */ + // eslint-disable-next-line valid-jsdoc + validateRequestBody: (req, res, next) => { + validateReference(req.body.param, req) + .then(() => { + if (req.body.param.sourceReference) { + return validateReference({ + reference: req.body.param.sourceReference, + referenceId: req.body.param.sourceReferenceId, + }); + } + + return Promise.resolve(); + }) + .then(next) + .catch(next); + }, + + /** + * The middleware to validate reference/referenceId pair + * present in the request's query filter and set to the request params. Because of the filter needs + * to be parsed, this can be the first middleware in the stack, and can be placed before the permissions() + * middleware. + * @param {Object} req the express request instance + * @param {Object} res the express response instance + * @param {Function} next the express next middleware + */ + // eslint-disable-next-line valid-jsdoc + validateQueryFilter: (req, res, next) => { + if (!req.query.filter) { + return next(); + } + + // Validate the filter + const filter = util.parseQueryFilter(req.query.filter); + + // Save the parsed filter for later + req.params.filter = filter; + + if (!util.isValidFilter(filter, ['reference', 'referenceId'])) { + const apiErr = new Error('Only allowed to filter by reference and referenceId'); + apiErr.status = 422; + return next(apiErr); + } + + // Verify required filters are present + if (!filter.reference || !filter.referenceId) { + const apiErr = new Error('Please provide reference and referenceId filter parameters'); + apiErr.status = 422; + return next(apiErr); + } + + // Verify reference is a valid value + if (!_.includes(MILESTONE_TEMPLATE_REFERENCES, filter.reference)) { + const apiErr = new Error(`reference filter must be in ${MILESTONE_TEMPLATE_REFERENCES}`); + apiErr.status = 422; + return next(apiErr); + } + + if (_.lt(filter.referenceId, 1)) { + const apiErr = new Error('referenceId filter must be a positive integer'); + apiErr.status = 422; + return next(apiErr); + } + + return validateReference(filter, req) + .then(next) + .catch(next); + }, + + /** + * The middleware to validate milestoneTemplateId from request + * path parameter, and set to the request params. This should be called after the validate() + * middleware, and before the permissions() middleware. + * @param {Object} req the express request instance + * @param {Object} res the express response instance + * @param {Function} next the express next middleware + */ + // eslint-disable-next-line valid-jsdoc + validateIdParam: (req, res, next) => { + models.MilestoneTemplate.findById(req.params.milestoneTemplateId) + .then((milestoneTemplate) => { + if (!milestoneTemplate) { + const apiErr = new Error( + `MilestoneTemplate not found for id ${req.params.milestoneTemplateId}`); + apiErr.status = 404; + return next(apiErr); + } + + req.milestoneTemplate = milestoneTemplate; + + return next(); + }); + }, +}; + +export default validateMilestoneTemplate; diff --git a/src/models/productMilestoneTemplate.js b/src/models/milestoneTemplate.js similarity index 77% rename from src/models/productMilestoneTemplate.js rename to src/models/milestoneTemplate.js index 7db76b52..feb37a1d 100644 --- a/src/models/productMilestoneTemplate.js +++ b/src/models/milestoneTemplate.js @@ -1,10 +1,10 @@ /* eslint-disable valid-jsdoc */ /** - * The Product Milestone Template model + * The Milestone Template model */ module.exports = (sequelize, DataTypes) => { - const ProductMilestoneTemplate = sequelize.define('ProductMilestoneTemplate', { + const MilestoneTemplate = sequelize.define('MilestoneTemplate', { id: { type: DataTypes.BIGINT, primaryKey: true, autoIncrement: true }, name: { type: DataTypes.STRING(255), allowNull: false }, description: DataTypes.STRING(255), @@ -16,6 +16,11 @@ module.exports = (sequelize, DataTypes) => { completedText: { type: DataTypes.STRING(512), allowNull: false }, blockedText: { type: DataTypes.STRING(512), allowNull: false }, hidden: { type: DataTypes.BOOLEAN, defaultValue: false }, + + reference: { type: DataTypes.STRING(45), allowNull: false }, + referenceId: { type: DataTypes.BIGINT, allowNull: false }, + metadata: { type: DataTypes.JSON, defaultValue: {}, allowNull: false }, + deletedAt: DataTypes.DATE, createdAt: { type: DataTypes.DATE, defaultValue: DataTypes.NOW }, updatedAt: { type: DataTypes.DATE, defaultValue: DataTypes.NOW }, @@ -23,7 +28,7 @@ module.exports = (sequelize, DataTypes) => { createdBy: { type: DataTypes.BIGINT, allowNull: false }, updatedBy: { type: DataTypes.BIGINT, allowNull: false }, }, { - tableName: 'product_milestone_templates', + tableName: 'milestone_templates', paranoid: true, timestamps: true, updatedAt: 'updatedAt', @@ -31,5 +36,5 @@ module.exports = (sequelize, DataTypes) => { deletedAt: 'deletedAt', }); - return ProductMilestoneTemplate; + return MilestoneTemplate; }; diff --git a/src/models/productTemplate.js b/src/models/productTemplate.js index fe955de8..4e4dc184 100644 --- a/src/models/productTemplate.js +++ b/src/models/productTemplate.js @@ -29,15 +29,6 @@ module.exports = (sequelize, DataTypes) => { updatedAt: 'updatedAt', createdAt: 'createdAt', deletedAt: 'deletedAt', - classMethods: { - associate: (models) => { - ProductTemplate.hasMany(models.ProductMilestoneTemplate, { - as: 'milestones', - foreignKey: 'productTemplateId', - onDelete: 'cascade', - }); - }, - }, }); return ProductTemplate; diff --git a/src/models/projectPhase.js b/src/models/projectPhase.js index 75b8e3dd..35649382 100644 --- a/src/models/projectPhase.js +++ b/src/models/projectPhase.js @@ -14,6 +14,7 @@ module.exports = function defineProjectPhase(sequelize, DataTypes) { spentBudget: { type: DataTypes.DOUBLE, defaultValue: 0.0 }, progress: { type: DataTypes.DOUBLE, defaultValue: 0.0 }, details: { type: DataTypes.JSON, defaultValue: {} }, + order: { type: DataTypes.INTEGER, allowNull: true }, deletedAt: { type: DataTypes.DATE, allowNull: true }, createdAt: { type: DataTypes.DATE, defaultValue: DataTypes.NOW }, diff --git a/src/permissions/index.js b/src/permissions/index.js index f9b3668c..2bdfd10e 100644 --- a/src/permissions/index.js +++ b/src/permissions/index.js @@ -68,4 +68,6 @@ module.exports = () => { Authorizer.setPolicy('milestone.edit', projectEdit); Authorizer.setPolicy('milestone.delete', projectEdit); Authorizer.setPolicy('milestone.view', projectView); + + Authorizer.setPolicy('metadata.list', true); // anyone can view all metadata }; diff --git a/src/routes/index.js b/src/routes/index.js index 8e4f034f..c2a39ec8 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -3,6 +3,7 @@ import _ from 'lodash'; import config from 'config'; import validate from 'express-validation'; import { Router } from 'express'; +import userIdAuth from '../middlewares/userIdAuth'; const router = Router(); @@ -26,29 +27,44 @@ router.get(`/${apiVersion}/projects/health`, (req, res) => { // All project service endpoints need authentication const jwtAuth = require('tc-core-library-js').middleware.jwtAuthenticator; -router.route('/v4/projectTemplates') +router.route('/v4/projects/metadata/projectTemplates') .get(require('./projectTemplates/list')); -router.route('/v4/projectTemplates/:templateId(\\d+)') +router.route('/v4/projects/metadata/projectTemplates/:templateId(\\d+)') .get(require('./projectTemplates/get')); -router.route('/v4/productTemplates') +router.route('/v4/projects/metadata/productTemplates') .get(require('./productTemplates/list')); -router.route('/v4/productTemplates/:templateId(\\d+)') +router.route('/v4/projects/metadata/productTemplates/:templateId(\\d+)') .get(require('./productTemplates/get')); -router.route('/v4/projectTypes') +router.route('/v4/projects/metadata/projectTypes') .get(require('./projectTypes/list')); -router.route('/v4/projectTypes/:key') +router.route('/v4/projects/metadata/projectTypes/:key') .get(require('./projectTypes/get')); -router.route('/v4/productCategories') +router.route('/v4/projects/metadata/productCategories') .get(require('./productCategories/list')); -router.route('/v4/productCategories/:key') +router.route('/v4/projects/metadata/productCategories/:key') .get(require('./productCategories/get')); +router.route('/v4/projects/metadata') + .get(require('./metadata/list')); + router.all( - RegExp(`\\/${apiVersion}\\/(projects|projectTemplates|productTemplates|productCategories|projectTypes|` + - 'timelines)(?!\\/health).*'), jwtAuth()); + RegExp(`\\/${apiVersion}\\/(projects|timelines)(?!\\/health).*`), (req, res, next) => { + // userId authentication for project creation endpoint + if (req.method === 'POST' && + req.path.endsWith('/v4/projects') && + req.headers.authorization && + req.headers.authorization.startsWith('Bearer userId_') + ) { + return userIdAuth(req, res, next); + } + + // JWT authentication + return jwtAuth()(req, res, next); + }, +); // Register all the routes router.route('/v4/projects') @@ -90,32 +106,20 @@ router.route('/v4/projects/:projectId(\\d+)/attachments/:id(\\d+)') router.route('/v4/projects/:projectId(\\d+)/upgrade') .post(require('./projectUpgrade/create')); -router.route('/v4/projectTemplates') +router.route('/v4/projects/metadata/projectTemplates') .post(require('./projectTemplates/create')); -router.route('/v4/projectTemplates/:templateId(\\d+)') +router.route('/v4/projects/metadata/projectTemplates/:templateId(\\d+)') .patch(require('./projectTemplates/update')) .delete(require('./projectTemplates/delete')); -router.route('/v4/productTemplates') +router.route('/v4/projects/metadata/productTemplates') .post(require('./productTemplates/create')); -router.route('/v4/productTemplates/:templateId(\\d+)') +router.route('/v4/projects/metadata/productTemplates/:templateId(\\d+)') .patch(require('./productTemplates/update')) .delete(require('./productTemplates/delete')); -router.route('/v4/productTemplates/:productTemplateId(\\d+)/milestones') - .post(require('./milestoneTemplates/create')) - .get(require('./milestoneTemplates/list')); - -router.route('/v4/productTemplates/:productTemplateId(\\d+)/milestones/clone') - .post(require('./milestoneTemplates/clone')); - -router.route('/v4/productTemplates/:productTemplateId(\\d+)/milestones/:milestoneTemplateId(\\d+)') - .get(require('./milestoneTemplates/get')) - .patch(require('./milestoneTemplates/update')) - .delete(require('./milestoneTemplates/delete')); - router.route('/v4/projects/:projectId(\\d+)/phases') .get(require('./phases/list')) .post(require('./phases/create')); @@ -134,17 +138,17 @@ router.route('/v4/projects/:projectId(\\d+)/phases/:phaseId(\\d+)/products/:prod .patch(require('./phaseProducts/update')) .delete(require('./phaseProducts/delete')); -router.route('/v4/productCategories') +router.route('/v4/projects/metadata/productCategories') .post(require('./productCategories/create')); -router.route('/v4/productCategories/:key') +router.route('/v4/projects/metadata/productCategories/:key') .patch(require('./productCategories/update')) .delete(require('./productCategories/delete')); -router.route('/v4/projectTypes') +router.route('/v4/projects/metadata/projectTypes') .post(require('./projectTypes/create')); -router.route('/v4/projectTypes/:key') +router.route('/v4/projects/metadata/projectTypes/:key') .patch(require('./projectTypes/update')) .delete(require('./projectTypes/delete')); @@ -166,6 +170,18 @@ router.route('/v4/timelines/:timelineId(\\d+)/milestones/:milestoneId(\\d+)') .patch(require('./milestones/update')) .delete(require('./milestones/delete')); +router.route('/v4/timelines/metadata/milestoneTemplates') + .post(require('./milestoneTemplates/create')) + .get(require('./milestoneTemplates/list')); + +router.route('/v4/timelines/metadata/milestoneTemplates/clone') + .post(require('./milestoneTemplates/clone')); + +router.route('/v4/timelines/metadata/milestoneTemplates/:milestoneTemplateId(\\d+)') + .get(require('./milestoneTemplates/get')) + .patch(require('./milestoneTemplates/update')) + .delete(require('./milestoneTemplates/delete')); + // register error handler router.use((err, req, res, next) => { // eslint-disable-line no-unused-vars // DO NOT REMOVE next arg.. even though eslint diff --git a/src/routes/metadata/list.js b/src/routes/metadata/list.js new file mode 100644 index 00000000..5a173913 --- /dev/null +++ b/src/routes/metadata/list.js @@ -0,0 +1,36 @@ +/** + * API to list all metadata + */ +import { middleware as tcMiddleware } from 'tc-core-library-js'; +import util from '../../util'; +import models from '../../models'; + +const permissions = tcMiddleware.permissions; + +module.exports = [ + permissions('metadata.list'), + (req, res, next) => { + const query = { + attributes: { exclude: ['deletedAt', 'deletedBy'] }, + raw: true, + }; + + return Promise.all([ + models.ProjectTemplate.findAll(query), + models.ProductTemplate.findAll(query), + models.MilestoneTemplate.findAll(query), + models.ProjectType.findAll(query), + models.ProductCategory.findAll(query), + ]) + .then((results) => { + res.json(util.wrapResponse(req.id, { + projectTemplates: results[0], + productTemplates: results[1], + milestoneTemplates: results[2], + projectTypes: results[3], + productCategories: results[4], + })); + }) + .catch(next); + }, +]; diff --git a/src/routes/metadata/list.spec.js b/src/routes/metadata/list.spec.js new file mode 100644 index 00000000..7e7c9b4f --- /dev/null +++ b/src/routes/metadata/list.spec.js @@ -0,0 +1,162 @@ +/** + * Tests for list.js + */ +import chai from 'chai'; +import request from 'supertest'; + +import models from '../../models'; +import server from '../../app'; +import testUtil from '../../tests/util'; + +const should = chai.should(); + +const projectTemplates = [ + { + name: 'template 1', + key: 'key 1', + category: 'category 1', + icon: 'http://example.com/icon1.ico', + question: 'question 1', + info: 'info 1', + aliases: ['key-1', 'key_1'], + scope: {}, + phases: {}, + createdBy: 1, + updatedBy: 1, + }, +]; +const productTemplates = [ + { + name: 'name 1', + productKey: 'productKey 1', + category: 'category', + icon: 'http://example.com/icon1.ico', + brief: 'brief 1', + details: 'details 1', + aliases: {}, + template: {}, + createdBy: 1, + updatedBy: 2, + }, +]; +const milestoneTemplates = [ + { + id: 1, + name: 'milestoneTemplate 1', + duration: 3, + type: 'type1', + order: 1, + plannedText: 'text to be shown in planned stage', + blockedText: 'text to be shown in blocked stage', + activeText: 'text to be shown in active stage', + completedText: 'text to be shown in completed stage', + reference: 'product', + referenceId: 1, + metadata: {}, + createdBy: 1, + updatedBy: 2, + }, +]; +const projectTypes = [ + { + key: 'key1', + displayName: 'displayName 1', + icon: 'http://example.com/icon1.ico', + question: 'question 1', + info: 'info 1', + aliases: ['key-1', 'key_1'], + metadata: { 'slack-notification-mappings': { color: '#96d957', label: 'Full App' } }, + createdBy: 1, + updatedBy: 1, + }, +]; +const productCategories = [ + { + key: 'key1', + displayName: 'displayName 1', + icon: 'http://example.com/icon1.ico', + question: 'question 1', + info: 'info 1', + aliases: ['key-1', 'key_1'], + createdBy: 1, + updatedBy: 1, + }, +]; + +describe('GET all metadata', () => { + beforeEach(() => testUtil.clearDb() + .then(() => models.ProjectTemplate.bulkCreate(projectTemplates)) + .then(() => models.ProductTemplate.bulkCreate(productTemplates)) + .then(() => models.MilestoneTemplate.bulkCreate(milestoneTemplates)) + .then(() => models.ProjectType.bulkCreate(projectTypes)) + .then(() => models.ProductCategory.bulkCreate(productCategories)), + ); + after(testUtil.clearDb); + + describe('GET /projects/metadata', () => { + it('should return 200 even if user is not authenticated', (done) => { + request(server) + .get('/v4/projects/metadata') + .expect(200) + .end((err, res) => { + const resJson = res.body.result.content; + should.exist(resJson); + resJson.projectTemplates.should.have.length(1); + resJson.productTemplates.should.have.length(1); + resJson.milestoneTemplates.should.have.length(1); + resJson.projectTypes.should.have.length(1); + resJson.productCategories.should.have.length(1); + + done(); + }); + }); + + it('should return 200 for admin', (done) => { + request(server) + .get('/v4/projects/metadata') + .set({ + Authorization: `Bearer ${testUtil.jwts.admin}`, + }) + .expect(200) + .end(done); + }); + + it('should return 200 for admin', (done) => { + request(server) + .get('/v4/projects/metadata') + .set({ + Authorization: `Bearer ${testUtil.jwts.admin}`, + }) + .expect(200) + .end(done); + }); + + it('should return 200 for connect manager', (done) => { + request(server) + .get('/v4/projects/metadata') + .set({ + Authorization: `Bearer ${testUtil.jwts.manager}`, + }) + .expect(200) + .end(done); + }); + + it('should return 200 for member', (done) => { + request(server) + .get('/v4/projects/metadata') + .set({ + Authorization: `Bearer ${testUtil.jwts.member}`, + }) + .expect(200, done); + }); + + it('should return 200 for copilot', (done) => { + request(server) + .get('/v4/projects/metadata') + .set({ + Authorization: `Bearer ${testUtil.jwts.copilot}`, + }) + .expect(200, done); + }); + }); +}); diff --git a/src/routes/milestoneTemplates/clone.js b/src/routes/milestoneTemplates/clone.js index c7fd1bf3..bfe95a46 100644 --- a/src/routes/milestoneTemplates/clone.js +++ b/src/routes/milestoneTemplates/clone.js @@ -7,94 +7,68 @@ import Joi from 'joi'; import { middleware as tcMiddleware } from 'tc-core-library-js'; import util from '../../util'; import models from '../../models'; +import { MILESTONE_TEMPLATE_REFERENCES } from '../../constants'; +import validateMilestoneTemplate from '../../middlewares/validateMilestoneTemplate'; const permissions = tcMiddleware.permissions; const schema = { - params: { - productTemplateId: Joi.number().integer().positive().required(), - }, body: { param: Joi.object().keys({ - sourceTemplateId: Joi.number().integer().positive().required(), + sourceReference: Joi.string().valid(_.values(MILESTONE_TEMPLATE_REFERENCES)).required(), + sourceReferenceId: Joi.number().integer().positive().required(), + reference: Joi.string().valid(_.values(MILESTONE_TEMPLATE_REFERENCES)).required(), + referenceId: Joi.number().integer().positive().required(), }).required(), }, }; module.exports = [ validate(schema), + validateMilestoneTemplate.validateRequestBody, permissions('milestoneTemplate.clone'), (req, res, next) => { let result; return models.sequelize.transaction(tx => // Find the product template - models.ProductTemplate.findAll({ where: { id: [req.params.productTemplateId, req.body.param.sourceTemplateId] }, - transaction: tx }) - .then((productTemplates) => { - // Not found - if (!productTemplates) { - const apiErr = new Error( - `Product template not found for product template ids ${req.params.productTemplateId} - ${req.body.param.sourceTemplateId}`); - apiErr.status = 404; - return Promise.reject(apiErr); - } - - const targetProductTemplate = _.find(productTemplates, ['id', req.params.productTemplateId]); - const sourceProductTemplate = _.find(productTemplates, ['id', req.body.param.sourceTemplateId]); - - // Not found - if (!targetProductTemplate) { - const apiErr = new Error( - `Product template not found for product template id ${req.params.productTemplateId}`); - apiErr.status = 404; - return Promise.reject(apiErr); - } - - // Not found - if (!sourceProductTemplate) { - const apiErr = new Error( - `Product template not found for source product template id ${req.body.param.sourceTemplateId}`); - apiErr.status = 404; - return Promise.reject(apiErr); - } - - return models.ProductMilestoneTemplate.findAll({ - where: { - productTemplateId: req.body.param.sourceTemplateId, - }, - attributes: { exclude: ['id', 'deletedAt', 'createdAt', 'updatedAt', 'deletedBy'] }, - raw: true, - }) - .then((milestoneTemplatesToClone) => { - const newMilestoneTemplates = _.cloneDeep(milestoneTemplatesToClone); - _.each(newMilestoneTemplates, (milestone) => { - milestone.productTemplateId = req.params.productTemplateId; // eslint-disable-line no-param-reassign - milestone.createdBy = req.authUser.userId; // eslint-disable-line no-param-reassign - milestone.updatedBy = req.authUser.userId; // eslint-disable-line no-param-reassign - }); - return models.ProductMilestoneTemplate.bulkCreate(newMilestoneTemplates, { transaction: tx }); + models.MilestoneTemplate.findAll({ + where: { + reference: req.body.param.sourceReference, + referenceId: req.body.param.sourceReferenceId, + }, + attributes: { exclude: ['id', 'deletedAt', 'createdAt', 'updatedAt', 'deletedBy'] }, + raw: true, + }) + .then((milestoneTemplatesToClone) => { + const newMilestoneTemplates = _.cloneDeep(milestoneTemplatesToClone); + _.each(newMilestoneTemplates, (milestone) => { + milestone.reference = req.body.param.reference; // eslint-disable-line no-param-reassign + milestone.referenceId = req.body.param.referenceId; // eslint-disable-line no-param-reassign + milestone.createdBy = req.authUser.userId; // eslint-disable-line no-param-reassign + milestone.updatedBy = req.authUser.userId; // eslint-disable-line no-param-reassign }); + return models.MilestoneTemplate.bulkCreate(newMilestoneTemplates, { transaction: tx }); }) .then(() => { // eslint-disable-line arrow-body-style - return models.ProductMilestoneTemplate.findAll({ + return models.MilestoneTemplate.findAll({ where: { - productTemplateId: req.params.productTemplateId, + reference: req.body.param.reference, + referenceId: req.body.param.referenceId, }, attributes: { exclude: ['deletedAt', 'deletedBy'] }, raw: true, }) - .then((clonedMilestoneTemplates) => { - result = clonedMilestoneTemplates; - return result; - }); + .then((clonedMilestoneTemplates) => { + result = clonedMilestoneTemplates; + return result; + }); }), ) - .then(() => { - // Write to response - res.status(201).json(util.wrapResponse(req.id, result, 1, 201)); - }) - .catch(next); + .then(() => { + // Write to response + res.status(201).json(util.wrapResponse(req.id, result, result.length, 201)); + }) + .catch(next); }, ]; diff --git a/src/routes/milestoneTemplates/clone.spec.js b/src/routes/milestoneTemplates/clone.spec.js index 2f008e8d..03ad322a 100644 --- a/src/routes/milestoneTemplates/clone.spec.js +++ b/src/routes/milestoneTemplates/clone.spec.js @@ -83,7 +83,9 @@ const milestoneTemplates = [ duration: 3, type: 'type1', order: 1, - productTemplateId: 1, + reference: 'productTemplate', + referenceId: 1, + metadata: {}, plannedText: 'text to be shown in planned stage', blockedText: 'text to be shown in blocked stage', activeText: 'text to be shown in active stage', @@ -100,7 +102,9 @@ const milestoneTemplates = [ blockedText: 'text to be shown in blocked stage - 2', activeText: 'text to be shown in active stage - 2', completedText: 'text to be shown in completed stage - 2', - productTemplateId: 1, + reference: 'productTemplate', + referenceId: 1, + metadata: {}, createdBy: 2, updatedBy: 3, }, @@ -109,27 +113,30 @@ const milestoneTemplates = [ describe('CLONE milestone template', () => { beforeEach(() => testUtil.clearDb() .then(() => models.ProductTemplate.bulkCreate(productTemplates)) - .then(() => models.ProductMilestoneTemplate.bulkCreate(milestoneTemplates)), + .then(() => models.MilestoneTemplate.bulkCreate(milestoneTemplates)), ); after(testUtil.clearDb); - describe('POST /productTemplates/{productTemplateId}/milestones/clone', () => { + describe('POST /timelines/metadata/milestoneTemplates/clone', () => { const body = { param: { - sourceTemplateId: 1, + sourceReference: 'productTemplate', + sourceReferenceId: 1, + reference: 'productTemplate', + referenceId: 2, }, }; it('should return 403 if user is not authenticated/clone', (done) => { request(server) - .post('/v4/productTemplates/2/milestones') + .post('/v4/timelines/metadata/milestoneTemplates/clone') .send(body) .expect(403, done); }); it('should return 403 for member', (done) => { request(server) - .post('/v4/productTemplates/2/milestones/clone') + .post('/v4/timelines/metadata/milestoneTemplates/clone') .set({ Authorization: `Bearer ${testUtil.jwts.member}`, }) @@ -139,7 +146,7 @@ describe('CLONE milestone template', () => { it('should return 403 for copilot', (done) => { request(server) - .post('/v4/productTemplates/2/milestones/clone') + .post('/v4/timelines/metadata/milestoneTemplates/clone') .set({ Authorization: `Bearer ${testUtil.jwts.copilot}`, }) @@ -149,7 +156,7 @@ describe('CLONE milestone template', () => { it('should return 403 for manager', (done) => { request(server) - .post('/v4/productTemplates/2/milestones/clone') + .post('/v4/timelines/metadata/milestoneTemplates/clone') .set({ Authorization: `Bearer ${testUtil.jwts.manager}`, }) @@ -157,41 +164,55 @@ describe('CLONE milestone template', () => { .expect(403, done); }); - it('should return 404 for non-existent product template', (done) => { + it('should return 422 for non-existent product template', (done) => { + const invalidBody = { + param: { + sourceReference: 'productTemplate', + sourceReferenceId: 1, + reference: 'productTemplate', + referenceId: 2000, + }, + }; + request(server) - .post('/v4/productTemplates/1000/milestones/clone') + .post('/v4/timelines/metadata/milestoneTemplates/clone') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) - .send(body) - .expect(404, done); + .send(invalidBody) + .expect(422, done); }); - it('should return 404 for non-existent source product template', (done) => { + it('should return 422 for non-existent source product template', (done) => { const invalidBody = { param: { - sourceTemplateId: 99, + sourceReference: 'product', + sourceReferenceId: 1000, + reference: 'product', + referenceId: 2, }, }; request(server) - .post('/v4/productTemplates/2/milestones/clone') + .post('/v4/timelines/metadata/milestoneTemplates/clone') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) .send(invalidBody) - .expect(404, done); + .expect(422, done); }); - it('should return 422 if missing sourceTemplateId', (done) => { + it('should return 422 if missing sourceReference', (done) => { const invalidBody = { param: { - sourceTemplateId: undefined, + sourceReferenceId: 1000, + reference: 'productTemplate', + referenceId: 2, }, }; request(server) - .post('/v4/productTemplates/2/milestones/clone') + .post('/v4/timelines/metadata/milestoneTemplates/clone') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -202,7 +223,7 @@ describe('CLONE milestone template', () => { it('should return 201 for admin', (done) => { request(server) - .post('/v4/productTemplates/2/milestones/clone') + .post('/v4/timelines/metadata/milestoneTemplates/clone') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -220,7 +241,9 @@ describe('CLONE milestone template', () => { resJson[0].blockedText.should.be.eql(milestoneTemplates[0].blockedText); resJson[0].activeText.should.be.eql(milestoneTemplates[0].activeText); resJson[0].completedText.should.be.eql(milestoneTemplates[0].completedText); - resJson[0].productTemplateId.should.be.eql(2); + resJson[0].reference.should.be.eql('productTemplate'); + resJson[0].referenceId.should.be.eql(2); + resJson[0].metadata.should.be.eql({}); resJson[0].createdBy.should.be.eql(40051333); // admin should.exist(resJson[0].createdAt); @@ -235,7 +258,7 @@ describe('CLONE milestone template', () => { it('should return 201 for connect admin', (done) => { request(server) - .post('/v4/productTemplates/2/milestones/clone') + .post('/v4/timelines/metadata/milestoneTemplates/clone') .set({ Authorization: `Bearer ${testUtil.jwts.connectAdmin}`, }) diff --git a/src/routes/milestoneTemplates/create.js b/src/routes/milestoneTemplates/create.js index b207b72a..321c9b65 100644 --- a/src/routes/milestoneTemplates/create.js +++ b/src/routes/milestoneTemplates/create.js @@ -8,13 +8,12 @@ import Sequelize from 'sequelize'; import { middleware as tcMiddleware } from 'tc-core-library-js'; import util from '../../util'; import models from '../../models'; +import validateMilestoneTemplate from '../../middlewares/validateMilestoneTemplate'; +import { MILESTONE_TEMPLATE_REFERENCES } from '../../constants'; const permissions = tcMiddleware.permissions; const schema = { - params: { - productTemplateId: Joi.number().integer().positive().required(), - }, body: { param: Joi.object().keys({ id: Joi.any().strip(), @@ -27,7 +26,9 @@ const schema = { activeText: Joi.string().max(512).required(), completedText: Joi.string().max(512).required(), blockedText: Joi.string().max(512).required(), - productTemplateId: Joi.any().strip(), + reference: Joi.string().valid(_.values(MILESTONE_TEMPLATE_REFERENCES)).required(), + referenceId: Joi.number().integer().positive().required(), + metadata: Joi.object().required(), hidden: Joi.boolean().optional(), createdAt: Joi.any().strip(), updatedAt: Joi.any().strip(), @@ -41,39 +42,28 @@ const schema = { module.exports = [ validate(schema), + validateMilestoneTemplate.validateRequestBody, permissions('milestoneTemplate.create'), (req, res, next) => { const entity = _.assign(req.body.param, { createdBy: req.authUser.userId, updatedBy: req.authUser.userId, - productTemplateId: req.params.productTemplateId, }); let result; return models.sequelize.transaction(tx => - // Find the product template - models.ProductTemplate.findById(req.params.productTemplateId, { transaction: tx }) - .then((productTemplate) => { - // Not found - if (!productTemplate) { - const apiErr = new Error( - `Product template not found for product template id ${req.params.productTemplateId}`); - apiErr.status = 404; - return Promise.reject(apiErr); - } - - // Create the milestone template - return models.ProductMilestoneTemplate.create(entity, { transaction: tx }); - }) + // Create the milestone template + models.MilestoneTemplate.create(entity, { transaction: tx }) .then((createdEntity) => { // Omit deletedAt and deletedBy result = _.omit(createdEntity.toJSON(), 'deletedAt', 'deletedBy'); - // Increase the order of the other milestone templates in the same product template, + // Increase the order of the other milestone templates in the same referenceId, // which have `order` >= this milestone template order - return models.ProductMilestoneTemplate.update({ order: Sequelize.literal('"order" + 1') }, { + return models.MilestoneTemplate.update({ order: Sequelize.literal('"order" + 1') }, { where: { - productTemplateId: req.params.productTemplateId, + reference: result.reference, + referenceId: result.referenceId, id: { $ne: result.id }, order: { $gte: result.order }, }, diff --git a/src/routes/milestoneTemplates/create.spec.js b/src/routes/milestoneTemplates/create.spec.js index c821a5fe..00dad710 100644 --- a/src/routes/milestoneTemplates/create.spec.js +++ b/src/routes/milestoneTemplates/create.spec.js @@ -64,7 +64,9 @@ const milestoneTemplates = [ duration: 3, type: 'type1', order: 1, - productTemplateId: 1, + reference: 'productTemplate', + referenceId: 1, + metadata: {}, plannedText: 'text to be shown in planned stage', blockedText: 'text to be shown in blocked stage', activeText: 'text to be shown in active stage', @@ -81,7 +83,9 @@ const milestoneTemplates = [ blockedText: 'text to be shown in blocked stage - 2', activeText: 'text to be shown in active stage - 2', completedText: 'text to be shown in completed stage - 2', - productTemplateId: 1, + reference: 'productTemplate', + referenceId: 1, + metadata: {}, createdBy: 2, updatedBy: 3, }, @@ -90,11 +94,11 @@ const milestoneTemplates = [ describe('CREATE milestone template', () => { beforeEach(() => testUtil.clearDb() .then(() => models.ProductTemplate.bulkCreate(productTemplates)) - .then(() => models.ProductMilestoneTemplate.bulkCreate(milestoneTemplates)), + .then(() => models.MilestoneTemplate.bulkCreate(milestoneTemplates)), ); after(testUtil.clearDb); - describe('POST /productTemplates/{productTemplateId}/milestones', () => { + describe('POST /timelines/metadata/milestoneTemplates', () => { const body = { param: { name: 'milestoneTemplate 3', @@ -107,19 +111,22 @@ describe('CREATE milestone template', () => { activeText: 'text to be shown in active stage - 3', completedText: 'text to be shown in completed stage - 3', hidden: true, + reference: 'productTemplate', + referenceId: 1, + metadata: {}, }, }; it('should return 403 if user is not authenticated', (done) => { request(server) - .post('/v4/productTemplates/1/milestones') + .post('/v4/timelines/metadata/milestoneTemplates') .send(body) .expect(403, done); }); it('should return 403 for member', (done) => { request(server) - .post('/v4/productTemplates/1/milestones') + .post('/v4/timelines/metadata/milestoneTemplates') .set({ Authorization: `Bearer ${testUtil.jwts.member}`, }) @@ -129,7 +136,7 @@ describe('CREATE milestone template', () => { it('should return 403 for copilot', (done) => { request(server) - .post('/v4/productTemplates/1/milestones') + .post('/v4/timelines/metadata/milestoneTemplates') .set({ Authorization: `Bearer ${testUtil.jwts.copilot}`, }) @@ -139,7 +146,7 @@ describe('CREATE milestone template', () => { it('should return 403 for manager', (done) => { request(server) - .post('/v4/productTemplates/1/milestones') + .post('/v4/timelines/metadata/milestoneTemplates') .set({ Authorization: `Bearer ${testUtil.jwts.manager}`, }) @@ -147,14 +154,18 @@ describe('CREATE milestone template', () => { .expect(403, done); }); - it('should return 404 for non-existed product template', (done) => { + it('should return 422 for non-existed product template', (done) => { + const invalidBody = { + param: _.assign({}, body.param, { referenceId: 1000 }), + }; + request(server) - .post('/v4/productTemplates/1000/milestones') + .post('/v4/timelines/metadata/milestoneTemplates') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) - .send(body) - .expect(404, done); + .send(invalidBody) + .expect(422, done); }); it('should return 422 if missing name', (done) => { @@ -165,7 +176,7 @@ describe('CREATE milestone template', () => { }; request(server) - .post('/v4/productTemplates/1/milestones') + .post('/v4/timelines/metadata/milestoneTemplates') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -182,7 +193,7 @@ describe('CREATE milestone template', () => { }; request(server) - .post('/v4/productTemplates/1/milestones') + .post('/v4/timelines/metadata/milestoneTemplates') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -199,7 +210,7 @@ describe('CREATE milestone template', () => { }; request(server) - .post('/v4/productTemplates/1/milestones') + .post('/v4/timelines/metadata/milestoneTemplates') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -216,7 +227,7 @@ describe('CREATE milestone template', () => { }; request(server) - .post('/v4/productTemplates/1/milestones') + .post('/v4/timelines/metadata/milestoneTemplates') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -227,7 +238,7 @@ describe('CREATE milestone template', () => { it('should return 201 for admin', (done) => { request(server) - .post('/v4/productTemplates/1/milestones') + .post('/v4/timelines/metadata/milestoneTemplates') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -246,6 +257,9 @@ describe('CREATE milestone template', () => { resJson.blockedText.should.be.eql(body.param.blockedText); resJson.activeText.should.be.eql(body.param.activeText); resJson.completedText.should.be.eql(body.param.completedText); + resJson.reference.should.be.eql(body.param.reference); + resJson.referenceId.should.be.eql(body.param.referenceId); + resJson.metadata.should.be.eql(body.param.metadata); resJson.createdBy.should.be.eql(40051333); // admin should.exist(resJson.createdAt); @@ -255,9 +269,10 @@ describe('CREATE milestone template', () => { should.not.exist(resJson.deletedAt); // Verify 'order' of the other milestones - models.ProductMilestoneTemplate.findAll({ + models.MilestoneTemplate.findAll({ where: { - productTemplateId: 1, + reference: body.param.reference, + referenceId: body.param.referenceId, }, }).then((milestones) => { _.each(milestones, (milestone) => { @@ -278,7 +293,7 @@ describe('CREATE milestone template', () => { const minimalBody = _.cloneDeep(body); delete minimalBody.param.hidden; request(server) - .post('/v4/productTemplates/1/milestones') + .post('/v4/timelines/metadata/milestoneTemplates') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -294,7 +309,7 @@ describe('CREATE milestone template', () => { it('should return 201 for connect admin', (done) => { request(server) - .post('/v4/productTemplates/1/milestones') + .post('/v4/timelines/metadata/milestoneTemplates') .set({ Authorization: `Bearer ${testUtil.jwts.connectAdmin}`, }) diff --git a/src/routes/milestoneTemplates/delete.js b/src/routes/milestoneTemplates/delete.js index 43d3fd57..5cd0454b 100644 --- a/src/routes/milestoneTemplates/delete.js +++ b/src/routes/milestoneTemplates/delete.js @@ -5,44 +5,27 @@ import validate from 'express-validation'; import Joi from 'joi'; import { middleware as tcMiddleware } from 'tc-core-library-js'; import models from '../../models'; +import validateMilestoneTemplate from '../../middlewares/validateMilestoneTemplate'; const permissions = tcMiddleware.permissions; const schema = { params: { - productTemplateId: Joi.number().integer().positive().required(), milestoneTemplateId: Joi.number().integer().positive().required(), }, }; module.exports = [ validate(schema), + validateMilestoneTemplate.validateIdParam, permissions('milestoneTemplate.delete'), - (req, res, next) => { - const where = { - id: req.params.milestoneTemplateId, - deletedAt: { $eq: null }, - productTemplateId: req.params.productTemplateId, - }; - - return models.sequelize.transaction(() => + (req, res, next) => models.sequelize.transaction(() => // soft delete the record - models.ProductMilestoneTemplate.findOne({ - where, - }).then((existing) => { - if (!existing) { - // handle 404 - const err = new Error( - `Milestone template not found for milestone template id ${req.params.milestoneTemplateId}`); - err.status = 404; - return Promise.reject(err); - } - return existing.update({ deletedBy: req.authUser.userId }); + req.milestoneTemplate.update({ deletedBy: req.authUser.userId }) + .then(entity => entity.destroy()), + ) + .then(() => { + res.status(204).end(); }) - .then(entity => entity.destroy())) - .then(() => { - res.status(204).end(); - }) - .catch(next); - }, + .catch(next), ]; diff --git a/src/routes/milestoneTemplates/delete.spec.js b/src/routes/milestoneTemplates/delete.spec.js index 63091b36..0d0d5527 100644 --- a/src/routes/milestoneTemplates/delete.spec.js +++ b/src/routes/milestoneTemplates/delete.spec.js @@ -8,31 +8,32 @@ import models from '../../models'; import server from '../../app'; import testUtil from '../../tests/util'; -const expectAfterDelete = (productTemplateId, id, err, next) => { +const expectAfterDelete = (id, err, next) => { if (err) throw err; - setTimeout(() => - models.ProductMilestoneTemplate.findOne({ - where: { - id, - productTemplateId, - }, - paranoid: false, - }) - .then((res) => { - if (!res) { - throw new Error('Should found the entity'); - } else { - chai.assert.isNotNull(res.deletedAt); - chai.assert.isNotNull(res.deletedBy); + setTimeout(() => { + models.MilestoneTemplate.findOne({ + where: { + id, + }, + paranoid: false, + }) + .then((res) => { + server.logger.error(`res = ${res}`); + if (!res) { + throw new Error('Should found the entity'); + } else { + chai.assert.isNotNull(res.deletedAt); + chai.assert.isNotNull(res.deletedBy); - request(server) - .get(`/v4/productTemplates/${productTemplateId}/milestones/${id}`) - .set({ - Authorization: `Bearer ${testUtil.jwts.admin}`, - }) - .expect(404, next); - } - }), 500); + request(server) + .get(`/v4/timelines/metadata/milestoneTemplates/${id}`) + .set({ + Authorization: `Bearer ${testUtil.jwts.admin}`, + }) + .expect(404, next); + } + }); + }, 500); }; const productTemplates = [ { @@ -93,7 +94,9 @@ const milestoneTemplates = [ blockedText: 'text to be shown in blocked stage', activeText: 'text to be shown in active stage', completedText: 'text to be shown in completed stage', - productTemplateId: 1, + reference: 'productTemplate', + referenceId: 1, + metadata: {}, createdBy: 1, updatedBy: 2, }, @@ -107,7 +110,9 @@ const milestoneTemplates = [ blockedText: 'text to be shown in blocked stage - 2', activeText: 'text to be shown in active stage - 2', completedText: 'text to be shown in completed stage - 2', - productTemplateId: 1, + reference: 'productTemplate', + referenceId: 1, + metadata: {}, createdBy: 2, updatedBy: 3, deletedAt: new Date(), @@ -117,20 +122,20 @@ const milestoneTemplates = [ describe('DELETE milestone template', () => { beforeEach(() => testUtil.clearDb() .then(() => models.ProductTemplate.bulkCreate(productTemplates)) - .then(() => models.ProductMilestoneTemplate.bulkCreate(milestoneTemplates)), + .then(() => models.MilestoneTemplate.bulkCreate(milestoneTemplates)), ); after(testUtil.clearDb); - describe('DELETE /productTemplates/{productTemplateId}/milestones/{milestoneTemplateId}', () => { + describe('DELETE /timelines/metadata/milestoneTemplates/{milestoneTemplateId}', () => { it('should return 403 if user is not authenticated', (done) => { request(server) - .delete('/v4/productTemplates/1/milestones/1') + .delete('/v4/timelines/metadata/milestoneTemplates/1') .expect(403, done); }); it('should return 403 for member', (done) => { request(server) - .delete('/v4/productTemplates/1/milestones/1') + .delete('/v4/timelines/metadata/milestoneTemplates/1') .set({ Authorization: `Bearer ${testUtil.jwts.member}`, }) @@ -139,7 +144,7 @@ describe('DELETE milestone template', () => { it('should return 403 for copilot', (done) => { request(server) - .delete('/v4/productTemplates/1/milestones/1') + .delete('/v4/timelines/metadata/milestoneTemplates/1') .set({ Authorization: `Bearer ${testUtil.jwts.copilot}`, }) @@ -148,25 +153,16 @@ describe('DELETE milestone template', () => { it('should return 403 for manager', (done) => { request(server) - .delete('/v4/productTemplates/1/milestones/1') + .delete('/v4/timelines/metadata/milestoneTemplates/1') .set({ Authorization: `Bearer ${testUtil.jwts.manager}`, }) .expect(403, done); }); - it('should return 404 for non-existed product template', (done) => { - request(server) - .delete('/v4/productTemplates/1234/milestones/1') - .set({ - Authorization: `Bearer ${testUtil.jwts.admin}`, - }) - .expect(404, done); - }); - it('should return 404 for non-existed milestone template', (done) => { request(server) - .delete('/v4/productTemplates/1/milestones/444') + .delete('/v4/timelines/metadata/milestoneTemplates/444') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -175,25 +171,16 @@ describe('DELETE milestone template', () => { it('should return 404 for deleted milestone template', (done) => { request(server) - .delete('/v4/productTemplates/1/milestones/2') + .delete('/v4/timelines/metadata/milestoneTemplates/2') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) .expect(404, done); }); - it('should return 422 for invalid productTemplateId param', (done) => { - request(server) - .delete('/v4/productTemplates/0/milestones/2') - .set({ - Authorization: `Bearer ${testUtil.jwts.admin}`, - }) - .expect(422, done); - }); - it('should return 422 for invalid milestoneTemplateId param', (done) => { request(server) - .delete('/v4/productTemplates/1/milestones/0') + .delete('/v4/timelines/metadata/milestoneTemplates/0') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -202,22 +189,22 @@ describe('DELETE milestone template', () => { it('should return 204, for admin, if template was successfully removed', (done) => { request(server) - .delete('/v4/productTemplates/1/milestones/1') + .delete('/v4/timelines/metadata/milestoneTemplates/1') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) .expect(204) - .end(err => expectAfterDelete(1, 1, err, done)); + .end(err => expectAfterDelete(1, err, done)); }); it('should return 204, for connect admin, if template was successfully removed', (done) => { request(server) - .delete('/v4/productTemplates/1/milestones/1') + .delete('/v4/timelines/metadata/milestoneTemplates/1') .set({ Authorization: `Bearer ${testUtil.jwts.connectAdmin}`, }) .expect(204) - .end(err => expectAfterDelete(1, 1, err, done)); + .end(err => expectAfterDelete(1, err, done)); }); }); }); diff --git a/src/routes/milestoneTemplates/get.js b/src/routes/milestoneTemplates/get.js index 1c1fa3f0..1f6cd2f7 100644 --- a/src/routes/milestoneTemplates/get.js +++ b/src/routes/milestoneTemplates/get.js @@ -3,41 +3,22 @@ */ import validate from 'express-validation'; import Joi from 'joi'; +import _ from 'lodash'; import { middleware as tcMiddleware } from 'tc-core-library-js'; import util from '../../util'; -import models from '../../models'; +import validateMilestoneTemplate from '../../middlewares/validateMilestoneTemplate'; const permissions = tcMiddleware.permissions; const schema = { params: { - productTemplateId: Joi.number().integer().positive().required(), milestoneTemplateId: Joi.number().integer().positive().required(), }, }; module.exports = [ validate(schema), + validateMilestoneTemplate.validateIdParam, permissions('milestoneTemplate.view'), - (req, res, next) => models.ProductMilestoneTemplate.findOne({ - where: { - id: req.params.milestoneTemplateId, - productTemplateId: req.params.productTemplateId, - }, - attributes: { exclude: ['deletedAt', 'deletedBy'] }, - raw: true, - }) - .then((milestoneTemplate) => { - // Not found - if (!milestoneTemplate) { - const apiErr = new Error( - `Milestone template not found for milestone template id ${req.params.milestoneTemplateId}`); - apiErr.status = 404; - return Promise.reject(apiErr); - } - - res.json(util.wrapResponse(req.id, milestoneTemplate)); - return Promise.resolve(); - }) - .catch(next), + (req, res) => res.json(util.wrapResponse(req.id, _.omit(req.milestoneTemplate.toJSON(), 'deletedAt', 'deletedBy'))), ]; diff --git a/src/routes/milestoneTemplates/get.spec.js b/src/routes/milestoneTemplates/get.spec.js index 958a30a6..58ce6a5a 100644 --- a/src/routes/milestoneTemplates/get.spec.js +++ b/src/routes/milestoneTemplates/get.spec.js @@ -69,7 +69,9 @@ const milestoneTemplates = [ blockedText: 'text to be shown in blocked stage', activeText: 'text to be shown in active stage', completedText: 'text to be shown in completed stage', - productTemplateId: 1, + reference: 'productTemplate', + referenceId: 1, + metadata: {}, createdBy: 1, updatedBy: 2, }, @@ -83,7 +85,9 @@ const milestoneTemplates = [ blockedText: 'text to be shown in blocked stage - 2', activeText: 'text to be shown in active stage - 2', completedText: 'text to be shown in completed stage - 2', - productTemplateId: 1, + reference: 'productTemplate', + referenceId: 1, + metadata: {}, createdBy: 2, updatedBy: 3, deletedAt: new Date(), @@ -93,29 +97,20 @@ const milestoneTemplates = [ describe('GET milestone template', () => { beforeEach(() => testUtil.clearDb() .then(() => models.ProductTemplate.bulkCreate(productTemplates)) - .then(() => models.ProductMilestoneTemplate.bulkCreate(milestoneTemplates)), + .then(() => models.MilestoneTemplate.bulkCreate(milestoneTemplates)), ); after(testUtil.clearDb); - describe('GET /productTemplates/{productTemplateId}/milestones/{milestoneTemplateId}', () => { + describe('GET /timelines/metadata/milestoneTemplates/{milestoneTemplateId}', () => { it('should return 403 if user is not authenticated', (done) => { request(server) - .get('/v4/productTemplates/1/milestones/1') + .get('/v4/timelines/metadata/milestoneTemplates/1') .expect(403, done); }); - it('should return 404 for non-existed product template', (done) => { - request(server) - .get('/v4/productTemplates/1234/milestones/1') - .set({ - Authorization: `Bearer ${testUtil.jwts.admin}`, - }) - .expect(404, done); - }); - it('should return 404 for non-existed milestone template', (done) => { request(server) - .get('/v4/productTemplates/1/milestones/1111') + .get('/v4/timelines/metadata/milestoneTemplates/1111') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -124,7 +119,7 @@ describe('GET milestone template', () => { it('should return 404 for deleted milestone template', (done) => { request(server) - .get('/v4/productTemplates/1/milestones/2') + .get('/v4/timelines/metadata/milestoneTemplates/2') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -133,7 +128,7 @@ describe('GET milestone template', () => { it('should return 200 for admin', (done) => { request(server) - .get('/v4/productTemplates/1/milestones/1') + .get('/v4/timelines/metadata/milestoneTemplates/1') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -149,7 +144,9 @@ describe('GET milestone template', () => { resJson.blockedText.should.be.eql(milestoneTemplates[0].blockedText); resJson.activeText.should.be.eql(milestoneTemplates[0].activeText); resJson.completedText.should.be.eql(milestoneTemplates[0].completedText); - resJson.productTemplateId.should.be.eql(milestoneTemplates[0].productTemplateId); + resJson.reference.should.be.eql(milestoneTemplates[0].reference); + resJson.referenceId.should.be.eql(milestoneTemplates[0].referenceId); + resJson.metadata.should.be.eql(milestoneTemplates[0].metadata); resJson.createdBy.should.be.eql(milestoneTemplates[0].createdBy); should.exist(resJson.createdAt); @@ -164,7 +161,7 @@ describe('GET milestone template', () => { it('should return 200 for connect admin', (done) => { request(server) - .get('/v4/productTemplates/1/milestones/1') + .get('/v4/timelines/metadata/milestoneTemplates/1') .set({ Authorization: `Bearer ${testUtil.jwts.connectAdmin}`, }) @@ -174,7 +171,7 @@ describe('GET milestone template', () => { it('should return 200 for connect manager', (done) => { request(server) - .get('/v4/productTemplates/1/milestones/1') + .get('/v4/timelines/metadata/milestoneTemplates/1') .set({ Authorization: `Bearer ${testUtil.jwts.manager}`, }) @@ -184,7 +181,7 @@ describe('GET milestone template', () => { it('should return 200 for member', (done) => { request(server) - .get('/v4/productTemplates/1/milestones/1') + .get('/v4/timelines/metadata/milestoneTemplates/1') .set({ Authorization: `Bearer ${testUtil.jwts.member}`, }) @@ -193,7 +190,7 @@ describe('GET milestone template', () => { it('should return 200 for copilot', (done) => { request(server) - .get('/v4/productTemplates/1/milestones/1') + .get('/v4/timelines/metadata/milestoneTemplates/1') .set({ Authorization: `Bearer ${testUtil.jwts.copilot}`, }) diff --git a/src/routes/milestoneTemplates/list.js b/src/routes/milestoneTemplates/list.js index 40b6ae19..64d93acf 100644 --- a/src/routes/milestoneTemplates/list.js +++ b/src/routes/milestoneTemplates/list.js @@ -1,23 +1,16 @@ /** * API to list all milestone templates */ -import validate from 'express-validation'; -import Joi from 'joi'; import _ from 'lodash'; import { middleware as tcMiddleware } from 'tc-core-library-js'; import util from '../../util'; import models from '../../models'; +import validateMilestoneTemplate from '../../middlewares/validateMilestoneTemplate'; const permissions = tcMiddleware.permissions; -const schema = { - params: { - productTemplateId: Joi.number().integer().positive().required(), - }, -}; - module.exports = [ - validate(schema), + validateMilestoneTemplate.validateQueryFilter, permissions('milestoneTemplate.view'), (req, res, next) => { // Parse the sort query @@ -36,10 +29,9 @@ module.exports = [ const sortColumnAndOrder = sort.split(' '); // Get all milestone templates - return models.ProductMilestoneTemplate.findAll({ - where: { - productTemplateId: req.params.productTemplateId, - }, + const where = req.params.filter || {}; + return models.MilestoneTemplate.findAll({ + where, order: [sortColumnAndOrder], attributes: { exclude: ['deletedAt', 'deletedBy'] }, raw: true, diff --git a/src/routes/milestoneTemplates/list.spec.js b/src/routes/milestoneTemplates/list.spec.js index 086356c3..2ee2f25f 100644 --- a/src/routes/milestoneTemplates/list.spec.js +++ b/src/routes/milestoneTemplates/list.spec.js @@ -69,7 +69,9 @@ const milestoneTemplates = [ blockedText: 'text to be shown in blocked stage', activeText: 'text to be shown in active stage', completedText: 'text to be shown in completed stage', - productTemplateId: 1, + reference: 'productTemplate', + referenceId: 1, + metadata: {}, createdBy: 1, updatedBy: 2, }, @@ -83,7 +85,9 @@ const milestoneTemplates = [ blockedText: 'text to be shown in blocked stage - 2', activeText: 'text to be shown in active stage - 2', completedText: 'text to be shown in completed stage - 2', - productTemplateId: 1, + reference: 'productTemplate', + referenceId: 1, + metadata: {}, createdBy: 2, updatedBy: 3, }, @@ -97,7 +101,9 @@ const milestoneTemplates = [ blockedText: 'text to be shown in blocked stage - 3', activeText: 'text to be shown in active stage - 3', completedText: 'text to be shown in completed stage - 3', - productTemplateId: 1, + reference: 'productTemplate', + referenceId: 1, + metadata: {}, createdBy: 2, updatedBy: 3, deletedAt: new Date(), @@ -107,29 +113,20 @@ const milestoneTemplates = [ describe('LIST milestone template', () => { beforeEach(() => testUtil.clearDb() .then(() => models.ProductTemplate.bulkCreate(productTemplates)) - .then(() => models.ProductMilestoneTemplate.bulkCreate(milestoneTemplates)), + .then(() => models.MilestoneTemplate.bulkCreate(milestoneTemplates)), ); after(testUtil.clearDb); - describe('GET /productTemplates/{productTemplateId}/milestones', () => { + describe('GET /timelines/metadata/milestoneTemplates', () => { it('should return 403 if user is not authenticated', (done) => { request(server) - .get('/v4/productTemplates/1/milestones') + .get('/v4/timelines/metadata/milestoneTemplates') .expect(403, done); }); - it('should return 422 for invalid productTemplateId param', (done) => { - request(server) - .get('/v4/productTemplates/0/milestones') - .set({ - Authorization: `Bearer ${testUtil.jwts.admin}`, - }) - .expect(422, done); - }); - it('should return 422 for invalid sort column', (done) => { request(server) - .get('/v4/productTemplates/1/milestones?sort=id') + .get('/v4/timelines/metadata/milestoneTemplates?sort=id') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -138,7 +135,7 @@ describe('LIST milestone template', () => { it('should return 422 for invalid sort order', (done) => { request(server) - .get('/v4/productTemplates/1/milestones?sort=order%20invalid') + .get('/v4/timelines/metadata/milestoneTemplates?sort=order%20invalid') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -147,7 +144,7 @@ describe('LIST milestone template', () => { it('should return 200 for admin', (done) => { request(server) - .get('/v4/productTemplates/1/milestones') + .get('/v4/timelines/metadata/milestoneTemplates') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -164,7 +161,9 @@ describe('LIST milestone template', () => { resJson[0].blockedText.should.be.eql(milestoneTemplates[0].blockedText); resJson[0].activeText.should.be.eql(milestoneTemplates[0].activeText); resJson[0].completedText.should.be.eql(milestoneTemplates[0].completedText); - resJson[0].productTemplateId.should.be.eql(milestoneTemplates[0].productTemplateId); + resJson[0].reference.should.be.eql(milestoneTemplates[0].reference); + resJson[0].referenceId.should.be.eql(milestoneTemplates[0].referenceId); + resJson[0].metadata.should.be.eql(milestoneTemplates[0].metadata); resJson[0].createdBy.should.be.eql(milestoneTemplates[0].createdBy); should.exist(resJson[0].createdAt); @@ -177,9 +176,9 @@ describe('LIST milestone template', () => { }); }); - it('should return 200 for connect admin', (done) => { + it('should return 200 for connect admin with filter', (done) => { request(server) - .get('/v4/productTemplates/1/milestones') + .get('/v4/timelines/metadata/milestoneTemplates?filter=reference%3DproductTemplate%26referenceId%3D1') .set({ Authorization: `Bearer ${testUtil.jwts.connectAdmin}`, }) @@ -189,7 +188,7 @@ describe('LIST milestone template', () => { it('should return 200 for connect manager', (done) => { request(server) - .get('/v4/productTemplates/1/milestones') + .get('/v4/timelines/metadata/milestoneTemplates') .set({ Authorization: `Bearer ${testUtil.jwts.manager}`, }) @@ -199,7 +198,7 @@ describe('LIST milestone template', () => { it('should return 200 for member', (done) => { request(server) - .get('/v4/productTemplates/1/milestones') + .get('/v4/timelines/metadata/milestoneTemplates') .set({ Authorization: `Bearer ${testUtil.jwts.member}`, }) @@ -208,7 +207,7 @@ describe('LIST milestone template', () => { it('should return 200 for copilot', (done) => { request(server) - .get('/v4/productTemplates/1/milestones') + .get('/v4/timelines/metadata/milestoneTemplates') .set({ Authorization: `Bearer ${testUtil.jwts.copilot}`, }) @@ -217,7 +216,7 @@ describe('LIST milestone template', () => { it('should return 200 with sort desc', (done) => { request(server) - .get('/v4/productTemplates/1/milestones?sort=order%20desc') + .get('/v4/timelines/metadata/milestoneTemplates?sort=order%20desc') .set({ Authorization: `Bearer ${testUtil.jwts.copilot}`, }) diff --git a/src/routes/milestoneTemplates/update.js b/src/routes/milestoneTemplates/update.js index 8936b72c..c9ce67e4 100644 --- a/src/routes/milestoneTemplates/update.js +++ b/src/routes/milestoneTemplates/update.js @@ -8,12 +8,13 @@ import Sequelize from 'sequelize'; import { middleware as tcMiddleware } from 'tc-core-library-js'; import util from '../../util'; import models from '../../models'; +import validateMilestoneTemplate from '../../middlewares/validateMilestoneTemplate'; +import { MILESTONE_TEMPLATE_REFERENCES } from '../../constants'; const permissions = tcMiddleware.permissions; const schema = { params: { - productTemplateId: Joi.number().integer().positive().required(), milestoneTemplateId: Joi.number().integer().positive().required(), }, body: { @@ -30,6 +31,9 @@ const schema = { blockedText: Joi.string().max(512).optional(), productTemplateId: Joi.any().strip(), hidden: Joi.boolean().optional(), + reference: Joi.string().valid(_.values(MILESTONE_TEMPLATE_REFERENCES)).required(), + referenceId: Joi.number().integer().positive().required(), + metadata: Joi.object().optional(), createdAt: Joi.any().strip(), updatedAt: Joi.any().strip(), deletedAt: Joi.any().strip(), @@ -42,37 +46,23 @@ const schema = { module.exports = [ validate(schema), + validateMilestoneTemplate.validateIdParam, + validateMilestoneTemplate.validateRequestBody, permissions('milestoneTemplate.edit'), (req, res, next) => { const entityToUpdate = _.assign(req.body.param, { updatedBy: req.authUser.userId, }); - let original; + const original = _.omit(req.milestoneTemplate.toJSON(), 'deletedAt', 'deletedBy'); let updated; - return models.sequelize.transaction(() => - // Get the milestone template - models.ProductMilestoneTemplate.findOne({ - where: { - id: req.params.milestoneTemplateId, - productTemplateId: req.params.productTemplateId, - }, - attributes: { exclude: ['deletedAt', 'deletedBy'] }, - }) - .then((milestoneTemplate) => { - // Not found - if (!milestoneTemplate) { - const apiErr = new Error(`Milestone template not found for template id ${req.params.milestoneTemplateId}`); - apiErr.status = 404; - return Promise.reject(apiErr); - } + // Merge JSON field + entityToUpdate.metadata = util.mergeJsonObjects(original.metadata, entityToUpdate.metadata || {}); - original = _.omit(milestoneTemplate.toJSON(), ['deletedAt', 'deletedBy']); - - // Update - return milestoneTemplate.update(entityToUpdate); - }) + return models.sequelize.transaction(() => + // Update + req.milestoneTemplate.update(entityToUpdate) .then((milestoneTemplate) => { updated = _.omit(milestoneTemplate.toJSON(), ['deletedAt', 'deletedBy']); @@ -81,9 +71,10 @@ module.exports = [ return Promise.resolve(); } - return models.ProductMilestoneTemplate.count({ + return models.MilestoneTemplate.count({ where: { - productTemplateId: updated.productTemplateId, + reference: updated.reference, + referenceId: updated.referenceId, id: { $ne: updated.id }, order: updated.order, }, @@ -96,9 +87,10 @@ module.exports = [ // Increase the order from M to K: if there is an item with order K, // orders from M+1 to K should be made M to K-1 if (original.order < updated.order) { - return models.ProductMilestoneTemplate.update({ order: Sequelize.literal('"order" - 1') }, { + return models.MilestoneTemplate.update({ order: Sequelize.literal('"order" - 1') }, { where: { - productTemplateId: updated.productTemplateId, + reference: updated.reference, + referenceId: updated.referenceId, id: { $ne: updated.id }, order: { $between: [original.order + 1, updated.order] }, }, @@ -107,9 +99,10 @@ module.exports = [ // Decrease the order from M to K: if there is an item with order K, // orders from K to M-1 should be made K+1 to M - return models.ProductMilestoneTemplate.update({ order: Sequelize.literal('"order" + 1') }, { + return models.MilestoneTemplate.update({ order: Sequelize.literal('"order" + 1') }, { where: { - productTemplateId: updated.productTemplateId, + reference: updated.reference, + referenceId: updated.referenceId, id: { $ne: updated.id }, order: { $between: [updated.order, original.order - 1] }, }, @@ -117,10 +110,10 @@ module.exports = [ }); }), ) - .then(() => { - res.json(util.wrapResponse(req.id, updated)); - return Promise.resolve(); - }) - .catch(next); + .then(() => { + res.json(util.wrapResponse(req.id, updated)); + return Promise.resolve(); + }) + .catch(next); }, ]; diff --git a/src/routes/milestoneTemplates/update.spec.js b/src/routes/milestoneTemplates/update.spec.js index 59bbcb00..68be6f31 100644 --- a/src/routes/milestoneTemplates/update.spec.js +++ b/src/routes/milestoneTemplates/update.spec.js @@ -69,7 +69,9 @@ const milestoneTemplates = [ blockedText: 'text to be shown in blocked stage', activeText: 'text to be shown in active stage', completedText: 'text to be shown in completed stage', - productTemplateId: 1, + reference: 'productTemplate', + referenceId: 1, + metadata: {}, createdBy: 1, updatedBy: 2, }, @@ -83,7 +85,9 @@ const milestoneTemplates = [ blockedText: 'text to be shown in blocked stage - 2', activeText: 'text to be shown in active stage - 2', completedText: 'text to be shown in completed stage - 2', - productTemplateId: 1, + reference: 'productTemplate', + referenceId: 1, + metadata: {}, createdBy: 2, updatedBy: 3, }, @@ -97,7 +101,9 @@ const milestoneTemplates = [ blockedText: 'text to be shown in blocked stage - 3', activeText: 'text to be shown in active stage - 3', completedText: 'text to be shown in completed stage - 3', - productTemplateId: 1, + reference: 'productTemplate', + referenceId: 1, + metadata: {}, createdBy: 2, updatedBy: 3, }, @@ -111,21 +117,54 @@ const milestoneTemplates = [ blockedText: 'text to be shown in blocked stage - 4', activeText: 'text to be shown in active stage - 4', completedText: 'text to be shown in completed stage - 4', - productTemplateId: 1, + reference: 'productTemplate', + referenceId: 1, + metadata: {}, createdBy: 2, updatedBy: 3, deletedAt: new Date(), }, + { + id: 5, + name: 'milestoneTemplate 5', + duration: 5, + type: 'type5', + order: 5, + plannedText: 'text to be shown in planned stage - 5', + blockedText: 'text to be shown in blocked stage - 5', + activeText: 'text to be shown in active stage - 5', + completedText: 'text to be shown in completed stage - 5', + reference: 'productTemplate', + referenceId: 1, + metadata: { + metadata1: { + name: 'metadata 1', + details: { + anyDetails: 'any details 1', + }, + others: ['others 11', 'others 12'], + }, + metadata2: { + name: 'metadata 2', + details: { + anyDetails: 'any details 2', + }, + others: ['others 21', 'others 22'], + }, + }, + createdBy: 2, + updatedBy: 3, + }, ]; describe('UPDATE milestone template', () => { beforeEach(() => testUtil.clearDb() .then(() => models.ProductTemplate.bulkCreate(productTemplates)) - .then(() => models.ProductMilestoneTemplate.bulkCreate(milestoneTemplates)), + .then(() => models.MilestoneTemplate.bulkCreate(milestoneTemplates)), ); after(testUtil.clearDb); - describe('PATCH /productTemplates/{productTemplateId}/milestones/{milestoneTemplateId}', () => { + describe('PATCH /timelines/metadata/milestoneTemplates/{milestoneTemplateId}', () => { const body = { param: { name: 'milestoneTemplate 1-updated', @@ -138,19 +177,22 @@ describe('UPDATE milestone template', () => { activeText: 'text to be shown in active stage', completedText: 'text to be shown in completed stage', hidden: true, + reference: 'productTemplate', + referenceId: 1, + metadata: {}, }, }; it('should return 403 if user is not authenticated', (done) => { request(server) - .patch('/v4/productTemplates/1/milestones/1') + .patch('/v4/timelines/metadata/milestoneTemplates/1') .send(body) .expect(403, done); }); it('should return 403 for member', (done) => { request(server) - .patch('/v4/productTemplates/1/milestones/1') + .patch('/v4/timelines/metadata/milestoneTemplates/1') .set({ Authorization: `Bearer ${testUtil.jwts.member}`, }) @@ -160,7 +202,7 @@ describe('UPDATE milestone template', () => { it('should return 403 for copilot', (done) => { request(server) - .patch('/v4/productTemplates/1/milestones/1') + .patch('/v4/timelines/metadata/milestoneTemplates/1') .send(body) .set({ Authorization: `Bearer ${testUtil.jwts.copilot}`, @@ -170,7 +212,7 @@ describe('UPDATE milestone template', () => { it('should return 403 for manager', (done) => { request(server) - .patch('/v4/productTemplates/1/milestones/1') + .patch('/v4/timelines/metadata/milestoneTemplates/1') .send(body) .set({ Authorization: `Bearer ${testUtil.jwts.manager}`, @@ -178,19 +220,9 @@ describe('UPDATE milestone template', () => { .expect(403, done); }); - it('should return 404 for non-existed product template', (done) => { - request(server) - .patch('/v4/productTemplates/122/milestones/1') - .set({ - Authorization: `Bearer ${testUtil.jwts.admin}`, - }) - .send(body) - .expect(404, done); - }); - it('should return 404 for non-existed milestone template', (done) => { request(server) - .patch('/v4/productTemplates/1/milestones/111') + .patch('/v4/timelines/metadata/milestoneTemplates/111') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -200,7 +232,7 @@ describe('UPDATE milestone template', () => { it('should return 404 for deleted milestone template', (done) => { request(server) - .patch('/v4/productTemplates/1/milestones/4') + .patch('/v4/timelines/metadata/milestoneTemplates/4') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -210,7 +242,7 @@ describe('UPDATE milestone template', () => { it('should return 200 for admin', (done) => { request(server) - .patch('/v4/productTemplates/1/milestones/1') + .patch('/v4/timelines/metadata/milestoneTemplates/1') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -228,6 +260,9 @@ describe('UPDATE milestone template', () => { resJson.blockedText.should.be.eql(body.param.blockedText); resJson.activeText.should.be.eql(body.param.activeText); resJson.completedText.should.be.eql(body.param.completedText); + resJson.reference.should.be.eql(body.param.reference); + resJson.referenceId.should.be.eql(body.param.referenceId); + resJson.metadata.should.be.eql(body.param.metadata); should.exist(resJson.createdBy); should.exist(resJson.createdAt); @@ -245,7 +280,7 @@ describe('UPDATE milestone template', () => { this.timeout(10000); request(server) - .patch('/v4/productTemplates/1/milestones/1') + .patch('/v4/timelines/metadata/milestoneTemplates/1') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -255,15 +290,15 @@ describe('UPDATE milestone template', () => { // Milestone 1: order 3 // Milestone 2: order 2 - 1 = 1 // Milestone 3: order 3 - 1 = 2 - models.ProductMilestoneTemplate.findById(1) + models.MilestoneTemplate.findById(1) .then((milestone) => { milestone.order.should.be.eql(3); }) - .then(() => models.ProductMilestoneTemplate.findById(2)) + .then(() => models.MilestoneTemplate.findById(2)) .then((milestone) => { milestone.order.should.be.eql(1); }) - .then(() => models.ProductMilestoneTemplate.findById(3)) + .then(() => models.MilestoneTemplate.findById(3)) .then((milestone) => { milestone.order.should.be.eql(2); @@ -277,7 +312,7 @@ describe('UPDATE milestone template', () => { this.timeout(10000); request(server) - .patch('/v4/productTemplates/1/milestones/1') + .patch('/v4/timelines/metadata/milestoneTemplates/1') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -287,15 +322,15 @@ describe('UPDATE milestone template', () => { // Milestone 1: order 4 // Milestone 2: order 2 // Milestone 3: order 3 - models.ProductMilestoneTemplate.findById(1) + models.MilestoneTemplate.findById(1) .then((milestone) => { milestone.order.should.be.eql(4); }) - .then(() => models.ProductMilestoneTemplate.findById(2)) + .then(() => models.MilestoneTemplate.findById(2)) .then((milestone) => { milestone.order.should.be.eql(2); }) - .then(() => models.ProductMilestoneTemplate.findById(3)) + .then(() => models.MilestoneTemplate.findById(3)) .then((milestone) => { milestone.order.should.be.eql(3); @@ -309,7 +344,7 @@ describe('UPDATE milestone template', () => { this.timeout(10000); request(server) - .patch('/v4/productTemplates/1/milestones/3') + .patch('/v4/timelines/metadata/milestoneTemplates/3') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -319,15 +354,15 @@ describe('UPDATE milestone template', () => { // Milestone 1: order 2 // Milestone 2: order 3 // Milestone 3: order 1 - models.ProductMilestoneTemplate.findById(1) + models.MilestoneTemplate.findById(1) .then((milestone) => { milestone.order.should.be.eql(2); }) - .then(() => models.ProductMilestoneTemplate.findById(2)) + .then(() => models.MilestoneTemplate.findById(2)) .then((milestone) => { milestone.order.should.be.eql(3); }) - .then(() => models.ProductMilestoneTemplate.findById(3)) + .then(() => models.MilestoneTemplate.findById(3)) .then((milestone) => { milestone.order.should.be.eql(1); @@ -341,7 +376,7 @@ describe('UPDATE milestone template', () => { this.timeout(10000); request(server) - .patch('/v4/productTemplates/1/milestones/3') + .patch('/v4/timelines/metadata/milestoneTemplates/3') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -351,15 +386,15 @@ describe('UPDATE milestone template', () => { // Milestone 1: order 1 // Milestone 2: order 2 // Milestone 3: order 0 - models.ProductMilestoneTemplate.findById(1) + models.MilestoneTemplate.findById(1) .then((milestone) => { milestone.order.should.be.eql(1); }) - .then(() => models.ProductMilestoneTemplate.findById(2)) + .then(() => models.MilestoneTemplate.findById(2)) .then((milestone) => { milestone.order.should.be.eql(2); }) - .then(() => models.ProductMilestoneTemplate.findById(3)) + .then(() => models.MilestoneTemplate.findById(3)) .then((milestone) => { milestone.order.should.be.eql(0); @@ -372,7 +407,7 @@ describe('UPDATE milestone template', () => { const partialBody = _.cloneDeep(body); delete partialBody.param.name; request(server) - .patch('/v4/productTemplates/1/milestones/1') + .patch('/v4/timelines/metadata/milestoneTemplates/1') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -384,7 +419,7 @@ describe('UPDATE milestone template', () => { const partialBody = _.cloneDeep(body); delete partialBody.param.type; request(server) - .patch('/v4/productTemplates/1/milestones/1') + .patch('/v4/timelines/metadata/milestoneTemplates/1') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -396,7 +431,7 @@ describe('UPDATE milestone template', () => { const partialBody = _.cloneDeep(body); delete partialBody.param.duration; request(server) - .patch('/v4/productTemplates/1/milestones/1') + .patch('/v4/timelines/metadata/milestoneTemplates/1') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -408,7 +443,7 @@ describe('UPDATE milestone template', () => { const partialBody = _.cloneDeep(body); delete partialBody.param.order; request(server) - .patch('/v4/productTemplates/1/milestones/1') + .patch('/v4/timelines/metadata/milestoneTemplates/1') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -420,7 +455,7 @@ describe('UPDATE milestone template', () => { const partialBody = _.cloneDeep(body); delete partialBody.param.plannedText; request(server) - .patch('/v4/productTemplates/1/milestones/1') + .patch('/v4/timelines/metadata/milestoneTemplates/1') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -432,7 +467,7 @@ describe('UPDATE milestone template', () => { const partialBody = _.cloneDeep(body); delete partialBody.param.blockedText; request(server) - .patch('/v4/productTemplates/1/milestones/1') + .patch('/v4/timelines/metadata/milestoneTemplates/1') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -444,7 +479,7 @@ describe('UPDATE milestone template', () => { const partialBody = _.cloneDeep(body); delete partialBody.param.activeText; request(server) - .patch('/v4/productTemplates/1/milestones/1') + .patch('/v4/timelines/metadata/milestoneTemplates/1') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -456,7 +491,7 @@ describe('UPDATE milestone template', () => { const partialBody = _.cloneDeep(body); delete partialBody.param.completedText; request(server) - .patch('/v4/productTemplates/1/milestones/1') + .patch('/v4/timelines/metadata/milestoneTemplates/1') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -468,7 +503,7 @@ describe('UPDATE milestone template', () => { const partialBody = _.cloneDeep(body); delete partialBody.param.hidden; request(server) - .patch('/v4/productTemplates/1/milestones/1') + .patch('/v4/timelines/metadata/milestoneTemplates/1') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -478,7 +513,7 @@ describe('UPDATE milestone template', () => { it('should return 200 for connect admin', (done) => { request(server) - .patch('/v4/productTemplates/1/milestones/1') + .patch('/v4/timelines/metadata/milestoneTemplates/1') .set({ Authorization: `Bearer ${testUtil.jwts.connectAdmin}`, }) @@ -486,5 +521,78 @@ describe('UPDATE milestone template', () => { .expect(200) .end(done); }); + + it('should return 200 for admin - updating metadata', (done) => { + const bodyWithMetadata = { + param: { + name: 'milestoneTemplate 5-updated', + description: 'description-updated', + duration: 6, + type: 'type5-updated', + order: 5, + plannedText: 'text to be shown in planned stage', + blockedText: 'text to be shown in blocked stage', + activeText: 'text to be shown in active stage', + completedText: 'text to be shown in completed stage', + hidden: true, + reference: 'productTemplate', + referenceId: 1, + metadata: { + metadata1: { + name: 'metadata 1 - update', + details: { + anyDetails: 'any details 1 - update', + newDetails: 'new', + }, + others: ['others new'], + }, + metadata3: { + name: 'metadata 3', + details: { + anyDetails: 'any details 3', + }, + others: ['others 31', 'others 32'], + }, + }, + }, + }; + + request(server) + .patch('/v4/timelines/metadata/milestoneTemplates/5') + .set({ + Authorization: `Bearer ${testUtil.jwts.admin}`, + }) + .send(bodyWithMetadata) + .expect(200) + .end((err, res) => { + const resJson = res.body.result.content; + resJson.metadata.should.be.eql({ + metadata1: { + name: 'metadata 1 - update', + details: { + anyDetails: 'any details 1 - update', + newDetails: 'new', + }, + others: ['others new'], + }, + metadata2: { + name: 'metadata 2', + details: { + anyDetails: 'any details 2', + }, + others: ['others 21', 'others 22'], + }, + metadata3: { + name: 'metadata 3', + details: { + anyDetails: 'any details 3', + }, + others: ['others 31', 'others 32'], + }, + }); + + done(); + }); + }); }); }); diff --git a/src/routes/milestones/create.js b/src/routes/milestones/create.js index e0643d38..eadec1f4 100644 --- a/src/routes/milestones/create.js +++ b/src/routes/milestones/create.js @@ -80,13 +80,6 @@ module.exports = [ // Omit deletedAt, deletedBy result = _.omit(createdEntity.toJSON(), 'deletedAt', 'deletedBy'); - // Send event to bus - req.log.debug('Sending event to RabbitMQ bus for milestone %d', result.id); - req.app.services.pubsub.publish(EVENT.ROUTING_KEY.MILESTONE_ADDED, - result, - { correlationId: req.id }, - ); - // Increase the order of the other milestones in the same timeline, // which have `order` >= this milestone order return models.Milestone.update({ order: Sequelize.literal('"order" + 1') }, { @@ -104,6 +97,16 @@ module.exports = [ // because it will make 'version conflict' error in ES. // The order of the other milestones need to be updated in the MILESTONE_ADDED event handler + // Send event to bus + req.log.debug('Sending event to RabbitMQ bus for milestone %d', result.id); + req.app.services.pubsub.publish(EVENT.ROUTING_KEY.MILESTONE_ADDED, + result, + { correlationId: req.id }, + ); + + req.app.emit(EVENT.ROUTING_KEY.MILESTONE_ADDED, + { req, created: result }); + // Write to the response res.status(201).json(util.wrapResponse(req.id, result, 1, 201)); return Promise.resolve(); diff --git a/src/routes/milestones/update.js b/src/routes/milestones/update.js index 24230354..cbb2f2a3 100644 --- a/src/routes/milestones/update.js +++ b/src/routes/milestones/update.js @@ -284,6 +284,9 @@ module.exports = [ // because it will make 'version conflict' error in ES. // The order of the other milestones need to be updated in the MILESTONE_UPDATED event above + req.app.emit(EVENT.ROUTING_KEY.MILESTONE_UPDATED, + { req, original, updated, cascadedUpdates }); + // Write to response res.json(util.wrapResponse(req.id, updated)); return Promise.resolve(); diff --git a/src/routes/phases/create.js b/src/routes/phases/create.js index 3c5c2f83..b4da22a1 100644 --- a/src/routes/phases/create.js +++ b/src/routes/phases/create.js @@ -1,6 +1,7 @@ import validate from 'express-validation'; import _ from 'lodash'; import Joi from 'joi'; +import Sequelize from 'sequelize'; import models from '../../models'; import util from '../../util'; @@ -21,6 +22,8 @@ const addProjectPhaseValidations = { spentBudget: Joi.number().min(0).optional(), progress: Joi.number().min(0).optional(), details: Joi.any().optional(), + order: Joi.number().integer().optional(), + productTemplateId: Joi.number().integer().positive().optional(), }).required(), }, }; @@ -46,44 +49,93 @@ module.exports = [ req.log.debug('Create Phase - Starting transaction'); return models.Project.findOne({ where: { id: projectId, deletedAt: { $eq: null } }, - }).then((existingProject) => { - if (!existingProject) { - const err = new Error(`active project not found for project id ${projectId}`); - err.status = 404; - throw err; - } - if (data.startDate !== null && data.endDate !== null && data.startDate > data.endDate) { - const err = new Error('startDate must not be after endDate.'); - err.status = 422; - throw err; - } - return models.ProjectPhase - .create(data) - .then((_newProjectPhase) => { - newProjectPhase = _.cloneDeep(_newProjectPhase); - req.log.debug('new project phase created (id# %d, name: %s)', - newProjectPhase.id, newProjectPhase.name); + }) + .then((existingProject) => { + if (!existingProject) { + const err = new Error(`active project not found for project id ${projectId}`); + err.status = 404; + throw err; + } + if (data.startDate !== null && data.endDate !== null && data.startDate > data.endDate) { + const err = new Error('startDate must not be after endDate.'); + err.status = 422; + throw err; + } + return models.ProjectPhase + .create(data) + .then((_newProjectPhase) => { + newProjectPhase = _.cloneDeep(_newProjectPhase); + req.log.debug('new project phase created (id# %d, name: %s)', + newProjectPhase.id, newProjectPhase.name); - newProjectPhase = newProjectPhase.get({ plain: true }); - newProjectPhase = _.omit(newProjectPhase, ['deletedAt', 'deletedBy', 'utm']); + newProjectPhase = newProjectPhase.get({ plain: true }); + newProjectPhase = _.omit(newProjectPhase, ['deletedAt', 'deletedBy', 'utm']); + }); + }) + .then(() => { + req.log.debug('re-ordering the other phases'); + + if (_.isNil(newProjectPhase.order)) { + return Promise.resolve(); + } + + // Increase the order of the other phases in the same project, + // which have `order` >= this phase order + return models.ProjectPhase.update({ order: Sequelize.literal('"order" + 1') }, { + where: { + projectId, + id: { $ne: newProjectPhase.id }, + order: { $gte: newProjectPhase.order }, + }, }); - }); - }) - .then(() => { - // Send events to buses - req.log.debug('Sending event to RabbitMQ bus for project phase %d', newProjectPhase.id); - req.app.services.pubsub.publish(EVENT.ROUTING_KEY.PROJECT_PHASE_ADDED, - newProjectPhase, - { correlationId: req.id }, - ); - req.log.debug('Sending event to Kafka bus for project phase %d', newProjectPhase.id); - req.app.emit(EVENT.ROUTING_KEY.PROJECT_PHASE_ADDED, { req, created: newProjectPhase }); + }) + .then(() => { + if (_.isNil(data.productTemplateId)) { + return Promise.resolve(); + } - res.status(201).json(util.wrapResponse(req.id, newProjectPhase, 1, 201)); + // Get the product template + return models.ProductTemplate.findById(data.productTemplateId) + .then((productTemplate) => { + if (!productTemplate) { + const err = new Error(`Product template does not exist with id = ${data.productTemplateId}`); + err.status = 422; + throw err; + } + + // Create the phase product + return models.PhaseProduct.create({ + name: productTemplate.name, + templateId: data.productTemplateId, + type: productTemplate.productKey, + projectId, + phaseId: newProjectPhase.id, + createdBy: req.authUser.userId, + updatedBy: req.authUser.userId, + }) + .then((phaseProduct) => { + newProjectPhase.products = [ + _.omit(phaseProduct.toJSON(), ['deletedAt', 'deletedBy']), + ]; + }); + }); + }); }) - .catch((err) => { - util.handleError('Error creating project phase', err, req, next); - }); + .then(() => { + // Send events to buses + req.log.debug('Sending event to RabbitMQ bus for project phase %d', newProjectPhase.id); + req.app.services.pubsub.publish(EVENT.ROUTING_KEY.PROJECT_PHASE_ADDED, + newProjectPhase, + { correlationId: req.id }, + ); + req.log.debug('Sending event to Kafka bus for project phase %d', newProjectPhase.id); + req.app.emit(EVENT.ROUTING_KEY.PROJECT_PHASE_ADDED, { req, created: newProjectPhase }); + + res.status(201).json(util.wrapResponse(req.id, newProjectPhase, 1, 201)); + }) + .catch((err) => { + util.handleError('Error creating project phase', err, req, next); + }); }, ]; diff --git a/src/routes/phases/create.spec.js b/src/routes/phases/create.spec.js index ff5de77e..2f84160f 100644 --- a/src/routes/phases/create.spec.js +++ b/src/routes/phases/create.spec.js @@ -47,41 +47,75 @@ describe('Project Phases', () => { lastName: 'lName', email: 'some@abc.com', }; + let productTemplateId; before((done) => { // mocks testUtil.clearDb() - .then(() => { - models.Project.create({ - type: 'generic', - billingAccountId: 1, - name: 'test1', - description: 'test project1', - status: 'draft', - details: {}, + .then(() => { + models.Project.create({ + type: 'generic', + billingAccountId: 1, + name: 'test1', + description: 'test project1', + status: 'draft', + details: {}, + createdBy: 1, + updatedBy: 1, + }).then((p) => { + projectId = p.id; + // create members + models.ProjectMember.bulkCreate([{ + id: 1, + userId: copilotUser.userId, + projectId, + role: 'copilot', + isPrimary: false, createdBy: 1, updatedBy: 1, - }).then((p) => { - projectId = p.id; - // create members - models.ProjectMember.bulkCreate([{ - id: 1, - userId: copilotUser.userId, - projectId, - role: 'copilot', - isPrimary: false, - createdBy: 1, - updatedBy: 1, - }, { - id: 2, - userId: memberUser.userId, - projectId, - role: 'customer', - isPrimary: true, - createdBy: 1, - updatedBy: 1, - }]).then(() => done()); - }); + }, { + id: 2, + userId: memberUser.userId, + projectId, + role: 'customer', + isPrimary: true, + createdBy: 1, + updatedBy: 1, + }]); }); + }) + .then(() => + models.ProductTemplate.create({ + name: 'name 1', + productKey: 'productKey 1', + category: 'generic', + icon: 'http://example.com/icon1.ico', + brief: 'brief 1', + details: 'details 1', + aliases: ['product key 1', 'product_key_1'], + template: { + template1: { + name: 'template 1', + details: { + anyDetails: 'any details 1', + }, + others: ['others 11', 'others 12'], + }, + template2: { + name: 'template 2', + details: { + anyDetails: 'any details 2', + }, + others: ['others 21', 'others 22'], + }, + }, + createdBy: 1, + updatedBy: 2, + }).then((template) => { + productTemplateId = template.id; + return Promise.resolve(); + }), + ) + .then(() => done()); }); after((done) => { @@ -91,24 +125,24 @@ describe('Project Phases', () => { describe('POST /projects/{id}/phases/', () => { it('should return 403 if user does not have permissions (non team member)', (done) => { request(server) - .post(`/v4/projects/${projectId}/phases/`) - .set({ - Authorization: `Bearer ${testUtil.jwts.member2}`, - }) - .send({ param: body }) - .expect('Content-Type', /json/) - .expect(403, done); + .post(`/v4/projects/${projectId}/phases/`) + .set({ + Authorization: `Bearer ${testUtil.jwts.member2}`, + }) + .send({ param: body }) + .expect('Content-Type', /json/) + .expect(403, done); }); it('should return 403 if user does not have permissions (customer)', (done) => { request(server) - .post(`/v4/projects/${projectId}/phases/`) - .set({ - Authorization: `Bearer ${testUtil.jwts.member}`, - }) - .send({ param: body }) - .expect('Content-Type', /json/) - .expect(403, done); + .post(`/v4/projects/${projectId}/phases/`) + .set({ + Authorization: `Bearer ${testUtil.jwts.member}`, + }) + .send({ param: body }) + .expect('Content-Type', /json/) + .expect(403, done); }); it('should return 422 when name not provided', (done) => { @@ -231,5 +265,76 @@ describe('Project Phases', () => { } }); }); + + it('should return 201 if payload has order specified', (done) => { + request(server) + .post(`/v4/projects/${projectId}/phases/`) + .set({ + Authorization: `Bearer ${testUtil.jwts.copilot}`, + }) + .send({ param: _.assign({ order: 1 }, body) }) + .expect('Content-Type', /json/) + .expect(201) + .end((err, res) => { + if (err) { + done(err); + } else { + const resJson = res.body.result.content; + validatePhase(resJson, body); + resJson.order.should.be.eql(1); + + const firstPhaseId = resJson.id; + + // Create second phase + request(server) + .post(`/v4/projects/${projectId}/phases/`) + .set({ + Authorization: `Bearer ${testUtil.jwts.copilot}`, + }) + .send({ param: _.assign({ order: 1 }, body) }) + .expect('Content-Type', /json/) + .expect(201) + .end((err2, res2) => { + const resJson2 = res2.body.result.content; + validatePhase(resJson2, body); + resJson2.order.should.be.eql(1); + + models.ProjectPhase.findOne({ where: { id: firstPhaseId } }) + .then((firstPhase) => { + firstPhase.order.should.be.eql(2); + done(); + }); + }); + } + }); + }); + + it('should return 201 if payload has productTemplateId specified', (done) => { + request(server) + .post(`/v4/projects/${projectId}/phases/`) + .set({ + Authorization: `Bearer ${testUtil.jwts.copilot}`, + }) + .send({ param: _.assign({ productTemplateId }, body) }) + .expect('Content-Type', /json/) + .expect(201) + .end((err, res) => { + if (err) { + done(err); + } else { + const resJson = res.body.result.content; + validatePhase(resJson, body); + resJson.products.should.have.length(1); + + resJson.products[0].name.should.be.eql('name 1'); + resJson.products[0].templateId.should.be.eql(1); + resJson.products[0].type.should.be.eql('productKey 1'); + resJson.products[0].projectId.should.be.eql(1); + resJson.products[0].phaseId.should.be.eql(resJson.id); + + done(); + } + }); + }); }); }); diff --git a/src/routes/phases/list.js b/src/routes/phases/list.js index 55d5ba63..e0084184 100644 --- a/src/routes/phases/list.js +++ b/src/routes/phases/list.js @@ -30,6 +30,7 @@ module.exports = [ 'startDate asc', 'startDate desc', 'endDate asc', 'endDate desc', 'status asc', 'status desc', + 'order asc', 'order desc', ]; if (sort && _.indexOf(sortableProps, sort) < 0) { return util.handleError('Invalid sort criteria', null, req, next); diff --git a/src/routes/phases/update.js b/src/routes/phases/update.js index 389157f2..d2c6a9b4 100644 --- a/src/routes/phases/update.js +++ b/src/routes/phases/update.js @@ -2,6 +2,7 @@ import validate from 'express-validation'; import _ from 'lodash'; import Joi from 'joi'; +import Sequelize from 'sequelize'; import { middleware as tcMiddleware } from 'tc-core-library-js'; import models from '../../models'; import util from '../../util'; @@ -22,6 +23,7 @@ const updateProjectPhaseValidation = { spentBudget: Joi.number().min(0).optional(), progress: Joi.number().min(0).optional(), details: Joi.any().optional(), + order: Joi.number().integer().optional(), }).required(), }, }; @@ -41,6 +43,7 @@ module.exports = [ updatedProps.updatedBy = req.authUser.userId; let previousValue; + let updated; models.sequelize.transaction(() => models.ProjectPhase.findOne({ where: { @@ -82,21 +85,83 @@ module.exports = [ existing.save().then(accept).catch(reject); } } - }))) - .then((updated) => { - req.log.debug('updated project phase', JSON.stringify(updated, null, 2)); - - // emit original and updated project phase information - req.app.services.pubsub.publish( - EVENT.ROUTING_KEY.PROJECT_PHASE_UPDATED, - { original: previousValue, updated }, - { correlationId: req.id }, - ); - req.app.emit(EVENT.ROUTING_KEY.PROJECT_PHASE_UPDATED, - { req, original: previousValue, updated }); - - res.json(util.wrapResponse(req.id, updated)); - }) - .catch(err => next(err)); + })) + .then((updatedPhase) => { + updated = updatedPhase; + + // Ignore re-ordering if there's no order specified for this phase + if (_.isNil(updated.order)) { + return Promise.resolve(); + } + + // Update order of the other phases only if the order was changed + if (previousValue.order === updated.order) { + return Promise.resolve(); + } + + return models.ProjectPhase.count({ + where: { + projectId, + id: { $ne: updated.id }, + order: updated.order, + }, + }) + .then((count) => { + if (count === 0) { + return Promise.resolve(); + } + + // Increase the order from M to K: if there is an item with order K, + // orders from M+1 to K should be made M to K-1 + if (!_.isNil(previousValue.order) && previousValue.order < updated.order) { + return models.ProjectPhase.update({ order: Sequelize.literal('"order" - 1') }, { + where: { + projectId, + id: { $ne: updated.id }, + order: { $between: [previousValue.order + 1, updated.order] }, + }, + }); + } + + // Decrease the order from M to K: if there is an item with order K, + // orders from K to M-1 should be made K+1 to M + return models.ProjectPhase.update({ order: Sequelize.literal('"order" + 1') }, { + where: { + projectId, + id: { $ne: updated.id }, + order: { + $between: [ + updated.order, + (previousValue.order ? previousValue.order : Number.MAX_SAFE_INTEGER) - 1, + ], + }, + }, + }); + }); + }) + .then(() => + // To simpify the logic, reload the phases from DB and send to the message queue + models.ProjectPhase.findAll({ + where: { + projectId, + }, + include: [{ model: models.PhaseProduct, as: 'products' }], + })), + ) + .then((allPhases) => { + req.log.debug('updated project phase', JSON.stringify(updated, null, 2)); + + // emit original and updated project phase information + req.app.services.pubsub.publish( + EVENT.ROUTING_KEY.PROJECT_PHASE_UPDATED, + { original: previousValue, updated, allPhases }, + { correlationId: req.id }, + ); + req.app.emit(EVENT.ROUTING_KEY.PROJECT_PHASE_UPDATED, + { req, original: previousValue, updated }); + + res.json(util.wrapResponse(req.id, updated)); + }) + .catch(err => next(err)); }, ]; diff --git a/src/routes/phases/update.spec.js b/src/routes/phases/update.spec.js index b154d339..ce9ddf16 100644 --- a/src/routes/phases/update.spec.js +++ b/src/routes/phases/update.spec.js @@ -46,6 +46,7 @@ const validatePhase = (resJson, expectedPhase) => { describe('Project Phases', () => { let projectId; let phaseId; + let phaseId2; const memberUser = { handle: testUtil.getDecodedToken(testUtil.jwts.member).handle, userId: testUtil.getDecodedToken(testUtil.jwts.member).userId, @@ -63,44 +64,51 @@ describe('Project Phases', () => { before((done) => { // mocks testUtil.clearDb() - .then(() => { - models.Project.create({ - type: 'generic', - billingAccountId: 1, - name: 'test1', - description: 'test project1', - status: 'draft', - details: {}, + .then(() => { + models.Project.create({ + type: 'generic', + billingAccountId: 1, + name: 'test1', + description: 'test project1', + status: 'draft', + details: {}, + createdBy: 1, + updatedBy: 1, + }).then((p) => { + projectId = p.id; + // create members + models.ProjectMember.bulkCreate([{ + id: 1, + userId: copilotUser.userId, + projectId, + role: 'copilot', + isPrimary: false, createdBy: 1, updatedBy: 1, - }).then((p) => { - projectId = p.id; - // create members - models.ProjectMember.bulkCreate([{ - id: 1, - userId: copilotUser.userId, - projectId, - role: 'copilot', - isPrimary: false, - createdBy: 1, - updatedBy: 1, - }, { - id: 2, - userId: memberUser.userId, - projectId, - role: 'customer', - isPrimary: true, - createdBy: 1, - updatedBy: 1, - }]).then(() => { - _.assign(body, { projectId }); - models.ProjectPhase.create(body).then((phase) => { - phaseId = phase.id; + }, { + id: 2, + userId: memberUser.userId, + projectId, + role: 'customer', + isPrimary: true, + createdBy: 1, + updatedBy: 1, + }]).then(() => { + _.assign(body, { projectId }); + const phases = [ + body, + _.assign({ order: 1 }, body), + ]; + models.ProjectPhase.bulkCreate(phases, { returning: true }) + .then((createdPhases) => { + phaseId = createdPhases[0].id; + phaseId2 = createdPhases[1].id; + done(); }); - }); }); }); + }); }); after((done) => { @@ -226,5 +234,32 @@ describe('Project Phases', () => { } }); }); + + it('should return updated phase if the order is specified', (done) => { + request(server) + .patch(`/v4/projects/${projectId}/phases/${phaseId}`) + .set({ + Authorization: `Bearer ${testUtil.jwts.copilot}`, + }) + .send({ param: _.assign({ order: 1 }, updateBody) }) + .expect('Content-Type', /json/) + .expect(200) + .end((err, res) => { + if (err) { + done(err); + } else { + const resJson = res.body.result.content; + validatePhase(resJson, updateBody); + resJson.order.should.be.eql(1); + + // Check the order of the other phase + models.ProjectPhase.findOne({ where: { id: phaseId2 } }) + .then((phase2) => { + phase2.order.should.be.eql(2); + done(); + }); + } + }); + }); }); }); diff --git a/src/routes/productCategories/create.spec.js b/src/routes/productCategories/create.spec.js index 7b8f0089..c345eda3 100644 --- a/src/routes/productCategories/create.spec.js +++ b/src/routes/productCategories/create.spec.js @@ -28,7 +28,7 @@ describe('CREATE product category', () => { ); after(testUtil.clearDb); - describe('POST /productCategories', () => { + describe('POST /projects/metadata/productCategories', () => { const body = { param: { key: 'app_dev', @@ -44,14 +44,14 @@ describe('CREATE product category', () => { it('should return 403 if user is not authenticated', (done) => { request(server) - .post('/v4/productCategories') + .post('/v4/projects/metadata/productCategories') .send(body) .expect(403, done); }); it('should return 403 for member', (done) => { request(server) - .post('/v4/productCategories') + .post('/v4/projects/metadata/productCategories') .set({ Authorization: `Bearer ${testUtil.jwts.member}`, }) @@ -61,7 +61,7 @@ describe('CREATE product category', () => { it('should return 403 for copilot', (done) => { request(server) - .post('/v4/productCategories') + .post('/v4/projects/metadata/productCategories') .set({ Authorization: `Bearer ${testUtil.jwts.copilot}`, }) @@ -71,7 +71,7 @@ describe('CREATE product category', () => { it('should return 403 for manager', (done) => { request(server) - .post('/v4/productCategories') + .post('/v4/projects/metadata/productCategories') .set({ Authorization: `Bearer ${testUtil.jwts.manager}`, }) @@ -84,7 +84,7 @@ describe('CREATE product category', () => { delete invalidBody.param.key; request(server) - .post('/v4/productCategories') + .post('/v4/projects/metadata/productCategories') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -98,7 +98,7 @@ describe('CREATE product category', () => { delete invalidBody.param.displayName; request(server) - .post('/v4/productCategories') + .post('/v4/projects/metadata/productCategories') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -112,7 +112,7 @@ describe('CREATE product category', () => { delete invalidBody.param.icon; request(server) - .post('/v4/productCategories') + .post('/v4/projects/metadata/productCategories') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -126,7 +126,7 @@ describe('CREATE product category', () => { delete invalidBody.param.question; request(server) - .post('/v4/productCategories') + .post('/v4/projects/metadata/productCategories') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -140,7 +140,7 @@ describe('CREATE product category', () => { delete invalidBody.param.info; request(server) - .post('/v4/productCategories') + .post('/v4/projects/metadata/productCategories') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -154,7 +154,7 @@ describe('CREATE product category', () => { invalidBody.param.key = 'key1'; request(server) - .post('/v4/productCategories') + .post('/v4/projects/metadata/productCategories') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -165,7 +165,7 @@ describe('CREATE product category', () => { it('should return 201 for admin', (done) => { request(server) - .post('/v4/productCategories') + .post('/v4/projects/metadata/productCategories') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -196,7 +196,7 @@ describe('CREATE product category', () => { it('should return 201 for connect admin', (done) => { request(server) - .post('/v4/productCategories') + .post('/v4/projects/metadata/productCategories') .set({ Authorization: `Bearer ${testUtil.jwts.connectAdmin}`, }) diff --git a/src/routes/productCategories/delete.spec.js b/src/routes/productCategories/delete.spec.js index dc33a92f..40f8baa5 100644 --- a/src/routes/productCategories/delete.spec.js +++ b/src/routes/productCategories/delete.spec.js @@ -26,7 +26,7 @@ const expectAfterDelete = (key, err, next) => { chai.assert.isNotNull(res.deletedBy); request(server) - .get(`/v4/productCategories/${key}`) + .get(`/v4/projects/metadata/productCategories/${key}`) .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -52,16 +52,16 @@ describe('DELETE product category', () => { ); after(testUtil.clearDb); - describe('DELETE /productCategories/{key}', () => { + describe('DELETE /projects/metadata/productCategories/{key}', () => { it('should return 403 if user is not authenticated', (done) => { request(server) - .delete(`/v4/productCategories/${key}`) + .delete(`/v4/projects/metadata/productCategories/${key}`) .expect(403, done); }); it('should return 403 for member', (done) => { request(server) - .delete(`/v4/productCategories/${key}`) + .delete(`/v4/projects/metadata/productCategories/${key}`) .set({ Authorization: `Bearer ${testUtil.jwts.member}`, }) @@ -70,7 +70,7 @@ describe('DELETE product category', () => { it('should return 403 for copilot', (done) => { request(server) - .delete(`/v4/productCategories/${key}`) + .delete(`/v4/projects/metadata/productCategories/${key}`) .set({ Authorization: `Bearer ${testUtil.jwts.copilot}`, }) @@ -79,7 +79,7 @@ describe('DELETE product category', () => { it('should return 403 for manager', (done) => { request(server) - .delete(`/v4/productCategories/${key}`) + .delete(`/v4/projects/metadata/productCategories/${key}`) .set({ Authorization: `Bearer ${testUtil.jwts.manager}`, }) @@ -88,7 +88,7 @@ describe('DELETE product category', () => { it('should return 404 for non-existed product category', (done) => { request(server) - .delete('/v4/productCategories/not_existed') + .delete('/v4/projects/metadata/productCategories/not_existed') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -99,7 +99,7 @@ describe('DELETE product category', () => { models.ProductCategory.destroy({ where: { key } }) .then(() => { request(server) - .delete(`/v4/productCategories/${key}`) + .delete(`/v4/projects/metadata/productCategories/${key}`) .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -109,7 +109,7 @@ describe('DELETE product category', () => { it('should return 204, for admin, if the product category was successfully removed', (done) => { request(server) - .delete(`/v4/productCategories/${key}`) + .delete(`/v4/projects/metadata/productCategories/${key}`) .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -119,7 +119,7 @@ describe('DELETE product category', () => { it('should return 204, for connect admin, if the product category was successfully removed', (done) => { request(server) - .delete(`/v4/productCategories/${key}`) + .delete(`/v4/projects/metadata/productCategories/${key}`) .set({ Authorization: `Bearer ${testUtil.jwts.connectAdmin}`, }) diff --git a/src/routes/productCategories/get.spec.js b/src/routes/productCategories/get.spec.js index 9d06dbf4..78ba07ce 100644 --- a/src/routes/productCategories/get.spec.js +++ b/src/routes/productCategories/get.spec.js @@ -32,10 +32,10 @@ describe('GET product category', () => { ); after(testUtil.clearDb); - describe('GET /productCategories/{key}', () => { + describe('GET /projects/metadata/productCategories/{key}', () => { it('should return 404 for non-existed product category', (done) => { request(server) - .get('/v4/productCategories/1234') + .get('/v4/projects/metadata/productCategories/1234') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -46,7 +46,7 @@ describe('GET product category', () => { models.ProductCategory.destroy({ where: { key } }) .then(() => { request(server) - .get(`/v4/productCategories/${key}`) + .get(`/v4/projects/metadata/productCategories/${key}`) .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -56,7 +56,7 @@ describe('GET product category', () => { it('should return 200 for admin', (done) => { request(server) - .get(`/v4/productCategories/${key}`) + .get(`/v4/projects/metadata/productCategories/${key}`) .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -84,13 +84,13 @@ describe('GET product category', () => { it('should return 200 even if user is not authenticated', (done) => { request(server) - .get(`/v4/productCategories/${key}`) + .get(`/v4/projects/metadata/productCategories/${key}`) .expect(200, done); }); it('should return 200 for connect admin', (done) => { request(server) - .get(`/v4/productCategories/${key}`) + .get(`/v4/projects/metadata/productCategories/${key}`) .set({ Authorization: `Bearer ${testUtil.jwts.connectAdmin}`, }) @@ -100,7 +100,7 @@ describe('GET product category', () => { it('should return 200 for connect manager', (done) => { request(server) - .get(`/v4/productCategories/${key}`) + .get(`/v4/projects/metadata/productCategories/${key}`) .set({ Authorization: `Bearer ${testUtil.jwts.manager}`, }) @@ -110,7 +110,7 @@ describe('GET product category', () => { it('should return 200 for member', (done) => { request(server) - .get(`/v4/productCategories/${key}`) + .get(`/v4/projects/metadata/productCategories/${key}`) .set({ Authorization: `Bearer ${testUtil.jwts.member}`, }) @@ -119,7 +119,7 @@ describe('GET product category', () => { it('should return 200 for copilot', (done) => { request(server) - .get(`/v4/productCategories/${key}`) + .get(`/v4/projects/metadata/productCategories/${key}`) .set({ Authorization: `Bearer ${testUtil.jwts.copilot}`, }) diff --git a/src/routes/productCategories/list.spec.js b/src/routes/productCategories/list.spec.js index e0e56ec7..d055f7df 100644 --- a/src/routes/productCategories/list.spec.js +++ b/src/routes/productCategories/list.spec.js @@ -45,10 +45,10 @@ describe('LIST product categories', () => { ); after(testUtil.clearDb); - describe('GET /productCategories', () => { + describe('GET /projects/metadata/productCategories', () => { it('should return 200 for admin', (done) => { request(server) - .get('/v4/productCategories') + .get('/v4/projects/metadata/productCategories') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -79,13 +79,13 @@ describe('LIST product categories', () => { it('should return 200 even if user is not authenticated', (done) => { request(server) - .get('/v4/productCategories') + .get('/v4/projects/metadata/productCategories') .expect(200, done); }); it('should return 200 for connect admin', (done) => { request(server) - .get('/v4/productCategories') + .get('/v4/projects/metadata/productCategories') .set({ Authorization: `Bearer ${testUtil.jwts.connectAdmin}`, }) @@ -95,7 +95,7 @@ describe('LIST product categories', () => { it('should return 200 for connect manager', (done) => { request(server) - .get('/v4/productCategories') + .get('/v4/projects/metadata/productCategories') .set({ Authorization: `Bearer ${testUtil.jwts.manager}`, }) @@ -105,7 +105,7 @@ describe('LIST product categories', () => { it('should return 200 for member', (done) => { request(server) - .get('/v4/productCategories') + .get('/v4/projects/metadata/productCategories') .set({ Authorization: `Bearer ${testUtil.jwts.member}`, }) @@ -114,7 +114,7 @@ describe('LIST product categories', () => { it('should return 200 for copilot', (done) => { request(server) - .get('/v4/productCategories') + .get('/v4/projects/metadata/productCategories') .set({ Authorization: `Bearer ${testUtil.jwts.copilot}`, }) diff --git a/src/routes/productCategories/update.spec.js b/src/routes/productCategories/update.spec.js index 7b877553..ad9a43b5 100644 --- a/src/routes/productCategories/update.spec.js +++ b/src/routes/productCategories/update.spec.js @@ -32,7 +32,7 @@ describe('UPDATE product category', () => { ); after(testUtil.clearDb); - describe('PATCH /productCategories/{key}', () => { + describe('PATCH /projects/metadata/productCategories/{key}', () => { const body = { param: { displayName: 'displayName 1 - update', @@ -47,14 +47,14 @@ describe('UPDATE product category', () => { it('should return 403 if user is not authenticated', (done) => { request(server) - .patch(`/v4/productCategories/${key}`) + .patch(`/v4/projects/metadata/productCategories/${key}`) .send(body) .expect(403, done); }); it('should return 403 for member', (done) => { request(server) - .patch(`/v4/productCategories/${key}`) + .patch(`/v4/projects/metadata/productCategories/${key}`) .set({ Authorization: `Bearer ${testUtil.jwts.member}`, }) @@ -64,7 +64,7 @@ describe('UPDATE product category', () => { it('should return 403 for copilot', (done) => { request(server) - .patch(`/v4/productCategories/${key}`) + .patch(`/v4/projects/metadata/productCategories/${key}`) .send(body) .set({ Authorization: `Bearer ${testUtil.jwts.copilot}`, @@ -74,7 +74,7 @@ describe('UPDATE product category', () => { it('should return 403 for manager', (done) => { request(server) - .patch(`/v4/productCategories/${key}`) + .patch(`/v4/projects/metadata/productCategories/${key}`) .send(body) .set({ Authorization: `Bearer ${testUtil.jwts.manager}`, @@ -84,7 +84,7 @@ describe('UPDATE product category', () => { it('should return 404 for non-existed product category', (done) => { request(server) - .patch('/v4/productCategories/1234') + .patch('/v4/projects/metadata/productCategories/1234') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -96,7 +96,7 @@ describe('UPDATE product category', () => { models.ProductCategory.destroy({ where: { key } }) .then(() => { request(server) - .patch(`/v4/productCategories/${key}`) + .patch(`/v4/projects/metadata/productCategories/${key}`) .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -114,7 +114,7 @@ describe('UPDATE product category', () => { delete partialBody.param.disabled; delete partialBody.param.hidden; request(server) - .patch(`/v4/productCategories/${key}`) + .patch(`/v4/projects/metadata/productCategories/${key}`) .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -150,7 +150,7 @@ describe('UPDATE product category', () => { delete partialBody.param.disabled; delete partialBody.param.hidden; request(server) - .patch(`/v4/productCategories/${key}`) + .patch(`/v4/projects/metadata/productCategories/${key}`) .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -186,7 +186,7 @@ describe('UPDATE product category', () => { delete partialBody.param.disabled; delete partialBody.param.hidden; request(server) - .patch(`/v4/productCategories/${key}`) + .patch(`/v4/projects/metadata/productCategories/${key}`) .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -222,7 +222,7 @@ describe('UPDATE product category', () => { delete partialBody.param.disabled; delete partialBody.param.hidden; request(server) - .patch(`/v4/productCategories/${key}`) + .patch(`/v4/projects/metadata/productCategories/${key}`) .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -258,7 +258,7 @@ describe('UPDATE product category', () => { delete partialBody.param.disabled; delete partialBody.param.hidden; request(server) - .patch(`/v4/productCategories/${key}`) + .patch(`/v4/projects/metadata/productCategories/${key}`) .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -294,7 +294,7 @@ describe('UPDATE product category', () => { delete partialBody.param.aliases; delete partialBody.param.hidden; request(server) - .patch(`/v4/productCategories/${key}`) + .patch(`/v4/projects/metadata/productCategories/${key}`) .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -330,7 +330,7 @@ describe('UPDATE product category', () => { delete partialBody.param.disabled; delete partialBody.param.aliases; request(server) - .patch(`/v4/productCategories/${key}`) + .patch(`/v4/projects/metadata/productCategories/${key}`) .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -358,7 +358,7 @@ describe('UPDATE product category', () => { it('should return 200 for admin all fields updated', (done) => { request(server) - .patch(`/v4/productCategories/${key}`) + .patch(`/v4/projects/metadata/productCategories/${key}`) .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -386,7 +386,7 @@ describe('UPDATE product category', () => { it('should return 200 for connect admin', (done) => { request(server) - .patch(`/v4/productCategories/${key}`) + .patch(`/v4/projects/metadata/productCategories/${key}`) .set({ Authorization: `Bearer ${testUtil.jwts.connectAdmin}`, }) diff --git a/src/routes/productTemplates/create.spec.js b/src/routes/productTemplates/create.spec.js index 846e429f..b4da9239 100644 --- a/src/routes/productTemplates/create.spec.js +++ b/src/routes/productTemplates/create.spec.js @@ -29,7 +29,7 @@ describe('CREATE product template', () => { .then(() => done()); }); - describe('POST /productTemplates', () => { + describe('POST /projects/metadata/productTemplates', () => { const body = { param: { name: 'name 1', @@ -62,14 +62,14 @@ describe('CREATE product template', () => { it('should return 403 if user is not authenticated', (done) => { request(server) - .post('/v4/productTemplates') + .post('/v4/projects/metadata/productTemplates') .send(body) .expect(403, done); }); it('should return 403 for member', (done) => { request(server) - .post('/v4/productTemplates') + .post('/v4/projects/metadata/productTemplates') .set({ Authorization: `Bearer ${testUtil.jwts.member}`, }) @@ -79,7 +79,7 @@ describe('CREATE product template', () => { it('should return 403 for copilot', (done) => { request(server) - .post('/v4/productTemplates') + .post('/v4/projects/metadata/productTemplates') .set({ Authorization: `Bearer ${testUtil.jwts.copilot}`, }) @@ -89,7 +89,7 @@ describe('CREATE product template', () => { it('should return 403 for connect manager', (done) => { request(server) - .post('/v4/productTemplates') + .post('/v4/projects/metadata/productTemplates') .set({ Authorization: `Bearer ${testUtil.jwts.manager}`, }) @@ -106,7 +106,7 @@ describe('CREATE product template', () => { }; request(server) - .post('/v4/productTemplates') + .post('/v4/projects/metadata/productTemplates') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -119,7 +119,7 @@ describe('CREATE product template', () => { const invalidBody = _.cloneDeep(body); invalidBody.param.category = null; request(server) - .post('/v4/productTemplates') + .post('/v4/projects/metadata/productTemplates') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -132,7 +132,7 @@ describe('CREATE product template', () => { const invalidBody = _.cloneDeep(body); invalidBody.param.category = 'not_exist'; request(server) - .post('/v4/productTemplates') + .post('/v4/projects/metadata/productTemplates') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -143,7 +143,7 @@ describe('CREATE product template', () => { it('should return 201 for admin', (done) => { request(server) - .post('/v4/productTemplates') + .post('/v4/projects/metadata/productTemplates') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -177,7 +177,7 @@ describe('CREATE product template', () => { it('should return 201 for connect admin', (done) => { request(server) - .post('/v4/productTemplates') + .post('/v4/projects/metadata/productTemplates') .set({ Authorization: `Bearer ${testUtil.jwts.connectAdmin}`, }) diff --git a/src/routes/productTemplates/delete.spec.js b/src/routes/productTemplates/delete.spec.js index 0f39eb15..edb53d74 100644 --- a/src/routes/productTemplates/delete.spec.js +++ b/src/routes/productTemplates/delete.spec.js @@ -25,7 +25,7 @@ const expectAfterDelete = (id, err, next) => { chai.assert.isNotNull(res.deletedBy); request(server) - .get(`/v4/productTemplates/${id}`) + .get(`/v4/projects/metadata/productTemplates/${id}`) .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -72,16 +72,16 @@ describe('DELETE product template', () => { ); after(testUtil.clearDb); - describe('DELETE /productTemplates/{templateId}', () => { + describe('DELETE /projects/metadata/productTemplates/{templateId}', () => { it('should return 403 if user is not authenticated', (done) => { request(server) - .delete(`/v4/productTemplates/${templateId}`) + .delete(`/v4/projects/metadata/productTemplates/${templateId}`) .expect(403, done); }); it('should return 403 for member', (done) => { request(server) - .delete(`/v4/productTemplates/${templateId}`) + .delete(`/v4/projects/metadata/productTemplates/${templateId}`) .set({ Authorization: `Bearer ${testUtil.jwts.member}`, }) @@ -90,7 +90,7 @@ describe('DELETE product template', () => { it('should return 403 for copilot', (done) => { request(server) - .delete(`/v4/productTemplates/${templateId}`) + .delete(`/v4/projects/metadata/productTemplates/${templateId}`) .set({ Authorization: `Bearer ${testUtil.jwts.copilot}`, }) @@ -99,7 +99,7 @@ describe('DELETE product template', () => { it('should return 403 for connect manager', (done) => { request(server) - .delete(`/v4/productTemplates/${templateId}`) + .delete(`/v4/projects/metadata/productTemplates/${templateId}`) .set({ Authorization: `Bearer ${testUtil.jwts.manager}`, }) @@ -108,7 +108,7 @@ describe('DELETE product template', () => { it('should return 404 for non-existed template', (done) => { request(server) - .delete('/v4/productTemplates/1234') + .delete('/v4/projects/metadata/productTemplates/1234') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -119,7 +119,7 @@ describe('DELETE product template', () => { models.ProductTemplate.destroy({ where: { id: templateId } }) .then(() => { request(server) - .delete(`/v4/productTemplates/${templateId}`) + .delete(`/v4/projects/metadata/productTemplates/${templateId}`) .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -129,7 +129,7 @@ describe('DELETE product template', () => { it('should return 204, for admin, if template was successfully removed', (done) => { request(server) - .delete(`/v4/productTemplates/${templateId}`) + .delete(`/v4/projects/metadata/productTemplates/${templateId}`) .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -139,7 +139,7 @@ describe('DELETE product template', () => { it('should return 204, for connect admin, if template was successfully removed', (done) => { request(server) - .delete(`/v4/productTemplates/${templateId}`) + .delete(`/v4/projects/metadata/productTemplates/${templateId}`) .set({ Authorization: `Bearer ${testUtil.jwts.connectAdmin}`, }) diff --git a/src/routes/productTemplates/get.spec.js b/src/routes/productTemplates/get.spec.js index c690efca..42b34e30 100644 --- a/src/routes/productTemplates/get.spec.js +++ b/src/routes/productTemplates/get.spec.js @@ -56,10 +56,10 @@ describe('GET product template', () => { ); after(testUtil.clearDb); - describe('GET /productTemplates/{templateId}', () => { + describe('GET /projects/metadata/productTemplates/{templateId}', () => { it('should return 404 for non-existed template', (done) => { request(server) - .get('/v4/productTemplates/1234') + .get('/v4/projects/metadata/productTemplates/1234') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -70,7 +70,7 @@ describe('GET product template', () => { models.ProductTemplate.destroy({ where: { id: templateId } }) .then(() => { request(server) - .get(`/v4/productTemplates/${templateId}`) + .get(`/v4/projects/metadata/productTemplates/${templateId}`) .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -80,7 +80,7 @@ describe('GET product template', () => { it('should return 200 for admin', (done) => { request(server) - .get(`/v4/productTemplates/${templateId}`) + .get(`/v4/projects/metadata/productTemplates/${templateId}`) .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -110,13 +110,13 @@ describe('GET product template', () => { it('should return 200 even if user is not authenticated', (done) => { request(server) - .get(`/v4/productTemplates/${templateId}`) + .get(`/v4/projects/metadata/productTemplates/${templateId}`) .expect(200, done); }); it('should return 200 for connect admin', (done) => { request(server) - .get(`/v4/productTemplates/${templateId}`) + .get(`/v4/projects/metadata/productTemplates/${templateId}`) .set({ Authorization: `Bearer ${testUtil.jwts.connectAdmin}`, }) @@ -126,7 +126,7 @@ describe('GET product template', () => { it('should return 200 for connect manager', (done) => { request(server) - .get(`/v4/productTemplates/${templateId}`) + .get(`/v4/projects/metadata/productTemplates/${templateId}`) .set({ Authorization: `Bearer ${testUtil.jwts.manager}`, }) @@ -136,7 +136,7 @@ describe('GET product template', () => { it('should return 200 for member', (done) => { request(server) - .get(`/v4/productTemplates/${templateId}`) + .get(`/v4/projects/metadata/productTemplates/${templateId}`) .set({ Authorization: `Bearer ${testUtil.jwts.member}`, }) @@ -145,7 +145,7 @@ describe('GET product template', () => { it('should return 200 for copilot', (done) => { request(server) - .get(`/v4/productTemplates/${templateId}`) + .get(`/v4/projects/metadata/productTemplates/${templateId}`) .set({ Authorization: `Bearer ${testUtil.jwts.copilot}`, }) diff --git a/src/routes/productTemplates/list.spec.js b/src/routes/productTemplates/list.spec.js index b0e8c56f..9282e409 100644 --- a/src/routes/productTemplates/list.spec.js +++ b/src/routes/productTemplates/list.spec.js @@ -94,10 +94,10 @@ describe('LIST product templates', () => { ); after(testUtil.clearDb); - describe('GET /productTemplates', () => { + describe('GET /projects/metadata/productTemplates', () => { it('should return 200 for admin', (done) => { request(server) - .get('/v4/productTemplates') + .get('/v4/projects/metadata/productTemplates') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -112,7 +112,7 @@ describe('LIST product templates', () => { it('should return 200 even if user is not authenticated', (done) => { request(server) - .get('/v4/productTemplates') + .get('/v4/projects/metadata/productTemplates') .expect(200) .end((err, res) => { const resJson = res.body.result.content; @@ -124,7 +124,7 @@ describe('LIST product templates', () => { it('should return 200 for connect admin', (done) => { request(server) - .get('/v4/productTemplates') + .get('/v4/projects/metadata/productTemplates') .set({ Authorization: `Bearer ${testUtil.jwts.connectAdmin}`, }) @@ -139,7 +139,7 @@ describe('LIST product templates', () => { it('should return 200 for connect manager', (done) => { request(server) - .get('/v4/productTemplates') + .get('/v4/projects/metadata/productTemplates') .set({ Authorization: `Bearer ${testUtil.jwts.manager}`, }) @@ -154,7 +154,7 @@ describe('LIST product templates', () => { it('should return 200 for member', (done) => { request(server) - .get('/v4/productTemplates') + .get('/v4/projects/metadata/productTemplates') .set({ Authorization: `Bearer ${testUtil.jwts.member}`, }) @@ -168,7 +168,7 @@ describe('LIST product templates', () => { it('should return 200 for copilot', (done) => { request(server) - .get('/v4/productTemplates') + .get('/v4/projects/metadata/productTemplates') .set({ Authorization: `Bearer ${testUtil.jwts.copilot}`, }) @@ -182,7 +182,7 @@ describe('LIST product templates', () => { it('should return filtered templates', (done) => { request(server) - .get('/v4/productTemplates?filter=productKey%3DproductKey-2') + .get('/v4/projects/metadata/productTemplates?filter=productKey%3DproductKey-2') .set({ Authorization: `Bearer ${testUtil.jwts.manager}`, }) diff --git a/src/routes/productTemplates/update.spec.js b/src/routes/productTemplates/update.spec.js index 80667f0f..6e65461d 100644 --- a/src/routes/productTemplates/update.spec.js +++ b/src/routes/productTemplates/update.spec.js @@ -80,7 +80,7 @@ describe('UPDATE product template', () => { ); after(testUtil.clearDb); - describe('PATCH /productTemplates/{templateId}', () => { + describe('PATCH /projects/metadata/productTemplates/{templateId}', () => { const body = { param: { name: 'template 1 - update', @@ -119,14 +119,14 @@ describe('UPDATE product template', () => { it('should return 403 if user is not authenticated', (done) => { request(server) - .patch(`/v4/productTemplates/${templateId}`) + .patch(`/v4/projects/metadata/productTemplates/${templateId}`) .send(body) .expect(403, done); }); it('should return 403 for member', (done) => { request(server) - .patch(`/v4/productTemplates/${templateId}`) + .patch(`/v4/projects/metadata/productTemplates/${templateId}`) .set({ Authorization: `Bearer ${testUtil.jwts.member}`, }) @@ -136,7 +136,7 @@ describe('UPDATE product template', () => { it('should return 403 for copilot', (done) => { request(server) - .patch(`/v4/productTemplates/${templateId}`) + .patch(`/v4/projects/metadata/productTemplates/${templateId}`) .send(body) .set({ Authorization: `Bearer ${testUtil.jwts.copilot}`, @@ -146,7 +146,7 @@ describe('UPDATE product template', () => { it('should return 403 for connect manager', (done) => { request(server) - .patch(`/v4/productTemplates/${templateId}`) + .patch(`/v4/projects/metadata/productTemplates/${templateId}`) .send(body) .set({ Authorization: `Bearer ${testUtil.jwts.manager}`, @@ -163,7 +163,7 @@ describe('UPDATE product template', () => { }; request(server) - .patch(`/v4/productTemplates/${templateId}`) + .patch(`/v4/projects/metadata/productTemplates/${templateId}`) .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -173,7 +173,7 @@ describe('UPDATE product template', () => { it('should return 404 for non-existed template', (done) => { request(server) - .patch('/v4/productTemplates/1234') + .patch('/v4/projects/metadata/productTemplates/1234') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -185,7 +185,7 @@ describe('UPDATE product template', () => { models.ProductTemplate.destroy({ where: { id: templateId } }) .then(() => { request(server) - .patch(`/v4/productTemplates/${templateId}`) + .patch(`/v4/projects/metadata/productTemplates/${templateId}`) .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -196,7 +196,7 @@ describe('UPDATE product template', () => { it('should return 200 for admin', (done) => { request(server) - .patch(`/v4/productTemplates/${templateId}`) + .patch(`/v4/projects/metadata/productTemplates/${templateId}`) .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -260,7 +260,7 @@ describe('UPDATE product template', () => { it('should return 200 for connect admin', (done) => { request(server) - .patch(`/v4/productTemplates/${templateId}`) + .patch(`/v4/projects/metadata/productTemplates/${templateId}`) .set({ Authorization: `Bearer ${testUtil.jwts.connectAdmin}`, }) diff --git a/src/routes/projectMembers/delete.js b/src/routes/projectMembers/delete.js index 43e1f037..b58aaa84 100644 --- a/src/routes/projectMembers/delete.js +++ b/src/routes/projectMembers/delete.js @@ -28,9 +28,9 @@ module.exports = [ err.status = 404; return Promise.reject(err); } - return member.update({ deletedBy: req.authUser.userId }); // eslint-disable-line no-console + return member.update({ deletedBy: req.authUser.userId }); }) - .then(member => member.destroy({ logging: console.log })) + .then(member => member.destroy({ logging: console.log })) // eslint-disable-line no-console .then(member => member.save()) // if primary co-pilot is removed promote the next co-pilot to primary #43 .then(member => new Promise((accept, reject) => { diff --git a/src/routes/projectTemplates/create.spec.js b/src/routes/projectTemplates/create.spec.js index c18123cb..51989b4c 100644 --- a/src/routes/projectTemplates/create.spec.js +++ b/src/routes/projectTemplates/create.spec.js @@ -30,7 +30,7 @@ describe('CREATE project template', () => { .then(() => done()); }); - describe('POST /projectTemplates', () => { + describe('POST /projects/metadata/projectTemplates', () => { const body = { param: { name: 'template 1', @@ -70,14 +70,14 @@ describe('CREATE project template', () => { it('should return 403 if user is not authenticated', (done) => { request(server) - .post('/v4/projectTemplates') + .post('/v4/projects/metadata/projectTemplates') .send(body) .expect(403, done); }); it('should return 403 for member', (done) => { request(server) - .post('/v4/projectTemplates') + .post('/v4/projects/metadata/projectTemplates') .set({ Authorization: `Bearer ${testUtil.jwts.member}`, }) @@ -87,7 +87,7 @@ describe('CREATE project template', () => { it('should return 403 for copilot', (done) => { request(server) - .post('/v4/projectTemplates') + .post('/v4/projects/metadata/projectTemplates') .set({ Authorization: `Bearer ${testUtil.jwts.copilot}`, }) @@ -97,7 +97,7 @@ describe('CREATE project template', () => { it('should return 403 for connect manager', (done) => { request(server) - .post('/v4/projectTemplates') + .post('/v4/projects/metadata/projectTemplates') .set({ Authorization: `Bearer ${testUtil.jwts.manager}`, }) @@ -114,7 +114,7 @@ describe('CREATE project template', () => { }; request(server) - .post('/v4/projectTemplates') + .post('/v4/projects/metadata/projectTemplates') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -127,7 +127,7 @@ describe('CREATE project template', () => { const invalidBody = _.cloneDeep(body); invalidBody.param.type = null; request(server) - .post('/v4/projectTemplates') + .post('/v4/projects/metadata/projectTemplates') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -140,7 +140,7 @@ describe('CREATE project template', () => { const invalidBody = _.cloneDeep(body); invalidBody.param.type = 'not_exist'; request(server) - .post('/v4/projectTemplates') + .post('/v4/projects/metadata/projectTemplates') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -151,7 +151,7 @@ describe('CREATE project template', () => { it('should return 201 for admin', (done) => { request(server) - .post('/v4/projectTemplates') + .post('/v4/projects/metadata/projectTemplates') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -182,7 +182,7 @@ describe('CREATE project template', () => { it('should return 201 for connect admin', (done) => { request(server) - .post('/v4/projectTemplates') + .post('/v4/projects/metadata/projectTemplates') .set({ Authorization: `Bearer ${testUtil.jwts.connectAdmin}`, }) diff --git a/src/routes/projectTemplates/delete.spec.js b/src/routes/projectTemplates/delete.spec.js index a475ee5d..8c3c268f 100644 --- a/src/routes/projectTemplates/delete.spec.js +++ b/src/routes/projectTemplates/delete.spec.js @@ -25,7 +25,7 @@ const expectAfterDelete = (id, err, next) => { chai.assert.isNotNull(res.deletedBy); request(server) - .get(`/v4/projectTemplates/${id}`) + .get(`/v4/projects/metadata/projectTemplates/${id}`) .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -78,16 +78,16 @@ describe('DELETE project template', () => { ); after(testUtil.clearDb); - describe('DELETE /projectTemplates/{templateId}', () => { + describe('DELETE /projects/metadata/projectTemplates/{templateId}', () => { it('should return 403 if user is not authenticated', (done) => { request(server) - .delete(`/v4/projectTemplates/${templateId}`) + .delete(`/v4/projects/metadata/projectTemplates/${templateId}`) .expect(403, done); }); it('should return 403 for member', (done) => { request(server) - .delete(`/v4/projectTemplates/${templateId}`) + .delete(`/v4/projects/metadata/projectTemplates/${templateId}`) .set({ Authorization: `Bearer ${testUtil.jwts.member}`, }) @@ -96,7 +96,7 @@ describe('DELETE project template', () => { it('should return 403 for copilot', (done) => { request(server) - .delete(`/v4/projectTemplates/${templateId}`) + .delete(`/v4/projects/metadata/projectTemplates/${templateId}`) .set({ Authorization: `Bearer ${testUtil.jwts.copilot}`, }) @@ -105,7 +105,7 @@ describe('DELETE project template', () => { it('should return 403 for connect manager', (done) => { request(server) - .delete(`/v4/projectTemplates/${templateId}`) + .delete(`/v4/projects/metadata/projectTemplates/${templateId}`) .set({ Authorization: `Bearer ${testUtil.jwts.manager}`, }) @@ -114,7 +114,7 @@ describe('DELETE project template', () => { it('should return 404 for non-existed template', (done) => { request(server) - .delete('/v4/projectTemplates/1234') + .delete('/v4/projects/metadata/projectTemplates/1234') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -125,7 +125,7 @@ describe('DELETE project template', () => { models.ProjectTemplate.destroy({ where: { id: templateId } }) .then(() => { request(server) - .delete(`/v4/projectTemplates/${templateId}`) + .delete(`/v4/projects/metadata/projectTemplates/${templateId}`) .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -135,7 +135,7 @@ describe('DELETE project template', () => { it('should return 204, for admin, if template was successfully removed', (done) => { request(server) - .delete(`/v4/projectTemplates/${templateId}`) + .delete(`/v4/projects/metadata/projectTemplates/${templateId}`) .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -144,7 +144,7 @@ describe('DELETE project template', () => { it('should return 204, for connect admin, if template was successfully removed', (done) => { request(server) - .delete(`/v4/projectTemplates/${templateId}`) + .delete(`/v4/projects/metadata/projectTemplates/${templateId}`) .set({ Authorization: `Bearer ${testUtil.jwts.connectAdmin}`, }) diff --git a/src/routes/projectTemplates/get.spec.js b/src/routes/projectTemplates/get.spec.js index 50899ec4..ae6607fa 100644 --- a/src/routes/projectTemplates/get.spec.js +++ b/src/routes/projectTemplates/get.spec.js @@ -57,10 +57,10 @@ describe('GET project template', () => { ); after(testUtil.clearDb); - describe('GET /projectTemplates/{templateId}', () => { + describe('GET /projects/metadata/projectTemplates/{templateId}', () => { it('should return 404 for non-existed template', (done) => { request(server) - .get('/v4/projectTemplates/1234') + .get('/v4/projects/metadata/projectTemplates/1234') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -71,7 +71,7 @@ describe('GET project template', () => { models.ProjectTemplate.destroy({ where: { id: templateId } }) .then(() => { request(server) - .get(`/v4/projectTemplates/${templateId}`) + .get(`/v4/projects/metadata/projectTemplates/${templateId}`) .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -81,7 +81,7 @@ describe('GET project template', () => { it('should return 200 for admin', (done) => { request(server) - .get(`/v4/projectTemplates/${templateId}`) + .get(`/v4/projects/metadata/projectTemplates/${templateId}`) .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -107,13 +107,13 @@ describe('GET project template', () => { it('should return 200 even if user is not authenticated', (done) => { request(server) - .get(`/v4/projectTemplates/${templateId}`) + .get(`/v4/projects/metadata/projectTemplates/${templateId}`) .expect(200, done); }); it('should return 200 for connect admin', (done) => { request(server) - .get(`/v4/projectTemplates/${templateId}`) + .get(`/v4/projects/metadata/projectTemplates/${templateId}`) .set({ Authorization: `Bearer ${testUtil.jwts.connectAdmin}`, }) @@ -123,7 +123,7 @@ describe('GET project template', () => { it('should return 200 for connect manager', (done) => { request(server) - .get(`/v4/projectTemplates/${templateId}`) + .get(`/v4/projects/metadata/projectTemplates/${templateId}`) .set({ Authorization: `Bearer ${testUtil.jwts.manager}`, }) @@ -133,7 +133,7 @@ describe('GET project template', () => { it('should return 200 for member', (done) => { request(server) - .get(`/v4/projectTemplates/${templateId}`) + .get(`/v4/projects/metadata/projectTemplates/${templateId}`) .set({ Authorization: `Bearer ${testUtil.jwts.member}`, }) @@ -142,7 +142,7 @@ describe('GET project template', () => { it('should return 200 for copilot', (done) => { request(server) - .get(`/v4/projectTemplates/${templateId}`) + .get(`/v4/projects/metadata/projectTemplates/${templateId}`) .set({ Authorization: `Bearer ${testUtil.jwts.copilot}`, }) diff --git a/src/routes/projectTemplates/list.spec.js b/src/routes/projectTemplates/list.spec.js index e826ea9f..9c3008e8 100644 --- a/src/routes/projectTemplates/list.spec.js +++ b/src/routes/projectTemplates/list.spec.js @@ -74,10 +74,10 @@ describe('LIST project templates', () => { ); after(testUtil.clearDb); - describe('GET /projectTemplates', () => { + describe('GET /projects/metadata/projectTemplates', () => { it('should return 200 for admin', (done) => { request(server) - .get('/v4/projectTemplates') + .get('/v4/projects/metadata/projectTemplates') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -106,13 +106,13 @@ describe('LIST project templates', () => { it('should return 200 for anonymous user', (done) => { request(server) - .get('/v4/projectTemplates') + .get('/v4/projects/metadata/projectTemplates') .expect(200, done); }); it('should return 200 for connect admin', (done) => { request(server) - .get('/v4/projectTemplates') + .get('/v4/projects/metadata/projectTemplates') .set({ Authorization: `Bearer ${testUtil.jwts.connectAdmin}`, }) @@ -122,7 +122,7 @@ describe('LIST project templates', () => { it('should return 200 for connect manager', (done) => { request(server) - .get('/v4/projectTemplates') + .get('/v4/projects/metadata/projectTemplates') .set({ Authorization: `Bearer ${testUtil.jwts.manager}`, }) @@ -132,7 +132,7 @@ describe('LIST project templates', () => { it('should return 200 for member', (done) => { request(server) - .get('/v4/projectTemplates') + .get('/v4/projects/metadata/projectTemplates') .set({ Authorization: `Bearer ${testUtil.jwts.member}`, }) @@ -141,7 +141,7 @@ describe('LIST project templates', () => { it('should return 200 for copilot', (done) => { request(server) - .get('/v4/projectTemplates') + .get('/v4/projects/metadata/projectTemplates') .set({ Authorization: `Bearer ${testUtil.jwts.copilot}`, }) diff --git a/src/routes/projectTemplates/update.spec.js b/src/routes/projectTemplates/update.spec.js index 514df753..ff051381 100644 --- a/src/routes/projectTemplates/update.spec.js +++ b/src/routes/projectTemplates/update.spec.js @@ -83,7 +83,7 @@ describe('UPDATE project template', () => { ); after(testUtil.clearDb); - describe('PATCH /projectTemplates/{templateId}', () => { + describe('PATCH /projects/metadata/projectTemplates/{templateId}', () => { const body = { param: { name: 'template 1 - update', @@ -119,14 +119,14 @@ describe('UPDATE project template', () => { it('should return 403 if user is not authenticated', (done) => { request(server) - .patch(`/v4/projectTemplates/${templateId}`) + .patch(`/v4/projects/metadata/projectTemplates/${templateId}`) .send(body) .expect(403, done); }); it('should return 403 for member', (done) => { request(server) - .patch(`/v4/projectTemplates/${templateId}`) + .patch(`/v4/projects/metadata/projectTemplates/${templateId}`) .set({ Authorization: `Bearer ${testUtil.jwts.member}`, }) @@ -136,7 +136,7 @@ describe('UPDATE project template', () => { it('should return 403 for copilot', (done) => { request(server) - .patch(`/v4/projectTemplates/${templateId}`) + .patch(`/v4/projects/metadata/projectTemplates/${templateId}`) .send(body) .set({ Authorization: `Bearer ${testUtil.jwts.copilot}`, @@ -146,7 +146,7 @@ describe('UPDATE project template', () => { it('should return 403 for connect manager', (done) => { request(server) - .patch(`/v4/projectTemplates/${templateId}`) + .patch(`/v4/projects/metadata/projectTemplates/${templateId}`) .send(body) .set({ Authorization: `Bearer ${testUtil.jwts.manager}`, @@ -163,7 +163,7 @@ describe('UPDATE project template', () => { }; request(server) - .patch(`/v4/projectTemplates/${templateId}`) + .patch(`/v4/projects/metadata/projectTemplates/${templateId}`) .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -173,7 +173,7 @@ describe('UPDATE project template', () => { it('should return 404 for non-existed template', (done) => { request(server) - .patch('/v4/projectTemplates/1234') + .patch('/v4/projects/metadata/projectTemplates/1234') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -185,7 +185,7 @@ describe('UPDATE project template', () => { models.ProjectTemplate.destroy({ where: { id: templateId } }) .then(() => { request(server) - .patch(`/v4/projectTemplates/${templateId}`) + .patch(`/v4/projects/metadata/projectTemplates/${templateId}`) .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -196,7 +196,7 @@ describe('UPDATE project template', () => { it('should return 200 for admin', (done) => { request(server) - .patch(`/v4/projectTemplates/${templateId}`) + .patch(`/v4/projects/metadata/projectTemplates/${templateId}`) .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -256,7 +256,7 @@ describe('UPDATE project template', () => { it('should return 200 for connect admin', (done) => { request(server) - .patch(`/v4/projectTemplates/${templateId}`) + .patch(`/v4/projects/metadata/projectTemplates/${templateId}`) .set({ Authorization: `Bearer ${testUtil.jwts.connectAdmin}`, }) diff --git a/src/routes/projectTypes/create.spec.js b/src/routes/projectTypes/create.spec.js index d2e339bc..7823e45b 100644 --- a/src/routes/projectTypes/create.spec.js +++ b/src/routes/projectTypes/create.spec.js @@ -29,7 +29,7 @@ describe('CREATE project type', () => { ); after(testUtil.clearDb); - describe('POST /projectTypes', () => { + describe('POST /projects/metadata/projectTypes', () => { const body = { param: { key: 'app_dev', @@ -46,14 +46,14 @@ describe('CREATE project type', () => { it('should return 403 if user is not authenticated', (done) => { request(server) - .post('/v4/projectTypes') + .post('/v4/projects/metadata/projectTypes') .send(body) .expect(403, done); }); it('should return 403 for member', (done) => { request(server) - .post('/v4/projectTypes') + .post('/v4/projects/metadata/projectTypes') .set({ Authorization: `Bearer ${testUtil.jwts.member}`, }) @@ -63,7 +63,7 @@ describe('CREATE project type', () => { it('should return 403 for copilot', (done) => { request(server) - .post('/v4/projectTypes') + .post('/v4/projects/metadata/projectTypes') .set({ Authorization: `Bearer ${testUtil.jwts.copilot}`, }) @@ -73,7 +73,7 @@ describe('CREATE project type', () => { it('should return 403 for manager', (done) => { request(server) - .post('/v4/projectTypes') + .post('/v4/projects/metadata/projectTypes') .set({ Authorization: `Bearer ${testUtil.jwts.manager}`, }) @@ -86,7 +86,7 @@ describe('CREATE project type', () => { delete invalidBody.param.key; request(server) - .post('/v4/projectTypes') + .post('/v4/projects/metadata/projectTypes') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -100,7 +100,7 @@ describe('CREATE project type', () => { delete invalidBody.param.displayName; request(server) - .post('/v4/projectTypes') + .post('/v4/projects/metadata/projectTypes') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -114,7 +114,7 @@ describe('CREATE project type', () => { delete invalidBody.param.icon; request(server) - .post('/v4/projectTypes') + .post('/v4/projects/metadata/projectTypes') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -128,7 +128,7 @@ describe('CREATE project type', () => { delete invalidBody.param.question; request(server) - .post('/v4/projectTypes') + .post('/v4/projects/metadata/projectTypes') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -142,7 +142,7 @@ describe('CREATE project type', () => { delete invalidBody.param.info; request(server) - .post('/v4/projectTypes') + .post('/v4/projects/metadata/projectTypes') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -156,7 +156,7 @@ describe('CREATE project type', () => { delete invalidBody.param.metadata; request(server) - .post('/v4/projectTypes') + .post('/v4/projects/metadata/projectTypes') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -170,7 +170,7 @@ describe('CREATE project type', () => { invalidBody.param.key = 'key1'; request(server) - .post('/v4/projectTypes') + .post('/v4/projects/metadata/projectTypes') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -181,7 +181,7 @@ describe('CREATE project type', () => { it('should return 201 for admin', (done) => { request(server) - .post('/v4/projectTypes') + .post('/v4/projects/metadata/projectTypes') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -213,7 +213,7 @@ describe('CREATE project type', () => { it('should return 201 for connect admin', (done) => { request(server) - .post('/v4/projectTypes') + .post('/v4/projects/metadata/projectTypes') .set({ Authorization: `Bearer ${testUtil.jwts.connectAdmin}`, }) diff --git a/src/routes/projectTypes/delete.spec.js b/src/routes/projectTypes/delete.spec.js index 26b35994..5b9cee54 100644 --- a/src/routes/projectTypes/delete.spec.js +++ b/src/routes/projectTypes/delete.spec.js @@ -24,7 +24,7 @@ const expectAfterDelete = (key, err, next) => { chai.assert.isNotNull(res.deletedBy); request(server) - .get(`/v4/projectTypes/${key}`) + .get(`/v4/projects/metadata/projectTypes/${key}`) .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -51,16 +51,16 @@ describe('DELETE project type', () => { ); after(testUtil.clearDb); - describe('DELETE /projectTypes/{key}', () => { + describe('DELETE /projects/metadata/projectTypes/{key}', () => { it('should return 403 if user is not authenticated', (done) => { request(server) - .delete(`/v4/projectTypes/${key}`) + .delete(`/v4/projects/metadata/projectTypes/${key}`) .expect(403, done); }); it('should return 403 for member', (done) => { request(server) - .delete(`/v4/projectTypes/${key}`) + .delete(`/v4/projects/metadata/projectTypes/${key}`) .set({ Authorization: `Bearer ${testUtil.jwts.member}`, }) @@ -69,7 +69,7 @@ describe('DELETE project type', () => { it('should return 403 for copilot', (done) => { request(server) - .delete(`/v4/projectTypes/${key}`) + .delete(`/v4/projects/metadata/projectTypes/${key}`) .set({ Authorization: `Bearer ${testUtil.jwts.copilot}`, }) @@ -78,7 +78,7 @@ describe('DELETE project type', () => { it('should return 403 for manager', (done) => { request(server) - .delete(`/v4/projectTypes/${key}`) + .delete(`/v4/projects/metadata/projectTypes/${key}`) .set({ Authorization: `Bearer ${testUtil.jwts.manager}`, }) @@ -87,7 +87,7 @@ describe('DELETE project type', () => { it('should return 404 for non-existed type', (done) => { request(server) - .delete('/v4/projectTypes/not_existed') + .delete('/v4/projects/metadata/projectTypes/not_existed') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -98,7 +98,7 @@ describe('DELETE project type', () => { models.ProjectType.destroy({ where: { key } }) .then(() => { request(server) - .delete(`/v4/projectTypes/${key}`) + .delete(`/v4/projects/metadata/projectTypes/${key}`) .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -108,7 +108,7 @@ describe('DELETE project type', () => { it('should return 204, for admin, if type was successfully removed', (done) => { request(server) - .delete(`/v4/projectTypes/${key}`) + .delete(`/v4/projects/metadata/projectTypes/${key}`) .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -118,7 +118,7 @@ describe('DELETE project type', () => { it('should return 204, for connect admin, if type was successfully removed', (done) => { request(server) - .delete(`/v4/projectTypes/${key}`) + .delete(`/v4/projects/metadata/projectTypes/${key}`) .set({ Authorization: `Bearer ${testUtil.jwts.connectAdmin}`, }) diff --git a/src/routes/projectTypes/get.spec.js b/src/routes/projectTypes/get.spec.js index eb72604f..099b4c66 100644 --- a/src/routes/projectTypes/get.spec.js +++ b/src/routes/projectTypes/get.spec.js @@ -33,10 +33,10 @@ describe('GET project type', () => { ); after(testUtil.clearDb); - describe('GET /projectTypes/{key}', () => { + describe('GET /projects/metadata/projectTypes/{key}', () => { it('should return 404 for non-existed type', (done) => { request(server) - .get('/v4/projectTypes/1234') + .get('/v4/projects/metadata/projectTypes/1234') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -47,7 +47,7 @@ describe('GET project type', () => { models.ProjectType.destroy({ where: { key } }) .then(() => { request(server) - .get(`/v4/projectTypes/${key}`) + .get(`/v4/projects/metadata/projectTypes/${key}`) .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -57,7 +57,7 @@ describe('GET project type', () => { it('should return 200 for admin', (done) => { request(server) - .get(`/v4/projectTypes/${key}`) + .get(`/v4/projects/metadata/projectTypes/${key}`) .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -86,13 +86,13 @@ describe('GET project type', () => { it('should return 200 even if user is not authenticated', (done) => { request(server) - .get(`/v4/projectTypes/${key}`) + .get(`/v4/projects/metadata/projectTypes/${key}`) .expect(200, done); }); it('should return 200 for connect admin', (done) => { request(server) - .get(`/v4/projectTypes/${key}`) + .get(`/v4/projects/metadata/projectTypes/${key}`) .set({ Authorization: `Bearer ${testUtil.jwts.connectAdmin}`, }) @@ -102,7 +102,7 @@ describe('GET project type', () => { it('should return 200 for connect manager', (done) => { request(server) - .get(`/v4/projectTypes/${key}`) + .get(`/v4/projects/metadata/projectTypes/${key}`) .set({ Authorization: `Bearer ${testUtil.jwts.manager}`, }) @@ -112,7 +112,7 @@ describe('GET project type', () => { it('should return 200 for member', (done) => { request(server) - .get(`/v4/projectTypes/${key}`) + .get(`/v4/projects/metadata/projectTypes/${key}`) .set({ Authorization: `Bearer ${testUtil.jwts.member}`, }) @@ -121,7 +121,7 @@ describe('GET project type', () => { it('should return 200 for copilot', (done) => { request(server) - .get(`/v4/projectTypes/${key}`) + .get(`/v4/projects/metadata/projectTypes/${key}`) .set({ Authorization: `Bearer ${testUtil.jwts.copilot}`, }) diff --git a/src/routes/projectTypes/list.spec.js b/src/routes/projectTypes/list.spec.js index 991667b5..f941fe02 100644 --- a/src/routes/projectTypes/list.spec.js +++ b/src/routes/projectTypes/list.spec.js @@ -47,10 +47,10 @@ describe('LIST project types', () => { ); after(testUtil.clearDb); - describe('GET /projectTypes', () => { + describe('GET /projects/metadata/projectTypes', () => { it('should return 200 for admin', (done) => { request(server) - .get('/v4/projectTypes') + .get('/v4/projects/metadata/projectTypes') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -82,13 +82,13 @@ describe('LIST project types', () => { it('should return 200 even if user is not authenticated', (done) => { request(server) - .get('/v4/projectTypes') + .get('/v4/projects/metadata/projectTypes') .expect(200, done); }); it('should return 200 for connect admin', (done) => { request(server) - .get('/v4/projectTypes') + .get('/v4/projects/metadata/projectTypes') .set({ Authorization: `Bearer ${testUtil.jwts.connectAdmin}`, }) @@ -98,7 +98,7 @@ describe('LIST project types', () => { it('should return 200 for connect manager', (done) => { request(server) - .get('/v4/projectTypes') + .get('/v4/projects/metadata/projectTypes') .set({ Authorization: `Bearer ${testUtil.jwts.manager}`, }) @@ -108,7 +108,7 @@ describe('LIST project types', () => { it('should return 200 for member', (done) => { request(server) - .get('/v4/projectTypes') + .get('/v4/projects/metadata/projectTypes') .set({ Authorization: `Bearer ${testUtil.jwts.member}`, }) @@ -117,7 +117,7 @@ describe('LIST project types', () => { it('should return 200 for copilot', (done) => { request(server) - .get('/v4/projectTypes') + .get('/v4/projects/metadata/projectTypes') .set({ Authorization: `Bearer ${testUtil.jwts.copilot}`, }) diff --git a/src/routes/projectTypes/update.spec.js b/src/routes/projectTypes/update.spec.js index 0402020c..229f544a 100644 --- a/src/routes/projectTypes/update.spec.js +++ b/src/routes/projectTypes/update.spec.js @@ -33,7 +33,7 @@ describe('UPDATE project type', () => { ); after(testUtil.clearDb); - describe('PATCH /projectTypes/{key}', () => { + describe('PATCH /projects/metadata/projectTypes/{key}', () => { const body = { param: { displayName: 'displayName 1 - update', @@ -49,14 +49,14 @@ describe('UPDATE project type', () => { it('should return 403 if user is not authenticated', (done) => { request(server) - .patch(`/v4/projectTypes/${key}`) + .patch(`/v4/projects/metadata/projectTypes/${key}`) .send(body) .expect(403, done); }); it('should return 403 for member', (done) => { request(server) - .patch(`/v4/projectTypes/${key}`) + .patch(`/v4/projects/metadata/projectTypes/${key}`) .set({ Authorization: `Bearer ${testUtil.jwts.member}`, }) @@ -66,7 +66,7 @@ describe('UPDATE project type', () => { it('should return 403 for copilot', (done) => { request(server) - .patch(`/v4/projectTypes/${key}`) + .patch(`/v4/projects/metadata/projectTypes/${key}`) .send(body) .set({ Authorization: `Bearer ${testUtil.jwts.copilot}`, @@ -76,7 +76,7 @@ describe('UPDATE project type', () => { it('should return 403 for manager', (done) => { request(server) - .patch(`/v4/projectTypes/${key}`) + .patch(`/v4/projects/metadata/projectTypes/${key}`) .send(body) .set({ Authorization: `Bearer ${testUtil.jwts.manager}`, @@ -86,7 +86,7 @@ describe('UPDATE project type', () => { it('should return 404 for non-existed type', (done) => { request(server) - .patch('/v4/projectTypes/1234') + .patch('/v4/projects/metadata/projectTypes/1234') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -98,7 +98,7 @@ describe('UPDATE project type', () => { models.ProjectType.destroy({ where: { key } }) .then(() => { request(server) - .patch(`/v4/projectTypes/${key}`) + .patch(`/v4/projects/metadata/projectTypes/${key}`) .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -117,7 +117,7 @@ describe('UPDATE project type', () => { delete partialBody.param.hidden; delete partialBody.param.metadata; request(server) - .patch(`/v4/projectTypes/${key}`) + .patch(`/v4/projects/metadata/projectTypes/${key}`) .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -155,7 +155,7 @@ describe('UPDATE project type', () => { delete partialBody.param.hidden; delete partialBody.param.metadata; request(server) - .patch(`/v4/projectTypes/${key}`) + .patch(`/v4/projects/metadata/projectTypes/${key}`) .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -193,7 +193,7 @@ describe('UPDATE project type', () => { delete partialBody.param.hidden; delete partialBody.param.metadata; request(server) - .patch(`/v4/projectTypes/${key}`) + .patch(`/v4/projects/metadata/projectTypes/${key}`) .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -231,7 +231,7 @@ describe('UPDATE project type', () => { delete partialBody.param.hidden; delete partialBody.param.metadata; request(server) - .patch(`/v4/projectTypes/${key}`) + .patch(`/v4/projects/metadata/projectTypes/${key}`) .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -269,7 +269,7 @@ describe('UPDATE project type', () => { delete partialBody.param.hidden; delete partialBody.param.metadata; request(server) - .patch(`/v4/projectTypes/${key}`) + .patch(`/v4/projects/metadata/projectTypes/${key}`) .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -307,7 +307,7 @@ describe('UPDATE project type', () => { delete partialBody.param.hidden; delete partialBody.param.metadata; request(server) - .patch(`/v4/projectTypes/${key}`) + .patch(`/v4/projects/metadata/projectTypes/${key}`) .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -345,7 +345,7 @@ describe('UPDATE project type', () => { delete partialBody.param.aliases; delete partialBody.param.metadata; request(server) - .patch(`/v4/projectTypes/${key}`) + .patch(`/v4/projects/metadata/projectTypes/${key}`) .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -382,7 +382,7 @@ describe('UPDATE project type', () => { delete partialBody.param.aliases; delete partialBody.param.hidden; request(server) - .patch(`/v4/projectTypes/${key}`) + .patch(`/v4/projects/metadata/projectTypes/${key}`) .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -411,7 +411,7 @@ describe('UPDATE project type', () => { it('should return 200 for admin all fields updated', (done) => { request(server) - .patch(`/v4/projectTypes/${key}`) + .patch(`/v4/projects/metadata/projectTypes/${key}`) .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) @@ -440,7 +440,7 @@ describe('UPDATE project type', () => { it('should return 200 for connect admin', (done) => { request(server) - .patch(`/v4/projectTypes/${key}`) + .patch(`/v4/projects/metadata/projectTypes/${key}`) .set({ Authorization: `Bearer ${testUtil.jwts.connectAdmin}`, }) diff --git a/src/routes/projects/create.spec.js b/src/routes/projects/create.spec.js index 7637cefe..dcec4e55 100644 --- a/src/routes/projects/create.spec.js +++ b/src/routes/projects/create.spec.js @@ -462,5 +462,90 @@ describe('Project create', () => { } }); }); + + it('should return 201 if valid user and data (using Bearer userId_)', (done) => { + const mockHttpClient = _.merge(testUtil.mockHttpClient, { + post: () => Promise.resolve({ + status: 200, + data: { + id: 'requesterId', + version: 'v3', + result: { + success: true, + status: 200, + content: { + projectId: 128, + }, + }, + }, + }), + get: () => Promise.resolve({ + status: 200, + data: { + id: 'requesterId', + version: 'v3', + result: { + success: true, + status: 200, + content: [ + { + id: 1800075, + active: false, + }, + ], + }, + }, + }), + }); + sandbox.stub(util, 'getHttpClient', () => mockHttpClient); + request(server) + .post('/v4/projects') + .set({ + Authorization: 'Bearer userId_1800075', + }) + .send(_.merge({ param: { templateId: 3 } }, body)) + .expect('Content-Type', /json/) + .expect(201) + .end((err, res) => { + if (err) { + server.log.error(err); + done(err); + } else { + const resJson = res.body.result.content; + should.exist(resJson); + should.exist(resJson.billingAccountId); + should.exist(resJson.name); + resJson.directProjectId.should.be.eql(128); + resJson.status.should.be.eql('draft'); + resJson.type.should.be.eql(body.param.type); + resJson.members.should.have.lengthOf(1); + resJson.members[0].role.should.be.eql('customer'); + resJson.members[0].userId.should.be.eql(1800075); + resJson.members[0].projectId.should.be.eql(resJson.id); + resJson.members[0].isPrimary.should.be.truthy; + resJson.bookmarks.should.have.lengthOf(1); + resJson.bookmarks[0].title.should.be.eql('title1'); + resJson.bookmarks[0].address.should.be.eql('http://www.address.com'); + resJson.phases.should.have.lengthOf(3); + const phases = _.sortBy(resJson.phases, p => p.name); + phases[0].name.should.be.eql('Design Stage'); + phases[0].status.should.be.eql('open'); + phases[0].startDate.should.be.a('string'); + phases[0].duration.should.be.eql(10); + const startDate = moment.utc(phases[0].startDate); + startDate.hours().should.be.eql(0); + startDate.minutes().should.be.eql(0); + startDate.seconds().should.be.eql(0); + startDate.milliseconds().should.be.eql(0); + new Date(phases[0].endDate).should.be.eql(startDate.add(9, 'days').toDate()); + expect(phases[0].details).to.be.empty; + phases[0].products.should.have.lengthOf(1); + phases[0].products[0].name.should.be.eql('product 1'); + phases[0].products[0].templateId.should.be.eql(21); + server.services.pubsub.publish.calledWith('project.draft-created').should.be.true; + done(); + } + }); + }); }); }); diff --git a/src/routes/timelines/create.js b/src/routes/timelines/create.js index 7aa53502..f7a5e3fc 100644 --- a/src/routes/timelines/create.js +++ b/src/routes/timelines/create.js @@ -9,7 +9,8 @@ import { middleware as tcMiddleware } from 'tc-core-library-js'; import util from '../../util'; import validateTimeline from '../../middlewares/validateTimeline'; import models from '../../models'; -import { EVENT, TIMELINE_REFERENCES, MILESTONE_STATUS } from '../../constants'; +import { EVENT, TIMELINE_REFERENCES, MILESTONE_STATUS, MILESTONE_TEMPLATE_REFERENCES } + from '../../constants'; const permissions = tcMiddleware.permissions; @@ -59,9 +60,10 @@ module.exports = [ req.log.debug('Checking templateId %d for creating milestones', templateId); if (templateId) { req.log.debug('Found templateId, finding milestone templates for the template'); - return models.ProductMilestoneTemplate.findAll({ + return models.MilestoneTemplate.findAll({ where: { - productTemplateId: templateId, + reference: MILESTONE_TEMPLATE_REFERENCES.PRODUCT_TEMPLATE, + referenceId: templateId, deletedAt: { $eq: null }, }, order: [['order', 'asc']], diff --git a/src/routes/timelines/create.spec.js b/src/routes/timelines/create.spec.js index c35d4661..7ce3e9c3 100644 --- a/src/routes/timelines/create.spec.js +++ b/src/routes/timelines/create.spec.js @@ -62,7 +62,9 @@ const milestoneTemplates = [ blockedText: 'text to be shown in blocked stage', activeText: 'text to be shown in active stage', completedText: 'text to be shown in completed stage', - productTemplateId: 1, + reference: 'product', + referenceId: 1, + metadata: {}, createdBy: 1, updatedBy: 2, hidden: false, @@ -78,7 +80,9 @@ const milestoneTemplates = [ blockedText: 'text to be shown in blocked stage - 2', activeText: 'text to be shown in active stage - 2', completedText: 'text to be shown in completed stage - 2', - productTemplateId: 1, + reference: 'product', + referenceId: 1, + metadata: {}, createdBy: 2, updatedBy: 3, hidden: false, @@ -94,7 +98,9 @@ const milestoneTemplates = [ blockedText: 'text to be shown in blocked stage - 3', activeText: 'text to be shown in active stage - 3', completedText: 'text to be shown in completed stage - 3', - productTemplateId: 1, + reference: 'product', + referenceId: 1, + metadata: {}, createdBy: 2, updatedBy: 3, hidden: false, @@ -168,7 +174,7 @@ describe('CREATE timeline', () => { }); }) .then(() => models.ProductTemplate.bulkCreate(productTemplates)) - .then(() => models.ProductMilestoneTemplate.bulkCreate(milestoneTemplates)) + .then(() => models.MilestoneTemplate.bulkCreate(milestoneTemplates)) .then(() => { done(); }); diff --git a/src/services/busApi.js b/src/services/busApi.js index 5d3aa07d..ddc58656 100644 --- a/src/services/busApi.js +++ b/src/services/busApi.js @@ -43,7 +43,7 @@ async function getClient() { * @return {Promise} new event promise */ function createEvent(topic, payload, logger) { - logger.debug(`Sending message: ${JSON.stringify(payload)}`); + logger.debug(`Sending message to topic ${topic}: ${JSON.stringify(payload)}`); return getClient().then((busClient) => { logger.debug('calling bus-api'); return busClient.post('/bus/events', { diff --git a/src/tests/seed.js b/src/tests/seed.js index ea2ea5fb..6b693e5c 100644 --- a/src/tests/seed.js +++ b/src/tests/seed.js @@ -441,13 +441,30 @@ models.sequelize.sync({ force: true }) }, ], { returning: true })) // Product milestone templates - .then(productTemplates => models.ProductMilestoneTemplate.bulkCreate([ + .then(productTemplates => models.MilestoneTemplate.bulkCreate([ { name: 'milestoneTemplate 1', duration: 3, type: 'type1', order: 1, - productTemplateId: productTemplates[0].id, + reference: 'productTemplate', + referenceId: productTemplates[0].id, + metadata: { + metadata1: { + name: 'metadata 1', + details: { + anyDetails: 'any details 1', + }, + others: ['others 11', 'others 12'], + }, + metadata2: { + name: 'metadata 2', + details: { + anyDetails: 'any details 2', + }, + others: ['others 21', 'others 22'], + }, + }, activeText: 'activeText 1', completedText: 'completedText 1', blockedText: 'blockedText 1', @@ -460,7 +477,9 @@ models.sequelize.sync({ force: true }) duration: 4, type: 'type2', order: 2, - productTemplateId: productTemplates[0].id, + metadata: {}, + reference: 'productTemplate', + referenceId: productTemplates[0].id, activeText: 'activeText 2', completedText: 'completedText 2', blockedText: 'blockedText 2', @@ -584,6 +603,7 @@ models.sequelize.sync({ force: true }) question: 'question 1', info: 'info 1', aliases: ['key-11', 'key_12'], + metadata: {}, }, { key: 'generic', @@ -594,6 +614,7 @@ models.sequelize.sync({ force: true }) question: 'question 2', info: 'info 2', aliases: ['key-21', 'key_22'], + metadata: {}, }, { key: 'visual_prototype', @@ -604,6 +625,7 @@ models.sequelize.sync({ force: true }) question: 'question 3', info: 'info 1', aliases: ['key-31', 'key_32'], + metadata: {}, }, { key: 'visual_design', @@ -614,6 +636,7 @@ models.sequelize.sync({ force: true }) question: 'question 4', info: 'info 4', aliases: ['key-41', 'key_42'], + metadata: {}, }, { key: 'website', @@ -624,6 +647,7 @@ models.sequelize.sync({ force: true }) question: 'question 5', info: 'info 5', aliases: ['key-51', 'key_52'], + metadata: {}, }, { key: 'app', @@ -634,6 +658,7 @@ models.sequelize.sync({ force: true }) question: 'question 6', info: 'info 6', aliases: ['key-61', 'key_62'], + metadata: {}, }, { key: 'quality_assurance', @@ -644,6 +669,7 @@ models.sequelize.sync({ force: true }) question: 'question 7', info: 'info 7', aliases: ['key-71', 'key_72'], + metadata: {}, }, { key: 'chatbot', @@ -654,6 +680,7 @@ models.sequelize.sync({ force: true }) question: 'question 8', info: 'info 8', aliases: ['key-81', 'key_82'], + metadata: {}, }, ])) .then(() => models.ProductCategory.bulkCreate([ diff --git a/src/util.js b/src/util.js index 79cecbc3..bc1fe325 100644 --- a/src/util.js +++ b/src/util.js @@ -17,10 +17,14 @@ import urlencode from 'urlencode'; import elasticsearch from 'elasticsearch'; import Promise from 'bluebird'; import AWS from 'aws-sdk'; + import { ADMIN_ROLES, TOKEN_SCOPES } from './constants'; const exec = require('child_process').exec; const models = require('./models').default; +const tcCoreLibAuth = require('tc-core-library-js').auth; + +const m2m = tcCoreLibAuth.m2m(config); const util = _.cloneDeep(require('tc-core-library-js').util(config)); @@ -282,6 +286,12 @@ _.assignIn(util, { .then(res => res.data.result.content.token); }, + /** + * Get machine to machine token. + * @returns {Promise} promise which resolves to the m2m token + */ + getM2MToken: () => m2m.getMachineToken(config.AUTH0_CLIENT_ID, config.AUTH0_CLIENT_SECRET), + /** * Fetches the topcoder user details using the given JWT token. * @@ -299,8 +309,9 @@ _.assignIn(util, { httpClient.defaults.headers.common.Authorization = `Bearer ${jwtToken}`; return httpClient.get(`${config.identityServiceEndpoint}users/${userId}`).then((response) => { if (response.data && response.data.result - && response.data.result.status === 200 && response.data.result.content) { - return response.data.result.content; + && response.data.result.status === 200 && response.data.result.content + && response.data.result.content.length > 0) { + return response.data.result.content[0]; } return null; }); diff --git a/swagger.yaml b/swagger.yaml index b95bbe94..8f081f9f 100755 --- a/swagger.yaml +++ b/swagger.yaml @@ -355,7 +355,7 @@ paths: - name: sort required: false description: | - sort project phases by startDate, endDate, status. Default is startDate asc + sort project phases by startDate, endDate, status, order. Default is startDate asc in: query type: string responses: @@ -373,13 +373,24 @@ paths: operationId: addProjectPhase security: - Bearer: [] - description: Create a project phase + description: Create a project phase. + It also updates the `order` field of all other phases in the same project which have `order` greater than or equal to the `order` specified in the POST body. parameters: - in: body name: body required: true schema: - $ref: '#/definitions/ProjectPhaseBodyParam' + type: object + allOf: + - $ref: '#/definitions/ProjectPhaseBodyParam' + properties: + param: + type: object + properties: + productTemplateId: + type: number + format: long + description: the optional productTemplateId used to populate a new phase product for the created phase responses: '403': description: No permission or wrong token @@ -428,6 +439,7 @@ paths: security: - Bearer: [] description: Update a project phase. All users who can edit project can access this endpoint. + It also updates the `order` field of all other phases in the same project which have `order` greater than or equal to the `order` specified in the POST body. responses: '403': description: No permission or wrong token @@ -647,8 +659,26 @@ paths: description: Project migrated successfully schema: $ref: "#/definitions/ProjectUpgradeResponse" + + /projects/metadata: + get: + tags: + - metadata + operationId: getAllMetadata + security: + - Bearer: [] + description: Retrieve all metadata including projectTemplates, productTemplates, milestoneTemplates, projectTypes, productCategories. All user roles can access this endpoint. + responses: + '200': + description: The metadata + schema: + $ref: "#/definitions/AllMetadataResponse" + '500': + description: Invalid server state or unknown error + schema: + $ref: "#/definitions/ErrorModel" - /projectTemplates: + /projects/metadata/projectTemplates: get: tags: - projectTemplate @@ -692,7 +722,7 @@ paths: schema: $ref: "#/definitions/ErrorModel" - /projectTemplates/{templateId}: + /projects/metadata/projectTemplates/{templateId}: get: tags: - projectTemplate @@ -774,7 +804,7 @@ paths: description: Project template successfully removed - /productTemplates: + /projects/metadata/productTemplates: get: tags: - productTemplate @@ -818,7 +848,7 @@ paths: schema: $ref: "#/definitions/ErrorModel" - /productTemplates/{templateId}: + /projects/metadata/productTemplates/{templateId}: get: tags: - productTemplate @@ -900,7 +930,7 @@ paths: description: Product template successfully removed - /productCategories: + /projects/metadata/productCategories: get: tags: - productCategory @@ -944,7 +974,7 @@ paths: schema: $ref: "#/definitions/ErrorModel" - /productCategories/{key}: + /projects/metadata/productCategories/{key}: get: tags: - productCategory @@ -1023,7 +1053,7 @@ paths: description: Product category successfully removed - /projectTypes: + /projects/metadata/projectTypes: get: tags: - projectType @@ -1067,7 +1097,7 @@ paths: schema: $ref: "#/definitions/ErrorModel" - /projectTypes/{key}: + /projects/metadata/projectTypes/{key}: get: tags: - projectType @@ -1438,12 +1468,10 @@ paths: description: Milestone successfully removed - /productTemplates/{productTemplateId}/milestones: - parameters: - - $ref: "#/parameters/productTemplateIdParam" + /timelines/metadata/milestoneTemplates: get: tags: - - productMilestoneTemplate + - milestoneTemplates operationId: findMilestoneTemplates security: - Bearer: [] @@ -1454,6 +1482,14 @@ paths: description: sort by `order`. Default is `order asc` in: query type: string + - name: filter + required: false + type: string + in: query + description: | + Url encoded list of supported filters + - reference + - referenceId responses: '403': description: No permission or wrong token @@ -1469,7 +1505,7 @@ paths: $ref: "#/definitions/MilestoneTemplateListResponse" post: tags: - - productMilestoneTemplate + - milestoneTemplates operationId: addMilestoneTemplate security: - Bearer: [] @@ -1494,12 +1530,10 @@ paths: schema: $ref: "#/definitions/ErrorModel" - /productTemplates/{productTemplateId}/milestones/clone: - parameters: - - $ref: "#/parameters/productTemplateIdParam" + /timelines/metadata/milestoneTemplates/clone: post: tags: - - productMilestoneTemplate + - milestoneTemplates operationId: cloneMilestoneTemplate security: - Bearer: [] @@ -1529,13 +1563,12 @@ paths: $ref: "#/definitions/ErrorModel" - /productTemplates/{productTemplateId}/milestones/{milestoneTemplateId}: + /timelines/metadata/milestoneTemplates/{milestoneTemplateId}: parameters: - - $ref: "#/parameters/productTemplateIdParam" - $ref: "#/parameters/milestoneTemplateIdParam" get: tags: - - productMilestoneTemplate + - milestoneTemplates description: Retrieve milestone template by id. All user roles can access this endpoint. security: - Bearer: [] @@ -1560,7 +1593,7 @@ paths: patch: tags: - - productMilestoneTemplate + - milestoneTemplates operationId: updateMilestoneTemplate security: - Bearer: [] @@ -1595,7 +1628,7 @@ paths: delete: tags: - - productMilestoneTemplate + - milestoneTemplates description: Remove an existing milestone template. Only connect manager, connect admin, and admin can access this endpoint. security: - Bearer: [] @@ -2613,6 +2646,10 @@ definitions: details: type: object description: the project phase details + order: + type: number + format: integer + description: the project phase order ProjectPhaseBodyParam: title: Project phase body param @@ -3427,6 +3464,9 @@ definitions: - duration - type - order + - reference + - referenceId + - metadata properties: name: type: string @@ -3445,6 +3485,19 @@ definitions: type: number format: integer description: the milestone template order + reference: + type: string + enum: + - productTemplate + description: the milestone template reference + refereneceId: + type: number + format: long + minimum: 1 + description: the milestone template reference id + metadata: + type: object + description: the milestone template metadata MilestoneTemplateBodyParam: title: Milestone template body param @@ -3459,12 +3512,31 @@ definitions: title: Milestone clone template request object type: object required: - - sourceTemplateId + - sourceReference + - sourceReferenceId + - reference + - referenceId properties: - sourceTemplateId: + sourceReference: + type: string + enum: + - productTemplate + description: the source reference to clone the milestone templates from + sourceReferenceId: type: number - format: integer - description: the product template id where to clone the milestone templates from + format: long + minimum: 1 + description: the source reference id to clone the milestone templates from + reference: + type: string + enum: + - productTemplate + description: the target reference to clone the milestone templates to + refereneceId: + type: number + format: long + minimum: 1 + description: the target reference id to clone the milestone templates to MilestoneTemplate: title: Milestone template object @@ -3547,3 +3619,48 @@ definitions: type: array items: $ref: "#/definitions/MilestoneTemplate" + + AllMetadataResponse: + title: All metadata response object + type: object + properties: + id: + type: string + readOnly: true + description: unique id identifying the request + version: + type: string + result: + type: object + properties: + success: + type: boolean + status: + type: string + description: http status code + metadata: + $ref: "#/definitions/ResponseMetadata" + content: + type: object + properties: + projectTemplates: + type: array + items: + $ref: "#/definitions/ProjectTemplate" + productTemplates: + type: array + items: + $ref: "#/definitions/ProductTemplate" + milestoneTemplates: + type: array + items: + $ref: "#/definitions/MilestoneTemplate" + projectTypes: + type: array + items: + $ref: "#/definitions/ProjectType" + productCategories: + type: array + items: + $ref: "#/definitions/ProductCategory" + \ No newline at end of file