From f29919b78fc5201f1a0f6630b5fb34b96c8506d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?ra=C3=BAl?= Date: Sun, 28 Nov 2021 16:59:24 -0300 Subject: [PATCH 01/17] remove condition for visualization on Iphones (#1215) --- client-participation/js/views/participation.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/client-participation/js/views/participation.js b/client-participation/js/views/participation.js index cc0c749bf..343bc8e10 100644 --- a/client-participation/js/views/participation.js +++ b/client-participation/js/views/participation.js @@ -193,9 +193,7 @@ module.exports = ConversationView.extend({ // ctx.showLogoInFooter = !ctx.showLogoAndBreadCrumbInHeader; ctx.showLogoInFooter = false; - ctx.no_vis = !Utils.userCanSeeVis() || - ctx.vis_type === Constants.VIS_TYPE.OFF || - (ctx.vis_type === Constants.VIS_TYPE.PCA && Utils.isIphone()); + ctx.no_vis = !Utils.userCanSeeVis() || ctx.vis_type === Constants.VIS_TYPE.OFF; ctx.no_write = ctx.write_type === 0 || !Utils.userCanWrite() || !ctx.is_active; ctx.no_voting = !Utils.userCanVote() || !ctx.is_active; ctx.no_topic = !Utils.userCanSeeTopic() || !ctx.topic || ctx.topic.length === 0; From 6b57632ff4c21aafb7a842e63b5c43ad7dc59f6b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 28 Nov 2021 12:00:37 -0800 Subject: [PATCH 02/17] Bump webpack from 5.24.1 to 5.64.2 in /client-admin (#1212) Bumps [webpack](https://github.com/webpack/webpack) from 5.24.1 to 5.64.2. - [Release notes](https://github.com/webpack/webpack/releases) - [Commits](https://github.com/webpack/webpack/compare/v5.24.1...v5.64.2) --- updated-dependencies: - dependency-name: webpack dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- client-admin/package-lock.json | 422 ++++++++++++++++----------------- client-admin/package.json | 2 +- 2 files changed, 211 insertions(+), 213 deletions(-) diff --git a/client-admin/package-lock.json b/client-admin/package-lock.json index a748561b7..0fdf20a07 100644 --- a/client-admin/package-lock.json +++ b/client-admin/package-lock.json @@ -4711,9 +4711,9 @@ } }, "@types/eslint": { - "version": "7.2.6", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.2.6.tgz", - "integrity": "sha512-I+1sYH+NPQ3/tVqCeUSBwTE/0heyvtXqpIopUUArlBm0Kpocb8FbMa3AZ/ASKIFpN3rnEx932TTXDbt9OXsNDw==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.2.0.tgz", + "integrity": "sha512-74hbvsnc+7TEDa1z5YLSe4/q8hGYB3USNvCuzHUJrjPV6hXaq8IXcngCrHkuvFt0+8rFz7xYXrHgNayIX0UZvQ==", "dev": true, "requires": { "@types/estree": "*", @@ -4721,9 +4721,9 @@ } }, "@types/eslint-scope": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.0.tgz", - "integrity": "sha512-O/ql2+rrCUe2W2rs7wMR+GqPRcgB6UiqN5RhrR5xruFlY7l9YLMn0ZkDzjoHLeiFkR8MCQZVudUuuvQ2BLC9Qw==", + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.1.tgz", + "integrity": "sha512-SCFeogqiptms4Fg29WpOTk5nHIzfpKCemSN63ksBQYKTcXoJEmJagV+DhVmbapZzY4/5YaOV1nZwrsU79fFm1g==", "dev": true, "requires": { "@types/eslint": "*", @@ -4731,9 +4731,9 @@ } }, "@types/estree": { - "version": "0.0.46", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.46.tgz", - "integrity": "sha512-laIjwTQaD+5DukBZaygQ79K1Z0jb1bPEMRrkXSLjtCcZm+abyp5YbrqpSLzD42FwWW6gK/aS4NYpJ804nG2brg==", + "version": "0.0.50", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.50.tgz", + "integrity": "sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw==", "dev": true }, "@types/hast": { @@ -4767,9 +4767,9 @@ } }, "@types/node": { - "version": "14.14.31", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.31.tgz", - "integrity": "sha512-vFHy/ezP5qI0rFgJ7aQnjDXwAMrG0KqqIH7tQG5PPv3BWBayOPIQNBjVc/P6hhdZfMx51REc6tfDNXHUio893g==", + "version": "16.11.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.9.tgz", + "integrity": "sha512-MKmdASMf3LtPzwLyRrFjtFFZ48cMf8jmX5VRYrDQiJa8Ybu5VAmkqBWqKU8fdCwD8ysw4mQ9nrEHvzg6gunR7A==", "dev": true }, "@types/parse-json": { @@ -4790,148 +4790,148 @@ "dev": true }, "@webassemblyjs/ast": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.0.tgz", - "integrity": "sha512-kX2W49LWsbthrmIRMbQZuQDhGtjyqXfEmmHyEi4XWnSZtPmxY0+3anPIzsnRb45VH/J55zlOfWvZuY47aJZTJg==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", + "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", "dev": true, "requires": { - "@webassemblyjs/helper-numbers": "1.11.0", - "@webassemblyjs/helper-wasm-bytecode": "1.11.0" + "@webassemblyjs/helper-numbers": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1" } }, "@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.0.tgz", - "integrity": "sha512-Q/aVYs/VnPDVYvsCBL/gSgwmfjeCb4LW8+TMrO3cSzJImgv8lxxEPM2JA5jMrivE7LSz3V+PFqtMbls3m1exDA==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", + "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", "dev": true }, "@webassemblyjs/helper-api-error": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.0.tgz", - "integrity": "sha512-baT/va95eXiXb2QflSx95QGT5ClzWpGaa8L7JnJbgzoYeaA27FCvuBXU758l+KXWRndEmUXjP0Q5fibhavIn8w==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", + "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", "dev": true }, "@webassemblyjs/helper-buffer": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.0.tgz", - "integrity": "sha512-u9HPBEl4DS+vA8qLQdEQ6N/eJQ7gT7aNvMIo8AAWvAl/xMrcOSiI2M0MAnMCy3jIFke7bEee/JwdX1nUpCtdyA==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", + "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", "dev": true }, "@webassemblyjs/helper-numbers": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.0.tgz", - "integrity": "sha512-DhRQKelIj01s5IgdsOJMKLppI+4zpmcMQ3XboFPLwCpSNH6Hqo1ritgHgD0nqHeSYqofA6aBN/NmXuGjM1jEfQ==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", + "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", "dev": true, "requires": { - "@webassemblyjs/floating-point-hex-parser": "1.11.0", - "@webassemblyjs/helper-api-error": "1.11.0", + "@webassemblyjs/floating-point-hex-parser": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", "@xtuc/long": "4.2.2" } }, "@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.0.tgz", - "integrity": "sha512-MbmhvxXExm542tWREgSFnOVo07fDpsBJg3sIl6fSp9xuu75eGz5lz31q7wTLffwL3Za7XNRCMZy210+tnsUSEA==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", + "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", "dev": true }, "@webassemblyjs/helper-wasm-section": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.0.tgz", - "integrity": "sha512-3Eb88hcbfY/FCukrg6i3EH8H2UsD7x8Vy47iVJrP967A9JGqgBVL9aH71SETPx1JrGsOUVLo0c7vMCN22ytJew==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", + "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.11.0", - "@webassemblyjs/helper-buffer": "1.11.0", - "@webassemblyjs/helper-wasm-bytecode": "1.11.0", - "@webassemblyjs/wasm-gen": "1.11.0" + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1" } }, "@webassemblyjs/ieee754": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.0.tgz", - "integrity": "sha512-KXzOqpcYQwAfeQ6WbF6HXo+0udBNmw0iXDmEK5sFlmQdmND+tr773Ti8/5T/M6Tl/413ArSJErATd8In3B+WBA==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", + "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", "dev": true, "requires": { "@xtuc/ieee754": "^1.2.0" } }, "@webassemblyjs/leb128": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.0.tgz", - "integrity": "sha512-aqbsHa1mSQAbeeNcl38un6qVY++hh8OpCOzxhixSYgbRfNWcxJNJQwe2rezK9XEcssJbbWIkblaJRwGMS9zp+g==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", + "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", "dev": true, "requires": { "@xtuc/long": "4.2.2" } }, "@webassemblyjs/utf8": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.0.tgz", - "integrity": "sha512-A/lclGxH6SpSLSyFowMzO/+aDEPU4hvEiooCMXQPcQFPPJaYcPQNKGOCLUySJsYJ4trbpr+Fs08n4jelkVTGVw==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", + "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", "dev": true }, "@webassemblyjs/wasm-edit": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.0.tgz", - "integrity": "sha512-JHQ0damXy0G6J9ucyKVXO2j08JVJ2ntkdJlq1UTiUrIgfGMmA7Ik5VdC/L8hBK46kVJgujkBIoMtT8yVr+yVOQ==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", + "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.11.0", - "@webassemblyjs/helper-buffer": "1.11.0", - "@webassemblyjs/helper-wasm-bytecode": "1.11.0", - "@webassemblyjs/helper-wasm-section": "1.11.0", - "@webassemblyjs/wasm-gen": "1.11.0", - "@webassemblyjs/wasm-opt": "1.11.0", - "@webassemblyjs/wasm-parser": "1.11.0", - "@webassemblyjs/wast-printer": "1.11.0" + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/helper-wasm-section": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-opt": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "@webassemblyjs/wast-printer": "1.11.1" } }, "@webassemblyjs/wasm-gen": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.0.tgz", - "integrity": "sha512-BEUv1aj0WptCZ9kIS30th5ILASUnAPEvE3tVMTrItnZRT9tXCLW2LEXT8ezLw59rqPP9klh9LPmpU+WmRQmCPQ==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", + "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.11.0", - "@webassemblyjs/helper-wasm-bytecode": "1.11.0", - "@webassemblyjs/ieee754": "1.11.0", - "@webassemblyjs/leb128": "1.11.0", - "@webassemblyjs/utf8": "1.11.0" + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" } }, "@webassemblyjs/wasm-opt": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.0.tgz", - "integrity": "sha512-tHUSP5F4ywyh3hZ0+fDQuWxKx3mJiPeFufg+9gwTpYp324mPCQgnuVKwzLTZVqj0duRDovnPaZqDwoyhIO8kYg==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", + "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.11.0", - "@webassemblyjs/helper-buffer": "1.11.0", - "@webassemblyjs/wasm-gen": "1.11.0", - "@webassemblyjs/wasm-parser": "1.11.0" + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1" } }, "@webassemblyjs/wasm-parser": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.0.tgz", - "integrity": "sha512-6L285Sgu9gphrcpDXINvm0M9BskznnzJTE7gYkjDbxET28shDqp27wpruyx3C2S/dvEwiigBwLA1cz7lNUi0kw==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", + "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.11.0", - "@webassemblyjs/helper-api-error": "1.11.0", - "@webassemblyjs/helper-wasm-bytecode": "1.11.0", - "@webassemblyjs/ieee754": "1.11.0", - "@webassemblyjs/leb128": "1.11.0", - "@webassemblyjs/utf8": "1.11.0" + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" } }, "@webassemblyjs/wast-printer": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.0.tgz", - "integrity": "sha512-Fg5OX46pRdTgB7rKIUojkh9vXaVN6sGYCnEiJN1GYkb0RPwShZXp6KTDqmoMdQPKhcroOXh3fEzmkWmCYaKYhQ==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", + "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.11.0", + "@webassemblyjs/ast": "1.11.1", "@xtuc/long": "4.2.2" } }, @@ -5001,6 +5001,12 @@ "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", "dev": true }, + "acorn-import-assertions": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", + "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", + "dev": true + }, "acorn-jsx": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", @@ -5264,9 +5270,9 @@ "dev": true }, "async": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz", - "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.2.tgz", + "integrity": "sha512-H0E+qZaDEfx/FY4t7iLRv1W2fFI6+pyCeTw1uN20AQPiwqwM6ojPxHxdLv4z8hi2DtnW9BOckSspLucW7pIE5g==", "dev": true }, "asynckit": { @@ -5727,9 +5733,9 @@ } }, "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, "builtin-modules": { @@ -5847,13 +5853,10 @@ "dev": true }, "chrome-trace-event": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz", - "integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==", - "dev": true, - "requires": { - "tslib": "^1.9.0" - } + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true }, "class-utils": { "version": "0.3.6", @@ -6599,9 +6602,9 @@ } }, "enhanced-resolve": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.7.0.tgz", - "integrity": "sha512-6njwt/NsZFUKhM6j9U8hzVyD4E4r0x7NQzhTCbcWOJ0IQjNSAoalWmb0AE51Wn+fwan5qVESWi7t2ToBxs9vrw==", + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.8.3.tgz", + "integrity": "sha512-EGAbGvH7j7Xt2nc0E7D99La1OiEs8LnyimkRgwExpUMScN6O+3x9tIWs7PLQZVNx4YD+00skHXPXi1yQHpAmZA==", "dev": true, "requires": { "graceful-fs": "^4.2.4", @@ -6609,9 +6612,9 @@ }, "dependencies": { "graceful-fs": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", + "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", "dev": true } } @@ -6668,9 +6671,9 @@ } }, "es-module-lexer": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.4.0.tgz", - "integrity": "sha512-iuEGihqqhKWFgh72Q/Jtch7V2t/ft8w8IPP2aEN8ArYKO+IWyo6hsi96hCdgyeEDQIV3InhYQ9BlwUFPGXrbEQ==", + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", + "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", "dev": true }, "es-to-primitive": { @@ -7386,9 +7389,9 @@ } }, "events": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.2.0.tgz", - "integrity": "sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", "dev": true }, "execa": { @@ -8570,7 +8573,7 @@ "from": "github:pol-is/gulp-s3#master", "dev": true, "requires": { - "async": "^3.2.0", + "async": "^3.2.2", "event-stream": "*", "gulp-util": "~2.2.6", "knox": "^0.9.2" @@ -9609,14 +9612,14 @@ "dev": true }, "jest-worker": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", - "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.3.1.tgz", + "integrity": "sha512-ks3WCzsiZaOPJl/oMsDjaf0TRiSv7ctNgs0FqRr2nARsovz6AWWy4oLElwcquGSz692DzgZQrCLScPNs5YlC4g==", "dev": true, "requires": { "@types/node": "*", "merge-stream": "^2.0.0", - "supports-color": "^7.0.0" + "supports-color": "^8.0.0" }, "dependencies": { "has-flag": { @@ -9626,9 +9629,9 @@ "dev": true }, "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, "requires": { "has-flag": "^4.0.0" @@ -11418,15 +11421,6 @@ "integrity": "sha512-K5J34NKeGyJvVVHUg4cAWDhtVYzT7UIRE9GbFyqHNZd61Pr0DHNTMsgoID7IVDmKc0QaLswYwKaNR2apbUJvkg==", "dev": true }, - "prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", - "dev": true, - "requires": { - "fast-diff": "^1.1.2" - } - }, "pretty-hrtime": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", @@ -12948,12 +12942,6 @@ } } }, - "source-list-map": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", - "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", - "dev": true - }, "source-map": { "version": "0.5.6", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", @@ -12974,9 +12962,9 @@ } }, "source-map-support": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", - "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "dev": true, "requires": { "buffer-from": "^1.0.0", @@ -13491,20 +13479,20 @@ } }, "tapable": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.0.tgz", - "integrity": "sha512-FBk4IesMV1rBxX2tfiK8RAmogtWn53puLOQlvO8XuwlgxcYbP4mVPS9Ph4aeamSyyVjOl24aYWAuc8U5kCVwMw==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", "dev": true }, "terser": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.6.0.tgz", - "integrity": "sha512-vyqLMoqadC1uR0vywqOZzriDYzgEkNJFK4q9GeyOBHIbiECHiWLKcWfbQWAUaPfxkjDhapSlZB9f7fkMrvkVjA==", + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.10.0.tgz", + "integrity": "sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA==", "dev": true, "requires": { "commander": "^2.20.0", "source-map": "~0.7.2", - "source-map-support": "~0.5.19" + "source-map-support": "~0.5.20" }, "dependencies": { "commander": { @@ -13522,26 +13510,42 @@ } }, "terser-webpack-plugin": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.1.1.tgz", - "integrity": "sha512-5XNNXZiR8YO6X6KhSGXfY0QrGrCRlSwAEjIIrlRQR4W8nP69TaJUlh3bkuac6zzgspiGPfKEHcY295MMVExl5Q==", + "version": "5.2.5", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.2.5.tgz", + "integrity": "sha512-3luOVHku5l0QBeYS8r4CdHYWEGMmIj3H1U64jgkdZzECcSOJAyJ9TjuqcQZvw1Y+4AOBN9SeYJPJmFn2cM4/2g==", "dev": true, "requires": { - "jest-worker": "^26.6.2", - "p-limit": "^3.1.0", - "schema-utils": "^3.0.0", - "serialize-javascript": "^5.0.1", + "jest-worker": "^27.0.6", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.0", "source-map": "^0.6.1", - "terser": "^5.5.1" + "terser": "^5.7.2" }, "dependencies": { - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "@types/json-schema": { + "version": "7.0.9", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", + "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", + "dev": true + }, + "schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + }, + "serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", "dev": true, "requires": { - "yocto-queue": "^0.1.0" + "randombytes": "^2.1.0" } }, "source-map": { @@ -13750,12 +13754,6 @@ } } }, - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -14666,9 +14664,9 @@ } }, "watchpack": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.1.1.tgz", - "integrity": "sha512-Oo7LXCmc1eE1AjyuSBmtC3+Wy4HcV8PxWh2kP6fOl8yTlNS7r0K9l1ao2lrrUza7V39Y3D/BbJgY8VeSlc5JKw==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.2.0.tgz", + "integrity": "sha512-up4YAn/XHgZHIxFBVCdlMiWDj6WaLKpwVeGQk2I5thdYxF/KmF0aaz6TfJZ/hfl1h/XlcDr7k1KH7ThDagpFaA==", "dev": true, "requires": { "glob-to-regexp": "^0.4.1", @@ -14682,22 +14680,23 @@ "dev": true }, "webpack": { - "version": "5.24.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.24.1.tgz", - "integrity": "sha512-eg+6OIt6npUSwbhRQY6XffAixEUSARBf+WAWOxrZwOB4jRbbpMXlridFy/Yt7N0U20Ry1vp/nnDbtN7l1rUdIA==", + "version": "5.64.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.64.2.tgz", + "integrity": "sha512-4KGc0+Ozi0aS3EaLNRvEppfZUer+CaORKqL6OBjDLZOPf9YfN8leagFzwe6/PoBdHFxc/utKArl8LMC0Ivtmdg==", "dev": true, "requires": { "@types/eslint-scope": "^3.7.0", - "@types/estree": "^0.0.46", - "@webassemblyjs/ast": "1.11.0", - "@webassemblyjs/wasm-edit": "1.11.0", - "@webassemblyjs/wasm-parser": "1.11.0", - "acorn": "^8.0.4", + "@types/estree": "^0.0.50", + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/wasm-edit": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "acorn": "^8.4.1", + "acorn-import-assertions": "^1.7.6", "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.7.0", - "es-module-lexer": "^0.4.0", - "eslint-scope": "^5.1.1", + "enhanced-resolve": "^5.8.3", + "es-module-lexer": "^0.9.0", + "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.2.4", @@ -14705,24 +14704,41 @@ "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", - "schema-utils": "^3.0.0", + "schema-utils": "^3.1.0", "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.1.1", - "watchpack": "^2.0.0", - "webpack-sources": "^2.1.1" + "terser-webpack-plugin": "^5.1.3", + "watchpack": "^2.2.0", + "webpack-sources": "^3.2.2" }, "dependencies": { + "@types/json-schema": { + "version": "7.0.9", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", + "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", + "dev": true + }, "acorn": { - "version": "8.0.5", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.0.5.tgz", - "integrity": "sha512-v+DieK/HJkJOpFBETDJioequtc3PfxsWMaxIdIwujtF7FEV/MAyDQLlm6/zPvr7Mix07mLh6ccVwIsloceodlg==", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.6.0.tgz", + "integrity": "sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw==", "dev": true }, "graceful-fs": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", + "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", "dev": true + }, + "schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } } } }, @@ -14897,22 +14913,10 @@ } }, "webpack-sources": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-2.2.0.tgz", - "integrity": "sha512-bQsA24JLwcnWGArOKUxYKhX3Mz/nK1Xf6hxullKERyktjNMC4x8koOeaDNTA2fEJ09BdWLbM/iTW0ithREUP0w==", - "dev": true, - "requires": { - "source-list-map": "^2.0.1", - "source-map": "^0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.2.tgz", + "integrity": "sha512-cp5qdmHnu5T8wRg2G3vZZHoJPN14aqQ89SyQ11NpGH5zEMDCclt49rzo+MaRazk7/UeILhAI+/sEtcM+7Fr0nw==", + "dev": true }, "which": { "version": "1.3.1", @@ -15011,12 +15015,6 @@ "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.0.tgz", "integrity": "sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg==" }, - "yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true - }, "zwitch": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz", diff --git a/client-admin/package.json b/client-admin/package.json index b2b89724a..7f5401170 100644 --- a/client-admin/package.json +++ b/client-admin/package.json @@ -51,7 +51,7 @@ "request": "^2.88.2", "rimraf": "^3.0.2", "run-sequence": "~2.2.1", - "webpack": "^5.24.1", + "webpack": "^5.64.2", "webpack-bundle-analyzer": "^4.4.0", "webpack-cli": "^4.5.0", "webpack-dev-middleware": "^4.1.0" From c3f907e1c159cfcd0dabed9f5eccfce41276078a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 28 Nov 2021 12:01:35 -0800 Subject: [PATCH 03/17] Bump node from 16.9.0-alpine to 17.1.0-alpine in /file-server (#1202) Bumps node from 16.9.0-alpine to 17.1.0-alpine. --- updated-dependencies: - dependency-name: node dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- file-server/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/file-server/Dockerfile b/file-server/Dockerfile index 5bdeb3f64..185c28066 100644 --- a/file-server/Dockerfile +++ b/file-server/Dockerfile @@ -4,7 +4,7 @@ FROM compdem/polis-client-admin:${TAG} as admin FROM compdem/polis-client-participation:${TAG} as participation FROM compdem/polis-client-report:${TAG} as report -FROM node:16.9.0-alpine +FROM node:17.1.0-alpine WORKDIR /app From 8411e7b327847c694ceca91ebc6ab3489cfb3269 Mon Sep 17 00:00:00 2001 From: Patrick Connolly Date: Sun, 28 Nov 2021 17:37:51 -0500 Subject: [PATCH 04/17] Removed last references to xip.io from codebase. (#1219) --- CONTRIBUTING.md | 4 ++-- Makefile | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 175bd8a45..e823f2f2e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -38,11 +38,11 @@ make e2e-run-minimal If for whatever reason, Docker is serving your application from a remote IP or URL instead of `http://127.0.0.1`, then there are work-arounds: ``` -make e2e-run-minimal BASEURL=https://123.45.67.89.xip.io +make e2e-run-minimal BASEURL=https://123.45.67.89.sslip.io make e2e-run-minimal BASEURL=https://mydomain.dev # Won't work right now ``` -(Specifically, [xip.io](https://xip.io) is a free third-party support service that allows any IP to "pretend" it's a domain. +(Specifically, [sslip.io](https://sslip.io) is a free third-party support service that allows any IP to "pretend" it's a domain. There is currently a hardcoded "allow list" in the codebase, that lets this service work in the "development mode" that our Docker environment currently uses.) diff --git a/Makefile b/Makefile index 13aa9a64d..500ac6139 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -BASEURL ?= https://127.0.0.1.xip.io +BASEURL ?= https://127.0.0.1.sslip.io E2E_RUN = cd e2e; CYPRESS_BASE_URL=$(BASEURL) pull: ## Pull most recent Docker container builds (nightlies) From 8764a8ccc0d318e4928f4f7bebae990695f7d477 Mon Sep 17 00:00:00 2001 From: Patrick Connolly Date: Thu, 2 Dec 2021 13:41:52 -0500 Subject: [PATCH 05/17] Upped bundlewatch limit for client-participation polis.js bundle from 140kb to 150 kb. --- .bundlewatch.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.bundlewatch.config.js b/.bundlewatch.config.js index 208e1e667..62be5bb91 100644 --- a/.bundlewatch.config.js +++ b/.bundlewatch.config.js @@ -15,7 +15,7 @@ module.exports = { }, { "path": "client-participation/dist/cached/*/js/polis.js", - "maxSize": "140 kB", + "maxSize": "150 kB", }, { "path": "client-participation/dist/cached/*/js/vis_bundle.js", From 2e918a1809978abcc24f94b32184ebd5420f92a5 Mon Sep 17 00:00:00 2001 From: Patrick Connolly Date: Thu, 2 Dec 2021 13:47:37 -0500 Subject: [PATCH 06/17] Started running bundlewatch for changes to client-participation. --- .github/workflows/bundlewatch.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/bundlewatch.yml b/.github/workflows/bundlewatch.yml index e9ec2aa09..f988aba48 100644 --- a/.github/workflows/bundlewatch.yml +++ b/.github/workflows/bundlewatch.yml @@ -4,15 +4,16 @@ on: push: # Required so that baseline for comparison is pushed to bundlewatch service. branches: ["dev"] - # Note: Only configured for client-admin right now. paths: - .github/workflows/bundlewatch.yml - client-admin/** + - client-participation/** pull_request: types: ["opened", "reopened", "synchronize"] paths: - .github/workflows/bundlewatch.yml - client-admin/** + - client-participation/** jobs: bundlewatch: From 3204a885fbdf08ce12491bf55147ba9a68b08af1 Mon Sep 17 00:00:00 2001 From: Patrick Connolly Date: Thu, 2 Dec 2021 15:55:57 -0500 Subject: [PATCH 07/17] Removed unused bootstrap@3.4.1 dependency. --- client-participation/package-lock.json | 5 ----- client-participation/package.json | 1 - 2 files changed, 6 deletions(-) diff --git a/client-participation/package-lock.json b/client-participation/package-lock.json index c1552cef9..32384e5c4 100644 --- a/client-participation/package-lock.json +++ b/client-participation/package-lock.json @@ -1219,11 +1219,6 @@ "resolved": "https://registry.npmjs.org/boolean/-/boolean-0.1.3.tgz", "integrity": "sha512-G6TadQPFofmOhzkzgtVSOYaosjpnPyVCDeZ4J7oPF74OmhM2++fXUdwu7NULTwgntK5KIMcls1UslwAY2btL6g==" }, - "bootstrap": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-3.4.1.tgz", - "integrity": "sha512-yN5oZVmRCwe5aKwzRj6736nSmKDX7pLYwsXiCj/EYmo16hODaBiT4En5btW/jhBF/seV+XMx3aYwukYC3A49DA==" - }, "bootstrap-sass": { "version": "3.4.1", "resolved": "https://registry.npmjs.org/bootstrap-sass/-/bootstrap-sass-3.4.1.tgz", diff --git a/client-participation/package.json b/client-participation/package.json index 9cfd41376..bdf22f58b 100644 --- a/client-participation/package.json +++ b/client-participation/package.json @@ -14,7 +14,6 @@ "autosize": "^3.0.3", "backbone": "github:pol-is/backbone#polis", "boolean": "^0.1.3", - "bootstrap": "^3.4.1", "bootstrap-sass": "^3.4.1", "brain": "~0.6.3", "combine-css": "0.0.2", From ecaedec6331285e270a9fe57836a150efc523ddc Mon Sep 17 00:00:00 2001 From: Patrick Connolly Date: Fri, 3 Dec 2021 19:18:51 -0500 Subject: [PATCH 08/17] e2e: Added check for hull in kitchensink. (#1227) --- client-participation/vis2/components/hull.js | 1 + .../polis/client-participation/kitchensink.spec.js | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/client-participation/vis2/components/hull.js b/client-participation/vis2/components/hull.js index a61cb3608..06751595e 100644 --- a/client-participation/vis2/components/hull.js +++ b/client-participation/vis2/components/hull.js @@ -7,6 +7,7 @@ class Hull extends React.Component { return ( {this.props.handleClick(this.props.gid)}} d={this.props.pathString} ref={this.props.getHullElems(this.props.gid)} diff --git a/e2e/cypress/integration/polis/client-participation/kitchensink.spec.js b/e2e/cypress/integration/polis/client-participation/kitchensink.spec.js index 8768ad8fa..93c24f0a8 100644 --- a/e2e/cypress/integration/polis/client-participation/kitchensink.spec.js +++ b/e2e/cypress/integration/polis/client-participation/kitchensink.spec.js @@ -63,9 +63,9 @@ describe('Kitchen Sink Participation', () => { // Confirm visualization does show after 7 participants. submitVotes(['DDD'], this.convoId) - cy.wait(2000) + cy.wait(4000) cy.get('#vis_not_yet_label').should('not.be.visible') cy.get('#vis2_root > div').should('exist') - + cy.get('[data-testid="hull-0"]').should('exist') }) }) From 60d2ee6804d8911e48e1f782577cf49c48032093 Mon Sep 17 00:00:00 2001 From: Patrick Connolly Date: Fri, 3 Dec 2021 19:19:08 -0500 Subject: [PATCH 09/17] Improvements to e2e tests (#1229) * Added make target e2e-run-subset to more easily run a single test. * Reduced compression on videos so stored CI videos are easier to diagnose. * Started using kitchensink e2e test as the minimal smoke test. * Moved e2e command into npm script, and improved doc. --- CONTRIBUTING.md | 6 ++++++ Makefile | 5 ++++- e2e/cypress.json | 1 + e2e/package.json | 5 +++-- 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e823f2f2e..cfbd1585e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -35,6 +35,12 @@ You can then run a minimal test suite with: make e2e-run-minimal ``` +You can also run a subset of tests (even just one) with: + +``` +make e2e-run-subset TEST_FILTER=kitchensink +``` + If for whatever reason, Docker is serving your application from a remote IP or URL instead of `http://127.0.0.1`, then there are work-arounds: ``` diff --git a/Makefile b/Makefile index 500ac6139..c5a351281 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ e2e-prepare: ## Prepare to run Cypress E2E tests @# Testing embeds requires a override of a file prior to build. cp e2e/cypress/fixtures/html/embed.html client-admin/embed.html -e2e-run-minimal: ## Run E2E tests: minimal (for nightly builds) +e2e-run-minimal: ## Run E2E tests: minimal (smoke test) $(E2E_RUN) npm run e2e:minimal e2e-run-standalone: ## Run E2E tests: standalone (no credentials required) @@ -26,6 +26,9 @@ e2e-run-standalone: ## Run E2E tests: standalone (no credentials required) e2e-run-secret: ## Run E2E tests: secret (credentials required) $(E2E_RUN) npm run e2e:secret +e2e-run-subset: ## Run E2E tests: filter tests by TEST_FILTER envvar (without browser exit) + $(E2E_RUN) npm run e2e:subset + e2e-run-all: ## Run E2E tests: all $(E2E_RUN) npm run e2e:all diff --git a/e2e/cypress.json b/e2e/cypress.json index a2f103a8d..388874b0a 100644 --- a/e2e/cypress.json +++ b/e2e/cypress.json @@ -1,5 +1,6 @@ { "chromeWebSecurity": false, + "videoCompression": 15, "apiPath": "/api/v3", "ignoreTestFiles": "**/examples/*.spec.js", "baseUrl": "http://localhost" diff --git a/e2e/package.json b/e2e/package.json index 39c1adf5c..2dbdd9052 100644 --- a/e2e/package.json +++ b/e2e/package.json @@ -9,9 +9,10 @@ "lint:fix": "eslint --fix .", "test": "npm run e2e:all", "e2e:all": "cypress run --spec 'cypress/integration/polis/**' --browser=chrome", - "e2e:minimal": "cypress run --spec '**/polis/**/!(*.secrets).spec.js,!**/embeds.spec.js' --browser=chrome", + "e2e:minimal": "cypress run --spec '**/kitchensink.spec.js' --browser=chrome", "e2e:standalone": "cypress run --spec '**/polis/**/!(*.secrets).spec.js' --browser=chrome", - "e2e:secret": "cypress run --spec '**/(*.secrets).spec.js' --browser=chrome" + "e2e:secret": "cypress run --spec '**/(*.secrets).spec.js' --browser=chrome", + "e2e:subset": "cypress run --spec **/*${TEST_FILTER:-kitchensink}*.spec.js --browser=chrome --no-exit" }, "author": "Benjamin Rosas ", "devDependencies": { From 56a9fc98214a43202b28599a776e81cb1192dba8 Mon Sep 17 00:00:00 2001 From: Dominik Vagala Date: Sat, 4 Dec 2021 17:35:14 +0100 Subject: [PATCH 10/17] update Slovak translation --- client-participation/js/strings/sk.js | 72 +++++++++++++-------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/client-participation/js/strings/sk.js b/client-participation/js/strings/sk.js index 38cec3057..830134a32 100644 --- a/client-participation/js/strings/sk.js +++ b/client-participation/js/strings/sk.js @@ -21,7 +21,7 @@ s.modSubmit = "Hotovo, ďalší výrok"; s.x_wrote = "napísal/a:"; s.x_tweeted = "tweetol/a:"; s.comments_remaining = "{{num_comments}} zostávajúcich"; -s.comments_remaining2 = "{{num_comments}} zostávajúcich výrokov"; +s.comments_remaining2 = "{{num_comments}} zostávajúcich komentárov"; s.group_123 = "Skupina:"; s.comment_123 = "Výrok:"; s.majorityOpinion = "Väčšinový názor"; @@ -30,65 +30,65 @@ s.info = "Info"; s.addPolisToYourSite = ""; s.privacy = "Súkromie"; s.TOS = "TOS"; -s.writePrompt = "Zdieľajte váš názor, či návrh na riešenie problému..."; +s.writePrompt = "Zdieľajte váš názor, či návrh na riešenie..."; s.anonPerson = "Anonym"; s.helpWhatAmISeeingTitle = "Čo vidím?"; s.helpWhatAmISeeing = "Ľudia, ktorí hlasovali podobne sú zoskupení v skupinách nižšie. Kliknite na konkrétnu skupinu pre zobrazenie ich názorov a postojov."; s.helpWhatDoIDoTitle = " Čo mám spraviť?"; s.helpWhatDoIDo = "Hlasujte o ostatných návrhoch kliknutím na 'súhlasím' alebo 'nesúhlasím'. Napíšte váš názor a pozvite svojich priateľov do diskusie!"; -s.writeCommentHelpText = "Chýbajú vám v diskusii vaše skúsenosti, návrhy alebo názory? Ak áno, zadajte ich do políčka nižšie."; -s.helpWriteListIntro = "Čo tvorí dobrý návrh?"; +s.writeCommentHelpText = "Chýbajú vám v diskusii vaše skúsenosti s problémom či návrhy na jeho riešenie? Neváhajte ich zadať do políčka nižšie."; +s.helpWriteListIntro = "Čo tvorí dobrý komentár?"; s.helpWriteListStandalone = "Samostatná myšlienka"; -s.helpWriteListRaisNew = "Originálna perspektíva, či skúsenosť"; -s.helpWriteListShort = "Zreteľný obsah a stručný opis (maximálne 140 znakov)"; +s.helpWriteListRaisNew = "Originálna perspektíva, či prehliadaný uhol pohľadu na vec"; +s.helpWriteListShort = "Zreteľný návrh a stručné odôvodnenie (maximálne 140 znakov)"; s.heresHowGroupVoted = "Takto hlasovala skupina {{GROUP_NUMBER}}:"; s.one_person = "{{x}} osoba"; s.x_people = "{{x}} osoby"; -s.acrossAllPtpts = "Naprieč všetkými účastníkmi:"; +s.acrossAllPtpts = "Naprieč všetkými diskutujúcimi:"; s.xPtptsSawThisComment = " videlo tento výrok"; -s.xOfThoseAgreed = "z týchto účastníkov súhlasilo"; -s.xOfthoseDisagreed = "z týchto účastníkov nesúhlasilo"; +s.xOfThoseAgreed = "z týchto diskutujúcich súhlasilo"; +s.xOfthoseDisagreed = "z týchto diskutujúcich nesúhlasilo"; s.opinionGroups = "Názorové skupiny"; s.topComments = "Top výroky"; s.divisiveComments = "Polarizujúce výroky"; s.pctAgreed = "{{pct}}% Súhlasilo"; s.pctDisagreed = "{{pct}}% Nesúhlasilo"; -s.pctAgreedLong = "{{pct}}% zo všetkých hlasujúcich o tomto výroku {{comment_id}} súhlasilo."; +s.pctAgreedLong = "{{pct}}% zo všetkých hlasujúcich o výroku {{comment_id}} súhlasilo."; s.pctAgreedOfGroup = "{{pct}}% zo skupiny {{group}} súhlasilo"; s.pctDisagreedOfGroup = "{{pct}}% zo skupiny {{group}} nesúhlasilo"; -s.pctDisagreedLong = "{{pct}}% zo všetkých hlasujúcich o tomto výroku {{comment_id}} nesúhlasilo."; +s.pctDisagreedLong = "{{pct}}% zo všetkých hlasujúcich o výroku {{comment_id}} nesúhlasilo."; s.pctAgreedOfGroupLong = "{{pct}}% zo skupiny {{group}}, ktorí hlasovali za výrok {{comment_id}} súhlasilo."; s.pctDisagreedOfGroupLong = "{{pct}}% zo skupiny {{group}}, ktorí hlasovali za výrok {{comment_id}} nesúhlasilo."; -s.commentSent = "Výrok úspešne pridaný! Váš názor a to, ako ste hlasovali uvidia ostatní účastníci diskusie."; +s.commentSent = "Komentár úspešne pridaný! Váš názor a to ako ste hlasovali uvidia len ostatní diskutujúci."; s.commentSendFailed = "Chyba pri zadaní výroku."; -s.commentSendFailedEmpty = "Chyba pri zadaní výroku - Políčko pre výrok nemôže byť prázdne."; -s.commentSendFailedTooLong = "Chyba pri zadaní výroku - Výrok príliš dlhý."; -s.commentSendFailedDuplicate = "Chyba pri zadaní výroku - Už existuje identický výrok."; -s.commentErrorDuplicate = "Duplikát! Tento výrok už existuje."; -s.commentErrorConversationClosed = "Táto diskusia už bola uzatvorená. Ďalšie názory už nemôžu byť pridané."; -s.commentIsEmpty = "Výrok je prázdny"; -s.commentIsTooLong = "Výrok je pridlhý"; -s.hereIsNextStatement = "Váš hlas bol úspešne zaznamenaný. Prejdite vyššie pre zobrazenie ďalšieho výroku."; +s.commentSendFailedEmpty = "Chyba pri zadaní komentáru - Políčko pre komentár nemôže byť prázdne."; +s.commentSendFailedTooLong = "Chyba pri zadaní komentáru - Komentár príliš dlhý."; +s.commentSendFailedDuplicate = "Chyba pri zadaní komentáru - Už existuje identický komentár."; +s.commentErrorDuplicate = "Duplikát! Tento komentár už existuje."; +s.commentErrorConversationClosed = "Táto diskusia bola uzatvorená. Ďalšie komentáre už nemôžu byť zadané."; +s.commentIsEmpty = "Komentár je prázdny"; +s.commentIsTooLong = "Komentár je príliš dlhý"; +s.hereIsNextStatement = "Váš hlas bol úspešne zaznamenaný. Prejdite vyššie pre zobrazenie ďalšieho komentáru."; -s.connectFacebook = "Pripoj Facebook"; -s.connectTwitter = "Pripoj Twitter"; -s.connectToPostPrompt = "Pridaj svoju identitu pre zaznamenanie výroku. Na vašu časovú os nebudeme pridávať žiadne príspevky."; -s.connectToVotePrompt = "Pridaj svoju identitu pre hlasovanie. Na vašu časovú os nebudeme pridávať žiadne príspevky."; +s.connectFacebook = "Prepojiť Facebook"; +s.connectTwitter = "Prepojiť Twitter"; +s.connectToPostPrompt = "Prepojte svoju profil pre zadanie komentáru. Na vašu časovú os nebudeme pridávať žiadne príspevky."; +s.connectToVotePrompt = "Prepojte svoju profil pre hlasovanie. Na vašu časovú os nebudeme pridávať žiadne príspevky."; s.tip = "Tip:"; s.commentWritingTipsHintsHeader = "Tipy pre písanie výrokov"; s.tipCharLimit = "Výroky sú limitované na {{char_limit}} znakov."; -s.tipCommentsRandom = "Návrhy sú zobrazované náhodne. Vaše návrhy sú všeobecné a nepredstavujú odpoveď na výroky ostatných účastníkov."; -s.tipOneIdea = "Rozložte dlhé výroky obsahujúce viacero myšlienok. Ostatným účatníkom sa tak bude ľahšie hlasovať o vašom výroku."; +s.tipCommentsRandom = "Návrhy sa zobrazujú náhodne. Vaše návrhy sú nezávislými komentármi a nepredstavujú odpoveď na komentáre ostatných diskutujúcich."; +s.tipOneIdea = "Rozložte dlhé výroky obsahujúce viacero myšlienok. Ostatným účastníkom sa tak bude ľahšie hlasovať o vašom výroku."; s.tipNoQuestions = 'Výroky by nemali byť v podobe otázok. Účastníci budú hlasovať "súhlasím" alebo "nesúhlasím" o vašich výrokoch.'; s.commentTooLongByChars = "Limit dĺžky výroku presiahnutý o {{CHARACTERS_COUNT}} znakov."; s.notSentSinceDemo = "(not really, this is a demo)"; s.submitComment = "Zdieľať"; s.tipStarred = "Označené ako dôležité."; -s.participantHelpWelcomeText = "Vitajte v novom druhu online diskusie - hlasujte o návrhoch a pridajte svoje vlastné. Len tak sa priblížime ku konsenzu"; -s.participantHelpGroupsText = "Účastníci, ktorí hlasovali podobne sú zoskupení. Kliknite na skupinu pre zobrazenie názorov, ktoré zdieľajú. ...ďalšie"; +s.participantHelpWelcomeText = "Vitajte v novom druhu online diskusie - hlasujte o návrhoch a zdieľajte vaše názory a skúsenosti. Len tak sa priblížime sa ku konsenzu"; +s.participantHelpGroupsText = "Diskutujúci, ktorí hlasovali podobne sú zoskupení v názorových skupinách. Kliknite na jednotlivú skupinu pre zobrazenie názorov, ktoré zastávajú. ...ďalšie"; s.participantHelpGroupsNotYetText = "Vizualizácia sa zobrazí keď 7 účastníkov začalo hlasovať"; -s.helpWhatAreGroupsDetail = '

Pravdepodobne ste už videli "odporúčané produkty" na Amazone, alebo "odporúčané filmy" na Netflixe. Všetky tieto internetové služby využívajú štatistiku na zoskupenie uživateľov, ktorí kupujú, či sledujú podobné veci. Tieto služby im následne odporúčajú produkty, ktoré si ľudia z ich skupiny už kúpili, či pozreli.

Keď účastník konverzácie hlasuje o jednotlivých komentároch, tak algoritmus ho zoskupí s účastníkmi, ktorí hlasovali podobne. Grafické vyobrazenie týchto skupín môžte vidieť nižšie. Každá skupina je zložená z ľudí, kotrí majú podobný názor na problematiku. Práve to nám umožňuje viesť konštruktívnu diskusiu a zistiť unikátne poznatky. Neváhajte, kliknite na ľubovolnú skupinu nižšie a zistite čo nás rozdeľuje a čo spája.

'; -s.socialConnectPrompt = "Môžte si pripojiť svoj účet, aby ste vo vizualizácii videli vašich priateľov a ľudí, ktorých sledujete."; +s.helpWhatAreGroupsDetail = '

Pravdepodobne ste už videli "odporúčané produkty" na Amazone, alebo "odporúčané filmy" na Netflixe. Všetky tieto internetové služby využívajú štatistiku na zoskupenie uživateľov, ktorí kupujú, či sledujú podobné veci. Tieto služby im následne odporúčajú produkty, ktoré si ľudia z ich skupiny už kúpili či pozreli.

Keď účastník konverzácie hlasuje o jednotlivých komentároch, tak algoritmus ho zoskupí s účastníkmi, ktorí hlasovali podobne. Grafické vyobrazenie týchto skupín môžte vidieť nižšie. Každá skupina je zložená z ľudí, kotrí majú podobný názor na vec. Práve to nám umožňuje viesť konštruktívnu diskusiu a prehľadne zistiť čo si veľké skupiny ľudí myslia. Neváhajte, kliknite na ľubovolnú skupinu nižšie a zistite čo nás rozdeľuje a čo spája.

'; +s.socialConnectPrompt = "Optionally connect to see friends and people you follow in the visualization."; s.connectFbButton = "Pripojte sa s Facebookom"; s.connectTwButton = "Pripojte sa s Twitterom"; s.polis_err_reg_fb_verification_email_sent = "Prosím, verifikujte váš mail a následne sa sem vráťte pre pokračovanie."; @@ -103,12 +103,12 @@ s.notificationsEnterEmail = "Zadajte vašu emailovú adresu, aby ste boli upoved s.labelEmail = "Email"; s.notificationsSubscribeButton = "Prihlásiť sa na odber"; s.notificationsSubscribeErrorAlert = "Chyba prihlásenia"; -s.noCommentsYet = "Zatiaľ tu nie sú žiadne výroky."; -s.noCommentsYetSoWrite = "Rozprúďte konverzáciu pridaním výroku."; -s.noCommentsYetSoInvite = "Rozprúďte konverzáciu pozvaním ďalších účastníkov, alebo pridajte výrok."; -s.noCommentsYouVotedOnAll = "Zahlasovali ste za všetky výroky."; -s.noCommentsTryWritingOne = "Ak by ste chceli niečo pridať, napíšte váš vlastný výrok."; -s.convIsClosed = "Táto konverzácia je už uzavretá."; +s.noCommentsYet = "Zatiaľ tu nie sú žiadne komentáre."; +s.noCommentsYetSoWrite = "Rozprúďte konverzáciu pridaním komentárom."; +s.noCommentsYetSoInvite = "Rozprúďte konverzáciu pozvaním ďalších diskutujúcich, alebo pridajte svoj komentár."; +s.noCommentsYouVotedOnAll = "Zahlasovali ste za všetky komentáre."; +s.noCommentsTryWritingOne = "Ak chcete zdieľať váš názor, napíšte vlastný komentár."; +s.convIsClosed = "Táto konverzácia je uzavretá."; s.noMoreVotingAllowed = "Hlasovanie už nie je povolené."; From 539c9607a1a4fcabafc888db2cd0d1f02b9f6886 Mon Sep 17 00:00:00 2001 From: Dominik Vagala Date: Sun, 5 Dec 2021 14:47:27 +0100 Subject: [PATCH 11/17] fix english socialPrompt --- client-participation/js/strings/sk.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client-participation/js/strings/sk.js b/client-participation/js/strings/sk.js index 830134a32..8d3f97fa0 100644 --- a/client-participation/js/strings/sk.js +++ b/client-participation/js/strings/sk.js @@ -88,7 +88,7 @@ s.participantHelpWelcomeText = "Vitajte v novom druhu online diskusie - hlas s.participantHelpGroupsText = "Diskutujúci, ktorí hlasovali podobne sú zoskupení v názorových skupinách. Kliknite na jednotlivú skupinu pre zobrazenie názorov, ktoré zastávajú. ...ďalšie"; s.participantHelpGroupsNotYetText = "Vizualizácia sa zobrazí keď 7 účastníkov začalo hlasovať"; s.helpWhatAreGroupsDetail = '

Pravdepodobne ste už videli "odporúčané produkty" na Amazone, alebo "odporúčané filmy" na Netflixe. Všetky tieto internetové služby využívajú štatistiku na zoskupenie uživateľov, ktorí kupujú, či sledujú podobné veci. Tieto služby im následne odporúčajú produkty, ktoré si ľudia z ich skupiny už kúpili či pozreli.

Keď účastník konverzácie hlasuje o jednotlivých komentároch, tak algoritmus ho zoskupí s účastníkmi, ktorí hlasovali podobne. Grafické vyobrazenie týchto skupín môžte vidieť nižšie. Každá skupina je zložená z ľudí, kotrí majú podobný názor na vec. Práve to nám umožňuje viesť konštruktívnu diskusiu a prehľadne zistiť čo si veľké skupiny ľudí myslia. Neváhajte, kliknite na ľubovolnú skupinu nižšie a zistite čo nás rozdeľuje a čo spája.

'; -s.socialConnectPrompt = "Optionally connect to see friends and people you follow in the visualization."; +s.socialConnectPrompt = "Môžte si pripojiť svoj účet, aby ste vo vizualizácii videli vašich priateľov a ľudí, ktorých sledujete."; s.connectFbButton = "Pripojte sa s Facebookom"; s.connectTwButton = "Pripojte sa s Twitterom"; s.polis_err_reg_fb_verification_email_sent = "Prosím, verifikujte váš mail a následne sa sem vráťte pre pokračovanie."; From 4eb6cdf183a12e0797f7611efba473aa092c2aba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Dec 2021 06:04:15 +0000 Subject: [PATCH 12/17] Bump node from 17.1.0-alpine to 17.2.0-alpine in /file-server Bumps node from 17.1.0-alpine to 17.2.0-alpine. --- updated-dependencies: - dependency-name: node dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- file-server/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/file-server/Dockerfile b/file-server/Dockerfile index 185c28066..462aa922d 100644 --- a/file-server/Dockerfile +++ b/file-server/Dockerfile @@ -4,7 +4,7 @@ FROM compdem/polis-client-admin:${TAG} as admin FROM compdem/polis-client-participation:${TAG} as participation FROM compdem/polis-client-report:${TAG} as report -FROM node:17.1.0-alpine +FROM node:17.2.0-alpine WORKDIR /app From 9a294140bbfc50d5bbb50ce4e474f4ad72541881 Mon Sep 17 00:00:00 2001 From: Patrick Connolly Date: Mon, 13 Dec 2021 18:47:54 -0500 Subject: [PATCH 13/17] [extended] convert server/ to TypeScript (#1232) * npm i typescript * npm install typescript --save-dev * add tsconfig.json * configure tsconfig, add build script, ignore dist dir * add license in packaged.json * npm i --save-dev @types/node * convert config.ts to typescript * add npm run type:check:watch command * convert log.ts with inferred types * npm i --save-dev @types/underscore * Revert "npm i --save-dev @types/underscore" This reverts commit 0ef521b5b1bf93a0057f389556be2b8fd77dab63. * npm i --save-dev @types/underscore * fix errors in log.ts * add type declaration for google-cloud__translate * declare module 'boolean'; * convert comments * Revert "convert comments" This reverts commit c7f7e87c6cde2287f2e4549dc7d1ca7902538546. * rename comment.js --> comment.ts * convert comment * common.js -> common.ts * type utils/common * constants.js -> constants.ts * cookies.js -> cookies.ts * type cookies * metered.js -> metered.ts * type metered.ts * first pass type parameter.ts * senders.js -> senders.ts * convert email/senders * password.js --> password.ts * convert auth/password * create-user.js -> create-user.ts * convert auth/create-user * sql.js --> sql.ts * pg-query.js -> pg-query.ts * prefer ts-ignore * prettier format remaining js files with vscode prettier plugin * npm i --save-dev prettier * add prettier npm scripts and config * check formatting in npm run test script * session.js --> session.ts * type session * user.js --> user.ts * add default export for log * sort imports for user * 0 ts errors for user * conversation.js --> conversation.ts * first pass at types for conversation. convert exports for user and conversation to ES2020 * server.js -> server.ts * infer all types from usage for server * use intermediate variable with type string[] to ensure that filename is in fact always a string and only a string * server down to 355 ts errors * down to 230 errors in server.ts * fix object is possibly undefined errors. 218 ts errors in server.ts * 143 errors in server.ts * 132 errors, fix string | undefined errors * 132 errors, fix deleted property must be optional errors * 129 errors, fix Type 'undefined' cannot be used as an index type * use intermediate variables to clean up referrer decoding * first refParts, then resultRef * add missing METRICS_IN_RAM import * fix Argument of type 'string | any[]'... errors * fix type mismatch in fb auth function * fix new expression which lacks context types error * widen User type * fix expected number of arguments errors * fix Object is possibly null errors * fix Cannot find name err errors * fix does not exist on type string errors * untangle User and Conversation, fix collision between types and non-stander PascalCase imports * fix property does not exist on error * add Demo type * fix possibly undefined * add Vote type * add Assignment type * 20 errors in server * 9 errors in server.ts * 0 errors in server.ts * app.js -> app.ts * install missing types for bluebird and express libraries * add @ts-nocheck and comment about refactoring for app.ts * convert all module.exports and requires to import, export syntax. back up to 186 typescript errors * add types for fb * ignore new expression whose target lacks a construct signature errors for now * down to 111 typescript errors * fix argument of type typescript errors * label object is of type unknown errors * 0 typescript errors * npm i typescript * npm install typescript --save-dev * add tsconfig.json * configure tsconfig, add build script, ignore dist dir * add license in packaged.json * npm i --save-dev @types/node * convert config.ts to typescript * add npm run type:check:watch command * convert log.ts with inferred types * npm i --save-dev @types/underscore * Revert "npm i --save-dev @types/underscore" This reverts commit 0ef521b5b1bf93a0057f389556be2b8fd77dab63. * npm i --save-dev @types/underscore * fix errors in log.ts * add type declaration for google-cloud__translate * declare module 'boolean'; * convert comments * Revert "convert comments" This reverts commit c7f7e87c6cde2287f2e4549dc7d1ca7902538546. * rename comment.js --> comment.ts * convert comment * common.js -> common.ts * type utils/common * constants.js -> constants.ts * cookies.js -> cookies.ts * type cookies * metered.js -> metered.ts * type metered.ts * first pass type parameter.ts * senders.js -> senders.ts * convert email/senders * password.js --> password.ts * convert auth/password * create-user.js -> create-user.ts * convert auth/create-user * sql.js --> sql.ts * pg-query.js -> pg-query.ts * prefer ts-ignore * prettier format remaining js files with vscode prettier plugin * npm i --save-dev prettier * add prettier npm scripts and config * check formatting in npm run test script * session.js --> session.ts * type session * user.js --> user.ts * add default export for log * sort imports for user * 0 ts errors for user * conversation.js --> conversation.ts * first pass at types for conversation. convert exports for user and conversation to ES2020 * server.js -> server.ts * infer all types from usage for server * use intermediate variable with type string[] to ensure that filename is in fact always a string and only a string * server down to 355 ts errors * down to 230 errors in server.ts * fix object is possibly undefined errors. 218 ts errors in server.ts * 143 errors in server.ts * 132 errors, fix string | undefined errors * 132 errors, fix deleted property must be optional errors * 129 errors, fix Type 'undefined' cannot be used as an index type * use intermediate variables to clean up referrer decoding * first refParts, then resultRef * add missing METRICS_IN_RAM import * fix Argument of type 'string | any[]'... errors * fix type mismatch in fb auth function * fix new expression which lacks context types error * widen User type * fix expected number of arguments errors * fix Object is possibly null errors * fix Cannot find name err errors * fix does not exist on type string errors * untangle User and Conversation, fix collision between types and non-stander PascalCase imports * fix property does not exist on error * add Demo type * fix possibly undefined * add Vote type * add Assignment type * 20 errors in server * 9 errors in server.ts * 0 errors in server.ts * app.js -> app.ts * install missing types for bluebird and express libraries * add @ts-nocheck and comment about refactoring for app.ts * convert all module.exports and requires to import, export syntax. back up to 186 typescript errors * add types for fb * ignore new expression whose target lacks a construct signature errors for now * down to 111 typescript errors * fix argument of type typescript errors * label object is of type unknown errors * 0 typescript errors * update Procfile to include build step and dist dir * update pg-connection-string from v2.0.0 to v2.5.0 * fix pgConnectionString arg undefined bug * disambiguate pg postgress library and dbPgQuery custom wrapper * add npm run start script for server * update to intercom-client@2.11.2 * add build:watch script * add additional check that process.env.INTERCOM_ACCESS_TOKEN is defined before trying to create a new Intercom client * run build as part of start script, add new run:dev script * add npm install to start command * run:dev --> serve:dev * fix makefile and dockerfile, remove xip.io, run build and use dist dir * rename serve:dev serve * call npm run serve in dockerfile * fix typescript config * fix usage of npm run serve in start command * move build command to later in server dockerfile * switch back to CommonJS bundle type * use outDir instead of outFile since CommonJS doesn't support outFile * adding types * dockerfile additions to ensure install * add nodemon * adding moderation types * first try connecting vscode debug to node inside docker config * auto generated vscode * move inspect into command * 9229 * expose port, build command in docker * 9229 again * successful debug attach * Added non-default export to pg-query.ts to allow function to be loaded in server.js. * Bugfix: Don't type iterator in for loop, as it compiled to void(0) aka undefined. * Bugfix: Loaded DEV_MODE envvar using prior get() func. Co-authored-by: micahstubbs Co-authored-by: Colin Megill --- .vscode/launch.json | 30 + .vscode/tasks.json | 42 + Makefile | 1 + Procfile | 2 +- docker-compose.debug.yml | 12 + docker-compose.dev.yml | 6 + docker-compose.yml | 1 + server/.gitignore | 1 + server/.vscode/settings.json | 3 + server/Dockerfile | 10 +- server/app.js | 1449 --- server/app.ts | 1970 ++++ server/package-lock.json | 7579 +++------------ server/package.json | 39 +- server/src/auth/create-user.js | 253 - server/src/auth/create-user.ts | 291 + server/src/auth/{password.js => password.ts} | 148 +- server/src/{comment.js => comment.ts} | 319 +- server/src/{config.js => config.ts} | 15 +- server/src/conversation.ts | 190 + server/src/d.ts | 227 + server/src/db/pg-query.js | 175 - server/src/db/pg-query.ts | 228 + server/src/db/{sql.js => sql.ts} | 20 +- server/src/email/{senders.js => senders.ts} | 56 +- server/src/{log.js => log.ts} | 38 +- server/src/{server.js => server.ts} | 8457 +++++++++++------ server/src/session.js | 217 - server/src/session.ts | 290 + server/src/user.ts | 540 ++ server/src/utils/{common.js => common.ts} | 42 +- .../src/utils/{constants.js => constants.ts} | 4 +- server/src/utils/{cookies.js => cookies.ts} | 122 +- server/src/utils/metered.js | 59 - server/src/utils/metered.ts | 83 + .../src/utils/{parameter.js => parameter.ts} | 290 +- server/tsconfig.json | 82 + server/types/akismet.d.ts | 1 + server/types/badwords.d.ts | 1 + server/types/boolean.d.ts | 1 + server/types/google-cloud__translate.d.ts | 1 + server/types/slack.d.ts | 1 + 42 files changed, 11974 insertions(+), 11322 deletions(-) create mode 100644 .vscode/launch.json create mode 100644 .vscode/tasks.json create mode 100644 docker-compose.debug.yml create mode 100644 server/.vscode/settings.json delete mode 100644 server/app.js create mode 100644 server/app.ts delete mode 100644 server/src/auth/create-user.js create mode 100644 server/src/auth/create-user.ts rename server/src/auth/{password.js => password.ts} (56%) rename server/src/{comment.js => comment.ts} (54%) rename server/src/{config.js => config.ts} (69%) create mode 100644 server/src/conversation.ts create mode 100644 server/src/d.ts delete mode 100644 server/src/db/pg-query.js create mode 100644 server/src/db/pg-query.ts rename server/src/db/{sql.js => sql.ts} (77%) rename server/src/email/{senders.js => senders.ts} (63%) rename server/src/{log.js => log.ts} (68%) rename server/src/{server.js => server.ts} (60%) delete mode 100644 server/src/session.js create mode 100644 server/src/session.ts create mode 100644 server/src/user.ts rename server/src/utils/{common.js => common.ts} (56%) rename server/src/utils/{constants.js => constants.ts} (81%) rename server/src/utils/{cookies.js => cookies.ts} (61%) delete mode 100644 server/src/utils/metered.js create mode 100644 server/src/utils/metered.ts rename server/src/utils/{parameter.js => parameter.ts} (61%) create mode 100644 server/tsconfig.json create mode 100644 server/types/akismet.d.ts create mode 100644 server/types/badwords.d.ts create mode 100644 server/types/boolean.d.ts create mode 100644 server/types/google-cloud__translate.d.ts create mode 100644 server/types/slack.d.ts diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 000000000..41df67203 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,30 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Docker: Attach to Node", + "type": "node", + "request": "attach", + "port": 9229, + "address": "localhost", + "protocol": "inspector", + "remoteRoot": "/app", + "localRoot": "${workspaceFolder}/server", + "restart": true + }, + { + "name": "Docker Node.js Launch", + "type": "docker", + "request": "launch", + "preLaunchTask": "docker-run: debug", + "platform": "node", + "node": { + "package": "${workspaceFolder}/server/package.json", + "localRoot": "${workspaceFolder}/server" + } + } + ] +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 000000000..740e86631 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,42 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "type": "docker-build", + "label": "docker-build", + "platform": "node", + "dockerBuild": { + "dockerfile": "${workspaceFolder}/server/Dockerfile", + "context": "${workspaceFolder}/server", + "pull": true + }, + "node": { + "package": "${workspaceFolder}/server/package.json" + } + }, + { + "type": "docker-run", + "label": "docker-run: release", + "dependsOn": ["docker-build"], + "platform": "node", + "node": { + "package": "${workspaceFolder}/server/package.json" + } + }, + { + "type": "docker-run", + "label": "docker-run: debug", + "dependsOn": ["docker-build"], + "dockerRun": { + "env": { + "DEBUG": "*", + "NODE_ENV": "development" + } + }, + "node": { + "package": "${workspaceFolder}/server/package.json", + "enableDebugging": true + } + } + ] +} diff --git a/Makefile b/Makefile index c5a351281..9cd1cdc50 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,4 @@ + BASEURL ?= https://127.0.0.1.sslip.io E2E_RUN = cd e2e; CYPRESS_BASE_URL=$(BASEURL) diff --git a/Procfile b/Procfile index f0afb9f9c..b3620583b 100644 --- a/Procfile +++ b/Procfile @@ -1 +1 @@ -web: sh -c 'cd server && node --max_old_space_size=400 --gc_interval=100 --harmony app.js' +web: sh -c 'cd server && npm i && npm run build && node --max_old_space_size=400 --gc_interval=100 --harmony dist/app.js' diff --git a/docker-compose.debug.yml b/docker-compose.debug.yml new file mode 100644 index 000000000..777eab55d --- /dev/null +++ b/docker-compose.debug.yml @@ -0,0 +1,12 @@ +version: "3.4" + +services: + polis: + image: polis + build: + context: server + dockerfile: ./Dockerfile + environment: + NODE_ENV: development + + command: ["npm", "run", "dev"] diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index e94b64173..d27f4aa45 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -5,6 +5,12 @@ version: "3.1" # * Definitely want to have different env var files for prod vs dev services: + server: + command: npm run dev + volumes: + - "./server:/app" + ports: + - "9229:9229" math: command: clojure -X:dev-poller volumes: diff --git a/docker-compose.yml b/docker-compose.yml index e979197af..cffa3436f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -30,6 +30,7 @@ services: - "polis-net" ports: - "5000:5000" + - "9229:9229" math: container_name: polis-math diff --git a/server/.gitignore b/server/.gitignore index ae9507dc5..6876e7f66 100644 --- a/server/.gitignore +++ b/server/.gitignore @@ -3,3 +3,4 @@ .google_creds_temp npm-debug.log node_modules +dist/* \ No newline at end of file diff --git a/server/.vscode/settings.json b/server/.vscode/settings.json new file mode 100644 index 000000000..55712c19f --- /dev/null +++ b/server/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "typescript.tsdk": "node_modules/typescript/lib" +} \ No newline at end of file diff --git a/server/Dockerfile b/server/Dockerfile index ccf892c2e..65cda2e36 100644 --- a/server/Dockerfile +++ b/server/Dockerfile @@ -2,19 +2,23 @@ FROM node:14.14.0-alpine WORKDIR /app -RUN apk add postgresql-dev +RUN apk add postgresql-dev python-dev build-base RUN apk add --no-cache --virtual .build \ g++ git make python COPY package*.json ./ + # TODO get `npm ci` to work RUN npm install - RUN apk del .build COPY . . EXPOSE 5000 +# For vscode debug +EXPOSE 9229 + -CMD node --max_old_space_size=400 --gc_interval=100 --harmony app.js +# CMD npm run build && npm run serve +CMD npm run build:watch && npm run serve \ No newline at end of file diff --git a/server/app.js b/server/app.js deleted file mode 100644 index 8cf3aa9a9..000000000 --- a/server/app.js +++ /dev/null @@ -1,1449 +0,0 @@ -// Copyright (C) 2012-present, The Authors. This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License, version 3, as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -"use strict"; - -const Promise = require('bluebird'); -const express = require('express'); - -const server = require('./src/server'); - -const app = express(); - -// Trust the X-Forwarded-Proto and X-Forwarded-Host, but only on private subnets. -// See: https://github.com/pol-is/polis/issues/546 -// See: https://expressjs.com/en/guide/behind-proxies.html -app.set('trust proxy', 'uniquelocal'); - -console.log('init 1'); - -var helpersInitialized = new Promise(function(resolve, reject) { - resolve(server.initializePolisHelpers()); -}); - - - -helpersInitialized.then(function(o) { - const { - addCorsHeader, - auth, - authOptional, - COOKIES, - denyIfNotFromWhitelistedDomain, - devMode, - enableAgid, - fetchThirdPartyCookieTestPt1, - fetchThirdPartyCookieTestPt2, - fetchIndexForAdminPage, - fetchIndexForConversation, - fetchIndexForReportPage, - fetchIndexWithoutPreloadData, - getPidForParticipant, - haltOnTimeout, - HMAC_SIGNATURE_PARAM_NAME, - hostname, - makeFileFetcher, - makeRedirectorTo, - pidCache, - portForAdminFiles, - portForParticipationFiles, - proxy, - redirectIfApiDomain, - redirectIfHasZidButNoConversationId, - redirectIfNotHttps, - redirectIfWrongDomain, - timeout, - winston, - writeDefaultHead, - - middleware_log_request_body, - middleware_log_middleware_errors, - middleware_check_if_options, - middleware_responseTime_start, - - handle_DELETE_metadata_answers, - handle_DELETE_metadata_questions, - handle_GET_bid, - handle_GET_bidToPid, - handle_GET_canvas_app_instructions_png, - handle_GET_changePlanWithCoupon, - handle_GET_comments, - handle_GET_comments_translations, - handle_GET_conditionalIndexFetcher, - handle_GET_contexts, - handle_GET_conversation_assigmnent_xml, - handle_GET_conversationPreloadInfo, - handle_GET_conversations, - handle_GET_conversationsRecentActivity, - handle_GET_conversationsRecentlyStarted, - handle_GET_conversationStats, - handle_GET_createPlanChangeCoupon, - handle_GET_enterprise_deal_url, - handle_GET_math_correlationMatrix, - handle_GET_dataExport, - handle_GET_dataExport_results, - handle_GET_domainWhitelist, - handle_GET_dummyButton, - handle_GET_einvites, - handle_GET_facebook_delete, - handle_GET_groupDemographics, - handle_GET_iim_conversation, - handle_GET_iip_conversation, - handle_GET_implicit_conversation_generation, - handle_GET_launchPrep, - handle_GET_localFile_dev_only, - handle_GET_locations, - handle_GET_logMaxmindResponse, - handle_GET_lti_oauthv1_credentials, - handle_GET_math_pca, - handle_GET_math_pca2, - handle_GET_metadata, - handle_GET_metadata_answers, - handle_GET_metadata_choices, - handle_GET_metadata_questions, - handle_GET_nextComment, - handle_GET_notifications_subscribe, - handle_GET_notifications_unsubscribe, - handle_GET_participants, - handle_GET_participation, - handle_GET_participationInit, - handle_GET_perfStats, - handle_GET_ptptois, - handle_GET_reports, - handle_GET_setup_assignment_xml, - handle_GET_slack_login, - handle_GET_snapshot, - handle_GET_stripe_account_connect, - handle_GET_stripe_account_connected_oauth_callback, - hangle_GET_testConnection, - hangle_GET_testDatabase, - handle_GET_tryCookie, - handle_GET_twitter_image, - handle_GET_twitter_oauth_callback, - handle_GET_twitter_users, - handle_GET_twitterBtn, - handle_GET_users, - handle_GET_verification, - handle_GET_votes, - handle_GET_votes_famous, - handle_GET_votes_me, - handle_GET_xids, - handle_GET_zinvites, - - - - handle_POST_auth_deregister, - handle_POST_auth_facebook, - handle_POST_auth_login, - handle_POST_auth_new, - handle_POST_auth_password, - handle_POST_auth_pwresettoken, - handle_POST_auth_slack_redirect_uri, - handle_POST_charge, - handle_POST_comments, - handle_POST_comments_slack, - handle_POST_contexts, - handle_POST_contributors, - handle_POST_conversation_close, - handle_POST_conversation_reopen, - handle_POST_conversations, - handle_POST_convSubscriptions, - handle_POST_domainWhitelist, - handle_POST_einvites, - handle_POST_joinWithInvite, - handle_POST_lti_conversation_assignment, - handle_POST_lti_setup_assignment, - handle_POST_math_update, - handle_POST_metadata_answers, - handle_POST_metadata_questions, - handle_POST_metrics, - handle_POST_notifyTeam, - handle_POST_participants, - handle_POST_ptptCommentMod, - handle_POST_query_participants_by_metadata, - handle_POST_reportCommentSelections, - handle_POST_reports, - handle_POST_reserve_conversation_id, - handle_POST_sendCreatedLinkToEmail, - handle_POST_sendEmailExportReady, - handle_POST_slack_interactive_messages, - handle_POST_slack_user_invites, - handle_POST_stars, - handle_POST_stripe_cancel, - handle_POST_stripe_save_token, - handle_POST_stripe_upgrade, - handle_POST_trashes, - handle_POST_tutorial, - handle_POST_upvotes, - handle_POST_users_invite, - handle_POST_votes, - handle_POST_waitinglist, - handle_POST_xidWhitelist, - handle_POST_zinvites, - handle_PUT_comments, - handle_PUT_conversations, - handle_PUT_participants_extended, - handle_PUT_ptptois, - handle_PUT_reports, - handle_PUT_users, - } = o; - - const { - assignToP, - assignToPCustom, - getArrayOfInt, - getArrayOfStringNonEmpty, - getArrayOfStringNonEmptyLimitLength, - getBool, - getConversationIdFetchZid, - getEmail, - getInt, - getIntInRange, - getNumberInRange, - getOptionalStringLimitLength, - getPassword, - getPasswordWithCreatePasswordRules, - getReportIdFetchRid, - getStringLimitLength, - getUrlLimitLength, - moveToBody, - need, - needCookie, - needHeader, - resolve_pidThing, - want, - wantCookie, - wantHeader, - } = require('./src/utils/parameter'); - - console.log('begin route config'); - - app.disable('x-powered-by'); - // app.disable('etag'); // seems to be eating CPU, and we're not using etags yet. https://www.dropbox.com/s/hgfd5dm0e29728w/Screenshot%202015-06-01%2023.42.47.png?dl=0 - - - //////////////////////////////////////////// - //////////////////////////////////////////// - //////////////////////////////////////////// - //////////////////////////////////////////// - //////////////////////////////////////////// - //////////////////////////////////////////// - // - // BEGIN MIDDLEWARE - // - //////////////////////////////////////////// - //////////////////////////////////////////// - //////////////////////////////////////////// - //////////////////////////////////////////// - //////////////////////////////////////////// - //////////////////////////////////////////// - - app.use(function(req, res, next) { - console.log("before"); - console.log(req.body); - console.log(req.headers); - next(); - }); - - app.use(middleware_responseTime_start); - - app.use(redirectIfNotHttps); - app.use(express.cookieParser()); - app.use(express.bodyParser()); - app.use(writeDefaultHead); - app.use(redirectIfWrongDomain); - app.use(redirectIfApiDomain); - - if (devMode) { - app.use(express.compress()); - } else { - // Cloudflare would apply gzip if we didn't - // but it's about 2x faster if we do the gzip (for the inbox query on mike's account) - app.use(express.compress()); - } - app.use(middleware_log_request_body); - app.use(middleware_log_middleware_errors); - - app.use(function(req, res, next) { - console.log("part2"); - console.log(req.body); - console.log(req.headers); - next(); - }); - - app.all("/api/v3/*", addCorsHeader); - app.all("/font/*", addCorsHeader); - app.all("/api/v3/*", middleware_check_if_options); - - //////////////////////////////////////////// - //////////////////////////////////////////// - //////////////////////////////////////////// - //////////////////////////////////////////// - //////////////////////////////////////////// - //////////////////////////////////////////// - // - // END MIDDLEWARE - // - //////////////////////////////////////////// - //////////////////////////////////////////// - //////////////////////////////////////////// - //////////////////////////////////////////// - //////////////////////////////////////////// - //////////////////////////////////////////// - - - - app.get("/api/v3/math/pca", - handle_GET_math_pca); - - app.get("/api/v3/math/pca2", - moveToBody, - redirectIfHasZidButNoConversationId, // TODO remove once - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - want('math_tick', getInt, assignToP), - wantHeader('If-None-Match', getStringLimitLength(1000), assignToPCustom('ifNoneMatch')), - handle_GET_math_pca2); - - app.get("/api/v3/math/correlationMatrix", - moveToBody, - // need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - need('report_id', getReportIdFetchRid, assignToPCustom('rid')), - want('math_tick', getInt, assignToP, -1), - handle_GET_math_correlationMatrix); - - - - app.get("/api/v3/dataExport", - moveToBody, - auth(assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - need('conversation_id', getStringLimitLength(1, 1000), assignToP), - want('format', getStringLimitLength(1, 100), assignToP), - want('unixTimestamp', getStringLimitLength(99), assignToP), - handle_GET_dataExport); - - app.get("/api/v3/dataExport/results", - moveToBody, - auth(assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - need('conversation_id', getStringLimitLength(1, 1000), assignToP), - want('filename', getStringLimitLength(1, 1000), assignToP), - handle_GET_dataExport_results); - - // TODO doesn't scale, stop sending entire mapping. - app.get("/api/v3/bidToPid", - authOptional(assignToP), - moveToBody, - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - want('math_tick', getInt, assignToP, 0), - handle_GET_bidToPid); - - app.get("/api/v3/xids", - moveToBody, - auth(assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - handle_GET_xids); - - // TODO cache - app.get("/api/v3/bid", - moveToBody, - auth(assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - want('math_tick', getInt, assignToP, 0), - handle_GET_bid); - - app.post("/api/v3/auth/password", - need('pwresettoken', getOptionalStringLimitLength(1000), assignToP), - need('newPassword', getPasswordWithCreatePasswordRules, assignToP), - handle_POST_auth_password); - - app.post("/api/v3/auth/pwresettoken", - need('email', getEmail, assignToP), - handle_POST_auth_pwresettoken); - - app.post("/api/v3/auth/deregister", - want("showPage", getStringLimitLength(1, 99), assignToP), - handle_POST_auth_deregister); - - app.get("/api/v3/zinvites/:zid", - moveToBody, - auth(assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - handle_GET_zinvites); - - app.post("/api/v3/zinvites/:zid", - moveToBody, - auth(assignToP), - want('short_url', getBool, assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - handle_POST_zinvites); - - // // tags: ANON_RELATED - app.get("/api/v3/participants", - moveToBody, - auth(assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - handle_GET_participants); - - app.get("/api/v3/dummyButton", - moveToBody, - need("button", getStringLimitLength(1, 999), assignToP), - authOptional(assignToP), - handle_GET_dummyButton); - - - app.get("/api/v3/conversations/preload", - moveToBody, - need('conversation_id', getStringLimitLength(1, 1000), assignToP), // we actually need conversation_id to build a url - handle_GET_conversationPreloadInfo); - - app.get("/api/v3/conversations/recently_started", - auth(assignToP), - moveToBody, - want('sinceUnixTimestamp', getStringLimitLength(99), assignToP), - handle_GET_conversationsRecentlyStarted); - - app.get("/api/v3/conversations/recent_activity", - auth(assignToP), - moveToBody, - want('sinceUnixTimestamp', getStringLimitLength(99), assignToP), - handle_GET_conversationsRecentActivity); - - app.post("/api/v3/participants", - auth(assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - want('answers', getArrayOfInt, assignToP, []), // {pmqid: [pmaid, pmaid], ...} where the pmaids are checked choices - want('parent_url', getStringLimitLength(9999), assignToP), - want('referrer', getStringLimitLength(9999), assignToP), - handle_POST_participants); - - app.get("/api/v3/notifications/subscribe", - moveToBody, - need(HMAC_SIGNATURE_PARAM_NAME, getStringLimitLength(10, 999), assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - need('conversation_id', getStringLimitLength(1, 1000), assignToP), // we actually need conversation_id to build a url - need('email', getEmail, assignToP), - handle_GET_notifications_subscribe); - - app.get("/api/v3/notifications/unsubscribe", - moveToBody, - need(HMAC_SIGNATURE_PARAM_NAME, getStringLimitLength(10, 999), assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - need('conversation_id', getStringLimitLength(1, 1000), assignToP), // we actually need conversation_id to build a url - need('email', getEmail, assignToP), - handle_GET_notifications_unsubscribe); - - app.post("/api/v3/convSubscriptions", - auth(assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - need("type", getInt, assignToP), - need('email', getEmail, assignToP), - handle_POST_convSubscriptions); - - app.post("/api/v3/auth/login", - need('password', getPassword, assignToP), - want('email', getEmail, assignToP), - want('lti_user_id', getStringLimitLength(1, 9999), assignToP), - want('lti_user_image', getStringLimitLength(1, 9999), assignToP), - want('lti_context_id', getStringLimitLength(1, 9999), assignToP), - want('tool_consumer_instance_guid', getStringLimitLength(1, 9999), assignToP), - want('afterJoinRedirectUrl', getStringLimitLength(1, 9999), assignToP), - handle_POST_auth_login); - - app.post("/api/v3/joinWithInvite", - authOptional(assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - wantCookie(COOKIES.PERMANENT_COOKIE, getOptionalStringLimitLength(32), assignToPCustom('permanentCookieToken')), - want('suzinvite', getOptionalStringLimitLength(32), assignToP), - want('answers', getArrayOfInt, assignToP, []), // {pmqid: [pmaid, pmaid], ...} where the pmaids are checked choices - want('referrer', getStringLimitLength(9999), assignToP), - want('parent_url', getStringLimitLength(9999), assignToP), - handle_POST_joinWithInvite); - - app.get("/perfStats_9182738127", - moveToBody, - handle_GET_perfStats); - - app.post("/api/v3/sendEmailExportReady", - need('webserver_username', getStringLimitLength(1, 999), assignToP), - need('webserver_pass', getStringLimitLength(1, 999), assignToP), - need('email', getEmail, assignToP), - need('conversation_id', getStringLimitLength(1, 1000), assignToP), // we actually need conversation_id to build a url - need('filename', getStringLimitLength(9999), assignToP), - handle_POST_sendEmailExportReady); - - - app.post("/api/v3/notifyTeam", - need('webserver_username', getStringLimitLength(1, 999), assignToP), - need('webserver_pass', getStringLimitLength(1, 999), assignToP), - need('subject', getStringLimitLength(9999), assignToP), - need('body', getStringLimitLength(99999), assignToP), - handle_POST_notifyTeam); - - app.get("/api/v3/domainWhitelist", - moveToBody, - auth(assignToP), - handle_GET_domainWhitelist); - - app.post("/api/v3/domainWhitelist", - auth(assignToP), - need('domain_whitelist', getOptionalStringLimitLength(999), assignToP, ""), - handle_POST_domainWhitelist); - - app.post("/api/v3/xidWhitelist", - auth(assignToP), - need('xid_whitelist', getArrayOfStringNonEmptyLimitLength(9999, 999), assignToP), - handle_POST_xidWhitelist); - - app.get("/api/v3/conversationStats", - moveToBody, - authOptional(assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - want('report_id', getReportIdFetchRid, assignToPCustom('rid')), - want('until', getInt, assignToP), - handle_GET_conversationStats); - - app.get("/api/v3/snapshot", - moveToBody, - auth(assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - handle_GET_snapshot); - - app.get("/api/v3/auth/slack/redirect_uri", - moveToBody, - need('code', getStringLimitLength(1, 999), assignToP), - want('state', getStringLimitLength(999), assignToP), - handle_POST_auth_slack_redirect_uri); - - app.post("/api/v3/slack/interactive_messages", - need('payload', getOptionalStringLimitLength(9999), assignToP, ""), - handle_POST_slack_interactive_messages); - - // this endpoint isn't really ready for general use TODO_SECURITY - app.get("/api/v3/facebook/delete", - moveToBody, - auth(assignToP), - handle_GET_facebook_delete); - - app.post("/api/v3/auth/facebook", - enableAgid, - authOptional(assignToP), - want('fb_granted_scopes', getStringLimitLength(1, 9999), assignToP), - want('fb_friends_response', getStringLimitLength(1, 99999), assignToP), - want('fb_public_profile', getStringLimitLength(1, 99999), assignToP), - want('fb_email', getEmail, assignToP), - want('hname', getOptionalStringLimitLength(9999), assignToP), - want('provided_email', getEmail, assignToP), - want('conversation_id', getOptionalStringLimitLength(999), assignToP), - want('password', getPassword, assignToP), - need('response', getStringLimitLength(1, 9999), assignToP), - want("owner", getBool, assignToP, true), - handle_POST_auth_facebook); - - app.post("/api/v3/auth/new", - want('anon', getBool, assignToP), - want('password', getPasswordWithCreatePasswordRules, assignToP), - want('password2', getPasswordWithCreatePasswordRules, assignToP), - want('email', getOptionalStringLimitLength(999), assignToP), - want('hname', getOptionalStringLimitLength(999), assignToP), - want('oinvite', getOptionalStringLimitLength(999), assignToP), - want('encodedParams', getOptionalStringLimitLength(9999), assignToP), // TODO_SECURITY we need to add an additional key param to ensure this is secure. we don't want anyone adding themselves to other people's site_id groups. - want('zinvite', getOptionalStringLimitLength(999), assignToP), - want('organization', getOptionalStringLimitLength(999), assignToP), - want('gatekeeperTosPrivacy', getBool, assignToP), - want('lti_user_id', getStringLimitLength(1, 9999), assignToP), - want('lti_user_image', getStringLimitLength(1, 9999), assignToP), - want('lti_context_id', getStringLimitLength(1, 9999), assignToP), - want('tool_consumer_instance_guid', getStringLimitLength(1, 9999), assignToP), - want('afterJoinRedirectUrl', getStringLimitLength(1, 9999), assignToP), - want("owner", getBool, assignToP, true), - handle_POST_auth_new); - - - app.post("/api/v3/tutorial", - auth(assignToP), - need("step", getInt, assignToP), - handle_POST_tutorial); - - app.get("/api/v3/users", - moveToBody, - authOptional(assignToP), - want("errIfNoAuth", getBool, assignToP), - handle_GET_users); - - // use this to generate coupons for free upgrades - // TODO_SECURITY - app.get("/api/v3/createPlanChangeCoupon_aiudhfaiodufy78sadtfiasdf", - moveToBody, - need('uid', getInt, assignToP), - need('planCode', getOptionalStringLimitLength(999), assignToP), - handle_GET_createPlanChangeCoupon); - - app.get("/api/v3/changePlanWithCoupon", - moveToBody, - authOptional(assignToP), - need('code', getOptionalStringLimitLength(999), assignToP), - handle_GET_changePlanWithCoupon); - - - // Just for testing that the new custom stripe form is submitting properly - app.post("/api/v3/stripe_save_token", - handle_POST_stripe_save_token); - - app.post("/api/v3/stripe_upgrade", - auth(assignToP), - need('stripeResponse', getStringLimitLength(9999), assignToP), - need('plan', getStringLimitLength(99), assignToP), - handle_POST_stripe_upgrade); - - - app.post("/api/v3/stripe_cancel", - auth(assignToP), - handle_POST_stripe_cancel); - - - app.post("/api/v3/charge", - auth(assignToP), - want('stripeToken', getOptionalStringLimitLength(999), assignToP), - want('stripeEmail', getOptionalStringLimitLength(999), assignToP), - need('plan', getOptionalStringLimitLength(999), assignToP), - handle_POST_charge); - - app.get("/api/v3/participation", - moveToBody, - auth(assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - want('strict', getBool, assignToP), - handle_GET_participation); - - - app.get("/api/v3/group_demographics", - moveToBody, - authOptional(assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - want('report_id', getReportIdFetchRid, assignToPCustom('rid')), - handle_GET_groupDemographics); - - app.get("/api/v3/comments", - moveToBody, - authOptional(assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - want('report_id', getReportIdFetchRid, assignToPCustom('rid')), // if you want to get report-specific info - want('tids', getArrayOfInt, assignToP), - want('moderation', getBool, assignToP), - want('mod', getInt, assignToP), - want('modIn', getBool, assignToP), // set this to true if you want to see the comments that are ptpt-visible given the current "strict mod" setting, or false for ptpt-invisible comments. - want('mod_gt', getInt, assignToP), - want('include_social', getBool, assignToP), - want('include_demographics', getBool, assignToP), - // need('lastServerToken', _.identity, assignToP), - want('include_voting_patterns', getBool, assignToP, false), - resolve_pidThing('not_voted_by_pid', assignToP, "get:comments:not_voted_by_pid"), - resolve_pidThing('pid', assignToP, "get:comments:pid"), - handle_GET_comments); - - // TODO probably need to add a retry mechanism like on joinConversation to handle possibility of duplicate tid race-condition exception - app.post("/api/v3/comments", - auth(assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - want('txt', getOptionalStringLimitLength(997), assignToP), - want('vote', getIntInRange(-1, 1), assignToP), - want("twitter_tweet_id", getStringLimitLength(999), assignToP), - want("quote_twitter_screen_name", getStringLimitLength(999), assignToP), - want("quote_txt", getStringLimitLength(999), assignToP), - want("quote_src_url", getUrlLimitLength(999), assignToP), - want("anon", getBool, assignToP), - want("is_seed", getBool, assignToP), - want('xid', getStringLimitLength(1, 999), assignToP), - resolve_pidThing('pid', assignToP, "post:comments"), - handle_POST_comments); - - - app.post("/api/v3/comments/slack", - auth(assignToP), - want('slack_team', getOptionalStringLimitLength(99), assignToP), - want('slack_user_id', getOptionalStringLimitLength(99), assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - want('txt', getOptionalStringLimitLength(997), assignToP), - want('vote', getIntInRange(-1, 1), assignToP, -1), // default to agree - want("twitter_tweet_id", getStringLimitLength(999), assignToP), - want("quote_twitter_screen_name", getStringLimitLength(999), assignToP), - want("quote_txt", getStringLimitLength(999), assignToP), - want("quote_src_url", getUrlLimitLength(999), assignToP), - want("anon", getBool, assignToP), - want("is_seed", getBool, assignToP), - resolve_pidThing('pid', assignToP, "post:comments"), - handle_POST_comments_slack); - - app.get("/api/v3/comments/translations", - auth(assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - want('tid', getInt, assignToP), - want('lang', getStringLimitLength(1,10), assignToP), - handle_GET_comments_translations); - - app.get("/api/v3/votes/me", - moveToBody, - auth(assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - handle_GET_votes_me); - - app.get("/api/v3/votes", - moveToBody, - authOptional(assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - want('tid', getInt, assignToP), - resolve_pidThing('pid', assignToP, "get:votes"), - handle_GET_votes); - - app.get("/api/v3/nextComment", - timeout(15000), - moveToBody, - authOptional(assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - resolve_pidThing('not_voted_by_pid', assignToP, "get:nextComment"), - want('without', getArrayOfInt, assignToP), - want('include_social', getBool, assignToP), - want('lang', getStringLimitLength(1,10), assignToP), // preferred language of nextComment - haltOnTimeout, - handle_GET_nextComment); - - app.get("/api/v3/testConnection", - moveToBody, - hangle_GET_testConnection); - - app.get("/api/v3/testDatabase", - moveToBody, - hangle_GET_testDatabase); - - app.get("/robots.txt", - function(req, res) { - res.send("User-agent: *\n" + - "Disallow: /api/"); - }); - - app.get("/api/v3/participationInit", - moveToBody, - authOptional(assignToP), - want('ptptoiLimit', getInt, assignToP), - want('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - want('conversation_id', getStringLimitLength(1, 1000), assignToP), // we actually need conversation_id to build a url - want('lang', getStringLimitLength(1,10), assignToP), // preferred language of nextComment - - want('domain_whitelist_override_key', getStringLimitLength(1, 1000), assignToP), - denyIfNotFromWhitelistedDomain, // this seems like the easiest place to enforce the domain whitelist. The index.html is cached on cloudflare, so that's not the right place. - - want('xid', getStringLimitLength(1, 999), assignToP), - resolve_pidThing('pid', assignToP, "get:votes"), // must be after zid getter - handle_GET_participationInit); - - app.post("/api/v3/votes", - auth(assignToP), - need('tid', getInt, assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - need('vote', getIntInRange(-1, 1), assignToP), - want('starred', getBool, assignToP), - want('weight', getNumberInRange(-1, 1), assignToP, 0), - resolve_pidThing('pid', assignToP, "post:votes"), - want('xid', getStringLimitLength(1, 999), assignToP), - want('lang', getStringLimitLength(1,10), assignToP), // language of the next comment to be returned - handle_POST_votes); - - - app.put("/api/v3/participants_extended", - auth(assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - want('show_translation_activated', getBool, assignToP), - handle_PUT_participants_extended); - - - app.get("/api/v3/logMaxmindResponse", - auth(assignToP), - need('user_uid', getInt, assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - handle_GET_logMaxmindResponse); - - app.post("/api/v3/ptptCommentMod", - auth(assignToP), - need('tid', getInt, assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - want('as_abusive', getBool, assignToP, null), - want('as_factual', getBool, assignToP, null), - want('as_feeling', getBool, assignToP, null), - want('as_important', getBool, assignToP, null), - want('as_notfact', getBool, assignToP, null), - want('as_notgoodidea', getBool, assignToP, null), - want('as_notmyfeeling', getBool, assignToP, null), - want('as_offtopic', getBool, assignToP, null), - want('as_spam', getBool, assignToP, null), - want('as_unsure', getBool, assignToP, null), - getPidForParticipant(assignToP, pidCache), - handle_POST_ptptCommentMod); - - app.post("/api/v3/upvotes", - auth(assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - handle_POST_upvotes); - - app.post("/api/v3/stars", - auth(assignToP), - need('tid', getInt, assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - need('starred', getIntInRange(0, 1), assignToP), - getPidForParticipant(assignToP, pidCache), - handle_POST_stars); - - app.post("/api/v3/trashes", - auth(assignToP), - need('tid', getInt, assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - need('trashed', getIntInRange(0, 1), assignToP), - getPidForParticipant(assignToP, pidCache), - handle_POST_trashes); - - app.put('/api/v3/comments', - moveToBody, - auth(assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - need('tid', getInt, assignToP), - need('active', getBool, assignToP), - need('mod', getInt, assignToP), - need('is_meta', getBool, assignToP), - need('velocity', getNumberInRange(0, 1), assignToP), - handle_PUT_comments); - - - app.post('/api/v3/reportCommentSelections', - auth(assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - need('report_id', getReportIdFetchRid, assignToPCustom('rid')), - need('tid', getInt, assignToP), - need('include', getBool, assignToP), - handle_POST_reportCommentSelections); - - - - // use this to generate them - app.get('/api/v3/lti_oauthv1_credentials', - moveToBody, - want('uid', getInt, assignToP), - handle_GET_lti_oauthv1_credentials); - - app.post('/api/v3/conversation/close', - moveToBody, - auth(assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - handle_POST_conversation_close); - - app.post('/api/v3/conversation/reopen', - moveToBody, - auth(assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - handle_POST_conversation_reopen); - - app.put('/api/v3/conversations', - moveToBody, - auth(assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - need('conversation_id', getStringLimitLength(1, 1000), assignToP), // we actually need conversation_id to build a url - want('is_active', getBool, assignToP), - want('is_anon', getBool, assignToP), - want('is_draft', getBool, assignToP, false), - want('is_data_open', getBool, assignToP, false), - want('owner_sees_participation_stats', getBool, assignToP, false), - want('profanity_filter', getBool, assignToP), - want('short_url', getBool, assignToP, false), - want('spam_filter', getBool, assignToP), - want('strict_moderation', getBool, assignToP), - want('topic', getOptionalStringLimitLength(1000), assignToP), - want('description', getOptionalStringLimitLength(50000), assignToP), - want('vis_type', getInt, assignToP), - want('help_type', getInt, assignToP), - want('write_type', getInt, assignToP), - want('socialbtn_type', getInt, assignToP), - want('bgcolor', getOptionalStringLimitLength(20), assignToP), - want('help_color', getOptionalStringLimitLength(20), assignToP), - want('help_bgcolor', getOptionalStringLimitLength(20), assignToP), - want('style_btn', getOptionalStringLimitLength(500), assignToP), - want('auth_needed_to_vote', getBool, assignToP), - want('auth_needed_to_write', getBool, assignToP), - want('auth_opt_fb', getBool, assignToP), - want('auth_opt_tw', getBool, assignToP), - want('auth_opt_allow_3rdparty', getBool, assignToP), - want('verifyMeta', getBool, assignToP), - want('send_created_email', getBool, assignToP), // ideally the email would be sent on the post, but we post before they click create to allow owner to prepopulate comments. - want('launch_presentation_return_url_hex', getStringLimitLength(1, 9999), assignToP), // LTI editor tool redirect url (once conversation editing is done) - want('context', getOptionalStringLimitLength(999), assignToP), - want('tool_consumer_instance_guid', getOptionalStringLimitLength(999), assignToP), - want('custom_canvas_assignment_id', getInt, assignToP), - want('link_url', getStringLimitLength(1, 9999), assignToP), - want('subscribe_type', getInt, assignToP), - handle_PUT_conversations); - - - app.put('/api/v3/users', - moveToBody, - auth(assignToP), - want('email', getEmail, assignToP), - want('hname', getOptionalStringLimitLength(9999), assignToP), - want('uid_of_user', getInt, assignToP), - handle_PUT_users); - - - app.delete('/api/v3/metadata/questions/:pmqid', - moveToBody, - auth(assignToP), - need('pmqid', getInt, assignToP), - handle_DELETE_metadata_questions); - - app.delete('/api/v3/metadata/answers/:pmaid', - moveToBody, - auth(assignToP), - need('pmaid', getInt, assignToP), - handle_DELETE_metadata_answers); - - app.get('/api/v3/metadata/questions', - moveToBody, - authOptional(assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - want('suzinvite', getOptionalStringLimitLength(32), assignToP), - want('zinvite', getOptionalStringLimitLength(300), assignToP), - // TODO want('lastMetaTime', getInt, assignToP, 0), - handle_GET_metadata_questions); - - app.post('/api/v3/metadata/questions', - moveToBody, - auth(assignToP), - need('key', getOptionalStringLimitLength(999), assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - handle_POST_metadata_questions); - - app.post('/api/v3/metadata/answers', - moveToBody, - auth(assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - need('pmqid', getInt, assignToP), - need('value', getOptionalStringLimitLength(999), assignToP), - handle_POST_metadata_answers); - - app.get('/api/v3/metadata/choices', - moveToBody, - auth(assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - handle_GET_metadata_choices); - - app.get('/api/v3/metadata/answers', - moveToBody, - authOptional(assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - want('pmqid', getInt, assignToP), - want('suzinvite', getOptionalStringLimitLength(32), assignToP), - want('zinvite', getOptionalStringLimitLength(300), assignToP), - // TODO want('lastMetaTime', getInt, assignToP, 0), - handle_GET_metadata_answers); - - app.get('/api/v3/metadata', - moveToBody, - auth(assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - want('zinvite', getOptionalStringLimitLength(300), assignToP), - want('suzinvite', getOptionalStringLimitLength(32), assignToP), - // TODO want('lastMetaTime', getInt, assignToP, 0), - handle_GET_metadata); - - - app.get('/api/v3/enterprise_deal_url', - moveToBody, - // want('upfront', getBool, assignToP), - need('monthly', getInt, assignToP), - want('maxUsers', getInt, assignToP), - want('plan_name', getOptionalStringLimitLength(99), assignToP), - want('plan_id', getOptionalStringLimitLength(99), assignToP), - handle_GET_enterprise_deal_url); - - app.get('/api/v3/stripe_account_connect', - handle_GET_stripe_account_connect); - - app.get('/api/v3/stripe_account_connected_oauth_callback', - moveToBody, - want("code", getStringLimitLength(9999), assignToP), - want("access_token", getStringLimitLength(9999), assignToP), - want("error", getStringLimitLength(9999), assignToP), - want("error_description", getStringLimitLength(9999), assignToP), - handle_GET_stripe_account_connected_oauth_callback); - - app.get('/api/v3/conversations', - moveToBody, - authOptional(assignToP), - want('include_all_conversations_i_am_in', getBool, assignToP), - want('is_active', getBool, assignToP), - want('is_draft', getBool, assignToP), - want('course_invite', getStringLimitLength(1, 32), assignToP), - want('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - want('want_upvoted', getBool, assignToP), - want('want_mod_url', getBool, assignToP), // NOTE - use this for API only! - want('want_inbox_item_admin_url', getBool, assignToP), // NOTE - use this for API only! - want('want_inbox_item_participant_url', getBool, assignToP), // NOTE - use this for API only! - want('want_inbox_item_admin_html', getBool, assignToP), // NOTE - use this for API only! - want('want_inbox_item_participant_html', getBool, assignToP), // NOTE - use this for API only! - want('limit', getIntInRange(1, 9999), assignToP), // not allowing a super high limit to prevent DOS attacks - want('context', getStringLimitLength(1, 999), assignToP), - want('xid', getStringLimitLength(1, 999), assignToP), - handle_GET_conversations); - - app.get('/api/v3/reports', - moveToBody, - authOptional(assignToP), - want('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - want('report_id', getReportIdFetchRid, assignToPCustom('rid')), // Knowing the report_id grants the user permission to view the report - handle_GET_reports); - - app.post('/api/v3/mathUpdate', - moveToBody, - auth(assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - need('math_update_type', getStringLimitLength(1, 32), assignToP), // expecting "recompute" or "update" - handle_POST_math_update); - - app.post('/api/v3/reports', - auth(assignToP), - want('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - handle_POST_reports); - - app.put('/api/v3/reports', - moveToBody, - auth(assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - need('report_id', getReportIdFetchRid, assignToPCustom('rid')), - want('report_name', getStringLimitLength(999), assignToP), - want('label_x_neg', getStringLimitLength(999), assignToP), - want('label_x_pos', getStringLimitLength(999), assignToP), - want('label_y_neg', getStringLimitLength(999), assignToP), - want('label_y_pos', getStringLimitLength(999), assignToP), - want('label_group_0', getStringLimitLength(999), assignToP), - want('label_group_1', getStringLimitLength(999), assignToP), - want('label_group_2', getStringLimitLength(999), assignToP), - want('label_group_3', getStringLimitLength(999), assignToP), - want('label_group_4', getStringLimitLength(999), assignToP), - want('label_group_5', getStringLimitLength(999), assignToP), - want('label_group_6', getStringLimitLength(999), assignToP), - want('label_group_7', getStringLimitLength(999), assignToP), - want('label_group_8', getStringLimitLength(999), assignToP), - want('label_group_9', getStringLimitLength(999), assignToP), - handle_PUT_reports); - - app.get('/api/v3/contexts', - moveToBody, - authOptional(assignToP), - handle_GET_contexts); - - app.post('/api/v3/contexts', - auth(assignToP), - need('name', getStringLimitLength(1, 300), assignToP), - handle_POST_contexts); - - app.post('/api/v3/reserve_conversation_id', - auth(assignToP), - handle_POST_reserve_conversation_id); - - // TODO check to see if ptpt has answered necessary metadata questions. - app.post('/api/v3/conversations', - auth(assignToP), - want('is_active', getBool, assignToP, true), - want('is_draft', getBool, assignToP, false), - want('is_anon', getBool, assignToP, false), - want('owner_sees_participation_stats', getBool, assignToP, false), - want('profanity_filter', getBool, assignToP, true), - want('short_url', getBool, assignToP, false), - want('spam_filter', getBool, assignToP, true), - want('strict_moderation', getBool, assignToP, false), - want('context', getOptionalStringLimitLength(999), assignToP, ""), - want('topic', getOptionalStringLimitLength(1000), assignToP, ""), - want('description', getOptionalStringLimitLength(50000), assignToP, ""), - want('conversation_id', getStringLimitLength(6, 300), assignToP, ""), - want('is_slack', getBool, assignToP, false), - want('is_data_open', getBool, assignToP, false), - want('ownerXid', getStringLimitLength(1, 999), assignToP), - handle_POST_conversations); - - app.post('/api/v3/query_participants_by_metadata', - auth(assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - need('pmaids', getArrayOfInt, assignToP, []), - handle_POST_query_participants_by_metadata); - - app.post('/api/v3/sendCreatedLinkToEmail', - auth(assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - handle_POST_sendCreatedLinkToEmail); - - app.get("/api/v3/twitterBtn", - moveToBody, - authOptional(assignToP), - want("dest", getStringLimitLength(9999), assignToP), - want("owner", getBool, assignToP, true), - handle_GET_twitterBtn); - - app.get("/api/v3/twitter_oauth_callback", - moveToBody, - enableAgid, - auth(assignToP), - need("dest", getStringLimitLength(9999), assignToP), - need("oauth_token", getStringLimitLength(9999), assignToP), // TODO verify - need("oauth_verifier", getStringLimitLength(9999), assignToP), // TODO verify - want("owner", getBool, assignToP, true), - handle_GET_twitter_oauth_callback); - - app.get("/api/v3/locations", - moveToBody, - authOptional(assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - need("gid", getInt, assignToP), - handle_GET_locations); - - app.put("/api/v3/ptptois", - moveToBody, - auth(assignToP), - need("mod", getInt, assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - resolve_pidThing('pid', assignToP), - handle_PUT_ptptois); - - app.get("/api/v3/ptptois", - moveToBody, - authOptional(assignToP), - want('mod', getInt, assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - need('conversation_id', getStringLimitLength(1, 1000), assignToP), - handle_GET_ptptois); - - app.get("/api/v3/votes/famous", - moveToBody, - authOptional(assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - want('math_tick', getInt, assignToP, -1), - want('ptptoiLimit', getIntInRange(0, 99), assignToP), - handle_GET_votes_famous); - - app.get("/api/v3/twitter_users", - moveToBody, - authOptional(assignToP), - want("twitter_user_id", getInt, assignToP), // if not provided, returns info for the signed-in user - handle_GET_twitter_users); - - app.post("/api/v3/einvites", - need('email', getEmail, assignToP), - handle_POST_einvites); - - app.get("/api/v3/einvites", - moveToBody, - need("einvite", getStringLimitLength(1, 100), assignToP), - handle_GET_einvites); - - app.post("/api/v3/LTI/setup_assignment", - authOptional(assignToP), - need("oauth_consumer_key", getStringLimitLength(1, 9999), assignToP), // for now, this will be the professor, but may also be the school - need("user_id", getStringLimitLength(1, 9999), assignToP), - need("context_id", getStringLimitLength(1, 9999), assignToP), - want("tool_consumer_instance_guid", getStringLimitLength(1, 9999), assignToP), // scope to the right LTI/canvas? instance - want("roles", getStringLimitLength(1, 9999), assignToP), - want("user_image", getStringLimitLength(1, 9999), assignToP), - want("lis_person_contact_email_primary", getStringLimitLength(1, 9999), assignToP), - want("lis_person_name_full", getStringLimitLength(1, 9999), assignToP), - want("lis_outcome_service_url", getStringLimitLength(1, 9999), assignToP), // send grades here! - want("launch_presentation_return_url", getStringLimitLength(1, 9999), assignToP), - want("ext_content_return_types", getStringLimitLength(1, 9999), assignToP), - handle_POST_lti_setup_assignment); - - app.post("/api/v3/LTI/conversation_assignment", - need("oauth_consumer_key", getStringLimitLength(1, 9999), assignToP), // for now, this will be the professor, but may also be the school need("oauth_consumer_key", getStringLimitLength(1, 9999), assignToP), // for now, this will be the professor, but may also be the school - need("oauth_signature_method", getStringLimitLength(1, 9999), assignToP), // probably "HMAC-SHA-1" - need("oauth_nonce", getStringLimitLength(1, 9999), assignToP), //rK81yoLBZhxVeaQHOUQQV8Ug5AObZtWv4R0ezQN20 - need("oauth_version", getStringLimitLength(1, 9999), assignToP), //'1.0' - need("oauth_timestamp", getStringLimitLength(1, 9999), assignToP), //? - need("oauth_callback", getStringLimitLength(1, 9999), assignToP), // about:blank - - need("user_id", getStringLimitLength(1, 9999), assignToP), - need("context_id", getStringLimitLength(1, 9999), assignToP), - want("roles", getStringLimitLength(1, 9999), assignToP), - want("user_image", getStringLimitLength(1, 9999), assignToP), - // per assignment stuff - want("custom_canvas_assignment_id", getInt, assignToP), // NOTE: it enters our system as an int, but we'll - want("lis_outcome_service_url", getStringLimitLength(1, 9999), assignToP), // send grades here! - want("lis_result_sourcedid", getStringLimitLength(1, 9999), assignToP), // grading context - want("tool_consumer_instance_guid", getStringLimitLength(1, 9999), assignToP), // canvas instance - handle_POST_lti_conversation_assignment); - - app.get("/api/v3/LTI/setup_assignment.xml", - handle_GET_setup_assignment_xml); - - app.get("/api/v3/LTI/conversation_assignment.xml", - handle_GET_conversation_assigmnent_xml); - - app.get("/canvas_app_instructions.png", - handle_GET_canvas_app_instructions_png); - - app.post("/api/v3/users/invite", - // authWithApiKey(assignToP), - auth(assignToP), - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - need('conversation_id', getStringLimitLength(1, 1000), assignToP), // we actually need conversation_id to build a url - // need('single_use_tokens', getBool, assignToP), - need('emails', getArrayOfStringNonEmpty, assignToP), - handle_POST_users_invite); - - - app.get(/^\/slack_login_code.*/, - moveToBody, - authOptional(assignToP), - handle_GET_slack_login); - - app.post("/api/v3/slack/user/invites", - need('slack_team', getStringLimitLength(1, 20), assignToP), - need('slack_user_id', getStringLimitLength(1, 20), assignToP), - handle_POST_slack_user_invites); - - - app.get(/^\/polis_site_id.*/, - moveToBody, - need("parent_url", getStringLimitLength(1, 10000), assignToP), - want("referrer", getStringLimitLength(1, 10000), assignToP), - want("auth_needed_to_vote", getBool, assignToP), - want("auth_needed_to_write", getBool, assignToP), - want("auth_opt_fb", getBool, assignToP), - want("auth_opt_tw", getBool, assignToP), - want('auth_opt_allow_3rdparty', getBool, assignToP), - want('show_vis', getBool, assignToP), - want('show_share', getBool, assignToP), - want('bg_white', getBool, assignToP), - want('topic', getStringLimitLength(1, 1000), assignToP), - want('ucv', getBool, assignToP), // not persisted - want('ucw', getBool, assignToP), // not persisted - want('ucsh', getBool, assignToP), // not persisted - want('ucst', getBool, assignToP), // not persisted - want('ucsd', getBool, assignToP), // not persisted - want('ucsv', getBool, assignToP), // not persisted - want('ucsf', getBool, assignToP), // not persisted - want('ui_lang', getStringLimitLength(1, 10), assignToP), // not persisted - want('dwok', getStringLimitLength(1, 1000), assignToP), // not persisted - want('xid', getStringLimitLength(1, 999), assignToP), // not persisted - want('subscribe_type', getStringLimitLength(1,9), assignToP), // not persisted - want('x_name', getStringLimitLength(1, 746), assignToP), // not persisted here, but later on POST vote/comment - want('x_profile_image_url', getStringLimitLength(1, 3000), assignToP), // not persisted here, but later on POST vote/comment - want('x_email', getStringLimitLength(256), assignToP), // not persisted here, but later on POST vote/comment - want('build', getStringLimitLength(300), assignToP), - handle_GET_implicit_conversation_generation); - - app.get("/iip/:conversation_id", - moveToBody, - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - handle_GET_iip_conversation); - - app.get("/iim/:conversation_id", - moveToBody, - need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), - handle_GET_iim_conversation); - - // proxy for fetching twitter profile images - // Needed because Twitter doesn't provide profile pics in response to a request - you have to fetch the user info, then parse that to get the URL, requiring two round trips. - // There is a bulk user data API, but it's too slow to block on in our /famous route. - // So references to this route are injected into the twitter part of the /famous response. - app.get("/twitter_image", - moveToBody, - need('id', getStringLimitLength(999), assignToP), - handle_GET_twitter_image); - - // TODO this should probably be exempt from the CORS restrictions - app.get("/api/v3/launchPrep", - moveToBody, - need("dest", getStringLimitLength(1, 10000), assignToP), - handle_GET_launchPrep); - - app.get("/api/v3/tryCookie", - moveToBody, - handle_GET_tryCookie); - - app.get("/api/v3/verify", - moveToBody, - need("e", getStringLimitLength(1, 1000), assignToP), - handle_GET_verification); - - app.post("/api/v3/contributors", - authOptional(assignToP), - need('agreement_version', getIntInRange(1, 999999), assignToP), - need('name', getStringLimitLength(746), assignToP), - need('email', getStringLimitLength(256), assignToP), - need('github_id', getStringLimitLength(256), assignToP), - need('company_name', getStringLimitLength(746), assignToP), - handle_POST_contributors); - - app.post("/api/v3/waitinglist", - need('name', getStringLimitLength(746), assignToP), - need('email', getEmail, assignToP), - want('affiliation', getStringLimitLength(999), assignToP), - want('role', getStringLimitLength(999), assignToP), - need('campaign', getStringLimitLength(100), assignToP), - handle_POST_waitinglist); - - app.post("/api/v3/metrics", - authOptional(assignToP), - need('types', getArrayOfInt, assignToP), - need('times', getArrayOfInt, assignToP), - need('durs', getArrayOfInt, assignToP), - need('clientTimestamp', getInt, assignToP), - handle_POST_metrics); - - function makeFetchIndexWithoutPreloadData() { - let port = portForParticipationFiles; - return function(req, res) { - return fetchIndexWithoutPreloadData(req, res, port); - }; - } - - - // Conversation aliases - app.get(/^\/football$/, makeRedirectorTo("/2arcefpshi")); - app.get(/^\/pdf$/, makeRedirectorTo("/23mymwyhkn")); // pdf 2017 - app.get(/^\/nabi$/, makeRedirectorTo("/8ufpzc6fkm")); // - - - app.get(/^\/[0-9][0-9A-Za-z]+(\/.*)?/, fetchIndexForConversation); // conversation view - app.get(/^\/explore\/[0-9][0-9A-Za-z]+(\/.*)?/, fetchIndexForConversation); // power view - app.get(/^\/share\/[0-9][0-9A-Za-z]+(\/.*)?/, fetchIndexForConversation); // share view - app.get(/^\/summary\/[0-9][0-9A-Za-z]+(\/.*)?/, fetchIndexForConversation); // summary view - app.get(/^\/ot\/[0-9][0-9A-Za-z]+(\/.*)?/, fetchIndexForConversation); // conversation view, one-time url - // TODO consider putting static files on /static, and then using a catch-all to serve the index. - app.get(/^\/conversation\/create(\/.*)?/, fetchIndexWithoutPreloadData); - app.get(/^\/user\/create(\/.*)?$/, fetchIndexWithoutPreloadData); - app.get(/^\/user\/login(\/.*)?$/, fetchIndexWithoutPreloadData); - - - app.get(/^\/settings(\/.*)?$/, makeFetchIndexWithoutPreloadData()); - app.get(/^\/settings\/enterprise}.*$/, makeFetchIndexWithoutPreloadData()); - - app.get(/^\/user\/logout(\/.*)?$/, fetchIndexWithoutPreloadData); - - // admin dash routes - app.get(/^\/m\/[0-9][0-9A-Za-z]+(\/.*)?/, fetchIndexForAdminPage); - app.get(/^\/integrate(\/.*)?/, fetchIndexForAdminPage); - app.get(/^\/other-conversations(\/.*)?/, fetchIndexForAdminPage); - app.get(/^\/account(\/.*)?/, fetchIndexForAdminPage); - app.get(/^\/bot(\/.*)?/, fetchIndexForAdminPage); - app.get(/^\/conversations(\/.*)?/, fetchIndexForAdminPage); - app.get(/^\/signout(\/.*)?/, fetchIndexForAdminPage); - app.get(/^\/signin(\/.*)?/, fetchIndexForAdminPage); - app.get(/^\/dist\/admin_bundle.js$/, makeFileFetcher(hostname, portForAdminFiles, "/dist/admin_bundle.js", { - 'Content-Type': "application/javascript", - })); - app.get(/^\/__webpack_hmr$/, makeFileFetcher(hostname, portForAdminFiles, "/__webpack_hmr", { - 'Content-Type': "eventsource", - })); - app.get(/^\/privacy$/, fetchIndexForAdminPage); - app.get(/^\/tos$/, fetchIndexForAdminPage); - - // admin dash-based landers - app.get(/^\/gov(\/.*)?/, fetchIndexForAdminPage); - app.get(/^\/createuser(\/.*)?/, fetchIndexForAdminPage); - app.get(/^\/contrib(\/.*)?/, fetchIndexForAdminPage); - - app.get(/^\/bot\/install(\/.*)?/, fetchIndexForAdminPage); - app.get(/^\/bot\/support(\/.*)?/, fetchIndexForAdminPage); - - app.get(/^\/inbox(\/.*)?$/, fetchIndexWithoutPreloadData); - // app.get(/^\/r/, fetchIndexWithoutPreloadData); - app.get(/^\/hk/, fetchIndexWithoutPreloadData); - app.get(/^\/s\//, fetchIndexWithoutPreloadData); - app.get(/^\/s$/, fetchIndexWithoutPreloadData); - app.get(/^\/hk\/new/, fetchIndexWithoutPreloadData); - app.get(/^\/inboxApiTest/, fetchIndexWithoutPreloadData); - app.get(/^\/pwresetinit.*/, fetchIndexForAdminPage); - app.get(/^\/demo\/[0-9][0-9A-Za-z]+/, fetchIndexForConversation); - app.get(/^\/demo$/, fetchIndexForAdminPage); - app.get(/^\/pwreset.*/, fetchIndexForAdminPage); - app.get(/^\/company$/, fetchIndexForAdminPage); - - app.get(/^\/report\/r?[0-9][0-9A-Za-z]+(\/.*)?/, fetchIndexForReportPage); - - app.get(/^\/thirdPartyCookieTestPt1\.html$/, fetchThirdPartyCookieTestPt1); - app.get(/^\/thirdPartyCookieTestPt2\.html$/, fetchThirdPartyCookieTestPt2); - - app.get(/^\/embed$/, makeFileFetcher(hostname, portForAdminFiles, "/embed.html", { - 'Content-Type': "text/html", - })); - app.get(/^\/embedPreprod$/, makeFileFetcher(hostname, portForAdminFiles, "/embedPreprod.html", { - 'Content-Type': "text/html", - })); - app.get(/^\/embedReport$/, makeFileFetcher(hostname, portForAdminFiles, "/embedReport.html", { - 'Content-Type': "text/html", - })); - app.get(/^\/embedReportPreprod$/, makeFileFetcher(hostname, portForAdminFiles, "/embedReportPreprod.html", { - 'Content-Type': "text/html", - })); - app.get(/^\/canvas_setup_backup_instructions$/, makeFileFetcher(hostname, portForParticipationFiles, "/canvas_setup_backup_instructions.html", { - 'Content-Type': "text/html", - })); - app.get(/^\/styleguide$/, makeFileFetcher(hostname, portForParticipationFiles, "/styleguide.html", { - 'Content-Type': "text/html", - })); - // Duplicate url for content at root. Needed so we have something for "About" to link to. - app.get(/^\/about$/, makeRedirectorTo("/home")); - app.get(/^\/home(\/.*)?/, fetchIndexForAdminPage); - app.get(/^\/s\/CTE\/?$/, makeFileFetcher(hostname, portForParticipationFiles, "/football.html", { - 'Content-Type': "text/html", - })); - app.get(/^\/twitterAuthReturn(\/.*)?$/, makeFileFetcher(hostname, portForParticipationFiles, "/twitterAuthReturn.html", { - 'Content-Type': "text/html", - })); - - app.get(/^\/localFile\/.*/, handle_GET_localFile_dev_only); - - app.get("/", handle_GET_conditionalIndexFetcher); - - // proxy static files - app.get(/^\/cached\/.*/, proxy); - app.get(/^\/font\/.*/, proxy); - app.get(/^\/.*embed.*js\/.*/, proxy); - - - // ends in slash? redirect to non-slash version - app.get(/.*\//, - function(req, res) { - let pathAndQuery = req.originalUrl; - - // remove slash at end - if (pathAndQuery.endsWith("/")) { - pathAndQuery = pathAndQuery.slice(0, pathAndQuery.length-1); - } - - // remove slashes before "?" - if (pathAndQuery.indexOf("?") >= 1) { - pathAndQuery = pathAndQuery.replace("/\?", "?"); - } - - let fullUrl = req.protocol + '://' + req.get('host') + pathAndQuery; - - if (pathAndQuery !== req.originalUrl) { - res.redirect(fullUrl); - } else { - proxy(req, res); - } - }); - - - var missingFilesGet404 = false; - if (missingFilesGet404) { - // 404 everything else - app.get(/^\/[^(api\/)]?.*/, makeFileFetcher(hostname, portForAdminFiles, "/404.html", { - 'Content-Type': "text/html", - })); - } else { - // proxy everything else - app.get(/^\/[^(api\/)]?.*/, proxy); - } - - app.listen(process.env.PORT); - - winston.log("info", 'started on port ' + process.env.PORT); - -}, function(err) { - console.error("failed to init server"); - console.error(err); -}); diff --git a/server/app.ts b/server/app.ts new file mode 100644 index 000000000..67d6ef0a5 --- /dev/null +++ b/server/app.ts @@ -0,0 +1,1970 @@ +// @ts-nocheck +// TODO ^^ enable typechecking after refactoring to use +// TODO modern import syntax for helpers + +// Copyright (C) 2012-present, The Authors. This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License, version 3, as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . +"use strict"; + +import Promise from "bluebird"; +import express from "express"; + +import server from "./src/server"; + +const app = express(); +// Trust the X-Forwarded-Proto and X-Forwarded-Host, but only on private subnets. +// See: https://github.com/pol-is/polis/issues/546 +// See: https://expressjs.com/en/guide/behind-proxies.html +app.set("trust proxy", "uniquelocal"); + + +var helpersInitialized = new Promise(function (resolve, reject) { + resolve(server.initializePolisHelpers()); +}); +/* @ts-ignore */ +helpersInitialized.then( + function (o) { + const { + addCorsHeader, + auth, + authOptional, + COOKIES, + denyIfNotFromWhitelistedDomain, + devMode, + enableAgid, + fetchThirdPartyCookieTestPt1, + fetchThirdPartyCookieTestPt2, + fetchIndexForAdminPage, + fetchIndexForConversation, + fetchIndexForReportPage, + fetchIndexWithoutPreloadData, + getPidForParticipant, + haltOnTimeout, + HMAC_SIGNATURE_PARAM_NAME, + hostname, + makeFileFetcher, + makeRedirectorTo, + pidCache, + portForAdminFiles, + portForParticipationFiles, + proxy, + redirectIfApiDomain, + redirectIfHasZidButNoConversationId, + redirectIfNotHttps, + redirectIfWrongDomain, + timeout, + winston, + writeDefaultHead, + + middleware_log_request_body, + middleware_log_middleware_errors, + middleware_check_if_options, + middleware_responseTime_start, + + handle_DELETE_metadata_answers, + handle_DELETE_metadata_questions, + handle_GET_bid, + handle_GET_bidToPid, + handle_GET_canvas_app_instructions_png, + handle_GET_changePlanWithCoupon, + handle_GET_comments, + handle_GET_comments_translations, + handle_GET_conditionalIndexFetcher, + handle_GET_contexts, + handle_GET_conversation_assigmnent_xml, + handle_GET_conversationPreloadInfo, + handle_GET_conversations, + handle_GET_conversationsRecentActivity, + handle_GET_conversationsRecentlyStarted, + handle_GET_conversationStats, + handle_GET_createPlanChangeCoupon, + handle_GET_enterprise_deal_url, + handle_GET_math_correlationMatrix, + handle_GET_dataExport, + handle_GET_dataExport_results, + handle_GET_domainWhitelist, + handle_GET_dummyButton, + handle_GET_einvites, + handle_GET_facebook_delete, + handle_GET_groupDemographics, + handle_GET_iim_conversation, + handle_GET_iip_conversation, + handle_GET_implicit_conversation_generation, + handle_GET_launchPrep, + handle_GET_localFile_dev_only, + handle_GET_locations, + handle_GET_logMaxmindResponse, + handle_GET_lti_oauthv1_credentials, + handle_GET_math_pca, + handle_GET_math_pca2, + handle_GET_metadata, + handle_GET_metadata_answers, + handle_GET_metadata_choices, + handle_GET_metadata_questions, + handle_GET_nextComment, + handle_GET_notifications_subscribe, + handle_GET_notifications_unsubscribe, + handle_GET_participants, + handle_GET_participation, + handle_GET_participationInit, + handle_GET_perfStats, + handle_GET_ptptois, + handle_GET_reports, + handle_GET_setup_assignment_xml, + handle_GET_slack_login, + handle_GET_snapshot, + handle_GET_stripe_account_connect, + handle_GET_stripe_account_connected_oauth_callback, + hangle_GET_testConnection, + hangle_GET_testDatabase, + handle_GET_tryCookie, + handle_GET_twitter_image, + handle_GET_twitter_oauth_callback, + handle_GET_twitter_users, + handle_GET_twitterBtn, + handle_GET_users, + handle_GET_verification, + handle_GET_votes, + handle_GET_votes_famous, + handle_GET_votes_me, + handle_GET_xids, + handle_GET_zinvites, + + handle_POST_auth_deregister, + handle_POST_auth_facebook, + handle_POST_auth_login, + handle_POST_auth_new, + handle_POST_auth_password, + handle_POST_auth_pwresettoken, + handle_POST_auth_slack_redirect_uri, + handle_POST_charge, + handle_POST_comments, + handle_POST_comments_slack, + handle_POST_contexts, + handle_POST_contributors, + handle_POST_conversation_close, + handle_POST_conversation_reopen, + handle_POST_conversations, + handle_POST_convSubscriptions, + handle_POST_domainWhitelist, + handle_POST_einvites, + handle_POST_joinWithInvite, + handle_POST_lti_conversation_assignment, + handle_POST_lti_setup_assignment, + handle_POST_math_update, + handle_POST_metadata_answers, + handle_POST_metadata_questions, + handle_POST_metrics, + handle_POST_notifyTeam, + handle_POST_participants, + handle_POST_ptptCommentMod, + handle_POST_query_participants_by_metadata, + handle_POST_reportCommentSelections, + handle_POST_reports, + handle_POST_reserve_conversation_id, + handle_POST_sendCreatedLinkToEmail, + handle_POST_sendEmailExportReady, + handle_POST_slack_interactive_messages, + handle_POST_slack_user_invites, + handle_POST_stars, + handle_POST_stripe_cancel, + handle_POST_stripe_save_token, + handle_POST_stripe_upgrade, + handle_POST_trashes, + handle_POST_tutorial, + handle_POST_upvotes, + handle_POST_users_invite, + handle_POST_votes, + handle_POST_waitinglist, + handle_POST_xidWhitelist, + handle_POST_zinvites, + handle_PUT_comments, + handle_PUT_conversations, + handle_PUT_participants_extended, + handle_PUT_ptptois, + handle_PUT_reports, + handle_PUT_users, + } = o; + + const { + assignToP, + assignToPCustom, + getArrayOfInt, + getArrayOfStringNonEmpty, + getArrayOfStringNonEmptyLimitLength, + getBool, + getConversationIdFetchZid, + getEmail, + getInt, + getIntInRange, + getNumberInRange, + getOptionalStringLimitLength, + getPassword, + getPasswordWithCreatePasswordRules, + getReportIdFetchRid, + getStringLimitLength, + getUrlLimitLength, + moveToBody, + need, + needCookie, + needHeader, + resolve_pidThing, + want, + wantCookie, + wantHeader, + } = require("./src/utils/parameter"); + + app.disable("x-powered-by"); + // app.disable('etag'); // seems to be eating CPU, and we're not using etags yet. https://www.dropbox.com/s/hgfd5dm0e29728w/Screenshot%202015-06-01%2023.42.47.png?dl=0 + + //////////////////////////////////////////// + //////////////////////////////////////////// + //////////////////////////////////////////// + //////////////////////////////////////////// + //////////////////////////////////////////// + //////////////////////////////////////////// + // + // BEGIN MIDDLEWARE + // + //////////////////////////////////////////// + //////////////////////////////////////////// + //////////////////////////////////////////// + //////////////////////////////////////////// + //////////////////////////////////////////// + //////////////////////////////////////////// + + app.use(function (req, res, next) { + console.log("before"); + console.log(req.body); + console.log(req.headers); + next(); + }); + + app.use(middleware_responseTime_start); + + app.use(redirectIfNotHttps); + app.use(express.cookieParser()); + app.use(express.bodyParser()); + app.use(writeDefaultHead); + app.use(redirectIfWrongDomain); + app.use(redirectIfApiDomain); + + if (devMode) { + app.use(express.compress()); + } else { + // Cloudflare would apply gzip if we didn't + // but it's about 2x faster if we do the gzip (for the inbox query on mike's account) + app.use(express.compress()); + } + app.use(middleware_log_request_body); + app.use(middleware_log_middleware_errors); + + app.use(function (req, res, next) { + console.log("part2"); + console.log(req.body); + console.log(req.headers); + next(); + }); + + app.all("/api/v3/*", addCorsHeader); + app.all("/font/*", addCorsHeader); + app.all("/api/v3/*", middleware_check_if_options); + + //////////////////////////////////////////// + //////////////////////////////////////////// + //////////////////////////////////////////// + //////////////////////////////////////////// + //////////////////////////////////////////// + //////////////////////////////////////////// + // + // END MIDDLEWARE + // + //////////////////////////////////////////// + //////////////////////////////////////////// + //////////////////////////////////////////// + //////////////////////////////////////////// + //////////////////////////////////////////// + //////////////////////////////////////////// + + app.get("/api/v3/math/pca", handle_GET_math_pca); + + app.get( + "/api/v3/math/pca2", + moveToBody, + redirectIfHasZidButNoConversationId, // TODO remove once + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + want("math_tick", getInt, assignToP), + wantHeader( + "If-None-Match", + getStringLimitLength(1000), + assignToPCustom("ifNoneMatch") + ), + handle_GET_math_pca2 + ); + + app.get( + "/api/v3/math/correlationMatrix", + moveToBody, + // need('conversation_id', getConversationIdFetchZid, assignToPCustom('zid')), + need("report_id", getReportIdFetchRid, assignToPCustom("rid")), + want("math_tick", getInt, assignToP, -1), + handle_GET_math_correlationMatrix + ); + + app.get( + "/api/v3/dataExport", + moveToBody, + auth(assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + need("conversation_id", getStringLimitLength(1, 1000), assignToP), + want("format", getStringLimitLength(1, 100), assignToP), + want("unixTimestamp", getStringLimitLength(99), assignToP), + handle_GET_dataExport + ); + + app.get( + "/api/v3/dataExport/results", + moveToBody, + auth(assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + need("conversation_id", getStringLimitLength(1, 1000), assignToP), + want("filename", getStringLimitLength(1, 1000), assignToP), + handle_GET_dataExport_results + ); + + // TODO doesn't scale, stop sending entire mapping. + app.get( + "/api/v3/bidToPid", + authOptional(assignToP), + moveToBody, + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + want("math_tick", getInt, assignToP, 0), + handle_GET_bidToPid + ); + + app.get( + "/api/v3/xids", + moveToBody, + auth(assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + handle_GET_xids + ); + + // TODO cache + app.get( + "/api/v3/bid", + moveToBody, + auth(assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + want("math_tick", getInt, assignToP, 0), + handle_GET_bid + ); + + app.post( + "/api/v3/auth/password", + need("pwresettoken", getOptionalStringLimitLength(1000), assignToP), + need("newPassword", getPasswordWithCreatePasswordRules, assignToP), + handle_POST_auth_password + ); + + app.post( + "/api/v3/auth/pwresettoken", + need("email", getEmail, assignToP), + handle_POST_auth_pwresettoken + ); + + app.post( + "/api/v3/auth/deregister", + want("showPage", getStringLimitLength(1, 99), assignToP), + handle_POST_auth_deregister + ); + + app.get( + "/api/v3/zinvites/:zid", + moveToBody, + auth(assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + handle_GET_zinvites + ); + + app.post( + "/api/v3/zinvites/:zid", + moveToBody, + auth(assignToP), + want("short_url", getBool, assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + handle_POST_zinvites + ); + + // // tags: ANON_RELATED + app.get( + "/api/v3/participants", + moveToBody, + auth(assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + handle_GET_participants + ); + + app.get( + "/api/v3/dummyButton", + moveToBody, + need("button", getStringLimitLength(1, 999), assignToP), + authOptional(assignToP), + handle_GET_dummyButton + ); + + app.get( + "/api/v3/conversations/preload", + moveToBody, + need("conversation_id", getStringLimitLength(1, 1000), assignToP), // we actually need conversation_id to build a url + handle_GET_conversationPreloadInfo + ); + + app.get( + "/api/v3/conversations/recently_started", + auth(assignToP), + moveToBody, + want("sinceUnixTimestamp", getStringLimitLength(99), assignToP), + handle_GET_conversationsRecentlyStarted + ); + + app.get( + "/api/v3/conversations/recent_activity", + auth(assignToP), + moveToBody, + want("sinceUnixTimestamp", getStringLimitLength(99), assignToP), + handle_GET_conversationsRecentActivity + ); + + app.post( + "/api/v3/participants", + auth(assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + want("answers", getArrayOfInt, assignToP, []), // {pmqid: [pmaid, pmaid], ...} where the pmaids are checked choices + want("parent_url", getStringLimitLength(9999), assignToP), + want("referrer", getStringLimitLength(9999), assignToP), + handle_POST_participants + ); + + app.get( + "/api/v3/notifications/subscribe", + moveToBody, + need(HMAC_SIGNATURE_PARAM_NAME, getStringLimitLength(10, 999), assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + need("conversation_id", getStringLimitLength(1, 1000), assignToP), // we actually need conversation_id to build a url + need("email", getEmail, assignToP), + handle_GET_notifications_subscribe + ); + + app.get( + "/api/v3/notifications/unsubscribe", + moveToBody, + need(HMAC_SIGNATURE_PARAM_NAME, getStringLimitLength(10, 999), assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + need("conversation_id", getStringLimitLength(1, 1000), assignToP), // we actually need conversation_id to build a url + need("email", getEmail, assignToP), + handle_GET_notifications_unsubscribe + ); + + app.post( + "/api/v3/convSubscriptions", + auth(assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + need("type", getInt, assignToP), + need("email", getEmail, assignToP), + handle_POST_convSubscriptions + ); + + app.post( + "/api/v3/auth/login", + need("password", getPassword, assignToP), + want("email", getEmail, assignToP), + want("lti_user_id", getStringLimitLength(1, 9999), assignToP), + want("lti_user_image", getStringLimitLength(1, 9999), assignToP), + want("lti_context_id", getStringLimitLength(1, 9999), assignToP), + want( + "tool_consumer_instance_guid", + getStringLimitLength(1, 9999), + assignToP + ), + want("afterJoinRedirectUrl", getStringLimitLength(1, 9999), assignToP), + handle_POST_auth_login + ); + + app.post( + "/api/v3/joinWithInvite", + authOptional(assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + wantCookie( + COOKIES.PERMANENT_COOKIE, + getOptionalStringLimitLength(32), + assignToPCustom("permanentCookieToken") + ), + want("suzinvite", getOptionalStringLimitLength(32), assignToP), + want("answers", getArrayOfInt, assignToP, []), // {pmqid: [pmaid, pmaid], ...} where the pmaids are checked choices + want("referrer", getStringLimitLength(9999), assignToP), + want("parent_url", getStringLimitLength(9999), assignToP), + handle_POST_joinWithInvite + ); + + app.get("/perfStats_9182738127", moveToBody, handle_GET_perfStats); + + app.post( + "/api/v3/sendEmailExportReady", + need("webserver_username", getStringLimitLength(1, 999), assignToP), + need("webserver_pass", getStringLimitLength(1, 999), assignToP), + need("email", getEmail, assignToP), + need("conversation_id", getStringLimitLength(1, 1000), assignToP), // we actually need conversation_id to build a url + need("filename", getStringLimitLength(9999), assignToP), + handle_POST_sendEmailExportReady + ); + + app.post( + "/api/v3/notifyTeam", + need("webserver_username", getStringLimitLength(1, 999), assignToP), + need("webserver_pass", getStringLimitLength(1, 999), assignToP), + need("subject", getStringLimitLength(9999), assignToP), + need("body", getStringLimitLength(99999), assignToP), + handle_POST_notifyTeam + ); + + app.get( + "/api/v3/domainWhitelist", + moveToBody, + auth(assignToP), + handle_GET_domainWhitelist + ); + + app.post( + "/api/v3/domainWhitelist", + auth(assignToP), + need( + "domain_whitelist", + getOptionalStringLimitLength(999), + assignToP, + "" + ), + handle_POST_domainWhitelist + ); + + app.post( + "/api/v3/xidWhitelist", + auth(assignToP), + need( + "xid_whitelist", + getArrayOfStringNonEmptyLimitLength(9999, 999), + assignToP + ), + handle_POST_xidWhitelist + ); + + app.get( + "/api/v3/conversationStats", + moveToBody, + authOptional(assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + want("report_id", getReportIdFetchRid, assignToPCustom("rid")), + want("until", getInt, assignToP), + handle_GET_conversationStats + ); + + app.get( + "/api/v3/snapshot", + moveToBody, + auth(assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + handle_GET_snapshot + ); + + app.get( + "/api/v3/auth/slack/redirect_uri", + moveToBody, + need("code", getStringLimitLength(1, 999), assignToP), + want("state", getStringLimitLength(999), assignToP), + handle_POST_auth_slack_redirect_uri + ); + + app.post( + "/api/v3/slack/interactive_messages", + need("payload", getOptionalStringLimitLength(9999), assignToP, ""), + handle_POST_slack_interactive_messages + ); + + // this endpoint isn't really ready for general use TODO_SECURITY + app.get( + "/api/v3/facebook/delete", + moveToBody, + auth(assignToP), + handle_GET_facebook_delete + ); + + app.post( + "/api/v3/auth/facebook", + enableAgid, + authOptional(assignToP), + want("fb_granted_scopes", getStringLimitLength(1, 9999), assignToP), + want("fb_friends_response", getStringLimitLength(1, 99999), assignToP), + want("fb_public_profile", getStringLimitLength(1, 99999), assignToP), + want("fb_email", getEmail, assignToP), + want("hname", getOptionalStringLimitLength(9999), assignToP), + want("provided_email", getEmail, assignToP), + want("conversation_id", getOptionalStringLimitLength(999), assignToP), + want("password", getPassword, assignToP), + need("response", getStringLimitLength(1, 9999), assignToP), + want("owner", getBool, assignToP, true), + handle_POST_auth_facebook + ); + + app.post( + "/api/v3/auth/new", + want("anon", getBool, assignToP), + want("password", getPasswordWithCreatePasswordRules, assignToP), + want("password2", getPasswordWithCreatePasswordRules, assignToP), + want("email", getOptionalStringLimitLength(999), assignToP), + want("hname", getOptionalStringLimitLength(999), assignToP), + want("oinvite", getOptionalStringLimitLength(999), assignToP), + want("encodedParams", getOptionalStringLimitLength(9999), assignToP), // TODO_SECURITY we need to add an additional key param to ensure this is secure. we don't want anyone adding themselves to other people's site_id groups. + want("zinvite", getOptionalStringLimitLength(999), assignToP), + want("organization", getOptionalStringLimitLength(999), assignToP), + want("gatekeeperTosPrivacy", getBool, assignToP), + want("lti_user_id", getStringLimitLength(1, 9999), assignToP), + want("lti_user_image", getStringLimitLength(1, 9999), assignToP), + want("lti_context_id", getStringLimitLength(1, 9999), assignToP), + want( + "tool_consumer_instance_guid", + getStringLimitLength(1, 9999), + assignToP + ), + want("afterJoinRedirectUrl", getStringLimitLength(1, 9999), assignToP), + want("owner", getBool, assignToP, true), + handle_POST_auth_new + ); + + app.post( + "/api/v3/tutorial", + auth(assignToP), + need("step", getInt, assignToP), + handle_POST_tutorial + ); + + app.get( + "/api/v3/users", + moveToBody, + authOptional(assignToP), + want("errIfNoAuth", getBool, assignToP), + handle_GET_users + ); + + // use this to generate coupons for free upgrades + // TODO_SECURITY + app.get( + "/api/v3/createPlanChangeCoupon_aiudhfaiodufy78sadtfiasdf", + moveToBody, + need("uid", getInt, assignToP), + need("planCode", getOptionalStringLimitLength(999), assignToP), + handle_GET_createPlanChangeCoupon + ); + + app.get( + "/api/v3/changePlanWithCoupon", + moveToBody, + authOptional(assignToP), + need("code", getOptionalStringLimitLength(999), assignToP), + handle_GET_changePlanWithCoupon + ); + + // Just for testing that the new custom stripe form is submitting properly + app.post("/api/v3/stripe_save_token", handle_POST_stripe_save_token); + + app.post( + "/api/v3/stripe_upgrade", + auth(assignToP), + need("stripeResponse", getStringLimitLength(9999), assignToP), + need("plan", getStringLimitLength(99), assignToP), + handle_POST_stripe_upgrade + ); + + app.post( + "/api/v3/stripe_cancel", + auth(assignToP), + handle_POST_stripe_cancel + ); + + app.post( + "/api/v3/charge", + auth(assignToP), + want("stripeToken", getOptionalStringLimitLength(999), assignToP), + want("stripeEmail", getOptionalStringLimitLength(999), assignToP), + need("plan", getOptionalStringLimitLength(999), assignToP), + handle_POST_charge + ); + + app.get( + "/api/v3/participation", + moveToBody, + auth(assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + want("strict", getBool, assignToP), + handle_GET_participation + ); + + app.get( + "/api/v3/group_demographics", + moveToBody, + authOptional(assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + want("report_id", getReportIdFetchRid, assignToPCustom("rid")), + handle_GET_groupDemographics + ); + + app.get( + "/api/v3/comments", + moveToBody, + authOptional(assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + want("report_id", getReportIdFetchRid, assignToPCustom("rid")), // if you want to get report-specific info + want("tids", getArrayOfInt, assignToP), + want("moderation", getBool, assignToP), + want("mod", getInt, assignToP), + want("modIn", getBool, assignToP), // set this to true if you want to see the comments that are ptpt-visible given the current "strict mod" setting, or false for ptpt-invisible comments. + want("mod_gt", getInt, assignToP), + want("include_social", getBool, assignToP), + want("include_demographics", getBool, assignToP), + // need('lastServerToken', _.identity, assignToP), + want("include_voting_patterns", getBool, assignToP, false), + resolve_pidThing( + "not_voted_by_pid", + assignToP, + "get:comments:not_voted_by_pid" + ), + resolve_pidThing("pid", assignToP, "get:comments:pid"), + handle_GET_comments + ); + + // TODO probably need to add a retry mechanism like on joinConversation to handle possibility of duplicate tid race-condition exception + app.post( + "/api/v3/comments", + auth(assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + want("txt", getOptionalStringLimitLength(997), assignToP), + want("vote", getIntInRange(-1, 1), assignToP), + want("twitter_tweet_id", getStringLimitLength(999), assignToP), + want("quote_twitter_screen_name", getStringLimitLength(999), assignToP), + want("quote_txt", getStringLimitLength(999), assignToP), + want("quote_src_url", getUrlLimitLength(999), assignToP), + want("anon", getBool, assignToP), + want("is_seed", getBool, assignToP), + want("xid", getStringLimitLength(1, 999), assignToP), + resolve_pidThing("pid", assignToP, "post:comments"), + handle_POST_comments + ); + + app.post( + "/api/v3/comments/slack", + auth(assignToP), + want("slack_team", getOptionalStringLimitLength(99), assignToP), + want("slack_user_id", getOptionalStringLimitLength(99), assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + want("txt", getOptionalStringLimitLength(997), assignToP), + want("vote", getIntInRange(-1, 1), assignToP, -1), // default to agree + want("twitter_tweet_id", getStringLimitLength(999), assignToP), + want("quote_twitter_screen_name", getStringLimitLength(999), assignToP), + want("quote_txt", getStringLimitLength(999), assignToP), + want("quote_src_url", getUrlLimitLength(999), assignToP), + want("anon", getBool, assignToP), + want("is_seed", getBool, assignToP), + resolve_pidThing("pid", assignToP, "post:comments"), + handle_POST_comments_slack + ); + + app.get( + "/api/v3/comments/translations", + auth(assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + want("tid", getInt, assignToP), + want("lang", getStringLimitLength(1, 10), assignToP), + handle_GET_comments_translations + ); + + app.get( + "/api/v3/votes/me", + moveToBody, + auth(assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + handle_GET_votes_me + ); + + app.get( + "/api/v3/votes", + moveToBody, + authOptional(assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + want("tid", getInt, assignToP), + resolve_pidThing("pid", assignToP, "get:votes"), + handle_GET_votes + ); + + app.get( + "/api/v3/nextComment", + timeout(15000), + moveToBody, + authOptional(assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + resolve_pidThing("not_voted_by_pid", assignToP, "get:nextComment"), + want("without", getArrayOfInt, assignToP), + want("include_social", getBool, assignToP), + want("lang", getStringLimitLength(1, 10), assignToP), // preferred language of nextComment + haltOnTimeout, + handle_GET_nextComment + ); + + app.get("/api/v3/testConnection", moveToBody, hangle_GET_testConnection); + + app.get("/api/v3/testDatabase", moveToBody, hangle_GET_testDatabase); + + app.get("/robots.txt", function (req, res) { + res.send("User-agent: *\n" + "Disallow: /api/"); + }); + + app.get( + "/api/v3/participationInit", + moveToBody, + authOptional(assignToP), + want("ptptoiLimit", getInt, assignToP), + want( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + want("conversation_id", getStringLimitLength(1, 1000), assignToP), // we actually need conversation_id to build a url + want("lang", getStringLimitLength(1, 10), assignToP), // preferred language of nextComment + + want( + "domain_whitelist_override_key", + getStringLimitLength(1, 1000), + assignToP + ), + denyIfNotFromWhitelistedDomain, // this seems like the easiest place to enforce the domain whitelist. The index.html is cached on cloudflare, so that's not the right place. + + want("xid", getStringLimitLength(1, 999), assignToP), + resolve_pidThing("pid", assignToP, "get:votes"), // must be after zid getter + handle_GET_participationInit + ); + + app.post( + "/api/v3/votes", + auth(assignToP), + need("tid", getInt, assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + need("vote", getIntInRange(-1, 1), assignToP), + want("starred", getBool, assignToP), + want("weight", getNumberInRange(-1, 1), assignToP, 0), + resolve_pidThing("pid", assignToP, "post:votes"), + want("xid", getStringLimitLength(1, 999), assignToP), + want("lang", getStringLimitLength(1, 10), assignToP), // language of the next comment to be returned + handle_POST_votes + ); + + app.put( + "/api/v3/participants_extended", + auth(assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + want("show_translation_activated", getBool, assignToP), + handle_PUT_participants_extended + ); + + app.get( + "/api/v3/logMaxmindResponse", + auth(assignToP), + need("user_uid", getInt, assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + handle_GET_logMaxmindResponse + ); + + app.post( + "/api/v3/ptptCommentMod", + auth(assignToP), + need("tid", getInt, assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + want("as_abusive", getBool, assignToP, null), + want("as_factual", getBool, assignToP, null), + want("as_feeling", getBool, assignToP, null), + want("as_important", getBool, assignToP, null), + want("as_notfact", getBool, assignToP, null), + want("as_notgoodidea", getBool, assignToP, null), + want("as_notmyfeeling", getBool, assignToP, null), + want("as_offtopic", getBool, assignToP, null), + want("as_spam", getBool, assignToP, null), + want("as_unsure", getBool, assignToP, null), + getPidForParticipant(assignToP, pidCache), + handle_POST_ptptCommentMod + ); + + app.post( + "/api/v3/upvotes", + auth(assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + handle_POST_upvotes + ); + + app.post( + "/api/v3/stars", + auth(assignToP), + need("tid", getInt, assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + need("starred", getIntInRange(0, 1), assignToP), + getPidForParticipant(assignToP, pidCache), + handle_POST_stars + ); + + app.post( + "/api/v3/trashes", + auth(assignToP), + need("tid", getInt, assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + need("trashed", getIntInRange(0, 1), assignToP), + getPidForParticipant(assignToP, pidCache), + handle_POST_trashes + ); + + app.put( + "/api/v3/comments", + moveToBody, + auth(assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + need("tid", getInt, assignToP), + need("active", getBool, assignToP), + need("mod", getInt, assignToP), + need("is_meta", getBool, assignToP), + need("velocity", getNumberInRange(0, 1), assignToP), + handle_PUT_comments + ); + + app.post( + "/api/v3/reportCommentSelections", + auth(assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + need("report_id", getReportIdFetchRid, assignToPCustom("rid")), + need("tid", getInt, assignToP), + need("include", getBool, assignToP), + handle_POST_reportCommentSelections + ); + + // use this to generate them + app.get( + "/api/v3/lti_oauthv1_credentials", + moveToBody, + want("uid", getInt, assignToP), + handle_GET_lti_oauthv1_credentials + ); + + app.post( + "/api/v3/conversation/close", + moveToBody, + auth(assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + handle_POST_conversation_close + ); + + app.post( + "/api/v3/conversation/reopen", + moveToBody, + auth(assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + handle_POST_conversation_reopen + ); + + app.put( + "/api/v3/conversations", + moveToBody, + auth(assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + need("conversation_id", getStringLimitLength(1, 1000), assignToP), // we actually need conversation_id to build a url + want("is_active", getBool, assignToP), + want("is_anon", getBool, assignToP), + want("is_draft", getBool, assignToP, false), + want("is_data_open", getBool, assignToP, false), + want("owner_sees_participation_stats", getBool, assignToP, false), + want("profanity_filter", getBool, assignToP), + want("short_url", getBool, assignToP, false), + want("spam_filter", getBool, assignToP), + want("strict_moderation", getBool, assignToP), + want("topic", getOptionalStringLimitLength(1000), assignToP), + want("description", getOptionalStringLimitLength(50000), assignToP), + want("vis_type", getInt, assignToP), + want("help_type", getInt, assignToP), + want("write_type", getInt, assignToP), + want("socialbtn_type", getInt, assignToP), + want("bgcolor", getOptionalStringLimitLength(20), assignToP), + want("help_color", getOptionalStringLimitLength(20), assignToP), + want("help_bgcolor", getOptionalStringLimitLength(20), assignToP), + want("style_btn", getOptionalStringLimitLength(500), assignToP), + want("auth_needed_to_vote", getBool, assignToP), + want("auth_needed_to_write", getBool, assignToP), + want("auth_opt_fb", getBool, assignToP), + want("auth_opt_tw", getBool, assignToP), + want("auth_opt_allow_3rdparty", getBool, assignToP), + want("verifyMeta", getBool, assignToP), + want("send_created_email", getBool, assignToP), // ideally the email would be sent on the post, but we post before they click create to allow owner to prepopulate comments. + want( + "launch_presentation_return_url_hex", + getStringLimitLength(1, 9999), + assignToP + ), // LTI editor tool redirect url (once conversation editing is done) + want("context", getOptionalStringLimitLength(999), assignToP), + want( + "tool_consumer_instance_guid", + getOptionalStringLimitLength(999), + assignToP + ), + want("custom_canvas_assignment_id", getInt, assignToP), + want("link_url", getStringLimitLength(1, 9999), assignToP), + want("subscribe_type", getInt, assignToP), + handle_PUT_conversations + ); + + app.put( + "/api/v3/users", + moveToBody, + auth(assignToP), + want("email", getEmail, assignToP), + want("hname", getOptionalStringLimitLength(9999), assignToP), + want("uid_of_user", getInt, assignToP), + handle_PUT_users + ); + + app.delete( + "/api/v3/metadata/questions/:pmqid", + moveToBody, + auth(assignToP), + need("pmqid", getInt, assignToP), + handle_DELETE_metadata_questions + ); + + app.delete( + "/api/v3/metadata/answers/:pmaid", + moveToBody, + auth(assignToP), + need("pmaid", getInt, assignToP), + handle_DELETE_metadata_answers + ); + + app.get( + "/api/v3/metadata/questions", + moveToBody, + authOptional(assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + want("suzinvite", getOptionalStringLimitLength(32), assignToP), + want("zinvite", getOptionalStringLimitLength(300), assignToP), + // TODO want('lastMetaTime', getInt, assignToP, 0), + handle_GET_metadata_questions + ); + + app.post( + "/api/v3/metadata/questions", + moveToBody, + auth(assignToP), + need("key", getOptionalStringLimitLength(999), assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + handle_POST_metadata_questions + ); + + app.post( + "/api/v3/metadata/answers", + moveToBody, + auth(assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + need("pmqid", getInt, assignToP), + need("value", getOptionalStringLimitLength(999), assignToP), + handle_POST_metadata_answers + ); + + app.get( + "/api/v3/metadata/choices", + moveToBody, + auth(assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + handle_GET_metadata_choices + ); + + app.get( + "/api/v3/metadata/answers", + moveToBody, + authOptional(assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + want("pmqid", getInt, assignToP), + want("suzinvite", getOptionalStringLimitLength(32), assignToP), + want("zinvite", getOptionalStringLimitLength(300), assignToP), + // TODO want('lastMetaTime', getInt, assignToP, 0), + handle_GET_metadata_answers + ); + + app.get( + "/api/v3/metadata", + moveToBody, + auth(assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + want("zinvite", getOptionalStringLimitLength(300), assignToP), + want("suzinvite", getOptionalStringLimitLength(32), assignToP), + // TODO want('lastMetaTime', getInt, assignToP, 0), + handle_GET_metadata + ); + + app.get( + "/api/v3/enterprise_deal_url", + moveToBody, + // want('upfront', getBool, assignToP), + need("monthly", getInt, assignToP), + want("maxUsers", getInt, assignToP), + want("plan_name", getOptionalStringLimitLength(99), assignToP), + want("plan_id", getOptionalStringLimitLength(99), assignToP), + handle_GET_enterprise_deal_url + ); + + app.get( + "/api/v3/stripe_account_connect", + handle_GET_stripe_account_connect + ); + + app.get( + "/api/v3/stripe_account_connected_oauth_callback", + moveToBody, + want("code", getStringLimitLength(9999), assignToP), + want("access_token", getStringLimitLength(9999), assignToP), + want("error", getStringLimitLength(9999), assignToP), + want("error_description", getStringLimitLength(9999), assignToP), + handle_GET_stripe_account_connected_oauth_callback + ); + + app.get( + "/api/v3/conversations", + moveToBody, + authOptional(assignToP), + want("include_all_conversations_i_am_in", getBool, assignToP), + want("is_active", getBool, assignToP), + want("is_draft", getBool, assignToP), + want("course_invite", getStringLimitLength(1, 32), assignToP), + want( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + want("want_upvoted", getBool, assignToP), + want("want_mod_url", getBool, assignToP), // NOTE - use this for API only! + want("want_inbox_item_admin_url", getBool, assignToP), // NOTE - use this for API only! + want("want_inbox_item_participant_url", getBool, assignToP), // NOTE - use this for API only! + want("want_inbox_item_admin_html", getBool, assignToP), // NOTE - use this for API only! + want("want_inbox_item_participant_html", getBool, assignToP), // NOTE - use this for API only! + want("limit", getIntInRange(1, 9999), assignToP), // not allowing a super high limit to prevent DOS attacks + want("context", getStringLimitLength(1, 999), assignToP), + want("xid", getStringLimitLength(1, 999), assignToP), + handle_GET_conversations + ); + + app.get( + "/api/v3/reports", + moveToBody, + authOptional(assignToP), + want( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + want("report_id", getReportIdFetchRid, assignToPCustom("rid")), // Knowing the report_id grants the user permission to view the report + handle_GET_reports + ); + + app.post( + "/api/v3/mathUpdate", + moveToBody, + auth(assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + need("math_update_type", getStringLimitLength(1, 32), assignToP), // expecting "recompute" or "update" + handle_POST_math_update + ); + + app.post( + "/api/v3/reports", + auth(assignToP), + want( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + handle_POST_reports + ); + + app.put( + "/api/v3/reports", + moveToBody, + auth(assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + need("report_id", getReportIdFetchRid, assignToPCustom("rid")), + want("report_name", getStringLimitLength(999), assignToP), + want("label_x_neg", getStringLimitLength(999), assignToP), + want("label_x_pos", getStringLimitLength(999), assignToP), + want("label_y_neg", getStringLimitLength(999), assignToP), + want("label_y_pos", getStringLimitLength(999), assignToP), + want("label_group_0", getStringLimitLength(999), assignToP), + want("label_group_1", getStringLimitLength(999), assignToP), + want("label_group_2", getStringLimitLength(999), assignToP), + want("label_group_3", getStringLimitLength(999), assignToP), + want("label_group_4", getStringLimitLength(999), assignToP), + want("label_group_5", getStringLimitLength(999), assignToP), + want("label_group_6", getStringLimitLength(999), assignToP), + want("label_group_7", getStringLimitLength(999), assignToP), + want("label_group_8", getStringLimitLength(999), assignToP), + want("label_group_9", getStringLimitLength(999), assignToP), + handle_PUT_reports + ); + + app.get( + "/api/v3/contexts", + moveToBody, + authOptional(assignToP), + handle_GET_contexts + ); + + app.post( + "/api/v3/contexts", + auth(assignToP), + need("name", getStringLimitLength(1, 300), assignToP), + handle_POST_contexts + ); + + app.post( + "/api/v3/reserve_conversation_id", + auth(assignToP), + handle_POST_reserve_conversation_id + ); + + // TODO check to see if ptpt has answered necessary metadata questions. + app.post( + "/api/v3/conversations", + auth(assignToP), + want("is_active", getBool, assignToP, true), + want("is_draft", getBool, assignToP, false), + want("is_anon", getBool, assignToP, false), + want("owner_sees_participation_stats", getBool, assignToP, false), + want("profanity_filter", getBool, assignToP, true), + want("short_url", getBool, assignToP, false), + want("spam_filter", getBool, assignToP, true), + want("strict_moderation", getBool, assignToP, false), + want("context", getOptionalStringLimitLength(999), assignToP, ""), + want("topic", getOptionalStringLimitLength(1000), assignToP, ""), + want("description", getOptionalStringLimitLength(50000), assignToP, ""), + want("conversation_id", getStringLimitLength(6, 300), assignToP, ""), + want("is_slack", getBool, assignToP, false), + want("is_data_open", getBool, assignToP, false), + want("ownerXid", getStringLimitLength(1, 999), assignToP), + handle_POST_conversations + ); + + app.post( + "/api/v3/query_participants_by_metadata", + auth(assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + need("pmaids", getArrayOfInt, assignToP, []), + handle_POST_query_participants_by_metadata + ); + + app.post( + "/api/v3/sendCreatedLinkToEmail", + auth(assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + handle_POST_sendCreatedLinkToEmail + ); + + app.get( + "/api/v3/twitterBtn", + moveToBody, + authOptional(assignToP), + want("dest", getStringLimitLength(9999), assignToP), + want("owner", getBool, assignToP, true), + handle_GET_twitterBtn + ); + + app.get( + "/api/v3/twitter_oauth_callback", + moveToBody, + enableAgid, + auth(assignToP), + need("dest", getStringLimitLength(9999), assignToP), + need("oauth_token", getStringLimitLength(9999), assignToP), // TODO verify + need("oauth_verifier", getStringLimitLength(9999), assignToP), // TODO verify + want("owner", getBool, assignToP, true), + handle_GET_twitter_oauth_callback + ); + + app.get( + "/api/v3/locations", + moveToBody, + authOptional(assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + need("gid", getInt, assignToP), + handle_GET_locations + ); + + app.put( + "/api/v3/ptptois", + moveToBody, + auth(assignToP), + need("mod", getInt, assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + resolve_pidThing("pid", assignToP), + handle_PUT_ptptois + ); + + app.get( + "/api/v3/ptptois", + moveToBody, + authOptional(assignToP), + want("mod", getInt, assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + need("conversation_id", getStringLimitLength(1, 1000), assignToP), + handle_GET_ptptois + ); + + app.get( + "/api/v3/votes/famous", + moveToBody, + authOptional(assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + want("math_tick", getInt, assignToP, -1), + want("ptptoiLimit", getIntInRange(0, 99), assignToP), + handle_GET_votes_famous + ); + + app.get( + "/api/v3/twitter_users", + moveToBody, + authOptional(assignToP), + want("twitter_user_id", getInt, assignToP), // if not provided, returns info for the signed-in user + handle_GET_twitter_users + ); + + app.post( + "/api/v3/einvites", + need("email", getEmail, assignToP), + handle_POST_einvites + ); + + app.get( + "/api/v3/einvites", + moveToBody, + need("einvite", getStringLimitLength(1, 100), assignToP), + handle_GET_einvites + ); + + app.post( + "/api/v3/LTI/setup_assignment", + authOptional(assignToP), + need("oauth_consumer_key", getStringLimitLength(1, 9999), assignToP), // for now, this will be the professor, but may also be the school + need("user_id", getStringLimitLength(1, 9999), assignToP), + need("context_id", getStringLimitLength(1, 9999), assignToP), + want( + "tool_consumer_instance_guid", + getStringLimitLength(1, 9999), + assignToP + ), // scope to the right LTI/canvas? instance + want("roles", getStringLimitLength(1, 9999), assignToP), + want("user_image", getStringLimitLength(1, 9999), assignToP), + want( + "lis_person_contact_email_primary", + getStringLimitLength(1, 9999), + assignToP + ), + want("lis_person_name_full", getStringLimitLength(1, 9999), assignToP), + want("lis_outcome_service_url", getStringLimitLength(1, 9999), assignToP), // send grades here! + want( + "launch_presentation_return_url", + getStringLimitLength(1, 9999), + assignToP + ), + want( + "ext_content_return_types", + getStringLimitLength(1, 9999), + assignToP + ), + handle_POST_lti_setup_assignment + ); + + app.post( + "/api/v3/LTI/conversation_assignment", + need("oauth_consumer_key", getStringLimitLength(1, 9999), assignToP), // for now, this will be the professor, but may also be the school need("oauth_consumer_key", getStringLimitLength(1, 9999), assignToP), // for now, this will be the professor, but may also be the school + need("oauth_signature_method", getStringLimitLength(1, 9999), assignToP), // probably "HMAC-SHA-1" + need("oauth_nonce", getStringLimitLength(1, 9999), assignToP), //rK81yoLBZhxVeaQHOUQQV8Ug5AObZtWv4R0ezQN20 + need("oauth_version", getStringLimitLength(1, 9999), assignToP), //'1.0' + need("oauth_timestamp", getStringLimitLength(1, 9999), assignToP), //? + need("oauth_callback", getStringLimitLength(1, 9999), assignToP), // about:blank + + need("user_id", getStringLimitLength(1, 9999), assignToP), + need("context_id", getStringLimitLength(1, 9999), assignToP), + want("roles", getStringLimitLength(1, 9999), assignToP), + want("user_image", getStringLimitLength(1, 9999), assignToP), + // per assignment stuff + want("custom_canvas_assignment_id", getInt, assignToP), // NOTE: it enters our system as an int, but we'll + want("lis_outcome_service_url", getStringLimitLength(1, 9999), assignToP), // send grades here! + want("lis_result_sourcedid", getStringLimitLength(1, 9999), assignToP), // grading context + want( + "tool_consumer_instance_guid", + getStringLimitLength(1, 9999), + assignToP + ), // canvas instance + handle_POST_lti_conversation_assignment + ); + + app.get( + "/api/v3/LTI/setup_assignment.xml", + handle_GET_setup_assignment_xml + ); + + app.get( + "/api/v3/LTI/conversation_assignment.xml", + handle_GET_conversation_assigmnent_xml + ); + + app.get( + "/canvas_app_instructions.png", + handle_GET_canvas_app_instructions_png + ); + + app.post( + "/api/v3/users/invite", + // authWithApiKey(assignToP), + auth(assignToP), + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + need("conversation_id", getStringLimitLength(1, 1000), assignToP), // we actually need conversation_id to build a url + // need('single_use_tokens', getBool, assignToP), + need("emails", getArrayOfStringNonEmpty, assignToP), + handle_POST_users_invite + ); + + app.get( + /^\/slack_login_code.*/, + moveToBody, + authOptional(assignToP), + handle_GET_slack_login + ); + + app.post( + "/api/v3/slack/user/invites", + need("slack_team", getStringLimitLength(1, 20), assignToP), + need("slack_user_id", getStringLimitLength(1, 20), assignToP), + handle_POST_slack_user_invites + ); + + app.get( + /^\/polis_site_id.*/, + moveToBody, + need("parent_url", getStringLimitLength(1, 10000), assignToP), + want("referrer", getStringLimitLength(1, 10000), assignToP), + want("auth_needed_to_vote", getBool, assignToP), + want("auth_needed_to_write", getBool, assignToP), + want("auth_opt_fb", getBool, assignToP), + want("auth_opt_tw", getBool, assignToP), + want("auth_opt_allow_3rdparty", getBool, assignToP), + want("show_vis", getBool, assignToP), + want("show_share", getBool, assignToP), + want("bg_white", getBool, assignToP), + want("topic", getStringLimitLength(1, 1000), assignToP), + want("ucv", getBool, assignToP), // not persisted + want("ucw", getBool, assignToP), // not persisted + want("ucsh", getBool, assignToP), // not persisted + want("ucst", getBool, assignToP), // not persisted + want("ucsd", getBool, assignToP), // not persisted + want("ucsv", getBool, assignToP), // not persisted + want("ucsf", getBool, assignToP), // not persisted + want("ui_lang", getStringLimitLength(1, 10), assignToP), // not persisted + want("dwok", getStringLimitLength(1, 1000), assignToP), // not persisted + want("xid", getStringLimitLength(1, 999), assignToP), // not persisted + want("subscribe_type", getStringLimitLength(1, 9), assignToP), // not persisted + want("x_name", getStringLimitLength(1, 746), assignToP), // not persisted here, but later on POST vote/comment + want("x_profile_image_url", getStringLimitLength(1, 3000), assignToP), // not persisted here, but later on POST vote/comment + want("x_email", getStringLimitLength(256), assignToP), // not persisted here, but later on POST vote/comment + want("build", getStringLimitLength(300), assignToP), + handle_GET_implicit_conversation_generation + ); + + app.get( + "/iip/:conversation_id", + moveToBody, + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + handle_GET_iip_conversation + ); + + app.get( + "/iim/:conversation_id", + moveToBody, + need( + "conversation_id", + getConversationIdFetchZid, + assignToPCustom("zid") + ), + handle_GET_iim_conversation + ); + + // proxy for fetching twitter profile images + // Needed because Twitter doesn't provide profile pics in response to a request - you have to fetch the user info, then parse that to get the URL, requiring two round trips. + // There is a bulk user data API, but it's too slow to block on in our /famous route. + // So references to this route are injected into the twitter part of the /famous response. + app.get( + "/twitter_image", + moveToBody, + need("id", getStringLimitLength(999), assignToP), + handle_GET_twitter_image + ); + + // TODO this should probably be exempt from the CORS restrictions + app.get( + "/api/v3/launchPrep", + moveToBody, + need("dest", getStringLimitLength(1, 10000), assignToP), + handle_GET_launchPrep + ); + + app.get("/api/v3/tryCookie", moveToBody, handle_GET_tryCookie); + + app.get( + "/api/v3/verify", + moveToBody, + need("e", getStringLimitLength(1, 1000), assignToP), + handle_GET_verification + ); + + app.post( + "/api/v3/contributors", + authOptional(assignToP), + need("agreement_version", getIntInRange(1, 999999), assignToP), + need("name", getStringLimitLength(746), assignToP), + need("email", getStringLimitLength(256), assignToP), + need("github_id", getStringLimitLength(256), assignToP), + need("company_name", getStringLimitLength(746), assignToP), + handle_POST_contributors + ); + + app.post( + "/api/v3/waitinglist", + need("name", getStringLimitLength(746), assignToP), + need("email", getEmail, assignToP), + want("affiliation", getStringLimitLength(999), assignToP), + want("role", getStringLimitLength(999), assignToP), + need("campaign", getStringLimitLength(100), assignToP), + handle_POST_waitinglist + ); + + app.post( + "/api/v3/metrics", + authOptional(assignToP), + need("types", getArrayOfInt, assignToP), + need("times", getArrayOfInt, assignToP), + need("durs", getArrayOfInt, assignToP), + need("clientTimestamp", getInt, assignToP), + handle_POST_metrics + ); + + function makeFetchIndexWithoutPreloadData() { + let port = portForParticipationFiles; + return function (req, res) { + return fetchIndexWithoutPreloadData(req, res, port); + }; + } + + // Conversation aliases + app.get(/^\/football$/, makeRedirectorTo("/2arcefpshi")); + app.get(/^\/pdf$/, makeRedirectorTo("/23mymwyhkn")); // pdf 2017 + app.get(/^\/nabi$/, makeRedirectorTo("/8ufpzc6fkm")); // + + app.get(/^\/[0-9][0-9A-Za-z]+(\/.*)?/, fetchIndexForConversation); // conversation view + app.get(/^\/explore\/[0-9][0-9A-Za-z]+(\/.*)?/, fetchIndexForConversation); // power view + app.get(/^\/share\/[0-9][0-9A-Za-z]+(\/.*)?/, fetchIndexForConversation); // share view + app.get(/^\/summary\/[0-9][0-9A-Za-z]+(\/.*)?/, fetchIndexForConversation); // summary view + app.get(/^\/ot\/[0-9][0-9A-Za-z]+(\/.*)?/, fetchIndexForConversation); // conversation view, one-time url + // TODO consider putting static files on /static, and then using a catch-all to serve the index. + app.get(/^\/conversation\/create(\/.*)?/, fetchIndexWithoutPreloadData); + app.get(/^\/user\/create(\/.*)?$/, fetchIndexWithoutPreloadData); + app.get(/^\/user\/login(\/.*)?$/, fetchIndexWithoutPreloadData); + + app.get(/^\/settings(\/.*)?$/, makeFetchIndexWithoutPreloadData()); + app.get(/^\/settings\/enterprise}.*$/, makeFetchIndexWithoutPreloadData()); + + app.get(/^\/user\/logout(\/.*)?$/, fetchIndexWithoutPreloadData); + + // admin dash routes + app.get(/^\/m\/[0-9][0-9A-Za-z]+(\/.*)?/, fetchIndexForAdminPage); + app.get(/^\/integrate(\/.*)?/, fetchIndexForAdminPage); + app.get(/^\/other-conversations(\/.*)?/, fetchIndexForAdminPage); + app.get(/^\/account(\/.*)?/, fetchIndexForAdminPage); + app.get(/^\/bot(\/.*)?/, fetchIndexForAdminPage); + app.get(/^\/conversations(\/.*)?/, fetchIndexForAdminPage); + app.get(/^\/signout(\/.*)?/, fetchIndexForAdminPage); + app.get(/^\/signin(\/.*)?/, fetchIndexForAdminPage); + app.get( + /^\/dist\/admin_bundle.js$/, + makeFileFetcher(hostname, portForAdminFiles, "/dist/admin_bundle.js", { + "Content-Type": "application/javascript", + }) + ); + app.get( + /^\/__webpack_hmr$/, + makeFileFetcher(hostname, portForAdminFiles, "/__webpack_hmr", { + "Content-Type": "eventsource", + }) + ); + app.get(/^\/privacy$/, fetchIndexForAdminPage); + app.get(/^\/tos$/, fetchIndexForAdminPage); + + // admin dash-based landers + app.get(/^\/gov(\/.*)?/, fetchIndexForAdminPage); + app.get(/^\/createuser(\/.*)?/, fetchIndexForAdminPage); + app.get(/^\/contrib(\/.*)?/, fetchIndexForAdminPage); + + app.get(/^\/bot\/install(\/.*)?/, fetchIndexForAdminPage); + app.get(/^\/bot\/support(\/.*)?/, fetchIndexForAdminPage); + + app.get(/^\/inbox(\/.*)?$/, fetchIndexWithoutPreloadData); + // app.get(/^\/r/, fetchIndexWithoutPreloadData); + app.get(/^\/hk/, fetchIndexWithoutPreloadData); + app.get(/^\/s\//, fetchIndexWithoutPreloadData); + app.get(/^\/s$/, fetchIndexWithoutPreloadData); + app.get(/^\/hk\/new/, fetchIndexWithoutPreloadData); + app.get(/^\/inboxApiTest/, fetchIndexWithoutPreloadData); + app.get(/^\/pwresetinit.*/, fetchIndexForAdminPage); + app.get(/^\/demo\/[0-9][0-9A-Za-z]+/, fetchIndexForConversation); + app.get(/^\/demo$/, fetchIndexForAdminPage); + app.get(/^\/pwreset.*/, fetchIndexForAdminPage); + app.get(/^\/company$/, fetchIndexForAdminPage); + + app.get(/^\/report\/r?[0-9][0-9A-Za-z]+(\/.*)?/, fetchIndexForReportPage); + + app.get(/^\/thirdPartyCookieTestPt1\.html$/, fetchThirdPartyCookieTestPt1); + app.get(/^\/thirdPartyCookieTestPt2\.html$/, fetchThirdPartyCookieTestPt2); + + app.get( + /^\/embed$/, + makeFileFetcher(hostname, portForAdminFiles, "/embed.html", { + "Content-Type": "text/html", + }) + ); + app.get( + /^\/embedPreprod$/, + makeFileFetcher(hostname, portForAdminFiles, "/embedPreprod.html", { + "Content-Type": "text/html", + }) + ); + app.get( + /^\/embedReport$/, + makeFileFetcher(hostname, portForAdminFiles, "/embedReport.html", { + "Content-Type": "text/html", + }) + ); + app.get( + /^\/embedReportPreprod$/, + makeFileFetcher(hostname, portForAdminFiles, "/embedReportPreprod.html", { + "Content-Type": "text/html", + }) + ); + app.get( + /^\/canvas_setup_backup_instructions$/, + makeFileFetcher( + hostname, + portForParticipationFiles, + "/canvas_setup_backup_instructions.html", + { + "Content-Type": "text/html", + } + ) + ); + app.get( + /^\/styleguide$/, + makeFileFetcher(hostname, portForParticipationFiles, "/styleguide.html", { + "Content-Type": "text/html", + }) + ); + // Duplicate url for content at root. Needed so we have something for "About" to link to. + app.get(/^\/about$/, makeRedirectorTo("/home")); + app.get(/^\/home(\/.*)?/, fetchIndexForAdminPage); + app.get( + /^\/s\/CTE\/?$/, + makeFileFetcher(hostname, portForParticipationFiles, "/football.html", { + "Content-Type": "text/html", + }) + ); + app.get( + /^\/twitterAuthReturn(\/.*)?$/, + makeFileFetcher( + hostname, + portForParticipationFiles, + "/twitterAuthReturn.html", + { + "Content-Type": "text/html", + } + ) + ); + + app.get(/^\/localFile\/.*/, handle_GET_localFile_dev_only); + + app.get("/", handle_GET_conditionalIndexFetcher); + + // proxy static files + app.get(/^\/cached\/.*/, proxy); + app.get(/^\/font\/.*/, proxy); + app.get(/^\/.*embed.*js\/.*/, proxy); + + // ends in slash? redirect to non-slash version + app.get(/.*\//, function (req, res) { + let pathAndQuery = req.originalUrl; + + // remove slash at end + if (pathAndQuery.endsWith("/")) { + pathAndQuery = pathAndQuery.slice(0, pathAndQuery.length - 1); + } + + // remove slashes before "?" + if (pathAndQuery.indexOf("?") >= 1) { + pathAndQuery = pathAndQuery.replace("/?", "?"); + } + + let fullUrl = req.protocol + "://" + req.get("host") + pathAndQuery; + + if (pathAndQuery !== req.originalUrl) { + res.redirect(fullUrl); + } else { + proxy(req, res); + } + }); + + var missingFilesGet404 = false; + if (missingFilesGet404) { + // 404 everything else + app.get( + /^\/[^(api\/)]?.*/, + makeFileFetcher(hostname, portForAdminFiles, "/404.html", { + "Content-Type": "text/html", + }) + ); + } else { + // proxy everything else + app.get(/^\/[^(api\/)]?.*/, proxy); + } + + app.listen(process.env.PORT); + + winston.log("info", "started on port " + process.env.PORT); + }, + function (err) { + console.error("failed to init server"); + console.error(err); + } +); diff --git a/server/package-lock.json b/server/package-lock.json index 91eae4624..0cc41b1f4 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -1,5910 +1,8 @@ { "name": "polis", "version": "0.0.0", - "lockfileVersion": 2, + "lockfileVersion": 1, "requires": true, - "packages": { - "": { - "name": "polis", - "version": "0.0.0", - "dependencies": { - "@google-cloud/translate": "^1.0.0", - "@slack/client": "^3.5.3", - "akismet": "0.0.11", - "async": "0.1.22", - "aws-sdk": "^2.78.0", - "babel-eslint": "^6.0.4", - "badwords": "0.0.3", - "bcrypt": "5.0.0", - "bluebird": "3.5.0", - "boolean": "^0.1.3", - "connect-timeout": "1.9.0", - "eslint": "2.13.1", - "express": "3.21.2", - "fb": "1.0.2", - "http-proxy": "1.18.1", - "intercom-client": "2.9.4", - "intercom.io": "1.5.0", - "lru-cache": "3.0.0", - "mimelib": "0.2.19", - "nodemailer": "^6.4.16", - "nodemailer-mailgun-transport": "^2.0.0", - "oauth": "0.9.14", - "optimist": "0.3.7", - "p3p": "0.0.2", - "pg": "7.4.3", - "pg-connection-string": "2.0.0", - "pg-native": "3.0.0", - "pushover-notifications": "0.1.9", - "replacestream": "4.0.0", - "request": "^2.72.0", - "request-promise": "^3.0.0", - "response-time": "2.3.1", - "simple-oauth2": "0.2.1", - "sql": "0.34.0", - "stripe": "~2.5.0", - "underscore": "1.12.1", - "valid-url": "1.0.9", - "winston": "1.0.2" - }, - "devDependencies": { - "prettier": "^2.2.1" - } - }, - "node_modules/@google-cloud/common": { - "version": "0.13.6", - "resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-0.13.6.tgz", - "integrity": "sha1-qdjhN7xCmkSrqWif5qDkMxeE+FM=", - "dependencies": { - "array-uniq": "^1.0.3", - "arrify": "^1.0.1", - "concat-stream": "^1.6.0", - "create-error-class": "^3.0.2", - "duplexify": "^3.5.0", - "ent": "^2.2.0", - "extend": "^3.0.0", - "google-auto-auth": "^0.7.1", - "is": "^3.2.0", - "log-driver": "^1.2.5", - "methmeth": "^1.1.0", - "modelo": "^4.2.0", - "request": "^2.79.0", - "retry-request": "^3.0.0", - "split-array-stream": "^1.0.0", - "stream-events": "^1.0.1", - "string-format-obj": "^1.1.0", - "through2": "^2.0.3" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/@google-cloud/translate": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@google-cloud/translate/-/translate-1.1.0.tgz", - "integrity": "sha512-UzllqCIb5aJys7qzX2pJ2eTrgJN8nd9TQurjPPBPoiIzuHojY5bTIdNUEEo01o1u9bQ/2trlaKEuwYXhoGXIww==", - "dependencies": { - "@google-cloud/common": "^0.13.0", - "arrify": "^1.0.0", - "extend": "^3.0.1", - "is": "^3.0.1", - "is-html": "^1.0.0", - "propprop": "^0.3.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/@sinonjs/formatio": { - "version": "2.0.0", - "resolved": "http://registry.npmjs.org/@sinonjs/formatio/-/formatio-2.0.0.tgz", - "integrity": "sha512-ls6CAMA6/5gG+O/IdsBcblvnd8qcO/l1TYoNeAzp3wcISOxlPXQEus0mLcdwazEkWjaBdaJ3TaxmNgCLWwvWzg==", - "dependencies": { - "samsam": "1.3.0" - } - }, - "node_modules/@slack/client": { - "version": "3.16.0", - "resolved": "https://registry.npmjs.org/@slack/client/-/client-3.16.0.tgz", - "integrity": "sha512-CWr7a3rTVrN5Vs8GYReRAvTourbXHOqB1zglcskj05ICH4GZL5BOAza2ARai+qc3Nz0nY08Bozi1x0014KOqlg==", - "dependencies": { - "async": "^1.5.0", - "bluebird": "^3.3.3", - "eventemitter3": "^1.1.1", - "https-proxy-agent": "^1.0.0", - "inherits": "^2.0.1", - "lodash": "^4.13.1", - "pkginfo": "^0.4.0", - "request": ">=2.0.0 <2.77.0", - "retry": "^0.9.0", - "url-join": "0.0.1", - "winston": "^2.1.1", - "ws": "^1.0.1" - }, - "engines": { - "node": ">= 0.12.x", - "npm": ">= 1.1.x" - } - }, - "node_modules/@slack/client/node_modules/assert-plus": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", - "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/@slack/client/node_modules/async": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" - }, - "node_modules/@slack/client/node_modules/aws-sign2": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", - "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=", - "engines": { - "node": "*" - } - }, - "node_modules/@slack/client/node_modules/boom": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", - "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", - "dependencies": { - "hoek": "2.x.x" - }, - "engines": { - "node": ">=0.10.40" - } - }, - "node_modules/@slack/client/node_modules/caseless": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz", - "integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c=" - }, - "node_modules/@slack/client/node_modules/cryptiles": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", - "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", - "dependencies": { - "boom": "2.x.x" - }, - "engines": { - "node": ">=0.10.40" - } - }, - "node_modules/@slack/client/node_modules/form-data": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", - "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.5", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 0.12" - } - }, - "node_modules/@slack/client/node_modules/har-validator": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz", - "integrity": "sha1-zcvAgYgmWtEZtqWnyKtw7s+10n0=", - "dependencies": { - "chalk": "^1.1.1", - "commander": "^2.9.0", - "is-my-json-valid": "^2.12.4", - "pinkie-promise": "^2.0.0" - }, - "bin": { - "har-validator": "bin/har-validator" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/@slack/client/node_modules/hawk": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", - "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", - "dependencies": { - "boom": "2.x.x", - "cryptiles": "2.x.x", - "hoek": "2.x.x", - "sntp": "1.x.x" - }, - "engines": { - "node": ">=0.10.32" - } - }, - "node_modules/@slack/client/node_modules/hoek": { - "version": "2.16.3", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", - "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", - "engines": { - "node": ">=0.10.40" - } - }, - "node_modules/@slack/client/node_modules/http-signature": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", - "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", - "dependencies": { - "assert-plus": "^0.2.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - }, - "engines": { - "node": ">=0.8", - "npm": ">=1.3.7" - } - }, - "node_modules/@slack/client/node_modules/node-uuid": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz", - "integrity": "sha1-sEDrCSOWivq/jTL7HxfxFn/auQc=", - "bin": { - "uuid": "bin/uuid" - } - }, - "node_modules/@slack/client/node_modules/qs": { - "version": "6.3.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.3.2.tgz", - "integrity": "sha1-51vV9uJoEioqDgvaYwslUMFmUCw=", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/@slack/client/node_modules/request": { - "version": "2.76.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.76.0.tgz", - "integrity": "sha1-vkRQWv73A2CgQ2lVEGvjlF2VVg4=", - "dependencies": { - "aws-sign2": "~0.6.0", - "aws4": "^1.2.1", - "caseless": "~0.11.0", - "combined-stream": "~1.0.5", - "extend": "~3.0.0", - "forever-agent": "~0.6.1", - "form-data": "~2.1.1", - "har-validator": "~2.0.6", - "hawk": "~3.1.3", - "http-signature": "~1.1.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.7", - "node-uuid": "~1.4.7", - "oauth-sign": "~0.8.1", - "qs": "~6.3.0", - "stringstream": "~0.0.4", - "tough-cookie": "~2.3.0", - "tunnel-agent": "~0.4.1" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@slack/client/node_modules/sntp": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", - "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", - "dependencies": { - "hoek": "2.x.x" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@slack/client/node_modules/tunnel-agent": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", - "integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=", - "engines": { - "node": "*" - } - }, - "node_modules/@slack/client/node_modules/winston": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/winston/-/winston-2.4.2.tgz", - "integrity": "sha512-4S/Ad4ZfSNl8OccCLxnJmNISWcm2joa6Q0YGDxlxMzH0fgSwWsjMt+SmlNwCqdpaPg3ev1HKkMBsIiXeSUwpbA==", - "dependencies": { - "async": "~1.0.0", - "colors": "1.0.x", - "cycle": "1.0.x", - "eyes": "0.1.x", - "isstream": "0.1.x", - "stack-trace": "0.0.x" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/@slack/client/node_modules/winston/node_modules/async": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async/-/async-1.0.0.tgz", - "integrity": "sha1-+PwEyjoTeErenhZBr5hXjPvWR6k=" - }, - "node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" - }, - "node_modules/agent-base": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-2.1.1.tgz", - "integrity": "sha1-1t4Q1a9hMtW9aSQn1G/FOFOQlMc=", - "dependencies": { - "extend": "~3.0.0", - "semver": "~5.0.1" - } - }, - "node_modules/ajv": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", - "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", - "dependencies": { - "co": "^4.6.0", - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0" - } - }, - "node_modules/akismet": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/akismet/-/akismet-0.0.11.tgz", - "integrity": "sha1-ofFFVvzgAzXrr9W2z2ZTUC7o/oU=", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/ansi-regex": { - "version": "2.1.1", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ansi-styles": { - "version": "2.2.1", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" - }, - "node_modules/are-we-there-yet": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", - "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", - "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "node_modules/array-uniq": { - "version": "1.0.3", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/arrify": { - "version": "1.0.1", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/asn1": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", - "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=" - }, - "node_modules/assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/ast-types": { - "version": "0.13.3", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.3.tgz", - "integrity": "sha512-XTZ7xGML849LkQP86sWdQzfhwbt3YwIO6MqbX9mUNYY98VKaaVZP7YNNm70IpwecbkkxmfC5IYAzOQ/2p29zRA==", - "engines": { - "node": ">=4" - } - }, - "node_modules/async": { - "version": "0.1.22", - "resolved": "https://registry.npmjs.org/async/-/async-0.1.22.tgz", - "integrity": "sha1-D8GqoIig4+8Ovi2IMbqw3PiEUGE=" - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, - "node_modules/aws-sdk": { - "version": "2.230.1", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.230.1.tgz", - "integrity": "sha1-SUzvau0uFtse2cEqz0vSpzF/U2U=", - "dependencies": { - "buffer": "4.9.1", - "events": "1.1.1", - "ieee754": "1.1.8", - "jmespath": "0.15.0", - "querystring": "0.2.0", - "sax": "1.2.1", - "url": "0.10.3", - "uuid": "3.1.0", - "xml2js": "0.4.17", - "xmlbuilder": "4.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/aws-sdk/node_modules/uuid": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", - "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==", - "bin": { - "uuid": "bin/uuid" - } - }, - "node_modules/aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", - "engines": { - "node": "*" - } - }, - "node_modules/aws4": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.7.0.tgz", - "integrity": "sha512-32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w==" - }, - "node_modules/babel-eslint": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-6.1.2.tgz", - "integrity": "sha1-UpNBn+NnLWZZjTJ9qWlFZ7pqXy8=", - "dependencies": { - "babel-traverse": "^6.0.20", - "babel-types": "^6.0.19", - "babylon": "^6.0.18", - "lodash.assign": "^4.0.0", - "lodash.pickby": "^4.0.0" - } - }, - "node_modules/babel-eslint/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/babel-eslint/node_modules/ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/babel-eslint/node_modules/babel-code-frame": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", - "dependencies": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" - } - }, - "node_modules/babel-eslint/node_modules/babel-messages": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", - "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", - "dependencies": { - "babel-runtime": "^6.22.0" - } - }, - "node_modules/babel-eslint/node_modules/babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", - "dependencies": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" - } - }, - "node_modules/babel-eslint/node_modules/babel-traverse": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", - "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", - "dependencies": { - "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" - } - }, - "node_modules/babel-eslint/node_modules/babel-types": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", - "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", - "dependencies": { - "babel-runtime": "^6.26.0", - "esutils": "^2.0.2", - "lodash": "^4.17.4", - "to-fast-properties": "^1.0.3" - } - }, - "node_modules/babel-eslint/node_modules/babylon": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", - "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", - "bin": { - "babylon": "bin/babylon.js" - } - }, - "node_modules/babel-eslint/node_modules/chalk": { - "version": "1.1.3", - "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dependencies": { - "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" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/babel-eslint/node_modules/core-js": { - "version": "2.5.7", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz", - "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==" - }, - "node_modules/babel-eslint/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/babel-eslint/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/babel-eslint/node_modules/esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/babel-eslint/node_modules/globals": { - "version": "9.18.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", - "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/babel-eslint/node_modules/has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/babel-eslint/node_modules/invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "dependencies": { - "loose-envify": "^1.0.0" - } - }, - "node_modules/babel-eslint/node_modules/js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" - }, - "node_modules/babel-eslint/node_modules/lodash": { - "version": "4.17.10", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", - "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==" - }, - "node_modules/babel-eslint/node_modules/lodash.assign": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", - "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=" - }, - "node_modules/babel-eslint/node_modules/lodash.pickby": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.pickby/-/lodash.pickby-4.6.0.tgz", - "integrity": "sha1-feoh2MGNdwOifHBMFdO4SmfjOv8=" - }, - "node_modules/babel-eslint/node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/babel-eslint/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "node_modules/babel-eslint/node_modules/regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" - }, - "node_modules/babel-eslint/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/babel-eslint/node_modules/supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/babel-eslint/node_modules/to-fast-properties": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", - "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/badwords": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/badwords/-/badwords-0.0.3.tgz", - "integrity": "sha1-x8Y/1MwsQM5cSnTldH7GH+GPWk4=" - }, - "node_modules/balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" - }, - "node_modules/base64-js": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", - "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==" - }, - "node_modules/base64url": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/base64url/-/base64url-2.0.0.tgz", - "integrity": "sha1-6sFuA+oUOO/5Qj1puqNiYu0fcLs=" - }, - "node_modules/bcrypt": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.0.0.tgz", - "integrity": "sha512-jB0yCBl4W/kVHM2whjfyqnxTmOHkCX4kHEa5nYKSoGeYe8YrjTYTc87/6bwt1g8cmV0QrbhKriETg9jWtcREhg==", - "hasInstallScript": true, - "dependencies": { - "node-addon-api": "^3.0.0", - "node-pre-gyp": "0.15.0" - }, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/bcrypt-pbkdf": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", - "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", - "optional": true, - "dependencies": { - "tweetnacl": "^0.14.3" - } - }, - "node_modules/bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "dependencies": { - "file-uri-to-path": "1.0.0" - } - }, - "node_modules/bluebird": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz", - "integrity": "sha1-eRQg1/VR7qKJdFOop3ZT+WYG1nw=" - }, - "node_modules/boolean": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/boolean/-/boolean-0.1.3.tgz", - "integrity": "sha512-G6TadQPFofmOhzkzgtVSOYaosjpnPyVCDeZ4J7oPF74OmhM2++fXUdwu7NULTwgntK5KIMcls1UslwAY2btL6g==" - }, - "node_modules/boom": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", - "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", - "dependencies": { - "hoek": "4.x.x" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/buffer": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", - "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", - "dependencies": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" - } - }, - "node_modules/buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" - }, - "node_modules/buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" - }, - "node_modules/buffer-writer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-1.0.1.tgz", - "integrity": "sha1-Iqk2kB4wKa/NdUfrRIfOtpejvwg=" - }, - "node_modules/bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/capture-stack-trace": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz", - "integrity": "sha1-Sm+gc5nCa7pH8LJJa00PtAjFVQ0=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" - }, - "node_modules/chalk": { - "version": "1.1.3", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dependencies": { - "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" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" - }, - "node_modules/co": { - "version": "4.6.0", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", - "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" - } - }, - "node_modules/code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/colors": { - "version": "1.0.3", - "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/combined-stream": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", - "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/commander": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", - "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==" - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "node_modules/concat-stream": { - "version": "1.6.0", - "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", - "engines": [ - "node >= 0.8" - ], - "dependencies": { - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "node_modules/connect-timeout": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/connect-timeout/-/connect-timeout-1.9.0.tgz", - "integrity": "sha1-vCcyaxIhA3FL6/oNlYurM/ZSLjo=", - "dependencies": { - "http-errors": "~1.6.1", - "ms": "2.0.0", - "on-finished": "~2.3.0", - "on-headers": "~1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/connect-timeout/node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/connect-timeout/node_modules/http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", - "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" - }, - "node_modules/consolidate": { - "version": "0.15.1", - "resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.15.1.tgz", - "integrity": "sha512-DW46nrsMJgy9kqAbPt5rKaCr7uFtpo4mSUvLHIUbJEjm0vo+aY5QLwBUq3FK4tRnJr/X0Psc0C4jf/h+HtXSMw==", - "dependencies": { - "bluebird": "^3.1.1" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/core-util-is": { - "version": "1.0.2", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "node_modules/create-error-class": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz", - "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", - "dependencies": { - "capture-stack-trace": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/cryptiles": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", - "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", - "dependencies": { - "boom": "5.x.x" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/cryptiles/node_modules/boom": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", - "integrity": "sha1-XdnabuOl8wIHdDYpDLcX0/SlTgI=", - "dependencies": { - "hoek": "4.x.x" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/cycle": { - "version": "1.0.3", - "integrity": "sha1-IegLK+hYD5i0aPN5QwZisEbDStI=", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dependencies": { - "assert-plus": "^1.0.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/data-uri-to-buffer": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-1.2.0.tgz", - "integrity": "sha512-vKQ9DTQPN1FLYiiEEOQ6IBGFqvjCa5rSK3cWMy/Nespm5d/x3dGFT9UBZnkLxCwua/IXBi2TYnwTEpsOvhC4UQ==" - }, - "node_modules/debug": { - "version": "2.6.9", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=" - }, - "node_modules/degenerator": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-1.0.4.tgz", - "integrity": "sha1-/PSQo37OJmRk2cxDGrmMWBnO0JU=", - "dependencies": { - "ast-types": "0.x.x", - "escodegen": "1.x.x", - "esprima": "3.x.x" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" - }, - "node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/detect-libc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", - "bin": { - "detect-libc": "bin/detect-libc.js" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/duplexify": { - "version": "3.5.4", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.5.4.tgz", - "integrity": "sha512-JzYSLYMhoVVBe8+mbHQ4KgpvHpm0DZpJuL8PY93Vyv1fW7jYJ90LoXa1di/CVbJM+TgMs91rbDapE/RNIfnJsA==", - "dependencies": { - "end-of-stream": "^1.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.0.0", - "stream-shift": "^1.0.0" - } - }, - "node_modules/ecc-jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", - "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", - "optional": true, - "dependencies": { - "jsbn": "~0.1.0" - } - }, - "node_modules/ecdsa-sig-formatter": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.9.tgz", - "integrity": "sha1-S8kmJ07Dtau1AW5+HWCSGsJisqE=", - "dependencies": { - "base64url": "^2.0.0", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/ee-first": { - "version": "1.1.1", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" - }, - "node_modules/end-of-stream": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", - "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/ent": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", - "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=" - }, - "node_modules/es6-promise": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" - }, - "node_modules/es6-promisify": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", - "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", - "dependencies": { - "es6-promise": "^4.0.3" - } - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/escodegen": { - "version": "1.14.3", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", - "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", - "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=4.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" - } - }, - "node_modules/escodegen/node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-2.13.1.tgz", - "integrity": "sha1-5MyPoPAJ+4KaquI4VaKTYL4fbBE=", - "dependencies": { - "chalk": "^1.1.3", - "concat-stream": "^1.4.6", - "debug": "^2.1.1", - "doctrine": "^1.2.2", - "es6-map": "^0.1.3", - "escope": "^3.6.0", - "espree": "^3.1.6", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "file-entry-cache": "^1.1.1", - "glob": "^7.0.3", - "globals": "^9.2.0", - "ignore": "^3.1.2", - "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", - "optionator": "^0.8.1", - "path-is-absolute": "^1.0.0", - "path-is-inside": "^1.0.1", - "pluralize": "^1.2.1", - "progress": "^1.1.8", - "require-uncached": "^1.0.2", - "shelljs": "^0.6.0", - "strip-json-comments": "~1.0.1", - "table": "^3.7.8", - "text-table": "~0.2.0", - "user-home": "^2.0.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/eslint/node_modules/acorn": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.2.tgz", - "integrity": "sha512-cJrKCNcr2kv8dlDnbw+JPUGjHZzo4myaxOLmpOX8a+rgX94YeTcTMv/LFJUSByRpc+i4GgVnnhLxvMu/2Y+rqw==", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/eslint/node_modules/acorn-jsx": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", - "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", - "dependencies": { - "acorn": "^3.0.4" - } - }, - "node_modules/eslint/node_modules/acorn-jsx/node_modules/acorn": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", - "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/eslint/node_modules/ajv": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", - "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", - "dependencies": { - "co": "^4.6.0", - "json-stable-stringify": "^1.0.1" - } - }, - "node_modules/eslint/node_modules/ajv-keywords": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz", - "integrity": "sha1-MU3QpLM2j609/NxU7eYXG4htrzw=" - }, - "node_modules/eslint/node_modules/ansi-escapes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", - "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint/node_modules/ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/eslint/node_modules/array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", - "dependencies": { - "array-uniq": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint/node_modules/array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint/node_modules/arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint/node_modules/balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" - }, - "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint/node_modules/caller-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", - "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", - "dependencies": { - "callsites": "^0.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint/node_modules/callsites": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", - "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint/node_modules/chalk": { - "version": "1.1.3", - "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dependencies": { - "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" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint/node_modules/circular-json": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", - "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==" - }, - "node_modules/eslint/node_modules/cli-cursor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", - "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", - "dependencies": { - "restore-cursor": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint/node_modules/cli-width": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", - "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=" - }, - "node_modules/eslint/node_modules/co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", - "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" - } - }, - "node_modules/eslint/node_modules/code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint/node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "node_modules/eslint/node_modules/concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "engines": [ - "node >= 0.8" - ], - "dependencies": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "node_modules/eslint/node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "node_modules/eslint/node_modules/d": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", - "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", - "dependencies": { - "es5-ext": "^0.10.9" - } - }, - "node_modules/eslint/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/eslint/node_modules/deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=" - }, - "node_modules/eslint/node_modules/del": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", - "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", - "dependencies": { - "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" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint/node_modules/doctrine": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", - "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", - "dependencies": { - "esutils": "^2.0.2", - "isarray": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint/node_modules/es5-ext": { - "version": "0.10.46", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.46.tgz", - "integrity": "sha512-24XxRvJXNFwEMpJb3nOkiRJKRoupmjYmOPVlI65Qy2SrtxwOTB+g6ODjBKOtwEHbYrhWRty9xxOWLNdClT2djw==", - "dependencies": { - "es6-iterator": "~2.0.3", - "es6-symbol": "~3.1.1", - "next-tick": "1" - } - }, - "node_modules/eslint/node_modules/es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", - "dependencies": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, - "node_modules/eslint/node_modules/es6-map": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", - "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", - "dependencies": { - "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" - } - }, - "node_modules/eslint/node_modules/es6-set": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", - "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", - "dependencies": { - "d": "1", - "es5-ext": "~0.10.14", - "es6-iterator": "~2.0.1", - "es6-symbol": "3.1.1", - "event-emitter": "~0.3.5" - } - }, - "node_modules/eslint/node_modules/es6-symbol": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", - "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", - "dependencies": { - "d": "1", - "es5-ext": "~0.10.14" - } - }, - "node_modules/eslint/node_modules/es6-weak-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz", - "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=", - "dependencies": { - "d": "1", - "es5-ext": "^0.10.14", - "es6-iterator": "^2.0.1", - "es6-symbol": "^3.1.1" - } - }, - "node_modules/eslint/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/eslint/node_modules/escope": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz", - "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=", - "dependencies": { - "es6-map": "^0.1.3", - "es6-weak-map": "^2.0.1", - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/eslint/node_modules/espree": { - "version": "3.5.4", - "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", - "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", - "dependencies": { - "acorn": "^5.5.0", - "acorn-jsx": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint/node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint/node_modules/esrecurse": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", - "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", - "dependencies": { - "estraverse": "^4.1.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/eslint/node_modules/estraverse": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", - "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint/node_modules/esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint/node_modules/event-emitter": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", - "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", - "dependencies": { - "d": "1", - "es5-ext": "~0.10.14" - } - }, - "node_modules/eslint/node_modules/exit-hook": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz", - "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint/node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" - }, - "node_modules/eslint/node_modules/figures": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", - "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", - "dependencies": { - "escape-string-regexp": "^1.0.5", - "object-assign": "^4.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint/node_modules/file-entry-cache": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-1.3.1.tgz", - "integrity": "sha1-RMYepgeuS+nBQC9B9EJwy/4zT/g=", - "dependencies": { - "flat-cache": "^1.2.1", - "object-assign": "^4.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint/node_modules/flat-cache": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz", - "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=", - "dependencies": { - "circular-json": "^0.3.1", - "del": "^2.0.2", - "graceful-fs": "^4.1.2", - "write": "^0.2.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint/node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "node_modules/eslint/node_modules/glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - } - }, - "node_modules/eslint/node_modules/globals": { - "version": "9.18.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", - "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint/node_modules/globby": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", - "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", - "dependencies": { - "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" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint/node_modules/graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/eslint/node_modules/has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint/node_modules/ignore": { - "version": "3.3.10", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", - "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==" - }, - "node_modules/eslint/node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/eslint/node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/eslint/node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "node_modules/eslint/node_modules/inquirer": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz", - "integrity": "sha1-HvK/1jUE3wvHV4X/+MLEHfEvB34=", - "dependencies": { - "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" - } - }, - "node_modules/eslint/node_modules/is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dependencies": { - "number-is-nan": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint/node_modules/is-path-cwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", - "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint/node_modules/is-path-in-cwd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", - "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", - "dependencies": { - "is-path-inside": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint/node_modules/is-path-inside": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", - "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", - "dependencies": { - "path-is-inside": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint/node_modules/is-resolvable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", - "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==" - }, - "node_modules/eslint/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "node_modules/eslint/node_modules/js-yaml": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", - "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/eslint/node_modules/json-stable-stringify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", - "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", - "dependencies": { - "jsonify": "~0.0.0" - } - }, - "node_modules/eslint/node_modules/jsonify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", - "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=" - }, - "node_modules/eslint/node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/eslint/node_modules/lodash": { - "version": "4.17.10", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", - "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==" - }, - "node_modules/eslint/node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/eslint/node_modules/minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" - }, - "node_modules/eslint/node_modules/mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dependencies": { - "minimist": "0.0.8" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/eslint/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "node_modules/eslint/node_modules/mute-stream": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz", - "integrity": "sha1-j7+rsKmKJT0xhDMfno3rc3L6xsA=" - }, - "node_modules/eslint/node_modules/number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint/node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint/node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/eslint/node_modules/onetime": { - "version": "1.1.0", - "resolved": "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", - "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint/node_modules/optionator": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", - "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", - "dependencies": { - "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" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/eslint/node_modules/os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint/node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint/node_modules/path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=" - }, - "node_modules/eslint/node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint/node_modules/pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint/node_modules/pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "dependencies": { - "pinkie": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint/node_modules/pluralize": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz", - "integrity": "sha1-0aIUg/0iu0HlihL6NCGCMUCJfEU=" - }, - "node_modules/eslint/node_modules/prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/eslint/node_modules/process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" - }, - "node_modules/eslint/node_modules/progress": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", - "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/eslint/node_modules/readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "dependencies": { - "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" - } - }, - "node_modules/eslint/node_modules/readline2": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz", - "integrity": "sha1-QQWWCP/BVHV7cV2ZidGZ/783LjU=", - "dependencies": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "mute-stream": "0.0.5" - } - }, - "node_modules/eslint/node_modules/require-uncached": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", - "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", - "dependencies": { - "caller-path": "^0.1.0", - "resolve-from": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint/node_modules/resolve-from": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", - "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint/node_modules/restore-cursor": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", - "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", - "dependencies": { - "exit-hook": "^1.0.0", - "onetime": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint/node_modules/rimraf": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", - "dependencies": { - "glob": "^7.0.5" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/eslint/node_modules/run-async": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz", - "integrity": "sha1-yK1KXhEGYeQCp9IbUw4AnyX444k=", - "dependencies": { - "once": "^1.3.0" - } - }, - "node_modules/eslint/node_modules/rx-lite": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz", - "integrity": "sha1-Gc5QLKVyZl87ZHsQk5+X/RYV8QI=" - }, - "node_modules/eslint/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/eslint/node_modules/shelljs": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.6.1.tgz", - "integrity": "sha1-7GIRvtGSBEIIj+D3Cyg3Iy7SyKg=", - "bin": { - "shjs": "bin/shjs" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint/node_modules/slice-ansi": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", - "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint/node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" - }, - "node_modules/eslint/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/eslint/node_modules/string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dependencies": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint/node_modules/strip-json-comments": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", - "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=", - "bin": { - "strip-json-comments": "cli.js" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/eslint/node_modules/supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/eslint/node_modules/table": { - "version": "3.8.3", - "resolved": "https://registry.npmjs.org/table/-/table-3.8.3.tgz", - "integrity": "sha1-K7xULw/amGGnVdOUf+/Ys/UThV8=", - "dependencies": { - "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.0.0" - } - }, - "node_modules/eslint/node_modules/table/node_modules/ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint/node_modules/table/node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint/node_modules/table/node_modules/string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dependencies": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint/node_modules/table/node_modules/strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dependencies": { - "ansi-regex": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint/node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" - }, - "node_modules/eslint/node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" - }, - "node_modules/eslint/node_modules/type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dependencies": { - "prelude-ls": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/eslint/node_modules/typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" - }, - "node_modules/eslint/node_modules/user-home": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz", - "integrity": "sha1-nHC/2Babwdy/SGBODwS4tJzenp8=", - "dependencies": { - "os-homedir": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint/node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "node_modules/eslint/node_modules/wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=" - }, - "node_modules/eslint/node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "node_modules/eslint/node_modules/write": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", - "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", - "dependencies": { - "mkdirp": "^0.5.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/esprima": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", - "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eventemitter3": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-1.2.0.tgz", - "integrity": "sha1-HIaZHYFq0eUEdQ5zh0Ik7PO+xQg=" - }, - "node_modules/events": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", - "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=", - "engines": { - "node": ">=0.4.x" - } - }, - "node_modules/express": { - "version": "3.21.2", - "resolved": "https://registry.npmjs.org/express/-/express-3.21.2.tgz", - "integrity": "sha1-DCkD7lxU5j1lqWFwdkcDVQZlo94=", - "dependencies": { - "basic-auth": "~1.0.3", - "commander": "2.6.0", - "connect": "2.30.2", - "content-disposition": "0.5.0", - "content-type": "~1.0.1", - "cookie": "0.1.3", - "cookie-signature": "1.0.6", - "debug": "~2.2.0", - "depd": "~1.0.1", - "escape-html": "1.0.2", - "etag": "~1.7.0", - "fresh": "0.3.0", - "merge-descriptors": "1.0.0", - "methods": "~1.1.1", - "mkdirp": "0.5.1", - "parseurl": "~1.3.0", - "proxy-addr": "~1.0.8", - "range-parser": "~1.0.2", - "send": "0.13.0", - "utils-merge": "1.0.0", - "vary": "~1.0.1" - }, - "bin": { - "express": "bin/express" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/express/node_modules/accepts": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.2.13.tgz", - "integrity": "sha1-5fHzkoxtlf2WVYw27D2dDeSm7Oo=", - "dependencies": { - "mime-types": "~2.1.6", - "negotiator": "0.5.3" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express/node_modules/base64-url": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/base64-url/-/base64-url-1.2.1.tgz", - "integrity": "sha1-GZ/WYXAqDnt9yubgaYuwicUvbXg=" - }, - "node_modules/express/node_modules/basic-auth": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.0.4.tgz", - "integrity": "sha1-Awk1sB3nyblKgksp8/zLdQ06UpA=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express/node_modules/basic-auth-connect": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/basic-auth-connect/-/basic-auth-connect-1.0.0.tgz", - "integrity": "sha1-/bC0OWLKe0BFanwrtI/hc9otISI=" - }, - "node_modules/express/node_modules/batch": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/batch/-/batch-0.5.3.tgz", - "integrity": "sha1-PzQU84AyF0O/wQQvmoP/HVgk1GQ=" - }, - "node_modules/express/node_modules/body-parser": { - "version": "1.13.3", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.13.3.tgz", - "integrity": "sha1-wIzzMMM1jhUQFqBXRvE/ApyX+pc=", - "dependencies": { - "bytes": "2.1.0", - "content-type": "~1.0.1", - "debug": "~2.2.0", - "depd": "~1.0.1", - "http-errors": "~1.3.1", - "iconv-lite": "0.4.11", - "on-finished": "~2.3.0", - "qs": "4.0.0", - "raw-body": "~2.1.2", - "type-is": "~1.6.6" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/express/node_modules/bytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-2.1.0.tgz", - "integrity": "sha1-rJPEEOL/ycx89LRks4KJBn9eR7Q=" - }, - "node_modules/express/node_modules/commander": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.6.0.tgz", - "integrity": "sha1-nfflL7Kgyw+4kFjugMMQQiXzfh0=", - "engines": { - "node": ">= 0.6.x" - } - }, - "node_modules/express/node_modules/compressible": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.14.tgz", - "integrity": "sha1-MmxfUH+7BV9UEWeCuWmoG2einac=", - "dependencies": { - "mime-db": ">= 1.34.0 < 2" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express/node_modules/compression": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.5.2.tgz", - "integrity": "sha1-sDuNhub4rSloPLqN+R3cb/x3s5U=", - "dependencies": { - "accepts": "~1.2.12", - "bytes": "2.1.0", - "compressible": "~2.0.5", - "debug": "~2.2.0", - "on-headers": "~1.0.0", - "vary": "~1.0.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/express/node_modules/connect": { - "version": "2.30.2", - "resolved": "https://registry.npmjs.org/connect/-/connect-2.30.2.tgz", - "integrity": "sha1-jam8vooFTT0xjXTf7JA7XDmhtgk=", - "dependencies": { - "basic-auth-connect": "1.0.0", - "body-parser": "~1.13.3", - "bytes": "2.1.0", - "compression": "~1.5.2", - "connect-timeout": "~1.6.2", - "content-type": "~1.0.1", - "cookie": "0.1.3", - "cookie-parser": "~1.3.5", - "cookie-signature": "1.0.6", - "csurf": "~1.8.3", - "debug": "~2.2.0", - "depd": "~1.0.1", - "errorhandler": "~1.4.2", - "express-session": "~1.11.3", - "finalhandler": "0.4.0", - "fresh": "0.3.0", - "http-errors": "~1.3.1", - "method-override": "~2.3.5", - "morgan": "~1.6.1", - "multiparty": "3.3.2", - "on-headers": "~1.0.0", - "parseurl": "~1.3.0", - "pause": "0.1.0", - "qs": "4.0.0", - "response-time": "~2.3.1", - "serve-favicon": "~2.3.0", - "serve-index": "~1.7.2", - "serve-static": "~1.10.0", - "type-is": "~1.6.6", - "utils-merge": "1.0.0", - "vhost": "~3.0.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/express/node_modules/connect-timeout": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/connect-timeout/-/connect-timeout-1.6.2.tgz", - "integrity": "sha1-3ppexh4zoStu2qt7XwYumMWZuI4=", - "dependencies": { - "debug": "~2.2.0", - "http-errors": "~1.3.1", - "ms": "0.7.1", - "on-headers": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/express/node_modules/content-disposition": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.0.tgz", - "integrity": "sha1-QoT+auBjCHRjnkToCkGMKTQTXp4=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express/node_modules/content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express/node_modules/cookie": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.1.3.tgz", - "integrity": "sha1-5zSlwUF/zkctWu+Cw4HKu2TRpDU=", - "engines": { - "node": "*" - } - }, - "node_modules/express/node_modules/cookie-parser": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.3.5.tgz", - "integrity": "sha1-nXVVcPtdF4kHcSJ6AjFNm+fPg1Y=", - "dependencies": { - "cookie": "0.1.3", - "cookie-signature": "1.0.6" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/express/node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" - }, - "node_modules/express/node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "node_modules/express/node_modules/crc": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/crc/-/crc-3.3.0.tgz", - "integrity": "sha1-+mIuG8OIvyVzCQgta2UgDOZwkLo=" - }, - "node_modules/express/node_modules/csrf": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/csrf/-/csrf-3.0.6.tgz", - "integrity": "sha1-thEg3c7q/JHnbtUxO7XAsmZ7cQo=", - "dependencies": { - "rndm": "1.2.0", - "tsscmp": "1.0.5", - "uid-safe": "2.1.4" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/express/node_modules/csurf": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/csurf/-/csurf-1.8.3.tgz", - "integrity": "sha1-I/KhO/HY/OHQyZZYg5RELLqGpWo=", - "dependencies": { - "cookie": "0.1.3", - "cookie-signature": "1.0.6", - "csrf": "~3.0.0", - "http-errors": "~1.3.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/express/node_modules/debug": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", - "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", - "dependencies": { - "ms": "0.7.1" - } - }, - "node_modules/express/node_modules/depd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.0.1.tgz", - "integrity": "sha1-gK7GTJ1tl+ZcwqnKqTwKpqv3Oqo=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express/node_modules/destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" - }, - "node_modules/express/node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" - }, - "node_modules/express/node_modules/errorhandler": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/errorhandler/-/errorhandler-1.4.3.tgz", - "integrity": "sha1-t7cO2PNZ6duICS8tIMD4MUIK2D8=", - "dependencies": { - "accepts": "~1.3.0", - "escape-html": "~1.0.3" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/express/node_modules/errorhandler/node_modules/accepts": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", - "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", - "dependencies": { - "mime-types": "~2.1.18", - "negotiator": "0.6.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express/node_modules/errorhandler/node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" - }, - "node_modules/express/node_modules/errorhandler/node_modules/negotiator": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", - "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express/node_modules/escape-html": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.2.tgz", - "integrity": "sha1-130y+pjjjC9BroXpJ44ODmuhAiw=" - }, - "node_modules/express/node_modules/etag": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.7.0.tgz", - "integrity": "sha1-A9MLX2fdbmMtKUXTDWZScxo01dg=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express/node_modules/express-session": { - "version": "1.11.3", - "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.11.3.tgz", - "integrity": "sha1-XMmPP1/4Ttg1+Ry/CqvQxxB0AK8=", - "dependencies": { - "cookie": "0.1.3", - "cookie-signature": "1.0.6", - "crc": "3.3.0", - "debug": "~2.2.0", - "depd": "~1.0.1", - "on-headers": "~1.0.0", - "parseurl": "~1.3.0", - "uid-safe": "~2.0.0", - "utils-merge": "1.0.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/express/node_modules/express-session/node_modules/uid-safe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.0.0.tgz", - "integrity": "sha1-p/PGymSh9qXQTsDvPkw9U2cxcTc=", - "dependencies": { - "base64-url": "1.2.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/express/node_modules/finalhandler": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-0.4.0.tgz", - "integrity": "sha1-llpS2ejQXSuFdUhUH7ibU6JJfZs=", - "dependencies": { - "debug": "~2.2.0", - "escape-html": "1.0.2", - "on-finished": "~2.3.0", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/express/node_modules/forwarded": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", - "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express/node_modules/fresh": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.3.0.tgz", - "integrity": "sha1-ZR+DjiJCTnVm3hYdg1jKoZn4PU8=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express/node_modules/http-errors": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.3.1.tgz", - "integrity": "sha1-GX4izevUGYWF6GlO9nhhl7ke2UI=", - "dependencies": { - "inherits": "~2.0.1", - "statuses": "1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express/node_modules/iconv-lite": { - "version": "0.4.11", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.11.tgz", - "integrity": "sha1-LstC/SlHRJIiCaLnxATayHk9it4=", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/express/node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "node_modules/express/node_modules/ipaddr.js": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.0.5.tgz", - "integrity": "sha1-X6eM8wG4JceKvDBC2BJyMEnqI8c=", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/express/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, - "node_modules/express/node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express/node_modules/merge-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.0.tgz", - "integrity": "sha1-IWnPdTjhsMyH+4jhUC2EdLv3mGQ=" - }, - "node_modules/express/node_modules/method-override": { - "version": "2.3.10", - "resolved": "https://registry.npmjs.org/method-override/-/method-override-2.3.10.tgz", - "integrity": "sha1-49r41d7hDdLc59SuiNYrvud0drQ=", - "dependencies": { - "debug": "2.6.9", - "methods": "~1.1.2", - "parseurl": "~1.3.2", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/express/node_modules/method-override/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/express/node_modules/method-override/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "node_modules/express/node_modules/method-override/node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/express/node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express/node_modules/mime": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz", - "integrity": "sha1-EV+eO2s9rylZmDyzjxSaLUDrXVM=", - "bin": { - "mime": "cli.js" - } - }, - "node_modules/express/node_modules/mime-db": { - "version": "1.36.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.36.0.tgz", - "integrity": "sha512-L+xvyD9MkoYMXb1jAmzI/lWYAxAMCPvIBSWur0PZ5nOf5euahRLVqH//FKW9mWp2lkqUgYiXPgkzfMUFi4zVDw==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express/node_modules/mime-types": { - "version": "2.1.20", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.20.tgz", - "integrity": "sha512-HrkrPaP9vGuWbLK1B1FfgAkbqNjIuy4eHlIYnFi7kamZyLLrGlo2mpcx0bBmNpKqBtYtAfGbodDddIgddSJC2A==", - "dependencies": { - "mime-db": "~1.36.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express/node_modules/minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" - }, - "node_modules/express/node_modules/mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dependencies": { - "minimist": "0.0.8" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/express/node_modules/morgan": { - "version": "1.6.1", - "resolved": "http://registry.npmjs.org/morgan/-/morgan-1.6.1.tgz", - "integrity": "sha1-X9gYOYxoGcuiinzWZk8pL+HAu/I=", - "dependencies": { - "basic-auth": "~1.0.3", - "debug": "~2.2.0", - "depd": "~1.0.1", - "on-finished": "~2.3.0", - "on-headers": "~1.0.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/express/node_modules/ms": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", - "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=" - }, - "node_modules/express/node_modules/multiparty": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/multiparty/-/multiparty-3.3.2.tgz", - "integrity": "sha1-Nd5oBNwZZD5SSfPT473GyM4wHT8=", - "dependencies": { - "readable-stream": "~1.1.9", - "stream-counter": "~0.2.0" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/express/node_modules/negotiator": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.5.3.tgz", - "integrity": "sha1-Jp1cR2gQ7JLtvntsLygxY4T5p+g=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express/node_modules/on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/express/node_modules/on-headers": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz", - "integrity": "sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c=", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/express/node_modules/parseurl": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", - "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/express/node_modules/pause": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/pause/-/pause-0.1.0.tgz", - "integrity": "sha1-68ikqGGf8LioGsFRPDQ0/0af23Q=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express/node_modules/proxy-addr": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-1.0.10.tgz", - "integrity": "sha1-DUCoL4Afw1VWfS7LZe/j8HfxIcU=", - "dependencies": { - "forwarded": "~0.1.0", - "ipaddr.js": "1.0.5" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express/node_modules/qs": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-4.0.0.tgz", - "integrity": "sha1-wx2bdOwn33XlQ6hseHKO2NRiNgc=" - }, - "node_modules/express/node_modules/random-bytes": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", - "integrity": "sha1-T2ih3Arli9P7lYSMMDJNt11kNgs=", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/express/node_modules/range-parser": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.0.3.tgz", - "integrity": "sha1-aHKCNTXGkuLCoBA4Jq/YLC4P8XU=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express/node_modules/raw-body": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.1.7.tgz", - "integrity": "sha1-rf6s4uT7MJgFgBTQjActzFl1h3Q=", - "dependencies": { - "bytes": "2.4.0", - "iconv-lite": "0.4.13", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/express/node_modules/raw-body/node_modules/bytes": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-2.4.0.tgz", - "integrity": "sha1-fZcZb51br39pNeJZhVSe3SpsIzk=" - }, - "node_modules/express/node_modules/raw-body/node_modules/iconv-lite": { - "version": "0.4.13", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz", - "integrity": "sha1-H4irpKsLFQjoMSrMOTRfNumS4vI=", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/express/node_modules/readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "node_modules/express/node_modules/rndm": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/rndm/-/rndm-1.2.0.tgz", - "integrity": "sha1-8z/pz7Urv9UgqhgyO8ZdsRCht2w=" - }, - "node_modules/express/node_modules/send": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.13.0.tgz", - "integrity": "sha1-UY+SGusFYK7H3KspkLFM9vPM5d4=", - "dependencies": { - "debug": "~2.2.0", - "depd": "~1.0.1", - "destroy": "1.0.3", - "escape-html": "1.0.2", - "etag": "~1.7.0", - "fresh": "0.3.0", - "http-errors": "~1.3.1", - "mime": "1.3.4", - "ms": "0.7.1", - "on-finished": "~2.3.0", - "range-parser": "~1.0.2", - "statuses": "~1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/express/node_modules/send/node_modules/destroy": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.3.tgz", - "integrity": "sha1-tDO0ck5x/YVR2YhRdIUcX8N34sk=" - }, - "node_modules/express/node_modules/send/node_modules/statuses": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.2.1.tgz", - "integrity": "sha1-3e1FzBglbVHtQK7BQkidXGECbSg=" - }, - "node_modules/express/node_modules/serve-favicon": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/serve-favicon/-/serve-favicon-2.3.2.tgz", - "integrity": "sha1-3UGeJo3gEqtysxnTN/IQUBP5OB8=", - "dependencies": { - "etag": "~1.7.0", - "fresh": "0.3.0", - "ms": "0.7.2", - "parseurl": "~1.3.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/express/node_modules/serve-favicon/node_modules/ms": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", - "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=" - }, - "node_modules/express/node_modules/serve-index": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.7.3.tgz", - "integrity": "sha1-egV/xu4o3GP2RWbl+lexEahq7NI=", - "dependencies": { - "accepts": "~1.2.13", - "batch": "0.5.3", - "debug": "~2.2.0", - "escape-html": "~1.0.3", - "http-errors": "~1.3.1", - "mime-types": "~2.1.9", - "parseurl": "~1.3.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/express/node_modules/serve-index/node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" - }, - "node_modules/express/node_modules/serve-static": { - "version": "1.10.3", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.10.3.tgz", - "integrity": "sha1-zlpuzTEB/tXsCYJ9rCKpwpv7BTU=", - "dependencies": { - "escape-html": "~1.0.3", - "parseurl": "~1.3.1", - "send": "0.13.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/express/node_modules/serve-static/node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express/node_modules/serve-static/node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" - }, - "node_modules/express/node_modules/serve-static/node_modules/send": { - "version": "0.13.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.13.2.tgz", - "integrity": "sha1-dl52B8gFVFK7pvCwUllTUJhgNt4=", - "dependencies": { - "debug": "~2.2.0", - "depd": "~1.1.0", - "destroy": "~1.0.4", - "escape-html": "~1.0.3", - "etag": "~1.7.0", - "fresh": "0.3.0", - "http-errors": "~1.3.1", - "mime": "1.3.4", - "ms": "0.7.1", - "on-finished": "~2.3.0", - "range-parser": "~1.0.3", - "statuses": "~1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/express/node_modules/serve-static/node_modules/statuses": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.2.1.tgz", - "integrity": "sha1-3e1FzBglbVHtQK7BQkidXGECbSg=" - }, - "node_modules/express/node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express/node_modules/stream-counter": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/stream-counter/-/stream-counter-0.2.0.tgz", - "integrity": "sha1-3tJmVWMZyLDiIoErnPOyb6fZR94=", - "dependencies": { - "readable-stream": "~1.1.8" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/express/node_modules/string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - }, - "node_modules/express/node_modules/tsscmp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.5.tgz", - "integrity": "sha1-fcSjOvcVgatDN9qR2FylQn69mpc=", - "engines": { - "node": ">=0.6.x" - } - }, - "node_modules/express/node_modules/type-is": { - "version": "1.6.16", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", - "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.18" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express/node_modules/uid-safe": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.4.tgz", - "integrity": "sha1-Otbzg2jG1MjHXsF2I/t5qh0HHYE=", - "dependencies": { - "random-bytes": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/express/node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/express/node_modules/utils-merge": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz", - "integrity": "sha1-ApT7kiu5N1FTVBxPcJYjHyh8ivg=", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/express/node_modules/vary": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.0.1.tgz", - "integrity": "sha1-meSYFWaihhGN+yuBc1ffeZM3bRA=", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/express/node_modules/vhost": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/vhost/-/vhost-3.0.2.tgz", - "integrity": "sha1-L7HezUxGaqiLD5NBrzPcGv8keNU=", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/extend": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", - "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=" - }, - "node_modules/extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "engines": [ - "node >=0.6.0" - ] - }, - "node_modules/eyes": { - "version": "0.1.8", - "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=", - "engines": { - "node": "> 0.1.90" - } - }, - "node_modules/fast-deep-equal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", - "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" - }, - "node_modules/fb": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/fb/-/fb-1.0.2.tgz", - "integrity": "sha1-SHLM+h/BzgE5LmAmgmqBl0OcAfo=", - "dependencies": { - "debug": "^2.2.0", - "request": "^2.62.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fb/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/fb/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "node_modules/file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" - }, - "node_modules/follow-redirects": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz", - "integrity": "sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "engines": { - "node": "*" - } - }, - "node_modules/form-data": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", - "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "1.0.6", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 0.12" - } - }, - "node_modules/fs-minipass": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", - "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", - "dependencies": { - "minipass": "^2.6.0" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "node_modules/ftp": { - "version": "0.3.10", - "resolved": "https://registry.npmjs.org/ftp/-/ftp-0.3.10.tgz", - "integrity": "sha1-kZfYYa2BQvPmPVqDv+TFn3MwiF0=", - "dependencies": { - "readable-stream": "1.1.x", - "xregexp": "2.0.0" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/ftp/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, - "node_modules/ftp/node_modules/readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "node_modules/ftp/node_modules/string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - }, - "node_modules/gauge": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", - "dependencies": { - "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" - } - }, - "node_modules/gcp-metadata": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-0.3.1.tgz", - "integrity": "sha1-MTgURW58PQ7rj4sISzNXnohvgpo=", - "dependencies": { - "extend": "^3.0.0", - "retry-request": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/generate-function": { - "version": "2.0.0", - "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=" - }, - "node_modules/generate-object-property": { - "version": "1.2.0", - "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", - "dependencies": { - "is-property": "^1.0.0" - } - }, - "node_modules/get-uri": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-2.0.4.tgz", - "integrity": "sha512-v7LT/s8kVjs+Tx0ykk1I+H/rbpzkHvuIq87LmeXptcf5sNWm9uQiwjNAt94SJPA1zOlCntmnOlJvVWKmzsxG8Q==", - "dependencies": { - "data-uri-to-buffer": "1", - "debug": "2", - "extend": "~3.0.2", - "file-uri-to-path": "1", - "ftp": "~0.3.10", - "readable-stream": "2" - } - }, - "node_modules/get-uri/node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "node_modules/getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "dependencies": { - "assert-plus": "^1.0.0" - } - }, - "node_modules/glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - } - }, - "node_modules/google-auth-library": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-0.10.0.tgz", - "integrity": "sha1-bhW6vuhf0d0U2NEoopW2g41SE24=", - "dependencies": { - "gtoken": "^1.2.1", - "jws": "^3.1.4", - "lodash.noop": "^3.0.1", - "request": "^2.74.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/google-auto-auth": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/google-auto-auth/-/google-auto-auth-0.7.2.tgz", - "integrity": "sha1-v5NS1cSgiXvzH9nEkQKLdl++px4=", - "dependencies": { - "async": "^2.3.0", - "gcp-metadata": "^0.3.0", - "google-auth-library": "^0.10.0", - "request": "^2.79.0" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/google-auto-auth/node_modules/async": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.0.tgz", - "integrity": "sha512-xAfGg1/NTLBBKlHFmnd7PlmUW9KhVQIUuSrYem9xzFUZy13ScvtyGGejaae9iAVRiRq9+Cx7DPFaAAhCpyxyPw==", - "dependencies": { - "lodash": "^4.14.0" - } - }, - "node_modules/google-p12-pem": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-0.1.2.tgz", - "integrity": "sha1-M8RqsCGqc0+gMys5YKmj/8svMXc=", - "dependencies": { - "node-forge": "^0.7.1" - }, - "bin": { - "gp12-pem": "bin/gp12-pem" - } - }, - "node_modules/gtoken": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-1.2.3.tgz", - "integrity": "sha1-VQlXG4r9QyLhJM9mz2gRUoTEdtg=", - "dependencies": { - "google-p12-pem": "^0.1.0", - "jws": "^3.0.0", - "mime": "^1.4.1", - "request": "^2.72.0" - } - }, - "node_modules/har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "engines": { - "node": ">=4" - } - }, - "node_modules/har-validator": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", - "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", - "dependencies": { - "ajv": "^5.1.0", - "har-schema": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/has-ansi": { - "version": "2.0.0", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "engines": { - "node": ">=4" - } - }, - "node_modules/has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" - }, - "node_modules/hawk": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", - "integrity": "sha1-r02RTrBl+bXOTZ0RwcshJu7MMDg=", - "dependencies": { - "boom": "4.x.x", - "cryptiles": "3.x.x", - "hoek": "4.x.x", - "sntp": "2.x.x" - }, - "engines": { - "node": ">=4.5.0" - } - }, - "node_modules/hoek": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", - "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/html-tags": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-1.2.0.tgz", - "integrity": "sha1-x43mW1Zjqll5id0rerSSANfk25g=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/htmlencode": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/htmlencode/-/htmlencode-0.0.4.tgz", - "integrity": "sha1-9+LWr74YqHp45jujMI51N2Z0Dj8=" - }, - "node_modules/http-errors": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", - "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", - "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.4", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/http-errors/node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/http-errors/node_modules/setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" - }, - "node_modules/http-errors/node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/http-proxy": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", - "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", - "dependencies": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/http-proxy-agent": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", - "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", - "dependencies": { - "agent-base": "4", - "debug": "3.1.0" - }, - "engines": { - "node": ">= 4.5.0" - } - }, - "node_modules/http-proxy-agent/node_modules/agent-base": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", - "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", - "dependencies": { - "es6-promisify": "^5.0.0" - }, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/http-proxy-agent/node_modules/debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/http-proxy/node_modules/eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" - }, - "node_modules/http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "dependencies": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - }, - "engines": { - "node": ">=0.8", - "npm": ">=1.3.7" - } - }, - "node_modules/https-proxy-agent": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz", - "integrity": "sha1-NffabEjOTdv6JkiRrFk+5f+GceY=", - "dependencies": { - "agent-base": "2", - "debug": "2", - "extend": "3" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ieee754": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz", - "integrity": "sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q=" - }, - "node_modules/ignore-walk": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz", - "integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==", - "dependencies": { - "minimatch": "^3.0.4" - } - }, - "node_modules/inflection": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz", - "integrity": "sha1-ogCTVlbW9fa8TcdQLhrstwMihBY=", - "engines": [ - "node >= 0.4.0" - ] - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.3", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" - }, - "node_modules/intercom-client": { - "version": "2.9.4", - "resolved": "https://registry.npmjs.org/intercom-client/-/intercom-client-2.9.4.tgz", - "integrity": "sha1-cOAYAkrBAURt59A9Wd6t+I7AH9I=", - "dependencies": { - "bluebird": "^3.3.4", - "htmlencode": "^0.0.4", - "request": "^2.83.0", - "sinon": "^4.1.3" - }, - "engines": { - "node": ">= v0.10.0" - } - }, - "node_modules/intercom.io": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/intercom.io/-/intercom.io-1.5.0.tgz", - "integrity": "sha512-wvZcoYd9ByWeDL1FBrfHRRXxaO9vEEX/OtMmFDgL5ononB+0FHaaxENqiUfN1KrIO1c8CXcmLn67oM1AQQtMBQ==", - "dependencies": { - "debug": "^2.2.0", - "lodash": "^4.3.0", - "q": "^1.4.1", - "qs": "^6.1.0", - "request": "^2.74.0" - } - }, - "node_modules/ip": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" - }, - "node_modules/is": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/is/-/is-3.2.1.tgz", - "integrity": "sha1-0Kwq1V63sL7JJqUmb2xmKqqD3KU=", - "engines": { - "node": "*" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dependencies": { - "number-is-nan": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-html": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-html/-/is-html-1.1.0.tgz", - "integrity": "sha1-4E8cGNOUhRETlvmgJz6rUa8hhGQ=", - "dependencies": { - "html-tags": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-my-ip-valid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz", - "integrity": "sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ==" - }, - "node_modules/is-my-json-valid": { - "version": "2.20.5", - "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.20.5.tgz", - "integrity": "sha512-VTPuvvGQtxvCeghwspQu1rBgjYUT6FGxPlvFKbYuFtgc4ADsX3U5ihZOYN0qyU6u+d4X9xXb0IT5O6QpXKt87A==", - "dependencies": { - "generate-function": "^2.0.0", - "generate-object-property": "^1.1.0", - "is-my-ip-valid": "^1.0.0", - "jsonpointer": "^4.0.0", - "xtend": "^4.0.0" - } - }, - "node_modules/is-property": { - "version": "1.0.2", - "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=" - }, - "node_modules/is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-stream-ended": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-stream-ended/-/is-stream-ended-0.1.4.tgz", - "integrity": "sha512-xj0XPvmr7bQFTvirqnFr50o0hQIh6ZItDqloxt5aJrR4NQsYeSsyFQERYGCAzfindAcnKjINnwEEgLx4IqVzQw==" - }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" - }, - "node_modules/isarray": { - "version": "1.0.0", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "node_modules/isstream": { - "version": "0.1.2", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" - }, - "node_modules/jmespath": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", - "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=", - "engines": { - "node": ">= 0.6.0" - } - }, - "node_modules/jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "optional": true - }, - "node_modules/json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" - }, - "node_modules/json-schema-traverse": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" - }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" - }, - "node_modules/jsonpointer": { - "version": "4.0.1", - "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "engines": [ - "node >=0.6.0" - ], - "dependencies": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - } - }, - "node_modules/just-extend": { - "version": "1.1.27", - "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-1.1.27.tgz", - "integrity": "sha512-mJVp13Ix6gFo3SBAy9U/kL+oeZqzlYYYLQBwXVBlVzIsZwBqGREnOro24oC/8s8aox+rJhtZ2DiQof++IrkA+g==" - }, - "node_modules/jwa": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.1.5.tgz", - "integrity": "sha1-oFUs4CIHQs1S4VN3SjKQXDDnVuU=", - "dependencies": { - "base64url": "2.0.0", - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.9", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/jws": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.1.4.tgz", - "integrity": "sha1-+ei5M46KhHJ31kRLFGT2GIDgUKI=", - "dependencies": { - "base64url": "^2.0.0", - "jwa": "^1.1.4", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/libpq": { - "version": "1.8.9", - "resolved": "https://registry.npmjs.org/libpq/-/libpq-1.8.9.tgz", - "integrity": "sha512-herU0STiW3+/XBoYRycKKf49O9hBKK0JbdC2QmvdC5pyCSu8prb9idpn5bUSbxj8XwcEsWPWWWwTDZE9ZTwJ7g==", - "hasInstallScript": true, - "dependencies": { - "bindings": "1.5.0", - "nan": "^2.14.0" - } - }, - "node_modules/libpq/node_modules/nan": { - "version": "2.14.1", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz", - "integrity": "sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==" - }, - "node_modules/lodash": { - "version": "4.17.4", - "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=" - }, - "node_modules/lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" - }, - "node_modules/lodash.noop": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash.noop/-/lodash.noop-3.0.1.tgz", - "integrity": "sha1-OBiPTWUKOkdCWEObluxFsyYXEzw=" - }, - "node_modules/log-driver": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.7.tgz", - "integrity": "sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg==", - "engines": { - "node": ">=0.8.6" - } - }, - "node_modules/lolex": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-2.3.2.tgz", - "integrity": "sha512-A5pN2tkFj7H0dGIAM6MFvHKMJcPnjZsOMvR7ujCjfgW5TbV6H9vb1PgxLtHvjqNZTHsUolz+6/WEO0N1xNx2ng==" - }, - "node_modules/lru-cache": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-3.0.0.tgz", - "integrity": "sha1-ZXBMpEsQcYvEAbp+DBz7W2lCLVw=", - "dependencies": { - "pseudomap": "^1.0.1" - } - }, - "node_modules/lru-cache/node_modules/pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" - }, - "node_modules/mailgun-js": { - "version": "0.22.0", - "resolved": "https://registry.npmjs.org/mailgun-js/-/mailgun-js-0.22.0.tgz", - "integrity": "sha512-a2alg5nuTZA9Psa1pSEIEsbxr1Zrmqx4VkgGCQ30xVh0kIH7Bu57AYILo+0v8QLSdXtCyLaS+KVmdCrQo0uWFA==", - "dependencies": { - "async": "^2.6.1", - "debug": "^4.1.0", - "form-data": "^2.3.3", - "inflection": "~1.12.0", - "is-stream": "^1.1.0", - "path-proxy": "~1.0.0", - "promisify-call": "^2.0.2", - "proxy-agent": "^3.0.3", - "tsscmp": "^1.0.6" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/mailgun-js/node_modules/async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", - "dependencies": { - "lodash": "^4.17.14" - } - }, - "node_modules/mailgun-js/node_modules/debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/mailgun-js/node_modules/form-data": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", - "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 0.12" - } - }, - "node_modules/mailgun-js/node_modules/lodash": { - "version": "4.17.19", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", - "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==" - }, - "node_modules/mailgun-js/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/methmeth": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/methmeth/-/methmeth-1.1.0.tgz", - "integrity": "sha1-6AomYY5S9cQiKGG7dIUQvRDikIk=" - }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/mime-db": { - "version": "1.30.0", - "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.17", - "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", - "dependencies": { - "mime-db": "~1.30.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimelib": { - "version": "0.2.19", - "resolved": "https://registry.npmjs.org/mimelib/-/mimelib-0.2.19.tgz", - "integrity": "sha1-N+yQpqx9AJVIUdCywxYY8KSdoO4=", - "dependencies": { - "addressparser": "~0.3.2", - "encoding": "~0.1.7" - } - }, - "node_modules/mimelib/node_modules/addressparser": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/addressparser/-/addressparser-0.3.2.tgz", - "integrity": "sha1-WYc/Nej89sc2HBAjkmHXbhU0i7I=" - }, - "node_modules/mimelib/node_modules/encoding": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", - "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", - "dependencies": { - "iconv-lite": "~0.4.13" - } - }, - "node_modules/mimelib/node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" - }, - "node_modules/minipass": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", - "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", - "dependencies": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - }, - "node_modules/minipass/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - }, - "node_modules/minizlib": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", - "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", - "dependencies": { - "minipass": "^2.9.0" - } - }, - "node_modules/mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/modelo": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/modelo/-/modelo-4.2.3.tgz", - "integrity": "sha512-9DITV2YEMcw7XojdfvGl3gDD8J9QjZTJ7ZOUuSAkP+F3T6rDbzMJuPktxptsdHYEvZcmXrCD3LMOhdSAEq6zKA==", - "engines": { - "node": "*" - } - }, - "node_modules/ms": { - "version": "2.0.0", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "node_modules/needle": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/needle/-/needle-2.5.0.tgz", - "integrity": "sha512-o/qITSDR0JCyCKEQ1/1bnUXMmznxabbwi/Y4WwJElf+evwJNFNwIDMCCt5IigFVxgeGBJESLohGtIS9gEzo1fA==", - "dependencies": { - "debug": "^3.2.6", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - }, - "bin": { - "needle": "bin/needle" - }, - "engines": { - "node": ">= 4.4.x" - } - }, - "node_modules/needle/node_modules/debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/needle/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/needle/node_modules/sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" - }, - "node_modules/netmask": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/netmask/-/netmask-1.0.6.tgz", - "integrity": "sha1-ICl+idhvb2QA8lDZ9Pa0wZRfzTU=", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/next-tick": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", - "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" - }, - "node_modules/nise": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/nise/-/nise-1.3.3.tgz", - "integrity": "sha512-v1J/FLUB9PfGqZLGDBhQqODkbLotP0WtLo9R4EJY2PPu5f5Xg4o0rA8FDlmrjFSv9vBBKcfnOSpfYYuu5RTHqg==", - "dependencies": { - "@sinonjs/formatio": "^2.0.0", - "just-extend": "^1.1.27", - "lolex": "^2.3.2", - "path-to-regexp": "^1.7.0", - "text-encoding": "^0.6.4" - } - }, - "node_modules/node-addon-api": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.0.0.tgz", - "integrity": "sha512-sSHCgWfJ+Lui/u+0msF3oyCgvdkhxDbkCS6Q8uiJquzOimkJBvX6hl5aSSA7DR1XbMpdM8r7phjcF63sF4rkKg==" - }, - "node_modules/node-forge": { - "version": "0.7.5", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.5.tgz", - "integrity": "sha512-MmbQJ2MTESTjt3Gi/3yG1wGpIMhUfcIypUCGtTizFR9IiccFwxSpfp0vtIZlkFclEqERemxfnSdZEMR9VqqEFQ==", - "engines": { - "node": "*" - } - }, - "node_modules/node-pre-gyp": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.15.0.tgz", - "integrity": "sha512-7QcZa8/fpaU/BKenjcaeFF9hLz2+7S9AqyXFhlH/rilsQ/hPZKK32RtR5EQHJElgu+q5RfbJ34KriI79UWaorA==", - "dependencies": { - "detect-libc": "^1.0.2", - "mkdirp": "^0.5.3", - "needle": "^2.5.0", - "nopt": "^4.0.1", - "npm-packlist": "^1.1.6", - "npmlog": "^4.0.2", - "rc": "^1.2.7", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^4.4.2" - }, - "bin": { - "node-pre-gyp": "bin/node-pre-gyp" - } - }, - "node_modules/node-pre-gyp/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/nodemailer": { - "version": "6.4.16", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.4.16.tgz", - "integrity": "sha512-68K0LgZ6hmZ7PVmwL78gzNdjpj5viqBdFqKrTtr9bZbJYj6BRj5W6WGkxXrEnUl3Co3CBXi3CZBUlpV/foGnOQ==", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/nodemailer-mailgun-transport": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/nodemailer-mailgun-transport/-/nodemailer-mailgun-transport-2.0.0.tgz", - "integrity": "sha512-TPGi2anyS0w/4jv7TJNS3wX5DbNQ2+j+ssnwY4IYxL4QaYXAXewcw6YUtBgnOsEvQVJvmxQLDuW4f4JaMPgfaA==", - "dependencies": { - "consolidate": "^0.15.1", - "mailgun-js": "^0.22.0" - } - }, - "node_modules/nopt": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", - "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", - "dependencies": { - "abbrev": "1", - "osenv": "^0.1.4" - }, - "bin": { - "nopt": "bin/nopt.js" - } - }, - "node_modules/npm-bundled": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz", - "integrity": "sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==", - "dependencies": { - "npm-normalize-package-bin": "^1.0.1" - } - }, - "node_modules/npm-normalize-package-bin": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", - "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==" - }, - "node_modules/npm-packlist": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz", - "integrity": "sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==", - "dependencies": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1", - "npm-normalize-package-bin": "^1.0.1" - } - }, - "node_modules/npmlog": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", - "dependencies": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "node_modules/number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/oauth": { - "version": "0.9.14", - "resolved": "https://registry.npmjs.org/oauth/-/oauth-0.9.14.tgz", - "integrity": "sha1-xXSIg6QLU94wrenKvyEAQUuKCXE=" - }, - "node_modules/oauth-sign": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", - "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", - "engines": { - "node": "*" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/on-finished": { - "version": "2.3.0", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/on-headers": { - "version": "1.0.1", - "integrity": "sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c=", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/optimist": { - "version": "0.3.7", - "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.3.7.tgz", - "integrity": "sha1-yQlBrVnkJzMokjB00s8ufLxuwNk=", - "dependencies": { - "wordwrap": "~0.0.2" - } - }, - "node_modules/optimist/node_modules/wordwrap": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dependencies": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/options": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz", - "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8=", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/osenv": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", - "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", - "dependencies": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "node_modules/p3p": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/p3p/-/p3p-0.0.2.tgz", - "integrity": "sha1-apQSgKau6l7xc7OrlZOyApmhhxA=", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/pac-proxy-agent": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-3.0.1.tgz", - "integrity": "sha512-44DUg21G/liUZ48dJpUSjZnFfZro/0K5JTyFYLBcmh9+T6Ooi4/i4efwUiEy0+4oQusCBqWdhv16XohIj1GqnQ==", - "dependencies": { - "agent-base": "^4.2.0", - "debug": "^4.1.1", - "get-uri": "^2.0.0", - "http-proxy-agent": "^2.1.0", - "https-proxy-agent": "^3.0.0", - "pac-resolver": "^3.0.0", - "raw-body": "^2.2.0", - "socks-proxy-agent": "^4.0.1" - } - }, - "node_modules/pac-proxy-agent/node_modules/agent-base": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", - "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", - "dependencies": { - "es6-promisify": "^5.0.0" - }, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/pac-proxy-agent/node_modules/debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/pac-proxy-agent/node_modules/https-proxy-agent": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-3.0.1.tgz", - "integrity": "sha512-+ML2Rbh6DAuee7d07tYGEKOEi2voWPUGan+ExdPbPW6Z3svq+JCqr0v8WmKPOkz1vOVykPCBSuobe7G8GJUtVg==", - "dependencies": { - "agent-base": "^4.3.0", - "debug": "^3.1.0" - }, - "engines": { - "node": ">= 4.5.0" - } - }, - "node_modules/pac-proxy-agent/node_modules/https-proxy-agent/node_modules/debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/pac-proxy-agent/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/pac-resolver": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-3.0.0.tgz", - "integrity": "sha512-tcc38bsjuE3XZ5+4vP96OfhOugrX+JcnpUbhfuc4LuXBLQhoTthOstZeoQJBDnQUDYzYmdImKsbz0xSl1/9qeA==", - "dependencies": { - "co": "^4.6.0", - "degenerator": "^1.0.4", - "ip": "^1.1.5", - "netmask": "^1.0.6", - "thunkify": "^2.1.2" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-proxy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/path-proxy/-/path-proxy-1.0.0.tgz", - "integrity": "sha1-GOijaFn8nS8aU7SN7hOFQ8Ag3l4=", - "dependencies": { - "inflection": "~1.3.0" - } - }, - "node_modules/path-proxy/node_modules/inflection": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.3.8.tgz", - "integrity": "sha1-y9Fg2p91sUw8xjV41POWeEvzAU4=", - "engines": [ - "node >= 0.4.0" - ] - }, - "node_modules/path-to-regexp": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", - "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=", - "dependencies": { - "isarray": "0.0.1" - } - }, - "node_modules/path-to-regexp/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, - "node_modules/performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" - }, - "node_modules/pg": { - "version": "7.4.3", - "resolved": "https://registry.npmjs.org/pg/-/pg-7.4.3.tgz", - "integrity": "sha1-97b5P1NA7MJZavu5ShPj1rYJg0s=", - "dependencies": { - "buffer-writer": "1.0.1", - "packet-reader": "0.3.1", - "pg-connection-string": "0.1.3", - "pg-pool": "~2.0.3", - "pg-types": "~1.12.1", - "pgpass": "1.x", - "semver": "4.3.2" - }, - "engines": { - "node": ">= 4.5.0" - } - }, - "node_modules/pg-connection-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.0.0.tgz", - "integrity": "sha1-Pu/lmX4G2Ugh5NUC5CtqHHP434I=" - }, - "node_modules/pg-int8": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", - "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/pg-native": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pg-native/-/pg-native-3.0.0.tgz", - "integrity": "sha512-qZZyywXJ8O4lbiIN7mn6vXIow1fd3QZFqzRe+uET/SZIXvCa3HBooXQA4ZU8EQX8Ae6SmaYtDGLp5DwU+8vrfg==", - "dependencies": { - "libpq": "^1.7.0", - "pg-types": "^1.12.1", - "readable-stream": "1.0.31" - } - }, - "node_modules/pg-native/node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "node_modules/pg-native/node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "node_modules/pg-native/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, - "node_modules/pg-native/node_modules/readable-stream": { - "version": "1.0.31", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.31.tgz", - "integrity": "sha1-jyUC4LyeOw2huUUgqrtOJgPsr64=", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "node_modules/pg-native/node_modules/string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - }, - "node_modules/pg-types": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-1.13.0.tgz", - "integrity": "sha512-lfKli0Gkl/+za/+b6lzENajczwZHc7D5kiUCZfgm914jipD2kIOIvEkAhZ8GrW3/TUoP9w8FHjwpPObBye5KQQ==", - "dependencies": { - "pg-int8": "1.0.1", - "postgres-array": "~1.0.0", - "postgres-bytea": "~1.0.0", - "postgres-date": "~1.0.0", - "postgres-interval": "^1.1.0" - } - }, - "node_modules/pg/node_modules/packet-reader": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-0.3.1.tgz", - "integrity": "sha1-zWLmCvjX/qinBexP+ZCHHEaHHyc=" - }, - "node_modules/pg/node_modules/pg-connection-string": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-0.1.3.tgz", - "integrity": "sha1-2hhHsglA5C7hSSvq9l1J2RskXfc=" - }, - "node_modules/pg/node_modules/pg-pool": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-2.0.3.tgz", - "integrity": "sha1-wCIDLIlJ8xKk+R+2QJzgQHa+Mlc=" - }, - "node_modules/pg/node_modules/pg-types": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-1.12.1.tgz", - "integrity": "sha1-1kCH45A7WP+q0nnnWVxSIIoUw9I=", - "dependencies": { - "postgres-array": "~1.0.0", - "postgres-bytea": "~1.0.0", - "postgres-date": "~1.0.0", - "postgres-interval": "^1.1.0" - } - }, - "node_modules/pg/node_modules/semver": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.2.tgz", - "integrity": "sha1-x6BxWKgL7dBSNVt3DYLWZA+AO+c=", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/pgpass": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.2.tgz", - "integrity": "sha1-Knu0G2BltnkH6R2hsHwYR8h3swY=", - "dependencies": { - "split": "^1.0.0" - } - }, - "node_modules/pinkie": { - "version": "2.0.4", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pinkie-promise": { - "version": "2.0.1", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "dependencies": { - "pinkie": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pkginfo": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.4.1.tgz", - "integrity": "sha1-tUGO8EOd5UJfxJlQQtztFPsqhP8=", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/postgres-array": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-1.0.2.tgz", - "integrity": "sha1-jgsy6wO/d6XAp4UeBEHBaaJWojg=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postgres-bytea": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", - "integrity": "sha1-AntTPAqokOJtFy1Hz5zOzFIazTU=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postgres-date": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", - "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postgres-interval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.1.1.tgz", - "integrity": "sha1-rNsPiXtLHG5JbZ1OCoU+HEKPBvA=", - "dependencies": { - "xtend": "^4.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz", - "integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==", - "dev": true, - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/process-nextick-args": { - "version": "1.0.7", - "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" - }, - "node_modules/promisify-call": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/promisify-call/-/promisify-call-2.0.4.tgz", - "integrity": "sha1-1IwtRWUszM1SgB3ey9UzptS9X7o=", - "dependencies": { - "with-callback": "^1.0.2" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/propprop": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/propprop/-/propprop-0.3.1.tgz", - "integrity": "sha1-oEmjVouJZEAGfRXY7J8zc15XAXg=" - }, - "node_modules/proxy-agent": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-3.1.1.tgz", - "integrity": "sha512-WudaR0eTsDx33O3EJE16PjBRZWcX8GqCEeERw1W3hZJgH/F2a46g7jty6UGty6NeJ4CKQy8ds2CJPMiyeqaTvw==", - "dependencies": { - "agent-base": "^4.2.0", - "debug": "4", - "http-proxy-agent": "^2.1.0", - "https-proxy-agent": "^3.0.0", - "lru-cache": "^5.1.1", - "pac-proxy-agent": "^3.0.1", - "proxy-from-env": "^1.0.0", - "socks-proxy-agent": "^4.0.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/proxy-agent/node_modules/agent-base": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", - "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", - "dependencies": { - "es6-promisify": "^5.0.0" - }, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/proxy-agent/node_modules/debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/proxy-agent/node_modules/https-proxy-agent": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-3.0.1.tgz", - "integrity": "sha512-+ML2Rbh6DAuee7d07tYGEKOEi2voWPUGan+ExdPbPW6Z3svq+JCqr0v8WmKPOkz1vOVykPCBSuobe7G8GJUtVg==", - "dependencies": { - "agent-base": "^4.3.0", - "debug": "^3.1.0" - }, - "engines": { - "node": ">= 4.5.0" - } - }, - "node_modules/proxy-agent/node_modules/https-proxy-agent/node_modules/debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/proxy-agent/node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/proxy-agent/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" - }, - "node_modules/punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" - }, - "node_modules/pushover-notifications": { - "version": "0.1.9", - "resolved": "https://registry.npmjs.org/pushover-notifications/-/pushover-notifications-0.1.9.tgz", - "integrity": "sha1-EMGxuNhIrcZGkdFmTtbOSQh/IMY=", - "engines": { - "node": "*" - } - }, - "node_modules/q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", - "engines": { - "node": ">=0.6.0", - "teleport": ">=0.2.0" - } - }, - "node_modules/qs": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", - "integrity": "sha1-NJzfbu+J7EXBLX1es/wMhwNDptg=", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", - "engines": { - "node": ">=0.4.x" - } - }, - "node_modules/raw-body": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.1.tgz", - "integrity": "sha512-9WmIKF6mkvA0SLmA2Knm9+qj89e+j1zqgyn8aXGd7+nAduPoqgI9lO57SAZNn/Byzo5P7JhXTyg9PzaJbH73bA==", - "dependencies": { - "bytes": "3.1.0", - "http-errors": "1.7.3", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } - }, - "node_modules/readable-stream": { - "version": "2.3.3", - "integrity": "sha1-No8lEtefnUb9/HE0mueHi7weuVw=", - "dependencies": { - "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" - } - }, - "node_modules/replacestream": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/replacestream/-/replacestream-4.0.0.tgz", - "integrity": "sha1-rVdK8dr1Zqg9h62lqzleC9xD4qQ=", - "dependencies": { - "escape-string-regexp": "^1.0.3", - "object-assign": "^3.0.0", - "readable-stream": "^2.0.1" - } - }, - "node_modules/replacestream/node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "node_modules/replacestream/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/replacestream/node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "node_modules/replacestream/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "node_modules/replacestream/node_modules/object-assign": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", - "integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/replacestream/node_modules/process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" - }, - "node_modules/replacestream/node_modules/readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "dependencies": { - "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" - } - }, - "node_modules/replacestream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/replacestream/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/replacestream/node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "node_modules/request": { - "version": "2.85.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.85.0.tgz", - "integrity": "sha512-8H7Ehijd4js+s6wuVPLjwORxD4zeuyjYugprdOXlPSqaApmL/QOy+EB/beICHVCHkGMKNh5rvihb5ov+IDw4mg==", - "dependencies": { - "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" - }, - "engines": { - "node": ">= 4" - } - }, - "node_modules/request-promise": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-3.0.0.tgz", - "integrity": "sha1-vh7bJvQcSc0dVlbGdT1oQqEkn0Y=", - "dependencies": { - "bluebird": "^3.3", - "lodash": "^4.6.1", - "request": "^2.34" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/request-promise/node_modules/lodash": { - "version": "4.17.10", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", - "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==" - }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" - }, - "node_modules/response-time": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/response-time/-/response-time-2.3.1.tgz", - "integrity": "sha1-K94ZGB3myBq5XjIHoo1h2WWzF5c=", - "dependencies": { - "depd": "~1.0.1", - "on-headers": "~1.0.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/response-time/node_modules/depd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.0.1.tgz", - "integrity": "sha1-gK7GTJ1tl+ZcwqnKqTwKpqv3Oqo=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/response-time/node_modules/on-headers": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz", - "integrity": "sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c=", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/retry": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.9.0.tgz", - "integrity": "sha1-b2l+UKDk3cjI9/tUeptg3q1DZ40=", - "engines": { - "node": "*" - } - }, - "node_modules/retry-request": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-3.3.1.tgz", - "integrity": "sha512-PjAmtWIxjNj4Co/6FRtBl8afRP3CxrrIAnUzb1dzydfROd+6xt7xAebFeskgQgkfFf8NmzrXIoaB3HxmswXyxw==", - "dependencies": { - "request": "^2.81.0", - "through2": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/safe-buffer": { - "version": "5.1.1", - "integrity": "sha1-iTMSr2myEj3vcfV4iQAWce6yyFM=" - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "node_modules/samsam": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.3.0.tgz", - "integrity": "sha512-1HwIYD/8UlOtFS3QO3w7ey+SdSDFE4HRNLZoZRYVQefrOY3l17epswImeB1ijgJFQJodIaHcwkp3r/myBjFVbg==" - }, - "node_modules/sax": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", - "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=" - }, - "node_modules/semver": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz", - "integrity": "sha1-d0Zt5YnNXTyV8TiqeLxWmjy10no=", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" - }, - "node_modules/setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" - }, - "node_modules/signal-exit": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" - }, - "node_modules/simple-oauth2": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/simple-oauth2/-/simple-oauth2-0.2.1.tgz", - "integrity": "sha1-+HmanxTrB77Szzpqz7PDcRFJOc4=", - "dependencies": { - "date-utils": "~1.2.12", - "querystring": "~0.1.0", - "request": "~2.12.0" - } - }, - "node_modules/simple-oauth2/node_modules/date-utils": { - "version": "1.2.21", - "resolved": "https://registry.npmjs.org/date-utils/-/date-utils-1.2.21.tgz", - "integrity": "sha1-YfsWzcEnSzyayq/+n8ad+HIKK2Q=", - "engines": { - "node": ">0.4.0" - } - }, - "node_modules/simple-oauth2/node_modules/querystring": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.1.0.tgz", - "integrity": "sha1-y3aibNoKEKlBY/zbPhMoJ/BLexA=", - "engines": { - "node": ">=0.4.x" - } - }, - "node_modules/simple-oauth2/node_modules/request": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.12.0.tgz", - "integrity": "sha1-EfRvILPQ9ISMY4OZHIB5CvFsjkg=", - "bundleDependencies": [ - "form-data", - "mime" - ], - "engines": [ - "node >= 0.3.6" - ], - "dependencies": { - "form-data": "~0.0.3", - "mime": "~1.2.7" - } - }, - "node_modules/simple-oauth2/node_modules/request/node_modules/form-data": { - "version": "0.0.3", - "inBundle": true, - "dependencies": { - "async": "~0.1.9", - "combined-stream": "0.0.3", - "mime": "~1.2.2" - }, - "engines": { - "node": "*" - } - }, - "node_modules/simple-oauth2/node_modules/request/node_modules/form-data/node_modules/async": { - "version": "0.1.9", - "inBundle": true, - "engines": { - "node": "*" - } - }, - "node_modules/simple-oauth2/node_modules/request/node_modules/form-data/node_modules/combined-stream": { - "version": "0.0.3", - "inBundle": true, - "dependencies": { - "delayed-stream": "0.0.5" - }, - "engines": { - "node": "*" - } - }, - "node_modules/simple-oauth2/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream": { - "version": "0.0.5", - "inBundle": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/simple-oauth2/node_modules/request/node_modules/mime": { - "version": "1.2.7", - "inBundle": true, - "engines": { - "node": "*" - } - }, - "node_modules/sinon": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-4.5.0.tgz", - "integrity": "sha512-trdx+mB0VBBgoYucy6a9L7/jfQOmvGeaKZT4OOJ+lPAtI8623xyGr8wLiE4eojzBS8G9yXbhx42GHUOVLr4X2w==", - "hasInstallScript": true, - "dependencies": { - "@sinonjs/formatio": "^2.0.0", - "diff": "^3.1.0", - "lodash.get": "^4.4.2", - "lolex": "^2.2.0", - "nise": "^1.2.0", - "supports-color": "^5.1.0", - "type-detect": "^4.0.5" - } - }, - "node_modules/sinon/node_modules/supports-color": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/smart-buffer": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.1.0.tgz", - "integrity": "sha512-iVICrxOzCynf/SNaBQCw34eM9jROU/s5rzIhpOvzhzuYHfJR/DhZfDkXiZSgKXfgv26HT3Yni3AV/DGw0cGnnw==", - "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/sntp": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", - "integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==", - "dependencies": { - "hoek": "4.x.x" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/socks": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.3.3.tgz", - "integrity": "sha512-o5t52PCNtVdiOvzMry7wU4aOqYWL0PeCXRWBEiJow4/i/wr+wpsJQ9awEu1EonLIqsfGd5qSgDdxEOvCdmBEpA==", - "dependencies": { - "ip": "1.1.5", - "smart-buffer": "^4.1.0" - }, - "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks-proxy-agent": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-4.0.2.tgz", - "integrity": "sha512-NT6syHhI9LmuEMSK6Kd2V7gNv5KFZoLE7V5udWmn0de+3Mkj3UMA/AJPLyeNUVmElCurSHtUdM3ETpR3z770Wg==", - "dependencies": { - "agent-base": "~4.2.1", - "socks": "~2.3.2" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/socks-proxy-agent/node_modules/agent-base": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz", - "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==", - "dependencies": { - "es6-promisify": "^5.0.0" - }, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/split": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", - "integrity": "sha1-YFvZvjA6pZ+zX5Ip++oN3snqB9k=", - "dependencies": { - "through": "2" - }, - "engines": { - "node": "*" - } - }, - "node_modules/split-array-stream": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/split-array-stream/-/split-array-stream-1.0.3.tgz", - "integrity": "sha1-0rdajl4Ngk1S/eyLgiWDncLjXfo=", - "dependencies": { - "async": "^2.4.0", - "is-stream-ended": "^0.1.0" - } - }, - "node_modules/split-array-stream/node_modules/async": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.0.tgz", - "integrity": "sha512-xAfGg1/NTLBBKlHFmnd7PlmUW9KhVQIUuSrYem9xzFUZy13ScvtyGGejaae9iAVRiRq9+Cx7DPFaAAhCpyxyPw==", - "dependencies": { - "lodash": "^4.14.0" - } - }, - "node_modules/sql": { - "version": "0.34.0", - "resolved": "https://registry.npmjs.org/sql/-/sql-0.34.0.tgz", - "integrity": "sha1-FsgT6Dv+wvsgfdohAJb2ERwY17o=", - "dependencies": { - "lodash": "1.3.x", - "sliced": "0.0.x" - }, - "engines": { - "node": "*" - } - }, - "node_modules/sql/node_modules/lodash": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-1.3.1.tgz", - "integrity": "sha1-pGY7U2hriV/wdOK6UE37dqjit3A=", - "engines": [ - "node", - "rhino" - ] - }, - "node_modules/sql/node_modules/sliced": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/sliced/-/sliced-0.0.5.tgz", - "integrity": "sha1-XtwETKTrb3gW1Qui/GPiXY/kcH8=" - }, - "node_modules/sshpk": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.1.tgz", - "integrity": "sha1-Ew9Zde3a2WPx1W+SuaxsUfqfg+s=", - "dependencies": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "dashdash": "^1.12.0", - "getpass": "^0.1.1" - }, - "engines": { - "node": ">=0.10.0" - }, - "optionalDependencies": { - "bcrypt-pbkdf": "^1.0.0", - "ecc-jsbn": "~0.1.1", - "jsbn": "~0.1.0", - "tweetnacl": "~0.14.0" - } - }, - "node_modules/stack-trace": { - "version": "0.0.10", - "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", - "engines": { - "node": "*" - } - }, - "node_modules/statuses": { - "version": "1.4.0", - "integrity": "sha1-u3PURtonlhBu/MG2AaJT1sRr0Ic=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/stream-events": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/stream-events/-/stream-events-1.0.4.tgz", - "integrity": "sha512-D243NJaYs/xBN2QnoiMDY7IesJFIK7gEhnvAYqJa5JvDdnh2dC4qDBwlCf0ohPpX2QRlA/4gnbnPd3rs3KxVcA==", - "dependencies": { - "stubs": "^3.0.0" - } - }, - "node_modules/stream-shift": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", - "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=" - }, - "node_modules/string_decoder": { - "version": "1.0.3", - "integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/string-format-obj": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string-format-obj/-/string-format-obj-1.1.1.tgz", - "integrity": "sha512-Mm+sROy+pHJmx0P/0Bs1uxIX6UhGJGj6xDGQZ5zh9v/SZRmLGevp+p0VJxV7lirrkAmQ2mvva/gHKpnF/pTb+Q==" - }, - "node_modules/string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dependencies": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/stringstream": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", - "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=" - }, - "node_modules/strip-ansi": { - "version": "3.0.1", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/stripe": { - "version": "2.5.5", - "resolved": "https://registry.npmjs.org/stripe/-/stripe-2.5.5.tgz", - "integrity": "sha1-Stv0FuRRFqupmYrCCGxeZYVXQTA=", - "dependencies": { - "when": "~2.4.0" - }, - "engines": { - "node": ">= v0.8.0" - } - }, - "node_modules/stripe/node_modules/when": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/when/-/when-2.4.0.tgz", - "integrity": "sha1-S3YhcKTe5nE1vWKsPSLMT8ZM+DE=" - }, - "node_modules/stubs": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/stubs/-/stubs-3.0.0.tgz", - "integrity": "sha1-6NK6H6nJBXAwPAMLaQD31fiavls=" - }, - "node_modules/supports-color": { - "version": "2.0.0", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/tar": { - "version": "4.4.13", - "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz", - "integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==", - "dependencies": { - "chownr": "^1.1.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.8.6", - "minizlib": "^1.2.1", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.2", - "yallist": "^3.0.3" - }, - "engines": { - "node": ">=4.5" - } - }, - "node_modules/tar/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - }, - "node_modules/text-encoding": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/text-encoding/-/text-encoding-0.6.4.tgz", - "integrity": "sha1-45mpgiV6J22uQou5KEXLcb3CbRk=" - }, - "node_modules/through": { - "version": "2.3.8", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" - }, - "node_modules/through2": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", - "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", - "dependencies": { - "readable-stream": "^2.1.5", - "xtend": "~4.0.1" - } - }, - "node_modules/thunkify": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/thunkify/-/thunkify-2.1.2.tgz", - "integrity": "sha1-+qDp0jDFGsyVyhOjYawFyn4EVT0=" - }, - "node_modules/toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/tough-cookie": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", - "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", - "dependencies": { - "punycode": "^1.4.1" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/tsscmp": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz", - "integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==", - "engines": { - "node": ">=0.6.x" - } - }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "optional": true - }, - "node_modules/type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dependencies": { - "prelude-ls": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "engines": { - "node": ">=4" - } - }, - "node_modules/typedarray": { - "version": "0.0.6", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" - }, - "node_modules/ultron": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz", - "integrity": "sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po=" - }, - "node_modules/underscore": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.12.1.tgz", - "integrity": "sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==" - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/url": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", - "integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=", - "dependencies": { - "punycode": "1.3.2", - "querystring": "0.2.0" - } - }, - "node_modules/url-join": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/url-join/-/url-join-0.0.1.tgz", - "integrity": "sha1-HbSK1CLTQCRpqH99l73r/k+x48g=" - }, - "node_modules/url/node_modules/punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "node_modules/uuid": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz", - "integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==", - "bin": { - "uuid": "bin/uuid" - } - }, - "node_modules/valid-url": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/valid-url/-/valid-url-1.0.9.tgz", - "integrity": "sha1-HBRHm0DxOXp1eC8RXkCGRHQzogA=" - }, - "node_modules/verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "engines": [ - "node >=0.6.0" - ], - "dependencies": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "node_modules/wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", - "dependencies": { - "string-width": "^1.0.2 || 2" - } - }, - "node_modules/winston": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/winston/-/winston-1.0.2.tgz", - "integrity": "sha1-NRxY4jI/ikyimkUZWqmqO0w1128=", - "dependencies": { - "async": "~1.0.0", - "colors": "1.0.x", - "cycle": "1.0.x", - "eyes": "0.1.x", - "isstream": "0.1.x", - "pkginfo": "0.3.x", - "stack-trace": "0.0.x" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/winston/node_modules/async": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async/-/async-1.0.0.tgz", - "integrity": "sha1-+PwEyjoTeErenhZBr5hXjPvWR6k=" - }, - "node_modules/winston/node_modules/colors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", - "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/winston/node_modules/cycle": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", - "integrity": "sha1-IegLK+hYD5i0aPN5QwZisEbDStI=", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/winston/node_modules/eyes": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", - "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=", - "engines": { - "node": "> 0.1.90" - } - }, - "node_modules/winston/node_modules/isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" - }, - "node_modules/winston/node_modules/pkginfo": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.3.1.tgz", - "integrity": "sha1-Wyn2qB9wcXFC4J52W76rl7T4HiE=", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/winston/node_modules/stack-trace": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", - "engines": { - "node": "*" - } - }, - "node_modules/with-callback": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/with-callback/-/with-callback-1.0.2.tgz", - "integrity": "sha1-oJYpuakgAo1yFAT7Q1vc/1yRvCE=", - "engines": { - "node": ">=4" - } - }, - "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "node_modules/ws": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.5.tgz", - "integrity": "sha512-o3KqipXNUdS7wpQzBHSe180lBGO60SoK0yVo3CYJgb2MkobuWuBX6dhkYP5ORCLd55y+SaflMOV5fqAB53ux4w==", - "dependencies": { - "options": ">=0.0.5", - "ultron": "1.0.x" - } - }, - "node_modules/xml2js": { - "version": "0.4.17", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.17.tgz", - "integrity": "sha1-F76T6q4/O3eTWceVtBlwWogX6Gg=", - "dependencies": { - "sax": ">=0.6.0", - "xmlbuilder": "^4.1.0" - } - }, - "node_modules/xmlbuilder": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-4.2.1.tgz", - "integrity": "sha1-qlijBBoGb5DqoWwvU4n/GfP0YaU=", - "dependencies": { - "lodash": "^4.0.0" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/xregexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-2.0.0.tgz", - "integrity": "sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM=" - }, - "node_modules/xtend": { - "version": "4.0.1", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", - "engines": { - "node": ">=0.4" - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" - } - }, "dependencies": { "@google-cloud/common": { "version": "0.13.6", @@ -5944,13 +42,11 @@ "propprop": "^0.3.0" } }, - "@sinonjs/formatio": { - "version": "2.0.0", - "resolved": "http://registry.npmjs.org/@sinonjs/formatio/-/formatio-2.0.0.tgz", - "integrity": "sha512-ls6CAMA6/5gG+O/IdsBcblvnd8qcO/l1TYoNeAzp3wcISOxlPXQEus0mLcdwazEkWjaBdaJ3TaxmNgCLWwvWzg==", - "requires": { - "samsam": "1.3.0" - } + "@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "dev": true }, "@slack/client": { "version": "3.16.0", @@ -6126,6 +222,286 @@ } } }, + "@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "dev": true, + "requires": { + "defer-to-connect": "^1.0.1" + } + }, + "@types/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@types/async/-/async-3.2.6.tgz", + "integrity": "sha512-ZkrXnZLC1mc4b9QLKaSrsxV4oxTRs10OI2kgSApT8G0v1jrmqppSHUVQ15kLorzsFBTjvf7OKF4kAibuuNQ+xA==", + "dev": true + }, + "@types/bcrypt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-3.0.1.tgz", + "integrity": "sha512-SwBrq5wb6jXP0o3O3jStdPWbKpimTImfdFD/OZE3uW+jhGpds/l5wMX9lfYOTDOa5Bod2QmOgo9ln+tMp2XP/w==", + "dev": true + }, + "@types/bluebird": { + "version": "3.5.33", + "resolved": "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.33.tgz", + "integrity": "sha512-ndEo1xvnYeHxm7I/5sF6tBvnsA4Tdi3zj1keRKRs12SP+2ye2A27NDJ1B6PqkfMbGAcT+mqQVqbZRIrhfOp5PQ==", + "dev": true + }, + "@types/body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==", + "dev": true, + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/caseless": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz", + "integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w==", + "dev": true + }, + "@types/connect": { + "version": "3.4.34", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.34.tgz", + "integrity": "sha512-ePPA/JuI+X0vb+gSWlPKOY0NdNAie/rPUqX2GUPpbZwiKTkSPhjXWuee47E4MtE54QVzGCQMQkAL6JhV2E1+cQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/connect-timeout": { + "version": "0.0.34", + "resolved": "https://registry.npmjs.org/@types/connect-timeout/-/connect-timeout-0.0.34.tgz", + "integrity": "sha512-ZadN0ttd64Wg5suotSRqJTn/QSw6gO1OqFY3GVgzY9WC5Efo2fxsSt5Scd5IOC6eXPbA7N4VlK17/oRpGSmOzA==", + "dev": true, + "requires": { + "@types/express": "*" + } + }, + "@types/express": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.11.tgz", + "integrity": "sha512-no+R6rW60JEc59977wIxreQVsIEOAYwgCqldrA/vkpCnbD7MqTefO97lmoBe4WE0F156bC4uLSP1XHDOySnChg==", + "dev": true, + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.18", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.19.tgz", + "integrity": "sha512-DJOSHzX7pCiSElWaGR8kCprwibCB/3yW6vcT8VG3P0SJjnv19gnWG/AZMfM60Xj/YJIp/YCaDHyvzsFVeniARA==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "@types/fb": { + "version": "0.0.28", + "resolved": "https://registry.npmjs.org/@types/fb/-/fb-0.0.28.tgz", + "integrity": "sha512-MHI7JYMZh7VkTxNh200OrcxjkWJseuXuI3okN25d/crFcnXcScN37cHrih7tIrv66dIscnzZMXvj2j8P2vWBJw==", + "dev": true, + "requires": { + "fb": "*" + } + }, + "@types/http-proxy": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.5.tgz", + "integrity": "sha512-GNkDE7bTv6Sf8JbV2GksknKOsk7OznNYHSdrtvPJXO0qJ9odZig6IZKUi5RFGi6d1bf6dgIAe4uXi3DBc7069Q==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/intercom-client": { + "version": "2.11.10", + "resolved": "https://registry.npmjs.org/@types/intercom-client/-/intercom-client-2.11.10.tgz", + "integrity": "sha512-FvETNb7T9FLFRATBrJ3ssGSnATtOmY2NtIeDOqaq/vaU+jmnpd+kTydpAtwezWXz0cSHc85vpcVAOPHghsJRcw==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/request": "*" + } + }, + "@types/lru-cache": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@types/lru-cache/-/lru-cache-5.1.0.tgz", + "integrity": "sha512-RaE0B+14ToE4l6UqdarKPnXwVDuigfFv+5j9Dze/Nqr23yyuqdNvzcZi3xB+3Agvi5R4EOgAksfv3lXX4vBt9w==", + "dev": true + }, + "@types/mime": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", + "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", + "dev": true + }, + "@types/node": { + "version": "14.14.39", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.39.tgz", + "integrity": "sha512-Qipn7rfTxGEDqZiezH+wxqWYR8vcXq5LRpZrETD19Gs4o8LbklbmqotSUsMU+s5G3PJwMRDfNEYoxrcBwIxOuw==", + "dev": true + }, + "@types/nodemailer": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.4.1.tgz", + "integrity": "sha512-8081UY/0XTTDpuGqCnDc8IY+Q3DSg604wB3dBH0CaZlj4nZWHWuxtZ3NRZ9c9WUrz1Vfm6wioAUnqL3bsh49uQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/nodemailer-mailgun-transport": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@types/nodemailer-mailgun-transport/-/nodemailer-mailgun-transport-1.4.2.tgz", + "integrity": "sha512-KuLTQcbebCI1A5BbAhbPmmXXk1g9JuaVfdQzCXuZ/igKc1CQpJS7wIZ3CndhIde3zZTvRF55NgDGHpYW8w4NMw==", + "dev": true, + "requires": { + "@types/nodemailer": "*" + } + }, + "@types/oauth": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@types/oauth/-/oauth-0.9.1.tgz", + "integrity": "sha512-a1iY62/a3yhZ7qH7cNUsxoI3U/0Fe9+RnuFrpTKr+0WVOzbKlSLojShCKe20aOD1Sppv+i8Zlq0pLDuTJnwS4A==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/pg": { + "version": "7.14.11", + "resolved": "https://registry.npmjs.org/@types/pg/-/pg-7.14.11.tgz", + "integrity": "sha512-EnZkZ1OMw9DvNfQkn2MTJrwKmhJYDEs5ujWrPfvseWNoI95N8B4HzU/Ltrq5ZfYxDX/Zg8mTzwr6UAyTjjFvXA==", + "dev": true, + "requires": { + "@types/node": "*", + "pg-protocol": "^1.2.0", + "pg-types": "^2.2.0" + }, + "dependencies": { + "pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "dev": true, + "requires": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + } + }, + "postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "dev": true + } + } + }, + "@types/qs": { + "version": "6.9.6", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.6.tgz", + "integrity": "sha512-0/HnwIfW4ki2D8L8c9GVcG5I72s9jP5GSLVF0VIXDW00kmIpA6O33G7a8n59Tmh7Nz0WUC3rSb7PTY/sdW2JzA==", + "dev": true + }, + "@types/range-parser": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz", + "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==", + "dev": true + }, + "@types/replacestream": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/replacestream/-/replacestream-4.0.0.tgz", + "integrity": "sha512-Ek7AzrEXgy8BO/HySVAcP7GHTflsuiduR4P1AyJlE5MQhD2uX+vWvfwXSEBuDFD1VgGAaJFCNEI8fw7qpVgu5Q==", + "dev": true + }, + "@types/request": { + "version": "2.48.5", + "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.5.tgz", + "integrity": "sha512-/LO7xRVnL3DxJ1WkPGDQrp4VTV1reX9RkC85mJ+Qzykj2Bdw+mG15aAfDahc76HtknjzE16SX/Yddn6MxVbmGQ==", + "dev": true, + "requires": { + "@types/caseless": "*", + "@types/node": "*", + "@types/tough-cookie": "*", + "form-data": "^2.5.0" + }, + "dependencies": { + "form-data": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", + "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + } + } + }, + "@types/request-promise": { + "version": "4.1.47", + "resolved": "https://registry.npmjs.org/@types/request-promise/-/request-promise-4.1.47.tgz", + "integrity": "sha512-eRSZhAS8SMsrWOM8vbhxFGVZhTbWSJvaRKyufJTdIf4gscUouQvOBlfotPSPHbMR3S7kfkyKbhb1SWPmQdy3KQ==", + "dev": true, + "requires": { + "@types/bluebird": "*", + "@types/request": "*" + } + }, + "@types/response-time": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/@types/response-time/-/response-time-2.3.4.tgz", + "integrity": "sha512-+MuxeMIzmXDy/CTw/mPlZO1SWBKbpz9QFo4+KYNXc2iiY0OGH3Ny9DPKT4eSamyDbhWJPfvMMPB4Kh7DapwJhA==", + "dev": true, + "requires": { + "@types/express": "*", + "@types/node": "*" + } + }, + "@types/serve-static": { + "version": "1.13.9", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.9.tgz", + "integrity": "sha512-ZFqF6qa48XsPdjXV5Gsz0Zqmux2PerNd3a/ktL45mHpa19cuMi/cL8tcxdAx497yRh+QtYPuofjT9oWw9P7nkA==", + "dev": true, + "requires": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "@types/tough-cookie": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.0.tgz", + "integrity": "sha512-I99sngh224D0M7XgW1s120zxCt3VYQ3IQsuw3P3jbq5GG4yc79+ZjyKznyOGIQrflfylLgcfekeZW/vk0yng6A==", + "dev": true + }, + "@types/underscore": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@types/underscore/-/underscore-1.11.1.tgz", + "integrity": "sha512-mW23Xkp9HYgdMV7gnwuzqnPx6aG0J7xg/b7erQszOcyOizWylwCr9cgYM/BVVJHezUDxwyigG6+wCFQwCvyMBw==", + "dev": true + }, + "@types/valid-url": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@types/valid-url/-/valid-url-1.0.3.tgz", + "integrity": "sha512-+33x29mg+ecU88ODdWpqaie2upIuRkhujVLA7TuJjM823cNMbeggfI6NhxewaRaRF8dy+g33e4uIg/m5Mb3xDQ==", + "dev": true + }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -6141,14 +517,14 @@ } }, "ajv": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", - "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "requires": { - "co": "^4.6.0", - "fast-deep-equal": "^1.0.0", + "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0" + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" } }, "akismet": { @@ -6156,14 +532,69 @@ "resolved": "https://registry.npmjs.org/akismet/-/akismet-0.0.11.tgz", "integrity": "sha1-ofFFVvzgAzXrr9W2z2ZTUC7o/oU=" }, + "ansi-align": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz", + "integrity": "sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw==", + "dev": true, + "requires": { + "string-width": "^3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, "ansi-regex": { "version": "2.1.1", + "resolved": false, "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" }, "ansi-styles": { "version": "2.2.1", + "resolved": false, "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" }, + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, "aproba": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", @@ -6180,10 +611,12 @@ }, "array-uniq": { "version": "1.0.3", + "resolved": false, "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=" }, "arrify": { "version": "1.0.1", + "resolved": false, "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=" }, "asn1": { @@ -6241,9 +674,9 @@ "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" }, "aws4": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.7.0.tgz", - "integrity": "sha512-32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w==" + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" }, "babel-eslint": { "version": "6.1.2", @@ -6387,11 +820,6 @@ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" }, - "lodash": { - "version": "4.17.10", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", - "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==" - }, "lodash.assign": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", @@ -6478,6 +906,12 @@ "tweetnacl": "^0.14.3" } }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, "bindings": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", @@ -6496,12 +930,94 @@ "resolved": "https://registry.npmjs.org/boolean/-/boolean-0.1.3.tgz", "integrity": "sha512-G6TadQPFofmOhzkzgtVSOYaosjpnPyVCDeZ4J7oPF74OmhM2++fXUdwu7NULTwgntK5KIMcls1UslwAY2btL6g==" }, - "boom": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", - "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", + "boxen": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz", + "integrity": "sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ==", + "dev": true, "requires": { - "hoek": "4.x.x" + "ansi-align": "^3.0.0", + "camelcase": "^5.3.1", + "chalk": "^3.0.0", + "cli-boxes": "^2.2.0", + "string-width": "^4.1.0", + "term-size": "^2.1.0", + "type-fest": "^0.8.1", + "widest-line": "^3.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "string-width": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "brace-expansion": { @@ -6513,6 +1029,15 @@ "concat-map": "0.0.1" } }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, "buffer": { "version": "4.9.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", @@ -6543,6 +1068,44 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" }, + "cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "dev": true, + "requires": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + }, + "dependencies": { + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true + } + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, "capture-stack-trace": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz", @@ -6555,6 +1118,7 @@ }, "chalk": { "version": "1.1.3", + "resolved": false, "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "requires": { "ansi-styles": "^2.2.1", @@ -6564,13 +1128,51 @@ "supports-color": "^2.0.0" } }, + "chokidar": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", + "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.3.1", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.5.0" + } + }, "chownr": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" }, + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "dev": true + }, + "clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, "co": { "version": "4.6.0", + "resolved": false, "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" }, "code-point-at": { @@ -6578,8 +1180,24 @@ "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, "colors": { "version": "1.0.3", + "resolved": false, "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=" }, "combined-stream": { @@ -6602,6 +1220,7 @@ }, "concat-stream": { "version": "1.6.0", + "resolved": false, "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", "requires": { "inherits": "^2.0.3", @@ -6609,6 +1228,20 @@ "typedarray": "^0.0.6" } }, + "configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "dev": true, + "requires": { + "dot-prop": "^5.2.0", + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "unique-string": "^2.0.0", + "write-file-atomic": "^3.0.0", + "xdg-basedir": "^4.0.0" + } + }, "connect-timeout": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/connect-timeout/-/connect-timeout-1.9.0.tgz", @@ -6653,6 +1286,7 @@ }, "core-util-is": { "version": "1.0.2", + "resolved": false, "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, "create-error-class": { @@ -6663,26 +1297,15 @@ "capture-stack-trace": "^1.0.0" } }, - "cryptiles": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", - "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", - "requires": { - "boom": "5.x.x" - }, - "dependencies": { - "boom": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", - "integrity": "sha1-XdnabuOl8wIHdDYpDLcX0/SlTgI=", - "requires": { - "hoek": "4.x.x" - } - } - } + "crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "dev": true }, "cycle": { "version": "1.0.3", + "resolved": false, "integrity": "sha1-IegLK+hYD5i0aPN5QwZisEbDStI=" }, "dashdash": { @@ -6700,11 +1323,21 @@ }, "debug": { "version": "2.6.9", + "resolved": false, "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", "requires": { "ms": "2.0.0" } }, + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, "deep-extend": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", @@ -6715,6 +1348,12 @@ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=" }, + "defer-to-connect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", + "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", + "dev": true + }, "degenerator": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-1.0.4.tgz", @@ -6745,10 +1384,20 @@ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=" }, - "diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==" + "dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "requires": { + "is-obj": "^2.0.0" + } + }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "dev": true }, "duplexify": { "version": "3.5.4", @@ -6781,8 +1430,15 @@ }, "ee-first": { "version": "1.1.1", + "resolved": false, "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, "end-of-stream": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", @@ -6809,8 +1465,15 @@ "es6-promise": "^4.0.3" } }, + "escape-goat": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", + "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", + "dev": true + }, "escape-string-regexp": { "version": "1.0.5", + "resolved": false, "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, "escodegen": { @@ -7403,11 +2066,6 @@ "type-check": "~0.3.2" } }, - "lodash": { - "version": "4.17.10", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", - "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==" - }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -7616,14 +2274,6 @@ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - }, "string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", @@ -7634,6 +2284,14 @@ "strip-ansi": "^3.0.0" } }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, "strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", @@ -8179,19 +2837,6 @@ "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz", "integrity": "sha1-EV+eO2s9rylZmDyzjxSaLUDrXVM=" }, - "mime-db": { - "version": "1.36.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.36.0.tgz", - "integrity": "sha512-L+xvyD9MkoYMXb1jAmzI/lWYAxAMCPvIBSWur0PZ5nOf5euahRLVqH//FKW9mWp2lkqUgYiXPgkzfMUFi4zVDw==" - }, - "mime-types": { - "version": "2.1.20", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.20.tgz", - "integrity": "sha512-HrkrPaP9vGuWbLK1B1FfgAkbqNjIuy4eHlIYnFi7kamZyLLrGlo2mpcx0bBmNpKqBtYtAfGbodDddIgddSJC2A==", - "requires": { - "mime-db": "~1.36.0" - } - }, "minimist": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", @@ -8500,9 +3145,9 @@ } }, "extend": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", - "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=" + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" }, "extsprintf": { "version": "1.3.0", @@ -8511,17 +3156,18 @@ }, "eyes": { "version": "0.1.8", + "resolved": false, "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=" }, "fast-deep-equal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", - "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" }, "fast-levenshtein": { "version": "2.0.6", @@ -8557,6 +3203,15 @@ "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, "follow-redirects": { "version": "1.13.0", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz", @@ -8590,6 +3245,13 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, "ftp": { "version": "0.3.10", "resolved": "https://registry.npmjs.org/ftp/-/ftp-0.3.10.tgz", @@ -8648,15 +3310,26 @@ }, "generate-function": { "version": "2.0.0", + "resolved": false, "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=" }, "generate-object-property": { "version": "1.2.0", + "resolved": false, "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", "requires": { "is-property": "^1.0.0" } }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, "get-uri": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-2.0.4.tgz", @@ -8668,13 +3341,6 @@ "file-uri-to-path": "1", "ftp": "~0.3.10", "readable-stream": "2" - }, - "dependencies": { - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - } } }, "getpass": { @@ -8698,6 +3364,32 @@ "path-is-absolute": "^1.0.0" } }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "global-dirs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-2.1.0.tgz", + "integrity": "sha512-MG6kdOUh/xBnyo9cJFeIKkLEc1AyFq42QTU4XiX51i2NEdxLxLWXIjEjmqKeSuKR7pAZjTqUVoT2b2huxVLgYQ==", + "dev": true, + "requires": { + "ini": "1.3.7" + }, + "dependencies": { + "ini": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.7.tgz", + "integrity": "sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ==", + "dev": true + } + } + }, "google-auth-library": { "version": "0.10.0", "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-0.10.0.tgz", @@ -8738,6 +3430,31 @@ "node-forge": "^0.7.1" } }, + "got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "dev": true, + "requires": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + } + }, + "graceful-fs": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", + "dev": true + }, "gtoken": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-1.2.3.tgz", @@ -8755,16 +3472,17 @@ "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" }, "har-validator": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", - "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", "requires": { - "ajv": "^5.1.0", + "ajv": "^6.12.3", "har-schema": "^2.0.0" } }, "has-ansi": { "version": "2.0.0", + "resolved": false, "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "requires": { "ansi-regex": "^2.0.0" @@ -8773,28 +3491,19 @@ "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true }, "has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" }, - "hawk": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", - "integrity": "sha1-r02RTrBl+bXOTZ0RwcshJu7MMDg=", - "requires": { - "boom": "4.x.x", - "cryptiles": "3.x.x", - "hoek": "4.x.x", - "sntp": "2.x.x" - } - }, - "hoek": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", - "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==" + "has-yarn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", + "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", + "dev": true }, "html-tags": { "version": "1.2.0", @@ -8806,6 +3515,12 @@ "resolved": "https://registry.npmjs.org/htmlencode/-/htmlencode-0.0.4.tgz", "integrity": "sha1-9+LWr74YqHp45jujMI51N2Z0Dj8=" }, + "http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "dev": true + }, "http-errors": { "version": "1.7.3", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", @@ -8912,6 +3627,12 @@ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz", "integrity": "sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q=" }, + "ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", + "dev": true + }, "ignore-walk": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz", @@ -8920,6 +3641,18 @@ "minimatch": "^3.0.4" } }, + "import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", + "dev": true + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, "inflection": { "version": "1.12.0", "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz", @@ -8936,6 +3669,7 @@ }, "inherits": { "version": "2.0.3", + "resolved": false, "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, "ini": { @@ -8944,14 +3678,21 @@ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" }, "intercom-client": { - "version": "2.9.4", - "resolved": "https://registry.npmjs.org/intercom-client/-/intercom-client-2.9.4.tgz", - "integrity": "sha1-cOAYAkrBAURt59A9Wd6t+I7AH9I=", + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/intercom-client/-/intercom-client-2.11.2.tgz", + "integrity": "sha512-liIAVaXMZeaLLibWGKYGVIKV4yY5ra5Q3AA1YOnL3hI+mWIpBSx8DIXSKVM5iWMPQhr2H7Ss9jWppnBv+ujaew==", "requires": { - "bluebird": "^3.3.4", + "bluebird": "^3.7.2", "htmlencode": "^0.0.4", - "request": "^2.83.0", - "sinon": "^4.1.3" + "lodash": "^4.17.19", + "request": "^2.88.0" + }, + "dependencies": { + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + } } }, "intercom.io": { @@ -8976,6 +3717,30 @@ "resolved": "https://registry.npmjs.org/is/-/is-3.2.1.tgz", "integrity": "sha1-0Kwq1V63sL7JJqUmb2xmKqqD3KU=" }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "requires": { + "ci-info": "^2.0.0" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, "is-fullwidth-code-point": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", @@ -8984,6 +3749,15 @@ "number-is-nan": "^1.0.0" } }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, "is-html": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-html/-/is-html-1.1.0.tgz", @@ -8992,6 +3766,16 @@ "html-tags": "^1.0.0" } }, + "is-installed-globally": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.3.2.tgz", + "integrity": "sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g==", + "dev": true, + "requires": { + "global-dirs": "^2.0.1", + "is-path-inside": "^3.0.1" + } + }, "is-my-ip-valid": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz", @@ -9009,8 +3793,33 @@ "xtend": "^4.0.0" } }, + "is-npm": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-4.0.0.tgz", + "integrity": "sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig==", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true + }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true + }, "is-property": { "version": "1.0.2", + "resolved": false, "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=" }, "is-stream": { @@ -9028,12 +3837,20 @@ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" }, + "is-yarn-global": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", + "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", + "dev": true + }, "isarray": { "version": "1.0.0", + "resolved": false, "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, "isstream": { "version": "0.1.2", + "resolved": false, "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" }, "jmespath": { @@ -9047,15 +3864,21 @@ "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", "optional": true }, + "json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", + "dev": true + }, "json-schema": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" }, "json-schema-traverse": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, "json-stringify-safe": { "version": "5.0.1", @@ -9064,6 +3887,7 @@ }, "jsonpointer": { "version": "4.0.1", + "resolved": false, "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=" }, "jsprim": { @@ -9077,11 +3901,6 @@ "verror": "1.10.0" } }, - "just-extend": { - "version": "1.1.27", - "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-1.1.27.tgz", - "integrity": "sha512-mJVp13Ix6gFo3SBAy9U/kL+oeZqzlYYYLQBwXVBlVzIsZwBqGREnOro24oC/8s8aox+rJhtZ2DiQof++IrkA+g==" - }, "jwa": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.1.5.tgz", @@ -9103,6 +3922,24 @@ "safe-buffer": "^5.0.1" } }, + "keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "dev": true, + "requires": { + "json-buffer": "3.0.0" + } + }, + "latest-version": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", + "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", + "dev": true, + "requires": { + "package-json": "^6.3.0" + } + }, "levn": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", @@ -9129,13 +3966,9 @@ } }, "lodash": { - "version": "4.17.4", - "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=" - }, - "lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "lodash.noop": { "version": "3.0.1", @@ -9147,10 +3980,11 @@ "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.7.tgz", "integrity": "sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg==" }, - "lolex": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-2.3.2.tgz", - "integrity": "sha512-A5pN2tkFj7H0dGIAM6MFvHKMJcPnjZsOMvR7ujCjfgW5TbV6H9vb1PgxLtHvjqNZTHsUolz+6/WEO0N1xNx2ng==" + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true }, "lru-cache": { "version": "3.0.0", @@ -9209,11 +4043,6 @@ "mime-types": "^2.1.12" } }, - "lodash": { - "version": "4.17.19", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", - "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==" - }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -9221,6 +4050,23 @@ } } }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, "methmeth": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/methmeth/-/methmeth-1.1.0.tgz", @@ -9232,14 +4078,16 @@ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" }, "mime-db": { - "version": "1.30.0", - "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=" + "version": "1.47.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.47.0.tgz", + "integrity": "sha512-QBmA/G2y+IfeS4oktet3qRZ+P5kPhCKRXxXnQEudYqUaEioAU1/Lq2us3D/t1Jfo4hE9REQPrbB7K5sOczJVIw==" }, "mime-types": { - "version": "2.1.17", - "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", + "version": "2.1.30", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.30.tgz", + "integrity": "sha512-crmjA4bLtR8m9qLpHvgxSChT+XoSlZi8J4n/aIdn3z92e/U47Z0V/yl+Wh9W046GgFVAmoNR/fmdbZYcSSIUeg==", "requires": { - "mime-db": "~1.30.0" + "mime-db": "1.47.0" } }, "mimelib": { @@ -9274,6 +4122,12 @@ } } }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true + }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -9326,6 +4180,7 @@ }, "ms": { "version": "2.0.0", + "resolved": false, "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, "needle": { @@ -9368,18 +4223,6 @@ "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" }, - "nise": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/nise/-/nise-1.3.3.tgz", - "integrity": "sha512-v1J/FLUB9PfGqZLGDBhQqODkbLotP0WtLo9R4EJY2PPu5f5Xg4o0rA8FDlmrjFSv9vBBKcfnOSpfYYuu5RTHqg==", - "requires": { - "@sinonjs/formatio": "^2.0.0", - "just-extend": "^1.1.27", - "lolex": "^2.3.2", - "path-to-regexp": "^1.7.0", - "text-encoding": "^0.6.4" - } - }, "node-addon-api": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.0.0.tgz", @@ -9410,24 +4253,74 @@ "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, + "nodemailer": { + "version": "6.4.16", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.4.16.tgz", + "integrity": "sha512-68K0LgZ6hmZ7PVmwL78gzNdjpj5viqBdFqKrTtr9bZbJYj6BRj5W6WGkxXrEnUl3Co3CBXi3CZBUlpV/foGnOQ==" + }, + "nodemailer-mailgun-transport": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/nodemailer-mailgun-transport/-/nodemailer-mailgun-transport-2.0.0.tgz", + "integrity": "sha512-TPGi2anyS0w/4jv7TJNS3wX5DbNQ2+j+ssnwY4IYxL4QaYXAXewcw6YUtBgnOsEvQVJvmxQLDuW4f4JaMPgfaA==", + "requires": { + "consolidate": "^0.15.1", + "mailgun-js": "^0.22.0" + } + }, + "nodemon": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.7.tgz", + "integrity": "sha512-XHzK69Awgnec9UzHr1kc8EomQh4sjTQ8oRf8TsGrSmHDx9/UmiGG9E/mM3BuTfNeFwdNBvrqQq/RHL0xIeyFOA==", + "dev": true, + "requires": { + "chokidar": "^3.2.2", + "debug": "^3.2.6", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.0.4", + "pstree.remy": "^1.1.7", + "semver": "^5.7.1", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.3", + "update-notifier": "^4.1.0" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } } } }, - "nodemailer": { - "version": "6.4.16", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.4.16.tgz", - "integrity": "sha512-68K0LgZ6hmZ7PVmwL78gzNdjpj5viqBdFqKrTtr9bZbJYj6BRj5W6WGkxXrEnUl3Co3CBXi3CZBUlpV/foGnOQ==" - }, - "nodemailer-mailgun-transport": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/nodemailer-mailgun-transport/-/nodemailer-mailgun-transport-2.0.0.tgz", - "integrity": "sha512-TPGi2anyS0w/4jv7TJNS3wX5DbNQ2+j+ssnwY4IYxL4QaYXAXewcw6YUtBgnOsEvQVJvmxQLDuW4f4JaMPgfaA==", - "requires": { - "consolidate": "^0.15.1", - "mailgun-js": "^0.22.0" - } - }, "nopt": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", @@ -9437,6 +4330,18 @@ "osenv": "^0.1.4" } }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "normalize-url": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", + "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", + "dev": true + }, "npm-bundled": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz", @@ -9493,6 +4398,7 @@ }, "on-finished": { "version": "2.3.0", + "resolved": false, "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", "requires": { "ee-first": "1.1.1" @@ -9500,10 +4406,12 @@ }, "on-headers": { "version": "1.0.1", + "resolved": false, "integrity": "sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c=" }, "once": { "version": "1.4.0", + "resolved": false, "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "requires": { "wrappy": "1" @@ -9561,6 +4469,12 @@ "os-tmpdir": "^1.0.0" } }, + "p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", + "dev": true + }, "p3p": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/p3p/-/p3p-0.0.2.tgz", @@ -9635,6 +4549,26 @@ "thunkify": "^2.1.2" } }, + "package-json": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", + "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "dev": true, + "requires": { + "got": "^9.6.0", + "registry-auth-token": "^4.0.0", + "registry-url": "^5.0.0", + "semver": "^6.2.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -9655,21 +4589,6 @@ } } }, - "path-to-regexp": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", - "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=", - "requires": { - "isarray": "0.0.1" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - } - } - }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", @@ -9723,9 +4642,9 @@ } }, "pg-connection-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.0.0.tgz", - "integrity": "sha1-Pu/lmX4G2Ugh5NUC5CtqHHP434I=" + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz", + "integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==" }, "pg-int8": { "version": "1.0.1", @@ -9775,6 +4694,12 @@ } } }, + "pg-protocol": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.5.0.tgz", + "integrity": "sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ==", + "dev": true + }, "pg-types": { "version": "1.13.0", "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-1.13.0.tgz", @@ -9795,12 +4720,20 @@ "split": "^1.0.0" } }, + "picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "dev": true + }, "pinkie": { "version": "2.0.4", + "resolved": false, "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" }, "pinkie-promise": { "version": "2.0.1", + "resolved": false, "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", "requires": { "pinkie": "^2.0.0" @@ -9839,6 +4772,12 @@ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" }, + "prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", + "dev": true + }, "prettier": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz", @@ -9847,6 +4786,7 @@ }, "process-nextick-args": { "version": "1.0.7", + "resolved": false, "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" }, "promisify-call": { @@ -9932,11 +4872,41 @@ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" }, + "psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" + }, + "pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "punycode": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" }, + "pupa": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", + "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", + "dev": true, + "requires": { + "escape-goat": "^2.0.0" + } + }, "pushover-notifications": { "version": "0.1.9", "resolved": "https://registry.npmjs.org/pushover-notifications/-/pushover-notifications-0.1.9.tgz", @@ -9948,9 +4918,9 @@ "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=" }, "qs": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", - "integrity": "sha1-NJzfbu+J7EXBLX1es/wMhwNDptg=" + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" }, "querystring": { "version": "0.2.0", @@ -9981,6 +4951,7 @@ }, "readable-stream": { "version": "2.3.3", + "resolved": false, "integrity": "sha1-No8lEtefnUb9/HE0mueHi7weuVw=", "requires": { "core-util-is": "~1.0.0", @@ -9992,6 +4963,33 @@ "util-deprecate": "~1.0.1" } }, + "readdirp": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", + "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "registry-auth-token": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", + "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", + "dev": true, + "requires": { + "rc": "^1.2.8" + } + }, + "registry-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", + "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", + "dev": true, + "requires": { + "rc": "^1.2.8" + } + }, "replacestream": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/replacestream/-/replacestream-4.0.0.tgz", @@ -10067,32 +5065,56 @@ } }, "request": { - "version": "2.85.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.85.0.tgz", - "integrity": "sha512-8H7Ehijd4js+s6wuVPLjwORxD4zeuyjYugprdOXlPSqaApmL/QOy+EB/beICHVCHkGMKNh5rvihb5ov+IDw4mg==", + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", "requires": { "aws-sign2": "~0.7.0", - "aws4": "^1.6.0", + "aws4": "^1.8.0", "caseless": "~0.12.0", - "combined-stream": "~1.0.5", - "extend": "~3.0.1", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", "forever-agent": "~0.6.1", - "form-data": "~2.3.1", - "har-validator": "~5.0.3", - "hawk": "~6.0.2", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", "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", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", "performance-now": "^2.1.0", - "qs": "~6.5.1", - "safe-buffer": "^5.1.1", - "stringstream": "~0.0.5", - "tough-cookie": "~2.3.3", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", "tunnel-agent": "^0.6.0", - "uuid": "^3.1.0" + "uuid": "^3.3.2" + }, + "dependencies": { + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + } } }, "request-promise": { @@ -10103,13 +5125,6 @@ "bluebird": "^3.3", "lodash": "^4.6.1", "request": "^2.34" - }, - "dependencies": { - "lodash": { - "version": "4.17.10", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", - "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==" - } } }, "requires-port": { @@ -10138,6 +5153,15 @@ } } }, + "responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "dev": true, + "requires": { + "lowercase-keys": "^1.0.0" + } + }, "retry": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/retry/-/retry-0.9.0.tgz", @@ -10162,6 +5186,7 @@ }, "safe-buffer": { "version": "5.1.1", + "resolved": false, "integrity": "sha1-iTMSr2myEj3vcfV4iQAWce6yyFM=" }, "safer-buffer": { @@ -10169,11 +5194,6 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, - "samsam": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.3.0.tgz", - "integrity": "sha512-1HwIYD/8UlOtFS3QO3w7ey+SdSDFE4HRNLZoZRYVQefrOY3l17epswImeB1ijgJFQJodIaHcwkp3r/myBjFVbg==" - }, "sax": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", @@ -10184,6 +5204,23 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz", "integrity": "sha1-d0Zt5YnNXTyV8TiqeLxWmjy10no=" }, + "semver-diff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", + "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", + "dev": true, + "requires": { + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", @@ -10264,43 +5301,11 @@ } } }, - "sinon": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-4.5.0.tgz", - "integrity": "sha512-trdx+mB0VBBgoYucy6a9L7/jfQOmvGeaKZT4OOJ+lPAtI8623xyGr8wLiE4eojzBS8G9yXbhx42GHUOVLr4X2w==", - "requires": { - "@sinonjs/formatio": "^2.0.0", - "diff": "^3.1.0", - "lodash.get": "^4.4.2", - "lolex": "^2.2.0", - "nise": "^1.2.0", - "supports-color": "^5.1.0", - "type-detect": "^4.0.5" - }, - "dependencies": { - "supports-color": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, "smart-buffer": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.1.0.tgz", "integrity": "sha512-iVICrxOzCynf/SNaBQCw34eM9jROU/s5rzIhpOvzhzuYHfJR/DhZfDkXiZSgKXfgv26HT3Yni3AV/DGw0cGnnw==" }, - "sntp": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", - "integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==", - "requires": { - "hoek": "4.x.x" - } - }, "socks": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/socks/-/socks-2.3.3.tgz", @@ -10400,10 +5405,12 @@ }, "stack-trace": { "version": "0.0.10", + "resolved": false, "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" }, "statuses": { "version": "1.4.0", + "resolved": false, "integrity": "sha1-u3PURtonlhBu/MG2AaJT1sRr0Ic=" }, "stream-events": { @@ -10419,13 +5426,6 @@ "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=" }, - "string_decoder": { - "version": "1.0.3", - "integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=", - "requires": { - "safe-buffer": "~5.1.0" - } - }, "string-format-obj": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string-format-obj/-/string-format-obj-1.1.1.tgz", @@ -10441,6 +5441,14 @@ "strip-ansi": "^3.0.0" } }, + "string_decoder": { + "version": "1.0.3", + "resolved": false, + "integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=", + "requires": { + "safe-buffer": "~5.1.0" + } + }, "stringstream": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", @@ -10448,6 +5456,7 @@ }, "strip-ansi": { "version": "3.0.1", + "resolved": false, "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { "ansi-regex": "^2.0.0" @@ -10480,6 +5489,7 @@ }, "supports-color": { "version": "2.0.0", + "resolved": false, "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" }, "tar": { @@ -10503,13 +5513,15 @@ } } }, - "text-encoding": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/text-encoding/-/text-encoding-0.6.4.tgz", - "integrity": "sha1-45mpgiV6J22uQou5KEXLcb3CbRk=" + "term-size": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz", + "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==", + "dev": true }, "through": { "version": "2.3.8", + "resolved": false, "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" }, "through2": { @@ -10526,11 +5538,46 @@ "resolved": "https://registry.npmjs.org/thunkify/-/thunkify-2.1.2.tgz", "integrity": "sha1-+qDp0jDFGsyVyhOjYawFyn4EVT0=" }, + "to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", + "dev": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, "toidentifier": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" }, + "touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dev": true, + "requires": { + "nopt": "~1.0.10" + }, + "dependencies": { + "nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", + "dev": true, + "requires": { + "abbrev": "1" + } + } + } + }, "tough-cookie": { "version": "2.3.4", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", @@ -10566,30 +5613,137 @@ "prelude-ls": "~1.1.2" } }, - "type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==" + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true }, "typedarray": { "version": "0.0.6", + "resolved": false, "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "requires": { + "is-typedarray": "^1.0.0" + } + }, + "typescript": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz", + "integrity": "sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==", + "dev": true + }, "ultron": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz", "integrity": "sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po=" }, + "undefsafe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.3.tgz", + "integrity": "sha512-nrXZwwXrD/T/JXeygJqdCO6NZZ1L66HrxM/Z7mIq2oPanoN0F1nLx3lwJMu6AwJY69hdixaFQOuoYsMjE5/C2A==", + "dev": true, + "requires": { + "debug": "^2.2.0" + } + }, "underscore": { "version": "1.12.1", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.12.1.tgz", "integrity": "sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==" }, + "unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dev": true, + "requires": { + "crypto-random-string": "^2.0.0" + } + }, "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" }, + "update-notifier": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-4.1.3.tgz", + "integrity": "sha512-Yld6Z0RyCYGB6ckIjffGOSOmHXj1gMeE7aROz4MG+XMkmixBX4jUngrGXNYz7wPKBmtoD4MnBa2Anu7RSKht/A==", + "dev": true, + "requires": { + "boxen": "^4.2.0", + "chalk": "^3.0.0", + "configstore": "^5.0.1", + "has-yarn": "^2.1.0", + "import-lazy": "^2.1.0", + "is-ci": "^2.0.0", + "is-installed-globally": "^0.3.1", + "is-npm": "^4.0.0", + "is-yarn-global": "^0.3.0", + "latest-version": "^5.0.0", + "pupa": "^2.0.1", + "semver-diff": "^3.1.1", + "xdg-basedir": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "requires": { + "punycode": "^2.1.0" + }, + "dependencies": { + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + } + } + }, "url": { "version": "0.10.3", "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", @@ -10611,14 +5765,24 @@ "resolved": "https://registry.npmjs.org/url-join/-/url-join-0.0.1.tgz", "integrity": "sha1-HbSK1CLTQCRpqH99l73r/k+x48g=" }, + "url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", + "dev": true, + "requires": { + "prepend-http": "^2.0.0" + } + }, "util-deprecate": { "version": "1.0.2", + "resolved": false, "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, "uuid": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz", - "integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==" + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" }, "valid-url": { "version": "1.0.9", @@ -10643,6 +5807,55 @@ "string-width": "^1.0.2 || 2" } }, + "widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "dev": true, + "requires": { + "string-width": "^4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "string-width": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + } + } + }, "winston": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/winston/-/winston-1.0.2.tgz", @@ -10706,8 +5919,21 @@ }, "wrappy": { "version": "1.0.2", + "resolved": false, "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, "ws": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.5.tgz", @@ -10717,6 +5943,12 @@ "ultron": "1.0.x" } }, + "xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", + "dev": true + }, "xml2js": { "version": "0.4.17", "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.17.tgz", @@ -10741,6 +5973,7 @@ }, "xtend": { "version": "4.0.1", + "resolved": false, "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" }, "yallist": { diff --git a/server/package.json b/server/package.json index 5d9b847aa..be9ffe222 100644 --- a/server/package.json +++ b/server/package.json @@ -2,9 +2,15 @@ "name": "polis", "version": "0.0.0", "description": "polis =====", - "main": "app.js", + "main": "./dist/app.js", "scripts": { - "test": "npm format:check", + "test": "npm run format:check", + "build": "./node_modules/typescript/bin/tsc --project tsconfig.json", + "build:watch": "./node_modules/typescript/bin/tsc --watch & ./node_modules/nodemon/bin/nodemon.js --inspect=0.0.0.0:9229 -q dist/app.js", + "serve": "node --max_old_space_size=400 --gc_interval=100 --harmony dist/app.js", + "start": "npm install && npm run build && npm run serve", + "dev": "npm install && npm run build:watch", + "type:check:watch": "tsc --watch", "format": "prettier --config ./prettier.config.js --no-editorconfig 'src/**/*.{js,ts}' --write", "format:check": "prettier --config ./prettier.config.js --no-editorconfig 'src/**/*.{js,ts}' --check" }, @@ -13,7 +19,7 @@ "url": "git://github.com/pol-is/polisServer.git" }, "author": "", - "license": "", + "license": "AGPL-3.0", "dependencies": { "@google-cloud/translate": "^1.0.0", "@slack/client": "^3.5.3", @@ -30,7 +36,7 @@ "express": "3.21.2", "fb": "1.0.2", "http-proxy": "1.18.1", - "intercom-client": "2.9.4", + "intercom-client": "2.11.2", "intercom.io": "1.5.0", "lru-cache": "3.0.0", "mimelib": "0.2.19", @@ -40,7 +46,7 @@ "optimist": "0.3.7", "p3p": "0.0.2", "pg": "7.4.3", - "pg-connection-string": "2.0.0", + "pg-connection-string": "2.5.0", "pg-native": "3.0.0", "pushover-notifications": "0.1.9", "replacestream": "4.0.0", @@ -55,6 +61,27 @@ "winston": "1.0.2" }, "devDependencies": { - "prettier": "^2.2.1" + "@types/async": "^3.2.6", + "@types/bcrypt": "^3.0.1", + "@types/bluebird": "^3.5.33", + "@types/connect-timeout": "^0.0.34", + "@types/express": "^4.17.11", + "@types/fb": "^0.0.28", + "@types/http-proxy": "^1.17.5", + "@types/intercom-client": "^2.11.10", + "@types/lru-cache": "^5.1.0", + "@types/node": "^14.14.39", + "@types/nodemailer": "^6.4.1", + "@types/nodemailer-mailgun-transport": "^1.4.2", + "@types/oauth": "^0.9.1", + "@types/pg": "^7.14.11", + "@types/replacestream": "^4.0.0", + "@types/request-promise": "^4.1.47", + "@types/response-time": "^2.3.4", + "@types/underscore": "^1.11.1", + "@types/valid-url": "^1.0.3", + "prettier": "^2.2.1", + "typescript": "^4.2.4", + "nodemon": "^2.0.7" } } diff --git a/server/src/auth/create-user.js b/server/src/auth/create-user.js deleted file mode 100644 index 9517a5c73..000000000 --- a/server/src/auth/create-user.js +++ /dev/null @@ -1,253 +0,0 @@ -const _ = require("underscore"); -const pg = require("../db/pg-query"); -const fail = require("../log").fail; -const Config = require("../config"); -const Cookies = require("../utils/cookies"); -const User = require("../user"); -const Session = require("../session"); -const Utils = require("../utils/common"); -const Password = require("./password"); - -const emailSenders = require("../email/senders"); -const sendTextEmail = emailSenders.sendTextEmail; - -function createUser(req, res) { - const COOKIES = require("../utils/cookies").COOKIES; - let hname = req.p.hname; - let password = req.p.password; - let password2 = req.p.password2; // for verification - let email = req.p.email; - let oinvite = req.p.oinvite; - let zinvite = req.p.zinvite; - let referrer = req.cookies[COOKIES.REFERRER]; - let organization = req.p.organization; - let gatekeeperTosPrivacy = req.p.gatekeeperTosPrivacy; - let lti_user_id = req.p.lti_user_id; - let lti_user_image = req.p.lti_user_image; - let lti_context_id = req.p.lti_context_id; - let tool_consumer_instance_guid = req.p.tool_consumer_instance_guid; - let afterJoinRedirectUrl = req.p.afterJoinRedirectUrl; - - let site_id = void 0; - if (req.p.encodedParams) { - let decodedParams = decodeParams(req.p.encodedParams); - if (decodedParams.site_id) { - // NOTE: we could have just allowed site_id to be passed as a normal param, but then we'd need to think about securing that with some other token sooner. - // I think we can get by with this obscure scheme for a bit. - // TODO_SECURITY add the extra token associated with the site_id owner. - site_id = decodedParams.site_id; - } - } - - if (password2 && password !== password2) { - fail(res, 400, "Passwords do not match."); - return; - } - if (!gatekeeperTosPrivacy) { - fail(res, 400, "polis_err_reg_need_tos"); - return; - } - if (!email) { - fail(res, 400, "polis_err_reg_need_email"); - return; - } - if (!hname) { - fail(res, 400, "polis_err_reg_need_name"); - return; - } - if (!password) { - fail(res, 400, "polis_err_reg_password"); - return; - } - if (password.length < 6) { - fail(res, 400, "polis_err_reg_password_too_short"); - return; - } - if (!_.contains(email, "@") || email.length < 3) { - fail(res, 400, "polis_err_reg_bad_email"); - return; - } - - pg.queryP("SELECT * FROM users WHERE email = ($1)", [email]).then( - function (rows) { - if (rows.length > 0) { - fail(res, 403, "polis_err_reg_user_with_that_email_exists"); - return; - } - - Password.generateHashedPassword(password, function (err, hashedPassword) { - if (err) { - fail(res, 500, "polis_err_generating_hash", err); - return; - } - let query = - "insert into users " + - "(email, hname, zinvite, oinvite, is_owner" + - (site_id ? ", site_id" : "") + - ") VALUES " + // TODO use sql query builder - "($1, $2, $3, $4, $5" + - (site_id ? ", $6" : "") + - ") " + // TODO use sql query builder - "returning uid;"; - let vals = [email, hname, zinvite || null, oinvite || null, true]; - if (site_id) { - vals.push(site_id); // TODO use sql query builder - } - - pg.query(query, vals, function (err, result) { - if (err) { - winston.log("info", err); - fail(res, 500, "polis_err_reg_failed_to_add_user_record", err); - return; - } - let uid = - result && result.rows && result.rows[0] && result.rows[0].uid; - - pg.query( - "insert into jianiuevyew (uid, pwhash) values ($1, $2);", - [uid, hashedPassword], - function (err, results) { - if (err) { - winston.log("info", err); - fail(res, 500, "polis_err_reg_failed_to_add_user_record", err); - return; - } - Session.startSession(uid, function (err, token) { - if (err) { - fail(res, 500, "polis_err_reg_failed_to_start_session", err); - return; - } - Cookies.addCookies(req, res, token, uid) - .then( - function () { - let ltiUserPromise = lti_user_id - ? User.addLtiUserIfNeeded( - uid, - lti_user_id, - tool_consumer_instance_guid, - lti_user_image - ) - : Promise.resolve(); - let ltiContextMembershipPromise = lti_context_id - ? User.addLtiContextMembership( - uid, - lti_context_id, - tool_consumer_instance_guid - ) - : Promise.resolve(); - Promise.all([ltiUserPromise, ltiContextMembershipPromise]) - .then(function () { - if (lti_user_id) { - if (afterJoinRedirectUrl) { - res.redirect(afterJoinRedirectUrl); - } else { - User.renderLtiLinkageSuccessPage(req, res, { - // may include token here too - context_id: lti_context_id, - uid: uid, - hname: hname, - email: email, - }); - } - } else { - res.json({ - uid: uid, - hname: hname, - email: email, - // token: token - }); - } - }) - .catch(function (err) { - fail( - res, - 500, - "polis_err_creating_user_associating_with_lti_user", - err - ); - }); - }, - function (err) { - fail(res, 500, "polis_err_adding_cookies", err); - } - ) - .catch(function (err) { - fail(res, 500, "polis_err_adding_user", err); - }); - }); // end startSession - } - ); // end insert pwhash - }); // end insert user - }); // end generateHashedPassword - }, - function (err) { - fail(res, 500, "polis_err_reg_checking_existing_users", err); - } - ); -} - -function doSendVerification(req, email) { - return Password.generateTokenP(30, false).then(function (einvite) { - return pg - .queryP("insert into einvites (email, einvite) values ($1, $2);", [ - email, - einvite, - ]) - .then(function (rows) { - return sendVerificationEmail(req, email, einvite); - }); - }); -} - -function sendVerificationEmail(req, email, einvite) { - let serverName = Config.getServerNameWithProtocol(req); - let body = `Welcome to pol.is! - -Click this link to verify your email address: - -${serverName}/api/v3/verify?e=${einvite}`; - - return sendTextEmail( - Config.get("POLIS_FROM_ADDRESS"), - email, - "Polis verification", - body - ); -} - -function decodeParams(encodedStringifiedJson) { - if (!encodedStringifiedJson.match(/^\/?ep1_/)) { - throw new Error("wrong encoded params prefix"); - } - if (encodedStringifiedJson[0] === "/") { - encodedStringifiedJson = encodedStringifiedJson.slice(5); - } else { - encodedStringifiedJson = encodedStringifiedJson.slice(4); - } - let stringifiedJson = Utils.hexToStr(encodedStringifiedJson); - let o = JSON.parse(stringifiedJson); - return o; -} - -function generateAndRegisterZinvite(zid, generateShort) { - let len = 10; - if (generateShort) { - len = 6; - } - return Password.generateTokenP(len, false).then(function (zinvite) { - return pg - .queryP( - "INSERT INTO zinvites (zid, zinvite, created) VALUES ($1, $2, default);", - [zid, zinvite] - ) - .then(function (rows) { - return zinvite; - }); - }); -} - -module.exports = { - createUser, - doSendVerification, - generateAndRegisterZinvite, -}; diff --git a/server/src/auth/create-user.ts b/server/src/auth/create-user.ts new file mode 100644 index 000000000..25a237940 --- /dev/null +++ b/server/src/auth/create-user.ts @@ -0,0 +1,291 @@ +import _ from "underscore"; + +import pg from "../db/pg-query"; +import { fail } from "../log"; +import Config from "../config"; +import Cookies from "../utils/cookies"; +import { COOKIES } from "../utils/cookies"; +import User from "../user"; +import Session from "../session"; +import Utils from "../utils/common"; +import Password from "./password"; + +import emailSenders from "../email/senders"; +const sendTextEmail = emailSenders.sendTextEmail; +function createUser(req: any, res: any) { + let hname = req.p.hname; + let password = req.p.password; + let password2 = req.p.password2; // for verification + let email = req.p.email; + let oinvite = req.p.oinvite; + let zinvite = req.p.zinvite; + let referrer = req.cookies[COOKIES.REFERRER]; + let organization = req.p.organization; + let gatekeeperTosPrivacy = req.p.gatekeeperTosPrivacy; + let lti_user_id = req.p.lti_user_id; + let lti_user_image = req.p.lti_user_image; + let lti_context_id = req.p.lti_context_id; + let tool_consumer_instance_guid = req.p.tool_consumer_instance_guid; + let afterJoinRedirectUrl = req.p.afterJoinRedirectUrl; + + let site_id = void 0; + if (req.p.encodedParams) { + let decodedParams = decodeParams(req.p.encodedParams); + if (decodedParams.site_id) { + // NOTE: we could have just allowed site_id to be passed as a normal param, but then we'd need to think about securing that with some other token sooner. + // I think we can get by with this obscure scheme for a bit. + // TODO_SECURITY add the extra token associated with the site_id owner. + site_id = decodedParams.site_id; + } + } + + if (password2 && password !== password2) { + fail(res, 400, "Passwords do not match."); + return; + } + if (!gatekeeperTosPrivacy) { + fail(res, 400, "polis_err_reg_need_tos"); + return; + } + if (!email) { + fail(res, 400, "polis_err_reg_need_email"); + return; + } + if (!hname) { + fail(res, 400, "polis_err_reg_need_name"); + return; + } + if (!password) { + fail(res, 400, "polis_err_reg_password"); + return; + } + if (password.length < 6) { + fail(res, 400, "polis_err_reg_password_too_short"); + return; + } + if (!_.contains(email, "@") || email.length < 3) { + fail(res, 400, "polis_err_reg_bad_email"); + return; + } + + pg.queryP("SELECT * FROM users WHERE email = ($1)", [email]).then( + // Argument of type '(rows: string | any[]) => void' is not assignable to parameter of type '(value: unknown) => void | PromiseLike'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + function (rows: string | any[]) { + if (rows.length > 0) { + fail(res, 403, "polis_err_reg_user_with_that_email_exists"); + return; + } + + Password.generateHashedPassword( + password, + function (err: any, hashedPassword: any) { + if (err) { + fail(res, 500, "polis_err_generating_hash", err); + return; + } + let query = + "insert into users " + + "(email, hname, zinvite, oinvite, is_owner" + + (site_id ? ", site_id" : "") + + ") VALUES " + // TODO use sql query builder + "($1, $2, $3, $4, $5" + + (site_id ? ", $6" : "") + + ") " + // TODO use sql query builder + "returning uid;"; + let vals = [email, hname, zinvite || null, oinvite || null, true]; + if (site_id) { + vals.push(site_id); // TODO use sql query builder + } + + pg.query( + query, + vals, + function (err: any, result: { rows: { uid: any }[] }) { + if (err) { + // TS2304: Cannot find name 'winston'. + // 117 winston.log("info", err); + // @ts-ignore + winston.log("info", err); + fail(res, 500, "polis_err_reg_failed_to_add_user_record", err); + return; + } + let uid = + result && result.rows && result.rows[0] && result.rows[0].uid; + + pg.query( + "insert into jianiuevyew (uid, pwhash) values ($1, $2);", + [uid, hashedPassword], + function (err: any, results: any) { + if (err) { + // TS2304: Cannot find name 'winston'. + // 120 winston.log("info", err); + // @ts-ignore + winston.log("info", err); + fail( + res, + 500, + "polis_err_reg_failed_to_add_user_record", + err + ); + return; + } + Session.startSession(uid, function (err: any, token: any) { + if (err) { + fail( + res, + 500, + "polis_err_reg_failed_to_start_session", + err + ); + return; + } + Cookies.addCookies(req, res, token, uid) + .then( + function () { + let ltiUserPromise = lti_user_id + ? User.addLtiUserIfNeeded( + uid, + lti_user_id, + tool_consumer_instance_guid, + lti_user_image + ) + : Promise.resolve(); + let ltiContextMembershipPromise = lti_context_id + ? User.addLtiContextMembership( + uid, + lti_context_id, + tool_consumer_instance_guid + ) + : Promise.resolve(); + Promise.all([ + ltiUserPromise, + ltiContextMembershipPromise, + ]) + .then(function () { + if (lti_user_id) { + if (afterJoinRedirectUrl) { + res.redirect(afterJoinRedirectUrl); + } else { + User.renderLtiLinkageSuccessPage(req, res, { + // may include token here too + // Argument of type '{ context_id: any; uid: any; + // hname: any; email: any; + // }' is not assignable to parameter of type '{ email: string; }'. + //Object literal may only specify known properties, and + // 'context_id' does not exist in type '{ email: string; }'.ts(2345) + // @ts-ignore + context_id: lti_context_id, + uid: uid, + hname: hname, + email: email, + }); + } + } else { + res.json({ + uid: uid, + hname: hname, + email: email, + // token: token + }); + } + }) + .catch(function (err) { + fail( + res, + 500, + "polis_err_creating_user_associating_with_lti_user", + err + ); + }); + }, + function (err: any) { + fail(res, 500, "polis_err_adding_cookies", err); + } + ) + .catch(function (err: any) { + fail(res, 500, "polis_err_adding_user", err); + }); + }); // end startSession + } + ); // end insert pwhash + } + ); // end insert user + } + ); // end generateHashedPassword + }, + function (err: any) { + fail(res, 500, "polis_err_reg_checking_existing_users", err); + } + ); +} + +function doSendVerification(req: any, email: any) { + return Password.generateTokenP(30, false).then(function (einvite: any) { + return pg + .queryP("insert into einvites (email, einvite) values ($1, $2);", [ + email, + einvite, + ]) + .then(function (rows: any) { + return sendVerificationEmail(req, email, einvite); + }); + }); +} + +function sendVerificationEmail(req: any, email: any, einvite: any) { + let serverName = Config.getServerNameWithProtocol(req); + let body = `Welcome to pol.is! + +Click this link to verify your email address: + +${serverName}/api/v3/verify?e=${einvite}`; + + return sendTextEmail( + Config.get("POLIS_FROM_ADDRESS"), + email, + "Polis verification", + body + ); +} + +function decodeParams(encodedStringifiedJson: string | string[]) { + if ( + typeof encodedStringifiedJson === "string" && + !encodedStringifiedJson.match(/^\/?ep1_/) + ) { + throw new Error("wrong encoded params prefix"); + } + if (encodedStringifiedJson[0] === "/") { + encodedStringifiedJson = encodedStringifiedJson.slice(5); + } else { + encodedStringifiedJson = encodedStringifiedJson.slice(4); + } + let stringifiedJson = Utils.hexToStr(encodedStringifiedJson as string); + let o = JSON.parse(stringifiedJson); + return o; +} + +function generateAndRegisterZinvite(zid: any, generateShort: any) { + let len = 10; + if (generateShort) { + len = 6; + } + return Password.generateTokenP(len, false).then(function (zinvite: any) { + return pg + .queryP( + "INSERT INTO zinvites (zid, zinvite, created) VALUES ($1, $2, default);", + [zid, zinvite] + ) + .then(function (rows: any) { + return zinvite; + }); + }); +} + +export { createUser, doSendVerification, generateAndRegisterZinvite }; + +export default { createUser, doSendVerification, generateAndRegisterZinvite }; diff --git a/server/src/auth/password.js b/server/src/auth/password.ts similarity index 56% rename from server/src/auth/password.js rename to server/src/auth/password.ts index 6119ab092..a079d6c97 100644 --- a/server/src/auth/password.js +++ b/server/src/auth/password.ts @@ -1,14 +1,18 @@ -const bcrypt = require("bcrypt"); -const crypto = require("crypto"); -const _ = require("underscore"); -const pg = require("../db/pg-query"); +import bcrypt from "bcrypt"; +import crypto from "crypto"; +import _ from "underscore"; -function generateHashedPassword(password, callback) { - bcrypt.genSalt(12, function (errSalt, salt) { +import pg from "../db/pg-query"; + +function generateHashedPassword( + password: any, + callback: (arg0: string | null, arg1?: undefined) => void +) { + bcrypt.genSalt(12, function (errSalt: any, salt: any) { if (errSalt) { return callback("polis_err_salt"); } - bcrypt.hash(password, salt, function (errHash, hashedPassword) { + bcrypt.hash(password, salt, function (errHash: any, hashedPassword: any) { if (errHash) { return callback("polis_err_hash"); } @@ -17,32 +21,50 @@ function generateHashedPassword(password, callback) { }); } -function checkPassword(uid, password) { - return pg - .queryP_readOnly_wRetryIfEmpty( - "select pwhash from jianiuevyew where uid = ($1);", - [uid] - ) - .then(function (rows) { - if (!rows || !rows.length) { - return null; - } else if (!rows[0].pwhash) { - return void 0; - } - let hashedPassword = rows[0].pwhash; - return new Promise(function (resolve, reject) { - bcrypt.compare(password, hashedPassword, function (errCompare, result) { - if (errCompare) { - reject(errCompare); - } else { - resolve(result ? "ok" : 0); - } +function checkPassword(uid: any, password: any) { + return ( + pg + .queryP_readOnly_wRetryIfEmpty( + "select pwhash from jianiuevyew where uid = ($1);", + [uid] + ) + // Argument of type '(rows: string | any[]) => Promise | null | undefined' is not assignable to parameter of type '(value: unknown) => unknown'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + .then(function (rows: string | any[]) { + if (!rows || !rows.length) { + return null; + } else if (!rows[0].pwhash) { + return void 0; + } + let hashedPassword = rows[0].pwhash; + return new Promise(function (resolve, reject) { + bcrypt.compare( + password, + hashedPassword, + function (errCompare: any, result: any) { + if (errCompare) { + reject(errCompare); + } else { + resolve(result ? "ok" : 0); + } + } + ); }); - }); - }); + }) + ); } -function generateToken(len, pseudoRandomOk, callback) { +function generateToken( + len: any, + pseudoRandomOk: any, + callback: { + (err: any, token: any): void; + (arg0: number, longStringOfTokens?: string): void; + } +) { // TODO store up a buffer of random bytes sampled at random times to reduce predictability. (or see if crypto module does this for us) // TODO if you want more readable tokens, see ReadableIds let gen; @@ -51,38 +73,44 @@ function generateToken(len, pseudoRandomOk, callback) { } else { gen = crypto.randomBytes; } - gen(len, function (err, buf) { - if (err) { - return callback(err); - } + gen( + len, + function ( + err: any, + buf: { toString: (arg0: BufferEncoding | undefined) => string } + ) { + if (err) { + return callback(err); + } - let prettyToken = buf - .toString("base64") - .replace(/\//g, "A") - .replace(/\+/g, "B") // replace url-unsafe tokens (ends up not being a proper encoding since it maps onto A and B. Don't want to use any punctuation.) - .replace(/l/g, "C") // looks like '1' - .replace(/L/g, "D") // looks like '1' - .replace(/o/g, "E") // looks like 0 - .replace(/O/g, "F") // looks lke 0 - .replace(/1/g, "G") // looks like 'l' - .replace(/0/g, "H") // looks like 'O' - .replace(/I/g, "J") // looks like 'l' - .replace(/g/g, "K") // looks like 'g' - .replace(/G/g, "M") // looks like 'g' - .replace(/q/g, "N") // looks like 'q' - .replace(/Q/g, "R"); // looks like 'q' - // replace first character with a number between 2 and 9 (avoiding 0 and 1 since they look like l and O) - prettyToken = _.random(2, 9) + prettyToken.slice(1); - prettyToken = prettyToken.toLowerCase(); - prettyToken = prettyToken.slice(0, len); // in case it's too long - - callback(0, prettyToken); - }); + let prettyToken = buf + .toString("base64") + .replace(/\//g, "A") + .replace(/\+/g, "B") // replace url-unsafe tokens (ends up not being a proper encoding since it maps onto A and B. Don't want to use any punctuation.) + .replace(/l/g, "C") // looks like '1' + .replace(/L/g, "D") // looks like '1' + .replace(/o/g, "E") // looks like 0 + .replace(/O/g, "F") // looks lke 0 + .replace(/1/g, "G") // looks like 'l' + .replace(/0/g, "H") // looks like 'O' + .replace(/I/g, "J") // looks like 'l' + .replace(/g/g, "K") // looks like 'g' + .replace(/G/g, "M") // looks like 'g' + .replace(/q/g, "N") // looks like 'q' + .replace(/Q/g, "R"); // looks like 'q' + // replace first character with a number between 2 and 9 (avoiding 0 and 1 since they look like l and O) + prettyToken = _.random(2, 9) + prettyToken.slice(1); + prettyToken = prettyToken.toLowerCase(); + prettyToken = prettyToken.slice(0, len); // in case it's too long + + callback(0, prettyToken); + } + ); } -function generateTokenP(len, pseudoRandomOk) { +function generateTokenP(len: any, pseudoRandomOk: any) { return new Promise(function (resolve, reject) { - generateToken(len, pseudoRandomOk, function (err, token) { + generateToken(len, pseudoRandomOk, function (err: any, token: unknown) { if (err) { reject(err); } else { @@ -192,7 +220,9 @@ function generateTokenP(len, pseudoRandomOk) { // console.error(err); // }); -module.exports = { +export { generateHashedPassword, checkPassword, generateToken, generateTokenP }; + +export default { generateHashedPassword, checkPassword, generateToken, diff --git a/server/src/comment.js b/server/src/comment.ts similarity index 54% rename from server/src/comment.js rename to server/src/comment.ts index ad1931069..ee046ccc1 100644 --- a/server/src/comment.js +++ b/server/src/comment.ts @@ -1,16 +1,51 @@ -const _ = require("underscore"); -const fs = require("fs"); -const pg = require("./db/pg-query"); -const Conversation = require("./conversation"); -const User = require("./user"); -const MPromise = require("./utils/metered").MPromise; -const SQL = require("./db/sql"); -const Translate = require("@google-cloud/translate"); -const isTrue = require("boolean"); -const Utils = require("./utils/common"); +import _ from "underscore"; +import fs from "fs"; +import Translate from "@google-cloud/translate"; +import isTrue from "boolean"; + +import pg from "./db/pg-query"; +import SQL from "./db/sql"; +import { MPromise } from "./utils/metered"; +import Utils from "./utils/common"; + +import Conversation from "./conversation"; +import User from "./user"; +import { CommentType } from "./d"; + +// TODO should this be a number instead? +type Id = string; + +type Row = { + tid: Id; + disagree_count: number; + agree_count: number; + vote: any; + count: number; + pass_count: number; +}; + +type Docs = { + rows: Row[]; +}; + +type InfoToReturn = { + uid?: string | number; + followers_count?: any; + fb_user_id?: any; + fb_verified?: any; + fb_public_profile?: string; + fb_picture?: any; + tw_verified?: any; + tw_followers_count?: any; + verified?: any; +}; + +type UidToSocialInfo = { + [key: string]: any; +}; const useTranslateApi = isTrue(process.env.SHOULD_USE_TRANSLATION_API); -let translateClient = null; +let translateClient: any = null; if (useTranslateApi) { // Tell translation library where to find credentials, and write them to disk. process.env.GOOGLE_APPLICATION_CREDENTIALS = ".google_creds_temp"; @@ -19,28 +54,35 @@ if (useTranslateApi) { ? new Buffer(process.env.GOOGLE_CREDENTIALS_BASE64, "base64").toString( "ascii" ) - : process.env.GOOGLE_CREDS_STRINGIFIED; + : (process.env.GOOGLE_CREDS_STRINGIFIED as string | NodeJS.ArrayBufferView); fs.writeFileSync(process.env.GOOGLE_APPLICATION_CREDENTIALS, creds_string); translateClient = Translate(); } -function getComment(zid, tid) { - return pg - .queryP("select * from comments where zid = ($1) and tid = ($2);", [ - zid, - tid, - ]) - .then((rows) => { - return (rows && rows[0]) || null; - }); +function getComment(zid: Id, tid: Id) { + return ( + pg + .queryP("select * from comments where zid = ($1) and tid = ($2);", [ + zid, + tid, + ]) + + // Argument of type '(rows: Row[]) => Row' is not assignable to parameter of type '(value: unknown) => Row | PromiseLike'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'Row[]'.ts(2345) + // @ts-ignore + .then((rows: Row[]) => { + return (rows && rows[0]) || null; + }) + ); } -function getComments(o) { +function getComments(o: CommentType) { let commentListPromise = o.moderation ? _getCommentsForModerationList(o) : _getCommentsList(o); let convPromise = Conversation.getConversationInfo(o.zid); - let conv = null; + let conv: { is_anon: any } | null = null; return Promise.all([convPromise, commentListPromise]) .then(function (a) { let rows = a[1]; @@ -68,7 +110,7 @@ function getComments(o) { cols.push("pass_count"); // in moderation queries, we join in the vote count cols.push("count"); // in moderation queries, we join in the vote count } - rows = rows.map(function (row) { + rows = rows.map(function (row: Row) { let x = _.pick(row, cols); if (!_.isUndefined(x.count)) { x.count = Number(x.count); @@ -78,20 +120,28 @@ function getComments(o) { return rows; }) .then(function (comments) { - let include_social = !conv.is_anon && o.include_social; + let include_social = !conv?.is_anon && o.include_social; if (include_social) { - let nonAnonComments = comments.filter(function (c) { + let nonAnonComments = comments.filter(function (c: { + anon: any; + is_seed: any; + }) { return !c.anon && !c.is_seed; }); let uids = _.pluck(nonAnonComments, "uid"); return User.getSocialInfoForUsers(uids, o.zid).then(function ( - socialInfos + socialInfos: any[] ) { - let uidToSocialInfo = {}; - socialInfos.forEach(function (info) { + let uidToSocialInfo: UidToSocialInfo = {}; + socialInfos.forEach(function (info: { + verified: any; + followers_count: any; + fb_public_profile: string; + uid: string | number; + }) { // whitelist properties to send - let infoToReturn = _.pick(info, [ + let infoToReturn: InfoToReturn = _.pick(info, [ // fb "fb_name", "fb_link", @@ -130,7 +180,11 @@ function getComments(o) { uidToSocialInfo[info.uid] = infoToReturn; }); - return comments.map(function (c) { + return comments.map(function (c: { + uid: string | number; + anon: any; + social: any; + }) { let s = uidToSocialInfo[c.uid]; if (s) { if (!c.anon) { @@ -146,7 +200,7 @@ function getComments(o) { } }) .then(function (comments) { - comments.forEach(function (c) { + comments.forEach(function (c: { uid: any; anon: any }) { delete c.uid; delete c.anon; }); @@ -154,7 +208,14 @@ function getComments(o) { }); } -function _getCommentsForModerationList(o) { +function _getCommentsForModerationList(o: { + include_voting_patterns: any; + modIn: boolean; + zid: any; + strict_moderation: any; + mod: any; + mod_gt: any; +}) { var strictCheck = Promise.resolve(null); var include_voting_patterns = o.include_voting_patterns; @@ -163,7 +224,7 @@ function _getCommentsForModerationList(o) { .queryP("select strict_moderation from conversations where zid = ($1);", [ o.zid, ]) - .then((c) => { + .then((c: any) => { return o.strict_moderation; }); } @@ -207,9 +268,9 @@ function _getCommentsForModerationList(o) { modClause, params ) - .then((rows) => { + .then((rows: Row[]) => { // each comment will have up to three rows. merge those into one with agree/disagree/pass counts. - let adp = {}; + let adp: { [key: string]: Row } = {}; for (let i = 0; i < rows.length; i++) { let row = rows[i]; let o = (adp[row.tid] = adp[row.tid] || { @@ -225,7 +286,7 @@ function _getCommentsForModerationList(o) { o.pass_count = Number(row.count); } } - rows = _.uniq(rows, false, (row) => { + rows = _.uniq(rows, false, (row: { tid: Id }) => { return row.tid; }); @@ -241,80 +302,98 @@ function _getCommentsForModerationList(o) { }); } -function _getCommentsList(o) { - return new MPromise("_getCommentsList", function (resolve, reject) { - Conversation.getConversationInfo(o.zid).then(function (conv) { - let q = SQL.sql_comments - .select(SQL.sql_comments.star()) - .where(SQL.sql_comments.zid.equals(o.zid)); - if (!_.isUndefined(o.pid)) { - q = q.and(SQL.sql_comments.pid.equals(o.pid)); - } - if (!_.isUndefined(o.tids)) { - q = q.and(SQL.sql_comments.tid.in(o.tids)); - } - if (!_.isUndefined(o.mod)) { - q = q.and(SQL.sql_comments.mod.equals(o.mod)); - } - if (!_.isUndefined(o.not_voted_by_pid)) { - // 'SELECT * FROM comments WHERE zid = 12 AND tid NOT IN (SELECT tid FROM votes WHERE pid = 1);' - // Don't return comments the user has already voted on. - q = q.and( - SQL.sql_comments.tid.notIn( - SQL.sql_votes_latest_unique - .subQuery() - .select(SQL.sql_votes_latest_unique.tid) - .where(SQL.sql_votes_latest_unique.zid.equals(o.zid)) - .and(SQL.sql_votes_latest_unique.pid.equals(o.not_voted_by_pid)) - ) - ); - } +function _getCommentsList(o: { + zid: any; + pid: any; + tids: any; + mod: any; + not_voted_by_pid: any; + withoutTids: any; + moderation: any; + random: any; + limit: any; +}) { + // 'new' expression, whose target lacks a construct signature, implicitly has an 'any' type.ts(7009) + // @ts-ignore + return new MPromise( + "_getCommentsList", + function (resolve: (rows: Row[]) => void, reject: (arg0: any) => void) { + Conversation.getConversationInfo(o.zid).then(function (conv: { + strict_moderation: any; + prioritize_seed: any; + }) { + let q = SQL.sql_comments + .select(SQL.sql_comments.star()) + .where(SQL.sql_comments.zid.equals(o.zid)); + if (!_.isUndefined(o.pid)) { + q = q.and(SQL.sql_comments.pid.equals(o.pid)); + } + if (!_.isUndefined(o.tids)) { + q = q.and(SQL.sql_comments.tid.in(o.tids)); + } + if (!_.isUndefined(o.mod)) { + q = q.and(SQL.sql_comments.mod.equals(o.mod)); + } + if (!_.isUndefined(o.not_voted_by_pid)) { + // 'SELECT * FROM comments WHERE zid = 12 AND tid NOT IN (SELECT tid FROM votes WHERE pid = 1);' + // Don't return comments the user has already voted on. + q = q.and( + SQL.sql_comments.tid.notIn( + SQL.sql_votes_latest_unique + .subQuery() + .select(SQL.sql_votes_latest_unique.tid) + .where(SQL.sql_votes_latest_unique.zid.equals(o.zid)) + .and(SQL.sql_votes_latest_unique.pid.equals(o.not_voted_by_pid)) + ) + ); + } - if (!_.isUndefined(o.withoutTids)) { - q = q.and(SQL.sql_comments.tid.notIn(o.withoutTids)); - } - if (o.moderation) { - } else { - q = q.and(SQL.sql_comments.active.equals(true)); - if (conv.strict_moderation) { - q = q.and(SQL.sql_comments.mod.equals(Utils.polisTypes.mod.ok)); + if (!_.isUndefined(o.withoutTids)) { + q = q.and(SQL.sql_comments.tid.notIn(o.withoutTids)); + } + if (o.moderation) { } else { - q = q.and(SQL.sql_comments.mod.notEquals(Utils.polisTypes.mod.ban)); + q = q.and(SQL.sql_comments.active.equals(true)); + if (conv.strict_moderation) { + q = q.and(SQL.sql_comments.mod.equals(Utils.polisTypes.mod.ok)); + } else { + q = q.and(SQL.sql_comments.mod.notEquals(Utils.polisTypes.mod.ban)); + } } - } - q = q.and(SQL.sql_comments.velocity.gt(0)); // filter muted comments + q = q.and(SQL.sql_comments.velocity.gt(0)); // filter muted comments - if (!_.isUndefined(o.random)) { - if (conv.prioritize_seed) { - q = q.order("is_seed desc, random()"); + if (!_.isUndefined(o.random)) { + if (conv.prioritize_seed) { + q = q.order("is_seed desc, random()"); + } else { + q = q.order("random()"); + } } else { - q = q.order("random()"); - } - } else { - q = q.order(SQL.sql_comments.created); - } - if (!_.isUndefined(o.limit)) { - q = q.limit(o.limit); - } else { - q = q.limit(999); // TODO paginate - } - return pg.query(q.toString(), [], function (err, docs) { - if (err) { - reject(err); - return; + q = q.order(SQL.sql_comments.created); } - if (docs.rows && docs.rows.length) { - resolve(docs.rows); + if (!_.isUndefined(o.limit)) { + q = q.limit(o.limit); } else { - resolve([]); + q = q.limit(999); // TODO paginate } + return pg.query(q.toString(), [], function (err: any, docs: Docs) { + if (err) { + reject(err); + return; + } + if (docs.rows && docs.rows.length) { + resolve(docs.rows); + } else { + resolve([]); + } + }); }); - }); - }); + } + ); } -function getNumberOfCommentsRemaining(zid, pid) { +function getNumberOfCommentsRemaining(zid: any, pid: any) { return pg.queryP( "with " + "v as (select * from votes_latest_unique where zid = ($1) and pid = ($2)), " + @@ -326,32 +405,38 @@ function getNumberOfCommentsRemaining(zid, pid) { ); } -function translateAndStoreComment(zid, tid, txt, lang) { +function translateAndStoreComment(zid: any, tid: any, txt: any, lang: any) { if (useTranslateApi) { - return translateString(txt, lang).then((results) => { + return translateString(txt, lang).then((results: any[]) => { const translation = results[0]; const src = -1; // Google Translate of txt with no added context - return pg - .queryP( - "insert into comment_translations (zid, tid, txt, lang, src) values ($1, $2, $3, $4, $5) returning *;", - [zid, tid, translation, lang, src] - ) - .then((rows) => { - return rows[0]; - }); + return ( + pg + .queryP( + "insert into comment_translations (zid, tid, txt, lang, src) values ($1, $2, $3, $4, $5) returning *;", + [zid, tid, translation, lang, src] + ) + // Argument of type '(rows: Row[]) => Row' is not assignable to parameter of type '(value: unknown) => Row | PromiseLike'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'Row[]'.ts(2345) + // @ts-ignore + .then((rows: Row[]) => { + return rows[0]; + }) + ); }); } return Promise.resolve(null); } -function translateString(txt, target_lang) { +function translateString(txt: any, target_lang: any) { if (useTranslateApi) { return translateClient.translate(txt, target_lang); } return Promise.resolve(null); } -function detectLanguage(txt) { +function detectLanguage(txt: any) { if (useTranslateApi) { return translateClient.detect(txt); } @@ -363,7 +448,17 @@ function detectLanguage(txt) { ]); } -module.exports = { +export { + getComment, + getComments, + _getCommentsForModerationList, + _getCommentsList, + getNumberOfCommentsRemaining, + translateAndStoreComment, + detectLanguage, +}; + +export default { getComment, getComments, _getCommentsForModerationList, diff --git a/server/src/config.js b/server/src/config.ts similarity index 69% rename from server/src/config.js rename to server/src/config.ts index b1c973f1b..fd8f64043 100644 --- a/server/src/config.js +++ b/server/src/config.ts @@ -1,8 +1,9 @@ -const devMode = require("boolean")(get("DEV_MODE")); +import boolean from "boolean"; +const devMode = boolean(get('DEV_MODE')); const domainOverride = process.env.DOMAIN_OVERRIDE || null; -function getServerNameWithProtocol(req) { +function getServerNameWithProtocol(req: any) { let server = "https://pol.is"; if (domainOverride) { @@ -25,7 +26,7 @@ function getServerNameWithProtocol(req) { return server; } -function get(key) { +function get(key: any) { return process.env[key]; } @@ -33,9 +34,5 @@ function isDevMode() { return devMode; } -module.exports = { - domainOverride, - getServerNameWithProtocol, - get, - isDevMode, -}; +export { domainOverride, getServerNameWithProtocol, get, isDevMode }; +export default { domainOverride, getServerNameWithProtocol, get, isDevMode }; diff --git a/server/src/conversation.ts b/server/src/conversation.ts new file mode 100644 index 000000000..e7d8d48a3 --- /dev/null +++ b/server/src/conversation.ts @@ -0,0 +1,190 @@ +import LruCache from "lru-cache"; + +import pg from "./db/pg-query"; +import { MPromise } from "./utils/metered"; + +function createXidRecord( + ownerUid: any, + uid: any, + xid: any, + x_profile_image_url: any, + x_name: any, + x_email: any +) { + return pg.queryP( + "insert into xids (owner, uid, xid, x_profile_image_url, x_name, x_email) values ($1, $2, $3, $4, $5, $6) " + + "on conflict (owner, xid) do nothing;", + [ + ownerUid, + uid, + xid, + x_profile_image_url || null, + x_name || null, + x_email || null, + ] + ); +} + +function createXidRecordByZid( + zid: any, + uid: any, + xid: any, + x_profile_image_url: any, + x_name: any, + x_email: any +) { + return getConversationInfo(zid).then( + (conv: { use_xid_whitelist: any; owner: any }) => { + const shouldCreateXidRecord = conv.use_xid_whitelist + ? isXidWhitelisted(conv.owner, xid) + : Promise.resolve(true); + return shouldCreateXidRecord.then((should: any) => { + if (!should) { + throw new Error("polis_err_xid_not_whitelisted_2"); + } + return pg.queryP( + "insert into xids (owner, uid, xid, x_profile_image_url, x_name, x_email) values ((select org_id from conversations where zid = ($1)), $2, $3, $4, $5, $6) " + + "on conflict (owner, xid) do nothing;", + [ + zid, + uid, + xid, + x_profile_image_url || null, + x_name || null, + x_email || null, + ] + ); + }); + } + ); +} + +function getXidRecord(xid: any, zid: any) { + return pg.queryP( + "select * from xids where xid = ($1) and owner = (select org_id from conversations where zid = ($2));", + [xid, zid] + ); +} + +function isXidWhitelisted(owner: any, xid: any) { + return ( + pg + .queryP( + "select * from xid_whitelist where owner = ($1) and xid = ($2);", + [owner, xid] + ) + // Argument of type '(rows: string | any[]) => boolean' is not assignable to parameter of type '(value: unknown) => boolean | PromiseLike'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + .then((rows: string | any[]) => { + return !!rows && rows.length > 0; + }) + ); +} + +function getConversationInfo(zid: any) { + // (alias) function MPromise(name: string, f: (resolve: (value: unknown) => void, reject: (reason?: any) => void) => void): Promise + // import MPromise + // 'new' expression, whose target lacks a construct signature, implicitly has an 'any' type.ts(7009) + // @ts-ignore + return new MPromise( + "getConversationInfo", + function (resolve: (arg0: any) => void, reject: (arg0: any) => void) { + pg.query( + "SELECT * FROM conversations WHERE zid = ($1);", + [zid], + function (err: any, result: { rows: any[] }) { + if (err) { + reject(err); + } else { + resolve(result.rows[0]); + } + } + ); + } + ); +} + +function getConversationInfoByConversationId(conversation_id: any) { + // (alias) function MPromise(name: string, f: (resolve: (value: unknown) => void, reject: (reason?: any) => void) => void): Promise + // import MPromise + // 'new' expression, whose target lacks a construct signature, implicitly has an 'any' type.ts(7009) + // @ts-ignore + return new MPromise( + "getConversationInfoByConversationId", + function (resolve: (arg0: any) => void, reject: (arg0: any) => void) { + pg.query( + "SELECT * FROM conversations WHERE zid = (select zid from zinvites where zinvite = ($1));", + [conversation_id], + function (err: any, result: { rows: any[] }) { + if (err) { + reject(err); + } else { + resolve(result.rows[0]); + } + } + ); + } + ); +} + +const conversationIdToZidCache = new LruCache({ + max: 1000, +}); + +// NOTE: currently conversation_id is stored as zinvite +function getZidFromConversationId(conversation_id: string) { + // (alias) function MPromise(name: string, f: (resolve: (value: unknown) => void, reject: (reason?: any) => void) => void): Promise + // import MPromise + // 'new' expression, whose target lacks a construct signature, implicitly has an 'any' type.ts(7009) + // @ts-ignore + return new MPromise( + "getZidFromConversationId", + function (resolve: (arg0: any) => void, reject: (arg0: string) => any) { + let cachedZid = conversationIdToZidCache.get(conversation_id); + if (cachedZid) { + resolve(cachedZid); + return; + } + pg.query_readOnly( + "select zid from zinvites where zinvite = ($1);", + [conversation_id], + function (err: any, results: { rows: string | any[] }) { + if (err) { + return reject(err); + } else if (!results || !results.rows || !results.rows.length) { + console.error( + "polis_err_fetching_zid_for_conversation_id " + conversation_id + ); + return reject("polis_err_fetching_zid_for_conversation_id"); + } else { + let zid = results.rows[0].zid; + conversationIdToZidCache.set(conversation_id, zid); + return resolve(zid); + } + } + ); + } + ); +} + +export { + createXidRecordByZid, + getXidRecord, + isXidWhitelisted, + getConversationInfo, + getConversationInfoByConversationId, + getZidFromConversationId, +}; + +export default { + createXidRecordByZid, + createXidRecord, + getXidRecord, + isXidWhitelisted, + getConversationInfo, + getConversationInfoByConversationId, + getZidFromConversationId, +}; diff --git a/server/src/d.ts b/server/src/d.ts new file mode 100644 index 000000000..ee5ba1d04 --- /dev/null +++ b/server/src/d.ts @@ -0,0 +1,227 @@ +import { any } from "underscore"; + +export type Headers = { + [key: string]: any; + host?: string; + referrer?: string; + origin?: string; + "x-request-id"?: string; + "user-agent"?: string; + authorization?: string; + "x-polis"?: string; + "accept-language"?: string; + "Accept-Language"?: string; +}; + +export type DetectLanguageResult = { + language: string; + confidence: any; +}; + +export type Body = { + [key: string]: any; + agid?: any; + xid?: any; + uid?: any; +}; + +export type Query = { [x: string]: any }; + +export type AuthBody = { + x_profile_image_url?: any; + x_name?: any; + x_email?: any; + agid?: any; +}; + +export type AuthQuery = { + x_profile_image_url: any; + x_name: any; + x_email: any; + agid: any; +}; + +export type AuthRequest = { + body: AuthBody; + query?: AuthQuery; +}; + +export type ParticipantInfo = { + parent_url?: string; + referrer?: string; +}; + +export type PidReadyResult = { + modOptions?: any; + nextComment?: any; + currentPid?: any; + shouldMod?: any; +}; + +export type CommentOptions = { + currentPid?: any; +}; + +type ModerationState = -1 | 0 | 1; + +type ModerationObject = { isMod: ModerationState | undefined }; + +export type CommentType = { + zid: any; + not_voted_by_pid: any; + include_social?: any; + withoutTids: any; + tid?: any; + translations?: any; + txt?: any; + include_voting_patterns: any; + modIn: boolean; + pid: any; + tids: any; + random: any; + limit: any; + moderation: any; + strict_moderation: any; + mod: ModerationState; + mod_gt: any; +}; + +export type ParticipantFields = { + show_translation_activated?: any; +}; + +export type ParticipantCommentModerationResult = { + nextComment?: any; + currentPid?: any; +}; + +// TODO rename this to User after converting +// TODO User import in server.ts to camelCase +// TODO in standalone change +export type UserType = { + email?: any; + hname?: any; + stripeCustomerId?: any; + uid?: any; + pid?: any; + id?: any; + screen_name?: any; + name?: any; + followers_count?: number; + friends_count?: number; + verified?: any; + profile_image_url_https?: string; + location?: any; + context_id?: any; + user_id?: any; + user_image?: any; + tool_consumer_instance_guid?: any; + lis_person_contact_email_primary?: any; + lis_person_name_full?: any; +}; + +// TODO rename this to Conversation after converting +// TODO User import in server.ts to camelCase +// TODO in standalone change +export type ConversationType = { + is_active?: any; + is_anon?: any; + is_draft?: any; + is_data_open?: any; + profanity_filter?: any; + spam_filter?: any; + strict_moderation?: any; + topic?: any; + description?: any; + vis_type?: any; + help_type?: any; + socialbtn_type?: any; + bgcolor?: any; + help_color?: any; + help_bgcolor?: any; + style_btn?: any; + write_type?: any; + owner_sees_participation_stats?: any; + lti_users_only?: any; + link_url?: any; + course_invite?: any; + course_id?: any; + zid?: any; + uid?: any; + context?: any; + xid?: any; + include_all_conversations_i_am_in?: any; + want_mod_url?: any; + want_upvoted?: any; + want_inbox_item_admin_url?: any; + want_inbox_item_participant_url?: any; + want_inbox_item_admin_html?: any; + want_inbox_item_participant_html?: any; + limit?: any; +}; + +export type TwitterParameters = { + [key: string]: any; + user_id?: any; + screen_name?: any; +}; + +export type ParticipantSocialNetworkInfo = { + [key: string]: any; + facebook?: any; + twitter?: any; +}; + +export type ParticipantOption = { + bidToPid?: any; + asPOJO?: any; + "group-clusters": any; + "base-clusters": any; +}; + +export type DemographicEntry = { + count: number; + gender_male: number; + gender_female: number; + gender_null: number; + birth_year: number; + birth_year_count: number; + ms_birth_year_estimate_fb: number; + ms_birth_year_count: number; + birth_year_guess: number; + birth_year_guess_count: number; +}; + +export type Demo = { + pid?: any; + fb_gender?: any; + ms_gender_estimate_fb?: any; + ms_birth_year_estimate_fb: number; +}; + +export type SlackUser = { + slack_team?: any; + slack_user_id?: any; + zid?: any; + uid?: any; + pid?: any; +}; + +export type Vote = { + uid?: any; + zid: any; + pid: any; + lang: any; + tid: any; + vote: any; + weight: any; + starred: any; + parent_url: any; +}; + +export type Assignment = { + lti_user_id: number; + gradeFromZeroToOne: string; + lis_outcome_service_url: any; + lis_result_sourcedid: any; +}; diff --git a/server/src/db/pg-query.js b/server/src/db/pg-query.js deleted file mode 100644 index dce920d6f..000000000 --- a/server/src/db/pg-query.js +++ /dev/null @@ -1,175 +0,0 @@ -const _ = require("underscore"); -const Config = require("../config"); -const yell = require("../log").yell; -const MPromise = require("../utils/metered").MPromise; - -// # DB Connections -// -// heroku pg standard plan has 120 connections -// plus a dev poller connection and a direct db connection -// 3 devs * (2 + 1 + 1) = 12 for devs -// plus the prod and preprod pollers = 14 -// round up to 20 -// so we can have 25 connections per server, of of which is the preprod server -// so we can have 1 preprod/3 prod servers, or 2 preprod / 2 prod. -// -// Note we use native -const pgnative = require("pg").native; //.native, // native provides ssl (needed for dev laptop to access) http://stackoverflow.com/questions/10279965/authentication-error-when-connecting-to-heroku-postgresql-databa -const parsePgConnectionString = require("pg-connection-string").parse; - -const usingReplica = - process.env.DATABASE_URL !== process.env[process.env.DATABASE_FOR_READS_NAME]; -const poolSize = Config.isDevMode() ? 2 : usingReplica ? 3 : 12; - -// not sure how many of these config options we really need anymore -const pgConnection = Object.assign( - parsePgConnectionString(process.env.DATABASE_URL), - { - max: poolSize, - isReadOnly: false, - poolLog: function (str, level) { - if (pgPoolLevelRanks.indexOf(level) <= pgPoolLoggingLevel) { - console.log("pool.primary." + level + " " + str); - } - }, - } -); -const readsPgConnection = Object.assign( - parsePgConnectionString(process.env[process.env.DATABASE_FOR_READS_NAME]), - { - max: poolSize, - isReadOnly: true, - poolLog: function (str, level) { - if (pgPoolLevelRanks.indexOf(level) <= pgPoolLoggingLevel) { - console.log("pool.replica." + level + " " + str); - } - }, - } -); - -// split requests into centralized read/write transactor pool vs read pool for scalability concerns in keeping -// pressure down on the transactor (read+write) server -const readWritePool = new pgnative.Pool(pgConnection); -const readPool = new pgnative.Pool(readsPgConnection); - -// Same syntax as pg.client.query, but uses connection pool -// Also takes care of calling 'done'. -function queryImpl(pool, queryString, ...args) { - // variable arity depending on whether or not query has params (default to []) - let params, callback; - if (_.isFunction(args[1])) { - params = args[0]; - callback = args[1]; - } else if (_.isFunction(args[0])) { - params = []; - callback = args[0]; - } else { - throw "unexpected db query syntax"; - } - - // Not sure whether we have to be this careful in calling release for these query results. There may or may - // not have been a good reason why Mike did this. If just using pool.query works and doesn't exhibit scale - // under load, might be worth stripping - pool.connect((err, client, release) => { - if (err) { - callback(err); - // force the pool to destroy and remove a client by passing an instance of Error (or anything truthy, actually) to the done() callback - release(err); - yell("pg_connect_pool_fail"); - return; - } - // Anyway, here's the actual query call - client.query(queryString, params, function (err, results) { - if (err) { - // force the pool to destroy and remove a client by passing an instance of Error (or anything truthy, actually) to the release() callback - release(err); - } else { - release(); - } - callback(err, results); - }); - }); -} - -const pgPoolLevelRanks = ["info", "verbose"]; // TODO investigate -const pgPoolLoggingLevel = -1; // -1 to get anything more important than info and verbose. // pgPoolLevelRanks.indexOf("info"); - -// remove queryreadwriteobj -// remove queryreadonlyobj - -function query(...args) { - return queryImpl(readWritePool, ...args); -} - -function query_readOnly(...args) { - return queryImpl(readPool, ...args); -} - -function queryP_impl(config, queryString, params) { - if (!_.isString(queryString)) { - return Promise.reject("query_was_not_string"); - } - let f = config.isReadOnly ? query_readOnly : query; - return new Promise(function (resolve, reject) { - f(queryString, params, function (err, result) { - if (err) { - return reject(err); - } - if (!result || !result.rows) { - // caller is responsible for testing if there are results - return resolve([]); - } - resolve(result.rows); - }); - }); -} - -function queryP(...args) { - return queryP_impl(readWritePool, ...args); -} - -function queryP_readOnly(...args) { - return queryP_impl(readPool, ...args); -} - -function queryP_readOnly_wRetryIfEmpty(...args) { - return queryP_impl(readPool, ...args).then(function (rows) { - if (!rows.length) { - // the replica DB didn't have it (yet?) so try the master. - return queryP(...args); - } - return rows; - }); // NOTE: this does not retry in case of errors. Not sure what's best in that case. -} - -function queryP_metered_impl(isReadOnly, name, queryString, params) { - let f = isReadOnly ? queryP_readOnly : queryP; - if ( - _.isUndefined(name) || - _.isUndefined(queryString) || - _.isUndefined(params) - ) { - throw new Error("polis_err_queryP_metered_impl missing params"); - } - return new MPromise(name, function (resolve, reject) { - f(queryString, params).then(resolve, reject); - }); -} - -function queryP_metered(name, queryString, params) { - return queryP_metered_impl(false, ...arguments); -} - -function queryP_metered_readOnly(name, queryString, params) { - return queryP_metered_impl(true, ...arguments); -} - -module.exports = { - query, - query_readOnly, - queryP, - queryP_metered, - queryP_metered_readOnly, - queryP_readOnly, - queryP_readOnly_wRetryIfEmpty, -}; diff --git a/server/src/db/pg-query.ts b/server/src/db/pg-query.ts new file mode 100644 index 000000000..e45a09808 --- /dev/null +++ b/server/src/db/pg-query.ts @@ -0,0 +1,228 @@ +import { isFunction, isString, isUndefined } from "underscore"; +import { native as pgnative, Pool } from "pg"; //.native, // native provides ssl (needed for dev laptop to access) http://stackoverflow.com/questions/10279965/authentication-error-when-connecting-to-heroku-postgresql-databa +import { parse as parsePgConnectionString } from "pg-connection-string"; + +import { isDevMode } from "../config"; +import { yell } from "../log"; +import { MPromise } from "../utils/metered"; + +// # DB Connections +// +// heroku pg standard plan has 120 connections +// plus a dev poller connection and a direct db connection +// 3 devs * (2 + 1 + 1) = 12 for devs +// plus the prod and preprod pollers = 14 +// round up to 20 +// so we can have 25 connections per server, of of which is the preprod server +// so we can have 1 preprod/3 prod servers, or 2 preprod / 2 prod. +// +// Note we use native +const usingReplica = + process.env.DATABASE_URL !== + process.env[process.env.DATABASE_FOR_READS_NAME as string]; +const poolSize = isDevMode() ? 2 : usingReplica ? 3 : 12; + +// not sure how many of these config options we really need anymore +const pgConnection = Object.assign( + parsePgConnectionString(process.env.DATABASE_URL || ""), + { + max: poolSize, + isReadOnly: false, + poolLog: function (str: string, level: string) { + if (pgPoolLevelRanks.indexOf(level) <= pgPoolLoggingLevel) { + console.log("pool.primary." + level + " " + str); + } + }, + } +); +const readsPgConnection = Object.assign( + parsePgConnectionString( + // (property) NodeJS.Process.env: NodeJS.ProcessEnv + // Type 'undefined' cannot be used as an index type.ts(2538) + // @ts-ignore + process.env[process.env.DATABASE_FOR_READS_NAME] || "" + ), + { + max: poolSize, + isReadOnly: true, + poolLog: function (str: string, level: string) { + if (pgPoolLevelRanks.indexOf(level) <= pgPoolLoggingLevel) { + console.log("pool.replica." + level + " " + str); + } + }, + } +); + +// split requests into centralized read/write transactor pool vs read pool for scalability concerns in keeping +// pressure down on the transactor (read+write) server +// +// (alias) const pgnative: typeof Pg | null +// import pgnative +// Object is possibly 'null'.ts(2531) +// @ts-ignore +const readWritePool = new pgnative.Pool(pgConnection); +// (alias) const pgnative: typeof Pg | null +// import pgnative +// Object is possibly 'null'.ts(2531) +// @ts-ignore +const readPool = new pgnative.Pool(readsPgConnection); + +// Same syntax as pg.client.query, but uses connection pool +// Also takes care of calling 'done'. +function queryImpl(pool: Pool, queryString?: any, ...args: undefined[]) { + // variable arity depending on whether or not query has params (default to []) + let params: never[] | undefined; + let callback: ((arg0: any, arg1?: undefined) => void) | undefined; + if (isFunction(args[1])) { + params = args[0]; + callback = args[1]; + } else if (isFunction(args[0])) { + params = []; + callback = args[0]; + } else { + throw "unexpected db query syntax"; + } + + // Not sure whether we have to be this careful in calling release for these query results. There may or may + // not have been a good reason why Mike did this. If just using pool.query works and doesn't exhibit scale + // under load, might be worth stripping + pool.connect( + ( + err: any, + client: { + query: ( + arg0: any, + arg1: any, + arg2: (err: any, results: any) => void + ) => void; + }, + release: (arg0?: undefined) => void + ) => { + if (err) { + if (callback) callback(err); + // force the pool to destroy and remove a client by passing an instance of Error (or anything truthy, actually) to the done() callback + release(err); + yell("pg_connect_pool_fail"); + return; + } + // Anyway, here's the actual query call + client.query(queryString, params, function (err: any, results: any) { + if (err) { + // force the pool to destroy and remove a client by passing an instance of Error (or anything truthy, actually) to the release() callback + release(err); + } else { + release(); + } + if (callback) callback(err, results); + }); + } + ); +} + +const pgPoolLevelRanks = ["info", "verbose"]; // TODO investigate +const pgPoolLoggingLevel = -1; // -1 to get anything more important than info and verbose. // pgPoolLevelRanks.indexOf("info"); + +// remove queryreadwriteobj +// remove queryreadonlyobj + +function query(...args: any[]) { + return queryImpl(readWritePool, ...args); +} + +function query_readOnly(...args: any[]) { + return queryImpl(readPool, ...args); +} + +function queryP_impl(config: Pool, queryString?: any, params?: undefined) { + if (!isString(queryString)) { + return Promise.reject("query_was_not_string"); + } + // Property 'isReadOnly' does not exist on type 'Pool'.ts(2339) + // @ts-ignore + let f = config.isReadOnly ? query_readOnly : query; + return new Promise(function (resolve, reject) { + f(queryString, params, function (err: any, result: { rows: unknown }) { + if (err) { + return reject(err); + } + if (!result || !result.rows) { + // caller is responsible for testing if there are results + return resolve([]); + } + resolve(result.rows); + }); + }); +} + +function queryP(...args: any[]) { + return queryP_impl(readWritePool, ...args); +} + +function queryP_readOnly(...args: any[]) { + return queryP_impl(readPool, ...args); +} + +function queryP_readOnly_wRetryIfEmpty(...args: any[]) { + return queryP_impl(readPool, ...args).then(function (rows) { + // (parameter) rows: unknown + // Object is of type 'unknown'.ts(2571) + // @ts-ignore + if (!rows.length) { + // the replica DB didn't have it (yet?) so try the master. + return queryP(...args); + } + return rows; + }); // NOTE: this does not retry in case of errors. Not sure what's best in that case. +} + +function queryP_metered_impl( + isReadOnly: boolean, + name?: string, + queryString?: undefined, + params?: undefined +) { + let f = isReadOnly ? queryP_readOnly : queryP; + if (isUndefined(name) || isUndefined(queryString) || isUndefined(params)) { + throw new Error("polis_err_queryP_metered_impl missing params"); + } + // (parameter) resolve: (value: unknown) => void + // 'new' expression, whose target lacks a construct signature, implicitly has an 'any' type.ts(7009) + // @ts-ignore + return new MPromise(name, function (resolve, reject) { + f(queryString, params).then(resolve, reject); + }); +} + +function queryP_metered(name: any, queryString: any, params: any) { + // Type 'IArguments' is not an array type or a string type. + // Use compiler option '--downlevelIteration' to allow iterating of iterators.ts(2569) + // @ts-ignore + return queryP_metered_impl(false, ...arguments); +} + +function queryP_metered_readOnly(name: any, queryString: any, params: any) { + // Type 'IArguments' is not an array type or a string type. + // Use compiler option '--downlevelIteration' to allow iterating of iterators.ts(2569) + // @ts-ignore + return queryP_metered_impl(true, ...arguments); +} + +export { + query, + query_readOnly, + queryP, + queryP_metered, + queryP_metered_readOnly, + queryP_readOnly, + queryP_readOnly_wRetryIfEmpty, +}; + +export default { + query, + query_readOnly, + queryP, + queryP_metered, + queryP_metered_readOnly, + queryP_readOnly, + queryP_readOnly_wRetryIfEmpty, +}; diff --git a/server/src/db/sql.js b/server/src/db/sql.ts similarity index 77% rename from server/src/db/sql.js rename to server/src/db/sql.ts index 8a9afa752..71fff8abe 100644 --- a/server/src/db/sql.js +++ b/server/src/db/sql.ts @@ -1,6 +1,6 @@ -const sql = require("sql"); // see here for useful syntax: https://github.com/brianc/node-sql/blob/bbd6ed15a02d4ab8fbc5058ee2aff1ad67acd5dc/lib/node/valueExpression.js +import sql from "sql"; // see here for useful syntax: https://github.com/brianc/node-sql/blob/bbd6ed15a02d4ab8fbc5058ee2aff1ad67acd5dc/lib/node/valueExpression.js -const sql_conversations = sql.define({ +const sql_conversations: any = sql.define({ name: "conversations", columns: [ "zid", @@ -55,6 +55,8 @@ const sql_conversations = sql.define({ // ], // }); +// 'sql_comments' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.ts(7022) +// @ts-ignore const sql_comments = sql.define({ name: "comments", columns: [ @@ -133,7 +135,19 @@ const sql_reports = sql.define({ ], }); -module.exports = { +export { + sql_conversations, + sql_comments, + sql_votes_latest_unique, + sql_participant_metadata_answers, + sql_participants_extended, + sql_reports, + sql_users, +}; + +// 'default' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.ts(7022) +// @ts-ignore +export default { sql_conversations, sql_comments, sql_votes_latest_unique, diff --git a/server/src/email/senders.js b/server/src/email/senders.ts similarity index 63% rename from server/src/email/senders.js rename to server/src/email/senders.ts index 722d8942e..972d1f421 100644 --- a/server/src/email/senders.js +++ b/server/src/email/senders.ts @@ -1,12 +1,26 @@ -// Copyright (C) 2012-present, The Authors. This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License, version 3, as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -"use strict"; +// Copyright (C) 2012-present, The Authors. This program is free software: you can redistribute +// it and / or modify it under the terms of the GNU Affero General Public License, version 3, +// as published by the Free Software Foundation.This program is distributed in the hope that it +// will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE.See the GNU Affero General Public License for more details. +// You should have received a copy of the GNU Affero General Public License along with this program. +// If not, see < http://www.gnu.org/licenses/>. -const fs = require("fs"); -const nodemailer = require("nodemailer"); -const AWS = require("aws-sdk"); -AWS.config.set("region", process.env.AWS_REGION); +import fs from "fs"; +import AWS from "aws-sdk"; +import nodemailer from "nodemailer"; +import mg from "nodemailer-mailgun-transport"; -function sendTextEmailWithBackup(sender, recipient, subject, text) { +// https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/setting-region.html +// v2 docs, since we use v2 in our package.json: "aws:sdk": "2.78.0" +AWS.config.update({ region: process.env.AWS_REGION }); + +function sendTextEmailWithBackup( + sender: any, + recipient: any, + subject: any, + text: any +) { const transportTypes = process.env.EMAIL_TRANSPORT_TYPES ? process.env.EMAIL_TRANSPORT_TYPES.split(",") : ["aws-ses", "mailgun"]; @@ -22,7 +36,7 @@ function isDocker() { return fs.existsSync("/.dockerenv"); } -function getMailOptions(transportType) { +function getMailOptions(transportType: any) { switch (transportType) { case "maildev": return { @@ -32,7 +46,6 @@ function getMailOptions(transportType) { ignoreTLS: true, }; case "mailgun": - const mg = require("nodemailer-mailgun-transport"); const mailgunAuth = { auth: { // This forces fake credentials if envvars unset, so error is caught @@ -55,10 +68,10 @@ function getMailOptions(transportType) { } function sendTextEmail( - sender, - recipient, - subject, - text, + sender: any, + recipient: any, + subject: any, + text: any, transportTypes = process.env.EMAIL_TRANSPORT_TYPES, priority = 1 ) { @@ -67,16 +80,16 @@ function sendTextEmail( return; } - transportTypes = transportTypes.split(","); + const transportTypesArray = transportTypes.split(","); // Shift first index and clone to rename. - const thisTransportType = transportTypes.shift(); - const nextTransportTypes = [...transportTypes]; + const thisTransportType = transportTypesArray.shift(); + const nextTransportTypes = [...transportTypesArray]; const mailOptions = getMailOptions(thisTransportType); const transporter = nodemailer.createTransport(mailOptions); - let promise = transporter + let promise: any = transporter .sendMail({ from: sender, to: recipient, subject: subject, text: text }) - .catch(function (err) { + .catch(function (err: any) { console.error( "polis_err_email_sender_failed_transport_priority_" + priority.toString() @@ -97,7 +110,12 @@ function sendTextEmail( return promise; } -module.exports = { +export { + sendTextEmail, + sendTextEmailWithBackup as sendTextEmailWithBackupOnly, +}; + +export default { sendTextEmail: sendTextEmail, sendTextEmailWithBackupOnly: sendTextEmailWithBackup, }; diff --git a/server/src/log.js b/server/src/log.ts similarity index 68% rename from server/src/log.js rename to server/src/log.ts index 91bb9d576..03fb56032 100644 --- a/server/src/log.js +++ b/server/src/log.ts @@ -1,5 +1,6 @@ -const Config = require("./config"); -const _ = require("underscore"); +import _ from "underscore"; + +import Config from "./config"; const errorNotifications = (function () { let errors = []; @@ -20,7 +21,7 @@ const errorNotifications = (function () { } setInterval(sendAll, 60 * 1000); return { - add: function (token) { + add: function (token: any) { if (Config.isDevMode() && !_.isString(token)) { throw new Error("empty token for pushover"); } @@ -32,12 +33,22 @@ const errorNotifications = (function () { const yell = errorNotifications.add; -function fail(res, httpCode, clientVisibleErrorString, err) { +function fail( + res: any, + httpCode: any, + clientVisibleErrorString: any, + err?: any +) { emitTheFailure(res, httpCode, "polis_err", clientVisibleErrorString, err); yell(clientVisibleErrorString); } -function userFail(res, httpCode, clientVisibleErrorString, err) { +function userFail( + res: any, + httpCode: any, + clientVisibleErrorString: any, + err?: any +) { emitTheFailure( res, httpCode, @@ -48,11 +59,11 @@ function userFail(res, httpCode, clientVisibleErrorString, err) { } function emitTheFailure( - res, - httpCode, - extraErrorCodeForLogs, - clientVisibleErrorString, - err + res: { writeHead: (arg0: any) => void; end: (arg0: any) => void }, + httpCode: any, + extraErrorCodeForLogs: string, + clientVisibleErrorString: any, + err: { stack: any } ) { console.error(clientVisibleErrorString, extraErrorCodeForLogs, err); if (err && err.stack) { @@ -62,8 +73,5 @@ function emitTheFailure( res.end(clientVisibleErrorString); } -module.exports = { - yell, - fail, - userFail, -}; +export { yell, fail, userFail }; +export default { yell, fail, userFail }; diff --git a/server/src/server.js b/server/src/server.ts similarity index 60% rename from server/src/server.js rename to server/src/server.ts index 575e067f0..859baaff3 100644 --- a/server/src/server.js +++ b/server/src/server.ts @@ -2,111 +2,143 @@ "use strict"; -const Config = require("./config"); - -const akismetLib = require("akismet"); -const AWS = require("aws-sdk"); -AWS.config.set("region", process.env.AWS_REGION); -const badwords = require("badwords/object"); -const Promise = require("bluebird"); -const http = require("http"); -const httpProxy = require("http-proxy"); +import akismetLib from "akismet"; +import AWS from "aws-sdk"; +import badwords from "badwords/object"; +import Promise from "bluebird"; +import http from "http"; +import httpProxy from "http-proxy"; // const Promise = require('es6-promise').Promise, -const escapeLiteral = require("pg").Client.prototype.escapeLiteral; -const async = require("async"); -const FB = require("fb"); -const fs = require("fs"); -const bcrypt = require("bcrypt"); -const crypto = require("crypto"); +import async from "async"; +// npm list types-at-fb +// @ts-ignore +import FB from "fb"; +import fs from "fs"; +import bcrypt from "bcrypt"; +import crypto from "crypto"; // May not need this anymore; looks like we're just using the other Intercom api, but need to figure out // what's going on here //const Intercom = require('intercom.io'); // https://github.com/tarunc/intercom.io -const IntercomOfficial = require("intercom-client"); -const isTrue = require("boolean"); -const OAuth = require("oauth"); +import * as IntercomOfficial from "intercom-client"; +import isTrue from "boolean"; +import OAuth from "oauth"; // const Pushover = require('pushover-notifications'); // const pushoverInstance = new Pushover({ // user: process.env.PUSHOVER_GROUP_POLIS_DEV, // token: process.env.PUSHOVER_POLIS_PROXY_API_KEY, // }); // const postmark = require("postmark")(process.env.POSTMARK_API_KEY); -const querystring = require("querystring"); +import querystring from "querystring"; +import replaceStream from "replacestream"; +import responseTime from "response-time"; +import request from "request-promise"; // includes Request, but adds promise methods +import LruCache from "lru-cache"; +import timeout from "connect-timeout"; +import zlib from "zlib"; +import _ from "underscore"; +import { WebClient } from "@slack/client"; +import pg from "pg"; + +import { METRICS_IN_RAM, addInRamMetric, MPromise } from "./utils/metered"; +import CreateUser from "./auth/create-user"; +import Password from "./auth/password"; +import dbPgQuery from "./db/pg-query"; + +import Config from "./config"; +// Re-import disassembled code to promise existing code will work +import Log from "./log"; + +import { + Body, + DetectLanguageResult, + Headers, + Query, + AuthRequest, + AuthBody, + AuthQuery, + ParticipantInfo, + PidReadyResult, + CommentOptions, + ParticipantFields, + ParticipantCommentModerationResult, + UserType, + ConversationType, + CommentType, + TwitterParameters, + ParticipantSocialNetworkInfo, + ParticipantOption, + DemographicEntry, + Demo, + SlackUser, + Vote, + Assignment, +} from "./d"; + +AWS.config.update({ region: process.env.AWS_REGION }); const devMode = isTrue(process.env.DEV_MODE); -const replaceStream = require("replacestream"); -const responseTime = require("response-time"); -const request = require("request-promise"); // includes Request, but adds promise methods const s3Client = new AWS.S3({ apiVersion: "2006-03-01" }); const stripe = require("stripe")(process.env.STRIPE_SECRET_KEY); -const LruCache = require("lru-cache"); -const timeout = require("connect-timeout"); -const zlib = require("zlib"); -const _ = require("underscore"); - -// Re-import disassembled code to promise existing code will work -const Log = require("./log"); - -const addInRamMetric = require("./utils/metered").addInRamMetric; -const MPromise = require("./utils/metered").MPromise; const yell = Log.yell; - -const pg = require("./db/pg-query"); -const pgQuery = pg.query; -const pgQuery_readOnly = pg.query_readOnly; -const pgQueryP = pg.queryP; -const pgQueryP_metered = pg.queryP_metered; -const pgQueryP_metered_readOnly = pg.queryP_metered_readOnly; -const pgQueryP_readOnly = pg.queryP_readOnly; -const pgQueryP_readOnly_wRetryIfEmpty = pg.queryP_readOnly_wRetryIfEmpty; - -const CreateUser = require("./auth/create-user"); -const Password = require("./auth/password"); +// Property 'Client' does not exist on type '{ query: (...args: any[]) => void; query_readOnly: +// (...args: any[]) => void; queryP: (...args: any[]) => Promise; queryP_metered: +// (name: any, queryString: any, params: any) => any; queryP_metered_readOnly: +// (name: any, queryString: any, params: any) => any; queryP_readOnly: +// (...args: any[]) => Promise <...>; ...'.ts(2339) +// @ts-ignore +const escapeLiteral = pg.Client.prototype.escapeLiteral; +const pgQuery = dbPgQuery.query; +const pgQuery_readOnly = dbPgQuery.query_readOnly; +const pgQueryP = dbPgQuery.queryP; +const pgQueryP_metered = dbPgQuery.queryP_metered; +const pgQueryP_metered_readOnly = dbPgQuery.queryP_metered_readOnly; +const pgQueryP_readOnly = dbPgQuery.queryP_readOnly; +const pgQueryP_readOnly_wRetryIfEmpty = dbPgQuery.queryP_readOnly_wRetryIfEmpty; const doSendVerification = CreateUser.doSendVerification; const generateAndRegisterZinvite = CreateUser.generateAndRegisterZinvite; const generateToken = Password.generateToken; const generateTokenP = Password.generateTokenP; // TODO: Maybe able to remove -const generateHashedPassword = require("./auth/password") - .generateHashedPassword; -const checkPassword = require("./auth/password").checkPassword; - -const cookies = require("./utils/cookies"); +import { checkPassword, generateHashedPassword } from "./auth/password"; +import cookies from "./utils/cookies"; const COOKIES = cookies.COOKIES; const COOKIES_TO_CLEAR = cookies.COOKIES_TO_CLEAR; -const constants = require("./utils/constants"); +import constants from "./utils/constants"; const DEFAULTS = constants.DEFAULTS; -const User = require("./user"); -const Conversation = require("./conversation"); -const Session = require("./session"); -const Comment = require("./comment"); -const Utils = require("./utils/common"); -const SQL = require("./db/sql"); +import User from "./user"; +import Conversation from "./conversation"; +import Session from "./session"; +import Comment from "./comment"; +import Utils from "./utils/common"; +import SQL from "./db/sql"; // End of re-import // # Slack setup - -var WebClient = require("@slack/client").WebClient; var web = new WebClient(process.env.SLACK_API_TOKEN); // const winston = require("winston"); // # notifications const winston = console; -const emailSenders = require("./email/senders"); +import emailSenders from "./email/senders"; const sendTextEmail = emailSenders.sendTextEmail; const sendTextEmailWithBackupOnly = emailSenders.sendTextEmailWithBackupOnly; -const resolveWith = (x) => { +const resolveWith = (x: { body?: { user_id: string } }) => { return Promise.resolve(x); }; -const intercomClient = !isTrue(process.env.DISABLE_INTERCOM) - ? new IntercomOfficial.Client({ token: process.env.INTERCOM_ACCESS_TOKEN }) - : { - leads: { - create: resolveWith({ body: { user_id: "null_intercom_user_id" } }), - update: resolveWith({}), - }, - }; + +const intercomClient = + !isTrue(process.env.DISABLE_INTERCOM) && process.env.INTERCOM_ACCESS_TOKEN + ? new IntercomOfficial.Client({ + token: process.env.INTERCOM_ACCESS_TOKEN, + }) + : { + leads: { + create: resolveWith({ body: { user_id: "null_intercom_user_id" } }), + update: resolveWith({}), + }, + }; //var SegfaultHandler = require('segfault-handler'); @@ -129,7 +161,7 @@ if (devMode) { } // Bluebird uncaught error handler. -Promise.onPossiblyUnhandledRejection(function (err) { +Promise.onPossiblyUnhandledRejection(function (err: { stack: any }) { console.log("onPossiblyUnhandledRejection"); if (_.isObject(err)) { // since it may just throw as [object Object] @@ -164,7 +196,7 @@ const admin_emails = process.env.ADMIN_EMAILS const polisDevs = process.env.ADMIN_UIDS ? JSON.parse(process.env.ADMIN_UIDS) : []; -function isPolisDev(uid) { +function isPolisDev(uid?: any) { console.log("polisDevs", polisDevs); return polisDevs.indexOf(uid) >= 0; } @@ -215,7 +247,7 @@ const akismet = akismetLib.client({ apiKey: process.env.AKISMET_ANTISPAM_API_KEY, }); -akismet.verifyKey(function (err, verified) { +akismet.verifyKey(function (err: any, verified: any) { if (verified) { winston.log("info", "Akismet: API key successfully verified."); } else { @@ -228,19 +260,44 @@ akismet.verifyKey(function (err, verified) { // SELF_HOSTNAME = process.env.SERVICE_HOSTNAME //} -function isSpam(o) { - return new MPromise("isSpam", function (resolve, reject) { - akismet.checkSpam(o, function (err, spam) { - if (err) { - reject(err); - } else { - resolve(spam); - } - }); - }); +function isSpam(o: { + comment_content: any; + comment_author: any; + permalink: string; + user_ip: any; + user_agent: any; + referrer: any; +}) { + // 'new' expression, whose target lacks a construct signature, implicitly has an 'any' type.ts(7009) + // @ts-ignore + return new MPromise( + "isSpam", + function (resolve: (arg0: any) => void, reject: (arg0: any) => void) { + akismet.checkSpam(o, function (err: any, spam: any) { + if (err) { + reject(err); + } else { + resolve(spam); + } + }); + } + ); } -var INFO; +var INFO: { + ( + arg0: string, + arg1: string | undefined, + arg2: undefined, + arg3: string | undefined, + arg4: undefined, + arg5: string | undefined, + arg6: undefined + ): void; + (...data: any[]): void; + (message?: any, ...optionalParams: any[]): void; + (): void; +}; if (devMode) { INFO = console.log; @@ -252,16 +309,16 @@ if (devMode) { } // basic defaultdict implementation -function DD(f) { +function DD(this: any, f: () => { votes: number; comments: number }) { this.m = {}; this.f = f; } // basic defaultarray implementation -function DA(f) { +function DA(this: any, f: any) { this.m = []; this.f = f; } -DD.prototype.g = DA.prototype.g = function (k) { +DD.prototype.g = DA.prototype.g = function (k: string | number) { if (this.m.hasOwnProperty(k)) { return this.m[k]; } @@ -269,7 +326,7 @@ DD.prototype.g = DA.prototype.g = function (k) { this.m[k] = v; return v; }; -DD.prototype.s = DA.prototype.s = function (k, v) { +DD.prototype.s = DA.prototype.s = function (k: string | number, v: any) { this.m[k] = v; }; // function emptyArray() { @@ -278,7 +335,7 @@ DD.prototype.s = DA.prototype.s = function (k, v) { const domainOverride = Config.domainOverride; -function haltOnTimeout(req, res, next) { +function haltOnTimeout(req: { timedout: any }, res: any, next: () => void) { if (req.timedout) { fail(res, 500, "polis_err_timeout_misc"); } else { @@ -286,7 +343,11 @@ function haltOnTimeout(req, res, next) { } } -function ifDefinedSet(name, source, dest) { +function ifDefinedSet( + name: string, + source: { [x: string]: any }, + dest: { [x: string]: any } +) { if (!_.isUndefined(source[name])) { dest[name] = source[name]; } @@ -351,18 +412,25 @@ const setupPwReset = Session.setupPwReset; const getUidForPwResetToken = Session.getUidForPwResetToken; const clearPwResetToken = Session.clearPwResetToken; -function hasAuthToken(req) { +function hasAuthToken(req: { cookies: { [x: string]: any } }) { return !!req.cookies[COOKIES.TOKEN]; } -function getUidForApiKey(apikey) { +function getUidForApiKey(apikey: any) { return pgQueryP_readOnly_wRetryIfEmpty( "select uid from apikeysndvweifu WHERE apikey = ($1);", [apikey] ); } // http://en.wikipedia.org/wiki/Basic_access_authentication#Client_side -function doApiKeyBasicAuth(assigner, header, isOptional, req, res, next) { +function doApiKeyBasicAuth( + assigner: any, + header: string, + isOptional: any, + req: any, + res: any, + next: (err: any) => void +) { let token = header.split(/\s+/).pop() || "", // and the encoded auth token auth = new Buffer(token, "base64").toString(), // convert from base64 parts = auth.split(/:/), // split on colon @@ -372,9 +440,21 @@ function doApiKeyBasicAuth(assigner, header, isOptional, req, res, next) { return doApiKeyAuth(assigner, apikey, isOptional, req, res, next); } -function doApiKeyAuth(assigner, apikey, isOptional, req, res, next) { +function doApiKeyAuth( + assigner: (arg0: any, arg1: string, arg2: number) => void, + apikey: string, + isOptional: any, + req: any, + res: { status: (arg0: number) => void }, + next: { (err: any): void; (err: any): void; (arg0?: string): void } +) { getUidForApiKey(apikey) - .then(function (rows) { + // Argument of type '(rows: string | any[]) => void' is not assignable to parameter of type '(value: unknown) => void | PromiseLike'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + .then(function (rows: string | any[]) { if (!rows || !rows.length) { res.status(403); next("polis_err_auth_no_such_api_token"); @@ -383,7 +463,7 @@ function doApiKeyAuth(assigner, apikey, isOptional, req, res, next) { assigner(req, "uid", Number(rows[0].uid)); next(); }) - .catch(function (err) { + .catch(function (err: { stack: any }) { res.status(403); console.error(err.stack); next("polis_err_auth_no_such_api_token2"); @@ -413,10 +493,27 @@ const getXidRecordByXidOwnerId = User.getXidRecordByXidOwnerId; // }); // } -function doXidApiKeyAuth(assigner, apikey, xid, isOptional, req, res, next) { +function doXidApiKeyAuth( + assigner: (arg0: any, arg1: string, arg2: number) => void, + apikey: any, + xid: any, + isOptional: any, + req: AuthRequest, + res: { status: (arg0: number) => void }, + next: { + (err: any): void; + (err: any): void; + (arg0?: string | undefined): void; + } +) { getUidForApiKey(apikey) .then( - function (rows) { + // Argument of type '(rows: string | any[]) => Promise | undefined' is not assignable to parameter of type '(value: unknown) => void | PromiseLike | undefined'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + function (rows: string | any[]) { if (!rows || !rows.length) { res.status(403); next("polis_err_auth_no_such_api_token4"); @@ -427,11 +524,16 @@ function doXidApiKeyAuth(assigner, apikey, xid, isOptional, req, res, next) { xid, uidForApiKey, void 0, //zid_optional, - req.body.x_profile_image_url || req.query.x_profile_image_url, - req.body.x_name || req.query.x_name || null, - req.body.x_email || req.query.x_email || null, - !!req.body.agid || !!req.query.agid || null - ).then((rows) => { + req.body.x_profile_image_url || req?.query?.x_profile_image_url, + req.body.x_name || req?.query?.x_name || null, + req.body.x_email || req?.query?.x_email || null, + !!req.body.agid || !!req?.query?.agid || null + // Argument of type '(rows: string | any[]) => void' is not assignable to parameter of type '(value: unknown) => void | PromiseLike'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + ).then((rows: string | any[]) => { if (!rows || !rows.length) { if (isOptional) { return next(); @@ -449,24 +551,31 @@ function doXidApiKeyAuth(assigner, apikey, xid, isOptional, req, res, next) { next(); }); }, - function (err) { + function (err: { stack: any }) { res.status(403); console.error(err.stack); next("polis_err_auth_no_such_api_token3"); } ) - .catch(function (err) { + .catch(function (err: { stack: any }) { res.status(403); console.error(err); console.error(err.stack); next("polis_err_auth_misc_23423"); }); } -function doHeaderAuth(assigner, isOptional, req, res, next) { - let token = req.headers["x-polis"]; +function doHeaderAuth( + assigner: (arg0: any, arg1: string, arg2: number) => void, + isOptional: any, + req: { headers?: { [x: string]: any }; body: { uid?: any } }, + res: { status: (arg0: number) => void }, + next: { (err: any): void; (arg0?: string | undefined): void } +) { + let token = ""; + if (req && req.headers) token = req?.headers?.["x-polis"]; //if (req.body.uid) { next(401); return; } // shouldn't be in the post - TODO - see if we can do the auth in parallel for non-destructive operations - getUserInfoForSessionToken(token, res, function (err, uid) { + getUserInfoForSessionToken(token, res, function (err: any, uid?: any) { if (err) { res.status(403); next("polis_err_auth_no_such_token"); @@ -482,15 +591,21 @@ function doHeaderAuth(assigner, isOptional, req, res, next) { }); } -function doPolisLtiTokenHeaderAuth(assigner, isOptional, req, res, next) { - let token = req.headers["x-polis"]; +function doPolisLtiTokenHeaderAuth( + assigner: (arg0: any, arg1: string, arg2: number) => void, + isOptional: any, + req: { headers?: { [x: string]: any } }, + res: { status: (arg0: number) => void }, + next: { (err: any): void; (arg0?: string): void } +) { + let token = req?.headers?.["x-polis"]; getUserInfoForPolisLtiToken(token) - .then(function (uid) { + .then(function (uid?: any) { assigner(req, "uid", Number(uid)); next(); }) - .catch(function (err) { + .catch(function (err: any) { res.status(403); next("polis_err_auth_no_such_token"); return; @@ -498,20 +613,20 @@ function doPolisLtiTokenHeaderAuth(assigner, isOptional, req, res, next) { } function doPolisSlackTeamUserTokenHeaderAuth( - assigner, - isOptional, - req, - res, - next + assigner: (arg0: any, arg1: string, arg2: number) => void, + isOptional: any, + req: { headers?: { [x: string]: any } }, + res: { status: (arg0: number) => void }, + next: { (err: any): void; (arg0?: string): void } ) { - let token = req.headers["x-polis"]; + let token = req?.headers?.["x-polis"]; getUserInfoForPolisLtiToken(token) - .then(function (uid) { + .then(function (uid?: any) { assigner(req, "uid", Number(uid)); next(); }) - .catch(function (err) { + .catch(function (err: any) { res.status(403); next("polis_err_auth_no_such_token"); return; @@ -521,6 +636,8 @@ function doPolisSlackTeamUserTokenHeaderAuth( // winston.log("info",req.method + " " + req.url); // next(); // } +// Property 'hashCode' does not exist on type 'String'.ts(2339) +// @ts-ignore String.prototype.hashCode = function () { let hash = 0; let i; @@ -597,7 +714,7 @@ function initializePolisHelpers() { const getPidPromise = User.getPidPromise; const getPidForParticipant = User.getPidForParticipant; - function recordPermanentCookieZidJoin(permanentCookieToken, zid) { + function recordPermanentCookieZidJoin(permanentCookieToken: any, zid: any) { function doInsert() { return pgQueryP( "insert into permanentCookieZidJoins (cookie, zid) values ($1, $2);", @@ -608,14 +725,19 @@ function initializePolisHelpers() { "select zid from permanentCookieZidJoins where cookie = ($1) and zid = ($2);", [permanentCookieToken, zid] ).then( - function (rows) { + // Argument of type '(rows: string | any[]) => Promise | undefined' is not assignable to parameter of type '(value: unknown) => unknown'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + function (rows: string | any[]) { if (rows && rows.length) { // already there } else { return doInsert(); } }, - function (err) { + function (err: any) { console.error(err); // hmm, weird, try inserting anyway return doInsert(); @@ -627,18 +749,23 @@ function initializePolisHelpers() { if (isTrue(process.env.BACKFILL_COMMENT_LANG_DETECTION)) { pgQueryP("select tid, txt, zid from comments where lang is null;", []).then( - (comments) => { + // Argument of type '(comments: string | any[]) => void' is not assignable to parameter of type '(value: unknown) => void | PromiseLike'. + // Types of parameters 'comments' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + (comments: string | any[]) => { let i = 0; function doNext() { if (i < comments.length) { let c = comments[i]; i += 1; - detectLanguage(c.txt).then((x) => { - x = x[0]; - console.log("backfill", x.language + "\t\t" + c.txt); + detectLanguage(c.txt).then((x: DetectLanguageResult[]) => { + const firstResult = x[0]; + console.log("backfill", firstResult.language + "\t\t" + c.txt); pgQueryP( "update comments set lang = ($1), lang_confidence = ($2) where zid = ($3) and tid = ($4)", - [x.language, x.confidence, c.zid, c.tid] + [firstResult.language, firstResult.confidence, c.zid, c.tid] ).then(() => { doNext(); }); @@ -650,15 +777,26 @@ function initializePolisHelpers() { ); } - function doVotesPost(uid, pid, conv, tid, voteType, weight, shouldNotify) { - let zid = conv.zid; + function doVotesPost( + uid?: any, + pid?: any, + conv?: { zid: any; is_slack: any }, + tid?: any, + voteType?: any, + weight?: number, + shouldNotify?: any + ) { + let zid = conv?.zid; weight = weight || 0; let weight_x_32767 = Math.trunc(weight * 32767); // weight is stored as a SMALLINT, so convert from a [-1,1] float to [-32767,32767] int - return new Promise(function (resolve, reject) { + return new Promise(function ( + resolve: (arg0: { conv: any; vote: any }) => void, + reject: (arg0: string) => void + ) { let query = "INSERT INTO votes (pid, zid, tid, vote, weight_x_32767, created) VALUES ($1, $2, $3, $4, $5, default) RETURNING *;"; let params = [pid, zid, tid, voteType, weight_x_32767]; - pgQuery(query, params, function (err, result) { + pgQuery(query, params, function (err: any, result: { rows: any[] }) { if (err) { if (isDuplicateKey(err)) { reject("polis_err_vote_duplicate"); @@ -691,76 +829,119 @@ function initializePolisHelpers() { }); } - function votesPost(uid, pid, zid, tid, voteType, weight, shouldNotify) { - return pgQueryP_readOnly("select * from conversations where zid = ($1);", [ - zid, - ]) - .then(function (rows) { - if (!rows || !rows.length) { - throw "polis_err_unknown_conversation"; - } - let conv = rows[0]; - if (!conv.is_active) { - throw "polis_err_conversation_is_closed"; - } - if (conv.auth_needed_to_vote) { - return isModerator(zid, uid).then((is_mod) => { - if (is_mod) { - return conv; - } - return Promise.all([ - pgQueryP( - "select * from xids where owner = ($1) and uid = ($2);", - [conv.owner, uid] - ), - getSocialInfoForUsers([uid], zid), - ]).then(([xids, info]) => { - var socialAccountIsLinked = info.length > 0; - var hasXid = xids.length > 0; - if (socialAccountIsLinked || hasXid) { + function votesPost( + uid?: any, + pid?: any, + zid?: any, + tid?: any, + voteType?: any, + weight?: number, + shouldNotify?: boolean + ) { + return ( + pgQueryP_readOnly("select * from conversations where zid = ($1);", [zid]) + // Argument of type '(rows: string | any[]) => any' is not assignable to parameter of type '(value: unknown) => any'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + .then(function (rows: string | any[]) { + if (!rows || !rows.length) { + throw "polis_err_unknown_conversation"; + } + let conv = rows[0]; + if (!conv.is_active) { + throw "polis_err_conversation_is_closed"; + } + if (conv.auth_needed_to_vote) { + return isModerator(zid, uid).then((is_mod: any) => { + if (is_mod) { return conv; - } else { - throw "polis_err_post_votes_social_needed"; } + return Promise.all([ + pgQueryP( + "select * from xids where owner = ($1) and uid = ($2);", + [conv.owner, uid] + ), + getSocialInfoForUsers([uid], zid), + // Binding elements 'xids' and 'info' implicitly have an 'any' type.ts(7031) + // @ts-ignore + ]).then(([xids, info]) => { + var socialAccountIsLinked = info.length > 0; + // Object is of type 'unknown'.ts(2571) + // @ts-ignore + var hasXid = xids.length > 0; + if (socialAccountIsLinked || hasXid) { + return conv; + } else { + throw "polis_err_post_votes_social_needed"; + } + }); }); - }); - } - return conv; - }) - .then(function (conv) { - return doVotesPost(uid, pid, conv, tid, voteType, weight, shouldNotify); - }); + } + return conv; + }) + .then(function (conv: any) { + return doVotesPost( + uid, + pid, + conv, + tid, + voteType, + weight, + shouldNotify + ); + }) + ); } - function getVotesForSingleParticipant(p) { + function getVotesForSingleParticipant(p: { pid: any }) { if (_.isUndefined(p.pid)) { return Promise.resolve([]); } return votesGet(p); } - function votesGet(p) { - return new MPromise("votesGet", function (resolve, reject) { - let q = sql_votes_latest_unique - .select(sql_votes_latest_unique.star()) - .where(sql_votes_latest_unique.zid.equals(p.zid)); - - if (!_.isUndefined(p.pid)) { - q = q.where(sql_votes_latest_unique.pid.equals(p.pid)); - } - if (!_.isUndefined(p.tid)) { - q = q.where(sql_votes_latest_unique.tid.equals(p.tid)); - } - pgQuery_readOnly(q.toString(), function (err, results) { - if (err) { - reject(err); - } else { - resolve(results.rows); + function votesGet(p: { zid?: any; pid?: any; tid?: any }) { + // 'new' expression, whose target lacks a construct signature, implicitly has an 'any' type.ts(7009) + // @ts-ignore + return new MPromise( + "votesGet", + function (resolve: (arg0: any) => void, reject: (arg0: any) => void) { + let q = sql_votes_latest_unique + .select(sql_votes_latest_unique.star()) + .where(sql_votes_latest_unique.zid.equals(p.zid)); + + if (!_.isUndefined(p.pid)) { + q = q.where(sql_votes_latest_unique.pid.equals(p.pid)); } - }); - }); + if (!_.isUndefined(p.tid)) { + q = q.where(sql_votes_latest_unique.tid.equals(p.tid)); + } + pgQuery_readOnly( + q.toString(), + function (err: any, results: { rows: any }) { + if (err) { + reject(err); + } else { + resolve(results.rows); + } + } + ); + } + ); } // End votesGet - function writeDefaultHead(req, res, next) { + function writeDefaultHead( + req: any, + res: { + set: (arg0: { + "Content-Type": string; + "Cache-Control": string; + Connection: string; + }) => void; + }, + next: () => void + ) { res.set({ "Content-Type": "application/json", "Cache-Control": "no-cache", @@ -771,32 +952,46 @@ function initializePolisHelpers() { next(); } - function redirectIfNotHttps(req, res, next) { + function redirectIfNotHttps( + req: { headers?: { [x: string]: string; host: string }; url: string }, + res: { + writeHead: (arg0: number, arg1: { Location: string }) => void; + end: () => any; + }, + next: () => any + ) { let exempt = devMode; // IE is picky, so use HTTP. // TODO figure out IE situation, (proxy static files in worst-case) - // exempt = exempt || /MSIE/.test(req.headers['user-agent']); // TODO test IE11 + // exempt = exempt || /MSIE/.test(req?.headers?.['user-agent']); // TODO test IE11 if (exempt) { return next(); } - if (!/https/.test(req.headers["x-forwarded-proto"])) { + if (!/https/.test(req?.headers?.["x-forwarded-proto"] || "")) { // assuming we're running on Heroku, where we're behind a proxy. res.writeHead(302, { - Location: "https://" + req.headers.host + req.url, + Location: "https://" + req?.headers?.host + req.url, }); return res.end(); } return next(); } - function redirectIfWrongDomain(req, res, next) { + function redirectIfWrongDomain( + req: { headers?: { host: string }; url: string }, + res: { + writeHead: (arg0: number, arg1: { Location: string }) => void; + end: () => any; + }, + next: () => any + ) { // let reServiceHostname = new RegExp(process.env.SERVICE_HOSTNAME); if ( - // reServiceHostname.test(req.headers.host) || // needed for heroku integrations (like slack?) - /www.pol.is/.test(req.headers.host) + // reServiceHostname.test(req?.headers?.host) || // needed for heroku integrations (like slack?) + /www.pol.is/.test(req?.headers?.host || "") ) { res.writeHead(302, { Location: "https://pol.is" + req.url, @@ -806,8 +1001,15 @@ function initializePolisHelpers() { return next(); } - function redirectIfApiDomain(req, res, next) { - if (/api.pol.is/.test(req.headers.host)) { + function redirectIfApiDomain( + req: { headers?: { host: string }; url: string }, + res: { + writeHead: (arg0: number, arg1: { Location: string }) => void; + end: () => any; + }, + next: () => any + ) { + if (/api.pol.is/.test(req?.headers?.host || "")) { if (req.url === "/" || req.url === "") { res.writeHead(302, { Location: "https://pol.is/docs/api", @@ -849,25 +1051,30 @@ function initializePolisHelpers() { // } function doXidConversationIdAuth( - assigner, - xid, - conversation_id, - isOptional, - req, - res, - onDone + assigner: (arg0: any, arg1: string, arg2: number) => void, + xid: any, + conversation_id: any, + isOptional: any, + req: AuthRequest, + res: { status: (arg0: number) => void }, + onDone: { (err: any): void; (arg0?: string): void } ) { return getConversationInfoByConversationId(conversation_id) - .then((conv) => { + .then((conv: { org_id: any; zid: any }) => { return getXidRecordByXidOwnerId( xid, conv.org_id, conv.zid, - req.body.x_profile_image_url || req.query.x_profile_image_url, - req.body.x_name || req.query.x_name || null, - req.body.x_email || req.query.x_email || null, - !!req.body.agid || !!req.query.agid || null - ).then((rows) => { + req.body.x_profile_image_url || req?.query?.x_profile_image_url, + req.body.x_name || req?.query?.x_name || null, + req.body.x_email || req?.query?.x_email || null, + !!req.body.agid || !!req?.query?.agid || null + // Argument of type '(rows: string | any[]) => void' is not assignable to parameter of type '(value: unknown) => void | PromiseLike'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + ).then((rows: string | any[]) => { if (!rows || !rows.length) { if (isOptional) { return onDone(); @@ -882,23 +1089,41 @@ function initializePolisHelpers() { onDone(); }); }) - .catch((err) => { + .catch((err: any) => { console.log(err); onDone(err); }); } - function _auth(assigner, isOptional) { - function getKey(req, key) { - return req.body[key] || req.headers[key] || req.query[key]; + function _auth(assigner: any, isOptional: boolean) { + function getKey( + req: { + body: Body; + headers?: Headers; + query?: Query; + }, + key: string + ) { + return req.body[key] || req?.headers?.[key] || req?.query?.[key]; } - function doAuth(req, res) { + function doAuth( + req: { + cookies: { [x: string]: any }; + headers?: { [x: string]: any; authorization: any }; + p: { uid?: any }; + body: Body; + }, + res: { status: (arg0: number) => void } + ) { //var token = req.body.token; let token = req.cookies[COOKIES.TOKEN]; - let xPolisToken = req.headers["x-polis"]; + let xPolisToken = req?.headers?.["x-polis"]; - return new Promise(function (resolve, reject) { - function onDone(err) { + return new Promise(function ( + resolve: (arg0: any) => void, + reject: (arg0: string) => void + ) { + function onDone(err?: string) { if (err) { reject(err); } @@ -944,12 +1169,12 @@ function initializePolisHelpers() { res, onDone ); - // } else if (req.headers["x-sandstorm-app-polis-apikey"] && req.headers["x-sandstorm-app-polis-xid"] && req.headers["x-sandstorm-app-polis-owner-xid"]) { + // } else if (req?.headers?.["x-sandstorm-app-polis-apikey"] && req?.headers?.["x-sandstorm-app-polis-xid"] && req?.headers?.["x-sandstorm-app-polis-owner-xid"]) { // doXidApiKeyAuth( // assigner, - // req.headers["x-sandstorm-app-polis-apikey"], - // req.headers["x-sandstorm-app-polis-owner-xid"], - // req.headers["x-sandstorm-app-polis-xid"], + // req?.headers?.["x-sandstorm-app-polis-apikey"], + // req?.headers?.["x-sandstorm-app-polis-owner-xid"], + // req?.headers?.["x-sandstorm-app-polis-xid"], // isOptional, req, res, onDone); } else if (getKey(req, "xid") && getKey(req, "conversation_id")) { console.log("authtype", "doXidConversationIdAuth"); @@ -962,11 +1187,11 @@ function initializePolisHelpers() { res, onDone ); - } else if (req.headers["x-sandstorm-app-polis-apikey"]) { + } else if (req?.headers?.["x-sandstorm-app-polis-apikey"]) { console.log("authtype", "doApiKeyAuth"); doApiKeyAuth( assigner, - req.headers["x-sandstorm-app-polis-apikey"], + req?.headers?.["x-sandstorm-app-polis-apikey"], isOptional, req, res, @@ -985,7 +1210,7 @@ function initializePolisHelpers() { } else if (token) { console.log("authtype", "doCookieAuth"); doCookieAuth(assigner, isOptional, req, res, onDone); - } else if (req.headers.authorization) { + } else if (req?.headers?.authorization) { console.log("authtype", "doApiKeyBasicAuth"); doApiKeyBasicAuth( assigner, @@ -1000,7 +1225,7 @@ function initializePolisHelpers() { console.log("authtype", "no auth but agid"); createDummyUser() .then( - function (uid) { + function (uid?: any) { let shouldAddCookies = _.isUndefined(req.body.xid); if (!shouldAddCookies) { req.p = req.p || {}; @@ -1013,20 +1238,20 @@ function initializePolisHelpers() { req.p.uid = uid; onDone(); }, - function (err) { + function (err: any) { res.status(500); console.error(err); onDone("polis_err_auth_token_error_2343"); } ); }, - function (err) { + function (err: any) { res.status(500); console.error(err); onDone("polis_err_auth_token_error_1241"); } ) - .catch(function (err) { + .catch(function (err: any) { res.status(500); console.error(err); onDone("polis_err_auth_token_error_5345"); @@ -1039,12 +1264,16 @@ function initializePolisHelpers() { } }); } - return function (req, res, next) { + return function ( + req: any, + res: { status: (arg0: number) => void }, + next: (arg0?: undefined) => void + ) { doAuth(req, res) .then(() => { return next(); }) - .catch((err) => { + .catch((err: any) => { res.status(500); console.error(err); next(err || "polis_err_auth_error_432"); @@ -1104,15 +1333,15 @@ function initializePolisHelpers() { // }; } // input token from body or query, and populate req.body.u with userid. - function authOptional(assigner) { + function authOptional(assigner: any) { return _auth(assigner, true); } - function auth(assigner) { + function auth(assigner: any) { return _auth(assigner, false); } - function enableAgid(req, res, next) { + function enableAgid(req: { body: Body }, res: any, next: () => void) { req.body.agid = 1; next(); } @@ -1180,7 +1409,7 @@ function initializePolisHelpers() { "survey.pol.is": "survey.pol.is", "preprod.pol.is": "preprod.pol.is", }; - function hasWhitelistMatches(host) { + function hasWhitelistMatches(host: string) { let hostWithoutProtocol = host; if (host.startsWith("http://")) { hostWithoutProtocol = host.slice(7); @@ -1190,14 +1419,15 @@ function initializePolisHelpers() { for (let i = 0; i < whitelistedDomains.length; i++) { let w = whitelistedDomains[i]; - if (hostWithoutProtocol.endsWith(w)) { + if (hostWithoutProtocol.endsWith(w || "")) { // ok, the ending matches, now we need to make sure it's the same, or a subdomain. if (hostWithoutProtocol === w) { return true; } if ( - hostWithoutProtocol[hostWithoutProtocol.length - (w.length + 1)] === - "." + hostWithoutProtocol[ + hostWithoutProtocol.length - ((w || "").length + 1) + ] === "." ) { // separated by a dot, so it's a subdomain. return true; @@ -1206,7 +1436,16 @@ function initializePolisHelpers() { } return false; } - function addCorsHeader(req, res, next) { + function addCorsHeader( + req: { + protocol: string; + get: (arg0: string) => any; + path: any; + headers: Headers; + }, + res: { header: (arg0: string, arg1: string | boolean) => void }, + next: (arg0?: string) => any + ) { let host = ""; if (domainOverride) { host = req.protocol + "://" + domainOverride; @@ -1230,7 +1469,7 @@ function initializePolisHelpers() { // check if the route is on a special list that allows it to be called cross domain (by polisHost.js for example) let routeIsWhitelistedForAnyDomain = _.some( whitelistedCrossDomainRoutes, - function (regex) { + function (regex: { test: (arg0: any) => any }) { return regex.test(req.path); } ); @@ -1282,9 +1521,16 @@ function initializePolisHelpers() { const strToHex = Utils.strToHex; const hexToStr = Utils.hexToStr; - function handle_GET_launchPrep(req, res) { + function handle_GET_launchPrep( + req: { + headers?: { origin: string }; + cookies: { [x: string]: any }; + p: { dest: any }; + }, + res: { redirect: (arg0: any) => void } + ) { let setOnPolisDomain = !domainOverride; - let origin = req.headers.origin || ""; + let origin = req?.headers?.origin || ""; if (setOnPolisDomain && origin.match(/^http:\/\/localhost:[0-9]{4}/)) { setOnPolisDomain = false; } @@ -1294,6 +1540,9 @@ function initializePolisHelpers() { } setCookieTestCookie(req, res, setOnPolisDomain); + // Argument of type '{ redirect: (arg0: any) => void; }' is not assignable to parameter of type '{ cookie: (arg0: any, arg1: any, arg2: any) => void; }'. + // Property 'cookie' is missing in type '{ redirect: (arg0: any) => void; }' but required in type '{ cookie: (arg0: any, arg1: any, arg2: any) => void; }'.ts(2345) + // @ts-ignore setCookie(req, res, setOnPolisDomain, "top", "ok", { httpOnly: false, // not httpOnly - needed by JS }); @@ -1304,7 +1553,7 @@ function initializePolisHelpers() { } // function handle_GET_setFirstCookie(req, res) { // let setOnPolisDomain = !domainOverride; - // let origin = req.headers.origin || ""; + // let origin = req?.headers?.origin || ""; // if (setOnPolisDomain && origin.match(/^http:\/\/localhost:[0-9]{4}/)) { // setOnPolisDomain = false; // } @@ -1318,14 +1567,28 @@ function initializePolisHelpers() { // res.status(200).json({}); // }); - function handle_GET_tryCookie(req, res) { + function handle_GET_tryCookie( + req: { headers?: { origin: string }; cookies: { [x: string]: any } }, + res: { + status: ( + arg0: number + ) => { (): any; new (): any; json: { (arg0: {}): void; new (): any } }; + } + ) { let setOnPolisDomain = !domainOverride; - let origin = req.headers.origin || ""; + let origin = req?.headers?.origin || ""; if (setOnPolisDomain && origin.match(/^http:\/\/localhost:[0-9]{4}/)) { setOnPolisDomain = false; } if (!req.cookies[COOKIES.TRY_COOKIE]) { + // Argument of type '{ status: (arg0: number) => { (): any; new (): any; json: + // { (arg0: {}): void; new (): any; }; }; }' is not assignable to parameter of type + // '{ cookie: (arg0: any, arg1: any, arg2: any) => void; }'. + // Property 'cookie' is missing in type '{ status: (arg0: number) => + // { (): any; new (): any; json: { (arg0: {}): void; new (): any; }; }; + // } ' but required in type '{ cookie: (arg0: any, arg1: any, arg2: any) => void; } '.ts(2345) + // @ts-ignore setCookie(req, res, setOnPolisDomain, COOKIES.TRY_COOKIE, "ok", { httpOnly: false, // not httpOnly - needed by JS }); @@ -1352,7 +1615,11 @@ function initializePolisHelpers() { "select * from math_main where caching_tick > ($1) order by caching_tick limit 10;", [lastPrefetchedMathTick] ) - .then((rows) => { + // Argument of type '(rows: any[]) => void' is not assignable to parameter of type '(value: unknown) => void | PromiseLike'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + .then((rows: any[]) => { if (!rows || !rows.length) { // call again INFO("mathpoll done"); @@ -1360,32 +1627,34 @@ function initializePolisHelpers() { return; } - let results = rows.map((row) => { - let item = row.data; + let results = rows.map( + (row: { data: any; math_tick: any; caching_tick: any }) => { + let item = row.data; - if (row.math_tick) { - item.math_tick = Number(row.math_tick); - } - if (row.caching_tick) { - item.caching_tick = Number(row.caching_tick); - } + if (row.math_tick) { + item.math_tick = Number(row.math_tick); + } + if (row.caching_tick) { + item.caching_tick = Number(row.caching_tick); + } - INFO("mathpoll updating", item.caching_tick, item.zid); + INFO("mathpoll updating", item.caching_tick, item.zid); - // let prev = pcaCache.get(item.zid); - if (item.caching_tick > lastPrefetchedMathTick) { - lastPrefetchedMathTick = item.caching_tick; - } + // let prev = pcaCache.get(item.zid); + if (item.caching_tick > lastPrefetchedMathTick) { + lastPrefetchedMathTick = item.caching_tick; + } - processMathObject(item); + processMathObject(item); - return updatePcaCache(item.zid, item); - }); - Promise.all(results).then((a) => { + return updatePcaCache(item.zid, item); + } + ); + Promise.all(results).then((a: any) => { setTimeout(fetchAndCacheLatestPcaData, waitTime()); }); }) - .catch((err) => { + .catch((err: any) => { INFO("mathpoll error", err); setTimeout(fetchAndCacheLatestPcaData, waitTime()); }); @@ -1463,14 +1732,19 @@ function initializePolisHelpers() { } */ - function processMathObject(o) { - function remapSubgroupStuff(g) { + function processMathObject(o: { [x: string]: any }) { + function remapSubgroupStuff(g: { val: any[] }) { if (_.isArray(g.val)) { - g.val = g.val.map((x) => { + g.val = g.val.map((x: { id: number }) => { return { id: Number(x.id), val: x }; }); } else { - g.val = _.keys(g.val).map((id) => { + // Argument of type '(id: number) => { id: number; val: any; }' + // is not assignable to parameter of type '(value: string, index: number, array: string[]) => { id: number; val: any; }'. + // Types of parameters 'id' and 'value' are incompatible. + // Type 'string' is not assignable to type 'number'.ts(2345) + // @ts-ignore + g.val = _.keys(g.val).map((id: number) => { return { id: Number(id), val: g.val[id] }; }); } @@ -1481,37 +1755,45 @@ function initializePolisHelpers() { if (_.isArray(o["group-clusters"])) { // NOTE this is different since group-clusters is already an array. - o["group-clusters"] = o["group-clusters"].map((g) => { + o["group-clusters"] = o["group-clusters"].map((g: { id: any }) => { return { id: Number(g.id), val: g }; }); } if (!_.isArray(o["repness"])) { - o["repness"] = _.keys(o["repness"]).map((gid) => { + o["repness"] = _.keys(o["repness"]).map((gid: string | number) => { return { id: Number(gid), val: o["repness"][gid] }; }); } if (!_.isArray(o["group-votes"])) { - o["group-votes"] = _.keys(o["group-votes"]).map((gid) => { - return { id: Number(gid), val: o["group-votes"][gid] }; - }); + o["group-votes"] = _.keys(o["group-votes"]).map( + (gid: string | number) => { + return { id: Number(gid), val: o["group-votes"][gid] }; + } + ); } if (!_.isArray(o["subgroup-repness"])) { - o["subgroup-repness"] = _.keys(o["subgroup-repness"]).map((gid) => { - return { id: Number(gid), val: o["subgroup-repness"][gid] }; - }); + o["subgroup-repness"] = _.keys(o["subgroup-repness"]).map( + (gid: string | number) => { + return { id: Number(gid), val: o["subgroup-repness"][gid] }; + } + ); o["subgroup-repness"].map(remapSubgroupStuff); } if (!_.isArray(o["subgroup-votes"])) { - o["subgroup-votes"] = _.keys(o["subgroup-votes"]).map((gid) => { - return { id: Number(gid), val: o["subgroup-votes"][gid] }; - }); + o["subgroup-votes"] = _.keys(o["subgroup-votes"]).map( + (gid: string | number) => { + return { id: Number(gid), val: o["subgroup-votes"][gid] }; + } + ); o["subgroup-votes"].map(remapSubgroupStuff); } if (!_.isArray(o["subgroup-clusters"])) { - o["subgroup-clusters"] = _.keys(o["subgroup-clusters"]).map((gid) => { - return { id: Number(gid), val: o["subgroup-clusters"][gid] }; - }); + o["subgroup-clusters"] = _.keys(o["subgroup-clusters"]).map( + (gid: string | number) => { + return { id: Number(gid), val: o["subgroup-clusters"][gid] }; + } + ); o["subgroup-clusters"].map(remapSubgroupStuff); } @@ -1537,22 +1819,28 @@ function initializePolisHelpers() { // Un-normalize to maintain API consistency. // This could removed in a future API version. - function toObj(a) { + function toObj(a: string | any[]) { let obj = {}; if (!a) { return obj; } for (let i = 0; i < a.length; i++) { + // Element implicitly has an 'any' type + // because expression of type 'any' can't be used to index type '{ } '.ts(7053) + // @ts-ignore obj[a[i].id] = a[i].val; + // Element implicitly has an 'any' type + // because expression of type 'any' can't be used to index type '{ } '.ts(7053) + // @ts-ignore obj[a[i].id].id = a[i].id; } return obj; } - function toArray(a) { + function toArray(a: any[]) { if (!a) { return []; } - return a.map((g) => { + return a.map((g: { id: any; val: any }) => { let id = g.id; g = g.val; g.id = id; @@ -1569,14 +1857,18 @@ function initializePolisHelpers() { return o; } - function getPca(zid, math_tick) { + function getPca(zid?: any, math_tick?: number) { let cached = pcaCache.get(zid); + // Object is of type 'unknown'.ts(2571) + // @ts-ignore if (cached && cached.expiration < Date.now()) { cached = null; } + // Object is of type 'unknown'.ts(2571) + // @ts-ignore let cachedPOJO = cached && cached.asPOJO; if (cachedPOJO) { - if (cachedPOJO.math_tick <= math_tick) { + if (cachedPOJO.math_tick <= (math_tick || 0)) { INFO( "mathpoll related", "math was cached but not new: zid=", @@ -1604,7 +1896,12 @@ function initializePolisHelpers() { return pgQueryP_readOnly( "select * from math_main where zid = ($1) and math_env = ($2);", [zid, process.env.MATH_ENV] - ).then((rows) => { + // Argument of type '(rows: string | any[]) => Promise | null' is not assignable to parameter of type '(value: unknown) => any'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + ).then((rows: string | any[]) => { let queryEnd = Date.now(); let queryDuration = queryEnd - queryStart; addInRamMetric("pcaGetQuery", queryDuration); @@ -1623,7 +1920,7 @@ function initializePolisHelpers() { item.math_tick = Number(rows[0].math_tick); } - if (item.math_tick <= math_tick) { + if (item.math_tick <= (math_tick || 0)) { INFO( "mathpoll related", "after cache miss, unable to find newer item", @@ -1642,22 +1939,30 @@ function initializePolisHelpers() { processMathObject(item); return updatePcaCache(zid, item).then( - function (o) { + function (o: any) { return o; }, - function (err) { + function (err: any) { return err; } ); }); } - function updatePcaCache(zid, item) { - return new Promise(function (resolve, reject) { + function updatePcaCache(zid: any, item: { zid: any }) { + return new Promise(function ( + resolve: (arg0: { + asPOJO: any; + asJSON: string; + asBufferOfGzippedJson: any; + expiration: number; + }) => void, + reject: (arg0: any) => any + ) { delete item.zid; // don't leak zid let asJSON = JSON.stringify(item); let buf = new Buffer(asJSON, "utf-8"); - zlib.gzip(buf, function (err, jsondGzipdPcaBuffer) { + zlib.gzip(buf, function (err: any, jsondGzipdPcaBuffer: any) { if (err) { return reject(err); } @@ -1674,7 +1979,14 @@ function initializePolisHelpers() { }); }); } - function redirectIfHasZidButNoConversationId(req, res, next) { + function redirectIfHasZidButNoConversationId( + req: { body: { zid: any; conversation_id: any } }, + res: { + writeHead: (arg0: number, arg1: { Location: string }) => void; + end: () => any; + }, + next: () => any + ) { if (req.body.zid && !req.body.conversation_id) { winston.log("info", "redirecting old zid user to about page"); res.writeHead(302, { @@ -1685,7 +1997,14 @@ function initializePolisHelpers() { return next(); } - function handle_GET_math_pca(req, res) { + function handle_GET_math_pca( + req: any, + res: { + status: ( + arg0: number + ) => { (): any; new (): any; end: { (): void; new (): any } }; + } + ) { // migrated off this path, old clients were causing timeout issues by polling repeatedly without waiting for a result for a previous poll. res.status(304).end(); } @@ -1694,7 +2013,20 @@ function initializePolisHelpers() { // Needed to determine whether to return a 404 or a 304. // zid -> boolean let pcaResultsExistForZid = {}; - function handle_GET_math_pca2(req, res) { + function handle_GET_math_pca2( + req: { p: { zid: any; math_tick: any; ifNoneMatch: any } }, + res: { + status: ( + arg0: number + ) => { (): any; new (): any; end: { (): void; new (): any } }; + set: (arg0: { + "Content-Type": string; + "Content-Encoding": string; + Etag: string; + }) => void; + send: (arg0: any) => void; + } + ) { let zid = req.p.zid; let math_tick = req.p.math_tick; @@ -1710,7 +2042,7 @@ function initializePolisHelpers() { if (ifNoneMatch.includes("*")) { math_tick = 0; } else { - let entries = ifNoneMatch.split(/ *, */).map((x) => { + let entries = ifNoneMatch.split(/ *, */).map((x: string) => { return Number( x .replace(/^[wW]\//, "") @@ -1724,6 +2056,10 @@ function initializePolisHelpers() { math_tick = -1; } function finishWith304or404() { + let pcaResultsExistForZid: {}; + // Element implicitly has an 'any' type + // because expression of type 'any' can't be used to index type '{ } '.ts(7053) + // @ts-ignore if (pcaResultsExistForZid[zid]) { res.status(304).end(); } else { @@ -1736,7 +2072,10 @@ function initializePolisHelpers() { } getPca(zid, math_tick) - .then(function (data) { + .then(function (data: { + asPOJO: { math_tick: string }; + asBufferOfGzippedJson: any; + }) { if (data) { // The buffer is gzipped beforehand to cut down on server effort in re-gzipping the same json string for each response. // We can't cache this endpoint on Cloudflare because the response changes too freqently, so it seems like the best way @@ -1749,11 +2088,17 @@ function initializePolisHelpers() { res.send(data.asBufferOfGzippedJson); } else { // check whether we should return a 304 or a 404 + // Element implicitly has an 'any' type + // because expression of type 'any' can't be used to index type '{ } '.ts(7053) + // @ts-ignore if (_.isUndefined(pcaResultsExistForZid[zid])) { // This server doesn't know yet if there are any PCA results in the DB // So try querying from -1 - return getPca(zid, -1).then(function (data) { + return getPca(zid, -1).then(function (data: any) { let exists = !!data; + // Element implicitly has an 'any' type + // because expression of type 'any' can't be used to index type '{ } '.ts(7053) + // @ts-ignore pcaResultsExistForZid[zid] = exists; finishWith304or404(); }); @@ -1762,7 +2107,7 @@ function initializePolisHelpers() { } } }) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, err); }); } @@ -1780,9 +2125,14 @@ function initializePolisHelpers() { }); */ - function getZidForRid(rid) { + function getZidForRid(rid: any) { return pgQueryP("select zid from reports where rid = ($1);", [rid]).then( - (row) => { + // Argument of type '(row: string | any[]) => any' is not assignable to parameter of type '(value: unknown) => any'. + // Types of parameters 'row' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + (row: string | any[]) => { if (!row || !row.length) { return null; } @@ -1791,13 +2141,20 @@ function initializePolisHelpers() { ); } - function handle_POST_math_update(req, res) { + function handle_POST_math_update( + req: { p: { zid: any; uid?: any; math_update_type: any } }, + res: { + status: ( + arg0: number + ) => { (): any; new (): any; json: { (arg0: {}): void; new (): any } }; + } + ) { let zid = req.p.zid; let uid = req.p.uid; let math_env = process.env.MATH_ENV; let math_update_type = req.p.math_update_type; - isModerator(zid, uid).then((hasPermission) => { + isModerator(zid, uid).then((hasPermission: any) => { if (!hasPermission) { return fail(res, 500, "handle_POST_math_update_permission"); } @@ -1815,13 +2172,25 @@ function initializePolisHelpers() { .then(() => { res.status(200).json({}); }) - .catch((err) => { + .catch((err: any) => { return fail(res, 500, "polis_err_POST_math_update", err); }); }); } - function handle_GET_math_correlationMatrix(req, res) { + function handle_GET_math_correlationMatrix( + req: { p: { rid: any; math_tick: any } }, + res: { + status: ( + arg0: number + ) => { + (): any; + new (): any; + json: { (arg0: { status: string }): void; new (): any }; + }; + json: (arg0: any) => void; + } + ) { let rid = req.p.rid; let math_env = process.env.MATH_ENV; let math_tick = req.p.math_tick; @@ -1837,7 +2206,12 @@ function initializePolisHelpers() { return pgQueryP( "select * from report_comment_selections where rid = ($1) and selection = 1;", [rid] - ).then((rows) => { + // Argument of type '(rows: string | any[]) => boolean' is not assignable to parameter of type '(value: unknown) => boolean | PromiseLike'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + ).then((rows: string | any[]) => { return rows.length > 0; }); } @@ -1857,16 +2231,21 @@ function initializePolisHelpers() { ); Promise.all([resultExistsPromise, getZidForRid(rid)]) - .then((a) => { + .then((a: any[]) => { let rows = a[0]; let zid = a[1]; if (!rows || !rows.length) { - return requestExistsPromise.then((requests_rows) => { + // Argument of type '(requests_rows: string | any[]) => globalThis.Promise | undefined' is not assignable to parameter of type '(value: unknown) => void | PromiseLike | undefined'. + // Types of parameters 'requests_rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + return requestExistsPromise.then((requests_rows: string | any[]) => { const shouldAddTask = !requests_rows || !requests_rows.length; // const shouldAddTask = true; if (shouldAddTask) { - return hasCommentSelections().then((hasSelections) => { + return hasCommentSelections().then((hasSelections: any) => { if (!hasSelections) { return res.status(202).json({ status: "polis_report_needs_comment_selection", @@ -1891,18 +2270,18 @@ function initializePolisHelpers() { } res.json(rows[0].data); }) - .catch((err) => { + .catch((err: any) => { return fail(res, 500, "polis_err_GET_math_correlationMatrix", err); }); } function doAddDataExportTask( - math_env, - email, - zid, - atDate, - format, - task_bucket + math_env: string | undefined, + email: string, + zid: number, + atDate: number, + format: string, + task_bucket: number ) { return pgQueryP( "insert into worker_tasks (math_env, task_data, task_type, task_bucket) values ($1, $2, 'generate_export_data', $3);", @@ -1942,12 +2321,18 @@ function initializePolisHelpers() { pgQueryP( "select * from worker_tasks where task_type = 'generate_export_data' and task_bucket = ($1);", [task_bucket] - ).then((rows) => { + // Argument of type '(rows: string | any[]) => void' is not assignable to parameter of type '(value: unknown) => void | PromiseLike'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + ).then((rows: string | any[]) => { let ok = rows && rows.length; + let newOk; if (ok) { - ok = rows[0].finished_time > 0; + newOk = rows[0].finished_time > 0; } - if (ok) { + if (ok && newOk) { console.log("runExportTest success"); } else { console.log("runExportTest failed"); @@ -1959,9 +2344,12 @@ function initializePolisHelpers() { }; setInterval(runExportTest, 6 * 60 * 60 * 1000); // every 6 hours } - function handle_GET_dataExport(req, res) { + function handle_GET_dataExport( + req: { p: { uid?: any; zid: any; unixTimestamp: number; format: any } }, + res: { json: (arg0: {}) => void } + ) { getUserInfoForUid2(req.p.uid) - .then((user) => { + .then((user: { email: any }) => { return doAddDataExportTask( process.env.MATH_ENV, user.email, @@ -1973,15 +2361,18 @@ function initializePolisHelpers() { .then(() => { res.json({}); }) - .catch((err) => { + .catch((err: any) => { fail(res, 500, "polis_err_data_export123", err); }); }) - .catch((err) => { + .catch((err: any) => { fail(res, 500, "polis_err_data_export123b", err); }); } - function handle_GET_dataExport_results(req, res) { + function handle_GET_dataExport_results( + req: { p: { filename: string } }, + res: { redirect: (arg0: any) => void } + ) { var url = s3Client.getSignedUrl("getObject", { Bucket: "polis-datadump", Key: process.env.MATH_ENV + "/" + req.p.filename, @@ -1990,16 +2381,21 @@ function initializePolisHelpers() { res.redirect(url); // res.writeHead(302, { - // Location: protocol + "://" + req.headers.host + path, + // Location: protocol + "://" + req?.headers?.host + path, // }); // return res.end(); } - function getBidIndexToPidMapping(zid, math_tick) { + function getBidIndexToPidMapping(zid: number, math_tick: number) { math_tick = math_tick || -1; return pgQueryP_readOnly( "select * from math_bidtopid where zid = ($1) and math_env = ($2);", [zid, process.env.MATH_ENV] - ).then((rows) => { + // Argument of type '(rows: string | any[]) => any' is not assignable to parameter of type '(value: unknown) => any'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + ).then((rows: string | any[]) => { if (zid === 12480) { console.log("bidToPid", rows[0].data); } @@ -2013,51 +2409,71 @@ function initializePolisHelpers() { } }); } - function handle_GET_bidToPid(req, res) { + function handle_GET_bidToPid( + req: { p: { zid: any; math_tick: any } }, + res: { + json: (arg0: { bidToPid: any }) => void; + status: ( + arg0: number + ) => { (): any; new (): any; end: { (): void; new (): any } }; + } + ) { let zid = req.p.zid; let math_tick = req.p.math_tick; getBidIndexToPidMapping(zid, math_tick).then( - function (doc) { + function (doc: { bidToPid: any }) { let b2p = doc.bidToPid; res.json({ bidToPid: b2p, }); }, - function (err) { + function (err: any) { res.status(304).end(); } ); } - function getXids(zid) { - return new MPromise("getXids", function (resolve, reject) { - pgQuery_readOnly( - "select pid, xid from xids inner join " + - "(select * from participants where zid = ($1)) as p on xids.uid = p.uid " + - " where owner in (select org_id from conversations where zid = ($1));", - [zid], - function (err, result) { - if (err) { - reject("polis_err_fetching_xids"); - return; + function getXids(zid: any) { + // 'new' expression, whose target lacks a construct signature, implicitly has an 'any' type.ts(7009) + // @ts-ignore + return new MPromise( + "getXids", + function (resolve: (arg0: any) => void, reject: (arg0: string) => void) { + pgQuery_readOnly( + "select pid, xid from xids inner join " + + "(select * from participants where zid = ($1)) as p on xids.uid = p.uid " + + " where owner in (select org_id from conversations where zid = ($1));", + [zid], + function (err: any, result: { rows: any }) { + if (err) { + reject("polis_err_fetching_xids"); + return; + } + resolve(result.rows); } - resolve(result.rows); - } - ); - }); + ); + } + ); } - function handle_GET_xids(req, res) { + function handle_GET_xids( + req: { p: { uid?: any; zid: any } }, + res: { + status: ( + arg0: number + ) => { (): any; new (): any; json: { (arg0: any): void; new (): any } }; + } + ) { let uid = req.p.uid; let zid = req.p.zid; isOwner(zid, uid).then( - function (owner) { + function (owner: any) { if (owner) { getXids(zid).then( - function (xids) { + function (xids: any) { res.status(200).json(xids); }, - function (err) { + function (err: any) { fail(res, 500, "polis_err_get_xids", err); } ); @@ -2065,12 +2481,19 @@ function initializePolisHelpers() { fail(res, 403, "polis_err_get_xids_not_authorized"); } }, - function (err) { + function (err: any) { fail(res, 500, "polis_err_get_xids", err); } ); } - function handle_POST_xidWhitelist(req, res) { + function handle_POST_xidWhitelist( + req: { p: { xid_whitelist: any; uid?: any } }, + res: { + status: ( + arg0: number + ) => { (): any; new (): any; json: { (arg0: {}): void; new (): any } }; + } + ) { const xid_whitelist = req.p.xid_whitelist; const len = xid_whitelist.length; const owner = req.p.uid; @@ -2089,23 +2512,25 @@ function initializePolisHelpers() { " on conflict do nothing;", [] ) - .then((result) => { + .then((result: any) => { res.status(200).json({}); }) - .catch((err) => { + .catch((err: any) => { return fail(res, 500, "polis_err_POST_xidWhitelist", err); }); } - function getBidsForPids(zid, math_tick, pids) { + function getBidsForPids(zid: any, math_tick: number, pids: any[]) { let dataPromise = getBidIndexToPidMapping(zid, math_tick); let mathResultsPromise = getPca(zid, math_tick); return Promise.all([dataPromise, mathResultsPromise]).then(function ( - items + items: { asPOJO: any }[] ) { + // Property 'bidToPid' does not exist on type '{ asPOJO: any; }'.ts(2339) + // @ts-ignore let b2p = items[0].bidToPid || []; // not sure yet if "|| []" is right here. let mathResults = items[1].asPOJO; - function findBidForPid(pid) { + function findBidForPid(pid: any) { let yourBidi = -1; // if (!b2p) { // return yourBidi; @@ -2146,7 +2571,15 @@ function initializePolisHelpers() { // return pcaData.asPOJO["group-clusters"]; // }); // } - function handle_GET_bid(req, res) { + function handle_GET_bid( + req: { p: { uid?: any; zid: any; math_tick: any } }, + res: { + json: (arg0: { bid: any }) => void; + status: ( + arg0: number + ) => { (): any; new (): any; end: { (): void; new (): any } }; + } + ) { let uid = req.p.uid; let zid = req.p.zid; let math_tick = req.p.math_tick; @@ -2157,11 +2590,13 @@ function initializePolisHelpers() { Promise.all([dataPromise, pidPromise, mathResultsPromise]) .then( - function (items) { + function (items: { asPOJO: any }[]) { + // Property 'bidToPid' does not exist on type '{ asPOJO: any; }'.ts(2339) + // @ts-ignore let b2p = items[0].bidToPid || []; // not sure yet if "|| []" is right here. let pid = items[1]; let mathResults = items[2].asPOJO; - if (pid < 0) { + if (((pid as unknown) as number) < 0) { // NOTE: this API should not be called in /demo mode fail(res, 500, "polis_err_get_bid_bad_pid"); return; @@ -2196,59 +2631,92 @@ function initializePolisHelpers() { bid: yourBid, // The user's current bid }); }, - function (err) { + function (err: any) { res.status(304).end(); } ) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_get_bid_misc", err); }); } - function handle_POST_auth_password(req, res) { + function handle_POST_auth_password( + req: { p: { pwresettoken: any; newPassword: any } }, + res: { + status: ( + arg0: number + ) => { + (): any; + new (): any; + json: { (arg0: string): void; new (): any }; + }; + } + ) { let pwresettoken = req.p.pwresettoken; let newPassword = req.p.newPassword; - getUidForPwResetToken(pwresettoken, function (err, userParams) { - if (err) { - console.error(err); - fail( - res, - 500, - "Password Reset failed. Couldn't find matching pwresettoken.", - err - ); - return; - } - let uid = Number(userParams.uid); - generateHashedPassword(newPassword, function (err, hashedPassword) { - return pgQueryP( - "insert into jianiuevyew (uid, pwhash) values " + - "($1, $2) on conflict (uid) " + - "do update set pwhash = excluded.pwhash;", - [uid, hashedPassword] - ).then( - (rows) => { - res.status(200).json("Password reset successful."); - clearPwResetToken(pwresettoken, function (err) { - if (err) { - yell(err); - console.error("polis_err_auth_pwresettoken_clear_fail"); + getUidForPwResetToken( + pwresettoken, + // Argument of type '(err: any, userParams: { uid?: any; }) => void' is not assignable to parameter of type '(arg0: number | null, arg1?: { uid: any; } | undefined) => void'. + // Types of parameters 'userParams' and 'arg1' are incompatible. + // Type '{ uid: any; } | undefined' is not assignable to type '{ uid?: any; }'. + // Type 'undefined' is not assignable to type '{ uid?: any; }'.ts(2345) + // @ts-ignore + function (err: any, userParams: { uid?: any }) { + if (err) { + console.error(err); + fail( + res, + 500, + "Password Reset failed. Couldn't find matching pwresettoken.", + err + ); + return; + } + let uid = Number(userParams.uid); + generateHashedPassword( + newPassword, + function (err: any, hashedPassword: any) { + return pgQueryP( + "insert into jianiuevyew (uid, pwhash) values " + + "($1, $2) on conflict (uid) " + + "do update set pwhash = excluded.pwhash;", + [uid, hashedPassword] + ).then( + (rows: any) => { + res.status(200).json("Password reset successful."); + clearPwResetToken(pwresettoken, function (err: any) { + if (err) { + yell(err); + console.error("polis_err_auth_pwresettoken_clear_fail"); + } + }); + }, + (err: any) => { + console.error(err); + fail(res, 500, "Couldn't reset password.", err); } - }); - }, - (err) => { - console.error(err); - fail(res, 500, "Couldn't reset password.", err); + ); } ); - }); - }); + } + ); } const getServerNameWithProtocol = Config.getServerNameWithProtocol; - function handle_POST_auth_slack_redirect_uri(req, res) { + function handle_POST_auth_slack_redirect_uri( + req: { p: { code: any } }, + res: { + status: ( + arg0: number + ) => { + (): any; + new (): any; + send: { (arg0: string): void; new (): any }; + }; + } + ) { const code = req.p.code; // const state = req.p.state; console.log("handle_POST_auth_slack_redirect_uri 1"); @@ -2282,31 +2750,42 @@ function initializePolisHelpers() { // redirect_uri: getServerNameWithProtocol(req) + "/api/v3/auth/slack/redirect_uri", // } // }) - .then((slack_response) => { - slack_response = JSON.parse(slack_response); - if (slack_response && slack_response.ok === false) { - fail(res, 500, "polis_err_slack_oauth 3", slack_response); + .then((slackResponse: string) => { + const parsedSlackResponse = JSON.parse(slackResponse); + if (parsedSlackResponse && parsedSlackResponse.ok === false) { + fail(res, 500, "polis_err_slack_oauth 3", parsedSlackResponse); return; } console.log("handle_POST_auth_slack_redirect_uri 2"); - console.log(slack_response); + console.log(parsedSlackResponse); return pgQueryP( "insert into slack_oauth_access_tokens (slack_access_token, slack_scope, slack_auth_response) values ($1, $2, $3);", [ - slack_response.access_token, - slack_response.scope, - slack_response, + parsedSlackResponse.access_token, + parsedSlackResponse.scope, + parsedSlackResponse, // state, ] ).then(() => { res.status(200).send(""); }); }) - .catch((err) => { + .catch((err: any) => { fail(res, 500, "polis_err_slack_oauth", err); }); } - function handle_POST_auth_pwresettoken(req, res) { + function handle_POST_auth_pwresettoken( + req: { p: { email: any } }, + res: { + status: ( + arg0: number + ) => { + (): any; + new (): any; + json: { (arg0: string): void; new (): any }; + }; + } + ) { let email = req.p.email; let server = getServerNameWithProtocol(req); @@ -2321,16 +2800,21 @@ function initializePolisHelpers() { } getUidByEmail(email).then( - function (uid) { - setupPwReset(uid, function (err, pwresettoken) { - sendPasswordResetEmail(uid, pwresettoken, server, function (err) { - if (err) { - console.error(err); - fail(res, 500, "Error: Couldn't send password reset email."); - return; + function (uid?: any) { + setupPwReset(uid, function (err: any, pwresettoken: any) { + sendPasswordResetEmail( + uid, + pwresettoken, + server, + function (err: any) { + if (err) { + console.error(err); + fail(res, 500, "Error: Couldn't send password reset email."); + return; + } + finish(); } - finish(); - }); + ); }); }, function () { @@ -2340,7 +2824,7 @@ function initializePolisHelpers() { ); } - function sendPasswordResetEmailFailure(email, server) { + function sendPasswordResetEmailFailure(email: any, server: any) { let body = `We were unable to find a pol.is account registered with the email address: ${email} You may have used another email address to create your account. @@ -2357,12 +2841,17 @@ Feel free to reply to this email if you need help.`; ); } - function getUidByEmail(email) { + function getUidByEmail(email: string) { email = email.toLowerCase(); return pgQueryP_readOnly( "SELECT uid FROM users where LOWER(email) = ($1);", [email] - ).then(function (rows) { + // Argument of type '(rows: string | any[]) => any' is not assignable to parameter of type '(value: unknown) => any'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + ).then(function (rows: string | any[]) { if (!rows || !rows.length) { throw new Error("polis_err_no_user_matching_email"); } @@ -2370,14 +2859,24 @@ Feel free to reply to this email if you need help.`; }); } - function clearCookie(req, res, cookieName) { - let origin = req.headers.origin || ""; + function clearCookie( + req: { [key: string]: any; headers?: { origin: string } }, + res: { + [key: string]: any; + clearCookie?: ( + arg0: any, + arg1: { path: string; domain?: string } + ) => void; + }, + cookieName: any + ) { + let origin = req?.headers?.origin || ""; if (domainOverride || origin.match(/^http:\/\/localhost:[0-9]{4}/)) { - res.clearCookie(cookieName, { + res?.clearCookie?.(cookieName, { path: "/", }); } else { - res.clearCookie(cookieName, { + res?.clearCookie?.(cookieName, { path: "/", domain: ".pol.is", }); @@ -2385,21 +2884,39 @@ Feel free to reply to this email if you need help.`; } } - function clearCookies(req, res) { - let origin = req.headers.origin || ""; + function clearCookies( + req: { headers?: Headers; cookies?: any; p?: any }, + res: { + clearCookie?: ( + arg0: string, + arg1: { path: string; domain?: string } + ) => void; + status?: (arg0: number) => void; + _headers?: { [x: string]: any }; + redirect?: (arg0: string) => void; + set?: (arg0: { "Content-Type": string }) => void; + } + ) { + let origin = req?.headers?.origin || ""; let cookieName; if (domainOverride || origin.match(/^http:\/\/localhost:[0-9]{4}/)) { for (cookieName in req.cookies) { + // Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ e: boolean; token2: boolean; uid2: boolean; uc: boolean; plan: boolean; referrer: boolean; parent_url: boolean; }'. + // No index signature with a parameter of type 'string' was found on type '{ e: boolean; token2: boolean; uid2: boolean; uc: boolean; plan: boolean; referrer: boolean; parent_url: boolean; }'.ts(7053) + // @ts-ignore if (COOKIES_TO_CLEAR[cookieName]) { - res.clearCookie(cookieName, { + res?.clearCookie?.(cookieName, { path: "/", }); } } } else { for (cookieName in req.cookies) { + // Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ e: boolean; token2: boolean; uid2: boolean; uc: boolean; plan: boolean; referrer: boolean; parent_url: boolean; }'. + // No index signature with a parameter of type 'string' was found on type '{ e: boolean; token2: boolean; uid2: boolean; uc: boolean; plan: boolean; referrer: boolean; parent_url: boolean; }'.ts(7053) + // @ts-ignore if (COOKIES_TO_CLEAR[cookieName]) { - res.clearCookie(cookieName, { + res?.clearCookie?.(cookieName, { path: "/", domain: ".pol.is", }); @@ -2414,14 +2931,20 @@ Feel free to reply to this email if you need help.`; winston.log( "info", "after clear res set-cookie: " + - JSON.stringify(res._headers["set-cookie"]) + JSON.stringify(res?._headers?.["set-cookie"]) ); } - function doCookieAuth(assigner, isOptional, req, res, next) { + function doCookieAuth( + assigner: (arg0: any, arg1: string, arg2: number) => void, + isOptional: any, + req: { cookies: { [x: string]: any }; body: { uid?: any } }, + res: { status: (arg0: number) => void }, + next: { (err: any): void; (arg0?: string): void } + ) { let token = req.cookies[COOKIES.TOKEN]; //if (req.body.uid) { next(401); return; } // shouldn't be in the post - TODO - see if we can do the auth in parallel for non-destructive operations - getUserInfoForSessionToken(token, res, function (err, uid) { + getUserInfoForSessionToken(token, res, function (err: any, uid?: any) { if (err) { clearCookies(req, res); // TODO_MULTI_DATACENTER_CONSIDERATION if (isOptional) { @@ -2441,7 +2964,20 @@ Feel free to reply to this email if you need help.`; next(); }); } - function handle_POST_auth_deregister(req, res) { + function handle_POST_auth_deregister( + req: { p: { showPage?: any }; cookies: { [x: string]: any } }, + res: { + status: ( + arg0: number + ) => { + (): any; + new (): any; + end: { (): void; new (): any }; + send: { (arg0: string): void; new (): any }; + }; + set: (arg0: { "Content-Type": string }) => void; + } + ) { req.p = req.p || {}; let token = req.cookies[COOKIES.TOKEN]; @@ -2467,7 +3003,7 @@ Feel free to reply to this email if you need help.`; // nothing to do return finish(); } - endSession(token, function (err, data) { + endSession(token, function (err: any, data: any) { if (err) { fail(res, 500, "couldn't end session", err); return; @@ -2476,7 +3012,7 @@ Feel free to reply to this email if you need help.`; }); } - function hashStringToInt32(s) { + function hashStringToInt32(s: string) { let h = 1; if (typeof s !== "string" || !s.length) { return 99; @@ -2494,7 +3030,24 @@ Feel free to reply to this email if you need help.`; return h; } - function handle_POST_metrics(req, res) { + function handle_POST_metrics( + req: { + cookies: { [x: string]: any }; + p: { + uid: null; + durs: any[]; + clientTimestamp: any; + times: any[]; + types: any[]; + }; + }, + res: { + status: ( + arg0: number + ) => { (): any; new (): any; json: { (arg0: {}): any; new (): any } }; + json: (arg0: {}) => void; + } + ) { var enabled = false; if (!enabled) { return res.status(200).json({}); @@ -2504,18 +3057,18 @@ Feel free to reply to this email if you need help.`; const hashedPc = hashStringToInt32(pc); const uid = req.p.uid || null; - const durs = req.p.durs.map(function (dur) { + const durs = req.p.durs.map(function (dur: number | null) { if (dur === -1) { dur = null; } return dur; }); const clientTimestamp = req.p.clientTimestamp; - const ages = req.p.times.map(function (t) { + const ages = req.p.times.map(function (t: number) { return clientTimestamp - t; }); const now = Date.now(); - const timesInTermsOfServerTime = ages.map(function (a) { + const timesInTermsOfServerTime = ages.map(function (a: number) { return now - a; }); const len = timesInTermsOfServerTime.length; @@ -2540,20 +3093,33 @@ Feel free to reply to this email if you need help.`; ";", [] ) - .then(function (result) { + .then(function (result: any) { res.json({}); }) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_metrics_post", err); }); } - function handle_GET_zinvites(req, res) { + function handle_GET_zinvites( + req: { p: { zid: any; uid?: any } }, + res: { + writeHead: (arg0: number) => void; + json: (arg0: { status: number }) => void; + status: ( + arg0: number + ) => { + (): any; + new (): any; + json: { (arg0: { codes: any }): void; new (): any }; + }; + } + ) { // if uid is not conversation owner, fail pgQuery_readOnly( "SELECT * FROM conversations WHERE zid = ($1) AND owner = ($2);", [req.p.zid, req.p.uid], - function (err, results) { + function (err: any, results: { rows: any }) { if (err) { fail( res, @@ -2573,7 +3139,7 @@ Feel free to reply to this email if you need help.`; pgQuery_readOnly( "SELECT * FROM zinvites WHERE zid = ($1);", [req.p.zid], - function (err, results) { + function (err: any, results: { rows: any }) { if (err) { fail( res, @@ -2604,20 +3170,23 @@ Feel free to reply to this email if you need help.`; return "" + _.random(2, 9); } - function generateSUZinvites(numTokens) { - return new Promise(function (resolve, reject) { + function generateSUZinvites(numTokens: number) { + return new Promise(function ( + resolve: (arg0: any) => void, + reject: (arg0: Error) => void + ) { generateToken( 31 * numTokens, true, // For now, pseodorandom bytes are probably ok. Anticipating API call will generate lots of these at once, possibly draining the entropy pool. Revisit this if the otzinvites really need to be unguessable. - function (err, longStringOfTokens) { + function (err: any, longStringOfTokens?: string) { if (err) { reject(new Error("polis_err_creating_otzinvite")); return; } winston.log("info", longStringOfTokens); - let otzinviteArray = longStringOfTokens.match(/.{1,31}/g); - otzinviteArray = otzinviteArray.slice(0, numTokens); // Base64 encoding expands to extra characters, so trim to the number of tokens we want. - otzinviteArray = otzinviteArray.map(function (suzinvite) { + let otzinviteArrayRegexMatch = longStringOfTokens?.match(/.{1,31}/g); + let otzinviteArray = otzinviteArrayRegexMatch?.slice(0, numTokens); // Base64 encoding expands to extra characters, so trim to the number of tokens we want. + otzinviteArray = otzinviteArray?.map(function (suzinvite: string) { return generateConversationURLPrefix() + suzinvite; }); winston.log("info", otzinviteArray); @@ -2627,13 +3196,24 @@ Feel free to reply to this email if you need help.`; }); } - function handle_POST_zinvites(req, res) { + function handle_POST_zinvites( + req: { p: { short_url: any; zid: any; uid?: any } }, + res: { + status: ( + arg0: number + ) => { + (): any; + new (): any; + json: { (arg0: { zinvite: any }): void; new (): any }; + }; + } + ) { let generateShortUrl = req.p.short_url; pgQuery( "SELECT * FROM conversations WHERE zid = ($1) AND owner = ($2);", [req.p.zid, req.p.uid], - function (err, results) { + function (err: any, results: any) { if (err) { fail( res, @@ -2645,23 +3225,32 @@ Feel free to reply to this email if you need help.`; } generateAndRegisterZinvite(req.p.zid, generateShortUrl) - .then(function (zinvite) { + .then(function (zinvite: any) { res.status(200).json({ zinvite: zinvite, }); }) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_creating_zinvite", err); }); } ); } - function checkZinviteCodeValidity(zid, zinvite, callback) { + function checkZinviteCodeValidity( + zid: any, + zinvite: any, + callback: { + (err: any, foo: any): void; + (err: any, foo: any): void; + (err: any): void; + (arg0: number | null): void; + } + ) { pgQuery_readOnly( "SELECT * FROM zinvites WHERE zid = ($1) AND zinvite = ($2);", [zid, zinvite], - function (err, results) { + function (err: any, results: { rows: string | any[] }) { if (err || !results || !results.rows || !results.rows.length) { callback(1); } else { @@ -2675,7 +3264,7 @@ Feel free to reply to this email if you need help.`; max: 1000, }); - function getZinvite(zid, dontUseCache) { + function getZinvite(zid: any, dontUseCache?: boolean) { let cachedConversationId = zidToConversationIdCache.get(zid); if (!dontUseCache && cachedConversationId) { return Promise.resolve(cachedConversationId); @@ -2684,7 +3273,7 @@ Feel free to reply to this email if you need help.`; "getZinvite", "select * from zinvites where zid = ($1);", [zid] - ).then(function (rows) { + ).then(function (rows: { zinvite: any }[]) { let conversation_id = (rows && rows[0] && rows[0].zinvite) || void 0; if (conversation_id) { zidToConversationIdCache.set(zid, conversation_id); @@ -2693,75 +3282,91 @@ Feel free to reply to this email if you need help.`; }); } - function getZinvites(zids) { + function getZinvites(zids: any[]) { if (!zids.length) { return Promise.resolve(zids); } - zids = _.map(zids, function (zid) { + zids = _.map(zids, function (zid: any) { return Number(zid); // just in case }); zids = _.uniq(zids); - let uncachedZids = zids.filter(function (zid) { + let uncachedZids = zids.filter(function (zid: any) { return !zidToConversationIdCache.get(zid); }); let zidsWithCachedConversationIds = zids - .filter(function (zid) { + .filter(function (zid: any) { return !!zidToConversationIdCache.get(zid); }) - .map(function (zid) { + .map(function (zid: any) { return { zid: zid, zinvite: zidToConversationIdCache.get(zid), }; }); - function makeZidToConversationIdMap(arrays) { + function makeZidToConversationIdMap(arrays: any[]) { let zid2conversation_id = {}; - arrays.forEach(function (a) { - a.forEach(function (o) { + arrays.forEach(function (a: any[]) { + a.forEach(function (o: { zid: string | number; zinvite: any }) { + // (property) zid: string | number + // Element implicitly has an 'any' type because expression of type 'string | number' can't be used to index type '{}'. + // No index signature with a parameter of type 'string' was found onpe '{}'.ts(7053) + // @ts-ignore zid2conversation_id[o.zid] = o.zinvite; }); }); return zid2conversation_id; } - return new MPromise("getZinvites", function (resolve, reject) { - if (uncachedZids.length === 0) { - resolve(makeZidToConversationIdMap([zidsWithCachedConversationIds])); - return; - } - pgQuery_readOnly( - "select * from zinvites where zid in (" + uncachedZids.join(",") + ");", - [], - function (err, result) { - if (err) { - reject(err); - } else { - resolve( - makeZidToConversationIdMap([ - result.rows, - zidsWithCachedConversationIds, - ]) - ); - } + // 'new' expression, whose target lacks a construct signature, implicitly has an 'any' type.ts(7009) + // @ts-ignore + return new MPromise( + "getZinvites", + function (resolve: (arg0: {}) => void, reject: (arg0: any) => void) { + if (uncachedZids.length === 0) { + resolve(makeZidToConversationIdMap([zidsWithCachedConversationIds])); + return; } - ); - }); + pgQuery_readOnly( + "select * from zinvites where zid in (" + + uncachedZids.join(",") + + ");", + [], + function (err: any, result: { rows: any }) { + if (err) { + reject(err); + } else { + resolve( + makeZidToConversationIdMap([ + result.rows, + zidsWithCachedConversationIds, + ]) + ); + } + } + ); + } + ); } - function addConversationId(o, dontUseCache) { + function addConversationId( + o: { zid?: any; conversation_id?: any }, + dontUseCache: any + ) { if (!o.zid) { // if no zid, resolve without fetching zinvite. return Promise.resolve(o); } - return getZinvite(o.zid, dontUseCache).then(function (conversation_id) { + return getZinvite(o.zid, dontUseCache).then(function ( + conversation_id: any + ) { o.conversation_id = conversation_id; return o; }); } - function addConversationIds(a) { + function addConversationIds(a: any[]) { let zids = []; for (var i = 0; i < a.length; i++) { if (a[i].zid) { @@ -2771,18 +3376,32 @@ Feel free to reply to this email if you need help.`; if (!zids.length) { return Promise.resolve(a); } - return getZinvites(zids).then(function (zid2conversation_id) { - return a.map(function (o) { + return getZinvites(zids).then(function (zid2conversation_id: { + [x: string]: any; + }) { + return a.map(function (o: { + conversation_id: any; + zid: string | number; + }) { o.conversation_id = zid2conversation_id[o.zid]; return o; }); }); } - function finishOne(res, o, dontUseCache, altStatusCode) { + function finishOne( + res: { + status: ( + arg0: any + ) => { (): any; new (): any; json: { (arg0: any): void; new (): any } }; + }, + o: { url?: string; zid?: any; currentPid?: any }, + dontUseCache?: boolean | undefined, + altStatusCode?: number | undefined + ) { addConversationId(o, dontUseCache) .then( - function (item) { + function (item: { zid: any }) { // ensure we don't expose zid if (item.zid) { delete item.zid; @@ -2790,19 +3409,26 @@ Feel free to reply to this email if you need help.`; let statusCode = altStatusCode || 200; res.status(statusCode).json(item); }, - function (err) { + function (err: any) { fail(res, 500, "polis_err_finishing_responseA", err); } ) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_finishing_response", err); }); } - function finishArray(res, a) { + function finishArray( + res: { + status: ( + arg0: number + ) => { (): any; new (): any; json: { (arg0: any): void; new (): any } }; + }, + a: any + ) { addConversationIds(a) .then( - function (items) { + function (items: string | any[]) { // ensure we don't expose zid if (items) { for (var i = 0; i < items.length; i++) { @@ -2813,20 +3439,29 @@ Feel free to reply to this email if you need help.`; } res.status(200).json(items); }, - function (err) { + function (err: any) { fail(res, 500, "polis_err_finishing_response2A", err); } ) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_finishing_response2", err); }); } - function checkSuzinviteCodeValidity(zid, suzinvite, callback) { + function checkSuzinviteCodeValidity( + zid: any, + suzinvite: any, + callback: { + (err: any, foo: any): void; + (err: any, foo: any): void; + (err: any): void; + (arg0: number | null): void; + } + ) { pgQuery( "SELECT * FROM suzinvites WHERE zid = ($1) AND suzinvite = ($2);", [zid, suzinvite], - function (err, results) { + function (err: any, results: { rows: string | any[] }) { if (err || !results || !results.rows || !results.rows.length) { callback(1); } else { @@ -2836,12 +3471,15 @@ Feel free to reply to this email if you need help.`; ); } - function getSUZinviteInfo(suzinvite) { - return new Promise(function (resolve, reject) { + function getSUZinviteInfo(suzinvite: any) { + return new Promise(function ( + resolve: (arg0: any) => void, + reject: (arg0: Error) => any + ) { pgQuery( "SELECT * FROM suzinvites WHERE suzinvite = ($1);", [suzinvite], - function (err, results) { + function (err: any, results: { rows: string | any[] }) { if (err) { return reject(err); } @@ -2854,12 +3492,12 @@ Feel free to reply to this email if you need help.`; }); } - function deleteSuzinvite(suzinvite) { - return new Promise(function (resolve, reject) { + function deleteSuzinvite(suzinvite: any) { + return new Promise(function (resolve: () => void, reject: any) { pgQuery( "DELETE FROM suzinvites WHERE suzinvite = ($1);", [suzinvite], - function (err, results) { + function (err: any, results: any) { if (err) { // resolve, but complain yell("polis_err_removing_suzinvite"); @@ -2870,21 +3508,29 @@ Feel free to reply to this email if you need help.`; }); } - function xidExists(xid, owner, uid) { + function xidExists(xid: any, owner: any, uid?: any) { return pgQueryP( "select * from xids where xid = ($1) and owner = ($2) and uid = ($3);", [xid, owner, uid] - ).then(function (rows) { + // Argument of type '(rows: string | any[]) => number | ""' is not assignable to parameter of type '(value: unknown) => number | "" | PromiseLike'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + ).then(function (rows: string | any[]) { return rows && rows.length; }); } - function createXidEntry(xid, owner, uid) { - return new Promise(function (resolve, reject) { + function createXidEntry(xid: any, owner: any, uid?: any) { + return new Promise(function ( + resolve: () => void, + reject: (arg0: Error) => void + ) { pgQuery( "INSERT INTO xids (uid, owner, xid) VALUES ($1, $2, $3);", [uid, owner, xid], - function (err, results) { + function (err: any, results: any) { if (err) { console.error(err); reject(new Error("polis_err_adding_xid_entry")); @@ -2896,9 +3542,12 @@ Feel free to reply to this email if you need help.`; }); } - function saveParticipantMetadataChoicesP(zid, pid, answers) { - return new Promise(function (resolve, reject) { - saveParticipantMetadataChoices(zid, pid, answers, function (err) { + function saveParticipantMetadataChoicesP(zid: any, pid: any, answers: any) { + return new Promise(function ( + resolve: (arg0: number) => void, + reject: (arg0: any) => void + ) { + saveParticipantMetadataChoices(zid, pid, answers, function (err: any) { if (err) { reject(err); } else { @@ -2908,7 +3557,12 @@ Feel free to reply to this email if you need help.`; }); } - function saveParticipantMetadataChoices(zid, pid, answers, callback) { + function saveParticipantMetadataChoices( + zid: any, + pid: any, + answers: any[], + callback: { (err: any): void; (arg0: number): void } + ) { // answers is a list of pmaid if (!answers || !answers.length) { // nothing to save @@ -2920,51 +3574,67 @@ Feel free to reply to this email if you need help.`; answers.join(",") + ");"; - pgQuery(q, [zid], function (err, qa_results) { - if (err) { - winston.log("info", "adsfasdfasd"); - return callback(err); - } - - qa_results = qa_results.rows; - qa_results = _.indexBy(qa_results, "pmaid"); - // construct an array of params arrays - answers = answers.map(function (pmaid) { - let pmqid = qa_results[pmaid].pmqid; - return [zid, pid, pmaid, pmqid]; - }); - // make simultaneous requests to insert the choices - async.map( - answers, - function (x, cb) { - // ...insert() - // .into("participant_metadata_choices") - // . - pgQuery( - "INSERT INTO participant_metadata_choices (zid, pid, pmaid, pmqid) VALUES ($1,$2,$3,$4);", - x, - function (err, results) { - if (err) { - winston.log("info", "sdkfuhsdu"); - return cb(err); + pgQuery( + q, + [zid], + function ( + err: any, + qa_results: { [x: string]: { pmqid: any }; rows: any } + ) { + if (err) { + winston.log("info", "adsfasdfasd"); + return callback(err); + } + + qa_results = qa_results.rows; + // Property 'rows' is missing in type 'Dictionary<{ pmqid: any; }>' but required in type '{ [x: string]: { pmqid: any; }; rows: any; }'.ts(2741) + // @ts-ignore + qa_results = _.indexBy(qa_results, "pmaid"); + // construct an array of params arrays + answers = answers.map(function (pmaid: string | number) { + let pmqid = qa_results[pmaid].pmqid; + return [zid, pid, pmaid, pmqid]; + }); + // make simultaneous requests to insert the choices + async.map( + answers, + function (x: any, cb: (arg0: number) => void) { + // ...insert() + // .into("participant_metadata_choices") + // . + pgQuery( + "INSERT INTO participant_metadata_choices (zid, pid, pmaid, pmqid) VALUES ($1,$2,$3,$4);", + x, + function (err: any, results: any) { + if (err) { + winston.log("info", "sdkfuhsdu"); + return cb(err); + } + cb(0); } - cb(0); + ); + }, + function (err: any) { + if (err) { + winston.log("info", "ifudshf78ds"); + return callback(err); } - ); - }, - function (err) { - if (err) { - winston.log("info", "ifudshf78ds"); - return callback(err); + // finished with all the inserts + callback(0); } - // finished with all the inserts - callback(0); - } - ); - }); + ); + } + ); } - function createParticpantLocationRecord(zid, uid, pid, lat, lng, source) { + function createParticpantLocationRecord( + zid: any, + uid?: any, + pid?: any, + lat?: any, + lng?: any, + source?: any + ) { return pgQueryP( "insert into participant_locations (zid, uid, pid, lat, lng, source) values ($1,$2,$3,$4,$5,$6);", [zid, uid, pid, lat, lng, source] @@ -2979,13 +3649,24 @@ Feel free to reply to this email if you need help.`; manual_entry: 1, }; - function getUsersLocationName(uid) { + function getUsersLocationName(uid?: any) { return Promise.all([ pgQueryP_readOnly("select * from facebook_users where uid = ($1);", [ uid, ]), pgQueryP_readOnly("select * from twitter_users where uid = ($1);", [uid]), - ]).then(function (o) { + // No overload matches this call. + // Overload 1 of 2, '(onFulfill?: ((value: [unknown, unknown]) => Resolvable<{ location: any; source: number; } | null>) | undefined, onReject?: ((error: any) => Resolvable<{ location: any; source: number; } | null>) | undefined): Bluebird<...>', gave the following error. + // Argument of type '(o: any[][]) => { location: any; source: number; } | null' is not assignable to parameter of type '(value: [unknown, unknown]) => Resolvable<{ location: any; source: number; } | null>'. + // Types of parameters 'o' and 'value' are incompatible. + // Type '[unknown, unknown]' is not assignable to type 'any[][]'. + // Type 'unknown' is not assignable to type 'any[]'. + // Overload 2 of 2, '(onfulfilled?: ((value: [unknown, unknown]) => Resolvable<{ location: any; source: number; } | null>) | null | undefined, onrejected?: ((reason: any) => PromiseLike) | null | undefined): Bluebird<...>', gave the following error. + // Argument of type '(o: any[][]) => { location: any; source: number; } | null' is not assignable to parameter of type '(value: [unknown, unknown]) => Resolvable<{ location: any; source: number; } | null>'. + // Types of parameters 'o' and 'value' are incompatible. + // Type '[unknown, unknown]' is not assignable to type 'any[][]'.ts(2769) + // @ts-ignore + ]).then(function (o: any[][]) { let fb = o[0] && o[0][0]; let tw = o[1] && o[1][0]; if (fb && _.isString(fb.location)) { @@ -3003,17 +3684,35 @@ Feel free to reply to this email if you need help.`; }); } - function populateParticipantLocationRecordIfPossible(zid, uid, pid) { + function populateParticipantLocationRecordIfPossible( + zid: any, + uid?: any, + pid?: any + ) { INFO("asdf1", zid, uid, pid); getUsersLocationName(uid) - .then(function (locationData) { + // No overload matches this call. + // Overload 1 of 2, '(onFulfill?: ((value: unknown) => Resolvable) | undefined, onReject?: ((error: any) => Resolvable) | undefined): Bluebird', gave the following error. + // Argument of type '(locationData: { location: any; source: any; }) => void' is not assignable to parameter of type '(value: unknown) => Resolvable'. + // Types of parameters 'locationData' and 'value' are incompatible. + // Type 'unknown' is not assignable to type '{ location: any; source: any; }'. + // Overload 2 of 2, '(onfulfilled?: ((value: unknown) => Resolvable) | null | undefined, onrejected?: ((reason: any) => PromiseLike) | null | undefined): Bluebird', gave the following error. + // Argument of type '(locationData: { location: any; source: any; }) => void' is not assignable to parameter of type '(value: unknown) => Resolvable'. + // Types of parameters 'locationData' and 'value' are incompatible. + // Type 'unknown' is not assignable to type '{ location: any; source: any; }'.ts(2769) + // @ts-ignore + .then(function (locationData: { location: any; source: any }) { if (!locationData) { INFO("asdf1.nope"); return; } INFO(locationData); geoCode(locationData.location) - .then(function (o) { + // Argument of type '(o: { lat: any; lng: any; }) => void' is not assignable to parameter of type '(value: unknown) => void | PromiseLike'. + // Types of parameters 'o' and 'value' are incompatible. + // Type 'unknown' is not assignable to type '{ lat: any; lng: any; }'.ts(2345) + // @ts-ignore + .then(function (o: { lat: any; lng: any }) { createParticpantLocationRecord( zid, uid, @@ -3021,31 +3720,31 @@ Feel free to reply to this email if you need help.`; o.lat, o.lng, locationData.source - ).catch(function (err) { + ).catch(function (err: any) { if (!isDuplicateKey(err)) { yell("polis_err_creating_particpant_location_record"); console.error(err); } }); }) - .catch(function (err) { + .catch(function (err: any) { yell("polis_err_geocoding_01"); console.error(err); }); }) - .catch(function (err) { + .catch(function (err: any) { yell("polis_err_fetching_user_location_name"); console.error(err); }); } - function updateLastInteractionTimeForConversation(zid, uid) { + function updateLastInteractionTimeForConversation(zid: any, uid?: any) { return pgQueryP( "update participants set last_interaction = now_as_millis(), nsli = 0 where zid = ($1) and uid = ($2);", [zid, uid] ); } - function populateGeoIpInfo(zid, uid, ipAddress) { + function populateGeoIpInfo(zid: any, uid?: any, ipAddress?: string | null) { var userId = process.env.MAXMIND_USERID; var licenseKey = process.env.MAXMIND_LICENSEKEY; @@ -3062,6 +3761,16 @@ Feel free to reply to this email if you need help.`; contentType = "application/vnd.maxmind.com-insights+json; charset=UTF-8; version=2.1"; } + // No overload matches this call. + // Overload 1 of 3, '(uri: string, options?: RequestPromiseOptions | undefined, callback?: RequestCallback | undefined): RequestPromise', gave the following error. + // Argument of type '{ method: string; contentType: string; headers: { Authorization: string; }; }' is not assignable to parameter of type 'RequestPromiseOptions'. + // Object literal may only specify known properties, and 'contentType' does not exist in type 'RequestPromiseOptions'. + // Overload 2 of 3, '(uri: string, callback?: RequestCallback | undefined): RequestPromise', gave the following error. + // Argument of type '{ method: string; contentType: string; headers: { Authorization: string; }; }' is not assignable to parameter of type 'RequestCallback'. + // Object literal may only specify known properties, and 'method' does not exist in type 'RequestCallback'. + // Overload 3 of 3, '(options: RequiredUriUrl & RequestPromiseOptions, callback?: RequestCallback | undefined): RequestPromise', gave the following error. + // Argument of type 'string' is not assignable to parameter of type 'RequiredUriUrl & RequestPromiseOptions'.ts(2769) + // @ts-ignore return request .get(url + ipAddress, { method: "GET", @@ -3072,7 +3781,7 @@ Feel free to reply to this email if you need help.`; new Buffer(userId + ":" + licenseKey, "utf8").toString("base64"), }, }) - .then(function (response) { + .then(function (response: string) { var parsedResponse = JSON.parse(response); console.log("BEGIN MAXMIND RESPONSE"); console.log(response); @@ -3097,7 +3806,7 @@ Feel free to reply to this email if you need help.`; }); } - function addExtendedParticipantInfo(zid, uid, data) { + function addExtendedParticipantInfo(zid: any, uid?: any, data?: {}) { if (!data || !_.keys(data).length) { return Promise.resolve(); } @@ -3116,7 +3825,12 @@ Feel free to reply to this email if you need help.`; return pgQueryP(qString, []); } - function tryToJoinConversation(zid, uid, info, pmaid_answers) { + function tryToJoinConversation( + zid: any, + uid?: any, + info?: any, + pmaid_answers?: string | any[] + ) { console.log("tryToJoinConversation"); console.dir(arguments); @@ -3126,14 +3840,18 @@ Feel free to reply to this email if you need help.`; } } - function saveMetadataChoices(pid) { + function saveMetadataChoices(pid?: number) { if (pmaid_answers && pmaid_answers.length) { saveParticipantMetadataChoicesP(zid, pid, pmaid_answers); } } // there was no participant row, so create one - return addParticipant(zid, uid).then(function (rows) { + // Argument of type '(rows: any[]) => any' is not assignable to parameter of type '(value: unknown) => any'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + return addParticipant(zid, uid).then(function (rows: any[]) { let pid = rows && rows[0] && rows[0].pid; let ptpt = rows[0]; @@ -3147,13 +3865,22 @@ Feel free to reply to this email if you need help.`; }); } - function addParticipantAndMetadata(zid, uid, req, permanent_cookie) { - let info = {}; - let parent_url = req.cookies[COOKIES.PARENT_URL] || req.p.parent_url; + function addParticipantAndMetadata( + zid: any, + uid?: any, + req?: { + cookies: { [x: string]: any }; + p: { parent_url: any }; + headers?: { [x: string]: any }; + }, + permanent_cookie?: any + ) { + let info: { [key: string]: string } = {}; + let parent_url = req?.cookies?.[COOKIES.PARENT_URL] || req?.p?.parent_url; let referer = - req.cookies[COOKIES.PARENT_REFERRER] || - req.headers["referer"] || - req.headers["referrer"]; + req?.cookies[COOKIES.PARENT_REFERRER] || + req?.headers?.["referer"] || + req?.headers?.["referrer"]; if (parent_url) { info.parent_url = parent_url; } @@ -3161,8 +3888,8 @@ Feel free to reply to this email if you need help.`; if (referer) { info.referrer = referer; } - let x_forwarded_for = req.headers["x-forwarded-for"]; - let ip = null; + let x_forwarded_for = req?.headers?.["x-forwarded-for"]; + let ip: string | null = null; if (x_forwarded_for) { let ips = x_forwarded_for; ips = ips && ips.split(", "); @@ -3174,10 +3901,14 @@ Feel free to reply to this email if you need help.`; if (permanent_cookie) { info.permanent_cookie = permanent_cookie; } - if (req.headers["origin"]) { - info.origin = req.headers["origin"]; + if (req?.headers?.["origin"]) { + info.origin = req?.headers?.["origin"]; } - return addParticipant(zid, uid).then((rows) => { + // Argument of type '(rows: any[]) => any[]' is not assignable to parameter of type '(value: unknown) => any[] | PromiseLike'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + return addParticipant(zid, uid).then((rows: any[]) => { let ptpt = rows[0]; let pid = ptpt.pid; populateParticipantLocationRecordIfPossible(zid, uid, pid); @@ -3189,7 +3920,12 @@ Feel free to reply to this email if you need help.`; }); } - function joinConversation(zid, uid, info, pmaid_answers) { + function joinConversation( + zid: any, + uid?: any, + info?: {}, + pmaid_answers?: any + ) { function tryJoin() { return tryToJoinConversation(zid, uid, info, pmaid_answers); } @@ -3213,7 +3949,7 @@ Feel free to reply to this email if you need help.`; return promise; } - return getPidPromise(zid, uid).then(function (pid) { + return getPidPromise(zid, uid).then(function (pid: number) { if (pid >= 0) { // already a ptpt, so don't create another return; @@ -3223,21 +3959,36 @@ Feel free to reply to this email if you need help.`; }, doJoin); } - function isOwnerOrParticipant(zid, uid, callback) { + function isOwnerOrParticipant( + zid: any, + uid?: any, + callback?: { (): void; (arg0: null): void } + ) { // TODO should be parallel. // look into bluebird, use 'some' https://github.com/petkaantonov/bluebird - getPid(zid, uid, function (err, pid) { + getPid(zid, uid, function (err: any, pid: number) { if (err || pid < 0) { - isConversationOwner(zid, uid, function (err) { - callback(err); + isConversationOwner(zid, uid, function (err: any) { + callback?.(err); }); } else { - callback(null); + callback?.(null); } }); } - function isConversationOwner(zid, uid, callback) { + function isConversationOwner( + zid: any, + uid?: any, + callback?: { + (err: any): void; + (err: any): void; + (err: any): void; + (err: any, foo: any): void; + (err: any, foo: any): void; + (arg0: any): void; + } + ) { // if (true) { // callback(null); // TODO remove! // return; @@ -3245,17 +3996,17 @@ Feel free to reply to this email if you need help.`; pgQuery_readOnly( "SELECT * FROM conversations WHERE zid = ($1) AND owner = ($2);", [zid, uid], - function (err, docs) { + function (err: number, docs: { rows: string | any[] }) { if (!docs || !docs.rows || docs.rows.length === 0) { err = err || 1; } - callback(err); + callback?.(err); } ); } - function isOwner(zid, uid) { - return getConversationInfo(zid).then(function (info) { + function isOwner(zid: any, uid: string) { + return getConversationInfo(zid).then(function (info: { owner: any }) { winston.log("info", 39847534987 + " isOwner " + uid); winston.log("info", info); winston.log("info", info.owner === uid); @@ -3263,41 +4014,56 @@ Feel free to reply to this email if you need help.`; }); } - function isModerator(zid, uid) { + function isModerator(zid: any, uid?: any) { if (isPolisDev(uid)) { return Promise.resolve(true); } return pgQueryP_readOnly( "select count(*) from conversations where owner in (select uid from users where site_id = (select site_id from users where uid = ($2))) and zid = ($1);", [zid, uid] - ).then(function (rows) { + // Argument of type '(rows: { count: number; }[]) => boolean' is not assignable to parameter of type '(value: unknown) => boolean | PromiseLike'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type '{ count: number; }[]'.ts(2345) + // @ts-ignore + ).then(function (rows: { count: number }[]) { return rows[0].count >= 1; }); } // returns null if it's missing - function getParticipant(zid, uid) { - return new MPromise("getParticipant", function (resolve, reject) { - pgQuery_readOnly( - "SELECT * FROM participants WHERE zid = ($1) AND uid = ($2);", - [zid, uid], - function (err, results) { - if (err) { - return reject(err); - } - if (!results || !results.rows) { - return reject(new Error("polis_err_getParticipant_failed")); + function getParticipant(zid: any, uid?: any) { + // 'new' expression, whose target lacks a construct signature, implicitly has an 'any' type.ts(7009) + // @ts-ignore + return new MPromise( + "getParticipant", + function (resolve: (arg0: any) => void, reject: (arg0: Error) => any) { + pgQuery_readOnly( + "SELECT * FROM participants WHERE zid = ($1) AND uid = ($2);", + [zid, uid], + function (err: any, results: { rows: any[] }) { + if (err) { + return reject(err); + } + if (!results || !results.rows) { + return reject(new Error("polis_err_getParticipant_failed")); + } + resolve(results.rows[0]); } - resolve(results.rows[0]); - } - ); - }); + ); + } + ); } - function getAnswersForConversation(zid, callback) { + function getAnswersForConversation( + zid: any, + callback: { + (err: any, available_answers: any): any; + (arg0: number, arg1?: undefined): void; + } + ) { pgQuery_readOnly( "SELECT * from participant_metadata_answers WHERE zid = ($1) AND alive=TRUE;", [zid], - function (err, x) { + function (err: any, x: { rows: any }) { if (err) { callback(err); return; @@ -3307,12 +4073,15 @@ Feel free to reply to this email if you need help.`; ); } - function getChoicesForConversation(zid) { - return new Promise(function (resolve, reject) { + function getChoicesForConversation(zid: any) { + return new Promise(function ( + resolve: (arg0: never[]) => void, + reject: (arg0: any) => void + ) { pgQuery_readOnly( "select * from participant_metadata_choices where zid = ($1) and alive = TRUE;", [zid], - function (err, x) { + function (err: any, x: { rows: any }) { if (err) { reject(err); return; @@ -3330,7 +4099,7 @@ Feel free to reply to this email if you need help.`; const getUserInfoForUid = User.getUserInfoForUid; const getUserInfoForUid2 = User.getUserInfoForUid2; - function emailFeatureRequest(message) { + function emailFeatureRequest(message: string) { const body = `Somebody clicked a dummy button! ${message}`; @@ -3340,40 +4109,54 @@ ${message}`; admin_emails, "Dummy button clicked!!!", body - ).catch(function (err) { + ).catch(function (err: any) { yell("polis_err_failed_to_email_for_dummy_button"); yell(message); }); } - function emailTeam(subject, body) { + function emailTeam(subject: string, body: string) { return sendMultipleTextEmails( POLIS_FROM_ADDRESS, admin_emails, subject, body - ).catch(function (err) { + ).catch(function (err: any) { yell("polis_err_failed_to_email_team"); + // Cannot find name 'message'. Did you mean 'onmessage'?ts(2552) + // lib.dom.d.ts(20013, 13): 'onmessage' is declared here. + // @ts-ignore yell(message); }); } - function emailBadProblemTime(message) { + function emailBadProblemTime(message: string) { const body = `Yo, there was a serious problem. Here's the message: ${message}`; return emailTeam("Polis Bad Problems!!!", body); } - function sendPasswordResetEmail(uid, pwresettoken, serverName, callback) { - getUserInfoForUid(uid, function (err, userInfo) { - if (err) { - return callback(err); - } - if (!userInfo) { - return callback("missing user info"); - } - let body = `Hi ${userInfo.hname}, + function sendPasswordResetEmail( + uid?: any, + pwresettoken?: any, + serverName?: any, + callback?: { (err: any): void; (arg0?: string): void } + ) { + getUserInfoForUid( + uid, + // Argument of type '(err: any, userInfo: { hname: any; email: any; }) => void' is not assignable to parameter of type '(arg0: null, arg1?: undefined) => void'. + // Types of parameters 'userInfo' and 'arg1' are incompatible. + // Type 'undefined' is not assignable to type '{ hname: any; email: any; }'.ts(2345) + // @ts-ignore + function (err: any, userInfo: { hname: any; email: any }) { + if (err) { + return callback?.(err); + } + if (!userInfo) { + return callback?.("missing user info"); + } + let body = `Hi ${userInfo.hname}, We have just received a password reset request for ${userInfo.email} @@ -3382,20 +4165,21 @@ ${serverName}/pwreset/${pwresettoken} "Thank you for using Polis`; - sendTextEmail( - POLIS_FROM_ADDRESS, - userInfo.email, - "Polis Password Reset", - body - ) - .then(function () { - callback(); - }) - .catch(function (err) { - yell("polis_err_failed_to_email_password_reset_code"); - callback(err); - }); - }); + sendTextEmail( + POLIS_FROM_ADDRESS, + userInfo.email, + "Polis Password Reset", + body + ) + .then(function () { + callback?.(); + }) + .catch(function (err: any) { + yell("polis_err_failed_to_email_password_reset_code"); + callback?.(err); + }); + } + ); } // function sendTextEmailWithPostmark(sender, recipient, subject, text) { @@ -3418,12 +4202,17 @@ ${serverName}/pwreset/${pwresettoken} // }); // }); // } - function sendMultipleTextEmails(sender, recipientArray, subject, text) { + function sendMultipleTextEmails( + sender: string | undefined, + recipientArray: any[], + subject: string, + text: string + ) { recipientArray = recipientArray || []; return Promise.all( - recipientArray.map(function (email) { + recipientArray.map(function (email: string) { let promise = sendTextEmail(sender, email, subject, text); - promise.catch(function (err) { + promise.catch(function (err: any) { yell("polis_err_failed_to_email_for_user " + email); }); return promise; @@ -3449,7 +4238,7 @@ ${serverName}/pwreset/${pwresettoken} } setInterval(trySendingBackupEmailTest, 1000 * 60 * 60 * 23); // try every 23 hours (so it should only try roughly once a day) trySendingBackupEmailTest(); - function sendEinviteEmail(req, email, einvite) { + function sendEinviteEmail(req: any, email: any, einvite: any) { let serverName = getServerNameWithProtocol(req); const body = `Welcome to pol.is! @@ -3467,18 +4256,36 @@ Thank you for using Polis`; ); } - function isEmailVerified(email) { - return pg - .queryP("select * from email_validations where email = ($1);", [email]) - .then(function (rows) { - return rows.length > 0; - }); + function isEmailVerified(email: any) { + return ( + dbPgQuery + .queryP("select * from email_validations where email = ($1);", [email]) + // Argument of type '(rows: string | any[]) => boolean' is not assignable to parameter of type '(value: unknown) => boolean | PromiseLike'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + .then(function (rows: string | any[]) { + return rows.length > 0; + }) + ); } - function handle_GET_verification(req, res) { + function handle_GET_verification( + req: { p: { e: any } }, + res: { + set: (arg0: string, arg1: string) => void; + send: (arg0: string) => void; + } + ) { let einvite = req.p.e; pgQueryP("select * from einvites where einvite = ($1);", [einvite]) - .then(function (rows) { + // Argument of type '(rows: string | any[]) => Promise' is not assignable to parameter of type '(value: unknown) => unknown'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + .then(function (rows: string | any[]) { if (!rows.length) { fail(res, 500, "polis_err_verification_missing"); } @@ -3486,7 +4293,12 @@ Thank you for using Polis`; return pgQueryP( "select email from email_validations where email = ($1);", [email] - ).then(function (rows) { + // Argument of type '(rows: string | any[]) => true | Promise' is not assignable to parameter of type '(value: unknown) => unknown'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + ).then(function (rows: string | any[]) { if (rows && rows.length > 0) { return true; } @@ -3506,19 +4318,25 @@ Email verified! You can close this tab or hit the back button. ` ); }) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_verification", err); }); } - function paramsToStringSortedByName(params) { - let pairs = _.pairs(params).sort(function (a, b) { + function paramsToStringSortedByName(params: { + conversation_id?: any; + email?: any; + }) { + // Argument of type '(a: number[], b: number[]) => boolean' is not assignable to parameter of type '(a: ["email" | "conversation_id", any], b: ["email" | "conversation_id", any]) => number'. + // Type 'boolean' is not assignable to type 'number'.ts(2345) + // @ts-ignore + let pairs = _.pairs(params).sort(function (a: number[], b: number[]) { return a[0] > b[0]; }); - pairs = pairs.map(function (pair) { + const pairsList = pairs.map(function (pair: any[]) { return pair.join("="); }); - return pairs.join("&"); + return pairsList.join("&"); } // // units are seconds @@ -3528,7 +4346,10 @@ Email verified! You can close this tab or hit the back button. let HMAC_SIGNATURE_PARAM_NAME = "signature"; - function createHmacForQueryParams(path, params) { + function createHmacForQueryParams( + path: string, + params: { conversation_id?: any; email?: any } + ) { path = path.replace(/\/$/, ""); // trim trailing "/" let s = path + "?" + paramsToStringSortedByName(params); let hmac = crypto.createHmac( @@ -3542,8 +4363,11 @@ Email verified! You can close this tab or hit the back button. return hash; } - function verifyHmacForQueryParams(path, params) { - return new Promise(function (resolve, reject) { + function verifyHmacForQueryParams( + path: string, + params: { [x: string]: any; conversation_id?: any; email?: any } + ) { + return new Promise(function (resolve: () => void, reject: () => void) { params = _.clone(params); let hash = params[HMAC_SIGNATURE_PARAM_NAME]; delete params[HMAC_SIGNATURE_PARAM_NAME]; @@ -3560,8 +4384,11 @@ Email verified! You can close this tab or hit the back button. }); } - function sendEmailByUid(uid, subject, body) { - return getUserInfoForUid2(uid).then(function (userInfo) { + function sendEmailByUid(uid?: any, subject?: string, body?: string | number) { + return getUserInfoForUid2(uid).then(function (userInfo: { + hname: any; + email: any; + }) { return sendTextEmail( POLIS_FROM_ADDRESS, userInfo.hname @@ -3573,7 +4400,14 @@ Email verified! You can close this tab or hit the back button. }); } - function handle_GET_participants(req, res) { + function handle_GET_participants( + req: { p: { uid?: any; zid: any } }, + res: { + status: ( + arg0: number + ) => { (): any; new (): any; json: { (arg0: any): void; new (): any } }; + } + ) { // let pid = req.p.pid; let uid = req.p.uid; let zid = req.p.zid; @@ -3582,11 +4416,16 @@ Email verified! You can close this tab or hit the back button. "select * from participants where uid = ($1) and zid = ($2)", [uid, zid] ) - .then(function (rows) { + // Argument of type '(rows: string | any[]) => void' is not assignable to parameter of type '(value: unknown) => void | PromiseLike'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + .then(function (rows: string | any[]) { let ptpt = (rows && rows.length && rows[0]) || null; res.status(200).json(ptpt); }) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_get_participant", err); }); @@ -3622,12 +4461,23 @@ Email verified! You can close this tab or hit the back button. // }); } - function handle_GET_dummyButton(req, res) { + function handle_GET_dummyButton( + req: { p: { button: string; uid: string } }, + res: { + status: ( + arg0: number + ) => { (): any; new (): any; end: { (): void; new (): any } }; + } + ) { let message = req.p.button + " " + req.p.uid; emailFeatureRequest(message); res.status(200).end(); } - function doGetConversationsRecent(req, res, field) { + function doGetConversationsRecent( + req: { p: { uid?: any; sinceUnixTimestamp: any } }, + res: { json: (arg0: any) => void }, + field: string + ) { if (!isPolisDev(req.p.uid)) { fail(res, 403, "polis_err_no_access_for_this_user"); return; @@ -3643,58 +4493,77 @@ Email verified! You can close this tab or hit the back button. "select * from conversations where " + field + " >= ($1);", [time] ) - .then((rows) => { + .then((rows: any) => { res.json(rows); }) - .catch((err) => { + .catch((err: any) => { fail(res, 403, "polis_err_conversationsRecent", err); }); } - function handle_GET_conversationsRecentlyStarted(req, res) { + function handle_GET_conversationsRecentlyStarted(req: any, res: any) { doGetConversationsRecent(req, res, "created"); } - function handle_GET_conversationsRecentActivity(req, res) { + function handle_GET_conversationsRecentActivity(req: any, res: any) { doGetConversationsRecent(req, res, "modified"); } - function userHasAnsweredZeQuestions(zid, answers) { + function userHasAnsweredZeQuestions(zid: any, answers: string | any[]) { + // 'new' expression, whose target lacks a construct signature, implicitly has an 'any' type.ts(7009) + // @ts-ignore return new MPromise( "userHasAnsweredZeQuestions", - function (resolve, reject) { - getAnswersForConversation(zid, function (err, available_answers) { - if (err) { - reject(err); - return; - } + // Argument of type '(resolve: () => any, reject: (arg0: Error) => void) => void' + // is not assignable to parameter of type '(resolve: (value: unknown) => void, reject: (reason?: any) => void) => void'. + // Types of parameters 'resolve' and 'resolve' are incompatible.ts(2345) + // @ts-ignore + function (resolve: () => any, reject: (arg0: Error) => void) { + getAnswersForConversation( + zid, + function (err: any, available_answers: any) { + if (err) { + reject(err); + return; + } - let q2a = _.indexBy(available_answers, "pmqid"); - let a2q = _.indexBy(available_answers, "pmaid"); - for (var i = 0; i < answers.length; i++) { - let pmqid = a2q[answers[i]].pmqid; - delete q2a[pmqid]; - } - let remainingKeys = _.keys(q2a); - let missing = remainingKeys && remainingKeys.length > 0; - if (missing) { - return reject( - new Error( - "polis_err_metadata_not_chosen_pmqid_" + remainingKeys[0] - ) - ); - } else { - return resolve(); + let q2a = _.indexBy(available_answers, "pmqid"); + let a2q = _.indexBy(available_answers, "pmaid"); + for (var i = 0; i < answers.length; i++) { + let pmqid = a2q[answers[i]].pmqid; + delete q2a[pmqid]; + } + let remainingKeys = _.keys(q2a); + let missing = remainingKeys && remainingKeys.length > 0; + if (missing) { + return reject( + new Error( + "polis_err_metadata_not_chosen_pmqid_" + remainingKeys[0] + ) + ); + } else { + return resolve(); + } } - }); + ); } ); } - function handle_POST_participants(req, res) { + function handle_POST_participants( + req: { + p: { zid: any; uid?: any; answers: any; parent_url: any; referrer: any }; + cookies: { [x: string]: any }; + }, + res: { + status: ( + arg0: number + ) => { (): any; new (): any; json: { (arg0: any): void; new (): any } }; + } + ) { let zid = req.p.zid; let uid = req.p.uid; let answers = req.p.answers; - let info = {}; + let info: ParticipantInfo = {}; let parent_url = req.cookies[COOKIES.PARENT_URL] || req.p.parent_url; let referrer = req.cookies[COOKIES.PARENT_REFERRER] || req.p.referrer; @@ -3706,7 +4575,7 @@ Email verified! You can close this tab or hit the back button. info.referrer = referrer; } - function finish(ptpt) { + function finish(ptpt: any) { // Probably don't need pid cookies..? // function getZidToPidCookieKey(zid) { // return zid + "p"; @@ -3726,15 +4595,15 @@ Email verified! You can close this tab or hit the back button. userHasAnsweredZeQuestions(zid, answers).then( function () { joinConversation(zid, uid, info, answers).then( - function (ptpt) { + function (ptpt: any) { finish(ptpt); }, - function (err) { + function (err: any) { fail(res, 500, "polis_err_add_participant", err); } ); }, - function (err) { + function (err: { message: any }) { userFail(res, 400, err.message, err); } ); @@ -3743,7 +4612,7 @@ Email verified! You can close this tab or hit the back button. // Check if already in the conversation getParticipant(zid, req.p.uid) .then( - function (ptpt) { + function (ptpt: { pid: any }) { if (ptpt) { finish(ptpt); @@ -3758,11 +4627,16 @@ Email verified! You can close this tab or hit the back button. } getConversationInfo(zid) - .then(function (conv) { + .then(function (conv: { lti_users_only: any }) { if (conv.lti_users_only) { if (uid) { pgQueryP("select * from lti_users where uid = ($1)", [uid]) - .then(function (rows) { + // Argument of type '(rows: string | any[]) => void' is not assignable to parameter of type '(value: unknown) => void | PromiseLike'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + .then(function (rows: string | any[]) { if (rows && rows.length) { // found a record in lti_users doJoin(); @@ -3774,7 +4648,7 @@ Email verified! You can close this tab or hit the back button. ); } }) - .catch(function (err) { + .catch(function (err: any) { fail( res, 500, @@ -3794,7 +4668,7 @@ Email verified! You can close this tab or hit the back button. doJoin(); } }) - .catch(function (err) { + .catch(function (err: any) { fail( res, 500, @@ -3803,11 +4677,11 @@ Email verified! You can close this tab or hit the back button. ); }); }, - function (err) { + function (err: any) { fail(res, 500, "polis_err_post_participants_db_err", err); } ) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_post_participants_misc", err); }); } @@ -3815,7 +4689,7 @@ Email verified! You can close this tab or hit the back button. const addLtiUserIfNeeded = User.addLtiUserIfNeeded; const addLtiContextMembership = User.addLtiContextMembership; - function subscribeToNotifications(zid, uid, email) { + function subscribeToNotifications(zid: any, uid?: any, email?: any) { let type = 1; // 1 for email winston.log("info", "subscribeToNotifications", zid, uid); return pgQueryP( @@ -3825,30 +4699,30 @@ Email verified! You can close this tab or hit the back button. return pgQueryP( "update participants set subscribed = ($3) where zid = ($1) and uid = ($2);", [zid, uid, type] - ).then(function (rows) { + ).then(function (rows: any) { return type; }); }); } - function unsubscribeFromNotifications(zid, uid) { + function unsubscribeFromNotifications(zid: any, uid?: any) { let type = 0; // 1 for nothing return pgQueryP( "update participants set subscribed = ($3) where zid = ($1) and uid = ($2);", [zid, uid, type] - ).then(function (rows) { + ).then(function (rows: any) { return type; }); } - function addNotificationTask(zid) { + function addNotificationTask(zid: any) { return pgQueryP( "insert into notification_tasks (zid) values ($1) on conflict (zid) do update set modified = now_as_millis();", [zid] ); } - function maybeAddNotificationTask(zid, timeInMillis) { + function maybeAddNotificationTask(zid: any, timeInMillis: any) { return pgQueryP( "insert into notification_tasks (zid, modified) values ($1, $2) on conflict (zid) do nothing;", [zid, timeInMillis] @@ -3858,7 +4732,12 @@ Email verified! You can close this tab or hit the back button. function claimNextNotificationTask() { return pgQueryP( "delete from notification_tasks where zid = (select zid from notification_tasks order by random() for update skip locked limit 1) returning *;" - ).then((rows) => { + // Argument of type '(rows: string | any[]) => any' is not assignable to parameter of type '(value: unknown) => any'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + ).then((rows: string | any[]) => { if (!rows || !rows.length) { return null; } @@ -3867,177 +4746,234 @@ Email verified! You can close this tab or hit the back button. } function getDbTime() { - return pgQueryP("select now_as_millis();", []).then((rows) => { - return rows[0].now_as_millis; - }); + return pgQueryP("select now_as_millis();", []).then( + // Argument of type '(rows: { now_as_millis: any;}[]) => any' is not assignable to parameter of type '(value: unknown) => any'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type '{ now_as_millis: any; }[]'.ts(2345) + // @ts-ignore + (rows: { now_as_millis: any }[]) => { + return rows[0].now_as_millis; + } + ); } - function doNotificationsForZid(zid, timeOfLastEvent) { + function doNotificationsForZid(zid: any, timeOfLastEvent: any) { let shouldTryAgain = false; - return pgQueryP( - "select * from participants where zid = ($1) and last_notified < ($2) and subscribed > 0;", - [zid, timeOfLastEvent] - ) - .then((candidates) => { - if (!candidates || !candidates.length) { - return null; - } - candidates = candidates.map((ptpt) => { - ptpt.last_notified = Number(ptpt.last_notified); - ptpt.last_interaction = Number(ptpt.last_interaction); - return ptpt; - }); - return Promise.all([ - getDbTime(), - getConversationInfo(zid), - getZinvite(zid), - ]).then((a) => { - let dbTimeMillis = a[0]; - let conv = a[1]; - let conversation_id = a[2]; - - let url = conv.parent_url || "https://pol.is/" + conversation_id; - - let pid_to_ptpt = {}; - candidates.forEach((c) => { - pid_to_ptpt[c.pid] = c; - }); - return Promise.mapSeries(candidates, (item, index, length) => { - return getNumberOfCommentsRemaining(item.zid, item.pid).then( - (rows) => { - return rows[0]; + return ( + pgQueryP( + "select * from participants where zid = ($1) and last_notified < ($2) and subscribed > 0;", + [zid, timeOfLastEvent] + ) + // Argument of type '(candidates: any[]) => Promise<{ pid: string | number; remaining: any; }[] + // | null > | null' is not assignable to parameter of type '(value: unknown) => { pid: string | number; remaining: any; } [] + // | PromiseLike<{ pid: string | number; remaining: any; }[] | null> | null'. + // Types of parameters 'candidates' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + .then((candidates: any[]) => { + if (!candidates || !candidates.length) { + return null; + } + candidates = candidates.map( + (ptpt: { last_notified: number; last_interaction: number }) => { + ptpt.last_notified = Number(ptpt.last_notified); + ptpt.last_interaction = Number(ptpt.last_interaction); + return ptpt; + } + ); + return Promise.all([ + getDbTime(), + getConversationInfo(zid), + getZinvite(zid), + ]).then((a: any[]) => { + let dbTimeMillis = a[0]; + let conv = a[1]; + let conversation_id = a[2]; + + let url = conv.parent_url || "https://pol.is/" + conversation_id; + + let pid_to_ptpt = {}; + candidates.forEach((c: { pid: string | number }) => { + // Element implicitly has an 'any' type because expression of type 'string | number' can't be used to index type '{}'. + // No index signature with a parameter of type 'string' was found on type '{}'.ts(7053) + // @ts-ignore + pid_to_ptpt[c.pid] = c; + }); + return Promise.mapSeries( + candidates, + (item: { zid: any; pid: any }, index: any, length: any) => { + return getNumberOfCommentsRemaining(item.zid, item.pid).then( + // Argument of type '(rows: any[]) => any' is not assignable to parameter of type '(value: unknown) => any'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + (rows: any[]) => { + return rows[0]; + } + ); } - ); - }).then((results) => { - const needNotification = results.filter((result) => { - let ptpt = pid_to_ptpt[result.pid]; - let needs = true; + ).then((results: any[]) => { + const needNotification = results.filter( + (result: { pid: string | number; remaining: number }) => { + // Element implicitly has an 'any' type because expression of type 'string | number' can't be used to index type '{}'. + // No index signature with a parameter of type 'string' was found on type '{}'.ts(7053) + // @ts-ignore + let ptpt = pid_to_ptpt[result.pid]; + let needs = true; + + needs = needs && result.remaining > 0; + + // if (needs && result.remaining < 5) { + // // no need to try again for this user since new comments will create new tasks + // console.log('doNotificationsForZid', 'not enough remaining'); + // needs = false; + // } + + let waitTime = 60 * 60 * 1000; + + // notifications since last interation + if (ptpt.nsli === 0) { + // first notification since last interaction + waitTime = 60 * 60 * 1000; // 1 hour + } else if (ptpt.nsli === 1) { + // second notification since last interaction + waitTime = 2 * 60 * 60 * 1000; // 4 hours + } else if (ptpt.nsli === 2) { + // third notification since last interaction + waitTime = 24 * 60 * 60 * 1000; // 24 hours + } else if (ptpt.nsli === 3) { + // third notification since last interaction + waitTime = 48 * 60 * 60 * 1000; // 48 hours + } else { + // give up, if they vote again nsli will be set to zero again. + console.log("doNotificationsForZid", "nsli"); + needs = false; + } - needs = needs && result.remaining > 0; + if (needs && dbTimeMillis < ptpt.last_notified + waitTime) { + // Limit to one per hour. + console.log( + "doNotificationsForZid", + "shouldTryAgain", + "last_notified" + ); + shouldTryAgain = true; + needs = false; + } + if ( + needs && + dbTimeMillis < ptpt.last_interaction + 5 * 60 * 1000 + ) { + // Wait until 5 minutes after their last interaction. + console.log( + "doNotificationsForZid", + "shouldTryAgain", + "last_interaction" + ); + shouldTryAgain = true; + needs = false; + } - // if (needs && result.remaining < 5) { - // // no need to try again for this user since new comments will create new tasks - // console.log('doNotificationsForZid', 'not enough remaining'); - // needs = false; - // } + if (devMode) { + needs = needs && isPolisDev(ptpt.uid); + } + return needs; + } + ); - let waitTime = 60 * 60 * 1000; - - // notifications since last interation - if (ptpt.nsli === 0) { - // first notification since last interaction - waitTime = 60 * 60 * 1000; // 1 hour - } else if (ptpt.nsli === 1) { - // second notification since last interaction - waitTime = 2 * 60 * 60 * 1000; // 4 hours - } else if (ptpt.nsli === 2) { - // third notification since last interaction - waitTime = 24 * 60 * 60 * 1000; // 24 hours - } else if (ptpt.nsli === 3) { - // third notification since last interaction - waitTime = 48 * 60 * 60 * 1000; // 48 hours - } else { - // give up, if they vote again nsli will be set to zero again. - console.log("doNotificationsForZid", "nsli"); - needs = false; + if (needNotification.length === 0) { + return null; } - - if (needs && dbTimeMillis < ptpt.last_notified + waitTime) { - // Limit to one per hour. - console.log( - "doNotificationsForZid", - "shouldTryAgain", - "last_notified" - ); - shouldTryAgain = true; - needs = false; - } - if ( - needs && - dbTimeMillis < ptpt.last_interaction + 5 * 60 * 1000 - ) { - // Wait until 5 minutes after their last interaction. - console.log( - "doNotificationsForZid", - "shouldTryAgain", - "last_interaction" + const pids = _.pluck(needNotification, "pid"); + + // return pgQueryP("select p.uid, p.pid, u.email from participants as p left join users as u on p.uid = u.uid where p.pid in (" + pids.join(",") + ")", []).then((rows) => { + + // }) + return pgQueryP( + "select uid, subscribe_email from participants_extended where uid in (select uid from participants where pid in (" + + pids.join(",") + + "));", + [] + // Argument of type '(rows: any[]) => Promise<{ pid: string | number; remaining: any; }[]>' + // is not assignable to parameter of type '(value: unknown) => { pid: string | number; remaining: any; }[] + // | PromiseLike < { pid: string | number; remaining: any; }[] > '. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + ).then((rows: any[]) => { + let uidToEmail = {}; + rows.forEach( + (row: { uid: string | number; subscribe_email: any }) => { + // Element implicitly has an 'any' type because expression of type 'string | number' can't be used to index type '{}'. + // No index signature with a parameter of type 'string' was found on type '{}'.ts(7053) + // @ts-ignore + uidToEmail[row.uid] = row.subscribe_email; + } ); - shouldTryAgain = true; - needs = false; - } - - if (devMode) { - needs = needs && isPolisDev(ptpt.uid); - } - return needs; - }); - if (needNotification.length === 0) { - return null; - } - const pids = _.pluck(needNotification, "pid"); - - // return pgQueryP("select p.uid, p.pid, u.email from participants as p left join users as u on p.uid = u.uid where p.pid in (" + pids.join(",") + ")", []).then((rows) => { - - // }) - return pgQueryP( - "select uid, subscribe_email from participants_extended where uid in (select uid from participants where pid in (" + - pids.join(",") + - "));", - [] - ).then((rows) => { - let uidToEmail = {}; - rows.forEach((row) => { - uidToEmail[row.uid] = row.subscribe_email; - }); - - return Promise.each(needNotification, (item, index, length) => { - const uid = pid_to_ptpt[item.pid].uid; - return sendNotificationEmail( - uid, - url, - conversation_id, - uidToEmail[uid], - item.remaining - ).then(() => { - return pgQueryP( - "update participants set last_notified = now_as_millis(), nsli = nsli + 1 where uid = ($1) and zid = ($2);", - [uid, zid] - ); - }); + return Promise.each( + needNotification, + ( + item: { pid: string | number; remaining: any }, + index: any, + length: any + ) => { + // Element implicitly has an 'any' type because expression of type 'string | number' can't be used to index type '{}'. + // No index signature with a parameter of type 'string' was found on type '{}'.ts(7053) + // @ts-ignore + const uid = pid_to_ptpt[item.pid].uid; + return sendNotificationEmail( + uid, + url, + conversation_id, + // Element implicitly has an 'any' type because expression of type 'string | number' can't be used to index type '{}'. + // No index signature with a parameter of type 'string' was found on type '{}'.ts(7053) + // @ts-ignore + uidToEmail[uid], + item.remaining + ).then(() => { + return pgQueryP( + "update participants set last_notified = now_as_millis(), nsli = nsli + 1 where uid = ($1) and zid = ($2);", + [uid, zid] + ); + }); + } + ); }); }); }); - }); - }) - .then(() => { - return shouldTryAgain; - }); + }) + .then(() => { + return shouldTryAgain; + }) + ); } function doNotificationBatch() { - return claimNextNotificationTask().then((task) => { - if (!task) { - return Promise.resolve(); - } - console.log("doNotificationsForZid", task.zid); - return doNotificationsForZid(task.zid, task.modified).then( - (shouldTryAgain) => { - console.log( - "doNotificationsForZid", - task.zid, - "shouldTryAgain", - shouldTryAgain - ); - if (shouldTryAgain) { - // Since we claimed the task above, there will be no record, so we need to - // put it back to trigger a retry - unless there's a new one there, in which case we should - // leave the new one. - maybeAddNotificationTask(task.zid, task.modified); - } + return claimNextNotificationTask().then( + (task: { zid: any; modified: any }) => { + if (!task) { + return Promise.resolve(); } - ); - }); + console.log("doNotificationsForZid", task.zid); + return doNotificationsForZid(task.zid, task.modified).then( + (shouldTryAgain: any) => { + console.log( + "doNotificationsForZid", + task.zid, + "shouldTryAgain", + shouldTryAgain + ); + if (shouldTryAgain) { + // Since we claimed the task above, there will be no record, so we need to + // put it back to trigger a retry - unless there's a new one there, in which case we should + // leave the new one. + maybeAddNotificationTask(task.zid, task.modified); + } + } + ); + } + ); } function doNotificationLoop() { @@ -4047,7 +4983,13 @@ Email verified! You can close this tab or hit the back button. }); } - function sendNotificationEmail(uid, url, conversation_id, email, remaining) { + function sendNotificationEmail( + uid?: any, + url?: string, + conversation_id?: string, + email?: any, + remaining?: any + ) { let subject = "New statements to vote on (conversation " + conversation_id + ")"; // Not sure if putting the conversation_id is ideal, but we need some way to ensure that the notifications for each conversation appear in separte threads. let body = "There are new statements available for you to vote on here:\n"; @@ -4071,12 +5013,15 @@ Email verified! You can close this tab or hit the back button. if (shouldSendNotifications) { doNotificationLoop(); } - function createNotificationsUnsubscribeUrl(conversation_id, email) { + function createNotificationsUnsubscribeUrl(conversation_id: any, email: any) { let params = { conversation_id: conversation_id, email: email, }; let path = "api/v3/notifications/unsubscribe"; + // Element implicitly has an 'any' type because expression of type 'string | number' can't be used to index type '{}'. + // No index signature with a parameter of type 'string' was found on type '{}'.ts(7053) + // @ts-ignore params[HMAC_SIGNATURE_PARAM_NAME] = createHmacForQueryParams(path, params); let server = "http://localhost:5000"; @@ -4086,12 +5031,15 @@ Email verified! You can close this tab or hit the back button. return server + "/" + path + "?" + paramsToStringSortedByName(params); } - function createNotificationsSubscribeUrl(conversation_id, email) { + function createNotificationsSubscribeUrl(conversation_id: any, email: any) { let params = { conversation_id: conversation_id, email: email, }; let path = "api/v3/notifications/subscribe"; + // Element implicitly has an 'any' type because expression of type 'string | number' can't be used to index type '{}'. + // No index signature with a parameter of type 'string' was found on type '{}'.ts(7053) + // @ts-ignore params[HMAC_SIGNATURE_PARAM_NAME] = createHmacForQueryParams(path, params); let server = "http://localhost:5000"; @@ -4101,13 +5049,24 @@ Email verified! You can close this tab or hit the back button. return server + "/" + path + "?" + paramsToStringSortedByName(params); } - function handle_GET_notifications_subscribe(req, res) { + function handle_GET_notifications_subscribe( + req: { + p: { [x: string]: any; zid: any; email: any; conversation_id: any }; + }, + res: { + set: (arg0: string, arg1: string) => void; + send: (arg0: string) => void; + } + ) { let zid = req.p.zid; let email = req.p.email; let params = { conversation_id: req.p.conversation_id, email: req.p.email, }; + // Element implicitly has an 'any' type because expression of type 'string | number' can't be used to index type '{}'. + // No index signature with a parameter of type 'string' was found on type '{}'.ts(7053) + // @ts-ignore params[HMAC_SIGNATURE_PARAM_NAME] = req.p[HMAC_SIGNATURE_PARAM_NAME]; verifyHmacForQueryParams("api/v3/notifications/subscribe", params) .then( @@ -4132,17 +5091,28 @@ Email verified! You can close this tab or hit the back button. fail(res, 403, "polis_err_subscribe_signature_mismatch"); } ) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_subscribe_misc", err); }); } - function handle_GET_notifications_unsubscribe(req, res) { + function handle_GET_notifications_unsubscribe( + req: { + p: { [x: string]: any; zid: any; email: any; conversation_id: any }; + }, + res: { + set: (arg0: string, arg1: string) => void; + send: (arg0: string) => void; + } + ) { let zid = req.p.zid; let email = req.p.email; let params = { conversation_id: req.p.conversation_id, email: email, }; + // Element implicitly has an 'any' type because expression of type 'string | number' can't be used to index type '{}'. + // No index signature with a parameter of type 'string' was found on type '{}'.ts(7053) + // @ts-ignore params[HMAC_SIGNATURE_PARAM_NAME] = req.p[HMAC_SIGNATURE_PARAM_NAME]; verifyHmacForQueryParams("api/v3/notifications/unsubscribe", params) .then( @@ -4167,18 +5137,29 @@ Email verified! You can close this tab or hit the back button. fail(res, 403, "polis_err_unsubscribe_signature_mismatch"); } ) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_unsubscribe_misc", err); }); } - function handle_POST_convSubscriptions(req, res) { + function handle_POST_convSubscriptions( + req: { p: { zid: any; uid?: any; type: any; email: any } }, + res: { + status: ( + arg0: number + ) => { + (): any; + new (): any; + json: { (arg0: { subscribed: any }): void; new (): any }; + }; + } + ) { let zid = req.p.zid; let uid = req.p.uid; let type = req.p.type; let email = req.p.email; - function finish(type) { + function finish(type: any) { res.status(200).json({ subscribed: type, }); @@ -4187,13 +5168,13 @@ Email verified! You can close this tab or hit the back button. if (type === 1) { subscribeToNotifications(zid, uid, email) .then(finish) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_sub_conv " + zid + " " + uid, err); }); } else if (type === 0) { unsubscribeFromNotifications(zid, uid) .then(finish) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_unsub_conv " + zid + " " + uid, err); }); } else { @@ -4206,7 +5187,23 @@ Email verified! You can close this tab or hit the back button. } } - function handle_POST_auth_login(req, res) { + function handle_POST_auth_login( + req: { + p: { + password: any; + email: string; + lti_user_id: any; + lti_user_image: any; + lti_context_id: any; + tool_consumer_instance_guid?: any; + afterJoinRedirectUrl: any; + }; + }, + res: { + redirect: (arg0: any) => void; + json: (arg0: { uid?: any; email: any; token: any }) => void; + } + ) { let password = req.p.password; let email = req.p.email || ""; let lti_user_id = req.p.lti_user_id; @@ -4223,32 +5220,33 @@ Email verified! You can close this tab or hit the back button. pgQuery( "SELECT * FROM users WHERE LOWER(email) = ($1);", [email], - function (err, docs) { - docs = docs.rows; + function (err: any, docs: { rows?: any[] }) { + const { rows } = docs; if (err) { fail(res, 403, "polis_err_login_unknown_user_or_password", err); console.error("polis_err_login_unknown_user_or_password_err"); return; } - if (!docs || docs.length === 0) { + if (!rows || rows.length === 0) { fail(res, 403, "polis_err_login_unknown_user_or_password_noresults"); console.error("polis_err_login_unknown_user_or_password_noresults"); return; } - let uid = docs[0].uid; + let uid = rows[0].uid; pgQuery( "select pwhash from jianiuevyew where uid = ($1);", [uid], - function (err, results) { - results = results.rows; + function (err: any, results: { rows: any[] }) { + // results: { pwhash: any }[] + const { rows } = results; if (err) { fail(res, 403, "polis_err_login_unknown_user_or_password", err); console.error("polis_err_login_unknown_user_or_password_err"); return; } - if (!results || results.length === 0) { + if (!results || rows.length === 0) { fail(res, 403, "polis_err_login_unknown_user_or_password"); console.error( "polis_err_login_unknown_user_or_password_noresults" @@ -4256,12 +5254,12 @@ Email verified! You can close this tab or hit the back button. return; } - let hashedPassword = results[0].pwhash; + let hashedPassword = rows[0].pwhash; bcrypt.compare( password, hashedPassword, - function (errCompare, result) { + function (errCompare: any, result: any) { winston.log("info", "errCompare, result", errCompare, result); if (errCompare || !result) { fail(res, 403, "polis_err_login_unknown_user_or_password"); @@ -4271,12 +5269,19 @@ Email verified! You can close this tab or hit the back button. return; } - startSession(uid, function (errSess, token) { + startSession(uid, function (errSess: any, token: any) { let response_data = { uid: uid, email: email, token: token, }; + // Argument of type '{ p: { password: any; email: string; lti_user_id: any; lti_user_image: any; + // lti_context_id: any; tool_consumer_instance_guid?: any; afterJoinRedirectUrl: any; }; }' is not assignable to parameter of type + // '{ cookies: { [x: string]: any; }; }'. + // Property 'cookies' is missing in type '{ p: { password: any; email: string; lti_user_id: any; + // lti_user_image: any; lti_context_id: any; tool_consumer_instance_guid?: any; afterJoinRedirectUrl: any; }; }' but required in type + // '{ cookies: { [x: string]: any; }; }'.ts(2345) + // @ts-ignore addCookies(req, res, token, uid) .then(function () { winston.log("info", "uid", uid); @@ -4303,6 +5308,13 @@ Email verified! You can close this tab or hit the back button. if (afterJoinRedirectUrl) { res.redirect(afterJoinRedirectUrl); } else { + // Argument of type '{ redirect: (arg0: any) => void; json: (arg0: { uid?: any; email: any; token: any; }) => void; }' + // is not assignable to parameter of type '{ set: (arg0: { "Content-Type": string; }) => void; status: + // (arg0: number) => { (): any; new (): any; send: { (arg0: string): void; new (): any; }; }; }'. + // Type '{ redirect: (arg0: any) => void; json: (arg0: { uid?: any; email: any; token: any; }) => void; }' + // is missing the following properties from type '{ set: (arg0: { "Content-Type": string; }) => void; + // status: (arg0: number) => { (): any; new (): any; send: { (arg0: string): void; new (): any; }; }; }': set, statusts(2345) + // @ts-ignore User.renderLtiLinkageSuccessPage(req, res, { // may include token here too context_id: lti_context_id, @@ -4315,7 +5327,7 @@ Email verified! You can close this tab or hit the back button. res.json(response_data); } }) - .catch(function (err) { + .catch(function (err: any) { fail( res, 500, @@ -4324,7 +5336,7 @@ Email verified! You can close this tab or hit the back button. ); }); }) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_adding_cookies", err); }); }); // startSession @@ -4336,7 +5348,28 @@ Email verified! You can close this tab or hit the back button. ); // users query } // /api/v3/auth/login - function handle_POST_joinWithInvite(req, res) { + function handle_POST_joinWithInvite( + req: { + p: { + answers: any; + uid?: any; + suzinvite: any; + permanentCookieToken: any; + zid: any; + referrer: any; + parent_url: any; + }; + }, + res: { + status: ( + arg0: number + ) => { + (): any; + new (): any; + json: { (arg0: { pid: any; uid?: any }): void; new (): any }; + }; + } + ) { // if they're already in the conv // this shouldn't get called // else @@ -4350,70 +5383,106 @@ Email verified! You can close this tab or hit the back button. // else // let them join without forcing a sign in (assuming conversation allows that) - return joinWithZidOrSuzinvite({ - answers: req.p.answers, - existingAuth: !!req.p.uid, - suzinvite: req.p.suzinvite, - permanentCookieToken: req.p.permanentCookieToken, - uid: req.p.uid, - zid: req.p.zid, // since the zid is looked up using the conversation_id, it's safe to use zid as an invite token. TODO huh? - referrer: req.p.referrer, - parent_url: req.p.parent_url, - }) - .then(function (o) { - let uid = o.uid; - winston.log( - "info", - "startSessionAndAddCookies " + uid + " existing " + o.existingAuth - ); - // TODO check for possible security implications - if (!o.existingAuth) { - return startSessionAndAddCookies(req, res, uid).then(function () { - return o; - }); - } - return Promise.resolve(o); + return ( + joinWithZidOrSuzinvite({ + answers: req.p.answers, + existingAuth: !!req.p.uid, + suzinvite: req.p.suzinvite, + permanentCookieToken: req.p.permanentCookieToken, + uid: req.p.uid, + zid: req.p.zid, // since the zid is looked up using the conversation_id, it's safe to use zid as an invite token. TODO huh? + referrer: req.p.referrer, + parent_url: req.p.parent_url, }) - .then(function (o) { - winston.log("info", "permanentCookieToken", o.permanentCookieToken); - if (o.permanentCookieToken) { - return recordPermanentCookieZidJoin( - o.permanentCookieToken, - o.zid - ).then( - function () { - return o; - }, - function () { - return o; - } + // No overload matches this call. + // Overload 1 of 2, '(onFulfill?: ((value: unknown) => Resolvable<{ uid?: any; existingAuth: string; }>) | undefined, onReject?: ((error: any) => Resolvable<{ uid?: any; existingAuth: string; }>) | undefined): Bluebird<...>', gave the following error. + // Argument of type '(o: { uid?: any; existingAuth: string; }) => Bluebird<{ uid?: any; existingAuth: string; }>' is not assignable to parameter of type '(value: unknown) => Resolvable<{ uid?: any; existingAuth: string; }>'. + // Types of parameters 'o' and 'value' are incompatible. + // Type 'unknown' is not assignable to type '{ uid?: any; existingAuth: string; }'. + // Overload 2 of 2, '(onfulfilled?: ((value: unknown) => Resolvable<{ uid?: any; existingAuth: string; }>) | null | undefined, onrejected?: ((reason: any) => PromiseLike) | null | undefined): Bluebird<...>', gave the following error. + // Argument of type '(o: { uid?: any; existingAuth: string; }) => Bluebird<{ uid?: any; existingAuth: string; }>' is not assignable to parameter of type '(value: unknown) => Resolvable<{ uid?: any; existingAuth: string; }>'. + // Types of parameters 'o' and 'value' are incompatible. + // Type 'unknown' is not assignable to type '{ uid?: any; existingAuth: string; }'.ts(2769) + // @ts-ignore + .then(function (o: { uid?: any; existingAuth: string }) { + let uid = o.uid; + winston.log( + "info", + "startSessionAndAddCookies " + uid + " existing " + o.existingAuth ); - } else { - return o; - } - }) - .then(function (o) { - let pid = o.pid; - res.status(200).json({ - pid: pid, - uid: req.p.uid, - }); - }) - .catch(function (err) { - if ( - err && - err.message && - err.message.match(/polis_err_need_full_user/) - ) { - userFail(res, 403, err.message, err); - } else if (err && err.message) { - fail(res, 500, err.message, err); - } else if (err) { - fail(res, 500, "polis_err_joinWithZidOrSuzinvite", err); - } else { - fail(res, 500, "polis_err_joinWithZidOrSuzinvite"); - } - }); + // TODO check for possible security implications + if (!o.existingAuth) { + return startSessionAndAddCookies(req, res, uid).then(function () { + return o; + }); + } + return Promise.resolve(o); + }) + // No overload matches this call. + // Overload 1 of 2, '(onFulfill?: ((value: unknown) => Resolvable<{ permanentCookieToken: any; zid: any; }>) | undefined, + // onReject ?: ((error: any) => Resolvable<{ permanentCookieToken: any; zid: any; }>) | undefined): Bluebird <...> ', gave the following error. + // Argument of type '(o: { permanentCookieToken: any; zid: any; }) => { permanentCookieToken: any; zid: any; } | + // Promise < { permanentCookieToken: any; zid: any; } > ' is not assignable to parameter of type '(value: unknown) => Resolvable < { permanentCookieToken: any; zid: any; } > '. + // Types of parameters 'o' and 'value' are incompatible. + // Type 'unknown' is not assignable to type '{ permanentCookieToken: any; zid: any; }'. + // Overload 2 of 2, '(onfulfilled?: ((value: unknown) => Resolvable<{ permanentCookieToken: any; zid: any; }>) | + // null | undefined, onrejected ?: ((reason: any) => PromiseLike) | null | undefined): Bluebird <...> ', gave the following error. + // Argument of type '(o: { permanentCookieToken: any; zid: any; }) => { permanentCookieToken: any; zid: any; } | + // Promise < { permanentCookieToken: any; zid: any; } > ' is not assignable to parameter of type '(value: unknown) => Resolvable < { permanentCookieToken: any; zid: any; } > '. + // Types of parameters 'o' and 'value' are incompatible. + // Type 'unknown' is not assignable to type '{ permanentCookieToken: any; zid: any; }'.ts(2769) + // @ts-ignore + .then(function (o: { permanentCookieToken: any; zid: any }) { + winston.log("info", "permanentCookieToken", o.permanentCookieToken); + if (o.permanentCookieToken) { + return recordPermanentCookieZidJoin( + o.permanentCookieToken, + o.zid + ).then( + function () { + return o; + }, + function () { + return o; + } + ); + } else { + return o; + } + }) + // No overload matches this call. + // Overload 1 of 2, '(onFulfill?: ((value: unknown) => Resolvable) | undefined, onReject?: ((error: any) => Resolvable) | undefined): Bluebird', gave the following error. + // Argument of type '(o: { pid: any; }) => void' is not assignable to parameter of type '(value: unknown) => Resolvable'. + // Types of parameters 'o' and 'value' are incompatible. + // Type 'unknown' is not assignable to type '{ pid: any; }'. + // Overload 2 of 2, '(onfulfilled?: ((value: unknown) => Resolvable) | null | undefined, onrejected?: ((reason: any) => PromiseLike) | null | undefined): Bluebird', gave the following error. + // Argument of type '(o: { pid: any; }) => void' is not assignable to parameter of type '(value: unknown) => Resolvable'. + // Types of parameters 'o' and 'value' are incompatible. + // Type 'unknown' is not assignable to type '{ pid: any; }'.ts(2769) + // @ts-ignore + .then(function (o: { pid: any }) { + let pid = o.pid; + res.status(200).json({ + pid: pid, + uid: req.p.uid, + }); + }) + .catch(function (err: { message: string }) { + if ( + err && + err.message && + err.message.match(/polis_err_need_full_user/) + ) { + userFail(res, 403, err.message, err); + } else if (err && err.message) { + fail(res, 500, err.message, err); + } else if (err) { + fail(res, 500, "polis_err_joinWithZidOrSuzinvite", err); + } else { + fail(res, 500, "polis_err_joinWithZidOrSuzinvite"); + } + }) + ); } // Test for deadlock condition // _.times(2, function() { @@ -4433,12 +5502,23 @@ Email verified! You can close this tab or hit the back button. // }, 10); // }); - function joinWithZidOrSuzinvite(o) { + function joinWithZidOrSuzinvite(o: { + answers: any; + existingAuth: boolean; + suzinvite: any; + permanentCookieToken: any; + uid?: any; + zid: any; // since the zid is looked up using the conversation_id, it's safe to use zid as an invite token. TODO huh? + referrer: any; + parent_url: any; + }) { return ( Promise.resolve(o) - .then(function (o) { + .then(function (o: { suzinvite: any; zid: any }) { if (o.suzinvite) { - return getSUZinviteInfo(o.suzinvite).then(function (suzinviteInfo) { + return getSUZinviteInfo(o.suzinvite).then(function ( + suzinviteInfo: any + ) { return Object.assign(o, suzinviteInfo); }); } else if (o.zid) { @@ -4447,20 +5527,26 @@ Email verified! You can close this tab or hit the back button. throw new Error("polis_err_missing_invite"); } }) - .then(function (o) { + .then(function (o: { zid: any; conv: any }) { winston.log("info", "joinWithZidOrSuzinvite convinfo begin"); - return getConversationInfo(o.zid).then(function (conv) { + return getConversationInfo(o.zid).then(function (conv: any) { winston.log("info", "joinWithZidOrSuzinvite convinfo done"); o.conv = conv; return o; }); }) - .then(function (o) { + .then(function (o: { lti_users_only: any; uid?: any }) { if (o.lti_users_only) { if (o.uid) { return pgQueryP("select * from lti_users where uid = ($1)", [ o.uid, - ]).then(function (rows) { + // Argument of type '(rows: string | any[]) => { lti_users_only: any; uid?: any; }' is not assignable to parameter of type + // '(value: unknown) => { lti_users_only: any; uid?: any; } | PromiseLike<{ lti_users_only: any; uid?: any; }>'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + ]).then(function (rows: string | any[]) { if (rows && rows.length) { return o; } else { @@ -4474,13 +5560,23 @@ Email verified! You can close this tab or hit the back button. return o; } }) - .then(function (o) { + // No overload matches this call. + // Overload 1 of 2, '(onFulfill?: ((value: unknown) => any) | undefined, onReject?: ((error: any) => any) | undefined): Bluebird', gave the following error. + // Argument of type '(o: { uid?: any; user: any; }) => any' is not assignable to parameter of type '(value: unknown) => any'. + // Types of parameters 'o' and 'value' are incompatible. + // Type 'unknown' is not assignable to type '{ uid?: any; user: any; }'. + // Overload 2 of 2, '(onfulfilled?: ((value: unknown) => any) | null | undefined, onrejected?: ((reason: any) => PromiseLike) | null | undefined): Bluebird', gave the following error. + // Argument of type '(o: { uid?: any; user: any; }) => any' is not assignable to parameter of type '(value: unknown) => any'. + // Types of parameters 'o' and 'value' are incompatible. + // Type 'unknown' is not assignable to type '{ uid?: any; user: any; }'.ts(2769) + // @ts-ignore + .then(function (o: { uid?: any; user: any }) { winston.log("info", "joinWithZidOrSuzinvite userinfo begin"); if (!o.uid) { winston.log("info", "joinWithZidOrSuzinvite userinfo nope"); return o; } - return getUserInfoForUid2(o.uid).then(function (user) { + return getUserInfoForUid2(o.uid).then(function (user: any) { winston.log("info", "joinWithZidOrSuzinvite userinfo done"); o.user = user; return o; @@ -4498,26 +5594,53 @@ Email verified! You can close this tab or hit the back button. // } // return o; // }) - .then(function (o) { + // @ts-ignore + .then(function (o: { uid?: any }) { // winston.log("info","joinWithZidOrSuzinvite check email done"); if (o.uid) { return o; } else { - return createDummyUser().then(function (uid) { + return createDummyUser().then(function (uid?: any) { return Object.assign(o, { uid: uid, }); }); } }) - .then(function (o) { + // No overload matches this call. + // Overload 1 of 2, '(onFulfill?: ((value: unknown) => any) | undefined, onReject?: ((error: any) => any) | undefined): Bluebird', gave the following error. + // Argument of type '(o: { zid: any; answers: any; }) => any' is not assignable to parameter of type '(value: unknown) => any'. + // Types of parameters 'o' and 'value' are incompatible. + // Type 'unknown' is not assignable to type '{ zid: any; answers: any; }'. + // Overload 2 of 2, '(onfulfilled?: ((value: unknown) => any) | null | undefined, onrejected?: ((reason: any) => PromiseLike) | null | undefined): Bluebird', gave the following error. + // Argument of type '(o: { zid: any; answers: any; }) => any' is not assignable to parameter of type '(value: unknown) => any'. + // Types of parameters 'o' and 'value' are incompatible. + // Type 'unknown' is not assignable to type '{ zid: any; answers: any; }'.ts(2769) + // @ts-ignore + .then(function (o: { zid: any; answers: any }) { return userHasAnsweredZeQuestions(o.zid, o.answers).then(function () { // looks good, pass through return o; }); }) - .then(function (o) { - let info = {}; + // No overload matches this call. + // Overload 1 of 2, '(onFulfill?: ((value: unknown) => any) | undefined, onReject?: ((error: any) => any) | undefined): Bluebird', gave the following error. + // Argument of type '(o: { referrer: any; parent_url: any; zid: any; uid?: any; answers: any; }) => any' is not assignable to parameter of type '(value: unknown) => any'. + // Types of parameters 'o' and 'value' are incompatible. + // Type 'unknown' is not assignable to type '{ referrer: any; parent_url: any; zid: any; uid?: any; answers: any; }'. + // Overload 2 of 2, '(onfulfilled?: ((value: unknown) => any) | null | undefined, onrejected?: ((reason: any) => PromiseLike) | null | undefined): Bluebird', gave the following error. + // Argument of type '(o: { referrer: any; parent_url: any; zid: any; uid?: any; answers: any; }) => any' is not assignable to parameter of type '(value: unknown) => any'. + // Types of parameters 'o' and 'value' are incompatible. + // Type 'unknown' is not assignable to type '{ referrer: any; parent_url: any; zid: any; uid?: any; answers: any; }'.ts(2769) + // @ts-ignore + .then(function (o: { + referrer: any; + parent_url: any; + zid: any; + uid?: any; + answers: any; + }) { + let info: ParticipantInfo = {}; if (o.referrer) { info.referrer = o.referrer; } @@ -4526,17 +5649,37 @@ Email verified! You can close this tab or hit the back button. } // TODO_REFERRER add info as third arg return joinConversation(o.zid, o.uid, info, o.answers).then(function ( - ptpt + ptpt: any ) { return Object.assign(o, ptpt); }); }) - .then(function (o) { + // No overload matches this call. + // Overload 1 of 2, '(onFulfill?: ((value: unknown) => Resolvable<{ xid: any; conv: { org_id: any; use_xid_whitelist: any; owner: any; }; + // uid?: any; } | undefined>) | undefined, onReject?: ((error: any) => Resolvable<{ xid: any; conv: { ...; }; uid?: any; } | undefined>) | undefined): Bluebird<...>', gave the following error. + // Argument of type '(o: { xid: any; conv: { org_id: any; use_xid_whitelist: any; owner: any; }; uid?: any; }) => + // { xid: any; conv: { org_id: any; use_xid_whitelist: any; owner: any; }; uid ?: any; } | Promise < { xid: any; conv: { org_id: any; use_xid_whitelist: any; owner: any; }; uid?: any; } | + // undefined > ' is not assignable to parameter of type '(value: unknown) => Resolvable < { xid: any; conv: { org_id: any; use_xid_whitelist: any; owner: any; }; uid?: any; } | undefined > '. + // Types of parameters 'o' and 'value' are incompatible. + // Type 'unknown' is not assignable to type '{ xid: any; conv: { org_id: any; use_xid_whitelist: any; owner: any; }; uid?: any; }'. + // Overload 2 of 2, '(onfulfilled?: ((value: unknown) => Resolvable<{ xid: any; conv: { org_id: any; use_xid_whitelist: any; owner: any; }; uid?: any; } + // | undefined >) | null | undefined, onrejected ?: ((reason: any) => PromiseLike) | null | undefined): Bluebird <...> ', gave the following error. + // Argument of type '(o: { xid: any; conv: { org_id: any; use_xid_whitelist: any; owner: any; }; uid?: any; }) => + // { xid: any; conv: { org_id: any; use_xid_whitelist: any; owner: any; }; uid ?: any; } | Promise < { xid: any; conv: { org_id: any; use_xid_whitelist: any; owner: any; }; uid?: any; } + // | undefined > ' is not assignable to parameter of type '(value: unknown) => Resolvable < { xid: any; conv: { org_id: any; use_xid_whitelist: any; owner: any; }; uid?: any; } | undefined > '. + // Types of parameters 'o' and 'value' are incompatible. + // Type 'unknown' is not assignable to type '{ xid: any; conv: { org_id: any; use_xid_whitelist: any; owner: any; }; uid?: any; }'.ts(2769) + // @ts-ignore + .then(function (o: { + xid: any; + conv: { org_id: any; use_xid_whitelist: any; owner: any }; + uid?: any; + }) { if (o.xid) { // used for suzinvite case return xidExists(o.xid, o.conv.org_id, o.uid).then(function ( - exists + exists: any ) { if (exists) { // skip creating the entry (workaround for posgres's lack of upsert) @@ -4545,7 +5688,7 @@ Email verified! You can close this tab or hit the back button. var shouldCreateXidEntryPromise = o.conv.use_xid_whitelist ? isXidWhitelisted(o.conv.owner, o.xid) : Promise.resolve(true); - shouldCreateXidEntryPromise.then((should) => { + shouldCreateXidEntryPromise.then((should: any) => { if (should) { return createXidEntry(o.xid, o.conv.org_id, o.uid).then( function () { @@ -4561,7 +5704,17 @@ Email verified! You can close this tab or hit the back button. return o; } }) - .then(function (o) { + // No overload matches this call. + // Overload 1 of 2, '(onFulfill?: ((value: unknown) => Resolvable<{ suzinvite: any; }>) | undefined, onReject?: ((error: any) => Resolvable<{ suzinvite: any; }>) | undefined): Bluebird<{ suzinvite: any; }>', gave the following error. + // Argument of type '(o: { suzinvite: any; }) => { suzinvite: any; } | Bluebird<{ suzinvite: any; }>' is not assignable to parameter of type '(value: unknown) => Resolvable<{ suzinvite: any; }>'. + // Types of parameters 'o' and 'value' are incompatible. + // Type 'unknown' is not assignable to type '{ suzinvite: any; }'. + // Overload 2 of 2, '(onfulfilled?: ((value: unknown) => Resolvable<{ suzinvite: any; }>) | null | undefined, onrejected?: ((reason: any) => PromiseLike) | null | undefined): Bluebird<...>', gave the following error. + // Argument of type '(o: { suzinvite: any; }) => { suzinvite: any; } | Bluebird<{ suzinvite: any; }>' is not assignable to parameter of type '(value: unknown) => Resolvable<{ suzinvite: any; }>'. + // Types of parameters 'o' and 'value' are incompatible. + // Type 'unknown' is not assignable to type '{ suzinvite: any; }'.ts(2769) + // @ts-ignore + .then(function (o: { suzinvite: any }) { if (o.suzinvite) { return deleteSuzinvite(o.suzinvite).then(function () { return o; @@ -4572,9 +5725,12 @@ Email verified! You can close this tab or hit the back button. }) ); } - function startSessionAndAddCookies(req, res, uid) { - return new Promise(function (resolve, reject) { - startSession(uid, function (err, token) { + function startSessionAndAddCookies(req: any, res: any, uid?: any) { + return new Promise(function ( + resolve: (arg0: any) => void, + reject: (arg0: Error) => void + ) { + startSession(uid, function (err: any, token: any) { if (err) { reject(new Error("polis_err_reg_failed_to_start_session")); return; @@ -4584,7 +5740,7 @@ Email verified! You can close this tab or hit the back button. }); } - function deleteFacebookUserRecord(o) { + function deleteFacebookUserRecord(o: { uid?: any }) { if (!isPolisDev(o.uid)) { // limit to test accounts for now return Promise.reject("polis_err_not_implemented"); @@ -4592,7 +5748,19 @@ Email verified! You can close this tab or hit the back button. return pgQueryP("delete from facebook_users where uid = ($1);", [o.uid]); } - function createFacebookUserRecord(o) { + function createFacebookUserRecord( + o: { uid?: any } & { + // uid provided later + fb_user_id: any; + fb_public_profile: any; + fb_login_status: any; + // fb_auth_response: fb_auth_response, + fb_access_token: any; + fb_granted_scopes: any; + fb_friends_response: any; + response: any; + } + ) { winston.log("info", "createFacebookUserRecord"); winston.log("info", "createFacebookUserRecord", JSON.stringify(o)); winston.log("info", o); @@ -4622,7 +5790,19 @@ Email verified! You can close this tab or hit the back button. ); } - function updateFacebookUserRecord(o) { + function updateFacebookUserRecord( + o: { uid?: any } & { + // uid provided later + fb_user_id: any; + fb_public_profile: any; + fb_login_status: any; + // fb_auth_response: fb_auth_response, + fb_access_token: any; + fb_granted_scopes: any; + fb_friends_response: any; + response: any; + } + ) { let profileInfo = o.fb_public_profile; let fb_public_profile_string = JSON.stringify(o.fb_public_profile); // Create facebook user record @@ -4646,12 +5826,12 @@ Email verified! You can close this tab or hit the back button. ); } - function addFacebookFriends(uid, fb_friends_response) { - let fbFriendIds = fb_friends_response - .map(function (friend) { + function addFacebookFriends(uid?: any, fb_friends_response?: any[]) { + let fbFriendIds = (fb_friends_response || []) + .map(function (friend: { id: string }) { return friend.id + ""; }) - .filter(function (id) { + .filter(function (id: string) { // NOTE: would just store facebook IDs as numbers, but they're too big for JS numbers. let hasNonNumericalCharacters = /[^0-9]/.test(id); if (hasNonNumericalCharacters) { @@ -4661,7 +5841,7 @@ Email verified! You can close this tab or hit the back button. } return !hasNonNumericalCharacters; }) - .map(function (id) { + .map(function (id: string) { return "'" + id + "'"; // wrap in quotes to force pg to treat them as strings }); if (!fbFriendIds.length) { @@ -4678,35 +5858,46 @@ Email verified! You can close this tab or hit the back button. } } - function handle_GET_perfStats(req, res) { + function handle_GET_perfStats(req: any, res: { json: (arg0: any) => void }) { res.json(METRICS_IN_RAM); } - function getFirstForPid(votes) { + function getFirstForPid(votes: string | any[]) { let seen = {}; let len = votes.length; let firstVotes = []; for (var i = 0; i < len; i++) { let vote = votes[i]; + // Element implicitly has an 'any' type because expression of type 'string | number' can't be used to index type '{}'. + // No index signature with a parameter of type 'string' was found on type '{}'.ts(7053) + // @ts-ignore if (!seen[vote.pid]) { firstVotes.push(vote); + // Element implicitly has an 'any' type because expression of type 'string | number' can't be used to index type '{}'. + // No index signature with a parameter of type 'string' was found on type '{}'.ts(7053) + // @ts-ignore seen[vote.pid] = true; } } return firstVotes; } function isParentDomainWhitelisted( - domain, - zid, - isWithinIframe, - domain_whitelist_override_key + domain: string, + zid: any, + isWithinIframe: any, + domain_whitelist_override_key: any ) { return pgQueryP_readOnly( "select * from site_domain_whitelist where site_id = " + "(select site_id from users where uid = " + "(select owner from conversations where zid = ($1)));", [zid] - ).then(function (rows) { + // Argument of type '(rows: string | any[]) => boolean' is not assignable to parameter of type '(value: unknown) => boolean | PromiseLike'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + ).then(function (rows: string | any[]) { console.log("isParentDomainWhitelisted", domain, zid, isWithinIframe); if (!rows || !rows.length || !rows[0].domain_whitelist.length) { // there is no whitelist, so any domain is ok. @@ -4782,30 +5973,37 @@ Email verified! You can close this tab or hit the back button. return ok; }); } - function denyIfNotFromWhitelistedDomain(req, res, next) { + function denyIfNotFromWhitelistedDomain( + req: { + headers?: { referrer: string }; + p: { zid: any; domain_whitelist_override_key: any }; + }, + res: { send: (arg0: number, arg1: string) => void }, + next: (arg0?: string) => void + ) { let isWithinIframe = req.headers && - req.headers.referer && - req.headers.referer.includes("parent_url"); + req.headers.referrer && + req.headers.referrer.includes("parent_url"); // res.status(403); // next("polis_err_domain"); // return; - let ref = req.headers.referer; + let ref = req?.headers?.referrer; + let refParts: string[] = []; + let resultRef = ""; if (isWithinIframe) { if (ref) { - ref = decodeURIComponent( + const decodedRefString = decodeURIComponent( ref.replace(/.*parent_url=/, "").replace(/&.*/, "") ); - - ref = ref && ref.length && ref.split("/"); - ref = ref && ref.length >= 3 && ref[2]; - ref = ref || ""; + if (decodedRefString && decodedRefString.length) + refParts = decodedRefString.split("/"); + resultRef = (refParts && refParts.length >= 3 && refParts[2]) || ""; } } else { - ref = ref && ref.length && ref.split("/"); - ref = ref && ref.length >= 3 && ref[2]; - ref = ref || ""; + if (ref && ref.length) refParts = ref.split("/"); + if (refParts && refParts.length >= 3) resultRef = refParts[2] || ""; } // let path = req.path; // path = path && path.split('/'); @@ -4813,12 +6011,12 @@ Email verified! You can close this tab or hit the back button. let zid = req.p.zid; isParentDomainWhitelisted( - ref, + resultRef, zid, isWithinIframe, req.p.domain_whitelist_override_key ) - .then(function (isOk) { + .then(function (isOk: any) { if (isOk) { next(); } else { @@ -4826,19 +6024,24 @@ Email verified! You can close this tab or hit the back button. next("polis_err_domain"); } }) - .catch(function (err) { + .catch(function (err: any) { console.error(err); res.send(403, "polis_err_domain"); next("polis_err_domain_misc"); }); } - function setDomainWhitelist(uid, newWhitelist) { + function setDomainWhitelist(uid?: any, newWhitelist?: any) { // TODO_UPSERT return pgQueryP( "select * from site_domain_whitelist where site_id = (select site_id from users where uid = ($1));", [uid] - ).then(function (rows) { + // Argument of type '(rows: string | any[]) => Promise' is not assignable to parameter of type '(value: unknown) => unknown'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + ).then(function (rows: string | any[]) { if (!rows || !rows.length) { return pgQueryP( "insert into site_domain_whitelist (site_id, domain_whitelist) values ((select site_id from users where uid = ($1)), $2);", @@ -4853,40 +6056,73 @@ Email verified! You can close this tab or hit the back button. }); } - function getDomainWhitelist(uid) { + function getDomainWhitelist(uid?: any) { return pgQueryP( "select * from site_domain_whitelist where site_id = (select site_id from users where uid = ($1));", [uid] - ).then(function (rows) { + // Argument of type '(rows: string | any[]) => any' is not assignable to parameter of type '(value: unknown) => any'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + ).then(function (rows: string | any[]) { if (!rows || !rows.length) { return ""; } return rows[0].domain_whitelist; }); } - function handle_GET_domainWhitelist(req, res) { + function handle_GET_domainWhitelist( + req: { p: { uid?: any } }, + res: { json: (arg0: { domain_whitelist: any }) => void } + ) { getDomainWhitelist(req.p.uid) - .then(function (whitelist) { + .then(function (whitelist: any) { res.json({ domain_whitelist: whitelist, }); }) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_get_domainWhitelist_misc", err); }); } - function handle_POST_domainWhitelist(req, res) { + function handle_POST_domainWhitelist( + req: { p: { uid?: any; domain_whitelist: any } }, + res: { json: (arg0: { domain_whitelist: any }) => void } + ) { setDomainWhitelist(req.p.uid, req.p.domain_whitelist) .then(function () { res.json({ domain_whitelist: req.p.domain_whitelist, }); }) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_post_domainWhitelist_misc", err); }); } - function handle_GET_conversationStats(req, res) { + function handle_GET_conversationStats( + req: { p: { zid: any; uid?: any; until: any; rid: any } }, + res: { + status: ( + arg0: number + ) => { + (): any; + new (): any; + json: { + (arg0: { + voteTimes: any; + firstVoteTimes: any[]; + commentTimes: any; + firstCommentTimes: any[]; + // viewTimes: viewTimes, + votesHistogram: any; + burstHistogram: any[]; + }): void; + new (): any; + }; + }; + } + ) { let zid = req.p.zid; let uid = req.p.uid; let until = req.p.until; @@ -4896,7 +6132,7 @@ Email verified! You can close this tab or hit the back button. : isModerator(zid, uid); hasPermission - .then(function (ok) { + .then(function (ok: any) { if (!ok) { fail( res, @@ -4932,8 +6168,8 @@ Email verified! You can close this tab or hit the back button. // pgQueryP_readOnly("with all_social as (select uid from facebook_users union select uid from twitter_users), "+ // "ptpts as (select created, uid from participants where zid = ($1)) "+ // "select ptpts.created from ptpts inner join all_social on ptpts.uid = all_social.uid;", [zid]), - ]).then(function (a) { - function castTimestamp(o) { + ]).then(function (a: any[]) { + function castTimestamp(o: { created: number }) { o.created = Number(o.created); return o; } @@ -4945,12 +6181,21 @@ Email verified! You can close this tab or hit the back button. let votesGroupedByPid = _.groupBy(votes, "pid"); let votesHistogramObj = {}; - _.each(votesGroupedByPid, function (votesByParticipant, pid) { - votesHistogramObj[votesByParticipant.length] = - votesHistogramObj[votesByParticipant.length] + 1 || 1; - }); - let votesHistogram = []; - _.each(votesHistogramObj, function (ptptCount, voteCount) { + _.each( + votesGroupedByPid, + function (votesByParticipant: string | any[], pid: any) { + // Element implicitly has an 'any' type because expression of type 'string | number' can't be used to index type '{}'. + // No index signature with a parameter of type 'string' was found on type '{}'.ts(7053) + // @ts-ignore + votesHistogramObj[votesByParticipant.length] = + // Element implicitly has an 'any' type because expression of type 'string | number' can't be used to index type '{}'. + // No index signature with a parameter of type 'string' was found on type '{}'.ts(7053) + // @ts-ignore + votesHistogramObj[votesByParticipant.length] + 1 || 1; + } + ); + let votesHistogram: { n_votes: any; n_ptpts: any }[] = []; + _.each(votesHistogramObj, function (ptptCount: any, voteCount: any) { votesHistogram.push({ n_votes: voteCount, n_ptpts: ptptCount, @@ -4962,25 +6207,45 @@ Email verified! You can close this tab or hit the back button. let burstsForPid = {}; let interBurstGap = 10 * 60 * 1000; // a 10 minute gap between votes counts as a gap between bursts - _.each(votesGroupedByPid, function (votesByParticipant, pid) { - burstsForPid[pid] = 1; - let prevCreated = votesByParticipant.length - ? votesByParticipant[0] - : 0; - for (var v = 1; v < votesByParticipant.length; v++) { - let vote = votesByParticipant[v]; - if (interBurstGap + prevCreated < vote.created) { - burstsForPid[pid] += 1; + _.each( + votesGroupedByPid, + function ( + votesByParticipant: string | any[], + pid: string | number + ) { + // Element implicitly has an 'any' type because expression of type 'string | number' can't be used to index type '{}'. + // No index signature with a parameter of type 'string' was found on type '{}'.ts(7053) + // @ts-ignore + burstsForPid[pid] = 1; + let prevCreated = votesByParticipant.length + ? votesByParticipant[0] + : 0; + for (var v = 1; v < votesByParticipant.length; v++) { + let vote = votesByParticipant[v]; + if (interBurstGap + prevCreated < vote.created) { + // Element implicitly has an 'any' type because expression of type 'string | number' can't be used to index type '{}'. + // No index signature with a parameter of type 'string' was found on type '{}'.ts(7053) + // @ts-ignore + burstsForPid[pid] += 1; + } + prevCreated = vote.created; } - prevCreated = vote.created; } - }); + ); let burstHistogramObj = {}; - _.each(burstsForPid, function (bursts, pid) { + // Argument of type '(bursts: string | number, pid: any) => void' is not assignable to parameter of type 'CollectionIterator'. + // Types of parameters 'bursts' and 'element' are incompatible. + // Type 'unknown' is not assignable to type 'string | number'. + // Type 'unknown' is not assignable to type 'number'.ts(2345) + // @ts-ignore + _.each(burstsForPid, function (bursts: string | number, pid: any) { + // Element implicitly has an 'any' type because expression of type 'string | number' can't be used to index type '{}'. + // No index signature with a parameter of type 'string' was found on type '{}'.ts(7053) + // @ts-ignore burstHistogramObj[bursts] = burstHistogramObj[bursts] + 1 || 1; }); - let burstHistogram = []; - _.each(burstHistogramObj, function (ptptCount, burstCount) { + let burstHistogram: { n_ptpts: any; n_bursts: number }[] = []; + _.each(burstHistogramObj, function (ptptCount: any, burstCount: any) { burstHistogram.push({ n_ptpts: ptptCount, n_bursts: Number(burstCount), @@ -5000,12 +6265,15 @@ Email verified! You can close this tab or hit the back button. // let viewTimes = _.pluck(uniqueHits, "created"); // let totalSocialUsers = _.pluck(socialUsers, "created"); - votesHistogram = _.map(votesHistogram, function (x) { - return { - n_votes: Number(x.n_votes), - n_ptpts: Number(x.n_ptpts), - }; - }); + votesHistogram = _.map( + votesHistogram, + function (x: { n_votes: any; n_ptpts: any }) { + return { + n_votes: Number(x.n_votes), + n_ptpts: Number(x.n_ptpts), + }; + } + ); res.status(200).json({ voteTimes: totalVotes, @@ -5019,11 +6287,25 @@ Email verified! You can close this tab or hit the back button. }); }); }) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_conversationStats_misc", err); }); } - function handle_GET_snapshot(req, res) { + function handle_GET_snapshot( + req: { p: { uid?: any; zid: any } }, + res: { + status: ( + arg0: number + ) => { + (): any; + new (): any; + json: { + (arg0: { zid: any; zinvite: any; url: string }): void; + new (): any; + }; + }; + } + ) { let uid = req.p.uid; let zid = req.p.zid; @@ -5043,7 +6325,7 @@ Email verified! You can close this tab or hit the back button. "insert into conversations (topic, description, link_url, owner, modified, created, participant_count) " + "(select '(SNAPSHOT) ' || topic, description, link_url, $2, now_as_millis(), created, participant_count from conversations where zid = $1) returning *;", [zid, uid], - function (err, result) { + function (err: any, result: { rows: any[] }) { if (err) { fail(res, 500, "polis_err_cloning_conversation", err); return; @@ -5066,10 +6348,19 @@ Email verified! You can close this tab or hit the back button. ).then(function () { return pgQueryP("select * from votes where zid = ($1);", [ zid, - ]).then((votes) => { + // Argument of type '(votes: any[]) => Promise' is not assignable to parameter of type '(value: unknown) => void | PromiseLike'. + // Types of parameters 'votes' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + ]).then((votes: any[]) => { // insert votes one at a time. return Promise.all( - votes.map(function (v) { + votes.map(function (v: { + pid: any; + tid: any; + vote: any; + created: any; + }) { let q = "insert into votes (zid, pid, tid, vote, created) values ($1, $2, $3, $4, $5);"; return pgQueryP(q, [ @@ -5082,7 +6373,7 @@ Email verified! You can close this tab or hit the back button. }) ).then(function () { return generateAndRegisterZinvite(newZid, true).then( - function (zinvite) { + function (zinvite: string) { res.status(200).json({ zid: newZid, zinvite: zinvite, @@ -5094,26 +6385,31 @@ Email verified! You can close this tab or hit the back button. }); }); }) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_cloning_conversation_misc", err); }); } ); } - function handle_GET_facebook_delete(req, res) { + function handle_GET_facebook_delete( + req: { p: any }, + res: { json: (arg0: {}) => void } + ) { deleteFacebookUserRecord(req.p) .then(function () { res.json({}); }) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, err); }); } - function getFriends(fb_access_token) { - function getMoreFriends(friendsSoFar, urlForNextCall) { + function getFriends(fb_access_token: any) { + // 'getMoreFriends' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.ts(7023) + // @ts-ignore + function getMoreFriends(friendsSoFar: any[], urlForNextCall: any) { // urlForNextCall includes access token return request.get(urlForNextCall).then( - function (response) { + function (response: { data: string | any[]; paging: { next: any } }) { let len = response.data.length; if (len) { for (var i = 0; i < len; i++) { @@ -5127,37 +6423,47 @@ Email verified! You can close this tab or hit the back button. return friendsSoFar; } }, - function (err) { + function (err: any) { emailBadProblemTime("getMoreFriends failed"); return friendsSoFar; } ); } - return new Promise(function (resolve, reject) { + return new Promise(function ( + resolve: (arg0: any) => void, + reject: (arg0: any) => void + ) { FB.setAccessToken(fb_access_token); - FB.api("/me/friends", function (response) { - if (response && !response.error) { - let friendsSoFar = response.data; - if (response.data.length && response.paging.next) { - getMoreFriends(friendsSoFar, response.paging.next).then( - resolve, - reject - ); + FB.api( + "/me/friends", + function (response: { + error: any; + data: any[]; + paging: { next: any }; + }) { + if (response && !response.error) { + let friendsSoFar = response.data; + if (response.data.length && response.paging.next) { + getMoreFriends(friendsSoFar, response.paging.next).then( + resolve, + reject + ); + } else { + resolve(friendsSoFar || []); + } } else { - resolve(friendsSoFar || []); + reject(response); } - } else { - reject(response); } - }); + ); }); } // end getFriends - function getLocationInfo(fb_access_token, location) { - return new Promise(function (resolve, reject) { + function getLocationInfo(fb_access_token: any, location: { id: string }) { + return new Promise(function (resolve: (arg0: {}) => void, reject: any) { if (location && location.id) { FB.setAccessToken(fb_access_token); - FB.api("/" + location.id, function (locationResponse) { + FB.api("/" + location.id, function (locationResponse: any) { resolve(locationResponse); }); } else { @@ -5165,14 +6471,25 @@ Email verified! You can close this tab or hit the back button. } }); } - function handle_POST_auth_facebook(req, res) { - let response = JSON.parse(req.p.response); + function handle_POST_auth_facebook( + req: { + p: { + response?: string; + locationInfo?: any; + fb_friends_response?: string; + }; + headers?: { referer: string }; + cookies?: any; + }, + res: any + ) { + let response = JSON.parse(req?.p?.response || ""); let fb_access_token = response && response.authResponse && response.authResponse.accessToken; if (!fb_access_token) { emailBadProblemTime( "polis_err_missing_fb_access_token " + - req.headers.referer + + req?.headers?.referer + "\n\n" + req.p.response ); @@ -5204,7 +6521,7 @@ Email verified! You can close this tab or hit the back button. { fields: fields, }, - function (fbRes) { + function (fbRes: { error: any; friends: string | any[]; location: any }) { if (!fbRes || fbRes.error) { fail(res, 500, "polis_err_fb_auth_check", fbRes && fbRes.error); return; @@ -5218,7 +6535,7 @@ Email verified! You can close this tab or hit the back button. Promise.all([ getLocationInfo(fb_access_token, fbRes.location), friendsPromise, - ]).then(function (a) { + ]).then(function (a: any[]) { let locationResponse = a[0]; let friends = a[1]; @@ -5238,14 +6555,40 @@ Email verified! You can close this tab or hit the back button. } ); } - function do_handle_POST_auth_facebook(req, res, o) { + function do_handle_POST_auth_facebook( + req: { + p: { + response?: string; + password?: any; + uid?: any; + fb_granted_scopes?: any; + fb_friends_response?: any; + }; + cookies?: { [x: string]: any }; + }, + res: { + json: (arg0: { uid?: any; hname: any; email: any }) => void; + status: ( + arg0: number + ) => { + (): any; + new (): any; + json: { + (arg0: { uid?: any; hname: any; email: any }): void; + new (): any; + }; + send: { (arg0: string): void; new (): any }; + }; + }, + o: { locationInfo?: any; friends: any; info: any } + ) { // If a pol.is user record exists, and someone logs in with a facebook account that has the same email address, we should bind that facebook account to the pol.is account, and let the user sign in. let TRUST_FB_TO_VALIDATE_EMAIL = true; let email = o.info.email; let hname = o.info.name; let fb_friends_response = o.friends; let fb_user_id = o.info.id; - let response = JSON.parse(req.p.response); + let response = JSON.parse(req?.p?.response || ""); let fb_public_profile = o.info; let fb_login_status = response.status; // let fb_auth_response = response.authResponse. @@ -5253,7 +6596,7 @@ Email verified! You can close this tab or hit the back button. let verified = o.info.verified; // let existingUid = req.p.existingUid; - let referrer = req.cookies[COOKIES.REFERRER]; + let referrer = req?.cookies?.[COOKIES.REFERRER]; let password = req.p.password; let uid = req.p.uid; @@ -5271,7 +6614,12 @@ Email verified! You can close this tab or hit the back button. fb_friends_response: req.p.fb_friends_response || "", response: req.p.response, }; - function doFbUserHasAccountLinked(user) { + function doFbUserHasAccountLinked(user: { + fb_user_id: any; + uid: string; + hname: any; + email: any; + }) { if (user.fb_user_id === fb_user_id) { updateFacebookUserRecord( Object.assign( @@ -5298,20 +6646,20 @@ Email verified! You can close this tab or hit the back button. // token: token }); }) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_reg_fb_start_session2", err); }); }, - function (err) { + function (err: any) { fail(res, 500, "polis_err_linking_fb_friends2", err); } ); }, - function (err) { + function (err: any) { fail(res, 500, "polis_err_updating_fb_info", err); } ) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_fb_auth_misc", err); }); } else { @@ -5321,7 +6669,7 @@ Email verified! You can close this tab or hit the back button. function () { doFbNotLinkedButUserWithEmailExists(user); }, - function (err) { + function (err: any) { emailBadProblemTime( "facebook auth where user exists with different facebook account " + user.uid @@ -5336,7 +6684,7 @@ Email verified! You can close this tab or hit the back button. } } // doFbUserHasAccountLinked - function doFbNotLinkedButUserWithEmailExists(user) { + function doFbNotLinkedButUserWithEmailExists(user: { uid?: any }) { // user for this email exists, but does not have FB account linked. // user will be prompted for their password, and client will repeat the call with password // fail(res, 409, "polis_err_reg_user_exits_with_email_but_has_no_facebook_linked") @@ -5347,7 +6695,7 @@ Email verified! You can close this tab or hit the back button. ? Promise.resolve(true) : checkPassword(user.uid, password || ""); pwPromise.then( - function (ok) { + function (ok: any) { if (ok) { createFacebookUserRecord( Object.assign( @@ -5374,12 +6722,17 @@ Email verified! You can close this tab or hit the back button. return user; }); }, - function (err) { + function (err: any) { fail(res, 500, "polis_err_linking_fb_friends", err); } ) .then( - function (user) { + // Argument of type '(user: { uid?: any; hname: any; email: any; }) => void' is not assignable to parameter of type '(value: void | { uid?: any; }) => void | PromiseLike'. + // Types of parameters 'user' and 'value' are incompatible. + // Type 'void | { uid?: any; }' is not assignable to type '{ uid?: any; hname: any; email: any; }'. + // Type 'void' is not assignable to type '{ uid?: any; hname: any; email: any; }'.ts(2345) + // @ts-ignore + function (user: { uid?: any; hname: any; email: any }) { res.status(200).json({ uid: user.uid, hname: user.hname, @@ -5387,12 +6740,12 @@ Email verified! You can close this tab or hit the back button. // token: token, }); }, - function (err) { + function (err: any) { fail(res, 500, "polis_err_linking_fb_misc", err); } ); }, - function (err) { + function (err: any) { fail( res, 500, @@ -5401,7 +6754,7 @@ Email verified! You can close this tab or hit the back button. ); } ) - .catch(function (err) { + .catch(function (err: any) { fail( res, 500, @@ -5413,14 +6766,14 @@ Email verified! You can close this tab or hit the back button. fail(res, 403, "polis_err_password_mismatch"); } }, - function (err) { + function (err: any) { fail(res, 500, "polis_err_password_check"); } ); } } // end doFbNotLinkedButUserWithEmailExists - function doFbNoUserExistsYet(user) { + function doFbNoUserExistsYet(user: any) { let promise; if (uid) { winston.log("info", "fb1 5a..."); @@ -5435,7 +6788,18 @@ Email verified! You can close this tab or hit the back button. "update users set email = ($2) where uid = ($1) and email is NULL;", [uid, email] ), - ]).then(function (o) { + // No overload matches this call. + // Overload 1 of 2, '(onFulfill?: ((value: [unknown, unknown, unknown]) => any) | undefined, onReject?: ((error: any) => any) | undefined): Bluebird', gave the following error. + // Argument of type '(o: any[][]) => any' is not assignable to parameter of type '(value: [unknown, unknown, unknown]) => any'. + // Types of parameters 'o' and 'value' are incompatible. + // Type '[unknown, unknown, unknown]' is not assignable to type 'any[][]'. + // Type 'unknown' is not assignable to type 'any[]'. + // Overload 2 of 2, '(onfulfilled?: ((value: [unknown, unknown, unknown]) => any) | null | undefined, onrejected?: ((reason: any) => PromiseLike) | null | undefined): Bluebird', gave the following error. + // Argument of type '(o: any[][]) => any' is not assignable to parameter of type '(value: [unknown, unknown, unknown]) => any'. + // Types of parameters 'o' and 'value' are incompatible. + // Type '[unknown, unknown, unknown]' is not assignable to type 'any[][]'.ts(2769) + // @ts-ignore + ]).then(function (o: any[][]) { let user = o[0][0]; winston.log("info", "fb1 5a"); winston.log("info", user); @@ -5450,7 +6814,14 @@ Email verified! You can close this tab or hit the back button. "(email, hname) VALUES " + "($1, $2) " + "returning *;"; - promise = pgQueryP(query, [email, hname]).then(function (rows) { + // Argument of type '(rows: string | any[]) => any' is not assignable to parameter of type '(value: unknown) => any'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + promise = pgQueryP(query, [email, hname]).then(function ( + rows: string | any[] + ) { let user = (rows && rows.length && rows[0]) || null; winston.log("info", "fb1 5b"); winston.log("info", user); @@ -5460,7 +6831,7 @@ Email verified! You can close this tab or hit the back button. } // Create user record promise - .then(function (user) { + .then(function (user: any) { winston.log("info", "fb1 4"); winston.log("info", user); winston.log("info", "end fb1 4"); @@ -5471,7 +6842,7 @@ Email verified! You can close this tab or hit the back button. }); }) .then( - function (user) { + function (user: { uid?: any }) { winston.log("info", "fb1 3"); winston.log("info", user); winston.log("info", "end fb1 3"); @@ -5486,12 +6857,17 @@ Email verified! You can close this tab or hit the back button. return user; } }, - function (err) { + function (err: any) { fail(res, 500, "polis_err_reg_fb_user_creating_record2", err); } ) .then( - function (user) { + // Argument of type '(user: { uid?: any; }) => Bluebird' is not assignable to parameter of type '(value: void | { uid?: any; }) => void | { uid?: any; } | PromiseLike'. + // Types of parameters 'user' and 'value' are incompatible. + // Type 'void | { uid?: any; }' is not assignable to type '{ uid?: any; }'. + // Type 'void' is not assignable to type '{ uid?: any; }'.ts(2345) + // @ts-ignore + function (user: { uid?: any }) { winston.log("info", "fb1 2"); winston.log("info", user); winston.log("info", "end fb1 2"); @@ -5500,17 +6876,22 @@ Email verified! You can close this tab or hit the back button. function () { return user; }, - function (err) { + function (err: any) { fail(res, 500, "polis_err_reg_fb_user_creating_record3", err); } ); }, - function (err) { + function (err: any) { fail(res, 500, "polis_err_reg_fb_user_creating_record", err); } ) .then( - function (user) { + // Argument of type '(user: { uid?: any; hname: any; email: any; }) => void' is not assignable to parameter of type '(value: void | { uid?: any; }) => void | PromiseLike'. + // Types of parameters 'user' and 'value' are incompatible. + // Type 'void | { uid?: any; }' is not assignable to type '{ uid?: any; hname: any; email: any; }'. + // Type 'void' is not assignable to type '{ uid?: any; hname: any; email: any; }'.ts(2345) + // @ts-ignore + function (user: { uid?: any; hname: any; email: any }) { winston.log("info", "fb1"); winston.log("info", user); winston.log("info", "end fb1"); @@ -5521,11 +6902,11 @@ Email verified! You can close this tab or hit the back button. // token: token }); }, - function (err) { + function (err: any) { fail(res, 500, "polis_err_reg_fb_user_misc22", err); } ) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_reg_fb_user_misc2", err); }); } // end doFbNoUserExistsYet @@ -5533,13 +6914,15 @@ Email verified! You can close this tab or hit the back button. let emailVerifiedPromise = Promise.resolve(true); if (!verified) { if (email) { + // Type 'Promise' is missing the following properties from type 'Bluebird': caught, error, lastly, bind, and 38 more.ts(2740) + // @ts-ignore emailVerifiedPromise = isEmailVerified(email); } else { emailVerifiedPromise = Promise.resolve(false); } } - Promise.all([emailVerifiedPromise]).then(function (a) { + Promise.all([emailVerifiedPromise]).then(function (a: any[]) { let isVerifiedByPolisOrFacebook = a[0]; if (!isVerifiedByPolisOrFacebook) { @@ -5563,12 +6946,17 @@ Email verified! You can close this tab or hit the back button. [email, fb_user_id] ) .then( - function (rows) { + // Argument of type '(rows: string | any[]) => void' is not assignable to parameter of type '(value: unknown) => void | PromiseLike'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + function (rows: string | any[]) { let user = (rows && rows.length && rows[0]) || null; if (rows && rows.length > 1) { // the auth provided us with email and fb_user_id where the email is one polis user, and the fb_user_id is for another. // go with the one matching the fb_user_id in this case, and leave the email matching account alone. - user = _.find(rows, function (row) { + user = _.find(rows, function (row: { fb_user_id: any }) { return row.fb_user_id === fb_user_id; }); } @@ -5582,32 +6970,46 @@ Email verified! You can close this tab or hit the back button. doFbNoUserExistsYet(user); } }, - function (err) { + function (err: any) { fail(res, 500, "polis_err_reg_fb_user_looking_up_email", err); } ) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_reg_fb_user_misc", err); }); }); } // end do_handle_POST_auth_facebook - function handle_POST_auth_new(req, res) { + function handle_POST_auth_new(req: any, res: any) { CreateUser.createUser(req, res); } // end /api/v3/auth/new - function handle_POST_tutorial(req, res) { + function handle_POST_tutorial( + req: { p: { uid?: any; step: any } }, + res: { + status: ( + arg0: number + ) => { (): any; new (): any; json: { (arg0: {}): void; new (): any } }; + } + ) { let uid = req.p.uid; let step = req.p.step; pgQueryP("update users set tut = ($1) where uid = ($2);", [step, uid]) .then(function () { res.status(200).json({}); }) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_saving_tutorial_state", err); }); } - function handle_GET_users(req, res) { + function handle_GET_users( + req: { p: { uid?: any; errIfNoAuth: any; xid: any; owner_uid?: any } }, + res: { + status: ( + arg0: number + ) => { (): any; new (): any; json: { (arg0: any): void; new (): any } }; + } + ) { let uid = req.p.uid; if (req.p.errIfNoAuth && !uid) { @@ -5617,14 +7019,14 @@ Email verified! You can close this tab or hit the back button. getUser(uid, null, req.p.xid, req.p.owner_uid) .then( - function (user) { + function (user: any) { res.status(200).json(user); }, - function (err) { + function (err: any) { fail(res, 500, "polis_err_getting_user_info2", err); } ) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_getting_user_info", err); }); } @@ -5656,12 +7058,15 @@ Email verified! You can close this tab or hit the back button. // 100: "Site", // 1000: "Organization", // }; - function changePlan(uid, planCode) { - return new Promise(function (resolve, reject) { + function changePlan(uid?: any, planCode?: any) { + return new Promise(function ( + resolve: () => void, + reject: (arg0: any) => void + ) { pgQuery( "update users set plan = ($1) where uid = ($2);", [planCode, uid], - function (err, results) { + function (err: any, results: any) { if (err) { reject(err); } else { @@ -5672,15 +7077,21 @@ Email verified! You can close this tab or hit the back button. }); } - function setUsersPlanInIntercom(uid, planCode) { - return new Promise(function (resolve, reject) { + function setUsersPlanInIntercom(uid?: any, planCode?: any) { + return new Promise(function ( + resolve: (arg0: any) => void, + reject: (arg0: any) => void + ) { var params = { user_id: uid, custom_data: { plan_code: planCode, }, }; - intercom.updateUser(params, function (err, res) { + // Property 'updateUser' does not exist on type 'Client | { leads: { create: Bluebird<{ body?: { user_id: string; } | undefined; }>; update: Bluebird<{ body?: { user_id: string; } | undefined; }>; }; }'. + // Property 'updateUser' does not exist on type 'Client'.ts(2339) + // @ts-ignore + intercom.updateUser(params, function (err: any, res: any) { if (err) { reject(err); } else { @@ -5689,9 +7100,17 @@ Email verified! You can close this tab or hit the back button. }); }); } - function createStripeUser(o) { - return new Promise(function (resolve, reject) { - stripe.customers.create(o, function (err, customer) { + function createStripeUser(o: { + card: any; + description: any; + email: any; + metadata: { uid?: any; polisEmail: any }; + }) { + return new Promise(function ( + resolve: (arg0: any) => void, + reject: (arg0: any) => void + ) { + stripe.customers.create(o, function (err: any, customer: any) { if (err) { reject(err); } else { @@ -5701,9 +7120,12 @@ Email verified! You can close this tab or hit the back button. }); } - function getStripeUser(customerId) { - return new Promise(function (resolve, reject) { - stripe.customers.retrieve(customerId, function (err, customer) { + function getStripeUser(customerId: any) { + return new Promise(function ( + resolve: (arg0: any) => void, + reject: (arg0: any) => void + ) { + stripe.customers.retrieve(customerId, function (err: any, customer: any) { if (err) { reject(err); } else { @@ -5713,14 +7135,17 @@ Email verified! You can close this tab or hit the back button. }); } - function createStripeSubscription(customerId, planId) { - return new Promise(function (resolve, reject) { + function createStripeSubscription(customerId: any, planId: any) { + return new Promise(function ( + resolve: (arg0: any) => void, + reject: (arg0: any) => void + ) { stripe.customers.createSubscription( customerId, { plan: planId, }, - function (err, subscription) { + function (err: any, subscription: any) { if (err) { reject(err); } else { @@ -5731,7 +7156,12 @@ Email verified! You can close this tab or hit the back button. }); } - function updateStripePlan(user, stripeToken, stripeEmail, plan) { + function updateStripePlan( + user: UserType, + stripeToken: any, + stripeEmail: any, + plan: any + ) { var customerPromise = user.stripeCustomerId ? getStripeUser(user.stripeCustomerId) : createStripeUser({ @@ -5744,12 +7174,14 @@ Email verified! You can close this tab or hit the back button. }, }); - return customerPromise.then(function (customer) { + return customerPromise.then(function (customer: { id: any }) { // throw new Error("TODO"); // TODO is "plan" the right identifier? // TODO may need to wrangle existing plans.. - return createStripeSubscription(customer.id, plan).then(function (data) { + return createStripeSubscription(customer.id, plan).then(function ( + data: any + ) { return pgQueryP( "insert into stripe_subscriptions (uid, stripe_subscription_data) values ($1, $2) " + "on conflict (uid) do update set stripe_subscription_data = ($2), modified = now_as_millis();", @@ -5759,35 +7191,55 @@ Email verified! You can close this tab or hit the back button. }); } - function handle_GET_createPlanChangeCoupon(req, res) { + function handle_GET_createPlanChangeCoupon( + req: { p: { uid?: any; planCode: any } }, + res: { + status: ( + arg0: number + ) => { (): any; new (): any; json: { (arg0: any): void; new (): any } }; + } + ) { var uid = req.p.uid; var planCode = req.p.planCode; generateTokenP(30, false) - .then(function (code) { - return pgQueryP( - "insert into coupons_for_free_upgrades (uid, code, plan) values ($1, $2, $3) returning *;", - [uid, code, planCode] - ) - .then(function (rows) { - var row = rows[0]; - row.url = - "https://pol.is/api/v3/changePlanWithCoupon?code=" + row.code; - res.status(200).json(row); - }) - .catch(function (err) { - fail(res, 500, "polis_err_creating_coupon", err); - }); + .then(function (code: any) { + return ( + pgQueryP( + "insert into coupons_for_free_upgrades (uid, code, plan) values ($1, $2, $3) returning *;", + [uid, code, planCode] + ) + // Argument of type '(rows: any[]) => void' is not assignable to parameter of type '(value: unknown) => void | PromiseLike'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + .then(function (rows: any[]) { + var row = rows[0]; + row.url = + "https://pol.is/api/v3/changePlanWithCoupon?code=" + row.code; + res.status(200).json(row); + }) + .catch(function (err: any) { + fail(res, 500, "polis_err_creating_coupon", err); + }) + ); }) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_creating_coupon_code", err); }); } - function handle_GET_changePlanWithCoupon(req, res) { + function handle_GET_changePlanWithCoupon( + req: { p: { uid?: any; code?: any } }, + res: any + ) { var uid = req.p.uid; var code = req.p.code; var isCurrentUser = true; getCouponInfo(code) - .then(function (infos) { + // Argument of type '(infos: any[]) => Bluebird' is not assignable to parameter of type '(value: unknown) => any'. + // Types of parameters 'infos' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + .then(function (infos: any[]) { var info = infos[0]; if (uid) { if (uid !== info.uid) { @@ -5799,22 +7251,30 @@ Email verified! You can close this tab or hit the back button. } return updatePlanOld(req, res, info.uid, info.plan, isCurrentUser); }) - .catch(function (err) { + .catch(function (err: any) { emailBadProblemTime("changePlanWithCoupon failed"); fail(res, 500, "polis_err_changing_plan_with_coupon", err); }); } - function getCouponInfo(couponCode) { + function getCouponInfo(couponCode: any) { return pgQueryP( "select * from coupons_for_free_upgrades where code = ($1);", [couponCode] ); } - function updatePlan(req, res, uid, planCode) { + function updatePlan( + req: { + headers?: Headers; + p: { uid?: any; plan: any; stripeResponse: string }; + }, + res: any, + uid: string, + planCode: number + ) { winston.log("info", "updatePlan", uid, planCode); - setUsersPlanInIntercom(uid, planCode).catch(function (err) { + setUsersPlanInIntercom(uid, planCode).catch(function (err: any) { emailBadProblemTime( "User " + uid + " changed their plan, but we failed to update Intercom" ); @@ -5824,16 +7284,32 @@ Email verified! You can close this tab or hit the back button. return changePlan(uid, planCode).then(function () { // Set cookie var setOnPolisDomain = !domainOverride; - var origin = req.headers.origin || ""; + const origin = req?.headers?.origin || ""; if (setOnPolisDomain && origin.match(/^http:\/\/localhost:[0-9]{4}/)) { setOnPolisDomain = false; } setPlanCookie(req, res, setOnPolisDomain, planCode); }); } - function updatePlanOld(req, res, uid, planCode, isCurrentUser) { + function updatePlanOld( + req: { headers?: { origin: string; host: string }; p?: any }, + res: { + writeHead: (arg0: number, arg1: { Location: string }) => void; + end: () => any; + status: ( + arg0: number + ) => { + (): any; + new (): any; + json: { (arg0: { status: string }): void; new (): any }; + }; + }, + uid: string, + planCode: number, + isCurrentUser: boolean + ) { winston.log("info", "updatePlan", uid, planCode); - setUsersPlanInIntercom(uid, planCode).catch(function (err) { + setUsersPlanInIntercom(uid, planCode).catch(function (err: any) { emailBadProblemTime( "User " + uid + " changed their plan, but we failed to update Intercom" ); @@ -5846,7 +7322,7 @@ Email verified! You can close this tab or hit the back button. if (isCurrentUser) { var protocol = devMode ? "http" : "https"; var setOnPolisDomain = !domainOverride; - var origin = req.headers.origin || ""; + var origin = req?.headers?.origin || ""; if ( setOnPolisDomain && origin.match(/^http:\/\/localhost:[0-9]{4}/) @@ -5861,7 +7337,7 @@ Email verified! You can close this tab or hit the back button. path = "/settings/enterprise"; } res.writeHead(302, { - Location: protocol + "://" + req.headers.host + path, + Location: protocol + "://" + req?.headers?.host + path, }); return res.end(); } else { @@ -5870,7 +7346,7 @@ Email verified! You can close this tab or hit the back button. }); } }) - .catch(function (err) { + .catch(function (err: any) { emailBadProblemTime( "User changed their plan, but we failed to update the DB." ); @@ -5878,18 +7354,24 @@ Email verified! You can close this tab or hit the back button. }); } - function handle_POST_stripe_save_token(req, res) { + function handle_POST_stripe_save_token(req: { body: any }, res: any) { console.log("info", "XXX - Got the params!"); console.log(req.body); console.log("info", "XXX - Got the params!"); } - function handle_POST_stripe_upgrade(req, res) { + function handle_POST_stripe_upgrade( + req: { p: { uid?: any; plan: any; stripeResponse: string } }, + res: { json: (arg0: {}) => void } + ) { var uid = req.p.uid; var planName = req.p.plan; + // Element implicitly has an 'any' type because expression of type 'string | number' can't be used to index type '{}'. + // No index signature with a parameter of type 'string' was found on type '{}'.ts(7053) + // @ts-ignore var planCode = planCodes[planName]; getUserInfoForUid2(uid) - .then(function (user) { + .then(function (user: UserType) { var stripeResponse = JSON.parse(req.p.stripeResponse); const body = @@ -5914,7 +7396,7 @@ Email verified! You can close this tab or hit the back button. .then(function () { res.json({}); }) - .catch(function (err) { + .catch(function (err: any) { emailBadProblemTime( "FAILED Polis account upgrade: " + uid + @@ -5936,14 +7418,22 @@ Email verified! You can close this tab or hit the back button. }); } - function handle_POST_stripe_cancel(req, res) { + function handle_POST_stripe_cancel( + req: { + headers?: Headers | undefined; + p: { uid?: any; plan: any; stripeResponse: string }; + }, + res: { json: (arg0: {}) => void } + ) { const uid = req.p.uid; - getUserInfoForUid2(uid).then((user) => { + getUserInfoForUid2(uid).then((user: { email: string }) => { emailBadProblemTime("User cancelled subscription: " + user.email); return pgQueryP("select * from stripe_subscriptions where uid = ($1);", [ uid, - ]).then((rows) => { + // Argument of type '(rows: string | any[], err: any) => void' is not assignable to parameter of type '(value: unknown) => void | PromiseLike'.ts(2345) + // @ts-ignore + ]).then((rows: string | any[], err: any) => { if (!rows || !rows.length) { return fail( res, @@ -5957,7 +7447,7 @@ Email verified! You can close this tab or hit the back button. stripe.customers.cancelSubscription( record.customer, record.id, - (err) => { + (err: any) => { if (err) { emailBadProblemTime( "User cancel subscription failed: " + user.email @@ -5973,11 +7463,17 @@ Email verified! You can close this tab or hit the back button. }); } - function handle_POST_charge(req, res) { + function handle_POST_charge( + req: { p: { stripeToken: any; stripeEmail: any; uid?: any; plan: any } }, + res: any + ) { var stripeToken = req.p.stripeToken; var stripeEmail = req.p.stripeEmail; var uid = req.p.uid; var plan = req.p.plan; + // Element implicitly has an 'any' type because expression of type 'string | number' can't be used to index type '{}'. + // No index signature with a parameter of type 'string' was found on type '{}'.ts(7053) + // @ts-ignore var planCode = planCodes[plan]; if (plan !== "pp") { @@ -5992,7 +7488,7 @@ Email verified! You can close this tab or hit the back button. var updateStripePromise = Promise.resolve(); if (plan !== "pp") { // not a participant pays plan, so we actually have to update stripe. - getUserInfoForUid2(uid).then(function (user) { + getUserInfoForUid2(uid).then(function (user: any) { return updateStripePlan(user, stripeToken, stripeEmail, plan); }); } @@ -6001,7 +7497,7 @@ Email verified! You can close this tab or hit the back button. .then(function () { return updatePlanOld(req, res, uid, planCode, true); }) - .catch(function (err) { + .catch(function (err: { type: string }) { if (err) { if (err.type === "StripeCardError") { return fail(res, 500, "polis_err_stripe_card_declined", err); @@ -6029,12 +7525,19 @@ Email verified! You can close this tab or hit the back button. */ - function handle_GET_participation(req, res) { + function handle_GET_participation( + req: { p: { zid: any; uid?: any; strict: any } }, + res: { + status: ( + arg0: number + ) => { (): any; new (): any; json: { (arg0: {}): void; new (): any } }; + } + ) { let zid = req.p.zid; let uid = req.p.uid; let strict = req.p.strict; isOwner(zid, uid) - .then(function (ok) { + .then(function (ok: any) { if (!ok) { fail(res, 403, "polis_err_get_participation_auth"); return; @@ -6050,7 +7553,7 @@ Email verified! You can close this tab or hit the back button. [zid] ), getXids(zid), //pgQueryP_readOnly("select pid, xid from xids inner join (select * from participants where zid = ($1)) as p on xids.uid = p.uid;", [zid]), - ]).then(function (o) { + ]).then(function (o: any[]) { let voteCountRows = o[0]; let commentCountRows = o[1]; let pidXidRows = o[2]; @@ -6066,6 +7569,9 @@ Email verified! You can close this tab or hit the back button. } // Build a map like this {xid -> {votes: 10, comments: 2}} + // (property) votes: number + // 'new' expression, whose target lacks a construct signature, implicitly has an 'any' type.ts(7009) + // @ts-ignore let result = new DD(function () { return { votes: 0, @@ -6091,11 +7597,17 @@ Email verified! You can close this tab or hit the back button. // Convert from {pid -> foo} to {xid -> foo} let pidToXid = {}; for (i = 0; i < pidXidRows.length; i++) { + // Element implicitly has an 'any' type because expression of type 'string | number' can't be used to index type '{}'. + // No index signature with a parameter of type 'string' was found on type '{}'.ts(7053) + // @ts-ignore pidToXid[pidXidRows[i].pid] = pidXidRows[i].xid; } let xidBasedResult = {}; let size = 0; - _.each(result, function (val, key) { + _.each(result, function (val: any, key: string | number) { + // Element implicitly has an 'any' type because expression of type 'string | number' can't be used to index type '{}'. + // No index signature with a parameter of type 'string' was found on type '{}'.ts(7053) + // @ts-ignore xidBasedResult[pidToXid[key]] = val; size += 1; }); @@ -6118,11 +7630,11 @@ Email verified! You can close this tab or hit the back button. } }); }) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_get_participation_misc", err); }); } - function getAgeRange(demo) { + function getAgeRange(demo: Demo) { var currentYear = new Date().getUTCFullYear(); var birthYear = demo.ms_birth_year_estimate_fb; if (_.isNull(birthYear) || _.isUndefined(birthYear) || _.isNaN(birthYear)) { @@ -6149,7 +7661,7 @@ Email verified! You can close this tab or hit the back button. } // 0 male, 1 female, 2 other, or NULL - function getGender(demo) { + function getGender(demo: Demo) { var gender = demo.fb_gender; if (_.isNull(gender) || _.isUndefined(gender)) { gender = demo.ms_gender_estimate_fb; @@ -6157,24 +7669,24 @@ Email verified! You can close this tab or hit the back button. return gender; } - function getDemographicsForVotersOnComments(zid, comments) { - function isAgree(v) { + function getDemographicsForVotersOnComments(zid: any, comments: any[]) { + function isAgree(v: { vote: any }) { return v.vote === polisTypes.reactions.pull; } - function isDisgree(v) { + function isDisgree(v: { vote: any }) { return v.vote === polisTypes.reactions.push; } - function isPass(v) { + function isPass(v: { vote: any }) { return v.vote === polisTypes.reactions.pass; } - function isGenderMale(demo) { + function isGenderMale(demo: { gender: number }) { return demo.gender === 0; } - function isGenderFemale(demo) { + function isGenderFemale(demo: { gender: number }) { return demo.gender === 1; } - function isGenderUnknown(demo) { + function isGenderUnknown(demo: { gender: any }) { var gender = demo.gender; return gender !== 0 && gender !== 1; } @@ -6188,10 +7700,10 @@ Email verified! You can close this tab or hit the back button. "select p.pid, d.* from participants p left join demographic_data d on p.uid = d.uid where p.zid = ($1);", [zid] ), - ]).then((a) => { + ]).then((a: any[]) => { var votes = a[0]; var demo = a[1]; - demo = demo.map((d) => { + demo = demo.map((d: Demo) => { return { pid: d.pid, gender: getGender(d), @@ -6200,7 +7712,7 @@ Email verified! You can close this tab or hit the back button. }); var demoByPid = _.indexBy(demo, "pid"); - votes = votes.map((v) => { + votes = votes.map((v: { pid: string | number }) => { return _.extend(v, demoByPid[v.pid]); }); @@ -6210,110 +7722,153 @@ Email verified! You can close this tab or hit the back button. // TODO maybe we should actually look at each age range, then a/d/p % // that will be more natrual in cases of unequal representation - return comments.map((c) => { - var votesForThisComment = votesByTid[c.tid]; - - if (!votesForThisComment || !votesForThisComment.length) { - console.log("skipping"); - // console.log(votesForThisComment); - return c; - } + return comments.map( + (c: { + tid: string | number; + demographics: { + gender: { + m: { agree: any; disagree: any; pass: any }; + f: { agree: any; disagree: any; pass: any }; + "?": { agree: any; disagree: any; pass: any }; + }; + // TODO return all age ranges even if zero. + age: any; + }; + }) => { + var votesForThisComment = votesByTid[c.tid]; - var agrees = votesForThisComment.filter(isAgree); - var disagrees = votesForThisComment.filter(isDisgree); - var passes = votesForThisComment.filter(isPass); + if (!votesForThisComment || !votesForThisComment.length) { + console.log("skipping"); + // console.log(votesForThisComment); + return c; + } - var votesByAgeRange = _.groupBy(votesForThisComment, "ageRange"); + var agrees = votesForThisComment.filter(isAgree); + var disagrees = votesForThisComment.filter(isDisgree); + var passes = votesForThisComment.filter(isPass); - c.demographics = { - gender: { - m: { - agree: agrees.filter(isGenderMale).length, - disagree: disagrees.filter(isGenderMale).length, - pass: passes.filter(isGenderMale).length, - }, - f: { - agree: agrees.filter(isGenderFemale).length, - disagree: disagrees.filter(isGenderFemale).length, - pass: passes.filter(isGenderFemale).length, - }, - "?": { - agree: agrees.filter(isGenderUnknown).length, - disagree: disagrees.filter(isGenderUnknown).length, - pass: passes.filter(isGenderUnknown).length, + var votesByAgeRange = _.groupBy(votesForThisComment, "ageRange"); + + c.demographics = { + gender: { + m: { + agree: agrees.filter(isGenderMale).length, + disagree: disagrees.filter(isGenderMale).length, + pass: passes.filter(isGenderMale).length, + }, + f: { + agree: agrees.filter(isGenderFemale).length, + disagree: disagrees.filter(isGenderFemale).length, + pass: passes.filter(isGenderFemale).length, + }, + "?": { + agree: agrees.filter(isGenderUnknown).length, + disagree: disagrees.filter(isGenderUnknown).length, + pass: passes.filter(isGenderUnknown).length, + }, }, - }, - // TODO return all age ranges even if zero. - age: _.mapObject(votesByAgeRange, (votes, ageRange) => { - var o = _.countBy(votes, "vote"); - return { - agree: o[polisTypes.reactions.pull], - disagree: o[polisTypes.reactions.push], - pass: o[polisTypes.reactions.pass], - }; - }), - }; - return c; - }); + // TODO return all age ranges even if zero. + age: _.mapObject(votesByAgeRange, (votes: any, ageRange: any) => { + var o = _.countBy(votes, "vote"); + return { + agree: o[polisTypes.reactions.pull], + disagree: o[polisTypes.reactions.push], + pass: o[polisTypes.reactions.pass], + }; + }), + }; + return c; + } + ); }); } const translateAndStoreComment = Comment.translateAndStoreComment; - function handle_GET_comments_translations(req, res) { + function handle_GET_comments_translations( + req: { p: { zid: any; tid: any; lang: string } }, + res: { + status: ( + arg0: number + ) => { (): any; new (): any; json: { (arg0: any): void; new (): any } }; + } + ) { const zid = req.p.zid; const tid = req.p.tid; const firstTwoCharsOfLang = req.p.lang.substr(0, 2); getComment(zid, tid) - .then((comment) => { - return pg + // Argument of type '(comment: { txt: any;}) => globalThis.Promise' is not assignable to parameter of type '(value: Row) => void | PromiseLike'. + // Types of parameters 'comment' and 'value' are incompatible. + // Property 'txt' is missing in type 'Row' but required in type '{ txt: any; }'.ts(2345) + // @ts-ignore + .then((comment: { txt: any }) => { + return dbPgQuery .queryP( "select * from comment_translations where zid = ($1) and tid = ($2) and lang LIKE '$3%';", [zid, tid, firstTwoCharsOfLang] ) - .then((existingTranslations) => { + .then((existingTranslations: any) => { if (existingTranslations) { return existingTranslations; } return translateAndStoreComment(zid, tid, comment.txt, req.p.lang); }) - .then((rows) => { + .then((rows: any) => { res.status(200).json(rows || []); }); }) - .catch((err) => { + .catch((err: any) => { fail(res, 500, "polis_err_get_comments_translations", err); }); } - function handle_GET_comments(req, res) { - let rid = req.headers["x-request-id"] + " " + req.headers["user-agent"]; + function handle_GET_comments( + req: { + headers?: Headers; + p: { rid: any; include_demographics: any; zid: any; uid?: any }; + }, + res: any + ) { + const rid = + req?.headers?.["x-request-id"] + " " + req?.headers?.["user-agent"]; winston.log("info", "getComments " + rid + " begin"); const isReportQuery = !_.isUndefined(req.p.rid); + // Argument of type '{ rid: any; include_demographics: any; zid: any; uid?: any; }' is not assignable to parameter of type 'O'. + // Type '{ rid: any; include_demographics: any; zid: any; uid?: any; }' is missing the following properties from type 'O': include_voting_patterns, modIn, pid, tids, and 9 more.ts(2345) + // @ts-ignore getComments(req.p) - .then(function (comments) { + .then(function (comments: any[]) { if (req.p.rid) { return pgQueryP( "select tid, selection from report_comment_selections where rid = ($1);", [req.p.rid] - ).then((selections) => { + ).then((selections: any) => { let tidToSelection = _.indexBy(selections, "tid"); - comments = comments.map((c) => { - c.includeInReport = - tidToSelection[c.tid] && tidToSelection[c.tid].selection > 0; - return c; - }); + comments = comments.map( + (c: { includeInReport: any; tid: string | number }) => { + c.includeInReport = + tidToSelection[c.tid] && tidToSelection[c.tid].selection > 0; + return c; + } + ); return comments; }); } else { return comments; } }) - .then(function (comments) { - comments = comments.map(function (c) { + .then(function (comments: any[]) { + comments = comments.map(function (c: { + social: { + twitter_user_id: string; + twitter_profile_image_url_https: string; + fb_user_id: any; + fb_picture: string; + }; + }) { let hasTwitter = c.social && c.social.twitter_user_id; if (hasTwitter) { c.social.twitter_profile_image_url_https = @@ -6332,32 +7887,36 @@ Email verified! You can close this tab or hit the back button. if (req.p.include_demographics) { isModerator(req.p.zid, req.p.uid) - .then((owner) => { + .then((owner: any) => { if (owner || isReportQuery) { return getDemographicsForVotersOnComments(req.p.zid, comments) - .then((commentsWithDemographics) => { + .then((commentsWithDemographics: any) => { finishArray(res, commentsWithDemographics); }) - .catch((err) => { + .catch((err: any) => { fail(res, 500, "polis_err_get_comments3", err); }); } else { fail(res, 500, "polis_err_get_comments_permissions"); } }) - .catch((err) => { + .catch((err: any) => { fail(res, 500, "polis_err_get_comments2", err); }); } else { finishArray(res, comments); } }) - .catch(function (err) { + .catch(function (err: any) { winston.log("info", "getComments " + rid + " failed"); fail(res, 500, "polis_err_get_comments", err); }); } // end GET /api/v3/comments - function isDuplicateKey(err) { + function isDuplicateKey(err: { + code: string | number; + sqlState: string | number; + messagePrimary: string | string[]; + }) { let isdup = err.code === 23505 || err.code === "23505" || @@ -6368,20 +7927,27 @@ Email verified! You can close this tab or hit the back button. return isdup; } - function failWithRetryRequest(res) { + function failWithRetryRequest(res: { + setHeader: (arg0: string, arg1: number) => void; + writeHead: ( + arg0: number + ) => { (): any; new (): any; send: { (arg0: number): void; new (): any } }; + }) { res.setHeader("Retry-After", 0); console.warn(57493875); res.writeHead(500).send(57493875); } - function getNumberOfCommentsWithModerationStatus(zid, mod) { + function getNumberOfCommentsWithModerationStatus(zid: any, mod: any) { + // 'new' expression, whose target lacks a construct signature, implicitly has an 'any' type.ts(7009) + // @ts-ignore return new MPromise( "getNumberOfCommentsWithModerationStatus", - function (resolve, reject) { + function (resolve: (arg0: any) => void, reject: (arg0: any) => void) { pgQuery_readOnly( "select count(*) from comments where zid = ($1) and mod = ($2);", [zid, mod], - function (err, result) { + function (err: any, result: { rows: { count: any }[] }) { if (err) { reject(err); } else { @@ -6399,7 +7965,12 @@ Email verified! You can close this tab or hit the back button. ); } - function sendCommentModerationEmail(req, uid, zid, unmoderatedCommentCount) { + function sendCommentModerationEmail( + req: any, + uid: number, + zid: any, + unmoderatedCommentCount: string | number + ) { if (_.isUndefined(unmoderatedCommentCount)) { unmoderatedCommentCount = ""; } @@ -6411,12 +7982,12 @@ Email verified! You can close this tab or hit the back button. } getZinvite(zid) - .catch(function (err) { + .catch(function (err: any) { console.error(err); yell("polis_err_getting_zinvite"); return void 0; }) - .then(function (zinvite) { + .then(function (zinvite: any) { // NOTE: the counter goes in the email body so it doesn't create a new email thread (in Gmail, etc) body += createProdModerationUrl(zinvite); @@ -6433,22 +8004,25 @@ Email verified! You can close this tab or hit the back button. body ); }) - .catch(function (err) { + .catch(function (err: any) { console.error(err); }); } - function createProdModerationUrl(zinvite) { + function createProdModerationUrl(zinvite: string) { return "https://pol.is/m/" + zinvite; } - function createModerationUrl(req, zinvite) { + function createModerationUrl( + req: { p?: ConversationType; protocol?: string; headers?: Headers }, + zinvite: string + ) { let server = devMode ? "http://localhost:5000" : "https://pol.is"; if (domainOverride) { - server = req.protocol + "://" + domainOverride; + server = req?.protocol + "://" + domainOverride; } - if (req.headers.host.includes("preprod.pol.is")) { + if (req?.headers?.host?.includes("preprod.pol.is")) { server = "https://preprod.pol.is"; } let url = server + "/m/" + zinvite; @@ -6477,12 +8051,21 @@ Email verified! You can close this tab or hit the back button. // return server + "/"+path+"?" + paramsToStringSortedByName(params); // } - function moderateComment(zid, tid, active, mod, is_meta) { - return new Promise(function (resolve, reject) { + function moderateComment( + zid: string, + tid: number, + active: boolean, + mod: boolean, + is_meta: boolean + ) { + return new Promise(function ( + resolve: () => void, + reject: (arg0: any) => void + ) { pgQuery( "UPDATE COMMENTS SET active=($3), mod=($4), modified=now_as_millis(), is_meta = ($5) WHERE zid=($1) and tid=($2);", [zid, tid, active, mod, is_meta], - function (err) { + function (err: any) { if (err) { reject(err); } else { @@ -6564,7 +8147,7 @@ Email verified! You can close this tab or hit the back button. // fail(res, 500, err); // }); // } - function hasBadWords(txt) { + function hasBadWords(txt: string) { txt = txt.toLowerCase(); let tokens = txt.split(" "); for (var i = 0; i < tokens.length; i++) { @@ -6575,26 +8158,41 @@ Email verified! You can close this tab or hit the back button. return false; } - function commentExists(zid, txt) { + function commentExists(zid: any, txt: any) { return pgQueryP( "select zid from comments where zid = ($1) and txt = ($2);", [zid, txt] - ).then(function (rows) { + // Argument of type '(rows: string | any[]) => number | ""' is not assignable to parameter of type '(value: unknown) => number | "" | PromiseLike'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + ).then(function (rows: string | any[]) { return rows && rows.length; }); } - function handle_POST_comments_slack(req, res) { + function handle_POST_comments_slack( + req: { + p: SlackUser; + }, + res: any + ) { const slack_team = req.p.slack_team; const slack_user_id = req.p.slack_user_id; pgQueryP( "select * from slack_users where slack_team = ($1) and slack_user_id = ($2);", [slack_team, slack_user_id] ) - .then((rows) => { + // Argument of type '(rows: string | any[]) => any' is not assignable to parameter of type '(value: unknown) => any'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + .then((rows: string | any[]) => { if (!rows || !rows.length) { const uidPromise = createDummyUser(); - return uidPromise.then((uid) => { + return uidPromise.then((uid?: any) => { return pgQueryP( "insert into slack_users (uid, slack_team, slack_user_id) values ($1, $2, $3) returning *;", [uid, slack_team, slack_user_id] @@ -6603,15 +8201,15 @@ Email verified! You can close this tab or hit the back button. } return rows; }) - .then((slack_user_rows) => { - return getPidPromise(req.p.zid, req.p.uid, true).then((pid) => { + .then((slack_user_rows: any) => { + return getPidPromise(req.p.zid, req.p.uid, true).then((pid: number) => { if (pid >= 0) { req.p.pid = pid; } return slack_user_rows; }); }) - .then((slack_user_rows) => { + .then((slack_user_rows: string | any[]) => { if (!slack_user_rows || !slack_user_rows.length) { fail(res, 500, "polis_err_post_comments_slack_missing_slack_user"); } @@ -6620,12 +8218,32 @@ Email verified! You can close this tab or hit the back button. handle_POST_comments(req, res); }) - .catch((err) => { + .catch((err: any) => { fail(res, 500, "polis_err_post_comments_slack_misc", err); }); } - function handle_POST_comments(req, res) { + function handle_POST_comments( + req: { + p: { + zid?: any; + uid?: any; + txt?: any; + pid?: any; + vote?: any; + twitter_tweet_id?: any; + quote_twitter_screen_name?: any; + quote_txt?: any; + quote_src_url?: any; + anon?: any; + is_seed?: any; + }; + headers?: Headers; + connection?: { remoteAddress: any; socket: { remoteAddress: any } }; + socket?: { remoteAddress: any }; + }, + res: { json: (arg0: { tid: any; currentPid: any }) => void } + ) { let zid = req.p.zid; let xid = void 0; //req.p.xid; let uid = req.p.uid; @@ -6664,13 +8282,19 @@ Email verified! You can close this tab or hit the back button. // PID_FLOW if (_.isUndefined(pid)) { - return getPidPromise(req.p.zid, req.p.uid, true).then((pid) => { + return getPidPromise(req.p.zid, req.p.uid, true).then((pid: number) => { if (pid === -1) { console.log( "POST_comments doGetPid addParticipant begin", Date.now() ); - return addParticipant(req.p.zid, req.p.uid).then(function (rows) { + // Argument of type '(rows: any[]) => number' is not assignable to parameter of type '(value: unknown) => number | PromiseLike'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + return addParticipant(req.p.zid, req.p.uid).then(function ( + rows: any[] + ) { let ptpt = rows[0]; pid = ptpt.pid; currentPid = pid; @@ -6703,7 +8327,17 @@ Email verified! You can close this tab or hit the back button. twitterPrepPromise .then( - function (info) { + // No overload matches this call. + // Overload 1 of 2, '(onFulfill?: ((value: void) => any) | undefined, onReject?: ((error: any) => any) | undefined): Bluebird', gave the following error. + // Argument of type '(info: { ptpt: any; tweet: any; }) => Bluebird' is not assignable to parameter of type '(value: void) => any'. + // Types of parameters 'info' and 'value' are incompatible. + // Type 'void' is not assignable to type '{ ptpt: any; tweet: any; }'. + // Overload 2 of 2, '(onfulfilled?: ((value: void) => any) | null | undefined, onrejected?: ((reason: any) => Resolvable) | null | undefined): Bluebird', gave the following error. + // Argument of type '(info: { ptpt: any; tweet: any; }) => Bluebird' is not assignable to parameter of type '(value: void) => any'. + // Types of parameters 'info' and 'value' are incompatible. + // Type 'void' is not assignable to type '{ ptpt: any; tweet: any; }'.ts(2769) + // @ts-ignore + function (info: { ptpt: any; tweet: any }) { console.log("POST_comments after twitterPrepPromise", Date.now()); let ptpt = info && info.ptpt; @@ -6721,20 +8355,20 @@ Email verified! You can close this tab or hit the back button. } let ip = - req.headers["x-forwarded-for"] || // TODO This header may contain multiple IP addresses. Which should we report? - req.connection.remoteAddress || - req.socket.remoteAddress || - req.connection.socket.remoteAddress; + req?.headers?.["x-forwarded-for"] || // TODO This header may contain multiple IP addresses. Which should we report? + req?.connection?.remoteAddress || + req?.socket?.remoteAddress || + req?.connection?.socket.remoteAddress; let isSpamPromise = isSpam({ comment_content: txt, comment_author: uid, permalink: "https://pol.is/" + zid, user_ip: ip, - user_agent: req.headers["user-agent"], - referrer: req.headers.referer, + user_agent: req?.headers?.["user-agent"], + referrer: req?.headers?.referer, }); - isSpamPromise.catch(function (err) { + isSpamPromise.catch(function (err: any) { console.error("isSpam failed"); winston.log("info", err); }); @@ -6755,15 +8389,18 @@ Email verified! You can close this tab or hit the back button. !_.isUndefined(xid) && !_.isNull(xid) ? getXidStuff(xid, zid) : Promise.resolve(); - pidPromise = xidUserPromise.then((xidUser) => { + pidPromise = xidUserPromise.then((xidUser: UserType) => { shouldCreateXidRecord = xidUser === "noXidRecord"; if (xidUser && xidUser.uid) { uid = xidUser.uid; pid = xidUser.pid; return pid; } else { - return doGetPid().then((pid) => { + return doGetPid().then((pid: any) => { if (shouldCreateXidRecord) { + // Expected 6 arguments, but got 3.ts(2554) + // conversation.ts(34, 3): An argument for 'x_profile_image_url' was not provided. + // @ts-ignore return createXidRecordByZid(zid, uid, xid).then(() => { return pid; }); @@ -6784,7 +8421,7 @@ Email verified! You can close this tab or hit the back button. isModeratorPromise, commentExistsPromise, ]).then( - function (results) { + function (results: any[]) { console.log("POST_comments after Promise.all", Date.now()); let pid = results[0]; @@ -6823,7 +8460,7 @@ Email verified! You can close this tab or hit the back button. console.log("POST_comments before isSpamPromise", Date.now()); return isSpamPromise .then( - function (spammy) { + function (spammy: any) { winston.log( "info", "spam test says: " + @@ -6833,13 +8470,13 @@ Email verified! You can close this tab or hit the back button. ); return spammy; }, - function (err) { + function (err: any) { console.error("spam check failed"); winston.log("info", err); return false; // spam check failed, continue assuming "not spammy". } ) - .then(function (spammy) { + .then(function (spammy: any) { console.log("POST_comments after isSpamPromise", Date.now()); let velocity = 1; let active = true; @@ -6882,7 +8519,7 @@ Email verified! You can close this tab or hit the back button. Date.now() ); - Promise.all([detectLanguage(txt)]).then((a) => { + Promise.all([detectLanguage(txt)]).then((a: any[]) => { let detections = a[0]; let detection = Array.isArray(detections) ? detections[0] @@ -6910,7 +8547,11 @@ Email verified! You can close this tab or hit the back button. lang_confidence, ] ).then( - function (docs) { + // Argument of type '(docs: any[]) => any' is not assignable to parameter of type '(value: unknown) => any'. + // Types of parameters 'docs' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + function (docs: any[]) { let comment = docs && docs[0]; let tid = comment && comment.tid; // let createdTime = comment && comment.created; @@ -6920,20 +8561,21 @@ Email verified! You can close this tab or hit the back button. zid, polisTypes.mod.unmoderated ) - .catch(function (err) { + .catch(function (err: any) { yell("polis_err_getting_modstatus_comment_count"); return void 0; }) - .then(function (n) { + .then(function (n: number) { if (n === 0) { return; } pgQueryP_readOnly( "select * from users where site_id = (select site_id from page_ids where zid = ($1)) UNION select * from users where uid = ($2);", [zid, conv.owner] - ).then(function (users) { + ).then(function (users: any) { let uids = _.pluck(users, "uid"); - uids.forEach(function (uid) { + // also notify polis team for moderation + uids.forEach(function (uid?: any) { sendCommentModerationEmail(req, uid, zid, n); }); }); @@ -6957,39 +8599,51 @@ Email verified! You can close this tab or hit the back button. ? Promise.resolve() : votesPost(uid, pid, zid, tid, vote, 0, false); - return votePromise.then( - function (o) { - if (o && o.vote && o.vote.created) { - createdTime = o.vote.created; - } - - setTimeout(function () { - updateConversationModifiedTime(zid, createdTime); - updateLastInteractionTimeForConversation( - zid, - uid - ); - if (!_.isUndefined(vote)) { - updateVoteCount(zid, pid); + return ( + votePromise + // This expression is not callable. + //Each member of the union type '{ (onFulfill?: ((value: void) => Resolvable) | undefined, onReject?: ((error: any) => Resolvable) | undefined): Bluebird; (onfulfilled?: ((value: void) => Resolvable<...>) | ... 1 more ... | undefined, onrejected?: ((reason: any) => Resolvable<...>) | ... 1 more ... | u...' has signatures, but none of those signatures are compatible with each other.ts(2349) + // @ts-ignore + .then( + function (o: { vote: { created: any } }) { + if (o && o.vote && o.vote.created) { + createdTime = o.vote.created; + } + + setTimeout(function () { + updateConversationModifiedTime( + zid, + createdTime + ); + updateLastInteractionTimeForConversation( + zid, + uid + ); + if (!_.isUndefined(vote)) { + updateVoteCount(zid, pid); + } + }, 100); + + console.log( + "POST_comments sending json", + Date.now() + ); + res.json({ + tid: tid, + currentPid: currentPid, + }); + console.log( + "POST_comments sent json", + Date.now() + ); + }, + function (err: any) { + fail(res, 500, "polis_err_vote_on_create", err); } - }, 100); - - console.log( - "POST_comments sending json", - Date.now() - ); - res.json({ - tid: tid, - currentPid: currentPid, - }); - console.log("POST_comments sent json", Date.now()); - }, - function (err) { - fail(res, 500, "polis_err_vote_on_create", err); - } + ) ); }, - function (err) { + function (err: { code: string | number }) { if (err.code === "23505" || err.code === 23505) { // duplicate comment fail( @@ -7006,7 +8660,7 @@ Email verified! You can close this tab or hit the back button. }); // lang }); }, - function (errors) { + function (errors: any[]) { if (errors[0]) { fail(res, 500, "polis_err_getting_pid", errors[0]); return; @@ -7018,11 +8672,11 @@ Email verified! You can close this tab or hit the back button. } ); }, - function (err) { + function (err: any) { fail(res, 500, "polis_err_fetching_tweet", err); } ) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_post_comment_misc", err); }); @@ -7055,8 +8709,11 @@ Email verified! You can close this tab or hit the back button. ////}); // nextTick //}); // BEGIN } // end POST /api/v3/comments - function handle_GET_votes_me(req, res) { - getPid(req.p.zid, req.p.uid, function (err, pid) { + function handle_GET_votes_me( + req: { p: { zid: any; uid?: any; pid: any } }, + res: any + ) { + getPid(req.p.zid, req.p.uid, function (err: any, pid: number) { if (err || pid < 0) { fail(res, 500, "polis_err_getting_pid", err); return; @@ -7064,7 +8721,7 @@ Email verified! You can close this tab or hit the back button. pgQuery_readOnly( "SELECT * FROM votes WHERE zid = ($1) AND pid = ($2);", [req.p.zid, req.p.pid], - function (err, docs) { + function (err: any, docs: { rows: string | any[] }) { if (err) { fail(res, 500, "polis_err_get_votes_by_me", err); return; @@ -7078,12 +8735,12 @@ Email verified! You can close this tab or hit the back button. }); } - function handle_GET_votes(req, res) { + function handle_GET_votes(req: { p: any }, res: any) { getVotesForSingleParticipant(req.p).then( - function (votes) { + function (votes: any) { finishArray(res, votes); }, - function (err) { + function (err: any) { fail(res, 500, "polis_err_votes_get", err); } ); @@ -7116,11 +8773,19 @@ Email verified! You can close this tab or hit the back button. //} //}); //} - function selectProbabilistically(comments, priorities, nTotal, nRemaining) { + function selectProbabilistically( + comments: any, + priorities: { [x: string]: any }, + nTotal: number, + nRemaining: number + ) { // Here we go through all of the comments we might select for the user and add their priority values let lookup = _.reduce( comments, - (o, comment) => { + ( + o: { lastCount: any; lookup: any[][] }, + comment: { tid: string | number } + ) => { // If we like, we can use nTotal and nRemaining here to figure out how much we should emphasize the // priority, potentially. Maybe we end up with different classes of priorities lists for this purpose? // scaling this value in some way may also be helpful. @@ -7136,16 +8801,23 @@ Email verified! You can close this tab or hit the back button. // Return the first one that has a greater lookup; could eventually replace this with something smarter // that does a bisectional lookup if performance becomes an issue. But I want to keep the implementation // simple to reason about all other things being equal. - let result = _.find(lookup.lookup, (x) => x[0] > randomN); - let c = result[1]; + let result = _.find(lookup.lookup, (x: number[]) => x[0] > randomN); + let c = result?.[1]; c.randomN = randomN; return c; } // This very much follows the outline of the random selection above, but factors out the probabilistic logic // to the selectProbabilistically fn above. - function getNextPrioritizedComment(zid, pid, withoutTids, include_social) { - let params = { + function getNextPrioritizedComment( + zid: string, + pid: string, + withoutTids: string | any[], + include_social: any + ) { + // Type '{ zid: string; not_voted_by_pid: string; include_social: any; }' is missing the following properties from type 'CommentType': withoutTids, include_voting_patterns, modIn, pid, and 7 more.ts(2740) + // @ts-ignore + let params: CommentType = { zid: zid, not_voted_by_pid: pid, include_social: include_social, @@ -7158,7 +8830,7 @@ Email verified! You can close this tab or hit the back button. getComments(params), getPca(zid, 0), getNumberOfCommentsRemaining(zid, pid), - ]).then((results) => { + ]).then((results: any[]) => { let comments = results[0]; let math = results[1]; let numberOfCommentsRemainingRows = results[2]; @@ -7262,14 +8934,20 @@ Email verified! You can close this tab or hit the back button. // }); // } - function getCommentTranslations(zid, tid) { - return pg.queryP( + function getCommentTranslations(zid: any, tid: any) { + return dbPgQuery.queryP( "select * from comment_translations where zid = ($1) and tid = ($2);", [zid, tid] ); } - function getNextComment(zid, pid, withoutTids, include_social, lang) { + function getNextComment( + zid?: any, + pid?: any, + withoutTids?: any, + include_social?: boolean, + lang?: string + ) { // return getNextCommentPrioritizingNonPassedComments(zid, pid, withoutTids, !!!!!!!!!!!!!!!!TODO IMPL!!!!!!!!!!!include_social); //return getNextCommentRandomly(zid, pid, withoutTids, include_social).then((c) => { return getNextPrioritizedComment( @@ -7277,17 +8955,17 @@ Email verified! You can close this tab or hit the back button. pid, withoutTids, include_social - ).then((c) => { + ).then((c: CommentType) => { if (lang && c) { const firstTwoCharsOfLang = lang.substr(0, 2); - return getCommentTranslations(zid, c.tid).then((translations) => { + return getCommentTranslations(zid, c.tid).then((translations: any) => { c.translations = translations; - let hasMatch = _.some(translations, (t) => { + let hasMatch = _.some(translations, (t: { lang: string }) => { return t.lang.startsWith(firstTwoCharsOfLang); }); if (!hasMatch) { return translateAndStoreComment(zid, c.tid, c.txt, lang).then( - (translation) => { + (translation: any) => { if (translation) { c.translations.push(translation); } @@ -7305,7 +8983,7 @@ Email verified! You can close this tab or hit the back button. } // NOTE: only call this in response to a vote. Don't call this from a poll, like /api/v3/nextComment - function addNoMoreCommentsRecord(zid, pid) { + function addNoMoreCommentsRecord(zid: any, pid: any) { return pgQueryP( "insert into event_ptpt_no_more_comments (zid, pid, votes_placed) values ($1, $2, " + "(select count(*) from votes where zid = ($1) and pid = ($2)))", @@ -7313,7 +8991,23 @@ Email verified! You can close this tab or hit the back button. ); } - function handle_GET_nextComment(req, res) { + function handle_GET_nextComment( + req: { + timedout: any; + p: { + zid: any; + not_voted_by_pid: any; + without: any; + include_social: any; + lang: any; + }; + }, + res: { + status: ( + arg0: number + ) => { (): any; new (): any; json: { (arg0: {}): void; new (): any } }; + } + ) { if (req.timedout) { return; } @@ -7332,7 +9026,7 @@ Email verified! You can close this tab or hit the back button. req.p.lang ) .then( - function (c) { + function (c: { currentPid: any }) { if (req.timedout) { return; } @@ -7342,30 +9036,65 @@ Email verified! You can close this tab or hit the back button. } finishOne(res, c); } else { - let o = {}; + let o: CommentOptions = {}; if (!_.isUndefined(req.p.not_voted_by_pid)) { o.currentPid = req.p.not_voted_by_pid; } res.status(200).json(o); } }, - function (err) { + function (err: any) { if (req.timedout) { return; } fail(res, 500, "polis_err_get_next_comment2", err); } ) - .catch(function (err) { + .catch(function (err: any) { if (req.timedout) { return; } fail(res, 500, "polis_err_get_next_comment", err); }); } - function handle_GET_participationInit(req, res) { + function handle_GET_participationInit( + req: { + p: { + conversation_id: any; + uid?: any; + lang: string; + zid: any; + xid: any; + owner_uid?: any; + pid: any; + }; + headers?: Headers; + cookies: { [x: string]: any }; + }, + res: { + status: ( + arg0: number + ) => { + (): any; + new (): any; + json: { + (arg0: { + user: any; + ptpt: any; + nextComment: any; + conversation: any; + votes: any; + pca: any; + famous: any; + // famous: JSON.parse(arr[6]), + acceptLanguage: any; + }): void; + new (): any; + }; + }; + } + ) { console.log("logging handle_GET_participationInit req", req); - // let qs = { // conversation_id: req.p.conversation_id, // }; @@ -7410,7 +9139,23 @@ Email verified! You can close this tab or hit the back button. // }); // } - function ifConv(f, args) { + function ifConv( + f: { + ( + zid: any, + pid: any, + withoutTids: any, + include_social: any, + lang?: any + ): CommentType; + (zid: any, uid?: any, lang?: any): any; + (p: any): any; + (zid: any, math_tick: any): any; + (o: any, req: any): any; + apply?: any; + }, + args: any[] + ) { if (req.p.conversation_id) { return f.apply(null, args); } else { @@ -7418,7 +9163,7 @@ Email verified! You can close this tab or hit the back button. } } - function ifConvAndAuth(f, args) { + function ifConvAndAuth(f: (zid: any, uid?: any) => any, args: any[]) { if (req.p.uid) { return ifConv(f, args); } else { @@ -7427,8 +9172,8 @@ Email verified! You can close this tab or hit the back button. } let acceptLanguage = - req.headers["accept-language"] || - req.headers["Accept-Language"] || + req?.headers?.["accept-language"] || + req?.headers?.["Accept-Language"] || "en-US"; if (req.p.lang === "acceptLang") { @@ -7445,18 +9190,34 @@ Email verified! You can close this tab or hit the back button. // getIfConvAndAuth({uri: "http://" + SELF_HOSTNAME + "/api/v3/participants", qs: qs, headers: req.headers, gzip: true}), ifConvAndAuth(getParticipant, [req.p.zid, req.p.uid]), // getIfConv({uri: "http://" + SELF_HOSTNAME + "/api/v3/nextComment", qs: nextCommentQs, headers: req.headers, gzip: true}), + // + // Argument of type '(zid?: any, pid?: any, withoutTids?: any, include_social?: boolean | undefined, lang?: string | undefined) => Bluebird' is not assignable to parameter of type '{ (zid: any, pid: any, withoutTids: any, include_social: any, lang?: any): CommentType; (zid: any, uid?: any, lang?: any): any; (p: any): any; (zid: any, math_tick: any): any; (o: any, req: any): any; apply?: any; }'. + // Type 'Bluebird' is missing the following properties from type 'CommentType': zid, not_voted_by_pid, withoutTids, include_voting_patterns, and 9 more.ts(2345) + // @ts-ignore ifConv(getNextComment, [req.p.zid, req.p.pid, [], true, req.p.lang]), // getIfConv({uri: "http://" + SELF_HOSTNAME + "/api/v3/conversations", qs: qs, headers: req.headers, gzip: true}), + // + // Argument of type '(zid: any, uid?: any, lang?: null | undefined) => Bluebird' is not assignable to parameter of type '{ (zid: any, pid: any, withoutTids: any, include_social: any, lang?: any): CommentType; (zid: any, uid?: any, lang?: any): any; (p: any): any; (zid: any, math_tick: any): any; (o: any, req: any): any; apply?: any; }'. + // Type 'Bluebird' is not assignable to type 'CommentType'.ts(2345) + // @ts-ignore ifConv(getOneConversation, [req.p.zid, req.p.uid, req.p.lang]), // getIfConv({uri: "http://" + SELF_HOSTNAME + "/api/v3/votes", qs: votesByMeQs, headers: req.headers, gzip: true}), ifConv(getVotesForSingleParticipant, [req.p]), + // + // Argument of type '(zid?: any, math_tick?: number | undefined) => Promise' is not assignable to parameter of type '{ (zid: any, pid: any, withoutTids: any, include_social: any, lang?: any): CommentType; (zid: any, uid?: any, lang?: any): any; (p: any): any; (zid: any, math_tick: any): any; (o: any, req: any): any; apply?: any; }'. + // Type 'Promise' is missing the following properties from type 'CommentType': zid, not_voted_by_pid, withoutTids, include_voting_patterns, and 9 more.ts(2345) + // @ts-ignore ifConv(getPca, [req.p.zid, -1]), // getWith304AsSuccess({uri: "http://" + SELF_HOSTNAME + "/api/v3/math/pca2", qs: qs, headers: req.headers, gzip: true}), + // + // Argument of type '(o?: { uid?: any; zid: any; math_tick: any; ptptoiLimit: any; } | undefined, req?: any) => Bluebird<{}>' is not assignable to parameter of type '{ (zid: any, pid: any, withoutTids: any, include_social: any, lang?: any): CommentType; (zid: any, uid?: any, lang?: any): any; (p: any): any; (zid: any, math_tick: any): any; (o: any, req: any): any; apply?: any; }'. + // Type 'Bluebird<{}>' is missing the following properties from type 'CommentType': zid, not_voted_by_pid, withoutTids, include_voting_patterns, and 9 more.ts(2345) + // @ts-ignore ifConv(doFamousQuery, [req.p, req]), // getIfConv({uri: "http://" + SELF_HOSTNAME + "/api/v3/votes/famous", qs: famousQs, headers: req.headers, gzip: true}), ]) .then( - function (arr) { + function (arr: any[]) { let conv = arr[3]; let o = { user: arr[0], @@ -7489,18 +9250,18 @@ Email verified! You can close this tab or hit the back button. res.status(200).json(o); }, - function (err) { + function (err: any) { console.error(err); fail(res, 500, "polis_err_get_participationInit2", err); } ) - .catch(function (err) { + .catch(function (err: any) { console.error(err); fail(res, 500, "polis_err_get_participationInit", err); }); } - function updateConversationModifiedTime(zid, t) { + function updateConversationModifiedTime(zid: any, t?: undefined) { let modified = _.isUndefined(t) ? Date.now() : Number(t); let query = "update conversations set modified = ($2) where zid = ($1) and modified < ($2);"; @@ -7516,11 +9277,14 @@ Email verified! You can close this tab or hit the back button. const createXidRecordByZid = Conversation.createXidRecordByZid; const getXidStuff = User.getXidStuff; - function handle_PUT_participants_extended(req, res) { + function handle_PUT_participants_extended( + req: { p: { zid: any; uid?: any; show_translation_activated: any } }, + res: { json: (arg0: any) => void } + ) { let zid = req.p.zid; let uid = req.p.uid; - let fields = {}; + let fields: ParticipantFields = {}; if (!_.isUndefined(req.p.show_translation_activated)) { fields.show_translation_activated = req.p.show_translation_activated; } @@ -7531,15 +9295,22 @@ Email verified! You can close this tab or hit the back button. .and(sql_participants_extended.uid.equals(uid)); pgQueryP(q.toString(), []) - .then((result) => { + .then((result: any) => { res.json(result); }) - .catch((err) => { + .catch((err: any) => { fail(res, 500, "polis_err_put_participants_extended", err); }); } - function handle_POST_votes(req, res) { + function handle_POST_votes( + req: { + p: Vote; + cookies: { [x: string]: any }; + headers?: Headers; + }, + res: any + ) { let uid = req.p.uid; // PID_FLOW uid may be undefined here. let zid = req.p.zid; let pid = req.p.pid; // PID_FLOW pid may be undefined here. @@ -7547,8 +9318,8 @@ Email verified! You can close this tab or hit the back button. // We allow viewing (and possibly writing) without cookies enabled, but voting requires cookies (except the auto-vote on your own comment, which seems ok) let token = req.cookies[COOKIES.TOKEN]; - let apiToken = req.headers.authorization; - let xPolisHeaderToken = req.headers["x-polis"]; + let apiToken = req?.headers?.authorization || ""; + let xPolisHeaderToken = req?.headers?.["x-polis"]; if (!uid && !token && !apiToken && !xPolisHeaderToken) { fail(res, 403, "polis_err_vote_noauth"); return; @@ -7563,7 +9334,7 @@ Email verified! You can close this tab or hit the back button. req.p.uid, req, permanent_cookie - ).then(function (rows) { + ).then(function (rows: any[]) { let ptpt = rows[0]; pid = ptpt.pid; }) @@ -7575,7 +9346,11 @@ Email verified! You can close this tab or hit the back button. // PID_FLOW WIP for now assume we have a uid, but need a participant record. let pidReadyPromise = _.isUndefined(pid) - ? addParticipant(zid, uid).then(function (rows) { + ? // Argument of type '(rows: any[]) => void' is not assignable to parameter of type '(value: unknown) => void | PromiseLike'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + addParticipant(zid, uid).then(function (rows: any[]) { let ptpt = rows[0]; pid = ptpt.pid; }) @@ -7593,7 +9368,7 @@ Email verified! You can close this tab or hit the back button. true ); }) - .then(function (o) { + .then(function (o: { vote: any }) { // conv = o.conv; vote = o.vote; let createdTime = vote.created; @@ -7613,8 +9388,8 @@ Email verified! You can close this tab or hit the back button. .then(function () { return getNextComment(zid, pid, [], true, lang); }) - .then(function (nextComment) { - let result = {}; + .then(function (nextComment: any) { + let result: PidReadyResult = {}; if (nextComment) { result.nextComment = nextComment; } else { @@ -7645,7 +9420,7 @@ Email verified! You can close this tab or hit the back button. finishOne(res, result); }); }) - .catch(function (err) { + .catch(function (err: string) { if (err === "polis_err_vote_duplicate") { fail(res, 406, "polis_err_vote_duplicate", err); // TODO allow for changing votes? } else if (err === "polis_err_conversation_is_closed") { @@ -7658,7 +9433,28 @@ Email verified! You can close this tab or hit the back button. }); } - function handle_POST_ptptCommentMod(req, res) { + function handle_POST_ptptCommentMod( + req: { + p: { + zid: any; + pid: any; + uid?: any; + tid: any; + as_abusive: any; + as_factual: any; + as_feeling: any; + as_important: any; + as_notfact: any; + as_notgoodidea: any; + as_notmyfeeling: any; + as_offtopic: any; + as_spam: any; + unsure: any; + lang: any; + }; + }, + res: any + ) { let zid = req.p.zid; let pid = req.p.pid; @@ -7712,7 +9508,7 @@ Email verified! You can close this tab or hit the back button. req.p.unsure, ] ) - .then((createdTime) => { + .then((createdTime: any) => { setTimeout(function () { updateConversationModifiedTime(req.p.zid, createdTime); updateLastInteractionTimeForConversation(zid, uid); @@ -7721,8 +9517,8 @@ Email verified! You can close this tab or hit the back button. .then(function () { return getNextComment(req.p.zid, pid, [], true, req.p.lang); // TODO req.p.lang is probably not defined }) - .then(function (nextComment) { - let result = {}; + .then(function (nextComment: any) { + let result: ParticipantCommentModerationResult = {}; if (nextComment) { result.nextComment = nextComment; } else { @@ -7733,7 +9529,7 @@ Email verified! You can close this tab or hit the back button. result.currentPid = req.p.pid; finishOne(res, result); }) - .catch(function (err) { + .catch(function (err: string) { if (err === "polis_err_ptptCommentMod_duplicate") { fail(res, 406, "polis_err_ptptCommentMod_duplicate", err); // TODO allow for changing votes? } else if (err === "polis_err_conversation_is_closed") { @@ -7744,7 +9540,14 @@ Email verified! You can close this tab or hit the back button. }); } - function handle_POST_upvotes(req, res) { + function handle_POST_upvotes( + req: { p: { uid?: any; zid: any } }, + res: { + status: ( + arg0: number + ) => { (): any; new (): any; json: { (arg0: {}): void; new (): any } }; + } + ) { let uid = req.p.uid; let zid = req.p.zid; @@ -7752,7 +9555,12 @@ Email verified! You can close this tab or hit the back button. uid, zid, ]).then( - function (rows) { + // Argument of type '(rows: string | any[]) => void' is not assignable to parameter of type '(value: unknown) => void | PromiseLike'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + function (rows: string | any[]) { if (rows && rows.length) { fail(res, 403, "polis_err_upvote_already_upvoted"); } else { @@ -7768,23 +9576,29 @@ Email verified! You can close this tab or hit the back button. function () { res.status(200).json({}); }, - function (err) { + function (err: any) { fail(res, 500, "polis_err_upvote_update", err); } ); }, - function (err) { + function (err: any) { fail(res, 500, "polis_err_upvote_insert", err); } ); } }, - function (err) { + function (err: any) { fail(res, 500, "polis_err_upvote_check", err); } ); } - function addStar(zid, tid, pid, starred, created) { + function addStar( + zid: any, + tid: any, + pid: any, + starred: number, + created?: undefined + ) { starred = starred ? 1 : 0; let query = "INSERT INTO stars (pid, zid, tid, starred, created) VALUES ($1, $2, $3, $4, default) RETURNING created;"; @@ -7796,16 +9610,27 @@ Email verified! You can close this tab or hit the back button. } return pgQueryP(query, params); } - function handle_POST_stars(req, res) { + function handle_POST_stars( + req: { p: { zid: any; tid: any; pid: any; starred: any } }, + res: { + status: ( + arg0: number + ) => { (): any; new (): any; json: { (arg0: {}): void; new (): any } }; + } + ) { addStar(req.p.zid, req.p.tid, req.p.pid, req.p.starred) - .then(function (result) { + // Argument of type '(result: { rows: { created: any; }[]; }) => void' is not assignable to parameter of type '(value: unknown) => void | PromiseLike'. + // Types of parameters 'result' and 'value' are incompatible. + // Type 'unknown' is not assignable to type '{ rows: { created: any; }[]; }'.ts(2345) + // @ts-ignore + .then(function (result: { rows: { created: any }[] }) { let createdTime = result.rows[0].created; setTimeout(function () { updateConversationModifiedTime(req.p.zid, createdTime); }, 100); res.status(200).json({}); // TODO don't stop after the first one, map the inserts to deferreds. }) - .catch(function (err) { + .catch(function (err: any) { if (err) { if (isDuplicateKey(err)) { fail(res, 406, "polis_err_vote_duplicate", err); // TODO allow for changing votes? @@ -7816,35 +9641,49 @@ Email verified! You can close this tab or hit the back button. }); } - function handle_POST_trashes(req, res) { + function handle_POST_trashes( + req: { p: { pid: any; zid: any; tid: any; trashed: any } }, + res: { + status: ( + arg0: number + ) => { (): any; new (): any; json: { (arg0: {}): void; new (): any } }; + } + ) { let query = "INSERT INTO trashes (pid, zid, tid, trashed, created) VALUES ($1, $2, $3, $4, default);"; let params = [req.p.pid, req.p.zid, req.p.tid, req.p.trashed]; - pgQuery(query, params, function (err, result) { - if (err) { - if (isDuplicateKey(err)) { - fail(res, 406, "polis_err_vote_duplicate", err); // TODO allow for changing votes? - } else { - fail(res, 500, "polis_err_vote", err); + pgQuery( + query, + params, + function (err: any, result: { rows: { created: any }[] }) { + if (err) { + if (isDuplicateKey(err)) { + fail(res, 406, "polis_err_vote_duplicate", err); // TODO allow for changing votes? + } else { + fail(res, 500, "polis_err_vote", err); + } + return; } - return; - } - let createdTime = result.rows[0].created; - setTimeout(function () { - updateConversationModifiedTime(req.p.zid, createdTime); - }, 100); + let createdTime = result.rows[0].created; + setTimeout(function () { + updateConversationModifiedTime(req.p.zid, createdTime); + }, 100); - res.status(200).json({}); // TODO don't stop after the first one, map the inserts to deferreds. - }); + res.status(200).json({}); // TODO don't stop after the first one, map the inserts to deferreds. + } + ); } - function verifyMetadataAnswersExistForEachQuestion(zid) { + function verifyMetadataAnswersExistForEachQuestion(zid: any) { let errorcode = "polis_err_missing_metadata_answers"; - return new Promise(function (resolve, reject) { + return new Promise(function ( + resolve: () => void, + reject: (arg0: Error) => void + ) { pgQuery_readOnly( "select pmqid from participant_metadata_questions where zid = ($1);", [zid], - function (err, results) { + function (err: any, results: { rows: any[] }) { if (err) { reject(err); return; @@ -7853,7 +9692,7 @@ Email verified! You can close this tab or hit the back button. resolve(); return; } - let pmqids = results.rows.map(function (row) { + let pmqids = results.rows.map(function (row: { pmqid: any }) { return Number(row.pmqid); }); pgQuery_readOnly( @@ -7861,7 +9700,7 @@ Email verified! You can close this tab or hit the back button. pmqids.join(",") + ") and alive = TRUE and zid = ($1);", [zid], - function (err, results) { + function (err: any, results: { rows: any[] }) { if (err) { reject(err); return; @@ -7872,13 +9711,13 @@ Email verified! You can close this tab or hit the back button. } let questions = _.reduce( pmqids, - function (o, pmqid) { + function (o: { [x: string]: number }, pmqid: string | number) { o[pmqid] = 1; return o; }, {} ); - results.rows.forEach(function (row) { + results.rows.forEach(function (row: { pmqid: string | number }) { delete questions[row.pmqid]; }); if (Object.keys(questions).length) { @@ -7893,7 +9732,16 @@ Email verified! You can close this tab or hit the back button. }); } - function handle_PUT_comments(req, res) { + function handle_PUT_comments( + req: { + p: { uid?: any; zid: any; tid: any; active: any; mod: any; is_meta: any }; + }, + res: { + status: ( + arg0: number + ) => { (): any; new (): any; json: { (arg0: {}): void; new (): any } }; + } + ) { let uid = req.p.uid; let zid = req.p.zid; let tid = req.p.tid; @@ -7902,13 +9750,13 @@ Email verified! You can close this tab or hit the back button. let is_meta = req.p.is_meta; isModerator(zid, uid) - .then(function (isModerator) { + .then(function (isModerator: any) { if (isModerator) { moderateComment(zid, tid, active, mod, is_meta).then( function () { res.status(200).json({}); }, - function (err) { + function (err: any) { fail(res, 500, "polis_err_update_comment", err); } ); @@ -7916,19 +9764,22 @@ Email verified! You can close this tab or hit the back button. fail(res, 403, "polis_err_update_comment_auth"); } }) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_update_comment", err); }); } - function handle_POST_reportCommentSelections(req, res) { + function handle_POST_reportCommentSelections( + req: { p: { uid?: any; zid: any; rid: any; tid: any; include: any } }, + res: { json: (arg0: {}) => void } + ) { let uid = req.p.uid; let zid = req.p.zid; let rid = req.p.rid; let tid = req.p.tid; let selection = req.p.include ? 1 : -1; isModerator(zid, uid) - .then((isMod) => { + .then((isMod: any) => { if (!isMod) { return fail(res, 403, "polis_err_POST_reportCommentSelections_auth"); } @@ -7948,27 +9799,30 @@ Email verified! You can close this tab or hit the back button. res.json({}); }); }) - .catch((err) => { + .catch((err: any) => { fail(res, 500, "polis_err_POST_reportCommentSelections_misc", err); }); } // kind of crappy that we're replacing the zinvite. // This is needed because we initially create a conversation with the POST, then actually set the properties with the subsequent PUT. // if we stop doing that, we can remove this function. - function generateAndReplaceZinvite(zid, generateShortZinvite) { + function generateAndReplaceZinvite(zid: any, generateShortZinvite: any) { let len = 12; if (generateShortZinvite) { len = 6; } - return new Promise(function (resolve, reject) { - generateToken(len, false, function (err, zinvite) { + return new Promise(function ( + resolve: (arg0: any) => void, + reject: (arg0: string) => void + ) { + generateToken(len, false, function (err: any, zinvite: any) { if (err) { return reject("polis_err_creating_zinvite"); } pgQuery( "update zinvites set zinvite = ($1) where zid = ($2);", [zinvite, zid], - function (err, results) { + function (err: any, results: any) { if (err) { reject(err); } else { @@ -7981,9 +9835,13 @@ Email verified! You can close this tab or hit the back button. } function sendGradeForAssignment( - oauth_consumer_key, - oauth_consumer_secret, - params + oauth_consumer_key: any, + oauth_consumer_secret: any, + params: { + lis_result_sourcedid: string; + gradeFromZeroToOne: string; + lis_outcome_service_url: any; + } ) { let replaceResultRequestBody = "" + @@ -8017,6 +9875,8 @@ Email verified! You can close this tab or hit the back button. ""; let oauth = new OAuth.OAuth( + // Argument of type 'null' is not assignable to parameter of type 'string'.ts(2345) + // @ts-ignore null, //'https://api.twitter.com/oauth/request_token', null, //'https://api.twitter.com/oauth/access_token', oauth_consumer_key, //'your application consumer key', @@ -8025,14 +9885,19 @@ Email verified! You can close this tab or hit the back button. null, "HMAC-SHA1" ); - return new Promise(function (resolve, reject) { + return new Promise(function ( + resolve: (arg0: any, arg1: any) => void, + reject: (arg0: any) => void + ) { oauth.post( params.lis_outcome_service_url, //'https://api.twitter.com/1.1/trends/place.json?id=23424977', + // Argument of type 'undefined' is not assignable to parameter of type 'string'.ts(2345) + // @ts-ignore void 0, //'your user token for this app', //test user token void 0, //'your user secret for this app', //test user secret replaceResultRequestBody, "application/xml", - function (e, data, res) { + function (e: any, data: any, res: any) { if (e) { winston.log("info", "grades foo failed"); console.error(e); @@ -8047,7 +9912,7 @@ Email verified! You can close this tab or hit the back button. }); } - function sendCanvasGradesIfNeeded(zid, ownerUid) { + function sendCanvasGradesIfNeeded(zid: any, ownerUid: string) { // get the lti_user_ids for participants who voted or commented let goodLtiUserIdsPromise = pgQueryP( "select lti_user_id from " + @@ -8076,7 +9941,7 @@ Email verified! You can close this tab or hit the back button. goodLtiUserIdsPromise, callbackInfoPromise, ownerLtiCredsPromise, - ]).then(function (results) { + ]).then(function (results: any[]) { let isFullPointsEarningLtiUserId = _.indexBy(results[0], "lti_user_id"); let callbackInfos = results[1]; if (!callbackInfos || !callbackInfos.length) { @@ -8097,13 +9962,15 @@ Email verified! You can close this tab or hit the back button. throw new Error("polis_err_lti_oauth_credentials_are_bad " + ownerUid); } - let promises = callbackInfos.map(function (assignmentCallbackInfo) { + let promises = callbackInfos.map(function ( + assignmentCallbackInfo: Assignment + ) { let gradeFromZeroToOne = isFullPointsEarningLtiUserId[ assignmentCallbackInfo.lti_user_id ] ? 1.0 : 0.0; - assignmentCallbackInfo.gradeFromZeroToOne = gradeFromZeroToOne; + assignmentCallbackInfo.gradeFromZeroToOne = String(gradeFromZeroToOne); winston.log( "info", "grades assigned" + @@ -8121,10 +9988,18 @@ Email verified! You can close this tab or hit the back button. }); } - function updateLocalRecordsToReflectPostedGrades(listOfGradingContexts) { + function updateLocalRecordsToReflectPostedGrades( + listOfGradingContexts: any[] + ) { listOfGradingContexts = listOfGradingContexts || []; return Promise.all( - listOfGradingContexts.map(function (gradingContext) { + listOfGradingContexts.map(function (gradingContext: { + gradeFromZeroToOne: string; + tool_consumer_instance_guid?: any; + lti_context_id: any; + lti_user_id: any; + custom_canvas_assignment_id: any; + }) { winston.log( "info", "grading set to " + gradingContext.gradeFromZeroToOne @@ -8143,13 +10018,36 @@ Email verified! You can close this tab or hit the back button. ); } - function handle_GET_lti_oauthv1_credentials(req, res) { + function handle_GET_lti_oauthv1_credentials( + req: { p: { uid: string } }, + res: { + status: ( + arg0: number + ) => { + (): any; + new (): any; + json: { (arg0: string): void; new (): any }; + }; + } + ) { let uid = "FOO"; if (req.p && req.p.uid) { uid = req.p.uid; } Promise.all([generateTokenP(40, false), generateTokenP(40, false)]).then( - function (results) { + // No overload matches this call. + // Overload 1 of 2, '(onFulfill?: ((value: [unknown, unknown]) => Resolvable) | undefined, onReject?: ((error: any) => Resolvable) | undefined): + // Bluebird', gave the following error. + // Argument of type '(results: string[]) => void' is not assignable to parameter of type '(value: [unknown, unknown]) => Resolvable'. + // Types of parameters 'results' and 'value' are incompatible. + // Type '[unknown, unknown]' is not assignable to type 'string[]'. + // Type 'unknown' is not assignable to type 'string'. + // Overload 2 of 2, '(onfulfilled?: ((value: [unknown, unknown]) => Resolvable) | null | undefined, onrejected?: ((reason: any) => PromiseLike) | null | undefined): Bluebird', gave the following error. + // Argument of type '(results: string[]) => void' is not assignable to parameter of type '(value: [unknown, unknown]) => Resolvable'. + // Types of parameters 'results' and 'value' are incompatible. + // Type '[unknown, unknown]' is not assignable to type 'string[]'.ts(2769) + // @ts-ignore + function (results: string[]) { let key = "polis_oauth_consumer_key_" + results[0]; let secret = "polis_oauth_shared_secret_" + results[1]; let x = [uid, "'" + key + "'", "'" + secret + "'"].join(","); @@ -8164,7 +10062,14 @@ Email verified! You can close this tab or hit the back button. } ); } - function handle_POST_conversation_close(req, res) { + function handle_POST_conversation_close( + req: { p: { zid: any; uid?: any } }, + res: { + status: ( + arg0: number + ) => { (): any; new (): any; json: { (arg0: {}): void; new (): any } }; + } + ) { var q = "select * from conversations where zid = ($1)"; var params = [req.p.zid]; if (!isPolisDev(req.p.uid)) { @@ -8172,7 +10077,12 @@ Email verified! You can close this tab or hit the back button. params.push(req.p.uid); } pgQueryP(q, params) - .then(function (rows) { + // Argument of type '(rows: string | any[]) => void' is not assignable to parameter of type '(value: unknown) => void | PromiseLike'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + .then(function (rows: string | any[]) { if (!rows || !rows.length) { fail(res, 500, "polis_err_closing_conversation_no_such_conversation"); return; @@ -8195,13 +10105,13 @@ Email verified! You can close this tab or hit the back button. // might need to send some grades let ownerUid = req.p.uid; sendCanvasGradesIfNeeded(conv.zid, ownerUid) - .then(function (listOfContexts) { + .then(function (listOfContexts: any) { return updateLocalRecordsToReflectPostedGrades(listOfContexts); }) .then(function () { res.status(200).json({}); }) - .catch(function (err) { + .catch(function (err: any) { fail( res, 500, @@ -8210,7 +10120,7 @@ Email verified! You can close this tab or hit the back button. ); }); }) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_closing_conversation2", err); }); // } else { @@ -8218,12 +10128,19 @@ Email verified! You can close this tab or hit the back button. // res.status(204).send(""); // } }) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_closing_conversation", err); }); } - function handle_POST_conversation_reopen(req, res) { + function handle_POST_conversation_reopen( + req: { p: { zid: any; uid?: any } }, + res: { + status: ( + arg0: number + ) => { (): any; new (): any; json: { (arg0: {}): void; new (): any } }; + } + ) { var q = "select * from conversations where zid = ($1)"; var params = [req.p.zid]; if (!isPolisDev(req.p.uid)) { @@ -8231,7 +10148,12 @@ Email verified! You can close this tab or hit the back button. params.push(req.p.uid); } pgQueryP(q, params) - .then(function (rows) { + // Argument of type '(rows: string | any[]) => void' is not assignable to parameter of type '(value: unknown) => void | PromiseLike'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + .then(function (rows: string | any[]) { if (!rows || !rows.length) { fail(res, 500, "polis_err_closing_conversation_no_such_conversation"); return; @@ -8250,22 +10172,25 @@ Email verified! You can close this tab or hit the back button. } res.status(200).json({}); }) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_reopening_conversation2", err); }); }) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_reopening_conversation", err); }); } - function handle_PUT_users(req, res) { + function handle_PUT_users( + req: { p: { uid?: any; uid_of_user: any; email: any; hname: any } }, + res: { json: (arg0: any) => void } + ) { let uid = req.p.uid; if (isPolisDev(uid) && req.p.uid_of_user) { uid = req.p.uid_of_user; } - let fields = {}; + let fields: UserType = {}; if (!_.isUndefined(req.p.email)) { fields.email = req.p.email; } @@ -8276,18 +10201,53 @@ Email verified! You can close this tab or hit the back button. let q = sql_users.update(fields).where(sql_users.uid.equals(uid)); pgQueryP(q.toString(), []) - .then((result) => { + .then((result: any) => { res.json(result); }) - .catch((err) => { + .catch((err: any) => { fail(res, 500, "polis_err_put_user", err); }); } - function handle_PUT_conversations(req, res) { + function handle_PUT_conversations( + req: { + p: { + short_url: any; + zid: any; + uid?: any; + verifyMeta: any; + is_active: any; + is_anon: any; + is_draft: any; + is_data_open: any; + profanity_filter: any; + spam_filter: any; + strict_moderation: any; + topic: string; + description: string; + vis_type: any; + help_type: any; + socialbtn_type: any; + bgcolor: string; + help_color: string; + help_bgcolor: string; + style_btn: any; + write_type: any; + owner_sees_participation_stats: any; + launch_presentation_return_url_hex: any; + link_url: any; + send_created_email: any; + conversation_id: string; + custom_canvas_assignment_id: any; + tool_consumer_instance_guid?: any; + context: any; + }; + }, + res: any + ) { let generateShortUrl = req.p.short_url; isModerator(req.p.zid, req.p.uid) - .then(function (ok) { + .then(function (ok: any) { if (!ok) { fail(res, 403, "polis_err_update_conversation_permission"); return; @@ -8302,7 +10262,7 @@ Email verified! You can close this tab or hit the back button. verifyMetaPromise = Promise.resolve(); } - let fields = {}; + let fields: ConversationType = {}; if (!_.isUndefined(req.p.is_active)) { fields.is_active = req.p.is_active; } @@ -8392,7 +10352,7 @@ Email verified! You can close this tab or hit the back button. .returning("*"); verifyMetaPromise.then( function () { - pgQuery(q.toString(), function (err, result) { + pgQuery(q.toString(), function (err: any, result: { rows: any[] }) { if (err) { fail(res, 500, "polis_err_update_conversation", err); return; @@ -8414,7 +10374,7 @@ Email verified! You can close this tab or hit the back button. getUserInfoForUid2(req.p.uid), getConversationUrl(req, req.p.zid, true), ]) - .then(function (results) { + .then(function (results: any[]) { let hname = results[0].hname; let url = results[1]; sendEmailByUid( @@ -8432,11 +10392,11 @@ Email verified! You can close this tab or hit the back button. "With gratitude,\n" + "\n" + "The team at pol.is\n" - ).catch(function (err) { + ).catch(function (err: any) { console.error(err); }); }) - .catch(function (err) { + .catch(function (err: any) { yell("polis_err_sending_conversation_created_email"); winston.log("info", err); }); @@ -8485,7 +10445,7 @@ Email verified! You can close this tab or hit the back button. .then(function () { finishOne(res, conv, true, successCode); }) - .catch(function (err) { + .catch(function (err: any) { fail( res, 500, @@ -8509,26 +10469,29 @@ Email verified! You can close this tab or hit the back button. // finishOne(res, conv); // // } }) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_update_conversation", err); }); }); }, - function (err) { + function (err: { message: any }) { fail(res, 500, err.message, err); } ); }) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_update_conversation", err); }); } - function handle_DELETE_metadata_questions(req, res) { + function handle_DELETE_metadata_questions( + req: { p: { uid?: any; pmqid: any } }, + res: { send: (arg0: number) => void } + ) { let uid = req.p.uid; let pmqid = req.p.pmqid; - getZidForQuestion(pmqid, function (err, zid) { + getZidForQuestion(pmqid, function (err: any, zid: any) { if (err) { fail( res, @@ -8538,7 +10501,7 @@ Email verified! You can close this tab or hit the back button. ); return; } - isConversationOwner(zid, uid, function (err) { + isConversationOwner(zid, uid, function (err: any) { if (err) { fail( res, @@ -8549,7 +10512,7 @@ Email verified! You can close this tab or hit the back button. return; } - deleteMetadataQuestionAndAnswers(pmqid, function (err) { + deleteMetadataQuestionAndAnswers(pmqid, function (err?: string | null) { if (err) { fail( res, @@ -8565,11 +10528,14 @@ Email verified! You can close this tab or hit the back button. }); } - function handle_DELETE_metadata_answers(req, res) { + function handle_DELETE_metadata_answers( + req: { p: { uid?: any; pmaid: any } }, + res: { send: (arg0: number) => void } + ) { let uid = req.p.uid; let pmaid = req.p.pmaid; - getZidForAnswer(pmaid, function (err, zid) { + getZidForAnswer(pmaid, function (err: any, zid: any) { if (err) { fail( res, @@ -8579,7 +10545,7 @@ Email verified! You can close this tab or hit the back button. ); return; } - isConversationOwner(zid, uid, function (err) { + isConversationOwner(zid, uid, function (err: any) { if (err) { fail( res, @@ -8590,7 +10556,7 @@ Email verified! You can close this tab or hit the back button. return; } - deleteMetadataAnswer(pmaid, function (err) { + deleteMetadataAnswer(pmaid, function (err: any) { if (err) { fail( res, @@ -8606,11 +10572,17 @@ Email verified! You can close this tab or hit the back button. }); } - function getZidForAnswer(pmaid, callback) { + function getZidForAnswer( + pmaid: any, + callback: { + (err: any, zid: any): void; + (arg0: string | null, arg1?: undefined): void; + } + ) { pgQuery( "SELECT zid FROM participant_metadata_answers WHERE pmaid = ($1);", [pmaid], - function (err, result) { + function (err: any, result: { rows: string | any[] }) { if (err) { callback(err); return; @@ -8624,11 +10596,17 @@ Email verified! You can close this tab or hit the back button. ); } - function getZidForQuestion(pmqid, callback) { + function getZidForQuestion( + pmqid: any, + callback: { + (err: any, zid?: any): void; + (arg0: string | null, arg1: undefined): void; + } + ) { pgQuery( "SELECT zid FROM participant_metadata_questions WHERE pmqid = ($1);", [pmqid], - function (err, result) { + function (err: any, result: { rows: string | any[] }) { if (err) { winston.log("info", err); callback(err); @@ -8643,13 +10621,16 @@ Email verified! You can close this tab or hit the back button. ); } - function deleteMetadataAnswer(pmaid, callback) { + function deleteMetadataAnswer( + pmaid: any, + callback: { (err: any): void; (arg0: null): void } + ) { // pgQuery("update participant_metadata_choices set alive = FALSE where pmaid = ($1);", [pmaid], function(err) { // if (err) {callback(34534545); return;} pgQuery( "update participant_metadata_answers set alive = FALSE where pmaid = ($1);", [pmaid], - function (err) { + function (err: any) { if (err) { callback(err); return; @@ -8660,13 +10641,16 @@ Email verified! You can close this tab or hit the back button. // }); } - function deleteMetadataQuestionAndAnswers(pmqid, callback) { + function deleteMetadataQuestionAndAnswers( + pmqid: any, + callback: { (err: any): void; (arg0: null): void } + ) { // pgQuery("update participant_metadata_choices set alive = FALSE where pmqid = ($1);", [pmqid], function(err) { // if (err) {callback(93847834); return;} pgQuery( "update participant_metadata_answers set alive = FALSE where pmqid = ($1);", [pmqid], - function (err) { + function (err: any) { if (err) { callback(err); return; @@ -8674,7 +10658,7 @@ Email verified! You can close this tab or hit the back button. pgQuery( "update participant_metadata_questions set alive = FALSE where pmqid = ($1);", [pmqid], - function (err) { + function (err: any) { if (err) { callback(err); return; @@ -8687,20 +10671,33 @@ Email verified! You can close this tab or hit the back button. // }); } - function handle_GET_metadata_questions(req, res) { + function handle_GET_metadata_questions( + req: { p: { zid: any; zinvite: any; suzinvite: any } }, + res: any + ) { let zid = req.p.zid; let zinvite = req.p.zinvite; let suzinvite = req.p.suzinvite; - function doneChecking(err, foo) { + function doneChecking(err: boolean, foo?: undefined) { if (err) { fail(res, 403, "polis_err_get_participant_metadata_auth", err); return; } + // No overload matches this call. + // Overload 1 of 3, '(tasks: AsyncFunction<{ rows: any; }, any>[], callback?: AsyncResultArrayCallback<{ rows: any; }, any> | undefined): void', gave the following error. + // Argument of type '(err: any, result: { rows: any; }[]) => void' is not assignable to parameter of type 'AsyncResultArrayCallback<{ rows: any; }, any>'. + // Types of parameters 'result' and 'results' are incompatible. + // Type '({ rows: any; } | undefined)[] | undefined' is not assignable to type '{ rows: any; }[]'. + // Type 'undefined' is not assignable to type '{ rows: any; }[]'. + // Overload 2 of 3, '(tasks: Dictionary>, callback?: AsyncResultObjectCallback | undefined): void', gave the following error. + // Argument of type '((callback: any) => void)[]' is not assignable to parameter of type 'Dictionary>'. + // Index signature is missing in type '((callback: any) => void)[]'.ts(2769) + // @ts-ignore async.parallel( [ - function (callback) { + function (callback: any) { pgQuery_readOnly( "SELECT * FROM participant_metadata_questions WHERE alive = true AND zid = ($1);", [zid], @@ -8710,13 +10707,13 @@ Email verified! You can close this tab or hit the back button. //function(callback) { pgQuery_readOnly("SELECT * FROM participant_metadata_answers WHERE alive = true AND zid = ($1);", [zid], callback); }, //function(callback) { pgQuery_readOnly("SELECT * FROM participant_metadata_choices WHERE alive = true AND zid = ($1);", [zid], callback); }, ], - function (err, result) { + function (err: any, result: { rows: any }[]) { if (err) { fail(res, 500, "polis_err_get_participant_metadata_questions", err); return; } let rows = result[0] && result[0].rows; - rows = rows.map(function (r) { + rows = rows.map(function (r: { required: boolean }) { r.required = true; return r; }); @@ -8726,20 +10723,39 @@ Email verified! You can close this tab or hit the back button. } if (zinvite) { + // (local function) doneChecking(err: boolean, foo?: undefined): void + // Argument of type '(err: boolean, foo?: undefined) => void' is not assignable to parameter of type '{ (err: any, foo: any): void; (err: any, foo: any): void; (err: any): void; (arg0: number | null): void; }'. + // Types of parameters 'err' and 'arg0' are incompatible. + // Type 'number | null' is not assignable to type 'boolean'. + // Type 'null' is not assignable to type 'boolean'.ts(2345) + // @ts-ignore checkZinviteCodeValidity(zid, zinvite, doneChecking); } else if (suzinvite) { + // (local function) checkSuzinviteCodeValidity(zid: any, suzinvite: any, callback: { + // (err: any, foo: any): void; + // (err: any, foo: any): void; + // (err: any): void; + // (arg0: number | null): void; + // }): void + // Argument of type '(err: boolean, foo?: undefined) => void' is not assignable to parameter of type '{ (err: any, foo: any): void; (err: any, foo: any): void; (err: any): void; (arg0: number | null): void; }'. + // Types of parameters 'err' and 'arg0' are incompatible. + // Type 'number | null' is not assignable to type 'boolean'.ts(2345) + // @ts-ignore checkSuzinviteCodeValidity(zid, suzinvite, doneChecking); } else { doneChecking(false); } } - function handle_POST_metadata_questions(req, res) { + function handle_POST_metadata_questions( + req: { p: { zid: any; key: any; uid?: any } }, + res: any + ) { let zid = req.p.zid; let key = req.p.key; let uid = req.p.uid; - function doneChecking(err, foo) { + function doneChecking(err: any, foo?: any) { if (err) { fail(res, 403, "polis_err_post_participant_metadata_auth", err); return; @@ -8747,7 +10763,7 @@ Email verified! You can close this tab or hit the back button. pgQuery( "INSERT INTO participant_metadata_questions (pmqid, zid, key) VALUES (default, $1, $2) RETURNING *;", [zid, key], - function (err, results) { + function (err: any, results: { rows: string | any[] }) { if (err || !results || !results.rows || !results.rows.length) { fail(res, 500, "polis_err_post_participant_metadata_key", err); return; @@ -8761,13 +10777,16 @@ Email verified! You can close this tab or hit the back button. isConversationOwner(zid, uid, doneChecking); } - function handle_POST_metadata_answers(req, res) { + function handle_POST_metadata_answers( + req: { p: { zid: any; uid?: any; pmqid: any; value: any } }, + res: any + ) { let zid = req.p.zid; let uid = req.p.uid; let pmqid = req.p.pmqid; let value = req.p.value; - function doneChecking(err, foo) { + function doneChecking(err: any, foo?: any) { if (err) { fail(res, 403, "polis_err_post_participant_metadata_auth", err); return; @@ -8775,12 +10794,12 @@ Email verified! You can close this tab or hit the back button. pgQuery( "INSERT INTO participant_metadata_answers (pmqid, zid, value, pmaid) VALUES ($1, $2, $3, default) RETURNING *;", [pmqid, zid, value], - function (err, results) { + function (err: any, results: { rows: string | any[] }) { if (err || !results || !results.rows || !results.rows.length) { pgQuery( "UPDATE participant_metadata_answers set alive = TRUE where pmqid = ($1) AND zid = ($2) AND value = ($3) RETURNING *;", [pmqid, zid, value], - function (err, results) { + function (err: any, results: { rows: any[] }) { if (err) { fail( res, @@ -8803,25 +10822,28 @@ Email verified! You can close this tab or hit the back button. isConversationOwner(zid, uid, doneChecking); } - function handle_GET_metadata_choices(req, res) { + function handle_GET_metadata_choices(req: { p: { zid: any } }, res: any) { let zid = req.p.zid; getChoicesForConversation(zid).then( - function (choices) { + function (choices: any) { finishArray(res, choices); }, - function (err) { + function (err: any) { fail(res, 500, "polis_err_get_participant_metadata_choices", err); } ); } - function handle_GET_metadata_answers(req, res) { + function handle_GET_metadata_answers( + req: { p: { zid: any; zinvite: any; suzinvite: any; pmqid: any } }, + res: any + ) { let zid = req.p.zid; let zinvite = req.p.zinvite; let suzinvite = req.p.suzinvite; let pmqid = req.p.pmqid; - function doneChecking(err, foo) { + function doneChecking(err: boolean, foo?: undefined) { if (err) { fail(res, 403, "polis_err_get_participant_metadata_auth", err); return; @@ -8836,54 +10858,92 @@ Email verified! You can close this tab or hit the back button. sql_participant_metadata_answers.pmqid.equals(pmqid) ); } - pgQuery_readOnly(query.toString(), function (err, result) { - if (err) { - fail(res, 500, "polis_err_get_participant_metadata_answers", err); - return; + pgQuery_readOnly( + query.toString(), + function (err: any, result: { rows: any[] }) { + if (err) { + fail(res, 500, "polis_err_get_participant_metadata_answers", err); + return; + } + let rows = result.rows.map(function (r: { is_exclusive: boolean }) { + r.is_exclusive = true; // TODO fetch this info from the queston itself + return r; + }); + finishArray(res, rows); } - let rows = result.rows.map(function (r) { - r.is_exclusive = true; // TODO fetch this info from the queston itself - return r; - }); - finishArray(res, rows); - }); + ); } if (zinvite) { + // (local function) doneChecking(err: boolean, foo?: undefined): void + // Argument of type '(err: boolean, foo?: undefined) => void' is not assignable to parameter of type '{ (err: any, foo: any): void; (err: any, foo: any): void; (err: any): void; (arg0: number | null): void; }'. + // Types of parameters 'err' and 'arg0' are incompatible. + // Type 'number | null' is not assignable to type 'boolean'.ts(2345) + // @ts-ignore checkZinviteCodeValidity(zid, zinvite, doneChecking); } else if (suzinvite) { + // (local function) doneChecking(err: boolean, foo?: undefined): void + // Argument of type '(err: boolean, foo?: undefined) => void' is not assignable to parameter of type '{ (err: any, foo: any): void; (err: any, foo: any): void; (err: any): void; (arg0: number | null): void; }'. + // Types of parameters 'err' and 'arg0' are incompatible. + // Type 'number | null' is not assignable to type 'boolean'.ts(2345) + // @ts-ignore checkSuzinviteCodeValidity(zid, suzinvite, doneChecking); } else { doneChecking(false); } } - function handle_GET_metadata(req, res) { + function handle_GET_metadata( + req: { p: { zid: any; zinvite: any; suzinvite: any } }, + res: { + status: ( + arg0: number + ) => { + (): any; + new (): any; + json: { + (arg0: { kvp?: {}; keys?: {}; values?: {} }): void; + new (): any; + }; + }; + } + ) { let zid = req.p.zid; let zinvite = req.p.zinvite; let suzinvite = req.p.suzinvite; - function doneChecking(err) { + function doneChecking(err: boolean) { if (err) { fail(res, 403, "polis_err_get_participant_metadata_auth", err); return; } + + // No overload matches this call. + // Overload 1 of 3, '(tasks: AsyncFunction<{ rows: any; }, any>[], callback?: AsyncResultArrayCallback<{ rows: any; }, any> | undefined): void', gave the following error. + // Argument of type '(err: any, result: { rows: any; }[]) => void' is not assignable to parameter of type 'AsyncResultArrayCallback<{ rows: any; }, any>'. + // Types of parameters 'result' and 'results' are incompatible. + // Type '({ rows: any; } | undefined)[] | undefined' is not assignable to type '{ rows: any; }[]'. + // Type 'undefined' is not assignable to type '{ rows: any; }[]'. + // Overload 2 of 3, '(tasks: Dictionary>, callback?: AsyncResultObjectCallback | undefined): void', gave the following error. + // Argument of type '((callback: any) => void)[]' is not assignable to parameter of type 'Dictionary>'. + // Index signature is missing in type '((callback: any) => void)[]'.ts(2769) + // @ts-ignore async.parallel( [ - function (callback) { + function (callback: any) { pgQuery_readOnly( "SELECT * FROM participant_metadata_questions WHERE zid = ($1);", [zid], callback ); }, - function (callback) { + function (callback: any) { pgQuery_readOnly( "SELECT * FROM participant_metadata_answers WHERE zid = ($1);", [zid], callback ); }, - function (callback) { + function (callback: any) { pgQuery_readOnly( "SELECT * FROM participant_metadata_choices WHERE zid = ($1);", [zid], @@ -8891,7 +10951,7 @@ Email verified! You can close this tab or hit the back button. ); }, ], - function (err, result) { + function (err: any, result: { rows: any }[]) { if (err) { fail(res, 500, "polis_err_get_participant_metadata", err); return; @@ -8912,20 +10972,35 @@ Email verified! You can close this tab or hit the back button. for (i = 0; i < keys.length; i++) { // Add a map for each keyId k = keys[i]; + // Element implicitly has an 'any' type because expression of type 'string | number' can't be used to index type '{}'. + // No index signature with a parameter of type 'string' was found on type '{}'.ts(7053) + // @ts-ignore o[k.pmqid] = {}; // keep the user-facing key name + // Element implicitly has an 'any' type because expression of type 'string | number' can't be used to index type '{}'. + // No index signature with a parameter of type 'string' was found on type '{}'.ts(7053) + // @ts-ignore keyNames[k.pmqid] = k.key; } for (i = 0; i < vals.length; i++) { // Add an array for each possible valueId k = vals[i]; v = vals[i]; + // Element implicitly has an 'any' type because expression of type 'string | number' can't be used to index type '{}'. + // No index signature with a parameter of type 'string' was found on type '{}'.ts(7053) + // @ts-ignore o[k.pmqid][v.pmaid] = []; // keep the user-facing value string + // Element implicitly has an 'any' type because expression of type 'string | number' can't be used to index type '{}'. + // No index signature with a parameter of type 'string' was found on type '{}'.ts(7053) + // @ts-ignore valueNames[v.pmaid] = v.value; } for (i = 0; i < choices.length; i++) { // Append a pid for each person who has seleted that value for that key. + // Element implicitly has an 'any' type because expression of type 'string | number' can't be used to index type '{}'. + // No index signature with a parameter of type 'string' was found on type '{}'.ts(7053) + // @ts-ignore o[choices[i].pmqid][choices[i].pmaid] = choices[i].pid; } // TODO cache @@ -8939,19 +11014,32 @@ Email verified! You can close this tab or hit the back button. } if (zinvite) { + // (local function) doneChecking(err: boolean): void + // Argument of type '(err: boolean) => void' is not assignable to parameter of type '{ (err: any, foo: any): void; (err: any, foo: any): void; (err: any): void; (arg0: number | null): void; }'. + // Types of parameters 'err' and 'arg0' are incompatible. + // Type 'number | null' is not assignable to type 'boolean'.ts(2345) + // @ts-ignore checkZinviteCodeValidity(zid, zinvite, doneChecking); } else if (suzinvite) { + // (local function) doneChecking(err: boolean): void + // Argument of type '(err: boolean) => void' is not assignable to parameter of type '{ (err: any, foo: any): void; (err: any, foo: any): void; (err: any): void; (arg0: number | null): void; }'. + // Types of parameters 'err' and 'arg0' are incompatible. + // Type 'number | null' is not assignable to type 'boolean'.ts(2345) + // @ts-ignore checkSuzinviteCodeValidity(zid, suzinvite, doneChecking); } else { doneChecking(false); } } - function getConversationHasMetadata(zid) { - return new Promise(function (resolve, reject) { + function getConversationHasMetadata(zid: any) { + return new Promise(function ( + resolve: (arg0: boolean) => void, + reject: (arg0: string) => any + ) { pgQuery_readOnly( "SELECT * from participant_metadata_questions where zid = ($1)", [zid], - function (err, metadataResults) { + function (err: any, metadataResults: { rows: string | any[] }) { if (err) { return reject("polis_err_get_conversation_metadata_by_zid"); } @@ -8965,7 +11053,7 @@ Email verified! You can close this tab or hit the back button. }); } - function getConversationTranslations(zid, lang) { + function getConversationTranslations(zid: any, lang: string) { const firstTwoCharsOfLang = lang.substr(0, 2); return pgQueryP( "select * from conversation_translations where zid = ($1) and lang = ($2);", @@ -8973,11 +11061,18 @@ Email verified! You can close this tab or hit the back button. ); } - function getConversationTranslationsMinimal(zid, lang) { + function getConversationTranslationsMinimal(zid: any, lang: any) { if (!lang) { return Promise.resolve([]); } - return getConversationTranslations(zid, lang).then(function (rows) { + // Argument of type '(rows: string | any[]) => string | any[]' is not assignable to parameter of type '(value: unknown) => string | any[] | PromiseLike'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + return getConversationTranslations(zid, lang).then(function ( + rows: string | any[] + ) { for (let i = 0; i < rows.length; i++) { delete rows[i].zid; delete rows[i].created; @@ -8988,7 +11083,7 @@ Email verified! You can close this tab or hit the back button. }); } - function getOneConversation(zid, uid, lang) { + function getOneConversation(zid: any, uid?: any, lang?: null) { return Promise.all([ pgQueryP_readOnly( "select * from conversations left join (select uid, site_id, plan from users) as u on conversations.owner = u.uid where conversations.zid = ($1);", @@ -8997,7 +11092,7 @@ Email verified! You can close this tab or hit the back button. getConversationHasMetadata(zid), _.isUndefined(uid) ? Promise.resolve({}) : getUserInfoForUid2(uid), getConversationTranslationsMinimal(zid, lang), - ]).then(function (results) { + ]).then(function (results: any[]) { let conv = results[0] && results[0][0]; let convHasMetadata = results[1]; let requestingUserInfo = results[2]; @@ -9016,7 +11111,9 @@ Email verified! You can close this tab or hit the back button. conv.translations = translations; - return getUserInfoForUid2(conv.owner).then(function (ownerInfo) { + return getUserInfoForUid2(conv.owner).then(function (ownerInfo: { + hname: any; + }) { let ownername = ownerInfo.hname; if (convHasMetadata) { conv.hasMetadata = true; @@ -9033,7 +11130,16 @@ Email verified! You can close this tab or hit the back button. }); } - function getConversations(req, res) { + function getConversations( + req: { + p: ConversationType; + }, + res: { + status: ( + arg0: number + ) => { (): any; new (): any; json: { (arg0: any): void; new (): any } }; + } + ) { let uid = req.p.uid; let zid = req.p.zid; let xid = req.p.xid; @@ -9062,211 +11168,256 @@ Email verified! You can close this tab or hit the back button. " UNION ALL select zid, 2 as type from participants where uid = ($1)"; // using UNION ALL instead of UNION to ensure we get all the 1's and 2's (I'm not sure if we can guarantee the 2's won't clobber some 1's if we use UNION) } zidListQuery += ";"; - pgQuery_readOnly(zidListQuery, [uid], function (err, results) { - if (err) { - fail(res, 500, "polis_err_get_conversations_participated_in", err); - return; - } - - let participantInOrSiteAdminOf = - (results && results.rows && _.pluck(results.rows, "zid")) || null; - let siteAdminOf = _.filter(results.rows, function (row) { - return row.type === 1; - }); - let isSiteAdmin = _.indexBy(siteAdminOf, "zid"); - - let query = sql_conversations.select(sql_conversations.star()); + pgQuery_readOnly( + zidListQuery, + [uid], + function (err: any, results: { rows: any }) { + if (err) { + fail(res, 500, "polis_err_get_conversations_participated_in", err); + return; + } - let isRootsQuery = false; - let orClauses; - if (!_.isUndefined(req.p.context)) { - if (req.p.context === "/") { - winston.log("info", "asdf" + req.p.context + "asdf"); - // root of roots returns all public conversations - // TODO lots of work to decide what's relevant - // There is a bit of mess here, because we're returning both public 'roots' conversations, and potentially private conversations that you are already in. - orClauses = sql_conversations.is_public.equals(true); - isRootsQuery = true; // more conditions follow in the ANDs below + let participantInOrSiteAdminOf = + (results && results.rows && _.pluck(results.rows, "zid")) || null; + let siteAdminOf = _.filter( + results.rows, + function (row: { type: number }) { + return row.type === 1; + } + ); + let isSiteAdmin = _.indexBy(siteAdminOf, "zid"); + + let query = sql_conversations.select(sql_conversations.star()); + + let isRootsQuery = false; + let orClauses; + if (!_.isUndefined(req.p.context)) { + if (req.p.context === "/") { + winston.log("info", "asdf" + req.p.context + "asdf"); + // root of roots returns all public conversations + // TODO lots of work to decide what's relevant + // There is a bit of mess here, because we're returning both public 'roots' conversations, and potentially private conversations that you are already in. + orClauses = sql_conversations.is_public.equals(true); + isRootsQuery = true; // more conditions follow in the ANDs below + } else { + // knowing a context grants access to those conversations (for now at least) + winston.log("info", "CONTEXT", context); + orClauses = sql_conversations.context.equals(req.p.context); + } } else { - // knowing a context grants access to those conversations (for now at least) - winston.log("info", "CONTEXT", context); - orClauses = sql_conversations.context.equals(req.p.context); + orClauses = sql_conversations.owner.equals(uid); + if (participantInOrSiteAdminOf.length) { + orClauses = orClauses.or( + sql_conversations.zid.in(participantInOrSiteAdminOf) + ); + } } - } else { - orClauses = sql_conversations.owner.equals(uid); - if (participantInOrSiteAdminOf.length) { - orClauses = orClauses.or( - sql_conversations.zid.in(participantInOrSiteAdminOf) + query = query.where(orClauses); + if (!_.isUndefined(req.p.course_invite)) { + query = query.and( + sql_conversations.course_id.equals(req.p.course_id) ); } - } - query = query.where(orClauses); - if (!_.isUndefined(req.p.course_invite)) { - query = query.and(sql_conversations.course_id.equals(req.p.course_id)); - } - // query = query.where("("+ or_clauses.join(" OR ") + ")"); - if (!_.isUndefined(req.p.is_active)) { - query = query.and(sql_conversations.is_active.equals(req.p.is_active)); - } - if (!_.isUndefined(req.p.is_draft)) { - query = query.and(sql_conversations.is_draft.equals(req.p.is_draft)); - } - if (!_.isUndefined(req.p.zid)) { - query = query.and(sql_conversations.zid.equals(zid)); - } - if (isRootsQuery) { - query = query.and(sql_conversations.context.isNotNull()); - } + // query = query.where("("+ or_clauses.join(" OR ") + ")"); + if (!_.isUndefined(req.p.is_active)) { + query = query.and( + sql_conversations.is_active.equals(req.p.is_active) + ); + } + if (!_.isUndefined(req.p.is_draft)) { + query = query.and(sql_conversations.is_draft.equals(req.p.is_draft)); + } + if (!_.isUndefined(req.p.zid)) { + query = query.and(sql_conversations.zid.equals(zid)); + } + if (isRootsQuery) { + query = query.and(sql_conversations.context.isNotNull()); + } - //query = whereOptional(query, req.p, 'owner'); - query = query.order(sql_conversations.created.descending); + //query = whereOptional(query, req.p, 'owner'); + query = query.order(sql_conversations.created.descending); - if (!_.isUndefined(req.p.limit)) { - query = query.limit(req.p.limit); - } else { - query = query.limit(999); // TODO paginate - } - pgQuery_readOnly(query.toString(), function (err, result) { - if (err) { - fail(res, 500, "polis_err_get_conversations", err); - return; + if (!_.isUndefined(req.p.limit)) { + query = query.limit(req.p.limit); + } else { + query = query.limit(999); // TODO paginate } - let data = result.rows || []; - addConversationIds(data) - .then(function (data) { - let suurlsPromise; - if (xid) { - suurlsPromise = Promise.all( - data.map(function (conv) { - return createOneSuzinvite( - xid, - conv.zid, - conv.owner, // TODO think: conv.owner or uid? - _.partial(generateSingleUseUrl, req) - ); - }) - ); - } else { - suurlsPromise = Promise.resolve(); + pgQuery_readOnly( + query.toString(), + function (err: any, result: { rows: never[] }) { + if (err) { + fail(res, 500, "polis_err_get_conversations", err); + return; } - let upvotesPromise = - uid && want_upvoted - ? pgQueryP_readOnly( - "select zid from upvotes where uid = ($1);", - [uid] - ) - : Promise.resolve(); - - return Promise.all([suurlsPromise, upvotesPromise]).then( - function (x) { - let suurlData = x[0]; - let upvotes = x[1]; - if (suurlData) { - suurlData = _.indexBy(suurlData, "zid"); - } - if (upvotes) { - upvotes = _.indexBy(upvotes, "zid"); + let data = result.rows || []; + addConversationIds(data) + .then(function (data: any[]) { + let suurlsPromise; + if (xid) { + suurlsPromise = Promise.all( + data.map(function (conv: { zid: any; owner: any }) { + return createOneSuzinvite( + xid, + conv.zid, + conv.owner, // TODO think: conv.owner or uid? + _.partial(generateSingleUseUrl, req) + ); + }) + ); + } else { + suurlsPromise = Promise.resolve(); } - data.forEach(function (conv) { - conv.is_owner = conv.owner === uid; - let root = getServerNameWithProtocol(req); - - if (want_mod_url) { - // TODO make this into a moderation invite URL so others can join Issue #618 - conv.mod_url = createModerationUrl( - req, - conv.conversation_id - ); - } - if (want_inbox_item_admin_url) { - conv.inbox_item_admin_url = - root + "/iim/" + conv.conversation_id; - } - if (want_inbox_item_participant_url) { - conv.inbox_item_participant_url = - root + "/iip/" + conv.conversation_id; - } - if (want_inbox_item_admin_html) { - conv.inbox_item_admin_html = - "" + - (conv.topic || conv.created) + - "" + - " moderate"; - - conv.inbox_item_admin_html_escaped = conv.inbox_item_admin_html.replace( - /'/g, - "\\'" - ); - } - if (want_inbox_item_participant_html) { - conv.inbox_item_participant_html = - "" + - (conv.topic || conv.created) + - ""; - conv.inbox_item_participant_html_escaped = conv.inbox_item_admin_html.replace( - /'/g, - "\\'" - ); - } + let upvotesPromise = + uid && want_upvoted + ? pgQueryP_readOnly( + "select zid from upvotes where uid = ($1);", + [uid] + ) + : Promise.resolve(); + + return Promise.all([suurlsPromise, upvotesPromise]).then( + function (x: any[]) { + let suurlData = x[0]; + let upvotes = x[1]; + if (suurlData) { + suurlData = _.indexBy(suurlData, "zid"); + } + if (upvotes) { + upvotes = _.indexBy(upvotes, "zid"); + } + data.forEach(function (conv: { + is_owner: boolean; + owner: any; + mod_url: string; + conversation_id: string; + inbox_item_admin_url: string; + inbox_item_participant_url: string; + inbox_item_admin_html: string; + topic: string; + created: string | number | Date; + inbox_item_admin_html_escaped: any; + inbox_item_participant_html: string; + inbox_item_participant_html_escaped: any; + url: string; + upvoted: boolean; + modified: number; + is_mod: any; + is_anon: any; + is_active: any; + is_draft: any; + is_public: any; + zid?: string | number; + context?: string; + }) { + conv.is_owner = conv.owner === uid; + let root = getServerNameWithProtocol(req); + + if (want_mod_url) { + // TODO make this into a moderation invite URL so others can join Issue #618 + conv.mod_url = createModerationUrl( + req, + conv.conversation_id + ); + } + if (want_inbox_item_admin_url) { + conv.inbox_item_admin_url = + root + "/iim/" + conv.conversation_id; + } + if (want_inbox_item_participant_url) { + conv.inbox_item_participant_url = + root + "/iip/" + conv.conversation_id; + } + if (want_inbox_item_admin_html) { + conv.inbox_item_admin_html = + "" + + (conv.topic || conv.created) + + "" + + " moderate"; + + conv.inbox_item_admin_html_escaped = conv.inbox_item_admin_html.replace( + /'/g, + "\\'" + ); + } + if (want_inbox_item_participant_html) { + conv.inbox_item_participant_html = + "" + + (conv.topic || conv.created) + + ""; + conv.inbox_item_participant_html_escaped = conv.inbox_item_admin_html.replace( + /'/g, + "\\'" + ); + } - if (suurlData) { - conv.url = suurlData[conv.zid].suurl; - } else { - conv.url = buildConversationUrl(req, conv.conversation_id); - } - if (upvotes && upvotes[conv.zid]) { - conv.upvoted = true; - } - conv.created = Number(conv.created); - conv.modified = Number(conv.modified); + if (suurlData) { + conv.url = suurlData[conv.zid || ""].suurl; + } else { + conv.url = buildConversationUrl( + req, + conv.conversation_id + ); + } + if (upvotes && upvotes[conv.zid || ""]) { + conv.upvoted = true; + } + conv.created = Number(conv.created); + conv.modified = Number(conv.modified); - // if there is no topic, provide a UTC timstamp instead - if (_.isUndefined(conv.topic) || conv.topic === "") { - conv.topic = new Date(conv.created).toUTCString(); - } + // if there is no topic, provide a UTC timstamp instead + if (_.isUndefined(conv.topic) || conv.topic === "") { + conv.topic = new Date(conv.created).toUTCString(); + } - conv.is_mod = conv.is_owner || isSiteAdmin[conv.zid]; + conv.is_mod = + conv.is_owner || isSiteAdmin[conv.zid || ""]; - // Make sure zid is not exposed - delete conv.zid; + // Make sure zid is not exposed + delete conv.zid; - delete conv.is_anon; - delete conv.is_active; - delete conv.is_draft; - delete conv.is_public; - if (conv.context === "") { - delete conv.context; - } - }); + delete conv.is_anon; + delete conv.is_active; + delete conv.is_draft; + delete conv.is_public; + if (conv.context === "") { + delete conv.context; + } + }); - res.status(200).json(data); - }, - function (err) { - fail(res, 500, "polis_err_get_conversations_surls", err); - } - ); - }) - .catch(function (err) { - fail(res, 500, "polis_err_get_conversations_misc", err); - }); - }); - }); + res.status(200).json(data); + }, + function (err: any) { + fail(res, 500, "polis_err_get_conversations_surls", err); + } + ); + }) + .catch(function (err: any) { + fail(res, 500, "polis_err_get_conversations_misc", err); + }); + } + ); + } + ); } - function createReport(zid) { - return generateTokenP(20, false).then(function (report_id) { + function createReport(zid: any) { + // Argument of type '(report_id: string) => Promise' is not assignable to parameter of type '(value: unknown) => unknown'. + // Types of parameters 'report_id' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string'.ts(2345) + // @ts-ignore + return generateTokenP(20, false).then(function (report_id: string) { report_id = "r" + report_id; return pgQueryP("insert into reports (zid, report_id) values ($1, $2);", [ zid, @@ -9274,70 +11425,89 @@ Email verified! You can close this tab or hit the back button. ]); }); } - function handle_POST_reports(req, res) { + function handle_POST_reports( + req: { p: { zid: any; uid?: any } }, + res: { json: (arg0: {}) => void } + ) { let zid = req.p.zid; let uid = req.p.uid; - return isModerator(zid, uid) - .then((isMod) => { - if (!isMod) { - return fail(res, 403, "polis_err_post_reports_permissions", err); - } - return createReport(zid).then(() => { - res.json({}); - }); - }) - .catch((err) => { - fail(res, 500, "polis_err_post_reports_misc", err); - }); + return ( + isModerator(zid, uid) + // Argument of type '(isMod: any, err: string) => void | globalThis.Promise' is not assignable to parameter of type '(value: unknown) => void | PromiseLike'.ts(2345) + // @ts-ignore + .then((isMod: any, err: string) => { + if (!isMod) { + return fail(res, 403, "polis_err_post_reports_permissions", err); + } + return createReport(zid).then(() => { + res.json({}); + }); + }) + .catch((err: any) => { + fail(res, 500, "polis_err_post_reports_misc", err); + }) + ); } - function handle_PUT_reports(req, res) { + function handle_PUT_reports( + req: { + p: { [x: string]: any; rid: any; uid?: any; zid: any; report_name: any }; + }, + res: { json: (arg0: {}) => void } + ) { let rid = req.p.rid; let uid = req.p.uid; let zid = req.p.zid; - return isModerator(zid, uid) - .then((isMod) => { - if (!isMod) { - return fail(res, 403, "polis_err_put_reports_permissions", err); - } + return ( + isModerator(zid, uid) + // Argument of type '(isMod: any, err: string) => void | globalThis.Promise' is not assignable to parameter of type '(value: unknown) => void | PromiseLike'.ts(2345) + // @ts-ignore + .then((isMod: any, err: string) => { + if (!isMod) { + return fail(res, 403, "polis_err_put_reports_permissions", err); + } - let fields = { - modified: "now_as_millis()", - }; + let fields: { [key: string]: string } = { + modified: "now_as_millis()", + }; - sql_reports.columns - .map((c) => { - return c.name; - }) - .filter((name) => { - // only allow changing label fields, (label_x_neg, etc) not zid, etc. - return name.startsWith("label_"); - }) - .forEach((name) => { - if (!_.isUndefined(req.p[name])) { - fields[name] = req.p[name]; - } - }); + sql_reports.columns + .map((c: { name: any }) => { + return c.name; + }) + .filter((name: string) => { + // only allow changing label fields, (label_x_neg, etc) not zid, etc. + return name.startsWith("label_"); + }) + .forEach((name: string | number) => { + if (!_.isUndefined(req.p[name])) { + fields[name] = req.p[name]; + } + }); - if (!_.isUndefined(req.p.report_name)) { - fields.report_name = req.p.report_name; - } + if (!_.isUndefined(req.p.report_name)) { + fields.report_name = req.p.report_name; + } - let q = sql_reports.update(fields).where(sql_reports.rid.equals(rid)); + let q = sql_reports.update(fields).where(sql_reports.rid.equals(rid)); - let query = q.toString(); - query = query.replace("'now_as_millis()'", "now_as_millis()"); // remove quotes added by sql lib + let query = q.toString(); + query = query.replace("'now_as_millis()'", "now_as_millis()"); // remove quotes added by sql lib - return pgQueryP(query, []).then((result) => { - res.json({}); - }); - }) - .catch((err) => { - fail(res, 500, "polis_err_post_reports_misc", err); - }); + return pgQueryP(query, []).then((result: any) => { + res.json({}); + }); + }) + .catch((err: any) => { + fail(res, 500, "polis_err_post_reports_misc", err); + }) + ); } - function handle_GET_reports(req, res) { + function handle_GET_reports( + req: { p: { zid: any; rid: any; uid?: any } }, + res: { json: (arg0: any) => void } + ) { let zid = req.p.zid; let rid = req.p.rid; let uid = req.p.uid; @@ -9355,12 +11525,14 @@ Email verified! You can close this tab or hit the back button. ]); } } else if (zid) { - reportsPromise = isModerator(zid, uid).then((doesOwnConversation) => { - if (!doesOwnConversation) { - throw "polis_err_permissions"; + reportsPromise = isModerator(zid, uid).then( + (doesOwnConversation: any) => { + if (!doesOwnConversation) { + throw "polis_err_permissions"; + } + return pgQueryP("select * from reports where zid = ($1);", [zid]); } - return pgQueryP("select * from reports where zid = ($1);", [zid]); - }); + ); } else { reportsPromise = pgQueryP( "select * from reports where zid in (select zid from conversations where owner = ($1));", @@ -9369,9 +11541,13 @@ Email verified! You can close this tab or hit the back button. } reportsPromise - .then((reports) => { - let zids = []; - reports = reports.map((report) => { + // Argument of type '(reports: any[]) => void | globalThis.Promise' is not assignable to parameter of type '(value: unknown) => void | PromiseLike'. + // Types of parameters 'reports' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + .then((reports: any[]) => { + let zids: any[] = []; + reports = reports.map((report: { zid: any; rid: any }) => { zids.push(report.zid); delete report.rid; return report; @@ -9383,17 +11559,19 @@ Email verified! You can close this tab or hit the back button. return pgQueryP( "select * from zinvites where zid in (" + zids.join(",") + ");", [] - ).then((zinvite_entries) => { + ).then((zinvite_entries: any) => { let zidToZinvite = _.indexBy(zinvite_entries, "zid"); - reports = reports.map((report) => { - report.conversation_id = zidToZinvite[report.zid].zinvite; - delete report.zid; - return report; - }); + reports = reports.map( + (report: { conversation_id: any; zid?: string | number }) => { + report.conversation_id = zidToZinvite[report.zid || ""]?.zinvite; + delete report.zid; + return report; + } + ); res.json(reports); }); }) - .catch((err) => { + .catch((err: string) => { if (err === "polis_err_permissions") { fail(res, 403, "polis_err_permissions"); } else if ( @@ -9411,14 +11589,24 @@ Email verified! You can close this tab or hit the back button. }); } - function encodeParams(o) { + function encodeParams(o: { + monthly?: any; + forceEmbedded?: boolean; + xPolisLti?: any; + tool_consumer_instance_guid?: any; + context?: any; + custom_canvas_assignment_id?: any; + }) { let stringifiedJson = JSON.stringify(o); let encoded = "ep1_" + strToHex(stringifiedJson); return encoded; } - function handle_GET_enterprise_deal_url(req, res) { - var o = { + function handle_GET_enterprise_deal_url( + req: { p: { monthly: any; maxUsers: any; plan_name: any; plan_id: any } }, + res: { send: (arg0: string) => void } + ) { + var o: { [key: string]: string } = { monthly: req.p.monthly, }; if (req.p.maxUsers) { @@ -9432,7 +11620,18 @@ Email verified! You can close this tab or hit the back button. } res.send("https://pol.is/settings/enterprise/" + encodeParams(o)); } - function handle_GET_stripe_account_connect(req, res) { + function handle_GET_stripe_account_connect( + req: any, + res: { + set: (arg0: { + "Content-Type": string; + }) => { + (): any; + new (): any; + send: { (arg0: string): void; new (): any }; + }; + } + ) { var stripe_client_id = process.env.STRIPE_CLIENT_ID; var stripeUrl = @@ -9451,7 +11650,18 @@ Email verified! You can close this tab or hit the back button. "" ); } - function handle_GET_stripe_account_connected_oauth_callback(req, res) { + function handle_GET_stripe_account_connected_oauth_callback( + req: { p: { code: any; error: string; error_description: any } }, + res: { + set: (arg0: { + "Content-Type": string; + }) => { + (): any; + new (): any; + send: { (arg0: string): void; new (): any }; + }; + } + ) { var code = req.p.code; // var access_token = req.p.access_token; // var error = req.p.error; @@ -9477,12 +11687,12 @@ Email verified! You can close this tab or hit the back button. client_secret: process.env.STRIPE_SECRET_KEY, }, }, - function (err, r, body) { + function (err: any, r: any, body: string) { if (err) { fail(res, 500, "polis_err_stripe_oauth", err); return; } - body = JSON.parse(body); + const parsedBody = JSON.parse(body); pgQueryP( "INSERT INTO stripe_accounts (" + "stripe_account_token_type, " + @@ -9494,13 +11704,13 @@ Email verified! You can close this tab or hit the back button. "stripe_account_access_token " + ") VALUES ($1, $2, $3, $4, $5, $6, $7);", [ - body.token_type, - body.stripe_publishable_key, - body.scope, - body.livemode, - body.stripe_user_id, - body.refresh_token, - body.access_token, + parsedBody.token_type, + parsedBody.stripe_publishable_key, + parsedBody.scope, + parsedBody.livemode, + parsedBody.stripe_user_id, + parsedBody.refresh_token, + parsedBody.access_token, ] ).then( function () { @@ -9510,24 +11720,35 @@ Email verified! You can close this tab or hit the back button. }) .send("success!"); }, - function (err) { + function (err: any) { fail(res, 500, "polis_err_saving_stripe_info", err); } ); } ); } - function handle_GET_conversations(req, res) { + function handle_GET_conversations( + req: { + p: ConversationType; + }, + res: any + ) { let courseIdPromise = Promise.resolve(); if (req.p.course_invite) { + // Type 'Promise' is missing the following properties from type 'Bluebird': caught, error, lastly, bind, and 38 more.ts(2740) + // @ts-ignore courseIdPromise = pgQueryP_readOnly( "select course_id from courses where course_invite = ($1);", [req.p.course_invite] - ).then(function (rows) { + // Argument of type '(rows: { course_id: any; }[]) => any' is not assignable to parameter of type '(value: unknown) => any'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type '{ course_id: any; }[]'.ts(2345) + // @ts-ignore + ).then(function (rows: { course_id: any }[]) { return rows[0].course_id; }); } - courseIdPromise.then(function (course_id) { + courseIdPromise.then(function (course_id: any) { if (course_id) { req.p.course_id = course_id; } @@ -9535,14 +11756,14 @@ Email verified! You can close this tab or hit the back button. if (req.p.zid) { getOneConversation(req.p.zid, req.p.uid, lang) .then( - function (data) { + function (data: any) { finishOne(res, data); }, - function (err) { + function (err: any) { fail(res, 500, "polis_err_get_conversations_2", err); } ) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_get_conversations_1", err); }); } else if (req.p.uid || req.p.context) { @@ -9553,25 +11774,39 @@ Email verified! You can close this tab or hit the back button. }); } - function handle_GET_contexts(req, res) { + function handle_GET_contexts( + req: any, + res: { + status: ( + arg0: number + ) => { (): any; new (): any; json: { (arg0: any): void; new (): any } }; + } + ) { pgQueryP_readOnly( "select name from contexts where is_public = TRUE order by name;", [] ) .then( - function (contexts) { + function (contexts: any) { res.status(200).json(contexts); }, - function (err) { + function (err: any) { fail(res, 500, "polis_err_get_contexts_query", err); } ) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_get_contexts_misc", err); }); } - function handle_POST_contexts(req, res) { + function handle_POST_contexts( + req: { p: { uid?: any; name: any } }, + res: { + status: ( + arg0: number + ) => { (): any; new (): any; json: { (arg0: {}): void; new (): any } }; + } + ) { let uid = req.p.uid; let name = req.p.name; @@ -9584,17 +11819,22 @@ Email verified! You can close this tab or hit the back button. function () { res.status(200).json({}); }, - function (err) { + function (err: any) { fail(res, 500, "polis_err_post_contexts_query", err); } ) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_post_contexts_misc", err); }); } pgQueryP("select name from contexts where name = ($1);", [name]) .then( - function (rows) { + // Argument of type '(rows: string | any[]) => Promise | undefined' is not assignable to parameter of type '(value: unknown) => void | PromiseLike | undefined'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + function (rows: string | any[]) { let exists = rows && rows.length; if (exists) { fail(res, 422, "polis_err_post_context_exists"); @@ -9602,16 +11842,23 @@ Email verified! You can close this tab or hit the back button. } return createContext(); }, - function (err) { + function (err: any) { fail(res, 500, "polis_err_post_contexts_check_query", err); } ) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_post_contexts_check_misc", err); }); } - function isUserAllowedToCreateConversations(uid, callback) { - callback(null, true); + function isUserAllowedToCreateConversations( + uid?: any, + callback?: { + (err: any, isAllowed: any): void; + (err: any, isAllowed: any): void; + (arg0: null, arg1: boolean): void; + } + ) { + callback?.(null, true); // pgQuery("select is_owner from users where uid = ($1);", [uid], function(err, results) { // if (err) { return callback(err); } // if (!results || !results.rows || !results.rows.length) { @@ -9621,21 +11868,51 @@ Email verified! You can close this tab or hit the back button. // }); } - function handle_POST_reserve_conversation_id(req, res) { + function handle_POST_reserve_conversation_id( + req: any, + res: { json: (arg0: { conversation_id: any }) => void } + ) { const zid = 0; const shortUrl = false; // TODO check auth - maybe bot has key generateAndRegisterZinvite(zid, shortUrl) - .then(function (conversation_id) { + .then(function (conversation_id: any) { res.json({ conversation_id: conversation_id, }); }) - .catch((err) => { + .catch((err: any) => { fail(res, 500, "polis_err_reserve_conversation_id", err); }); } - function handle_POST_conversations(req, res) { + function handle_POST_conversations( + req: { + p: { + context: any; + short_url: any; + uid?: any; + org_id: any; + topic: any; + description: any; + is_active: any; + is_data_open: any; + is_draft: any; + is_anon: any; + is_slack: any; + profanity_filter: any; + spam_filter: any; + strict_moderation: any; + owner_sees_participation_stats: any; + auth_needed_to_vote: any; + auth_needed_to_write: any; + auth_opt_allow_3rdparty: any; + auth_opt_fb: any; + auth_opt_tw: any; + conversation_id: any; + }; + }, + res: any + ) { let xidStuffReady = Promise.resolve(); xidStuffReady @@ -9645,7 +11922,7 @@ Email verified! You can close this tab or hit the back button. isUserAllowedToCreateConversations( req.p.uid, - function (err, isAllowed) { + function (err: any, isAllowed: any) { if (err) { fail( res, @@ -9696,58 +11973,73 @@ Email verified! You can close this tab or hit the back button. .returning("*") .toString(); - pgQuery(q, [], function (err, result) { - if (err) { - if (isDuplicateKey(err)) { - yell(err); - failWithRetryRequest(res); - } else { - fail(res, 500, "polis_err_add_conversation", err); + pgQuery( + q, + [], + function (err: any, result: { rows: { zid: any }[] }) { + if (err) { + if (isDuplicateKey(err)) { + yell(err); + failWithRetryRequest(res); + } else { + fail(res, 500, "polis_err_add_conversation", err); + } + return; } - return; - } - let zid = - result && result.rows && result.rows[0] && result.rows[0].zid; + let zid = + result && result.rows && result.rows[0] && result.rows[0].zid; - const zinvitePromise = req.p.conversation_id - ? Conversation.getZidFromConversationId( - req.p.conversation_id - ).then((zid) => { - return zid === 0 ? req.p.conversation_id : null; - }) - : generateAndRegisterZinvite(zid, generateShortUrl); + const zinvitePromise = req.p.conversation_id + ? Conversation.getZidFromConversationId( + req.p.conversation_id + ).then((zid: number) => { + return zid === 0 ? req.p.conversation_id : null; + }) + : generateAndRegisterZinvite(zid, generateShortUrl); - zinvitePromise - .then(function (zinvite) { - if (zinvite === null) { - fail( - res, - 400, - "polis_err_conversation_id_already_in_use", - err - ); - return; - } - // NOTE: OK to return conversation_id, because this conversation was just created by this user. - finishOne(res, { - url: buildConversationUrl(req, zinvite), - zid: zid, + zinvitePromise + .then(function (zinvite: null) { + if (zinvite === null) { + fail( + res, + 400, + "polis_err_conversation_id_already_in_use", + err + ); + return; + } + // NOTE: OK to return conversation_id, because this conversation was just created by this user. + finishOne(res, { + url: buildConversationUrl(req, zinvite), + zid: zid, + }); + }) + .catch(function (err: any) { + fail(res, 500, "polis_err_zinvite_create", err); }); - }) - .catch(function (err) { - fail(res, 500, "polis_err_zinvite_create", err); - }); - }); // end insert + } + ); // end insert } ); // end isUserAllowedToCreateConversations }) - .catch((err) => { + .catch((err: any) => { fail(res, 500, "polis_err_conversation_create", err); }); // end xidStuffReady } // end post conversations - function handle_POST_query_participants_by_metadata(req, res) { + function handle_POST_query_participants_by_metadata( + req: { p: { uid?: any; zid: any; pmaids: any } }, + res: { + status: ( + arg0: number + ) => { + (): any; + new (): any; + json: { (arg0: never[]): void; new (): any }; + }; + } + ) { let uid = req.p.uid; let zid = req.p.zid; let pmaids = req.p.pmaids; @@ -9771,11 +12063,13 @@ Email verified! You can close this tab or hit the back button. ")" + ";", [zid, zid], - function (err, results) { + function (err: any, results: { rows: any }) { if (err) { fail(res, 500, "polis_err_metadata_query", err); return; } + // Argument of type 'any[]' is not assignable to parameter of type 'never[]'.ts(2345) + // @ts-ignore res.status(200).json(_.pluck(results.rows, "pid")); } ); @@ -9783,12 +12077,19 @@ Email verified! You can close this tab or hit the back button. isOwnerOrParticipant(zid, uid, doneChecking); } - function handle_POST_sendCreatedLinkToEmail(req, res) { + function handle_POST_sendCreatedLinkToEmail( + req: { p: { uid?: any; zid: string } }, + res: { + status: ( + arg0: number + ) => { (): any; new (): any; json: { (arg0: {}): void; new (): any } }; + } + ) { winston.log("info", req.p); pgQuery_readOnly( "SELECT * FROM users WHERE uid = $1", [req.p.uid], - function (err, results) { + function (err: any, results: { rows: UserType[] }) { if (err) { fail(res, 500, "polis_err_get_email_db", err); return; @@ -9798,7 +12099,7 @@ Email verified! You can close this tab or hit the back button. pgQuery_readOnly( "select * from zinvites where zid = $1", [req.p.zid], - function (err, results) { + function (err: any, results: { rows: { zinvite: any }[] }) { let zinvite = results.rows[0].zinvite; let server = getServerNameWithProtocol(req); let createdLink = server + "/#" + req.p.zid + "/" + zinvite; @@ -9826,7 +12127,7 @@ Email verified! You can close this tab or hit the back button. .then(function () { res.status(200).json({}); }) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_sending_created_link_to_email", err); }); } @@ -9835,7 +12136,21 @@ Email verified! You can close this tab or hit the back button. ); } - function handle_POST_notifyTeam(req, res) { + function handle_POST_notifyTeam( + req: { + p: { + webserver_pass: string | undefined; + webserver_username: string | undefined; + subject: any; + body: any; + }; + }, + res: { + status: ( + arg0: number + ) => { (): any; new (): any; json: { (arg0: {}): void; new (): any } }; + } + ) { if ( req.p.webserver_pass !== process.env.WEBSERVER_PASS || req.p.webserver_username !== process.env.WEBSERVER_USERNAME @@ -9848,12 +12163,27 @@ Email verified! You can close this tab or hit the back button. .then(() => { res.status(200).json({}); }) - .catch((err) => { + .catch((err: any) => { return fail(res, 500, "polis_err_notifyTeam"); }); } - function handle_POST_sendEmailExportReady(req, res) { + function handle_POST_sendEmailExportReady( + req: { + p: { + webserver_pass: string | undefined; + webserver_username: string | undefined; + email: any; + conversation_id: string; + filename: any; + }; + }, + res: { + status: ( + arg0: number + ) => { (): any; new (): any; json: { (arg0: {}): void; new (): any } }; + } + ) { if ( req.p.webserver_pass !== process.env.WEBSERVER_PASS || req.p.webserver_username !== process.env.WEBSERVER_USERNAME @@ -9889,15 +12219,18 @@ Thanks for using Polis! .then(function () { res.status(200).json({}); }) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_sending_export_link_to_email", err); }); } - function getTwitterRequestToken(returnUrl) { + function getTwitterRequestToken(returnUrl: string) { let oauth = new OAuth.OAuth( "https://api.twitter.com/oauth/request_token", // null "https://api.twitter.com/oauth/access_token", // null + // Argument of type 'string | undefined' is not assignable to parameter of type 'string'. + // Type 'undefined' is not assignable to type 'string'.ts(2345) + // @ts-ignore process.env.TWITTER_CONSUMER_KEY, //'your application consumer key', process.env.TWITTER_CONSUMER_SECRET, //'your application secret', "1.0A", @@ -9907,14 +12240,19 @@ Thanks for using Polis! let body = { oauth_callback: returnUrl, }; - return new Promise(function (resolve, reject) { + return new Promise(function ( + resolve: (arg0: any) => void, + reject: (arg0: any) => void + ) { oauth.post( "https://api.twitter.com/oauth/request_token", + // Argument of type 'undefined' is not assignable to parameter of type 'string'.ts(2345) + // @ts-ignore void 0, //'your user token for this app', //test user token void 0, //'your user secret for this app', //test user secret body, "multipart/form-data", - function (e, data, res) { + function (e: any, data: any, res: any) { if (e) { console.error("get twitter token failed"); console.error(e); @@ -9928,7 +12266,10 @@ Thanks for using Polis! }); } - function handle_GET_twitterBtn(req, res) { + function handle_GET_twitterBtn( + req: { p: { dest: string; owner: string } }, + res: { redirect: (arg0: string) => void } + ) { let dest = req.p.dest || "/inbox"; dest = encodeURIComponent(getServerNameWithProtocol(req) + dest); let returnUrl = @@ -9939,34 +12280,45 @@ Thanks for using Polis! dest; getTwitterRequestToken(returnUrl) - .then(function (data) { + .then(function (data: string) { winston.log("info", data); data += "&callback_url=" + dest; // data += "&callback_url=" + encodeURIComponent(getServerNameWithProtocol(req) + "/foo"); res.redirect("https://api.twitter.com/oauth/authenticate?" + data); }) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_twitter_auth_01", err); }); } - function getTwitterAccessToken(body) { + function getTwitterAccessToken(body: { + oauth_verifier: any; + oauth_token: any; + }) { let oauth = new OAuth.OAuth( "https://api.twitter.com/oauth/request_token", // null "https://api.twitter.com/oauth/access_token", // null + // Argument of type 'string | undefined' is not assignable to parameter of type 'string'. + // Type 'undefined' is not assignable to type 'string'.ts(2345) + // @ts-ignore process.env.TWITTER_CONSUMER_KEY, //'your application consumer key', process.env.TWITTER_CONSUMER_SECRET, //'your application secret', "1.0A", null, "HMAC-SHA1" ); - return new Promise(function (resolve, reject) { + return new Promise(function ( + resolve: (arg0: any) => void, + reject: (arg0: any) => void + ) { oauth.post( "https://api.twitter.com/oauth/access_token", + // Argument of type 'undefined' is not assignable to parameter of type 'string'.ts(2345) + // @ts-ignore void 0, //'your user token for this app', //test user token void 0, //'your user secret for this app', //test user secret body, "multipart/form-data", - function (e, data, res) { + function (e: any, data: any, res: any) { if (e) { console.error("get twitter token failed"); console.error(e); @@ -9984,16 +12336,19 @@ Thanks for using Polis! let twitterUserInfoCache = new LruCache({ max: 10000, }); - function getTwitterUserInfo(o, useCache) { + function getTwitterUserInfo( + o: { twitter_user_id: any; twitter_screen_name?: any }, + useCache: boolean + ) { console.log("getTwitterUserInfo", o); let twitter_user_id = o.twitter_user_id; let twitter_screen_name = o.twitter_screen_name; - let params = { + let params: TwitterParameters = { // oauth_verifier: req.p.oauth_verifier, // oauth_token: req.p.oauth_token, // confused. needed, but docs say this: "The request token is also passed in the oauth_token portion of the header, but this will have been added by the signing process." }; - let identifier; // this is way sloppy, but should be ok for caching and logging + let identifier: string; // this is way sloppy, but should be ok for caching and logging if (twitter_user_id) { params.user_id = twitter_user_id; identifier = twitter_user_id; @@ -10005,75 +12360,101 @@ Thanks for using Polis! let oauth = new OAuth.OAuth( "https://api.twitter.com/oauth/request_token", // null "https://api.twitter.com/oauth/access_token", // null + // Argument of type 'string | undefined' is not assignable to parameter of type 'string'. + // Type 'undefined' is not assignable to type 'string'.ts(2345) + // @ts-ignore process.env.TWITTER_CONSUMER_KEY, //'your application consumer key', process.env.TWITTER_CONSUMER_SECRET, //'your application secret', "1.0A", null, "HMAC-SHA1" ); - return new MPromise("getTwitterUserInfo", function (resolve, reject) { - let cachedCopy = twitterUserInfoCache.get(identifier); - if (useCache && cachedCopy) { - return resolve(cachedCopy); - } - if ( - suspendedOrPotentiallyProblematicTwitterIds.indexOf(identifier) >= 0 + + // 'new' expression, whose target lacks a construct signature, implicitly has an 'any' type.ts(7009) + // @ts-ignore + return new MPromise( + "getTwitterUserInfo", + function ( + resolve: (arg0: any) => void, + reject: (arg0?: undefined) => void ) { - return reject(); - } - oauth.post( - "https://api.twitter.com/1.1/users/lookup.json", - void 0, //'your user token for this app', //test user token - void 0, //'your user secret for this app', //test user secret - params, - "multipart/form-data", - function (e, data, res) { - if (e) { - console.error( - "get twitter token failed for identifier: " + identifier - ); - console.error(e); - suspendedOrPotentiallyProblematicTwitterIds.push(identifier); - reject(e); - } else { - twitterUserInfoCache.set(identifier, data); - resolve(data); - } - // winston.log("info",require('util').inspect(data)); + let cachedCopy = twitterUserInfoCache.get(identifier); + if (useCache && cachedCopy) { + return resolve(cachedCopy); } - ); - }); + if ( + suspendedOrPotentiallyProblematicTwitterIds.indexOf(identifier) >= 0 + ) { + return reject(); + } + oauth.post( + "https://api.twitter.com/1.1/users/lookup.json", + // Argument of type 'undefined' is not assignable to parameter of type 'string'.ts(2345) + // @ts-ignore + void 0, //'your user token for this app', //test user token + void 0, //'your user secret for this app', //test user secret + params, + "multipart/form-data", + function (e: any, data: any, res: any) { + if (e) { + console.error( + "get twitter token failed for identifier: " + identifier + ); + console.error(e); + suspendedOrPotentiallyProblematicTwitterIds.push(identifier); + reject(e); + } else { + twitterUserInfoCache.set(identifier, data); + resolve(data); + } + // winston.log("info",require('util').inspect(data)); + } + ); + } + ); } - function getTwitterTweetById(twitter_tweet_id) { + function getTwitterTweetById(twitter_tweet_id: string) { let oauth = new OAuth.OAuth( "https://api.twitter.com/oauth/request_token", // null "https://api.twitter.com/oauth/access_token", // null + // Argument of type 'string | undefined' is not assignable to parameter of type 'string'. + // Type 'undefined' is not assignable to type 'string'.ts(2345) + // @ts-ignore process.env.TWITTER_CONSUMER_KEY, //'your application consumer key', process.env.TWITTER_CONSUMER_SECRET, //'your application secret', "1.0A", null, "HMAC-SHA1" ); - return new MPromise("getTwitterTweet", function (resolve, reject) { - oauth.get( - "https://api.twitter.com/1.1/statuses/show.json?id=" + twitter_tweet_id, - void 0, //'your user token for this app', //test user token - void 0, //'your user secret for this app', //test user secret - function (e, data, res) { - if (e) { - console.error(" - - - - get twitter tweet failed - - - -"); - console.error(e); - reject(e); - } else { - data = JSON.parse(data); - console.dir(data); - resolve(data); + + // 'new' expression, whose target lacks a construct signature, implicitly has an 'any' type.ts(7009) + // @ts-ignore + return new MPromise( + "getTwitterTweet", + function (resolve: (arg0: any) => void, reject: (arg0: any) => void) { + oauth.get( + "https://api.twitter.com/1.1/statuses/show.json?id=" + + twitter_tweet_id, + // Argument of type 'undefined' is not assignable to parameter of type 'string'.ts(2345) + // @ts-ignore + void 0, //'your user token for this app', //test user token + void 0, //'your user secret for this app', //test user secret + function (e: any, data: string, res: any) { + if (e) { + console.error(" - - - - get twitter tweet failed - - - -"); + console.error(e); + reject(e); + } else { + data = JSON.parse(data); + console.dir(data); + resolve(data); + } + // winston.log("info",require('util').inspect(data)); } - // winston.log("info",require('util').inspect(data)); - } - ); - }); + ); + } + ); } // function getTwitterUserTimeline(screen_name) { @@ -10113,21 +12494,29 @@ Thanks for using Polis! // so keep a list of these for as long as the server is running, // so we don't repeat requests for them. // This is probably not optimal, but is pretty easy. - let suspendedOrPotentiallyProblematicTwitterIds = []; - function getTwitterUserInfoBulk(list_of_twitter_user_id) { + let suspendedOrPotentiallyProblematicTwitterIds: any[] = []; + function getTwitterUserInfoBulk(list_of_twitter_user_id: any[]) { list_of_twitter_user_id = list_of_twitter_user_id || []; let oauth = new OAuth.OAuth( "https://api.twitter.com/oauth/request_token", // null "https://api.twitter.com/oauth/access_token", // null + // Argument of type 'string | undefined' is not assignable to parameter of type 'string'. + // Type 'undefined' is not assignable to type 'string'.ts(2345) + // @ts-ignore process.env.TWITTER_CONSUMER_KEY, //'your application consumer key', process.env.TWITTER_CONSUMER_SECRET, //'your application secret', "1.0A", null, "HMAC-SHA1" ); - return new Promise(function (resolve, reject) { + return new Promise(function ( + resolve: (arg0: any) => void, + reject: (arg0: any) => void + ) { oauth.post( "https://api.twitter.com/1.1/users/lookup.json", + // Argument of type 'undefined' is not assignable to parameter of type 'string'.ts(2345) + // @ts-ignore void 0, //'your user token for this app', //test user token void 0, //'your user secret for this app', //test user secret { @@ -10136,12 +12525,12 @@ Thanks for using Polis! user_id: list_of_twitter_user_id.join(","), }, "multipart/form-data", - function (e, data, res) { + function (e: any, data: string, res: any) { if (e) { console.error("get twitter token failed"); console.error(e); // we should probably check that the error is code 17: { statusCode: 404, data: '{"errors":[{"code":17,"message":"No user matches for specified terms."}]}' } - list_of_twitter_user_id.forEach(function (id) { + list_of_twitter_user_id.forEach(function (id: string) { console.log( "adding twitter_user_id to suspendedOrPotentiallyProblematicTwitterIds: " + id @@ -10159,9 +12548,12 @@ Thanks for using Polis! ); }); } - function switchToUser(req, res, uid) { - return new Promise(function (resolve, reject) { - startSession(uid, function (errSess, token) { + function switchToUser(req: any, res: any, uid?: any) { + return new Promise(function ( + resolve: () => void, + reject: (arg0: string) => void + ) { + startSession(uid, function (errSess: any, token: any) { if (errSess) { reject(errSess); return; @@ -10170,22 +12562,28 @@ Thanks for using Polis! .then(function () { resolve(); }) - .catch(function (err) { + .catch(function (err: any) { reject("polis_err_adding_cookies"); }); }); }); } // retry, resolving with first success, or rejecting with final error - function retryFunctionWithPromise(f, numTries) { - return new Promise(function (resolve, reject) { + function retryFunctionWithPromise( + f: { (): any; (): Promise }, + numTries: number + ) { + return new Promise(function ( + resolve: (arg0: any) => void, + reject: (arg0: any) => void + ) { winston.log("info", "retryFunctionWithPromise", numTries); f().then( - function (x) { + function (x: any) { winston.log("info", "retryFunctionWithPromise", "RESOLVED"); resolve(x); }, - function (err) { + function (err: any) { numTries -= 1; if (numTries <= 0) { winston.log("info", "retryFunctionWithPromise", "REJECTED"); @@ -10198,62 +12596,79 @@ Thanks for using Polis! }); } function updateSomeTwitterUsers() { - return pgQueryP_readOnly( - "select uid, twitter_user_id from twitter_users where modified < (now_as_millis() - 30*60*1000) order by modified desc limit 100;" - ).then(function (results) { - let twitter_user_ids = _.pluck(results, "twitter_user_id"); - if (results.length === 0) { - return []; - } - twitter_user_ids = _.difference( - twitter_user_ids, - suspendedOrPotentiallyProblematicTwitterIds - ); - if (twitter_user_ids.length === 0) { - return []; - } + return ( + pgQueryP_readOnly( + "select uid, twitter_user_id from twitter_users where modified < (now_as_millis() - 30*60*1000) order by modified desc limit 100;" + ) + // Argument of type '(results: string | any[]) => never[] | undefined' is not assignable to parameter of type '(value: unknown) => never[] | PromiseLike | undefined'. + // Types of parameters 'results' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + .then(function (results: string | any[]) { + let twitter_user_ids = _.pluck(results, "twitter_user_id"); + if (results.length === 0) { + return []; + } + twitter_user_ids = _.difference( + twitter_user_ids, + suspendedOrPotentiallyProblematicTwitterIds + ); + if (twitter_user_ids.length === 0) { + return []; + } - getTwitterUserInfoBulk(twitter_user_ids) - .then(function (info) { - // Uncomment to log out lots of twitter crap for a good time - //console.dir(info); - - let updateQueries = info.map(function (u) { - let q = - "update twitter_users set " + - "screen_name = ($2)," + - "name = ($3)," + - "followers_count = ($4)," + - "friends_count = ($5)," + - "verified = ($6)," + - "profile_image_url_https = ($7)," + - "location = ($8)," + - "modified = now_as_millis() " + - "where twitter_user_id = ($1);"; - - // uncomment to see some other twitter crap - //console.log(q); - return pgQueryP(q, [ - u.id, - u.screen_name, - u.name, - u.followers_count, - u.friends_count, - u.verified, - u.profile_image_url_https, - u.location, - ]); - }); - return Promise.all(updateQueries).then(function () { - console.log("done123"); - }); + getTwitterUserInfoBulk(twitter_user_ids) + .then(function (info: any[]) { + // Uncomment to log out lots of twitter crap for a good time + //console.dir(info); + + let updateQueries = info.map(function (u: { + id: any; + screen_name: any; + name: any; + followers_count: any; + friends_count: any; + verified: any; + profile_image_url_https: any; + location: any; + }) { + let q = + "update twitter_users set " + + "screen_name = ($2)," + + "name = ($3)," + + "followers_count = ($4)," + + "friends_count = ($5)," + + "verified = ($6)," + + "profile_image_url_https = ($7)," + + "location = ($8)," + + "modified = now_as_millis() " + + "where twitter_user_id = ($1);"; + + // uncomment to see some other twitter crap + //console.log(q); + return pgQueryP(q, [ + u.id, + u.screen_name, + u.name, + u.followers_count, + u.friends_count, + u.verified, + u.profile_image_url_https, + u.location, + ]); + }); + return Promise.all(updateQueries).then(function () { + console.log("done123"); + }); + }) + .catch(function (err: any) { + console.error( + "error updating twitter users:" + twitter_user_ids.join(" ") + ); + }); }) - .catch(function (err) { - console.error( - "error updating twitter users:" + twitter_user_ids.join(" ") - ); - }); - }); + ); } // Ensure we don't call this more than 60 times in each 15 minute window (across all of our servers/use-cases) setInterval(updateSomeTwitterUsers, 1 * 60 * 1000); @@ -10261,9 +12676,12 @@ Thanks for using Polis! // getTwitterTweetById("627881237101846528").then(function(tweet) { // console.dir(tweet); // }); - function createUserFromTwitterInfo(o) { - return createDummyUser().then(function (uid) { - return getAndInsertTwitterUser(o, uid).then(function (result) { + function createUserFromTwitterInfo(o: any) { + return createDummyUser().then(function (uid?: any) { + return getAndInsertTwitterUser(o, uid).then(function (result: { + twitterUser: any; + twitterUserDbRecord: any; + }) { let u = result.twitterUser; let twitterUserDbRecord = result.twitterUserDbRecord; @@ -10276,12 +12694,18 @@ Thanks for using Polis! }); }); } - function prepForQuoteWithTwitterUser(quote_twitter_screen_name, zid) { + function prepForQuoteWithTwitterUser( + quote_twitter_screen_name: any, + zid: any + ) { let query = pgQueryP( "select * from twitter_users where screen_name = ($1);", [quote_twitter_screen_name] ); return addParticipantByTwitterUserId( + // Argument of type 'Promise' is not assignable to parameter of type 'Bluebird'. + // Type 'Promise' is missing the following properties from type 'Bluebird': caught, error, lastly, bind, and 38 more.ts(2345) + // @ts-ignore query, { twitter_screen_name: quote_twitter_screen_name, @@ -10291,8 +12715,10 @@ Thanks for using Polis! ); } - function prepForTwitterComment(twitter_tweet_id, zid) { - return getTwitterTweetById(twitter_tweet_id).then(function (tweet) { + function prepForTwitterComment(twitter_tweet_id: any, zid: any) { + return getTwitterTweetById(twitter_tweet_id).then(function (tweet: { + user: any; + }) { let user = tweet.user; let twitter_user_id = user.id_str; let query = pgQueryP( @@ -10300,6 +12726,8 @@ Thanks for using Polis! [twitter_user_id] ); return addParticipantByTwitterUserId( + // Argument of type 'Promise' is not assignable to parameter of type 'Bluebird'.ts(2345) + // @ts-ignore query, { twitter_user_id: twitter_user_id, @@ -10309,23 +12737,39 @@ Thanks for using Polis! ); }); } - function addParticipantByTwitterUserId(query, o, zid, tweet) { - function addParticipantAndFinish(uid, twitterUser, tweet) { - return addParticipant(zid, uid).then(function (rows) { - let ptpt = rows[0]; - return { - ptpt: ptpt, - twitterUser: twitterUser, - tweet: tweet, - }; - }); + function addParticipantByTwitterUserId( + query: Promise, + o: { twitter_screen_name?: any; twitter_user_id?: any }, + zid: any, + tweet: { user: any } | null + ) { + function addParticipantAndFinish( + uid?: any, + twitterUser?: any, + tweet?: any + ) { + return ( + addParticipant(zid, uid) + // Argument of type '(rows: any[]) => { ptpt: any; twitterUser: any; tweet: any; }' is not assignable to parameter of type '(value: unknown) => { ptpt: any; twitterUser: any; tweet: any; } | PromiseLike<{ ptpt: any; twitterUser: any; tweet: any; }>'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + .then(function (rows: any[]) { + let ptpt = rows[0]; + return { + ptpt: ptpt, + twitterUser: twitterUser, + tweet: tweet, + }; + }) + ); } - return query.then(function (rows) { + return query.then(function (rows: string | any[]) { if (rows && rows.length) { let twitterUser = rows[0]; let uid = twitterUser.uid; return getParticipant(zid, uid) - .then(function (ptpt) { + .then(function (ptpt: any) { if (!ptpt) { return addParticipantAndFinish(uid, twitterUser, tweet); } @@ -10335,21 +12779,30 @@ Thanks for using Polis! tweet: tweet, }; }) - .catch(function (err) { + .catch(function (err: any) { return addParticipantAndFinish(uid, twitterUser, tweet); }); } else { // no user records yet - return createUserFromTwitterInfo(o).then(function (twitterUser) { + return createUserFromTwitterInfo(o).then(function (twitterUser: { + uid?: any; + }) { let uid = twitterUser.uid; - return addParticipant(zid, uid).then(function (rows) { - let ptpt = rows[0]; - return { - ptpt: ptpt, - twitterUser: twitterUser, - tweet: tweet, - }; - }); + return ( + addParticipant(zid, uid) + // Argument of type '(rows: any[]) => { ptpt: any; twitterUser: { uid?: any; }; tweet: { user: any; } | null; }' is not assignable to parameter of type '(value: unknown) => { ptpt: any; twitterUser: { uid?: any; }; tweet: { user: any; } | null; } | PromiseLike<{ ptpt: any; twitterUser: { uid?: any; }; tweet: { user: any; } | null; }>'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + .then(function (rows: any[]) { + let ptpt = rows[0]; + return { + ptpt: ptpt, + twitterUser: twitterUser, + tweet: tweet, + }; + }) + ); }); } }); @@ -10367,7 +12820,7 @@ Thanks for using Polis! // * create a twitter record } - function addParticipant(zid, uid) { + function addParticipant(zid: any, uid?: any) { return pgQueryP( "INSERT INTO participants_extended (zid, uid) VALUES ($1, $2);", [zid, uid] @@ -10378,50 +12831,61 @@ Thanks for using Polis! ); }); } - function getAndInsertTwitterUser(o, uid) { - return getTwitterUserInfo(o, false).then(function (u) { - u = JSON.parse(u)[0]; + function getAndInsertTwitterUser(o: any, uid?: any) { + return getTwitterUserInfo(o, false).then(function (userString: string) { + const u: UserType = JSON.parse(userString)[0]; winston.log("info", "TWITTER USER INFO"); winston.log("info", u); winston.log("info", "/TWITTER USER INFO"); - return pgQueryP( - "insert into twitter_users (" + - "uid," + - "twitter_user_id," + - "screen_name," + - "name," + - "followers_count," + - "friends_count," + - "verified," + - "profile_image_url_https," + - "location," + - "response" + - ") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) returning *;", - [ - uid, - u.id, - u.screen_name, - u.name, - u.followers_count, - u.friends_count, - u.verified, - u.profile_image_url_https, - u.location, - JSON.stringify(u), - ] - ).then(function (rows) { - let record = (rows && rows.length && rows[0]) || null; - - // return the twitter user record - return { - twitterUser: u, - twitterUserDbRecord: record, - }; - }); + return ( + pgQueryP( + "insert into twitter_users (" + + "uid," + + "twitter_user_id," + + "screen_name," + + "name," + + "followers_count," + + "friends_count," + + "verified," + + "profile_image_url_https," + + "location," + + "response" + + ") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) returning *;", + [ + uid, + u.id, + u.screen_name, + u.name, + u.followers_count, + u.friends_count, + u.verified, + u.profile_image_url_https, + u.location, + JSON.stringify(u), + ] + ) + // Argument of type '(rows: string | any[]) => { twitterUser: UserType; twitterUserDbRecord: any; }' is not assignable to parameter of type '(value: unknown) => { twitterUser: UserType; twitterUserDbRecord: any; } | PromiseLike<{ twitterUser: UserType; twitterUserDbRecord: any; }>'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + .then(function (rows: string | any[]) { + let record = (rows && rows.length && rows[0]) || null; + + // return the twitter user record + return { + twitterUser: u, + twitterUserDbRecord: record, + }; + }) + ); }); } - function handle_GET_twitter_oauth_callback(req, res) { + function handle_GET_twitter_oauth_callback( + req: { p: { uid?: any; dest: any; oauth_verifier: any; oauth_token: any } }, + res: { redirect: (arg0: any) => void } + ) { let uid = req.p.uid; winston.log("info", "twitter oauth callback req.p", req.p); @@ -10441,11 +12905,11 @@ Thanks for using Polis! } retryFunctionWithPromise(tryGettingTwitterAccessToken, 20) .then( - function (o) { + function (o: string) { winston.log("info", "TWITTER ACCESS TOKEN"); let pairs = o.split("&"); - let kv = {}; - pairs.forEach(function (pair) { + let kv: TwitterParameters = {}; + pairs.forEach(function (pair: string) { let pairSplit = pair.split("="); let k = pairSplit[0]; let v = pairSplit[1]; @@ -10467,8 +12931,8 @@ Thanks for using Polis! false ) .then( - function (u) { - u = JSON.parse(u)[0]; + function (userStringPayload: string) { + const u: UserType = JSON.parse(userStringPayload)[0]; winston.log("info", "TWITTER USER INFO"); winston.log("info", u); winston.log("info", "/TWITTER USER INFO"); @@ -10513,11 +12977,11 @@ Thanks for using Polis! //maybeAddToIntercom(u); res.redirect(dest); }, - function (err) { + function (err: any) { fail(res, 500, "polis_err_twitter_auth_update", err); } ) - .catch(function (err) { + .catch(function (err: any) { fail( res, 500, @@ -10526,7 +12990,7 @@ Thanks for using Polis! ); }); }, - function (err) { + function (err: any) { if (isDuplicateKey(err)) { // we know the uid OR twitter_user_id is filled // check if the uid is there with the same twitter_user_id - if so, redirect and good! @@ -10540,53 +13004,69 @@ Thanks for using Polis! "select * from twitter_users where twitter_user_id = ($1);", [u.id] ), - ]).then(function (foo) { - let recordForUid = foo[0][0]; - let recordForTwitterId = foo[1][0]; - if (recordForUid && recordForTwitterId) { - if (recordForUid.uid === recordForTwitterId.uid) { - // match - res.redirect(dest); - } else { + ]) + // No overload matches this call. + // Overload 1 of 2, '(onFulfill?: ((value: [unknown, unknown]) => Resolvable) | undefined, onReject?: ((error: any) => Resolvable) | undefined): Bluebird', gave the following error. + // Argument of type '(foo: any[][]) => void' is not assignable to parameter of type '(value: [unknown, unknown]) => Resolvable'. + // Types of parameters 'foo' and 'value' are incompatible. + // Type '[unknown, unknown]' is not assignable to type 'any[][]'. + // Overload 2 of 2, '(onfulfilled?: ((value: [unknown, unknown]) => Resolvable) | null | undefined, onrejected?: ((reason: any) => PromiseLike) | null | undefined): Bluebird', gave the following error. + // Argument of type '(foo: any[][]) => void' is not assignable to parameter of type '(value: [unknown, unknown]) => Resolvable'. + // Types of parameters 'foo' and 'value' are incompatible. + // Type '[unknown, unknown]' is not assignable to type 'any[][]'.ts(2769) + // @ts-ignore + .then(function (foo: any[][]) { + let recordForUid = foo[0][0]; + let recordForTwitterId = foo[1][0]; + if (recordForUid && recordForTwitterId) { + if (recordForUid.uid === recordForTwitterId.uid) { + // match + res.redirect(dest); + } else { + // TODO_SECURITY_REVIEW + // both exist, but not same uid + switchToUser(req, res, recordForTwitterId.uid) + .then(function () { + res.redirect(dest); + }) + .catch(function (err: any) { + fail( + res, + 500, + "polis_err_twitter_auth_456", + err + ); + }); + } + } else if (recordForUid) { + // currently signed in user has a twitter account attached, but it's a different twitter account, and they are now signing in with a different twitter account. + // the newly supplied twitter account is not attached to anything. + fail( + res, + 500, + "polis_err_twitter_already_attached", + err + ); + } else if (recordForTwitterId) { + // currently signed in user has no twitter account attached, but they just signed in with a twitter account which is attached to another user. + // For now, let's just have it sign in as that user. // TODO_SECURITY_REVIEW - // both exist, but not same uid switchToUser(req, res, recordForTwitterId.uid) .then(function () { res.redirect(dest); }) - .catch(function (err) { + .catch(function (err: any) { fail( res, 500, - "polis_err_twitter_auth_456", + "polis_err_twitter_auth_234", err ); }); + } else { + fail(res, 500, "polis_err_twitter_auth_345"); } - } else if (recordForUid) { - // currently signed in user has a twitter account attached, but it's a different twitter account, and they are now signing in with a different twitter account. - // the newly supplied twitter account is not attached to anything. - fail( - res, - 500, - "polis_err_twitter_already_attached", - err - ); - } else if (recordForTwitterId) { - // currently signed in user has no twitter account attached, but they just signed in with a twitter account which is attached to another user. - // For now, let's just have it sign in as that user. - // TODO_SECURITY_REVIEW - switchToUser(req, res, recordForTwitterId.uid) - .then(function () { - res.redirect(dest); - }) - .catch(function (err) { - fail(res, 500, "polis_err_twitter_auth_234", err); - }); - } else { - fail(res, 500, "polis_err_twitter_auth_345"); - } - }); + }); // else check if the uid is there and has some other screen_name - if so, ???????? @@ -10597,36 +13077,46 @@ Thanks for using Polis! } ); }, - function (err) { + function (err: any) { winston.log("error", "failed to getTwitterUserInfo"); fail(res, 500, "polis_err_twitter_auth_041", err); } ) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_twitter_auth_04", err); }); }, - function (err) { + function (err: any) { fail(res, 500, "polis_err_twitter_auth_gettoken", err); } ) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_twitter_auth_misc", err); }); } - function getSocialParticipantsForMod_timed() { + function getSocialParticipantsForMod_timed( + zid?: any, + limit?: any, + mod?: any, + convOwner?: any + ) { let start = Date.now(); return getSocialParticipantsForMod - .apply(null, arguments) - .then(function (results) { + .apply(null, [zid, limit, mod, convOwner]) + .then(function (results: any) { let elapsed = Date.now() - start; console.log("getSocialParticipantsForMod_timed", elapsed); return results; }); } - function getSocialParticipantsForMod(zid, limit, mod, owner) { + function getSocialParticipantsForMod( + zid: any, + limit: any, + mod: any, + owner: any + ) { let modClause = ""; let params = [zid, limit, owner]; if (!_.isUndefined(mod)) { @@ -10692,18 +13182,33 @@ Thanks for using Polis! max: 999, }); - function getSocialParticipants(zid, uid, limit, mod, math_tick, authorUids) { + function getSocialParticipants( + zid: any, + uid?: any, + limit?: any, + mod?: number, + math_tick?: any, + authorUids?: any[] + ) { // NOTE ignoring authorUids as part of cacheKey for now, just because. let cacheKey = [zid, limit, mod, math_tick].join("_"); if (socialParticipantsCache.get(cacheKey)) { return socialParticipantsCache.get(cacheKey); } - let authorsQuery = authorUids.map(function (authorUid) { + const authorsQueryParts = (authorUids || []).map(function ( + authoruid?: any + ) { + // TODO investigate this one. + // TODO looks like a possible typo bug + // Cannot find name 'authorUid'. Did you mean 'authoruid'?ts(2552) + // server.ts(12486, 7): 'authoruid' is declared here. + // @ts-ignore return "select " + Number(authorUid) + " as uid, 900 as priority"; }); - authorsQuery = "(" + authorsQuery.join(" union ") + ")"; - if (authorUids.length === 0) { + let authorsQuery: string | null = + "(" + authorsQueryParts.join(" union ") + ")"; + if (!authorUids || authorUids.length === 0) { authorsQuery = null; } @@ -10802,7 +13307,7 @@ Thanks for using Polis! uid, limit, mod, - ]).then(function (response) { + ]).then(function (response: any) { console.log("getSocialParticipants", response); socialParticipantsCache.set(cacheKey, response); return response; @@ -10832,7 +13337,7 @@ Thanks for using Polis! const getSocialInfoForUsers = User.getSocialInfoForUsers; - function updateVoteCount(zid, pid) { + function updateVoteCount(zid: any, pid: any) { // return pgQueryP("update participants set vote_count = vote_count + 1 where zid = ($1) and pid = ($2);",[zid, pid]); return pgQueryP( "update participants set vote_count = (select count(*) from votes where zid = ($1) and pid = ($2)) where zid = ($1) and pid = ($2)", @@ -10846,10 +13351,16 @@ Thanks for using Polis! max: 5000, }); - function getVotesForZidPidWithTimestampCheck(zid, pid, math_tick) { + function getVotesForZidPidWithTimestampCheck( + zid: string, + pid: string, + math_tick: number + ) { let key = zid + "_" + pid; let cachedVotes = votesForZidPidCache.get(key); if (cachedVotes) { + // Object is of type 'unknown'.ts(2571) + // @ts-ignore let pair = cachedVotes.split(":"); let cachedTime = Number(pair[0]); let votes = pair[1]; @@ -10859,33 +13370,45 @@ Thanks for using Polis! } return null; } - function cacheVotesForZidPidWithTimestamp(zid, pid, math_tick, votes) { + function cacheVotesForZidPidWithTimestamp( + zid: string, + pid: string, + math_tick: string, + votes: string + ) { let key = zid + "_" + pid; let val = math_tick + ":" + votes; votesForZidPidCache.set(key, val); } // returns {pid -> "adadddadpupuuuuuuuu"} - function getVotesForZidPidsWithTimestampCheck(zid, pids, math_tick) { - let cachedVotes = pids.map(function (pid) { + function getVotesForZidPidsWithTimestampCheck( + zid: any, + pids: any[], + math_tick: any + ) { + let cachedVotes = pids.map(function (pid: any) { return { pid: pid, votes: getVotesForZidPidWithTimestampCheck(zid, pid, math_tick), }; }); let uncachedPids = cachedVotes - .filter(function (o) { + .filter(function (o: { votes: any }) { return !o.votes; }) - .map(function (o) { + .map(function (o: { pid: any }) { return o.pid; }); - cachedVotes = cachedVotes.filter(function (o) { + cachedVotes = cachedVotes.filter(function (o: { votes: any }) { return !!o.votes; }); - function toObj(items) { + function toObj(items: string | any[]) { let o = {}; for (var i = 0; i < items.length; i++) { + // Element implicitly has an 'any' type because expression of type 'string | number' can't be used to index type '{}'. + // No index signature with a parameter of type 'string' was found on type '{}'.ts(7053) + // @ts-ignore o[items[i].pid] = items[i].votes; } return o; @@ -10894,33 +13417,41 @@ Thanks for using Polis! if (uncachedPids.length === 0) { return Promise.resolve(toObj(cachedVotes)); } - return getVotesForPids(zid, uncachedPids).then(function (votesRows) { + return getVotesForPids(zid, uncachedPids).then(function (votesRows: any) { let newPidToVotes = aggregateVotesToPidVotesObj(votesRows); - _.each(newPidToVotes, function (votes, pid) { + _.each(newPidToVotes, function (votes: any, pid: any) { cacheVotesForZidPidWithTimestamp(zid, pid, math_tick, votes); }); let cachedPidToVotes = toObj(cachedVotes); return Object.assign(newPidToVotes, cachedPidToVotes); }); } - function getVotesForPids(zid, pids) { + function getVotesForPids(zid: any, pids: any[]) { if (pids.length === 0) { return Promise.resolve([]); } - return pgQueryP_readOnly( - "select * from votes where zid = ($1) and pid in (" + - pids.join(",") + - ") order by pid, tid, created;", - [zid] - ).then(function (votesRows) { - for (var i = 0; i < votesRows.length; i++) { - votesRows[i].weight = votesRows[i].weight / 32767; - } - return votesRows; - }); + return ( + pgQueryP_readOnly( + "select * from votes where zid = ($1) and pid in (" + + pids.join(",") + + ") order by pid, tid, created;", + [zid] + ) + // Argument of type '(votesRows: string | any[]) => string | any[]' is not assignable to parameter of type '(value: unknown) => string | any[] | PromiseLike'. + // Types of parameters 'votesRows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + .then(function (votesRows: string | any[]) { + for (var i = 0; i < votesRows.length; i++) { + votesRows[i].weight = votesRows[i].weight / 32767; + } + return votesRows; + }) + ); } - function createEmptyVoteVector(greatestTid) { + function createEmptyVoteVector(greatestTid: number) { let a = []; for (var i = 0; i <= greatestTid; i++) { a[i] = "u"; // (u)nseen @@ -10928,7 +13459,7 @@ Thanks for using Polis! return a; } - function aggregateVotesToPidVotesObj(votes) { + function aggregateVotesToPidVotesObj(votes: string | any[]) { let i = 0; let greatestTid = 0; for (i = 0; i < votes.length; i++) { @@ -10943,38 +13474,54 @@ Thanks for using Polis! let v = votes[i]; // set up a vector for the participant, if not there already + // Element implicitly has an 'any' type because expression of type 'string | number' can't be used to index type '{}'. + // No index signature with a parameter of type 'string' was found on type '{}'.ts(7053) + // @ts-ignore vectors[v.pid] = vectors[v.pid] || createEmptyVoteVector(greatestTid); // assign a vote value at that location let vote = v.vote; if (polisTypes.reactions.push === vote) { + // Element implicitly has an 'any' type because expression of type 'string | number' can't be used to index type '{}'. + // No index signature with a parameter of type 'string' was found on type '{}'.ts(7053) + // @ts-ignore vectors[v.pid][v.tid] = "d"; } else if (polisTypes.reactions.pull === vote) { + // Element implicitly has an 'any' type because expression of type 'string | number' can't be used to index type '{}'. + // No index signature with a parameter of type 'string' was found on type '{}'.ts(7053) + // @ts-ignore vectors[v.pid][v.tid] = "a"; } else if (polisTypes.reactions.pass === vote) { + // Element implicitly has an 'any' type because expression of type 'string | number' can't be used to index type '{}'. + // No index signature with a parameter of type 'string' was found on type '{}'.ts(7053) + // @ts-ignore vectors[v.pid][v.tid] = "p"; } else { console.error("unknown vote value"); // let it stay 'u' } } - let vectors2 = {}; - _.each(vectors, function (val, key) { + let vectors2: { [key: string]: any } = {}; + // Argument of type '(val: any[], key: string) => void' is not assignable to parameter of type 'CollectionIterator'. + // Types of parameters 'val' and 'element' are incompatible. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + _.each(vectors, function (val: any[], key: string) { vectors2[key] = val.join(""); }); return vectors2; } - function getLocationsForParticipants(zid) { + function getLocationsForParticipants(zid: any) { return pgQueryP_readOnly( "select * from participant_locations where zid = ($1);", [zid] ); } - function getPidsForGid(zid, gid, math_tick) { + function getPidsForGid(zid: any, gid: number, math_tick: number) { return Promise.all([ getPca(zid, math_tick), getBidIndexToPidMapping(zid, math_tick), - ]).then(function (o) { + ]).then(function (o: ParticipantOption[]) { if (!o[0] || !o[0].asPOJO) { return []; } @@ -10991,7 +13538,7 @@ Thanks for using Polis! return []; } let members = cluster.members; // bids - let pids = []; + let pids: any[] = []; for (var i = 0; i < members.length; i++) { let bid = members[i]; let index = bidToIndex[bid]; @@ -11008,11 +13555,14 @@ Thanks for using Polis! }); } - function geoCodeWithGoogleApi(locationString) { + function geoCodeWithGoogleApi(locationString: string) { let googleApiKey = process.env.GOOGLE_API_KEY; let address = encodeURI(locationString); - return new Promise(function (resolve, reject) { + return new Promise(function ( + resolve: (arg0: any) => void, + reject: (arg0: string) => void + ) { request .get( "https://maps.googleapis.com/maps/api/geocode/json?address=" + @@ -11020,7 +13570,7 @@ Thanks for using Polis! "&key=" + googleApiKey ) - .then(function (response) { + .then(function (response: any) { response = JSON.parse(response); if (response.status !== "OK") { reject("polis_err_geocoding_failed"); @@ -11033,41 +13583,53 @@ Thanks for using Polis! }); } - function geoCode(locationString) { - return pgQueryP("select * from geolocation_cache where location = ($1);", [ - locationString, - ]).then(function (rows) { - if (!rows || !rows.length) { - return geoCodeWithGoogleApi(locationString).then(function (result) { - winston.log("info", result); - let lat = result.geometry.location.lat; - let lng = result.geometry.location.lng; - // NOTE: not waiting for the response to this - it might fail in the case of a race-condition, since we don't have upsert - pgQueryP( - "insert into geolocation_cache (location,lat,lng,response) values ($1,$2,$3,$4);", - [locationString, lat, lng, JSON.stringify(result)] - ); - let o = { - lat: lat, - lng: lng, - }; - return o; - }); - } else { - let o = { - lat: rows[0].lat, - lng: rows[0].lng, - }; - return o; - } - }); + function geoCode(locationString: any) { + return ( + pgQueryP("select * from geolocation_cache where location = ($1);", [ + locationString, + ]) + // Argument of type '(rows: string | any[]) => Bluebird<{ lat: any; lng: any; }> | { lat: any; lng: any; }' is not assignable to parameter of type '(value: unknown) => { lat: any; lng: any; } | PromiseLike<{ lat: any; lng: any; }>'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + .then(function (rows: string | any[]) { + if (!rows || !rows.length) { + return geoCodeWithGoogleApi(locationString).then(function (result: { + geometry: { location: { lat: any; lng: any } }; + }) { + winston.log("info", result); + let lat = result.geometry.location.lat; + let lng = result.geometry.location.lng; + // NOTE: not waiting for the response to this - it might fail in the case of a race-condition, since we don't have upsert + pgQueryP( + "insert into geolocation_cache (location,lat,lng,response) values ($1,$2,$3,$4);", + [locationString, lat, lng, JSON.stringify(result)] + ); + let o = { + lat: lat, + lng: lng, + }; + return o; + }); + } else { + let o = { + lat: rows[0].lat, + lng: rows[0].lng, + }; + return o; + } + }) + ); } + // Value of type 'typeof LRUCache' is not callable. Did you mean to include 'new'? ts(2348) + // @ts-ignore let twitterShareCountCache = LruCache({ maxAge: 1000 * 60 * 30, // 30 minutes max: 999, }); - function getTwitterShareCountForConversation(conversation_id) { + function getTwitterShareCountForConversation(conversation_id: string) { let cached = twitterShareCountCache.get(conversation_id); if (cached) { return Promise.resolve(cached); @@ -11079,7 +13641,7 @@ Thanks for using Polis! "https://cdn.api.twitter.com/1/urls/count.json?url=https://pol.is/" + conversation_id; return Promise.all([request.get(httpUrl), request.get(httpsUrl)]).then( - function (a) { + function (a: any[]) { let httpResult = a[0]; let httpsResult = a[1]; let httpCount = JSON.parse(httpResult).count; @@ -11096,37 +13658,71 @@ Thanks for using Polis! ); } + // Value of type 'typeof LRUCache' is not callable. Did you mean to include 'new'? ts(2348) + // @ts-ignore let fbShareCountCache = LruCache({ maxAge: 1000 * 60 * 30, // 30 minutes max: 999, }); - function getFacebookShareCountForConversation(conversation_id) { + function getFacebookShareCountForConversation(conversation_id: string) { let cached = fbShareCountCache.get(conversation_id); if (cached) { return Promise.resolve(cached); } let url = "http://graph.facebook.com/?id=https://pol.is/" + conversation_id; - return request.get(url).then(function (result) { + return request.get(url).then(function (result: string) { let shares = JSON.parse(result).shares; fbShareCountCache.set(conversation_id, shares); return shares; }); } - function getParticipantDemographicsForConversation(zid) { + function getParticipantDemographicsForConversation(zid: any) { return pgQueryP( "select * from demographic_data left join participants on participants.uid = demographic_data.uid where zid = ($1);", [zid] ); } - function getParticipantVotesForCommentsFlaggedWith_is_meta(zid) { + function getParticipantVotesForCommentsFlaggedWith_is_meta(zid: any) { return pgQueryP( "select tid, pid, vote from votes_latest_unique where zid = ($1) and tid in (select tid from comments where zid = ($1) and is_meta = true)", [zid] ); } - function handle_GET_groupDemographics(req, res) { + function handle_GET_groupDemographics( + req: { p: { zid: any; uid?: any; rid: any } }, + res: { + json: ( + arg0: { + gid: number; + count: number; + // fb_gender_male: 0, + // fb_gender_female: 0, + // fb_gender_null: 0, + // ms_gender_estimate_fb_male: 0, + // ms_gender_estimate_fb_female: 0, + // ms_gender_estimate_fb_null: 0, + // gender_guess_male: 0, + // gender_guess_female: 0, + // gender_guess_null: 0, + // ms_birth_year_estimate_fb: 0, + // ms_birth_year_count: 0, + // birth_year_guess: 0, + // birth_year_guess_count: 0, + // convenient counts + gender_male: number; + gender_female: number; + gender_null: number; + birth_year: number; + birth_year_count: number; + meta_comment_agrees: {}; + meta_comment_disagrees: {}; + meta_comment_passes: {}; + }[] + ) => void; + } + ) { let zid = req.p.zid; Promise.all([ getPidsForGid(zid, 0, -1), @@ -11138,7 +13734,7 @@ Thanks for using Polis! getParticipantVotesForCommentsFlaggedWith_is_meta(zid), isModerator(req.p.zid, req.p.uid), ]) - .then((o) => { + .then((o: any[]) => { let groupPids = []; let groupStats = []; @@ -11192,7 +13788,15 @@ Thanks for using Polis! let pidToMetaVotes = _.groupBy(metaVotes, "pid"); for (let i = 0; i < groupStats.length; i++) { - let s = groupStats[i]; + // Type '{ gid: number; count: number; gender_male: number; gender_female: number; + // gender_null: number; birth_year: number; birth_year_count: number; + // meta_comment_agrees: { }; meta_comment_disagrees: { }; meta_comment_passes: { }; } + // ' is missing the following properties from type 'DemographicEntry': + // ms_birth_year_estimate_fb, ms_birth_year_count, birth_year_guess, + // birth_year_guess_countts(2739) + // + // @ts-ignore + let s: DemographicEntry = groupStats[i]; let pids = groupPids[i]; for (let p = 0; p < pids.length; p++) { let pid = pids[p]; @@ -11262,13 +13866,31 @@ Thanks for using Polis! for (let v = 0; v < ptptMetaVotes.length; v++) { let vote = ptptMetaVotes[v]; if (vote.vote === polisTypes.reactions.pass) { + // Element implicitly has an 'any' type because expression of type 'string | number' can't be used to index type '{}'. + // No index signature with a parameter of type 'string' was found on type '{}'.ts(7053) + // @ts-ignore s.meta_comment_passes[vote.tid] = + // Element implicitly has an 'any' type because expression of type 'string | number' can't be used to index type '{}'. + // No index signature with a parameter of type 'string' was found on type '{}'.ts(7053) + // @ts-ignore 1 + (s.meta_comment_passes[vote.tid] || 0); } else if (vote.vote === polisTypes.reactions.pull) { + // Element implicitly has an 'any' type because expression of type 'string | number' can't be used to index type '{}'. + // No index signature with a parameter of type 'string' was found on type '{}'.ts(7053) + // @ts-ignore s.meta_comment_agrees[vote.tid] = + // Element implicitly has an 'any' type because expression of type 'string | number' can't be used to index type '{}'. + // No index signature with a parameter of type 'string' was found on type '{}'.ts(7053) + // @ts-ignore 1 + (s.meta_comment_agrees[vote.tid] || 0); } else if (vote.vote === polisTypes.reactions.push) { + // Element implicitly has an 'any' type because expression of type 'string | number' can't be used to index type '{}'. + // No index signature with a parameter of type 'string' was found on type '{}'.ts(7053) + // @ts-ignore s.meta_comment_disagrees[vote.tid] = + // Element implicitly has an 'any' type because expression of type 'string | number' can't be used to index type '{}'. + // No index signature with a parameter of type 'string' was found on type '{}'.ts(7053) + // @ts-ignore 1 + (s.meta_comment_disagrees[vote.tid] || 0); } } @@ -11282,28 +13904,39 @@ Thanks for using Polis! res.json(groupStats); }) - .catch((err) => { + .catch((err: any) => { fail(res, 500, "polis_err_groupDemographics", err); }); } // this is for testing the encryption - function handle_GET_logMaxmindResponse(req, res) { + function handle_GET_logMaxmindResponse( + req: { p: { uid?: any; zid: any; user_uid?: any } }, + res: { json: (arg0: {}) => void } + ) { if (!isPolisDev(req.p.uid) || !devMode) { + // TODO fix this by piping the error from the usage of this in ./app + // Cannot find name 'err'.ts(2304) + // @ts-ignore return fail(res, 403, "polis_err_permissions", err); } pgQueryP( "select * from participants_extended where zid = ($1) and uid = ($2);", [req.p.zid, req.p.user_uid] ) - .then((results) => { + // Argument of type '(results: string | any[]) => void' is not assignable to parameter of type '(value: unknown) => void | PromiseLike'. + // Types of parameters 'results' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + .then((results: string | any[]) => { if (!results || !results.length) { res.json({}); console.log("NOTHING"); return; } var o = results[0]; - _.each(o, (val, key) => { + _.each(o, (val: any, key: string) => { if (key.startsWith("encrypted_")) { o[key] = decrypt(val); } @@ -11311,24 +13944,31 @@ Thanks for using Polis! console.log(o); res.json({}); }) - .catch((err) => { + .catch((err: any) => { fail(res, 500, "polis_err_get_participantsExtended", err); }); } - function handle_GET_locations(req, res) { + function handle_GET_locations( + req: { p: { zid: any; gid: any } }, + res: { + status: ( + arg0: number + ) => { (): any; new (): any; json: { (arg0: any): void; new (): any } }; + } + ) { let zid = req.p.zid; let gid = req.p.gid; Promise.all([getPidsForGid(zid, gid, -1), getLocationsForParticipants(zid)]) - .then(function (o) { + .then(function (o: any[]) { let pids = o[0]; let locations = o[1]; - locations = locations.filter(function (locData) { + locations = locations.filter(function (locData: { pid: any }) { let pidIsInGroup = _.indexOf(pids, locData.pid, true) >= 0; // uses binary search return pidIsInGroup; }); - locations = locations.map(function (locData) { + locations = locations.map(function (locData: { lat: any; lng: any }) { return { lat: locData.lat, lng: locData.lng, @@ -11337,11 +13977,11 @@ Thanks for using Polis! }); res.status(200).json(locations); }) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_locations_01", err); }); } - function removeNullOrUndefinedProperties(o) { + function removeNullOrUndefinedProperties(o: { [x: string]: any }) { for (var k in o) { let v = o[k]; if (v === null || v === undefined) { @@ -11351,7 +13991,7 @@ Thanks for using Polis! return o; } - function pullXInfoIntoSubObjects(ptptoiRecord) { + function pullXInfoIntoSubObjects(ptptoiRecord: any) { let p = ptptoiRecord; if (p.x_profile_image_url || p.xid || p.x_email) { p.xInfo = {}; @@ -11367,10 +14007,10 @@ Thanks for using Polis! return p; } - function pullFbTwIntoSubObjects(ptptoiRecord) { + function pullFbTwIntoSubObjects(ptptoiRecord: any) { let p = ptptoiRecord; - let x = {}; - _.each(p, function (val, key) { + let x: ParticipantSocialNetworkInfo = {}; + _.each(p, function (val: null, key: string) { let fbMatch = /fb__(.*)/.exec(key); let twMatch = /tw__(.*)/.exec(key); if (fbMatch && fbMatch.length === 2 && val !== null) { @@ -11411,13 +14051,20 @@ Thanks for using Polis! } return x; } - function handle_PUT_ptptois(req, res) { + function handle_PUT_ptptois( + req: { p: { zid: any; uid?: any; pid: any; mod: any } }, + res: { + status: ( + arg0: number + ) => { (): any; new (): any; json: { (arg0: {}): void; new (): any } }; + } + ) { let zid = req.p.zid; let uid = req.p.uid; let pid = req.p.pid; let mod = req.p.mod; isModerator(zid, uid) - .then(function (isMod) { + .then(function (isMod: any) { if (!isMod) { fail(res, 403, "polis_err_ptptoi_permissions_123"); return; @@ -11429,23 +14076,30 @@ Thanks for using Polis! res.status(200).json({}); }); }) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_ptptoi_misc_234", err); }); } - function handle_GET_ptptois(req, res) { + function handle_GET_ptptois( + req: { p: { zid: any; mod: any; uid?: any; conversation_id: any } }, + res: { + status: ( + arg0: number + ) => { (): any; new (): any; json: { (arg0: any): void; new (): any } }; + } + ) { let zid = req.p.zid; let mod = req.p.mod; let uid = req.p.uid; let limit = 99999; let convPromise = getConversationInfo(req.p.zid); - let socialPtptsPromise = convPromise.then((conv) => { + let socialPtptsPromise = convPromise.then((conv: { owner: any }) => { return getSocialParticipantsForMod_timed(zid, limit, mod, conv.owner); }); Promise.all([socialPtptsPromise, getConversationInfo(zid)]) - .then(function (a) { + .then(function (a: any[]) { let ptptois = a[0]; let conv = a[1]; let isOwner = uid === conv.owner; @@ -11454,7 +14108,7 @@ Thanks for using Polis! ptptois = ptptois.map(pullXInfoIntoSubObjects); ptptois = ptptois.map(removeNullOrUndefinedProperties); ptptois = ptptois.map(pullFbTwIntoSubObjects); - ptptois = ptptois.map(function (p) { + ptptois = ptptois.map(function (p: { conversation_id: any }) { p.conversation_id = req.p.conversation_id; return p; }); @@ -11463,41 +14117,55 @@ Thanks for using Polis! } res.status(200).json(ptptois); }) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_ptptoi_misc", err); }); } - function handle_GET_votes_famous(req, res) { + function handle_GET_votes_famous( + req: { p: any }, + res: { + status: ( + arg0: number + ) => { (): any; new (): any; json: { (arg0: any): void; new (): any } }; + } + ) { doFamousQuery(req.p, req) .then( - function (data) { + function (data: any) { res.status(200).json(data); }, - function (err) { + function (err: any) { fail(res, 500, "polis_err_famous_proj_get2", err); } ) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_famous_proj_get1", err); }); } - function doFamousQuery(o, req) { - let uid = o.uid; - let zid = o.zid; - let math_tick = o.math_tick; + function doFamousQuery( + o?: { uid?: any; zid: any; math_tick: any; ptptoiLimit: any }, + req?: any + ) { + let uid = o?.uid; + let zid = o?.zid; + let math_tick = o?.math_tick; // NOTE: if this API is running slow, it's probably because fetching the PCA from pg is slow, and PCA caching is disabled // let twitterLimit = 999; // we can actually check a lot of these, since they might be among the fb users // let softLimit = 26; - let hardLimit = _.isUndefined(o.ptptoiLimit) ? 30 : o.ptptoiLimit; + let hardLimit = _.isUndefined(o?.ptptoiLimit) ? 30 : o?.ptptoiLimit; // let ALLOW_NON_FRIENDS_WHEN_EMPTY_SOCIAL_RESULT = true; let mod = 0; // for now, assume all conversations will show unmoderated and approved participants. function getAuthorUidsOfFeaturedComments() { - return getPca(zid, 0).then(function (pcaData) { + return getPca(zid, 0).then(function (pcaData: { + asPOJO: any; + consensus: { agree?: any; disagree?: any }; + repness: { [x: string]: any }; + }) { if (!pcaData) { return []; } @@ -11510,9 +14178,12 @@ Thanks for using Polis! _.pluck(pcaData.consensus.disagree, "tid") ); - let groupTids = []; + let groupTids: never[] = []; for (var gid in pcaData.repness) { let commentData = pcaData.repness[gid]; + // Type 'any[]' is not assignable to type 'never[]'. + // Type 'any' is not assignable to type 'never'.ts(2322) + // @ts-ignore groupTids = _.union(groupTids, _.pluck(commentData, "tid")); } let featuredTids = _.union(consensusTids, groupTids); @@ -11534,7 +14205,7 @@ Thanks for using Polis! "select authors.uid from authors inner join xids on xids.uid = authors.uid " + "order by uid;"; - return pgQueryP_readOnly(q, [zid]).then(function (comments) { + return pgQueryP_readOnly(q, [zid]).then(function (comments: any) { let uids = _.pluck(comments, "uid"); console.log("famous uids", uids); @@ -11546,7 +14217,7 @@ Thanks for using Polis! return Promise.all([ getConversationInfo(zid), getAuthorUidsOfFeaturedComments(), - ]).then(function (a) { + ]).then(function (a: any[]) { let conv = a[0]; let authorUids = a[1]; @@ -11560,7 +14231,7 @@ Thanks for using Polis! // getTwitterUsersInConversation(zid, uid, twitterLimit), // getPolisSocialSettings(zid, uid), // getPidPromise(zid, uid), - ]).then(function (stuff) { + ]).then(function (stuff: never[][]) { // // if we didn't find any FB friends or Twitter users, find some that aren't friends // // This may or may not be the right thing to do, but the reasoning is that it will help people understand what Polis is. Empty buckets will be confusing. // let facebookFriends = stuff[0] || []; @@ -11577,7 +14248,7 @@ Thanks for using Polis! // } // }).then(function(stuff) { - let participantsWithSocialInfo = stuff[0] || []; + let participantsWithSocialInfo: any[] = stuff[0] || []; // let facebookFriends = stuff[0] || []; // let twitterParticipants = stuff[1] || []; // let polisSocialSettings = stuff[2] || []; @@ -11607,30 +14278,30 @@ Thanks for using Polis! // ALSO, we could return data on everyone who might appear in the list view, and add an "importance" score to help determine who to show in the vis at various screen sizes. (a client determination) // ALSO, per-group-minimums: we should include at least a facebook friend and at least one famous twitter user(if they exist) per group - participantsWithSocialInfo = participantsWithSocialInfo.map(function ( - p - ) { - let x = pullXInfoIntoSubObjects(p); - // nest the fb and tw properties in sub objects - x = pullFbTwIntoSubObjects(x); + participantsWithSocialInfo = participantsWithSocialInfo.map( + function (p: { priority: number }) { + let x = pullXInfoIntoSubObjects(p); + // nest the fb and tw properties in sub objects + x = pullFbTwIntoSubObjects(x); - if (p.priority === 1000) { - x.isSelf = true; - } - if (x.twitter) { - x.twitter.profile_image_url_https = - getServerNameWithProtocol(req) + - "/twitter_image?id=" + - x.twitter.twitter_user_id; + if (p.priority === 1000) { + x.isSelf = true; + } + if (x.twitter) { + x.twitter.profile_image_url_https = + getServerNameWithProtocol(req) + + "/twitter_image?id=" + + x.twitter.twitter_user_id; + } + // // don't include FB info to non-friends + // if (!x.is_fb_friend && !x.isSelf) { + // delete x.facebook; + // } + return x; } - // // don't include FB info to non-friends - // if (!x.is_fb_friend && !x.isSelf) { - // delete x.facebook; - // } - return x; - }); + ); - let pids = participantsWithSocialInfo.map(function (p) { + let pids = participantsWithSocialInfo.map(function (p: { pid: any }) { return p.pid; }); console.log("mike1234", pids.length); @@ -11687,7 +14358,7 @@ Thanks for using Polis! // } // pidToData[myPid]= pidToData[myPid] || {}; - pids.sort(function (a, b) { + pids.sort(function (a: number, b: number) { return a - b; }); pids = _.uniq(pids, true); @@ -11695,30 +14366,33 @@ Thanks for using Polis! console.log("mike12346", pids); return getVotesForZidPidsWithTimestampCheck(zid, pids, math_tick).then( - function (vectors) { + function (vectors: any) { // TODO parallelize with above query return getBidsForPids(zid, -1, pids).then( - function (pidsToBids) { - _.each(vectors, function (value, pid, list) { - pid = parseInt(pid); - let bid = pidsToBids[pid]; - let notInBucket = _.isUndefined(bid); - let isSelf = pidToData[pid].isSelf; - // winston.log("info","pidToData", pid, myPid, isSelf); - // winston.log("info",pidToData[pid]); - if (notInBucket && !isSelf) { - // pidToData[pid].ignore = true; - console.log("mike12347", "deleting", pid); - delete pidToData[pid]; // if the participant isn't in a bucket, they probably haven't voted enough for the math worker to bucketize them. - } else if (!!pidToData[pid]) { - console.log("mike12348", "keeping", pid); - pidToData[pid].votes = value; // no separator, like this "adupuuauuauupuuu"; - pidToData[pid].bid = bid; + function (pidsToBids: { [x: string]: any }) { + _.each( + vectors, + function (value: any, pid: string | number, list: any) { + pid = parseInt(pid as string); + let bid = pidsToBids[pid]; + let notInBucket = _.isUndefined(bid); + let isSelf = pidToData[pid].isSelf; + // winston.log("info","pidToData", pid, myPid, isSelf); + // winston.log("info",pidToData[pid]); + if (notInBucket && !isSelf) { + // pidToData[pid].ignore = true; + console.log("mike12347", "deleting", pid); + delete pidToData[pid]; // if the participant isn't in a bucket, they probably haven't voted enough for the math worker to bucketize them. + } else if (!!pidToData[pid]) { + console.log("mike12348", "keeping", pid); + pidToData[pid].votes = value; // no separator, like this "adupuuauuauupuuu"; + pidToData[pid].bid = bid; + } } - }); + ); return pidToData; }, - function (err) { + function (err: any) { // looks like there is no pca yet, so nothing to return. return {}; } @@ -11729,7 +14403,14 @@ Thanks for using Polis! }); } // end doFamousQuery - function handle_GET_twitter_users(req, res) { + function handle_GET_twitter_users( + req: { p: { uid?: any; twitter_user_id: any } }, + res: { + status: ( + arg0: number + ) => { (): any; new (): any; json: { (arg0: any): void; new (): any } }; + } + ) { let uid = req.p.uid; let p; if (uid) { @@ -11745,24 +14426,24 @@ Thanks for using Polis! fail(res, 401, "polis_err_missing_uid_or_twitter_user_id"); return; } - p.then(function (data) { + p.then(function (data: any) { data = data[0]; data.profile_image_url_https = getServerNameWithProtocol(req) + "/twitter_image?id=" + data.twitter_user_id; res.status(200).json(data); - }).catch(function (err) { + }).catch(function (err: any) { fail(res, 500, "polis_err_twitter_user_info_get", err); }); } - function doSendEinvite(req, email) { - return generateTokenP(30, false).then(function (einvite) { + function doSendEinvite(req: any, email: any) { + return generateTokenP(30, false).then(function (einvite: any) { return pgQueryP( "insert into einvites (email, einvite) values ($1, $2);", [email, einvite] - ).then(function (rows) { + ).then(function (rows: any) { return sendEinviteEmail(req, email, einvite); }); }); @@ -11785,8 +14466,20 @@ CREATE TABLE slack_user_invites ( ); */ - function handle_GET_slack_login(req, res) { - function finish(uid) { + function handle_GET_slack_login( + req: { p: { uid?: any }; path: string }, + res: { + set: (arg0: { "Content-Type": string }) => void; + status: ( + arg0: number + ) => { + (): any; + new (): any; + send: { (arg0: string): void; new (): any }; + }; + } + ) { + function finish(uid?: any) { startSessionAndAddCookies(req, res, uid) .then(function () { res.set({ @@ -11803,18 +14496,23 @@ CREATE TABLE slack_user_invites ( ""; res.status(200).send(html); }) - .catch((err) => { + .catch((err: any) => { fail(res, 500, "polis_err_slack_login_session_start", err); }); } const existing_uid_for_client = req.p.uid; - const token = /\/slack_login_code\/([^\/]*)/.exec(req.path)[1]; + const token = /\/slack_login_code\/([^\/]*)/.exec(req.path)?.[1]; pgQueryP("select * from slack_user_invites where token = ($1);", [ token, ]).then( - (rows) => { + // Argument of type '(rows: string | any[]) => void' is not assignable to parameter of type '(value: unknown) => void | PromiseLike'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + (rows: string | any[]) => { if (!rows || !rows.length) { fail(res, 500, "polis_err_slack_login_unknown_token " + token); return; @@ -11830,27 +14528,32 @@ CREATE TABLE slack_user_invites ( "select * from slack_users where slack_team = ($1) and slack_user_id = ($2);", [slack_team, slack_user_id] ).then( - (rows) => { + // Argument of type '(rows: string | any[]) => void' is not assignable to parameter of type '(value: unknown) => void | PromiseLike'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + (rows: string | any[]) => { if (!rows || !rows.length) { // create new user (or use existing user) and associate a new slack_user entry const uidPromise = existing_uid_for_client ? Promise.resolve(existing_uid_for_client) : createDummyUser(); uidPromise - .then((uid) => { + .then((uid?: any) => { return pgQueryP( "insert into slack_users (uid, slack_team, slack_user_id) values ($1, $2, $3);", [uid, slack_team, slack_user_id] ).then( - (rows) => { + (rows: any) => { finish(uid); }, - function (err) { + function (err: any) { fail(res, 500, "polis_err_slack_login_03", err); } ); }) - .catch((err) => { + .catch((err: any) => { fail(res, 500, "polis_err_slack_login_02", err); }); } else { @@ -11858,20 +14561,50 @@ CREATE TABLE slack_user_invites ( finish(rows[0].uid); } }, - (err) => { + (err: any) => { fail(res, 500, "polis_err_slack_login_01", err); } ); }, - (err) => { + (err: any) => { fail(res, 500, "polis_err_slack_login_misc", err); } ); } - function postMessageUsingHttp(o) { - return new Promise(function (resolve, reject) { - web.chat.postMessage(o.channel, o.text, o, (err, info) => { + function postMessageUsingHttp(o: { + channel: any; + team?: any; + text: any; + attachments?: { + text: number; + fallback: string; + callback_id: string; + color: string; + attachment_type: string; + actions: ( + | { name: string; text: string; type: string; value: string } + | { + name: string; + text: string; + style: string; + type: string; + value: string; + confirm: { + title: string; + text: string; + ok_text: string; + dismiss_text: string; + }; + } + )[]; + }[]; + }) { + return new Promise(function ( + resolve: (arg0: any) => void, + reject: (arg0: any) => void + ) { + web.chat.postMessage(o.channel, o.text, o, (err: any, info: any) => { if (err) { reject(err); } else { @@ -11880,7 +14613,18 @@ CREATE TABLE slack_user_invites ( }); }); } - function handle_POST_slack_interactive_messages(req, res) { + function handle_POST_slack_interactive_messages( + req: { p: { payload: string } }, + res: { + status: ( + arg0: number + ) => { + (): any; + new (): any; + send: { (arg0: string): void; new (): any }; + }; + } + ) { const payload = JSON.parse(req.p.payload); // const attachments = payload.attachments; @@ -11941,42 +14685,58 @@ CREATE TABLE slack_user_invites ( }, ], }) - .then((result) => { + .then((result: any) => { // console.dir(req.p); res.status(200).send(""); }) - .catch((err) => { + .catch((err: any) => { fail(res, 500, "polis_err_slack_interactive_messages_000", err); }); } - function handle_POST_slack_user_invites(req, res) { + function handle_POST_slack_user_invites( + req: { p: { slack_team: any; slack_user_id: any } }, + res: { json: (arg0: { url: string }) => void } + ) { const slack_team = req.p.slack_team; const slack_user_id = req.p.slack_user_id; - generateTokenP(99, false).then(function (token) { - pgQueryP( - "insert into slack_user_invites (slack_team, slack_user_id, token) values ($1, $2, $3);", - [slack_team, slack_user_id, token] - ).then( - (rows) => { - res.json({ - url: getServerNameWithProtocol(req) + "/slack_login_code/" + token, - }); - }, - (err) => { - fail(res, 500, "polis_err_creating_slack_user_invite", err); - } - ); - }); + generateTokenP(99, false) + // Argument of type '(token: string) => void' is not assignable to parameter of type '(value: unknown) => void | PromiseLike'. + // Types of parameters 'token' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string'.ts(2345) + // @ts-ignore + .then(function (token: string) { + pgQueryP( + "insert into slack_user_invites (slack_team, slack_user_id, token) values ($1, $2, $3);", + [slack_team, slack_user_id, token] + ).then( + (rows: any) => { + res.json({ + url: + getServerNameWithProtocol(req) + "/slack_login_code/" + token, + }); + }, + (err: any) => { + fail(res, 500, "polis_err_creating_slack_user_invite", err); + } + ); + }); } - function handle_POST_einvites(req, res) { + function handle_POST_einvites( + req: { p: { email: any } }, + res: { + status: ( + arg0: number + ) => { (): any; new (): any; json: { (arg0: {}): void; new (): any } }; + } + ) { let email = req.p.email; doSendEinvite(req, email) .then(function () { res.status(200).json({}); }) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_sending_einvite", err); }); } @@ -11996,24 +14756,48 @@ CREATE TABLE slack_user_invites ( // .pipe(res); // } - function handle_GET_einvites(req, res) { + function handle_GET_einvites( + req: { p: { einvite: any } }, + res: { + status: ( + arg0: number + ) => { (): any; new (): any; json: { (arg0: any): void; new (): any } }; + } + ) { let einvite = req.p.einvite; winston.log("info", "select * from einvites where einvite = ($1);", [ einvite, ]); pgQueryP("select * from einvites where einvite = ($1);", [einvite]) - .then(function (rows) { + // Argument of type '(rows: string | any[]) => void' is not assignable to parameter of type '(value: unknown) => void | PromiseLike'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + .then(function (rows: string | any[]) { if (!rows.length) { throw new Error("polis_err_missing_einvite"); } res.status(200).json(rows[0]); }) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_fetching_einvite", err); }); } - function handle_POST_contributors(req, res) { + function handle_POST_contributors( + req: { + p: { + uid: null; + agreement_version: any; + name: any; + email: any; + github_id: any; + company_name: any; + }; + }, + res: { json: (arg0: {}) => void } + ) { const uid = req.p.uid || null; const agreement_version = req.p.agreement_version; const name = req.p.name; @@ -12036,22 +14820,31 @@ CREATE TABLE slack_user_invites ( res.json({}); }, - (err) => { + (err: any) => { fail(res, 500, "polis_err_POST_contributors_misc", err); } ); } - function handle_POST_waitinglist(req, res) { - let intercom_lead_user_id; + function handle_POST_waitinglist( + req: { + p: { campaign: any; affiliation: any; role: any; email: any; name: any }; + }, + res: { json: (arg0: {}) => void } + ) { + let intercom_lead_user_id: any; intercomClient.leads + // This expression is not callable. + // Not all constituents of type 'Bluebird<{ body?: { user_id: string; } | undefined; }> | { (lead: Partial): Promise>; (lead: Partial, cb: callback<...>): void; }' are callable. + // Type 'Bluebird<{ body?: { user_id: string; } | undefined; }>' has no call signatures.ts(2349) + // @ts-ignore .create() - .then((x) => { + .then((x: { body: { user_id: any } }) => { intercom_lead_user_id = x.body.user_id; return intercom_lead_user_id; }) .then(() => { - var custom = { + const custom: { [key: string]: string } = { campaign: req.p.campaign, }; if (req.p.affiliation) { @@ -12060,13 +14853,20 @@ CREATE TABLE slack_user_invites ( if (req.p.role) { custom.role = req.p.role; } - return intercomClient.leads.update({ - user_id: intercom_lead_user_id, - email: req.p.email, - last_request_at: Date.now(), - name: req.p.name, - custom_attributes: custom, - }); + return ( + intercomClient.leads + // This expression is not callable. + // Not all constituents of type 'Bluebird<{ body?: { user_id: string; } | undefined; }> | { (lead: UserIdentifier & Partial): Promise>; (lead: UserIdentifier & Partial<...>, cb: callback<...>): void; }' are callable. + // Type 'Bluebird<{ body?: { user_id: string; } | undefined; }>' has no call signatures.ts(2349) + // @ts-ignore + .update({ + user_id: intercom_lead_user_id, + email: req.p.email, + last_request_at: Date.now(), + name: req.p.name, + custom_attributes: custom, + }) + ); }) .then(() => { return pgQueryP( @@ -12084,11 +14884,15 @@ CREATE TABLE slack_user_invites ( .then(() => { res.json({}); }) - .catch((err) => { + .catch((err: any) => { fail(res, 500, "polis_err_POST_waitinglist", err); }); } - function generateSingleUseUrl(req, conversation_id, suzinvite) { + function generateSingleUseUrl( + req: any, + conversation_id: string, + suzinvite: string + ) { return ( getServerNameWithProtocol(req) + "/ot/" + @@ -12097,44 +14901,49 @@ CREATE TABLE slack_user_invites ( suzinvite ); } - function buildConversationUrl(req, zinvite) { + function buildConversationUrl(req: any, zinvite: string | null) { return getServerNameWithProtocol(req) + "/" + zinvite; } - function buildConversationDemoUrl(req, zinvite) { + function buildConversationDemoUrl(req: any, zinvite: string) { return getServerNameWithProtocol(req) + "/demo/" + zinvite; } - function buildModerationUrl(req, zinvite) { + function buildModerationUrl(req: any, zinvite: string) { return getServerNameWithProtocol(req) + "/m/" + zinvite; } - function buildSeedUrl(req, zinvite) { + function buildSeedUrl(req: any, zinvite: any) { return buildModerationUrl(req, zinvite) + "/comments/seed"; } - function getConversationUrl(req, zid, dontUseCache) { - return getZinvite(zid, dontUseCache).then(function (zinvite) { + function getConversationUrl(req: any, zid: any, dontUseCache: boolean) { + return getZinvite(zid, dontUseCache).then(function (zinvite: any) { return buildConversationUrl(req, zinvite); }); } - function createOneSuzinvite(xid, zid, owner, generateSingleUseUrl) { - return generateSUZinvites(1).then(function (suzinviteArray) { + function createOneSuzinvite( + xid: any, + zid: any, + owner: any, + generateSingleUseUrl: (arg0: any, arg1: any) => any + ) { + return generateSUZinvites(1).then(function (suzinviteArray: any[]) { let suzinvite = suzinviteArray[0]; return pgQueryP( "INSERT INTO suzinvites (suzinvite, xid, zid, owner) VALUES ($1, $2, $3, $4);", [suzinvite, xid, zid, owner] ) - .then(function (result) { + .then(function (result: any) { return getZinvite(zid); }) - .then(function (conversation_id) { + .then(function (conversation_id: any) { return { zid: zid, conversation_id: conversation_id, }; }) - .then(function (o) { + .then(function (o: { zid: any; conversation_id: any }) { return { zid: o.zid, conversation_id: o.conversation_id, @@ -12144,7 +14953,22 @@ CREATE TABLE slack_user_invites ( }); } - function renderLtiLinkagePage(req, res, afterJoinRedirectUrl) { + function renderLtiLinkagePage( + req: { + p: UserType; + }, + res: { + set: (arg0: { "Content-Type": string }) => void; + status: ( + arg0: number + ) => { + (): any; + new (): any; + send: { (arg0: string): void; new (): any }; + }; + }, + afterJoinRedirectUrl?: string + ) { let context_id = req.p.context_id; let user_id = req.p.user_id; let user_image = req.p.user_image; @@ -12317,7 +15141,18 @@ CREATE TABLE slack_user_invites ( // TODO rename to LTI/launch // TODO save launch contexts in mongo. For now, to err on the side of collecting extra data, let them be duplicated. Attach a timestamp too. // TODO return HTML from the auth functions. the html should contain the token? so that ajax calls can be made. - function handle_POST_lti_setup_assignment(req, res) { + function handle_POST_lti_setup_assignment( + req: { + p: { + user_id: any; + context_id: any; + tool_consumer_instance_guid?: any; + lis_outcome_service_url: any; + uid?: any; + }; + }, + res: any + ) { winston.log("info", req); // let roles = req.p.roles; // let isInstructor = /[iI]nstructor/.exec(roles); // others: Learner @@ -12352,10 +15187,10 @@ CREATE TABLE slack_user_invites ( "select * from lti_users left join users on lti_users.uid = users.uid where lti_user_id = ($1);", [user_id] ) - .then(function (rows) { + .then(function (rows: any) { // find the correct one - note: this loop may be useful in warning when people have multiple linkages - let userForLtiUserId = null; - (rows || []).forEach(function (row) { + let userForLtiUserId: any = null; + (rows || []).forEach(function (row: { uid?: any }) { if (row.uid === req.p.uid) { userForLtiUserId = row; } @@ -12366,6 +15201,9 @@ CREATE TABLE slack_user_invites ( // } else { // if (you paid) { User.renderLtiLinkageSuccessPage(req, res, { + // Argument of type '{ context_id: any; email: any; }' is not assignable to parameter of type '{ email: string; }'. + // Object literal may only specify known properties, and 'context_id' does not exist in type '{ email: string; }'.ts(2345) + // @ts-ignore context_id: context_id, // user_image: userForLtiUserId.user_image, email: userForLtiUserId.email, @@ -12384,7 +15222,7 @@ CREATE TABLE slack_user_invites ( renderLtiLinkagePage(req, res); } }) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_launching_lti_finding_user", err); }); } else { @@ -12394,7 +15232,7 @@ CREATE TABLE slack_user_invites ( renderLtiLinkagePage(req, res); } }) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_launching_lti_save", err); }); } // end /api/v3/LTI/setup_assignment @@ -12463,37 +15301,45 @@ CREATE TABLE slack_user_invites ( // } // end /api/v3/LTI/canvas_nav function addCanvasAssignmentConversationInfoIfNeeded( - zid, - tool_consumer_instance_guid, - lti_context_id, - custom_canvas_assignment_id - ) { - return getCanvasAssignmentInfo( - tool_consumer_instance_guid, - lti_context_id, - custom_canvas_assignment_id - ).then(function (rows) { - let exists = rows && rows.length; - if (exists) { - return exists; - } else { - return pgQueryP( - "insert into canvas_assignment_conversation_info (zid, tool_consumer_instance_guid, lti_context_id, custom_canvas_assignment_id) values ($1, $2, $3, $4);", - [ - zid, - tool_consumer_instance_guid, - lti_context_id, - custom_canvas_assignment_id, - ] - ); - } - }); + zid: any, + tool_consumer_instance_guid?: any, + lti_context_id?: any, + custom_canvas_assignment_id?: any + ) { + return ( + getCanvasAssignmentInfo( + tool_consumer_instance_guid, + lti_context_id, + custom_canvas_assignment_id + ) + // Argument of type '(rows: string | any[]) => number | Promise' is not assignable to parameter of type '(value: unknown) => unknown'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + .then(function (rows: string | any[]) { + let exists = rows && rows.length; + if (exists) { + return exists; + } else { + return pgQueryP( + "insert into canvas_assignment_conversation_info (zid, tool_consumer_instance_guid, lti_context_id, custom_canvas_assignment_id) values ($1, $2, $3, $4);", + [ + zid, + tool_consumer_instance_guid, + lti_context_id, + custom_canvas_assignment_id, + ] + ); + } + }) + ); } function getCanvasAssignmentInfo( - tool_consumer_instance_guid, - lti_context_id, - custom_canvas_assignment_id + tool_consumer_instance_guid: string, + lti_context_id: string, + custom_canvas_assignment_id: string ) { winston.log( "info", @@ -12512,58 +15358,66 @@ CREATE TABLE slack_user_invites ( } function addCanvasAssignmentConversationCallbackParamsIfNeeded( - lti_user_id, - lti_context_id, - custom_canvas_assignment_id, - tool_consumer_instance_guid, - lis_outcome_service_url, - lis_result_sourcedid, - stringified_json_of_post_content - ) { - return getCanvasAssignmentConversationCallbackParams( - lti_user_id, - lti_context_id, - custom_canvas_assignment_id, - tool_consumer_instance_guid - ).then(function (rows) { - if (rows && rows.length) { - // update - // this is failing, but it has been ok, since the insert worked (i assume) - return pgQueryP( - "update canvas_assignment_callback_info set lis_outcome_service_url = ($5), lis_result_sourcedid = ($6), stringified_json_of_post_content = ($7) where lti_user_id = ($1) and lti_context_id = ($2) and custom_canvas_assignment_id = ($3) and tool_consumer_instance_guid = ($4);", - [ - lti_user_id, - lti_context_id, - custom_canvas_assignment_id, - tool_consumer_instance_guid, - lis_outcome_service_url, - lis_result_sourcedid, - stringified_json_of_post_content, - ] - ); - } else { - // insert - return pgQueryP( - "insert into canvas_assignment_callback_info (lti_user_id, lti_context_id, custom_canvas_assignment_id, tool_consumer_instance_guid, lis_outcome_service_url, lis_result_sourcedid, stringified_json_of_post_content) values ($1, $2, $3, $4, $5, $6, $7);", - [ - lti_user_id, - lti_context_id, - custom_canvas_assignment_id, - tool_consumer_instance_guid, - lis_outcome_service_url, - lis_result_sourcedid, - stringified_json_of_post_content, - ] - ); - } - }); + lti_user_id: any, + lti_context_id: any, + custom_canvas_assignment_id: any, + tool_consumer_instance_guid?: any, + lis_outcome_service_url?: any, + lis_result_sourcedid?: any, + stringified_json_of_post_content?: string + ) { + return ( + getCanvasAssignmentConversationCallbackParams( + lti_user_id, + lti_context_id, + custom_canvas_assignment_id, + tool_consumer_instance_guid + ) + // Argument of type '(rows: string | any[]) => Promise' is not assignable to parameter of type '(value: unknown) => unknown'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + .then(function (rows: string | any[]) { + if (rows && rows.length) { + // update + // this is failing, but it has been ok, since the insert worked (i assume) + return pgQueryP( + "update canvas_assignment_callback_info set lis_outcome_service_url = ($5), lis_result_sourcedid = ($6), stringified_json_of_post_content = ($7) where lti_user_id = ($1) and lti_context_id = ($2) and custom_canvas_assignment_id = ($3) and tool_consumer_instance_guid = ($4);", + [ + lti_user_id, + lti_context_id, + custom_canvas_assignment_id, + tool_consumer_instance_guid, + lis_outcome_service_url, + lis_result_sourcedid, + stringified_json_of_post_content, + ] + ); + } else { + // insert + return pgQueryP( + "insert into canvas_assignment_callback_info (lti_user_id, lti_context_id, custom_canvas_assignment_id, tool_consumer_instance_guid, lis_outcome_service_url, lis_result_sourcedid, stringified_json_of_post_content) values ($1, $2, $3, $4, $5, $6, $7);", + [ + lti_user_id, + lti_context_id, + custom_canvas_assignment_id, + tool_consumer_instance_guid, + lis_outcome_service_url, + lis_result_sourcedid, + stringified_json_of_post_content, + ] + ); + } + }) + ); } function getCanvasAssignmentConversationCallbackParams( - lti_user_id, - lti_context_id, - custom_canvas_assignment_id, - tool_consumer_instance_guid + lti_user_id: any, + lti_context_id: any, + custom_canvas_assignment_id: any, + tool_consumer_instance_guid?: any ) { return pgQueryP( "select * from canvas_assignment_callback_info where lti_user_id = ($1) and lti_context_id = ($2) and custom_canvas_assignment_id = ($3) and tool_consumer_instance_guid = ($4);", @@ -12575,7 +15429,26 @@ CREATE TABLE slack_user_invites ( ] ); } - function handle_POST_lti_conversation_assignment(req, res) { + function handle_POST_lti_conversation_assignment( + req: { + p: { + roles: any; + user_id: any; + context_id: any; + tool_consumer_instance_guid?: any; + lis_result_sourcedid: any; + custom_canvas_assignment_id: any; + lis_outcome_service_url: any; + oauth_consumer_key: string; + }; + body: any; + }, + res: { + redirect: (arg0: string) => void; + set: (arg0: { "Content-Type": string }) => void; + send: (arg0: string) => void; + } + ) { let roles = req.p.roles; let isInstructor = /[iI]nstructor/.exec(roles); // others: Learner // let isLearner = /[lL]earner/.exec(roles); @@ -12590,20 +15463,28 @@ CREATE TABLE slack_user_invites ( // let oauth_consumer_key = req.p.oauth_consumer_key; function getPolisUserForLtiUser() { - return pgQueryP( - "select * from lti_users left join users on lti_users.uid = users.uid where lti_users.lti_user_id = ($1) and lti_users.tool_consumer_instance_guid = ($2);", - [user_id, req.p.tool_consumer_instance_guid] - ).then(function (rows) { - let userForLtiUserId = null; - if (rows.length) { - userForLtiUserId = rows[0]; - winston.log( - "info", - "got user for lti_user_id:" + JSON.stringify(userForLtiUserId) - ); - } - return userForLtiUserId; - }); + return ( + pgQueryP( + "select * from lti_users left join users on lti_users.uid = users.uid where lti_users.lti_user_id = ($1) and lti_users.tool_consumer_instance_guid = ($2);", + [user_id, req.p.tool_consumer_instance_guid] + ) + // Argument of type '(rows: string | any[]) => any' is not assignable to parameter of type '(value: unknown) => any'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + .then(function (rows: string | any[]) { + let userForLtiUserId = null; + if (rows.length) { + userForLtiUserId = rows[0]; + winston.log( + "info", + "got user for lti_user_id:" + JSON.stringify(userForLtiUserId) + ); + } + return userForLtiUserId; + }) + ); } if (req.p.lis_result_sourcedid) { @@ -12619,14 +15500,14 @@ CREATE TABLE slack_user_invites ( .then(function () { winston.log("info", "grading info added"); }) - .catch(function (err) { + .catch(function (err: any) { winston.log("info", "grading info error "); winston.log("info", err); }); } - function constructConversationUrl(zid) { + function constructConversationUrl(zid: any) { // sweet! the instructor has created the conversation. send students here. (instructors too) - return getZinvite(zid).then(function (zinvite) { + return getZinvite(zid).then(function (zinvite: string) { return ( getServerNameWithProtocol(req) + "/" + @@ -12662,7 +15543,7 @@ CREATE TABLE slack_user_invites ( ), getPolisUserForLtiUser(), ]) - .then(function (results) { + .then(function (results: any[]) { let infos = results[0]; let exists = infos && infos.length; let info = infos[0]; @@ -12671,7 +15552,7 @@ CREATE TABLE slack_user_invites ( if (exists) { return constructConversationUrl(info.zid) - .then(function (url) { + .then(function (url: any) { if (user) { // we're in business, user can join the conversation res.redirect(url); @@ -12685,10 +15566,21 @@ CREATE TABLE slack_user_invites ( winston.log("info", "lti_linkage didnt exist"); // Have them sign in again, since they weren't linked. // NOTE: this could be streamlined by showing a sign-in page that also says "you are signed in as foo, link account foo? OR sign in as someone else" + // + // (parameter) res: { + // redirect: (arg0: string) => void; + // set: (arg0: { + // "Content-Type": string; + // }) => void; + // send: (arg0: string) => void; + // } + // Argument of type '{ redirect: (arg0: string) => void; set: (arg0: { "Content-Type": string; }) => void; send: (arg0: string) => void; }' is not assignable to parameter of type '{ set: (arg0: { "Content-Type": string; }) => void; status: (arg0: number) => { (): any; new (): any; send: { (arg0: string): void; new (): any; }; }; }'.ts(2345) + // + // @ts-ignore renderLtiLinkagePage(req, res, url); } }) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_lti_generating_conversation_url", err); }); } else { @@ -12724,6 +15616,9 @@ CREATE TABLE slack_user_invites ( custom_canvas_assignment_id: req.p.custom_canvas_assignment_id, }); + // Argument of type '{ redirect: (arg0: string) => void; set: (arg0: { "Content-Type": string; }) => void; send: (arg0: string) => void; }' is not assignable to parameter of type '{ set: (arg0: { "Content-Type": string; }) => void; status: (arg0: number) => { (): any; new (): any; send: { (arg0: string): void; new (): any; }; }; }'. + // Property 'status' is missing in type '{ redirect: (arg0: string) => void; set: (arg0: { "Content-Type": string; }) => void; send: (arg0: string) => void; }' but required in type '{ set: (arg0: { "Content-Type": string; }) => void; status: (arg0: number) => { (): any; new (): any; send: { (arg0: string): void; new (): any; }; }; }'.ts(2345) + // @ts-ignore renderLtiLinkagePage(req, res, url); } } else { @@ -12747,7 +15642,7 @@ CREATE TABLE slack_user_invites ( } } }) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_checking_grading_context", err); }); @@ -12773,7 +15668,19 @@ CREATE TABLE slack_user_invites ( // wait! how do we know what the conversation should have for topic / description? } - function handle_GET_setup_assignment_xml(req, res) { + function handle_GET_setup_assignment_xml( + req: any, + res: { + set: (arg0: string, arg1: string) => void; + status: ( + arg0: number + ) => { + (): any; + new (): any; + send: { (arg0: string): void; new (): any }; + }; + } + ) { let xml = "" + '' + @@ -12819,7 +15726,19 @@ CREATE TABLE slack_user_invites ( res.set("Content-Type", "text/xml"); res.status(200).send(xml); } - function handle_GET_conversation_assigmnent_xml(req, res) { + function handle_GET_conversation_assigmnent_xml( + req: any, + res: { + set: (arg0: string, arg1: string) => void; + status: ( + arg0: number + ) => { + (): any; + new (): any; + send: { (arg0: string): void; new (): any }; + }; + } + ) { let serverName = getServerNameWithProtocol(req); let xml = @@ -12862,11 +15781,16 @@ CREATE TABLE slack_user_invites ( res.set("Content-Type", "text/xml"); res.status(200).send(xml); } - function handle_GET_canvas_app_instructions_png(req, res) { + function handle_GET_canvas_app_instructions_png( + req: { headers?: { [x: string]: string } }, + res: any + ) { let path = "/landerImages/"; - if (/Android/.exec(req.headers["user-agent"])) { + if (/Android/.exec(req?.headers?.["user-agent"] || "")) { path += "app_instructions_android.png"; - } else if (/iPhone.*like Mac OS X/.exec(req.headers["user-agent"])) { + } else if ( + /iPhone.*like Mac OS X/.exec(req?.headers?.["user-agent"] || "") + ) { path += "app_instructions_ios.png"; } else { path += "app_instructions_blank.png"; @@ -12874,6 +15798,9 @@ CREATE TABLE slack_user_invites ( let doFetch = makeFileFetcher(hostname, portForParticipationFiles, path, { "Content-Type": "image/png", }); + // Argument of type '{ headers?: { [x: string]: string; } | undefined; }' is not assignable to parameter of type '{ headers?: { host: any; } | undefined; path: any; pipe: (arg0: any) => void; }'. + // Type '{ headers?: { [x: string]: string; } | undefined; }' is missing the following properties from type '{ headers?: { host: any; } | undefined; path: any; pipe: (arg0: any) => void; }': path, pipets(2345) + // @ts-ignore doFetch(req, res); } @@ -12916,26 +15843,53 @@ CREATE TABLE slack_user_invites ( // }); // } - function hangle_GET_testConnection(req, res) { + function hangle_GET_testConnection( + req: any, + res: { + status: ( + arg0: number + ) => { + (): any; + new (): any; + json: { (arg0: { status: string }): void; new (): any }; + }; + } + ) { res.status(200).json({ status: "ok", }); } - function hangle_GET_testDatabase(req, res) { + function hangle_GET_testDatabase( + req: any, + res: { + status: ( + arg0: number + ) => { + (): any; + new (): any; + json: { (arg0: { status: string }): void; new (): any }; + }; + } + ) { pgQueryP("select uid from users limit 1", []).then( - (rows) => { + (rows: any) => { res.status(200).json({ status: "ok", }); }, - (err) => { + (err: any) => { fail(res, 500, "polis_err_testDatabase", err); } ); } - function sendSuzinviteEmail(req, email, conversation_id, suzinvite) { + function sendSuzinviteEmail( + req: any, + email: any, + conversation_id: string, + suzinvite: string + ) { let serverName = getServerNameWithProtocol(req); let body = "" + @@ -12960,31 +15914,42 @@ CREATE TABLE slack_user_invites ( ); } - function addInviter(inviter_uid, invited_email) { + function addInviter(inviter_uid?: any, invited_email?: any) { return pgQueryP( "insert into inviters (inviter_uid, invited_email) VALUES ($1, $2);", [inviter_uid, invited_email] ); } - function handle_POST_users_invite(req, res) { + function handle_POST_users_invite( + req: { p: { uid?: any; emails: any; zid: any; conversation_id: any } }, + res: { + status: ( + arg0: number + ) => { + (): any; + new (): any; + json: { (arg0: { status: string }): void; new (): any }; + }; + } + ) { let uid = req.p.uid; let emails = req.p.emails; let zid = req.p.zid; let conversation_id = req.p.conversation_id; getConversationInfo(zid) - .then(function (conv) { + .then(function (conv: { owner: any }) { let owner = conv.owner; // generate some tokens // add them to a table paired with user_ids // return URLs with those. generateSUZinvites(emails.length) - .then(function (suzinviteArray) { + .then(function (suzinviteArray: any) { let pairs = _.zip(emails, suzinviteArray); - let valuesStatements = pairs.map(function (pair) { + let valuesStatements = pairs.map(function (pair: any[]) { let xid = escapeLiteral(pair[0]); let suzinvite = escapeLiteral(pair[1]); let statement = @@ -12997,14 +15962,14 @@ CREATE TABLE slack_user_invites ( valuesStatements.join(",") + ";"; winston.log("info", query); - pgQuery(query, [], function (err, results) { + pgQuery(query, [], function (err: any, results: any) { if (err) { fail(res, 500, "polis_err_saving_invites", err); return; } Promise.all( - pairs.map(function (pair) { + pairs.map(function (pair: any[]) { let email = pair[0]; let suzinvite = pair[1]; return sendSuzinviteEmail( @@ -13016,7 +15981,7 @@ CREATE TABLE slack_user_invites ( function () { return addInviter(uid, email); }, - function (err) { + function (err: any) { fail(res, 500, "polis_err_sending_invite", err); } ); @@ -13027,109 +15992,137 @@ CREATE TABLE slack_user_invites ( status: ":-)", }); }) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_sending_invite", err); }); }); }) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_generating_invites", err); }); }) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_getting_conversation_info", err); }); } - function initializeImplicitConversation(site_id, page_id, o) { + function initializeImplicitConversation( + site_id: RegExpExecArray | null, + page_id: RegExpExecArray | null, + o: {} + ) { // find the user with that site_id.. wow, that will be a big index.. // I suppose we could duplicate the site_ids that actually have conversations // into a separate table, and search that first, only searching users if nothing is there. - return pgQueryP_readOnly( - "select uid from users where site_id = ($1) and site_owner = TRUE;", - [site_id] - ).then(function (rows) { - if (!rows || !rows.length) { - throw new Error("polis_err_bad_site_id"); - } - return new Promise(function (resolve, reject) { - let uid = rows[0].uid; - // create a conversation for the owner we got, - let generateShortUrl = false; - - isUserAllowedToCreateConversations(uid, function (err, isAllowed) { - if (err) { - reject(err); - return; - } - if (!isAllowed) { - reject(err); - return; + return ( + pgQueryP_readOnly( + "select uid from users where site_id = ($1) and site_owner = TRUE;", + [site_id] + ) + // Argument of type '(rows: string | any[]) => Bluebird<{ owner: any; zid: any; zinvite: any; }>' is not assignable to parameter of type '(value: unknown) => { owner: any; zid: any; zinvite: any; } | PromiseLike<{ owner: any; zid: any; zinvite: any; }>'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + .then(function (rows: string | any[]) { + if (!rows || !rows.length) { + throw new Error("polis_err_bad_site_id"); } + return new Promise(function ( + resolve: (arg0: { owner: any; zid: any; zinvite: any }) => void, + reject: (arg0: string, arg1?: undefined) => void + ) { + let uid = rows[0].uid; + // create a conversation for the owner we got, + let generateShortUrl = false; - let params = Object.assign(o, { - owner: uid, - org_id: uid, - // description: req.p.description, - is_active: true, - is_draft: false, - is_public: true, // TODO remove this column - is_anon: false, - profanity_filter: true, // TODO this could be drawn from config for the owner - spam_filter: true, // TODO this could be drawn from config for the owner - strict_moderation: false, // TODO this could be drawn from config for the owner - // context: req.p.context, - owner_sees_participation_stats: false, // TODO think, and test join - }); - - let q = sql_conversations.insert(params).returning("*").toString(); - - pgQuery(q, [], function (err, result) { - if (err) { - if (isDuplicateKey(err)) { - yell(err); - reject("polis_err_create_implicit_conv_duplicate_key"); - } else { - reject("polis_err_create_implicit_conv_db"); - } - } + isUserAllowedToCreateConversations( + uid, + function (err: any, isAllowed: any) { + if (err) { + reject(err); + return; + } + if (!isAllowed) { + reject(err); + return; + } - let zid = - result && result.rows && result.rows[0] && result.rows[0].zid; - - Promise.all([ - registerPageId(site_id, page_id, zid), - generateAndRegisterZinvite(zid, generateShortUrl), - ]) - .then(function (o) { - // let notNeeded = o[0]; - let zinvite = o[1]; - // NOTE: OK to return conversation_id, because this conversation was just created by this user. - resolve({ + let params = Object.assign(o, { owner: uid, - zid: zid, - zinvite: zinvite, + org_id: uid, + // description: req.p.description, + is_active: true, + is_draft: false, + is_public: true, // TODO remove this column + is_anon: false, + profanity_filter: true, // TODO this could be drawn from config for the owner + spam_filter: true, // TODO this could be drawn from config for the owner + strict_moderation: false, // TODO this could be drawn from config for the owner + // context: req.p.context, + owner_sees_participation_stats: false, // TODO think, and test join }); - }) - .catch(function (err) { - reject("polis_err_zinvite_create_implicit", err); - }); - }); // end insert - }); // end isUserAllowedToCreateConversations - // add a record to page_ids - // (put the site_id in the smaller site_ids table) - // redirect to the zinvite url for the conversation - }); - }); + let q = sql_conversations + .insert(params) + .returning("*") + .toString(); + + pgQuery( + q, + [], + function (err: any, result: { rows: { zid: any }[] }) { + if (err) { + if (isDuplicateKey(err)) { + yell(err); + reject("polis_err_create_implicit_conv_duplicate_key"); + } else { + reject("polis_err_create_implicit_conv_db"); + } + } + + let zid = + result && + result.rows && + result.rows[0] && + result.rows[0].zid; + + Promise.all([ + registerPageId(site_id, page_id, zid), + generateAndRegisterZinvite(zid, generateShortUrl), + ]) + .then(function (o: any[]) { + // let notNeeded = o[0]; + let zinvite = o[1]; + // NOTE: OK to return conversation_id, because this conversation was just created by this user. + resolve({ + owner: uid, + zid: zid, + zinvite: zinvite, + }); + }) + .catch(function (err: any) { + reject("polis_err_zinvite_create_implicit", err); + }); + } + ); // end insert + } + ); // end isUserAllowedToCreateConversations + + // add a record to page_ids + // (put the site_id in the smaller site_ids table) + // redirect to the zinvite url for the conversation + }); + }) + ); } function sendImplicitConversationCreatedEmails( - site_id, - page_id, - url, - modUrl, - seedUrl + site_id: string | RegExpExecArray | null, + page_id: string | RegExpExecArray | null, + url: string, + modUrl: string, + seedUrl: string ) { let body = "" + @@ -13162,7 +16155,7 @@ CREATE TABLE slack_user_invites ( return pgQueryP("select email from users where site_id = ($1)", [ site_id, - ]).then(function (rows) { + ]).then(function (rows: any) { let emails = _.pluck(rows, "email"); return sendMultipleTextEmails( @@ -13174,20 +16167,20 @@ CREATE TABLE slack_user_invites ( }); } - function registerPageId(site_id, page_id, zid) { + function registerPageId(site_id: any, page_id: any, zid: any) { return pgQueryP( "insert into page_ids (site_id, page_id, zid) values ($1, $2, $3);", [site_id, page_id, zid] ); } - function doGetConversationPreloadInfo(conversation_id) { + function doGetConversationPreloadInfo(conversation_id: any) { // return Promise.resolve({}); return Conversation.getZidFromConversationId(conversation_id) - .then(function (zid) { + .then(function (zid: any) { return Promise.all([getConversationInfo(zid)]); }) - .then(function (a) { + .then(function (a: any[]) { let conv = a[0]; let auth_opt_allow_3rdparty = ifDefinedFirstElseSecond( @@ -13233,12 +16226,19 @@ CREATE TABLE slack_user_invites ( }); } - function handle_GET_conversationPreloadInfo(req, res) { + function handle_GET_conversationPreloadInfo( + req: { p: { conversation_id: any } }, + res: { + status: ( + arg0: number + ) => { (): any; new (): any; json: { (arg0: any): void; new (): any } }; + } + ) { return doGetConversationPreloadInfo(req.p.conversation_id).then( - (conv) => { + (conv: any) => { res.status(200).json(conv); }, - (err) => { + (err: any) => { fail(res, 500, "polis_err_get_conversation_preload_info", err); } ); @@ -13252,14 +16252,52 @@ CREATE TABLE slack_user_invites ( // does not redirect, and instead serves up the index. // The routers on client and server will need to be updated for that // as will checks like isParticipationView on the client. - function handle_GET_implicit_conversation_generation(req, res) { - let site_id = /polis_site_id[^\/]*/.exec(req.path); - let page_id = /\S\/([^\/]*)/.exec(req.path); - if (!site_id.length || page_id.length < 2) { + function handle_GET_implicit_conversation_generation( + req: { + path: string; + p: { + demo: any; + ucv: any; + ucw: any; + ucsh: any; + ucst: any; + ucsd: any; + ucsv: any; + ucsf: any; + ui_lang: any; + subscribe_type: any; + xid: any; + x_name: any; + x_profile_image_url: any; + x_email: any; + parent_url: any; + dwok: any; + build: any; + show_vis: any; + bg_white: any; + show_share: any; + referrer: any; + }; + headers?: { origin: string }; + }, + res: { redirect: (arg0: string) => void } + ) { + let site_id = /polis_site_id[^\/]*/.exec(req.path) || null; + let page_id = /\S\/([^\/]*)/.exec(req.path) || null; + if (!site_id?.length || (page_id && page_id?.length < 2)) { fail(res, 404, "polis_err_parsing_site_id_or_page_id"); } - site_id = site_id[0]; - page_id = page_id[1]; + // TODO fix this after refactoring server.ts + // TODO into smaller files with one function per file + // TODO manually tracing scope is too difficult right now + // + // Type 'string | undefined' is not assignable to type 'RegExpExecArray | null'. + // Type 'undefined' is not assignable to type 'RegExpExecArray | null'.ts(2322) + // @ts-ignore + site_id = site_id?.[0]; + // Type 'string | undefined' is not assignable to type 'RegExpExecArray | null'.ts(2322) + // @ts-ignore + page_id = page_id?.[1]; let demo = req.p.demo; let ucv = req.p.ucv; @@ -13278,7 +16316,7 @@ CREATE TABLE slack_user_invites ( let parent_url = req.p.parent_url; let dwok = req.p.dwok; let build = req.p.build; - let o = {}; + let o: ConversationType = {}; ifDefinedSet("parent_url", req.p, o); ifDefinedSet("auth_needed_to_vote", req.p, o); ifDefinedSet("auth_needed_to_write", req.p, o); @@ -13295,7 +16333,7 @@ CREATE TABLE slack_user_invites ( o.socialbtn_type = req.p.show_share ? 1 : 0; // Set stuff in cookies to be retrieved when POST participants is called. let setOnPolisDomain = !domainOverride; - let origin = req.headers.origin || ""; + let origin = req?.headers?.origin || ""; if (setOnPolisDomain && origin.match(/^http:\/\/localhost:[0-9]{4}/)) { setOnPolisDomain = false; } @@ -13306,7 +16344,7 @@ CREATE TABLE slack_user_invites ( setParentUrlCookie(req, res, setOnPolisDomain, req.p.parent_url); } - function appendParams(url) { + function appendParams(url: string) { // These are needed to disambiguate postMessages from multiple polis conversations embedded on one page. url += "?site_id=" + site_id + "&page_id=" + page_id; if (!_.isUndefined(ucv)) { @@ -13366,11 +16404,20 @@ CREATE TABLE slack_user_invites ( "select * from page_ids where site_id = ($1) and page_id = ($2);", [site_id, page_id] ) - .then(function (rows) { + // Argument of type '(rows: string | any[]) => void' is not assignable to parameter of type '(value: unknown) => void | PromiseLike'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + .then(function (rows: string | any[]) { if (!rows || !rows.length) { // conv not initialized yet initializeImplicitConversation(site_id, page_id, o) - .then(function (conv) { + // Argument of type '(conv: { zinvite: any; }) => void' is not assignable to parameter of type '(value: unknown) => void | PromiseLike'. + // Types of parameters 'conv' and 'value' are incompatible. + // Type 'unknown' is not assignable to type '{ zinvite: any; }'.ts(2345) + // @ts-ignore + .then(function (conv: { zinvite: any }) { let url = _.isUndefined(demo) ? buildConversationUrl(req, conv.zinvite) : buildConversationDemoUrl(req, conv.zinvite); @@ -13386,7 +16433,7 @@ CREATE TABLE slack_user_invites ( .then(function () { winston.log("info", "email sent"); }) - .catch(function (err) { + .catch(function (err: any) { console.error("email fail"); console.error(err); }); @@ -13394,39 +16441,43 @@ CREATE TABLE slack_user_invites ( url = appendParams(url); res.redirect(url); }) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_creating_conv", err); }); } else { // conv was initialized, nothing to set up getZinvite(rows[0].zid) - .then(function (conversation_id) { + .then(function (conversation_id: any) { let url = buildConversationUrl(req, conversation_id); url = appendParams(url); res.redirect(url); }) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_finding_conversation_id", err); }); } }) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_redirecting_to_conv", err); }); } + // 'new' expression, whose target lacks a construct signature, implicitly has an 'any' type.ts(7009) + // @ts-ignore let routingProxy = new httpProxy.createProxyServer(); - function addStaticFileHeaders(res) { + function addStaticFileHeaders(res: { + setHeader: (arg0: string, arg1: string | number) => void; + }) { res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); res.setHeader("Pragma", "no-cache"); res.setHeader("Expires", 0); } - function proxy(req, res) { + function proxy(req: { headers?: { host: string }; path: any }, res: any) { let hostname = buildStaticHostname(req, res); if (!hostname) { - let host = req.headers.host || ""; + let host = req?.headers?.host || ""; let re = new RegExp(process.env.SERVICE_HOSTNAME + "$"); if (host.match(re)) { // don't alert for this, it's probably DNS related @@ -13440,7 +16491,7 @@ CREATE TABLE slack_user_invites ( } else { fail(res, 500, "polis_err_proxy_serving_to_domain", new Error(host)); } - console.error(req.headers.host); + console.error(req?.headers?.host); console.error(req.path); return; } @@ -13448,7 +16499,7 @@ CREATE TABLE slack_user_invites ( if (devMode) { addStaticFileHeaders(res); } - // if (/MSIE [^1]/.exec(req.headers['user-agent'])) { // older than 10 + // if (/MSIE [^1]/.exec(req?.headers?.['user-agent'])) { // older than 10 // // http.get(process.env.STATIC_FILES_HOST + "/unsupportedBrowser.html", function(page) { // // res.status(200).end(page); // // }).on('error', function(e) { @@ -13458,7 +16509,7 @@ CREATE TABLE slack_user_invites ( // } else { let port = process.env.STATIC_FILES_PORT; // set the host header too, since S3 will look at that (or the routing proxy will patch up the request.. not sure which) - req.headers.host = hostname; + if (req && req.headers && req.headers.host) req.headers.host = hostname; routingProxy.web(req, res, { target: { host: hostname, @@ -13468,13 +16519,16 @@ CREATE TABLE slack_user_invites ( // } } - function buildStaticHostname(req, res) { + function buildStaticHostname(req: { headers?: { host: string } }, res: any) { if (devMode || domainOverride) { return process.env.STATIC_FILES_HOST; } else { - let origin = req.headers.host; - if (!whitelistedBuckets[origin]) { - if (hasWhitelistMatches(origin)) { + let origin = req?.headers?.host; + // Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ "pol.is": string; "embed.pol.is": string; "survey.pol.is": string; "preprod.pol.is": string; }'. + // No index signature with a parameter of type 'string' was found on type '{ "pol.is": string; "embed.pol.is": string; "survey.pol.is": string; "preprod.pol.is": string; }'.ts(7053) + // @ts-ignore + if (!whitelistedBuckets[origin || ""]) { + if (hasWhitelistMatches(origin || "")) { // Use the prod bucket for non pol.is domains return ( whitelistedBuckets["pol.is"] + "." + process.env.STATIC_FILES_HOST @@ -13482,21 +16536,30 @@ CREATE TABLE slack_user_invites ( } else { console.error( "got request with host that's not whitelisted: (" + - req.headers.host + + req?.headers?.host + ")" ); return; } } - origin = whitelistedBuckets[origin]; + // Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ "pol.is": string; "embed.pol.is": string; "survey.pol.is": string; "preprod.pol.is": string; }'. + // No index signature with a parameter of type 'string' was found on type '{ "pol.is": string; "embed.pol.is": string; "survey.pol.is": string; "preprod.pol.is": string; }'.ts(7053) + // @ts-ignore + origin = whitelistedBuckets[origin || ""]; return origin + "." + process.env.STATIC_FILES_HOST; } } - function makeRedirectorTo(path) { - return function (req, res) { + function makeRedirectorTo(path: string) { + return function ( + req: { headers?: { host: string } }, + res: { + writeHead: (arg0: number, arg1: { Location: string }) => void; + end: () => void; + } + ) { let protocol = devMode ? "http://" : "https://"; - let url = protocol + req.headers.host + path; + let url = protocol + req?.headers?.host + path; res.writeHead(302, { Location: url, }); @@ -13506,7 +16569,13 @@ CREATE TABLE slack_user_invites ( // https://github.com/mindmup/3rdpartycookiecheck/ // https://stackoverflow.com/questions/32601424/render-raw-html-in-response-with-express - function fetchThirdPartyCookieTestPt1(req, res) { + function fetchThirdPartyCookieTestPt1( + req: any, + res: { + set: (arg0: { "Content-Type": string }) => void; + send: (arg0: Buffer) => void; + } + ) { res.set({ "Content-Type": "text/html" }); res.send( new Buffer( @@ -13519,7 +16588,13 @@ CREATE TABLE slack_user_invites ( ) ); } - function fetchThirdPartyCookieTestPt2(req, res) { + function fetchThirdPartyCookieTestPt2( + req: any, + res: { + set: (arg0: { "Content-Type": string }) => void; + send: (arg0: Buffer) => void; + } + ) { res.set({ "Content-Type": "text/html" }); res.send( new Buffer( @@ -13539,12 +16614,21 @@ CREATE TABLE slack_user_invites ( ); } - function makeFileFetcher(hostname, port, path, headers, preloadData) { - return function (req, res) { + function makeFileFetcher( + hostname?: string, + port?: string, + path?: string, + headers?: { "Content-Type": string }, + preloadData?: { conversation?: ConversationType } + ) { + return function ( + req: { headers?: { host: any }; path: any; pipe: (arg0: any) => void }, + res: { set: (arg0: any) => void } + ) { let hostname = buildStaticHostname(req, res); if (!hostname) { fail(res, 500, "polis_err_file_fetcher_serving_to_domain"); - console.error(req.headers.host); + console.error(req?.headers?.host); console.error(req.path); return; } @@ -13591,8 +16675,11 @@ CREATE TABLE slack_user_invites ( res.set(headers); + // Argument of type '{ set: (arg0: any) => void; }' is not assignable to parameter of type 'WritableStream'. + // Type '{ set: (arg0: any) => void; }' is missing the following properties from type 'WritableStream': writable, write, end, addListener, and 14 more.ts(2345) + // @ts-ignore x.pipe(res); - x.on("error", function (err) { + x.on("error", function (err: any) { fail(res, 500, "polis_err_finding_file " + path, err); }); // http.get(url, function(proxyResponse) { @@ -13613,16 +16700,18 @@ CREATE TABLE slack_user_invites ( } // function isIE(req) { - // let h = req.headers['user-agent']; + // let h = req?.headers?.['user-agent']; // return /MSIE [0-9]/.test(h) || /Trident/.test(h); // } - function isUnsupportedBrowser(req) { - return /MSIE [234567]/.test(req.headers["user-agent"]); + function isUnsupportedBrowser(req: { headers?: { [x: string]: string } }) { + return /MSIE [234567]/.test(req?.headers?.["user-agent"] || ""); } - function browserSupportsPushState(req) { - return !/MSIE [23456789]/.test(req.headers["user-agent"]); + function browserSupportsPushState(req: { + headers?: { [x: string]: string }; + }) { + return !/MSIE [23456789]/.test(req?.headers?.["user-agent"] || ""); } // serve up index.html in response to anything starting with a number @@ -13638,7 +16727,16 @@ CREATE TABLE slack_user_invites ( } ); - function fetchIndex(req, res, preloadData, port, buildNumber) { + function fetchIndex( + req: { path: string; headers?: { host: string } }, + res: { + writeHead: (arg0: number, arg1: { Location: string }) => void; + end: () => any; + }, + preloadData: { conversation?: ConversationType }, + port: string | undefined, + buildNumber?: string | null | undefined + ) { let headers = { "Content-Type": "text/html", }; @@ -13649,6 +16747,9 @@ CREATE TABLE slack_user_invites ( }); } + // Argument of type '{ path: string; headers?: { host: string; } | undefined; }' is not assignable to parameter of type 'Req'. + // Property 'cookies' is missing in type '{ path: string; headers?: { host: string; } | undefined; }' but required in type 'Req'.ts(2345) + // @ts-ignore setCookieTestCookie(req, res, shouldSetCookieOnPolisDomain(req)); if (devMode) { @@ -13666,6 +16767,9 @@ CREATE TABLE slack_user_invites ( preloadData ); if (isUnsupportedBrowser(req)) { + // Argument of type '{ path: string; headers?: { host: string; } | undefined; }' is not assignable to parameter of type '{ headers?: { host: any; } | undefined; path: any; pipe: (arg0: any) => void; }'. + // Property 'pipe' is missing in type '{ path: string; headers?: { host: string; } | undefined; }' but required in type '{ headers?: { host: any; } | undefined; path: any; pipe: (arg0: any) => void; }'.ts(2345) + // @ts-ignore return fetchUnsupportedBrowserPage(req, res); } else if ( !browserSupportsPushState(req) && @@ -13674,34 +16778,41 @@ CREATE TABLE slack_user_invites ( ) { // Redirect to the same URL with the path behind the fragment "#" res.writeHead(302, { - Location: "https://" + req.headers.host + "/#" + req.path, + Location: "https://" + req?.headers?.host + "/#" + req.path, }); return res.end(); } else { + // Argument of type '{ path: string; headers?: { host: string; } | undefined; }' + // is not assignable to parameter of type '{ headers?: { host: any; } | undefined; + // path: any; pipe: (arg0: any) => void; } '.ts(2345) + // @ts-ignore return doFetch(req, res); } } - function fetchIndexWithoutPreloadData(req, res, port) { + function fetchIndexWithoutPreloadData(req: any, res: any, port: any) { return fetchIndex(req, res, {}, port); } - function ifDefinedFirstElseSecond(first, second) { + function ifDefinedFirstElseSecond(first: any, second: boolean) { return _.isUndefined(first) ? second : first; } let fetch404Page = makeFileFetcher(hostname, portForAdminFiles, "/404.html", { "Content-Type": "text/html", }); - function fetchIndexForConversation(req, res) { + function fetchIndexForConversation( + req: { path: string; query?: { build: any } }, + res: any + ) { console.log("fetchIndexForConversation", req.path); let match = req.path.match(/[0-9][0-9A-Za-z]+/); - let conversation_id; + let conversation_id: any; if (match && match.length) { conversation_id = match[0]; } - let buildNumber = null; - if (req.query.build) { + let buildNumber: null = null; + if (req?.query?.build) { buildNumber = req.query.build; console.log("loading_build", buildNumber); } @@ -13713,7 +16824,7 @@ CREATE TABLE slack_user_invites ( // TODO actually store these values in a cache that is shared between // the servers, probably just in the db. getTwitterShareCountForConversation(conversation_id).catch(function ( - err + err: string ) { console.log( "fetchIndexForConversation/getTwitterShareCountForConversation err " + @@ -13721,7 +16832,7 @@ CREATE TABLE slack_user_invites ( ); }); getFacebookShareCountForConversation(conversation_id).catch(function ( - err + err: string ) { console.log( "fetchIndexForConversation/getFacebookShareCountForConversation err " + @@ -13731,7 +16842,7 @@ CREATE TABLE slack_user_invites ( }, 100); doGetConversationPreloadInfo(conversation_id) - .then(function (x) { + .then(function (x: any) { let preloadData = { conversation: x, // Nothing user-specific can go here, since we want to cache these per-conv index files on the CDN. @@ -13744,7 +16855,10 @@ CREATE TABLE slack_user_invites ( buildNumber ); }) - .catch(function (err) { + .catch(function (err: any) { + // Argument of type '{ path: string; query?: { build: any; } | undefined; }' is not assignable to parameter of type '{ headers?: { host: any; } | undefined; path: any; pipe: (arg0: any) => void; }'. + // Property 'pipe' is missing in type '{ path: string; query?: { build: any; } | undefined; }' but required in type '{ headers?: { host: any; } | undefined; path: any; pipe: (arg0: any) => void; }'.ts(2345) + // @ts-ignore fetch404Page(req, res); // fail(res, 500, "polis_err_fetching_conversation_info2", err); }); @@ -13766,7 +16880,13 @@ CREATE TABLE slack_user_invites ( } ); - function handle_GET_iip_conversation(req, res) { + function handle_GET_iip_conversation( + req: { params: { conversation_id: any } }, + res: { + set: (arg0: { "Content-Type": string }) => void; + send: (arg0: string) => void; + } + ) { let conversation_id = req.params.conversation_id; res.set({ "Content-Type": "text/html", @@ -13779,11 +16899,17 @@ CREATE TABLE slack_user_invites ( "" ); } - function handle_GET_iim_conversation(req, res) { + function handle_GET_iim_conversation( + req: { p: { zid: any }; params: { conversation_id: any } }, + res: { + set: (arg0: { "Content-Type": string }) => void; + send: (arg0: string) => void; + } + ) { let zid = req.p.zid; let conversation_id = req.params.conversation_id; getConversationInfo(zid) - .then(function (info) { + .then(function (info: { topic: any; created: any; description: string }) { res.set({ "Content-Type": "text/html", }); @@ -13800,12 +16926,22 @@ CREATE TABLE slack_user_invites ( (info.description ? "

" + info.description + "

" : "") ); }) - .catch(function (err) { + .catch(function (err: any) { fail(res, 500, "polis_err_fetching_conversation_info", err); }); } - function handle_GET_twitter_image(req, res) { + function handle_GET_twitter_image( + req: { p: { id: any } }, + res: { + setHeader: (arg0: string, arg1: string) => void; + writeHead: (arg0: number) => void; + end: (arg0: string) => void; + status: ( + arg0: number + ) => { (): any; new (): any; end: { (): void; new (): any } }; + } + ) { console.log("handle_GET_twitter_image", req.p.id); getTwitterUserInfo( { @@ -13813,18 +16949,16 @@ CREATE TABLE slack_user_invites ( }, true ) - .then(function (data) { - data = JSON.parse(data); - if (!data || !data.length) { + .then(function (data: string) { + let parsedData = JSON.parse(data); + if (!parsedData || !parsedData.length) { fail(res, 500, "polis_err_finding_twitter_user_info"); return; } - data = data[0]; - let url = data.profile_image_url; // not https to save a round-trip - + const url = parsedData[0].profile_image_url; // not https to save a round-trip let finished = false; http - .get(url, function (twitterResponse) { + .get(url, function (twitterResponse: { pipe: (arg0: any) => void }) { if (!finished) { clearTimeout(timeoutHandle); finished = true; @@ -13835,7 +16969,7 @@ CREATE TABLE slack_user_invites ( twitterResponse.pipe(res); } }) - .on("error", function (err) { + .on("error", function (err: any) { finished = true; fail(res, 500, "polis_err_finding_file " + url, err); }); @@ -13849,7 +16983,7 @@ CREATE TABLE slack_user_invites ( } }, 9999); }) - .catch(function (err) { + .catch(function (err: { stack: any }) { console.error("polis_err_missing_twitter_image", err); if (err && err.stack) { console.error(err.stack); @@ -13858,9 +16992,15 @@ CREATE TABLE slack_user_invites ( }); } let handle_GET_conditionalIndexFetcher = (function () { - return function (req, res) { + return function (req: any, res: { redirect: (arg0: string) => void }) { if (hasAuthToken(req)) { // user is signed in, serve the app + // Argument of type '{ redirect: (arg0: string) => void; }' + // is not assignable to parameter of type '{ set: (arg0: any) => void; }'. + // + // Property 'set' is missing in type '{ redirect: (arg0: string) => void; }' + // but required in type '{ set: (arg0: any) => void; }'.ts(2345) + // @ts-ignore return fetchIndexForAdminPage(req, res); } else if (!browserSupportsPushState(req)) { // TEMPORARY: Don't show the landing page. @@ -13868,6 +17008,10 @@ CREATE TABLE slack_user_invites ( // which ends up here, and since there's no auth token yet, // we would show the lander. One fix would be to serve up the auth page // as a separate html file, and not rely on JS for the routing. + // + // Argument of type '{ redirect: (arg0: string) => void; }' + // is not assignable to parameter of type '{ set: (arg0: any) => void; }'.ts(2345) + // @ts-ignore return fetchIndexForAdminPage(req, res); } else { // user not signed in, redirect to landing page @@ -13877,16 +17021,25 @@ CREATE TABLE slack_user_invites ( }; })(); - function handle_GET_localFile_dev_only(req, res) { - let filename = String(req.path).split("/"); - filename.shift(); - filename.shift(); - filename = filename.join("/"); + function handle_GET_localFile_dev_only( + req: { path: any }, + res: { + writeHead: ( + arg0: number, + arg1?: { "Content-Type": string } | undefined + ) => void; + end: (arg0?: undefined, arg1?: string) => void; + } + ) { + const filenameParts = String(req.path).split("/"); + filenameParts.shift(); + filenameParts.shift(); + const filename = filenameParts.join("/"); if (!devMode) { // pretend this route doesn't exist. return proxy(req, res); } - fs.readFile(filename, function (error, content) { + fs.readFile(filename, function (error: any, content: any) { if (error) { res.writeHead(500); res.end(); @@ -13899,7 +17052,11 @@ CREATE TABLE slack_user_invites ( }); } - function middleware_log_request_body(req, res, next) { + function middleware_log_request_body( + req: { body: any; path: string }, + res: any, + next: () => void + ) { if (devMode) { let b = ""; if (req.body) { @@ -13931,7 +17088,12 @@ CREATE TABLE slack_user_invites ( next(); } - function middleware_log_middleware_errors(err, req, res, next) { + function middleware_log_middleware_errors( + err: { stack: any }, + req: any, + res: any, + next: (arg0?: { stack: any }) => void + ) { if (!err) { return next(); } @@ -13944,14 +17106,22 @@ CREATE TABLE slack_user_invites ( next(err); } - function middleware_check_if_options(req, res, next) { + function middleware_check_if_options( + req: { method: string }, + res: { send: (arg0: number) => any }, + next: () => any + ) { if (req.method.toLowerCase() !== "options") { return next(); } return res.send(204); } - let middleware_responseTime_start = responseTime(function (req, res, time) { + let middleware_responseTime_start = responseTime(function ( + req: { route: { path: any } }, + res: any, + time: number + ) { if (req && req.route && req.route.path) { let path = req.route.path; time = Math.trunc(time); @@ -13960,7 +17130,7 @@ CREATE TABLE slack_user_invites ( }); console.log("end initializePolisHelpers"); - return { + const returnObject: any = { addCorsHeader, auth, authOptional, @@ -14127,6 +17297,7 @@ CREATE TABLE slack_user_invites ( //getNextPrioritizedComment, //getPca }; + return returnObject; } // End of initializePolisHelpers // debugging //let ph = initializePolisHelpers() @@ -14135,6 +17306,6 @@ CREATE TABLE slack_user_invites ( //let nextP = ph.getNextPrioritizedComment(17794, 100, [], true); //}; -module.exports = { - initializePolisHelpers, -}; +export { initializePolisHelpers }; + +export default { initializePolisHelpers }; diff --git a/server/src/session.js b/server/src/session.js deleted file mode 100644 index cc2683a21..000000000 --- a/server/src/session.js +++ /dev/null @@ -1,217 +0,0 @@ -const crypto = require("crypto"); -const LruCache = require("lru-cache"); -const pg = require("./db/pg-query"); - -function encrypt(text) { - const algorithm = "aes-256-ctr"; - const password = process.env.ENCRYPTION_PASSWORD_00001; - const cipher = crypto.createCipher(algorithm, password); - var crypted = cipher.update(text, "utf8", "hex"); - crypted += cipher.final("hex"); - return crypted; -} - -function decrypt(text) { - const algorithm = "aes-256-ctr"; - const password = process.env.ENCRYPTION_PASSWORD_00001; - const decipher = crypto.createDecipher(algorithm, password); - var dec = decipher.update(text, "hex", "utf8"); - dec += decipher.final("utf8"); - return dec; -} -decrypt; // appease linter -function makeSessionToken() { - // These can probably be shortened at some point. - return crypto - .randomBytes(32) - .toString("base64") - .replace(/[^A-Za-z0-9]/g, "") - .substr(0, 20); -} - -// But we need to squeeze a bit more out of the db right now, -// and generally remove sources of uncertainty about what makes -// various queries slow. And having every single query talk to PG -// adds a lot of variability across the board. -const userTokenCache = new LruCache({ - max: 9000, -}); - -function getUserInfoForSessionToken(sessionToken, res, cb) { - let cachedUid = userTokenCache.get(sessionToken); - if (cachedUid) { - cb(null, cachedUid); - return; - } - pg.query( - "select uid from auth_tokens where token = ($1);", - [sessionToken], - function (err, results) { - if (err) { - console.error("token_fetch_error"); - cb(500); - return; - } - if (!results || !results.rows || !results.rows.length) { - console.error("token_expired_or_missing"); - - cb(403); - return; - } - let uid = results.rows[0].uid; - userTokenCache.set(sessionToken, uid); - cb(null, uid); - } - ); -} - -function createPolisLtiToken(tool_consumer_instance_guid, lti_user_id) { - return ["xPolisLtiToken", tool_consumer_instance_guid, lti_user_id].join( - ":::" - ); -} - -function isPolisLtiToken(token) { - return token.match(/^xPolisLtiToken/); -} -function isPolisSlackTeamUserToken(token) { - return token.match(/^xPolisSlackTeamUserToken/); -} - -// function sendSlackEvent(slack_team, o) { -// return pg.queryP("insert into slack_bot_events (slack_team, event) values ($1, $2);", [slack_team, o]); -// } - -function sendSlackEvent(o) { - return pg.queryP("insert into slack_bot_events (event) values ($1);", [o]); -} - -function parsePolisLtiToken(token) { - let parts = token.split(/:::/); - let o = { - // parts[0] === "xPolisLtiToken", don't need that - tool_consumer_instance_guid: parts[1], - lti_user_id: parts[2], - }; - return o; -} - -function getUserInfoForPolisLtiToken(token) { - let o = parsePolisLtiToken(token); - return pg - .queryP( - "select uid from lti_users where tool_consumer_instance_guid = $1 and lti_user_id = $2", - [o.tool_consumer_instance_guid, o.lti_user_id] - ) - .then(function (rows) { - return rows[0].uid; - }); -} - -function startSession(uid, cb) { - let token = makeSessionToken(); - //console.log("info",'startSession: token will be: ' + sessionToken); - console.log("info", "startSession"); - pg.query( - "insert into auth_tokens (uid, token, created) values ($1, $2, default);", - [uid, token], - function (err, repliesSetToken) { - if (err) { - cb(err); - return; - } - console.log("info", "startSession: token set."); - cb(null, token); - } - ); -} - -function endSession(sessionToken, cb) { - pg.query( - "delete from auth_tokens where token = ($1);", - [sessionToken], - function (err, results) { - if (err) { - cb(err); - return; - } - cb(null); - } - ); -} -function setupPwReset(uid, cb) { - function makePwResetToken() { - // These can probably be shortened at some point. - return crypto - .randomBytes(140) - .toString("base64") - .replace(/[^A-Za-z0-9]/g, "") - .substr(0, 100); - } - let token = makePwResetToken(); - pg.query( - "insert into pwreset_tokens (uid, token, created) values ($1, $2, default);", - [uid, token], - function (errSetToken, repliesSetToken) { - if (errSetToken) { - cb(errSetToken); - return; - } - cb(null, token); - } - ); -} - -function getUidForPwResetToken(pwresettoken, cb) { - // TODO "and created > timestamp - x" - pg.query( - "select uid from pwreset_tokens where token = ($1);", - [pwresettoken], - function (errGetToken, results) { - if (errGetToken) { - console.error("pwresettoken_fetch_error"); - cb(500); - return; - } - if (!results || !results.rows || !results.rows.length) { - console.error("token_expired_or_missing"); - cb(403); - return; - } - cb(null, { - uid: results.rows[0].uid, - }); - } - ); -} - -function clearPwResetToken(pwresettoken, cb) { - pg.query( - "delete from pwreset_tokens where token = ($1);", - [pwresettoken], - function (errDelToken, repliesSetToken) { - if (errDelToken) { - cb(errDelToken); - return; - } - cb(null); - } - ); -} - -module.exports = { - encrypt, - decrypt, - makeSessionToken, - getUserInfoForSessionToken, - createPolisLtiToken, - isPolisLtiToken, - isPolisSlackTeamUserToken, - sendSlackEvent, - getUserInfoForPolisLtiToken, - startSession, - endSession, - setupPwReset, - getUidForPwResetToken, - clearPwResetToken, -}; diff --git a/server/src/session.ts b/server/src/session.ts new file mode 100644 index 000000000..4e3e26682 --- /dev/null +++ b/server/src/session.ts @@ -0,0 +1,290 @@ +import crypto from "crypto"; +import LruCache from "lru-cache"; + +import pg from "./db/pg-query"; + +function encrypt(text: string | null) { + const algorithm = "aes-256-ctr"; + const password = process.env.ENCRYPTION_PASSWORD_00001; + // + // TODO replace deprecated createCipher method with current createCipheriv method + // + // function createCipher(algorithm: crypto.CipherCCMTypes, password: crypto.BinaryLike, options: crypto.CipherCCMOptions): crypto.CipherCCM (+2 overloads) + // + // @deprecated — since v10.0.0 use createCipheriv() + // + // The signature '(algorithm: string, password: BinaryLike, options: TransformOptions | undefined): CipherCCM & CipherGCM & Cipher' of 'crypto.createCipher' is deprecated.ts(6387) + // crypto.d.ts(207, 9): The declaration was marked as deprecated here. + // No overload matches this call. + // Overload 1 of 3, '(algorithm: CipherGCMTypes, password: BinaryLike, options?: CipherGCMOptions | undefined): CipherGCM', gave the following error. + // Argument of type '"aes-256-ctr"' is not assignable to parameter of type 'CipherGCMTypes'. + // Overload 2 of 3, '(algorithm: string, password: BinaryLike, options?: TransformOptions | undefined): Cipher', gave the following error. + // Argument of type 'string | undefined' is not assignable to parameter of type 'BinaryLike'. + // Type 'undefined' is not assignable to type 'BinaryLike'.ts(2769) + // @ts-ignore + const cipher = crypto.createCipher(algorithm, password); + // No overload matches this call. + // Overload 1 of 4, '(data: ArrayBufferView, input_encoding: undefined, output_encoding: Encoding): string', gave the following error. + // Argument of type 'string | null' is not assignable to parameter of type 'ArrayBufferView'. + // Type 'null' is not assignable to type 'ArrayBufferView'. + // Overload 2 of 4, '(data: string, input_encoding: Encoding | undefined, output_encoding: Encoding): string', gave the following error. + // Argument of type 'string | null' is not assignable to parameter of type 'string'. + // Type 'null' is not assignable to type 'string'.ts(2769) + // @ts-ignore + var crypted = cipher.update(text, "utf8", "hex"); + // Type 'string' is not assignable to type 'Buffer & string'. + // Type 'string' is not assignable to type 'Buffer'.ts(2322) + // @ts-ignore + crypted += cipher.final("hex"); + return crypted; +} + +function decrypt(text: string) { + const algorithm = "aes-256-ctr"; + const password = process.env.ENCRYPTION_PASSWORD_00001; + // + // TODO replace deprecated createDecipher method with current createDecipheriv method + // + // function createDecipher(algorithm: crypto.CipherCCMTypes, password: crypto.BinaryLike, options: crypto.CipherCCMOptions): crypto.DecipherCCM (+2 overloads) + // + // @deprecated — since v10.0.0 use createDecipheriv() + // + // The signature '(algorithm: string, password: BinaryLike, options: TransformOptions | undefined): DecipherCCM & DecipherGCM & Decipher' of 'crypto.createDecipher' is deprecated.ts(6387) + // crypto.d.ts(253, 9): The declaration was marked as deprecated here. + // No overload matches this call. + // Overload 1 of 3, '(algorithm: CipherGCMTypes, password: BinaryLike, options?: CipherGCMOptions | undefined): DecipherGCM', gave the following error. + // Argument of type '"aes-256-ctr"' is not assignable to parameter of type 'CipherGCMTypes'. + // Overload 2 of 3, '(algorithm: string, password: BinaryLike, options?: TransformOptions | undefined): Decipher', gave the following error. + // Argument of type 'string | undefined' is not assignable to parameter of type 'BinaryLike'.ts(2769) + // @ts-ignore + const decipher = crypto.createDecipher(algorithm, password); + var dec = decipher.update(text, "hex", "utf8"); + dec += decipher.final("utf8"); + return dec; +} +decrypt; // appease linter +function makeSessionToken() { + // These can probably be shortened at some point. + return crypto + .randomBytes(32) + .toString("base64") + .replace(/[^A-Za-z0-9]/g, "") + .substr(0, 20); +} + +// But we need to squeeze a bit more out of the db right now, +// and generally remove sources of uncertainty about what makes +// various queries slow. And having every single query talk to PG +// adds a lot of variability across the board. +const userTokenCache = new LruCache({ + max: 9000, +}); + +function getUserInfoForSessionToken( + sessionToken: unknown, + res: any, + cb: (arg0: number | null, arg1?: unknown) => void +) { + let cachedUid = userTokenCache.get(sessionToken); + if (cachedUid) { + cb(null, cachedUid); + return; + } + pg.query( + "select uid from auth_tokens where token = ($1);", + [sessionToken], + function (err: any, results: { rows: string | any[] }) { + if (err) { + console.error("token_fetch_error"); + cb(500); + return; + } + if (!results || !results.rows || !results.rows.length) { + console.error("token_expired_or_missing"); + + cb(403); + return; + } + let uid = results.rows[0].uid; + userTokenCache.set(sessionToken, uid); + cb(null, uid); + } + ); +} + +function createPolisLtiToken( + tool_consumer_instance_guid: any, + lti_user_id: any +) { + return ["xPolisLtiToken", tool_consumer_instance_guid, lti_user_id].join( + ":::" + ); +} + +function isPolisLtiToken(token: string) { + return token.match(/^xPolisLtiToken/); +} +function isPolisSlackTeamUserToken(token: string) { + return token.match(/^xPolisSlackTeamUserToken/); +} + +// function sendSlackEvent(slack_team, o) { +// return pg.queryP("insert into slack_bot_events (slack_team, event) values ($1, $2);", [slack_team, o]); +// } + +function sendSlackEvent(o: any) { + return pg.queryP("insert into slack_bot_events (event) values ($1);", [o]); +} + +function parsePolisLtiToken(token: string) { + let parts = token.split(/:::/); + let o = { + // parts[0] === "xPolisLtiToken", don't need that + tool_consumer_instance_guid: parts[1], + lti_user_id: parts[2], + }; + return o; +} + +function getUserInfoForPolisLtiToken(token: any) { + let o = parsePolisLtiToken(token); + return pg + .queryP( + "select uid from lti_users where tool_consumer_instance_guid = $1 and lti_user_id = $2", + [o.tool_consumer_instance_guid, o.lti_user_id] + ) + .then(function (rows) { + // (parameter) rows: unknown + // Object is of type 'unknown'.ts(2571) + // @ts-ignore + return rows[0].uid; + }); +} + +function startSession(uid: any, cb: (arg0: null, arg1?: string) => void) { + let token = makeSessionToken(); + //console.log("info",'startSession: token will be: ' + sessionToken); + console.log("info", "startSession"); + pg.query( + "insert into auth_tokens (uid, token, created) values ($1, $2, default);", + [uid, token], + function (err: any, repliesSetToken: any) { + if (err) { + cb(err); + return; + } + console.log("info", "startSession: token set."); + cb(null, token); + } + ); +} + +function endSession(sessionToken: any, cb: (err: any, data?: any) => void) { + pg.query( + "delete from auth_tokens where token = ($1);", + [sessionToken], + function (err: any, results: any) { + if (err) { + cb(err); + return; + } + cb(null); + } + ); +} +function setupPwReset(uid: any, cb: (arg0: null, arg1?: string) => void) { + function makePwResetToken() { + // These can probably be shortened at some point. + return crypto + .randomBytes(140) + .toString("base64") + .replace(/[^A-Za-z0-9]/g, "") + .substr(0, 100); + } + let token = makePwResetToken(); + pg.query( + "insert into pwreset_tokens (uid, token, created) values ($1, $2, default);", + [uid, token], + function (errSetToken: any, repliesSetToken: any) { + if (errSetToken) { + cb(errSetToken); + return; + } + cb(null, token); + } + ); +} + +function getUidForPwResetToken( + pwresettoken: any, + cb: (arg0: number | null, arg1?: { uid: any }) => void +) { + // TODO "and created > timestamp - x" + pg.query( + "select uid from pwreset_tokens where token = ($1);", + [pwresettoken], + function (errGetToken: any, results: { rows: string | any[] }) { + if (errGetToken) { + console.error("pwresettoken_fetch_error"); + cb(500); + return; + } + if (!results || !results.rows || !results.rows.length) { + console.error("token_expired_or_missing"); + cb(403); + return; + } + cb(null, { + uid: results.rows[0].uid, + }); + } + ); +} + +function clearPwResetToken(pwresettoken: any, cb: (arg0: null) => void) { + pg.query( + "delete from pwreset_tokens where token = ($1);", + [pwresettoken], + function (errDelToken: any, repliesSetToken: any) { + if (errDelToken) { + cb(errDelToken); + return; + } + cb(null); + } + ); +} + +export { + encrypt, + decrypt, + makeSessionToken, + getUserInfoForSessionToken, + createPolisLtiToken, + isPolisLtiToken, + isPolisSlackTeamUserToken, + sendSlackEvent, + getUserInfoForPolisLtiToken, + startSession, + endSession, + setupPwReset, + getUidForPwResetToken, + clearPwResetToken, +}; + +export default { + encrypt, + decrypt, + makeSessionToken, + getUserInfoForSessionToken, + createPolisLtiToken, + isPolisLtiToken, + isPolisSlackTeamUserToken, + sendSlackEvent, + getUserInfoForPolisLtiToken, + startSession, + endSession, + setupPwReset, + getUidForPwResetToken, + clearPwResetToken, +}; diff --git a/server/src/user.ts b/server/src/user.ts new file mode 100644 index 000000000..d18b26686 --- /dev/null +++ b/server/src/user.ts @@ -0,0 +1,540 @@ +import _ from "underscore"; +import LruCache from "lru-cache"; + +import pg from "./db/pg-query"; +import { MPromise } from "./utils/metered"; + +import Config from "./config"; +import Conversation from "./conversation"; +import Log from "./log"; +import LRUCache from "lru-cache"; + +function getUserInfoForUid( + uid: any, + callback: (arg0: null, arg1?: undefined) => void +) { + pg.query_readOnly( + "SELECT email, hname from users where uid = $1", + [uid], + function (err: any, results: { rows: string | any[] }) { + if (err) { + return callback(err); + } + if (!results.rows || !results.rows.length) { + return callback(null); + } + callback(null, results.rows[0]); + } + ); +} + +function getUserInfoForUid2(uid: any) { + // 'new' expression, whose target lacks a construct signature, implicitly has an 'any' type.ts(7009) + // @ts-ignore + return new MPromise( + "getUserInfoForUid2", + function (resolve: (arg0: any) => void, reject: (arg0: null) => any) { + pg.query_readOnly( + "SELECT * from users where uid = $1", + [uid], + function (err: any, results: { rows: string | any[] }) { + if (err) { + return reject(err); + } + if (!results.rows || !results.rows.length) { + return reject(null); + } + let o = results.rows[0]; + resolve(o); + } + ); + } + ); +} + +function addLtiUserIfNeeded( + uid: any, + lti_user_id: any, + tool_consumer_instance_guid: any, + lti_user_image: null +) { + lti_user_image = lti_user_image || null; + return ( + pg + .queryP( + "select * from lti_users where lti_user_id = ($1) and tool_consumer_instance_guid = ($2);", + [lti_user_id, tool_consumer_instance_guid] + ) + // (local function)(rows: string | any[]): Promise | undefined + // Argument of type '(rows: string | any[]) => Promise | undefined' is not assignable to parameter of type '(value: unknown) => unknown'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + .then(function (rows: string | any[]) { + if (!rows || !rows.length) { + return pg.queryP( + "insert into lti_users (uid, lti_user_id, tool_consumer_instance_guid, lti_user_image) values ($1, $2, $3, $4);", + [uid, lti_user_id, tool_consumer_instance_guid, lti_user_image] + ); + } + }) + ); +} + +function addLtiContextMembership( + uid: any, + lti_context_id: any, + tool_consumer_instance_guid: any +) { + return ( + pg + .queryP( + "select * from lti_context_memberships where uid = $1 and lti_context_id = $2 and tool_consumer_instance_guid = $3;", + [uid, lti_context_id, tool_consumer_instance_guid] + ) + // (local function)(rows: string | any[]): Promise | undefined + // Argument of type '(rows: string | any[]) => Promise | undefined' is not assignable to parameter of type '(value: unknown) => unknown'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + .then(function (rows: string | any[]) { + if (!rows || !rows.length) { + return pg.queryP( + "insert into lti_context_memberships (uid, lti_context_id, tool_consumer_instance_guid) values ($1, $2, $3);", + [uid, lti_context_id, tool_consumer_instance_guid] + ); + } + }) + ); +} + +function renderLtiLinkageSuccessPage( + req: any, + res: { + set: (arg0: { "Content-Type": string }) => void; + status: ( + arg0: number + ) => { (): any; new (): any; send: { (arg0: string): void; new (): any } }; + }, + o: { email: string } +) { + res.set({ + "Content-Type": "text/html", + }); + let html = + "" + + "" + + "" + + '' + + "" + + "" + + "

You are signed in as polis user " + + o.email + + "

" + + // "

Change pol.is users

" + + // "

inbox

" + + // "

2demo

" + + // "

create

" + + + // form for sign out + '

' + + '' + + '' + + "

" + + // "

" + + // JSON.stringify(req.body)+ + // (o.user_image ? "" : "") + + // "

"+ + ""; + res.status(200).send(html); +} + +async function getUser( + uid: number, + zid_optional: any, + xid_optional: any, + owner_uid_optional: any +) { + if (!uid) { + // this api may be called by a new user, so we don't want to trigger a failure here. + return Promise.resolve({}); + } + + let xidInfoPromise = Promise.resolve(null); + if (zid_optional && xid_optional) { + // let xidInfoPromise: Promise + // Type 'Promise' is not assignable to type 'Promise'. + // Type 'unknown' is not assignable to type 'null'.ts(2322) + // @ts-ignore + xidInfoPromise = Conversation.getXidRecord(xid_optional, zid_optional); + } else if (xid_optional && owner_uid_optional) { + // let xidInfoPromise: Promise + // Type 'Promise' is not assignable to type 'Promise'.ts(2322) + // @ts-ignore + xidInfoPromise = Conversation.getXidRecordByXidOwnerId( + xid_optional, + owner_uid_optional, + zid_optional + ); + } + + const o: any[] = await Promise.all([ + getUserInfoForUid2(uid), + getFacebookInfo([uid]), + getTwitterInfo([uid]), + xidInfoPromise, + ]); + let info = o[0]; + let fbInfo = o[1]; + let twInfo = o[2]; + let xInfo = o[3]; + let hasFacebook = fbInfo && fbInfo.length && fbInfo[0]; + let hasTwitter = twInfo && twInfo.length && twInfo[0]; + let hasXid = xInfo && xInfo.length && xInfo[0]; + if (hasFacebook) { + let width = 40; + let height = 40; + fbInfo.fb_picture = + "https://graph.facebook.com/v2.2/" + + fbInfo.fb_user_id + + "/picture?width=" + + width + + "&height=" + + height; + delete fbInfo[0].response; + } + if (hasTwitter) { + delete twInfo[0].response; + } + if (hasXid) { + delete xInfo[0].owner; + delete xInfo[0].created; + delete xInfo[0].uid; + } + return { + uid: uid, + email: info.email, + hname: info.hname, + hasFacebook: !!hasFacebook, + facebook: fbInfo && fbInfo[0], + twitter: twInfo && twInfo[0], + hasTwitter: !!hasTwitter, + hasXid: !!hasXid, + xInfo: xInfo && xInfo[0], + finishedTutorial: !!info.tut, + site_ids: [info.site_id], + created: Number(info.created), + daysInTrial: 10 + (usersToAdditionalTrialDays[uid] || 0), + // plan: planCodeToPlanName[info.plan], + planCode: info.plan, + }; +} + +function getTwitterInfo(uids: any[]) { + return pg.queryP_readOnly( + "select * from twitter_users where uid in ($1);", + uids + ); +} + +function getFacebookInfo(uids: any[]) { + return pg.queryP_readOnly( + "select * from facebook_users where uid in ($1);", + uids + ); +} + +// so we can grant extra days to users +// eventually we should probably move this to db. +// for now, use git blame to see when these were added +const usersToAdditionalTrialDays: { [key: number]: number } = { + 50756: 14, // julien + 85423: 100, // mike test +}; + +function createDummyUser() { + // (parameter) resolve: (arg0: any) => void + // 'new' expression, whose target lacks a construct signature, implicitly has an 'any' type.ts(7009) + // @ts-ignore + return new MPromise( + "createDummyUser", + function (resolve: (arg0: any) => void, reject: (arg0: Error) => void) { + pg.query( + "INSERT INTO users (created) VALUES (default) RETURNING uid;", + [], + function (err: any, results: { rows: string | any[] }) { + if (err || !results || !results.rows || !results.rows.length) { + console.error(err); + reject(new Error("polis_err_create_empty_user")); + return; + } + resolve(results.rows[0].uid); + } + ); + } + ); +} + +let pidCache: LRUCache = new LruCache({ + max: 9000, +}); + +// returns a pid of -1 if it's missing +function getPid( + zid: string, + uid: string, + callback: (arg0: null, arg1: number) => void +) { + let cacheKey = zid + "_" + uid; + let cachedPid = pidCache.get(cacheKey); + if (!_.isUndefined(cachedPid)) { + callback(null, cachedPid); + return; + } + pg.query_readOnly( + "SELECT pid FROM participants WHERE zid = ($1) AND uid = ($2);", + [zid, uid], + function (err: any, docs: { rows: { pid: number }[] }) { + let pid = -1; + if (docs && docs.rows && docs.rows[0]) { + pid = docs.rows[0].pid; + pidCache.set(cacheKey, pid); + } + callback(err, pid); + } + ); +} + +// returns a pid of -1 if it's missing +function getPidPromise(zid: string, uid: string, usePrimary?: boolean) { + let cacheKey = zid + "_" + uid; + let cachedPid = pidCache.get(cacheKey); + // (alias) function MPromise(name: string, f: (resolve: (value: unknown) => void, reject: (reason?: any) => void) => void): Promise + // import MPromise + // 'new' expression, whose target lacks a construct signature, implicitly has an 'any' type.ts(7009) + // @ts-ignore + return new MPromise( + "getPidPromise", + function (resolve: (arg0: number) => void, reject: (arg0: any) => any) { + if (!_.isUndefined(cachedPid)) { + resolve(cachedPid); + return; + } + const f = usePrimary ? pg.query : pg.query_readOnly; + f( + "SELECT pid FROM participants WHERE zid = ($1) AND uid = ($2);", + [zid, uid], + function (err: any, results: { rows: string | any[] }) { + if (err) { + return reject(err); + } + if (!results || !results.rows || !results.rows.length) { + resolve(-1); + return; + } + let pid = results.rows[0].pid; + pidCache.set(cacheKey, pid); + resolve(pid); + } + ); + } + ); +} + +// must follow auth and need('zid'...) middleware +function getPidForParticipant( + assigner: (arg0: any, arg1: string, arg2: any) => void, + cache: any +) { + return function ( + req: { p: { zid: any; uid: any } }, + res: any, + next: (arg0?: string) => void + ) { + let zid = req.p.zid; + let uid = req.p.uid; + + function finish(pid: any) { + assigner(req, "pid", pid); + next(); + } + getPidPromise(zid, uid).then( + function (pid: number) { + if (pid === -1) { + let msg = "polis_err_get_pid_for_participant_missing"; + Log.yell(msg); + + console.log("info", zid); + console.log("info", uid); + console.log("info", req.p); + next(msg); + } + finish(pid); + }, + function (err: any) { + Log.yell("polis_err_get_pid_for_participant"); + next(err); + } + ); + }; +} + +function getSocialInfoForUsers(uids: any[], zid: any) { + uids = _.uniq(uids); + uids.forEach(function (uid: string) { + if (!_.isNumber(uid)) { + throw "polis_err_123123_invalid_uid got:" + uid; + } + }); + if (!uids.length) { + return Promise.resolve([]); + } + let uidString = uids.join(","); + return pg.queryP_metered_readOnly( + "getSocialInfoForUsers", + "with " + + "x as (select * from xids where uid in (" + + uidString + + ") and owner in (select org_id from conversations where zid = ($1))), " + + "fb as (select * from facebook_users where uid in (" + + uidString + + ")), " + + "tw as (select * from twitter_users where uid in (" + + uidString + + ")), " + + "foo as (select *, coalesce(fb.uid, tw.uid) as foouid from fb full outer join tw on tw.uid = fb.uid) " + + "select *, coalesce(foo.foouid, x.uid) as uid from foo full outer join x on x.uid = foo.foouid;", + [zid] + ); +} + +function getXidRecordByXidOwnerId( + xid: any, + owner: any, + zid_optional: any, + x_profile_image_url: any, + x_name: any, + x_email: any, + createIfMissing: any +) { + return ( + pg + .queryP("select * from xids where xid = ($1) and owner = ($2);", [ + xid, + owner, + ]) + // (local function)(rows: string | any[]): any + // Argument of type '(rows: string | any[]) => any' is not assignable to parameter of type '(value: unknown) => any'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + .then(function (rows: string | any[]) { + if (!rows || !rows.length) { + console.log("no xInfo yet"); + if (!createIfMissing) { + return null; + } + + var shouldCreateXidEntryPromise = !zid_optional + ? Promise.resolve(true) + : Conversation.getConversationInfo(zid_optional).then( + (conv: { use_xid_whitelist: any }) => { + return conv.use_xid_whitelist + ? Conversation.isXidWhitelisted(owner, xid) + : Promise.resolve(true); + } + ); + + return shouldCreateXidEntryPromise.then((should: any) => { + if (!should) { + return null; + } + return createDummyUser().then((newUid: any) => { + console.log("created dummy"); + return Conversation.createXidRecord( + owner, + newUid, + xid, + x_profile_image_url || null, + x_name || null, + x_email || null + ).then(() => { + console.log("created xInfo"); + return [ + { + uid: newUid, + owner: owner, + xid: xid, + x_profile_image_url: x_profile_image_url, + x_name: x_name, + x_email: x_email, + }, + ]; + }); + }); + }); + } + return rows; + }) + ); +} + +function getXidStuff(xid: any, zid: any) { + // Argument of type '(rows: string | any[]) => any' is not assignable to parameter of type '(value: unknown) => any'. + // Types of parameters 'rows' and 'value' are incompatible. + // Type 'unknown' is not assignable to type 'string | any[]'. + // Type 'unknown' is not assignable to type 'any[]'.ts(2345) + // @ts-ignore + return Conversation.getXidRecord(xid, zid).then((rows: string | any[]) => { + if (!rows || !rows.length) { + return "noXidRecord"; + } + let xidRecordForPtpt = rows[0]; + if (xidRecordForPtpt) { + return getPidPromise(zid, xidRecordForPtpt.uid, true).then( + (pidForXid: any) => { + xidRecordForPtpt.pid = pidForXid; + return xidRecordForPtpt; + } + ); + } + return xidRecordForPtpt; + }); +} + +export { + pidCache, + getUserInfoForUid, + getUserInfoForUid2, + addLtiUserIfNeeded, + addLtiContextMembership, + renderLtiLinkageSuccessPage, + getUser, + createDummyUser, + getPid, + getPidPromise, + getPidForParticipant, + getSocialInfoForUsers, +}; + +export default { + pidCache, + getXidRecordByXidOwnerId, + getXidStuff, + getUserInfoForUid, + getUserInfoForUid2, + addLtiUserIfNeeded, + addLtiContextMembership, + renderLtiLinkageSuccessPage, + getUser, + createDummyUser, + getPid, + getPidPromise, + getPidForParticipant, + getSocialInfoForUsers, +}; diff --git a/server/src/utils/common.js b/server/src/utils/common.ts similarity index 56% rename from server/src/utils/common.js rename to server/src/utils/common.ts index b7b18ec57..f645c1391 100644 --- a/server/src/utils/common.js +++ b/server/src/utils/common.ts @@ -1,6 +1,32 @@ -const _ = require("underscore"); +import _ from "underscore"; -function strToHex(str) { +type PolisTypes = { + reactions: Reactions; + staractions: StarActions; + mod: Mod; + reactionValues?: any; + starValues?: any; +}; + +type Reactions = { + push: number; + pull: number; + see: number; + pass: number; +}; + +type StarActions = { + unstar: number; + star: number; +}; + +type Mod = { + ban: number; + unmoderated: number; + ok: number; +}; + +function strToHex(str: string) { let hex, i; // let str = "\u6f22\u5b57"; // "\u6f22\u5b57" === "漢字" let result = ""; @@ -11,7 +37,7 @@ function strToHex(str) { return result; } -function hexToStr(hexString) { +function hexToStr(hexString: string) { let j; let hexes = hexString.match(/.{1,4}/g) || []; let str = ""; @@ -21,7 +47,7 @@ function hexToStr(hexString) { return str; } -let polisTypes = { +let polisTypes: PolisTypes = { reactions: { push: 1, pull: -1, @@ -41,8 +67,6 @@ let polisTypes = { polisTypes.reactionValues = _.values(polisTypes.reactions); polisTypes.starValues = _.values(polisTypes.staractions); -module.exports = { - strToHex, - hexToStr, - polisTypes, -}; +export { strToHex, hexToStr, polisTypes }; + +export default { strToHex, hexToStr, polisTypes }; diff --git a/server/src/utils/constants.js b/server/src/utils/constants.ts similarity index 81% rename from server/src/utils/constants.js rename to server/src/utils/constants.ts index a29546dee..f0de72098 100644 --- a/server/src/utils/constants.js +++ b/server/src/utils/constants.ts @@ -6,6 +6,8 @@ const DEFAULTS = { auth_opt_tw: true, }; -module.exports = { +export { DEFAULTS }; + +export default { DEFAULTS, }; diff --git a/server/src/utils/cookies.js b/server/src/utils/cookies.ts similarity index 61% rename from server/src/utils/cookies.js rename to server/src/utils/cookies.ts index 4d0f6fdcc..3e948e06b 100644 --- a/server/src/utils/cookies.js +++ b/server/src/utils/cookies.ts @@ -1,6 +1,20 @@ -const _ = require("underscore"); -const User = require("../user"); -const Session = require("../session"); +import _ from "underscore"; + +import User from "../user"; +import Session from "../session"; + +type Options = { + maxAge?: number; + path?: string; + httpOnly?: boolean; + secure?: any; + domain?: any; +}; + +type Req = { + headers?: { origin: string }; + cookies: { [x: string]: any }; +}; const COOKIES = { COOKIE_TEST: "ct", @@ -28,8 +42,15 @@ const COOKIES_TO_CLEAR = { let oneYear = 1000 * 60 * 60 * 24 * 365; -function setCookie(req, res, setOnPolisDomain, name, value, options) { - let o = _.clone(options || {}); +function setCookie( + req: any, + res: { cookie: (arg0: any, arg1: any, arg2: any) => void }, + setOnPolisDomain: any, + name: string, + value: number, + options: Options +) { + let o: Options = _.clone(options || {}); o.path = _.isUndefined(o.path) ? "/" : o.path; o.maxAge = _.isUndefined(o.maxAge) ? oneYear : o.maxAge; if (setOnPolisDomain) { @@ -42,19 +63,34 @@ function setCookie(req, res, setOnPolisDomain, name, value, options) { res.cookie(name, value, o); } -function setParentReferrerCookie(req, res, setOnPolisDomain, referrer) { +function setParentReferrerCookie( + req: any, + res: any, + setOnPolisDomain: any, + referrer: any +) { setCookie(req, res, setOnPolisDomain, COOKIES.PARENT_REFERRER, referrer, { httpOnly: true, }); } -function setParentUrlCookie(req, res, setOnPolisDomain, parent_url) { +function setParentUrlCookie( + req: any, + res: any, + setOnPolisDomain: any, + parent_url: any +) { setCookie(req, res, setOnPolisDomain, COOKIES.PARENT_URL, parent_url, { httpOnly: true, }); } -function setPlanCookie(req, res, setOnPolisDomain, planNumber) { +function setPlanCookie( + req: any, + res: any, + setOnPolisDomain: boolean, + planNumber: number +) { if (planNumber > 0) { setCookie(req, res, setOnPolisDomain, COOKIES.PLAN_NUMBER, planNumber, { // not httpOnly - needed by JS @@ -63,7 +99,12 @@ function setPlanCookie(req, res, setOnPolisDomain, planNumber) { // else falsy } -function setHasEmailCookie(req, res, setOnPolisDomain, email) { +function setHasEmailCookie( + req: any, + res: any, + setOnPolisDomain: boolean, + email: any +) { if (email) { setCookie(req, res, setOnPolisDomain, COOKIES.HAS_EMAIL, 1, { // not httpOnly - needed by JS @@ -72,7 +113,12 @@ function setHasEmailCookie(req, res, setOnPolisDomain, email) { // else falsy } -function setUserCreatedTimestampCookie(req, res, setOnPolisDomain, timestamp) { +function setUserCreatedTimestampCookie( + req: any, + res: any, + setOnPolisDomain: boolean, + timestamp: any +) { setCookie( req, res, @@ -85,42 +131,61 @@ function setUserCreatedTimestampCookie(req, res, setOnPolisDomain, timestamp) { ); } -function setTokenCookie(req, res, setOnPolisDomain, token) { +function setTokenCookie( + req: any, + res: any, + setOnPolisDomain: boolean, + token: any +) { setCookie(req, res, setOnPolisDomain, COOKIES.TOKEN, token, { httpOnly: true, }); } -function setUidCookie(req, res, setOnPolisDomain, uid) { +function setUidCookie(req: any, res: any, setOnPolisDomain: boolean, uid: any) { setCookie(req, res, setOnPolisDomain, COOKIES.UID, uid, { // not httpOnly - needed by JS }); } -function setPermanentCookie(req, res, setOnPolisDomain, token) { +function setPermanentCookie( + req: any, + res: any, + setOnPolisDomain: boolean, + token: any +) { setCookie(req, res, setOnPolisDomain, COOKIES.PERMANENT_COOKIE, token, { httpOnly: true, }); } -function setCookieTestCookie(req, res, setOnPolisDomain) { +function setCookieTestCookie(req: any, res: any, setOnPolisDomain: any) { setCookie(req, res, setOnPolisDomain, COOKIES.COOKIE_TEST, 1, { // not httpOnly - needed by JS }); } -function shouldSetCookieOnPolisDomain(req) { +function shouldSetCookieOnPolisDomain(req: Req) { // FIXME domainOverride let setOnPolisDomain = !(process.env.DOMAIN_OVERRIDE || null); - let origin = req.headers.origin || ""; + let origin = req?.headers?.origin || ""; if (setOnPolisDomain && origin.match(/^http:\/\/localhost:[0-9]{4}/)) { setOnPolisDomain = false; } return setOnPolisDomain; } -function addCookies(req, res, token, uid) { - return User.getUserInfoForUid2(uid).then(function (o) { +function addCookies( + req: { cookies: { [x: string]: any } }, + res: { header: (arg0: string, arg1: any) => void }, + token: any, + uid: any +) { + return User.getUserInfoForUid2(uid).then(function (o: { + email: any; + created: any; + plan: any; + }) { let email = o.email; let created = o.created; let plan = o.plan; @@ -144,7 +209,10 @@ function addCookies(req, res, token, uid) { }); } -function getPermanentCookieAndEnsureItIsSet(req, res) { +function getPermanentCookieAndEnsureItIsSet( + req: { cookies: { [x: string]: any } }, + res: any +) { let setOnPolisDomain = shouldSetCookieOnPolisDomain(req); if (!req.cookies[COOKIES.PERMANENT_COOKIE]) { let token = Session.makeSessionToken(); @@ -155,7 +223,21 @@ function getPermanentCookieAndEnsureItIsSet(req, res) { } } -module.exports = { +export { + COOKIES, + COOKIES_TO_CLEAR, + setCookie, + setParentReferrerCookie, + setParentUrlCookie, + setPlanCookie, + setPermanentCookie, + setCookieTestCookie, + shouldSetCookieOnPolisDomain, + addCookies, + getPermanentCookieAndEnsureItIsSet, +}; + +export default { COOKIES, COOKIES_TO_CLEAR, setCookie, diff --git a/server/src/utils/metered.js b/server/src/utils/metered.js deleted file mode 100644 index 23bc1cbdb..000000000 --- a/server/src/utils/metered.js +++ /dev/null @@ -1,59 +0,0 @@ -// metric name => { -// values: [circular buffers of values (holds 1000 items)] -// index: index in circular buffer -//} -const METRICS_IN_RAM = {}; -const SHOULD_ADD_METRICS_IN_RAM = false; - -function addInRamMetric(metricName, val) { - if (!SHOULD_ADD_METRICS_IN_RAM) { - return; - } - if (!METRICS_IN_RAM[metricName]) { - METRICS_IN_RAM[metricName] = { - values: new Array(1000), - index: 0, - }; - } - let index = METRICS_IN_RAM[metricName].index; - METRICS_IN_RAM[metricName].values[index] = val; - METRICS_IN_RAM[metricName].index = (index + 1) % 1000; -} - -// metered promise -function MPromise(name, f) { - let p = new Promise(f); - let start = Date.now(); - setTimeout(function () { - addInRamMetric(name + ".go", 1, start); - }, 100); - p.then( - function () { - let end = Date.now(); - let duration = end - start; - setTimeout(function () { - addInRamMetric(name + ".ok", duration, end); - }, 100); - }, - function () { - let end = Date.now(); - let duration = end - start; - setTimeout(function () { - addInRamMetric(name + ".fail", duration, end); - }, 100); - } - ).catch(function (err) { - let end = Date.now(); - let duration = end - start; - setTimeout(function () { - addInRamMetric(name + ".fail", duration, end); - console.log("MPromise internal error"); - }, 100); - }); - return p; -} - -module.exports = { - addInRamMetric, - MPromise, -}; diff --git a/server/src/utils/metered.ts b/server/src/utils/metered.ts new file mode 100644 index 000000000..22de5ad78 --- /dev/null +++ b/server/src/utils/metered.ts @@ -0,0 +1,83 @@ +type MetricsInRam = { + [key: string]: any; +}; + +// metric name => { +// values: [circular buffers of values (holds 1000 items)] +// index: index in circular buffer +//} +export const METRICS_IN_RAM: MetricsInRam = {}; +const SHOULD_ADD_METRICS_IN_RAM = false; + +export function addInRamMetric(metricName: string, val: number) { + if (!SHOULD_ADD_METRICS_IN_RAM) { + return; + } + if (!METRICS_IN_RAM[metricName]) { + METRICS_IN_RAM[metricName] = { + values: new Array(1000), + index: 0, + }; + } + let index = METRICS_IN_RAM[metricName].index; + METRICS_IN_RAM[metricName].values[index] = val; + METRICS_IN_RAM[metricName].index = (index + 1) % 1000; +} + +// metered promise +export function MPromise( + name: string, + f: (resolve: (value: unknown) => void, reject: (reason?: any) => void) => void +) { + let p = new Promise(f); + let start = Date.now(); + setTimeout(function () { + // TODO either add this arg to the function definition + // TODO or remove this arg from the function call + // TS2554: Expected 2 arguments, but got 3. + // 35 addInRamMetric(name + ".go", 1, start); + // @ts-ignore ~~~~~ + addInRamMetric(name + ".go", 1, start); + }, 100); + p.then( + function () { + let end = Date.now(); + let duration = end - start; + setTimeout(function () { + // TODO either add this arg to the function definition + // TODO or remove this arg from the function call + // TS2554: Expected 2 arguments, but got 3. + // 45 addInRamMetric(name + ".ok", duration, end); + // @ts-ignore + addInRamMetric(name + ".ok", duration, end); + }, 100); + }, + function () { + let end = Date.now(); + let duration = end - start; + setTimeout(function () { + // TODO either add this arg to the function definition + // TODO or remove this arg from the function call + // TS2554: Expected 2 arguments, but got 3. + // 59 addInRamMetric(name + ".fail", duration, end); + // @ts-ignore + addInRamMetric(name + ".fail", duration, end); + }, 100); + } + ).catch(function (err) { + let end = Date.now(); + let duration = end - start; + setTimeout(function () { + // TODO either add this arg to the function definition + // TODO or remove this arg from the function call + // TS2554: Expected 2 arguments, but got 3. + // 73 addInRamMetric(name + ".fail", duration, end); + // @ts-ignore + addInRamMetric(name + ".fail", duration, end); + console.log("MPromise internal error"); + }, 100); + }); + return p; +} + +export default { addInRamMetric, MPromise }; diff --git a/server/src/utils/parameter.js b/server/src/utils/parameter.ts similarity index 61% rename from server/src/utils/parameter.js rename to server/src/utils/parameter.ts index 6c7c055db..06ae194cb 100644 --- a/server/src/utils/parameter.js +++ b/server/src/utils/parameter.ts @@ -1,14 +1,24 @@ -const _ = require("underscore"); -const pg = require("../db/pg-query"); -const MPromise = require("./metered").MPromise; -const Log = require("../log"); -const Conversation = require("../conversation"); -const User = require("../user"); -const isValidUrl = require("valid-url"); -const LruCache = require("lru-cache"); +import _ from "underscore"; +import { isUri } from "valid-url"; +import LruCache from "lru-cache"; + +import pg from "../db/pg-query"; +import Log from "../log"; +import Conversation from "../conversation"; +import User from "../user"; + +import { MPromise } from "./metered"; + +type Req = { + query?: any; + body?: { [x: string]: any }; + params?: any; + p?: { zid?: any; uid?: any }; + cookies: { [x: string]: any }; +}; // Consolidate query/body items in one place so other middleware has one place to look. -function moveToBody(req, res, next) { +function moveToBody(req: Req, res: any, next: () => void) { if (req.query) { req.body = req.body || {}; Object.assign(req.body, req.query); @@ -17,12 +27,12 @@ function moveToBody(req, res, next) { req.body = req.body || {}; Object.assign(req.body, req.params); } - // inti req.p if not there already + // init req.p if not there already req.p = req.p || {}; next(); } -function need(name, parserWhichReturnsPromise, assigner) { +function need(name: any, parserWhichReturnsPromise: any, assigner: any) { return buildCallback({ name: name, extractor: extractFromBody, @@ -32,7 +42,12 @@ function need(name, parserWhichReturnsPromise, assigner) { }); } -function want(name, parserWhichReturnsPromise, assigner, defaultVal) { +function want( + name: any, + parserWhichReturnsPromise: any, + assigner: any, + defaultVal: any +) { return buildCallback({ name: name, extractor: extractFromBody, @@ -43,7 +58,7 @@ function want(name, parserWhichReturnsPromise, assigner, defaultVal) { }); } -function needCookie(name, parserWhichReturnsPromise, assigner) { +function needCookie(name: any, parserWhichReturnsPromise: any, assigner: any) { return buildCallback({ name: name, extractor: extractFromCookie, @@ -53,7 +68,12 @@ function needCookie(name, parserWhichReturnsPromise, assigner) { }); } -function wantCookie(name, parserWhichReturnsPromise, assigner, defaultVal) { +function wantCookie( + name: any, + parserWhichReturnsPromise: any, + assigner: any, + defaultVal: any +) { return buildCallback({ name: name, extractor: extractFromCookie, @@ -64,7 +84,12 @@ function wantCookie(name, parserWhichReturnsPromise, assigner, defaultVal) { }); } -function needHeader(name, parserWhichReturnsPromise, assigner, defaultVal) { +function needHeader( + name: any, + parserWhichReturnsPromise: any, + assigner: any, + defaultVal: any +) { return buildCallback({ name: name, extractor: extractFromHeader, @@ -75,7 +100,12 @@ function needHeader(name, parserWhichReturnsPromise, assigner, defaultVal) { }); } -function wantHeader(name, parserWhichReturnsPromise, assigner, defaultVal) { +function wantHeader( + name: any, + parserWhichReturnsPromise: any, + assigner: any, + defaultVal: any +) { return buildCallback({ name: name, extractor: extractFromHeader, @@ -86,28 +116,41 @@ function wantHeader(name, parserWhichReturnsPromise, assigner, defaultVal) { }); } -function extractFromBody(req, name) { +function extractFromBody(req: Req, name: string | number) { if (!req.body) { return void 0; } return req.body[name]; } -function extractFromCookie(req, name) { +function extractFromCookie( + req: { cookies: { [x: string]: any } }, + name: string | number +) { if (!req.cookies) { return void 0; } return req.cookies[name]; } -function extractFromHeader(req, name) { +function extractFromHeader( + req: { headers: { [x: string]: any } }, + name: string +) { if (!req.headers) { return void 0; } return req.headers[name.toLowerCase()]; } -function buildCallback(config) { +function buildCallback(config: { + name: any; + extractor: any; + parserWhichReturnsPromise: any; + assigner: any; + required: any; + defaultVal?: any; +}) { let name = config.name; let parserWhichReturnsPromise = config.parserWhichReturnsPromise; let assigner = config.assigner; @@ -122,16 +165,20 @@ function buildCallback(config) { throw "bad arg for parserWhichReturnsPromise"; } - return function (req, res, next) { + return function ( + req: any, + res: { status: (arg0: number) => void }, + next: (arg0?: string) => void + ) { let val = extractor(req, name); if (!_.isUndefined(val) && !_.isNull(val)) { parserWhichReturnsPromise(val) .then( - function (parsed) { + function (parsed: any) { assigner(req, name, parsed); next(); }, - function (e) { + function (e: any) { let s = "polis_err_param_parse_failed_" + name; console.error(s); console.error(e); @@ -141,7 +188,7 @@ function buildCallback(config) { return; } ) - .catch(function (err) { + .catch(function (err: any) { Log.fail(res, "polis_err_misc", err); return; }); @@ -161,11 +208,11 @@ function buildCallback(config) { }; } -function isEmail(s) { +function isEmail(s: string | string[]) { return typeof s === "string" && s.length < 999 && s.indexOf("@") > 0; } -function getEmail(s) { +function getEmail(s: string) { return new Promise(function (resolve, reject) { if (!isEmail(s)) { return reject("polis_fail_parse_email"); @@ -174,7 +221,7 @@ function getEmail(s) { }); } -function getPassword(s) { +function getPassword(s: string) { return new Promise(function (resolve, reject) { if (typeof s !== "string" || s.length > 999 || s.length === 0) { return reject("polis_fail_parse_password"); @@ -183,7 +230,7 @@ function getPassword(s) { }); } -function getPasswordWithCreatePasswordRules(s) { +function getPasswordWithCreatePasswordRules(s: any) { return getPassword(s).then(function (s) { if (typeof s !== "string" || s.length < 6) { throw new Error("polis_err_password_too_short"); @@ -192,8 +239,8 @@ function getPasswordWithCreatePasswordRules(s) { }); } -function getOptionalStringLimitLength(limit) { - return function (s) { +function getOptionalStringLimitLength(limit: number) { + return function (s: string) { return new Promise(function (resolve, reject) { if (s.length && s.length > limit) { return reject("polis_fail_parse_string_too_long"); @@ -205,17 +252,17 @@ function getOptionalStringLimitLength(limit) { }; } -function getStringLimitLength(min, max) { +function getStringLimitLength(min: number, max?: number) { if (_.isUndefined(max)) { max = min; min = 1; } - return function (s) { + return function (s: string): Promise { return new Promise(function (resolve, reject) { if (typeof s !== "string") { return reject("polis_fail_parse_string_missing"); } - if (s.length && s.length > max) { + if (s.length && s.length > (max as number)) { return reject("polis_fail_parse_string_too_long"); } if (s.length && s.length < min) { @@ -228,11 +275,11 @@ function getStringLimitLength(min, max) { }; } -function getUrlLimitLength(limit) { - return function (s) { +function getUrlLimitLength(limit: any) { + return function (s: any) { getStringLimitLength(limit)(s).then(function (s) { return new Promise(function (resolve, reject) { - if (isValidUrl(s)) { + if (isUri(s)) { return resolve(s); } else { return reject("polis_fail_parse_url_invalid"); @@ -242,12 +289,12 @@ function getUrlLimitLength(limit) { }; } -function getInt(s) { +function getInt(s: string): Promise { return new Promise(function (resolve, reject) { if (_.isNumber(s) && s >> 0 === s) { return resolve(s); } - let x = parseInt(s); + let x: number = parseInt(s); if (isNaN(x)) { return reject("polis_fail_parse_int " + s); } @@ -255,7 +302,7 @@ function getInt(s) { }); } -function getBool(s) { +function getBool(s: string | number) { return new Promise(function (resolve, reject) { let type = typeof s; if ("boolean" === type) { @@ -267,7 +314,7 @@ function getBool(s) { } return resolve(true); } - s = s.toLowerCase(); + s = (s as string).toLowerCase(); if (s === "t" || s === "true" || s === "on" || s === "1") { return resolve(true); } else if (s === "f" || s === "false" || s === "off" || s === "0") { @@ -277,9 +324,9 @@ function getBool(s) { }); } -function getIntInRange(min, max) { - return function (s) { - return getInt(s).then(function (x) { +function getIntInRange(min: number, max: number) { + return function (s: string): Promise { + return getInt(s).then(function (x: number) { if (x < min || max < x) { throw "polis_fail_parse_int_out_of_range"; } @@ -294,38 +341,52 @@ const reportIdToRidCache = new LruCache({ const getZidFromConversationId = Conversation.getZidFromConversationId; -function getRidFromReportId(report_id) { - return new MPromise("getRidFromReportId", function (resolve, reject) { - let cachedRid = reportIdToRidCache.get(report_id); - if (cachedRid) { - resolve(cachedRid); - return; - } - pg.query_readOnly( - "select rid from reports where report_id = ($1);", - [report_id], - function (err, results) { - if (err) { - return reject(err); - } else if (!results || !results.rows || !results.rows.length) { - console.error("polis_err_fetching_rid_for_report_id " + report_id); - return reject("polis_err_fetching_rid_for_report_id"); - } else { - let rid = results.rows[0].rid; - reportIdToRidCache.set(report_id, rid); - return resolve(rid); - } +function getRidFromReportId(report_id: string) { + // TS7009: 'new' expression, whose target lacks a construct signature, implicitly has an 'any' type. + // 344 return new MPromise( + // ~~~~~~~~~~~~~ + // 345 "getRidFromReportId", + // ~~~~~~~~~~~~~~~~~~~~~~~~~ + // ... + // 368 } + // ~~~~~ + // 369 ); + // ~~~ + // @ts-ignore + return new MPromise( + "getRidFromReportId", + function (resolve: any, reject: any) { + let cachedRid = reportIdToRidCache.get(report_id); + if (cachedRid) { + resolve(cachedRid); + return; } - ); - }); + pg.query_readOnly( + "select rid from reports where report_id = ($1);", + [report_id], + function (err: any, results: { rows: string | any[] }) { + if (err) { + return reject(err); + } else if (!results || !results.rows || !results.rows.length) { + console.error("polis_err_fetching_rid_for_report_id " + report_id); + return reject("polis_err_fetching_rid_for_report_id"); + } else { + let rid = results.rows[0].rid; + reportIdToRidCache.set(report_id, rid); + return resolve(rid); + } + } + ); + } + ); } // conversation_id is the client/ public API facing string ID const parseConversationId = getStringLimitLength(1, 100); -function getConversationIdFetchZid(s) { +function getConversationIdFetchZid(s: any) { return parseConversationId(s).then(function (conversation_id) { - return getZidFromConversationId(conversation_id).then(function (zid) { + return getZidFromConversationId(conversation_id).then(function (zid: any) { return Number(zid); }); }); @@ -333,22 +394,22 @@ function getConversationIdFetchZid(s) { const parseReportId = getStringLimitLength(1, 100); -function getReportIdFetchRid(s) { +function getReportIdFetchRid(s: any) { return parseReportId(s).then(function (report_id) { console.log(report_id); - return getRidFromReportId(report_id).then(function (rid) { + return getRidFromReportId(report_id).then(function (rid: any) { console.log(rid); return Number(rid); }); }); } -function getNumber(s) { +function getNumber(s: string): Promise { return new Promise(function (resolve, reject) { if (_.isNumber(s)) { return resolve(s); } - let x = parseFloat(s); + let x: number = parseFloat(s); if (isNaN(x)) { return reject("polis_fail_parse_number"); } @@ -356,9 +417,9 @@ function getNumber(s) { }); } -function getNumberInRange(min, max) { - return function (s) { - return getNumber(s).then(function (x) { +function getNumberInRange(min: number, max: number) { + return function (s: string) { + return getNumber(s).then(function (x: number) { if (x < min || max < x) { throw "polis_fail_parse_number_out_of_range"; } @@ -367,38 +428,43 @@ function getNumberInRange(min, max) { }; } -function getArrayOfString(a, maxStrings, maxLength) { +function getArrayOfString( + a: string, + maxStrings?: undefined, + maxLength?: undefined +): Promise { return new Promise(function (resolve, reject) { + let result; if (_.isString(a)) { - a = a.split(","); + result = a.split(","); } - if (!_.isArray(a)) { + if (!_.isArray(result)) { return reject("polis_fail_parse_int_array"); } - resolve(a); + resolve(result); }); } -function getArrayOfStringNonEmpty(a, maxStrings, maxLength) { +function getArrayOfStringNonEmpty(a: string, maxStrings: any, maxLength: any) { if (!a || !a.length) { return Promise.reject("polis_fail_parse_string_array_empty"); } return getArrayOfString(a); } -function getArrayOfStringLimitLength(maxStrings, maxLength) { - return function (a) { +function getArrayOfStringLimitLength(maxStrings: any, maxLength: any) { + return function (a: any) { return getArrayOfString(a, maxStrings || 999999999, maxLength); }; } -function getArrayOfStringNonEmptyLimitLength(maxStrings, maxLength) { - return function (a) { +function getArrayOfStringNonEmptyLimitLength(maxStrings: any, maxLength: any) { + return function (a: any) { return getArrayOfStringNonEmpty(a, maxStrings || 999999999, maxLength); }; } -function getArrayOfInt(a) { +function getArrayOfInt(a: string[]) { if (_.isString(a)) { a = a.split(","); } @@ -406,13 +472,13 @@ function getArrayOfInt(a) { return Promise.reject("polis_fail_parse_int_array"); } - function integer(i) { + function integer(i: any) { return Number(i) >> 0; } return Promise.resolve(a.map(integer)); } -function assignToP(req, name, x) { +function assignToP(req: { p: { [x: string]: any } }, name: string, x: any) { req.p = req.p || {}; if (!_.isUndefined(req.p[name])) { let s = "clobbering " + name; @@ -422,17 +488,21 @@ function assignToP(req, name, x) { req.p[name] = x; } -function assignToPCustom(name) { - return function (req, ignoredName, x) { +function assignToPCustom(name: any) { + return function (req: any, ignoredName: any, x: any) { assignToP(req, name, x); }; } -function resolve_pidThing(pidThingStringName, assigner, loggingString) { +function resolve_pidThing( + pidThingStringName: any, + assigner: (arg0: any, arg1: any, arg2: number) => void, + loggingString: string +) { if (_.isUndefined(loggingString)) { loggingString = ""; } - return function (req, res, next) { + return function (req: Req, res: any, next: (arg0?: string) => void) { if (!req.p) { Log.fail( res, @@ -447,15 +517,15 @@ function resolve_pidThing(pidThingStringName, assigner, loggingString) { extractFromBody(req, pidThingStringName) || extractFromCookie(req, pidThingStringName); - if (existingValue === "mypid" && req.p.zid && req.p.uid) { + if (existingValue === "mypid" && req?.p?.zid && req.p.uid) { User.getPidPromise(req.p.zid, req.p.uid) - .then(function (pid) { + .then(function (pid: number) { if (pid >= 0) { assigner(req, pidThingStringName, pid); } next(); }) - .catch(function (err) { + .catch(function (err: any) { Log.fail(res, 500, "polis_err_mypid_resolve_error", err); next(err); }); @@ -464,7 +534,7 @@ function resolve_pidThing(pidThingStringName, assigner, loggingString) { next(); } else if (!_.isUndefined(existingValue)) { getInt(existingValue) - .then(function (pidNumber) { + .then(function (pidNumber: number) { assigner(req, pidThingStringName, pidNumber); next(); }) @@ -478,7 +548,35 @@ function resolve_pidThing(pidThingStringName, assigner, loggingString) { }; } -module.exports = { +export { + assignToP, + assignToPCustom, + getArrayOfInt, + getArrayOfStringNonEmpty, + getArrayOfStringNonEmptyLimitLength, + getBool, + getConversationIdFetchZid, + getEmail, + getInt, + getIntInRange, + getNumberInRange, + getOptionalStringLimitLength, + getPassword, + getPasswordWithCreatePasswordRules, + getReportIdFetchRid, + getStringLimitLength, + getUrlLimitLength, + moveToBody, + need, + needCookie, + needHeader, + resolve_pidThing, + want, + wantCookie, + wantHeader, +}; + +export default { assignToP, assignToPCustom, getArrayOfInt, diff --git a/server/tsconfig.json b/server/tsconfig.json new file mode 100644 index 000000000..61ac8a8e3 --- /dev/null +++ b/server/tsconfig.json @@ -0,0 +1,82 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig.json to read more about this file */ + + /* Basic Options */ + // "incremental": true, /* Enable incremental compilation */ + "target": "es5" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */, + "module": "CommonJS" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */, + // "lib": [], /* Specify library files to be included in the compilation. */ + "allowJs": true /* Allow javascript files to be compiled. */, + // "checkJs": true, /* Report errors in .js files. */ + // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */ + // "declaration": true, /* Generates corresponding '.d.ts' file. */ + // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ + // "sourceMap": true, /* Generates corresponding '.map' file. */ + // "outFile": "./dist/app.js" /* Concatenate and emit output to single file. */, + "outDir": "./dist" /* Redirect output structure to the directory. */, + "rootDir": "./" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */, + // "composite": true, /* Enable project compilation */ + // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ + // "removeComments": true, /* Do not emit comments to output. */ + // "noEmit": true, /* Do not emit outputs. */ + // "importHelpers": true, /* Import emit helpers from 'tslib'. */ + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + + /* Strict Type-Checking Options */ + "strict": true /* Enable all strict type-checking options. */, + // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ + // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ + // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + + /* Additional Checks */ + // "noUnusedLocals": true, /* Report errors on unused locals. */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ + // "noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */ + + /* Module Resolution Options */ + "moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */, + "baseUrl": "./" /* Base directory to resolve non-absolute module names. */, + "paths": { + "*": [ + "*", + "src/*", + "src/auth/*", + "src/db/*", + "src/email/*", + "src/utils/*" + ] + } /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */, + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ + // "typeRoots": [], /* List of folders to include type definitions from. */ + // "types": [], /* Type declaration files to be included in compilation. */ + // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ + "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + + /* Source Map Options */ + // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + + /* Experimental Options */ + // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + + /* Advanced Options */ + "skipLibCheck": true /* Skip type checking of declaration files. */, + "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ + }, + "include": ["app.ts", "src/**/*", "types/**/*"], + "exclude": ["node_modules", "**/*.spec.ts", "dist"] +} diff --git a/server/types/akismet.d.ts b/server/types/akismet.d.ts new file mode 100644 index 000000000..7770b6ff7 --- /dev/null +++ b/server/types/akismet.d.ts @@ -0,0 +1 @@ +declare module "akismet"; diff --git a/server/types/badwords.d.ts b/server/types/badwords.d.ts new file mode 100644 index 000000000..c59cd89fd --- /dev/null +++ b/server/types/badwords.d.ts @@ -0,0 +1 @@ +declare module "badwords/object"; diff --git a/server/types/boolean.d.ts b/server/types/boolean.d.ts new file mode 100644 index 000000000..ceeed26e5 --- /dev/null +++ b/server/types/boolean.d.ts @@ -0,0 +1 @@ +declare module "boolean"; diff --git a/server/types/google-cloud__translate.d.ts b/server/types/google-cloud__translate.d.ts new file mode 100644 index 000000000..f37956bc3 --- /dev/null +++ b/server/types/google-cloud__translate.d.ts @@ -0,0 +1 @@ +declare module "@google-cloud/translate"; diff --git a/server/types/slack.d.ts b/server/types/slack.d.ts new file mode 100644 index 000000000..49696426a --- /dev/null +++ b/server/types/slack.d.ts @@ -0,0 +1 @@ +declare module "@slack/client"; From a5fcb6464f7dbab6e31f62083f66eeefd6c89f8b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 22 Dec 2021 06:06:11 +0000 Subject: [PATCH 14/17] Bump actions/setup-java from 2.3.0 to 2.5.0 Bumps [actions/setup-java](https://github.com/actions/setup-java) from 2.3.0 to 2.5.0. - [Release notes](https://github.com/actions/setup-java/releases) - [Commits](https://github.com/actions/setup-java/compare/v2.3.0...v2.5.0) --- updated-dependencies: - dependency-name: actions/setup-java dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/test-clojure.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-clojure.yml b/.github/workflows/test-clojure.yml index 5b3bcf256..3b6ec0b29 100644 --- a/.github/workflows/test-clojure.yml +++ b/.github/workflows/test-clojure.yml @@ -20,7 +20,7 @@ jobs: - uses: actions/checkout@v2.3.4 - name: Prepare java - uses: actions/setup-java@v2.3.0 + uses: actions/setup-java@v2.5.0 with: distribution: adopt java-version: 16.0.2 From 2aecf6e1cbceb4a848da7e28848131798c7bedcf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Dec 2021 06:03:34 +0000 Subject: [PATCH 15/17] Bump node from 17.2.0-alpine to 17.3.0-alpine in /file-server Bumps node from 17.2.0-alpine to 17.3.0-alpine. --- updated-dependencies: - dependency-name: node dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- file-server/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/file-server/Dockerfile b/file-server/Dockerfile index 462aa922d..53673c1fd 100644 --- a/file-server/Dockerfile +++ b/file-server/Dockerfile @@ -4,7 +4,7 @@ FROM compdem/polis-client-admin:${TAG} as admin FROM compdem/polis-client-participation:${TAG} as participation FROM compdem/polis-client-report:${TAG} as report -FROM node:17.2.0-alpine +FROM node:17.3.0-alpine WORKDIR /app From 4054eb055bebad0ea1185a7eb6f024b2ea666ba9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Dec 2021 21:59:30 +0000 Subject: [PATCH 16/17] Bump DeLaGuardo/setup-clojure from 3.5 to 3.7 Bumps [DeLaGuardo/setup-clojure](https://github.com/DeLaGuardo/setup-clojure) from 3.5 to 3.7. - [Release notes](https://github.com/DeLaGuardo/setup-clojure/releases) - [Commits](https://github.com/DeLaGuardo/setup-clojure/compare/3.5...3.7) --- updated-dependencies: - dependency-name: DeLaGuardo/setup-clojure dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/test-clojure.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-clojure.yml b/.github/workflows/test-clojure.yml index 5b3bcf256..a7bda1660 100644 --- a/.github/workflows/test-clojure.yml +++ b/.github/workflows/test-clojure.yml @@ -20,13 +20,13 @@ jobs: - uses: actions/checkout@v2.3.4 - name: Prepare java - uses: actions/setup-java@v2.3.0 + uses: actions/setup-java@v2.5.0 with: distribution: adopt java-version: 16.0.2 - name: Install Clojure tooling - uses: DeLaGuardo/setup-clojure@3.5 + uses: DeLaGuardo/setup-clojure@3.7 with: cli: 1.10.1.693 From 0bb72840ade43799d8b20264456a39ddc567e1fc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Jan 2022 06:03:09 +0000 Subject: [PATCH 17/17] Bump nginx from 1.21.3-alpine to 1.21.5-alpine in /file-server Bumps nginx from 1.21.3-alpine to 1.21.5-alpine. --- updated-dependencies: - dependency-name: nginx dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- file-server/nginx.Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/file-server/nginx.Dockerfile b/file-server/nginx.Dockerfile index 7b36d0a18..cc85a8e53 100644 --- a/file-server/nginx.Dockerfile +++ b/file-server/nginx.Dockerfile @@ -1,4 +1,4 @@ -FROM nginx:1.21.3-alpine +FROM nginx:1.21.5-alpine COPY nginx/nginx-ssl.site.default.conf /etc/nginx/conf.d/default.conf