mirror of
https://github.com/wassname/talk.git
synced 2026-06-27 18:07:26 +08:00
linting + initial mutation
- added tslint - mutation support
This commit is contained in:
Vendored
+2
-1
@@ -10,5 +10,6 @@
|
||||
"dist": true,
|
||||
".vscode": true,
|
||||
"package-lock.json": true
|
||||
}
|
||||
},
|
||||
"tslint.autoFixOnSave": true
|
||||
}
|
||||
|
||||
@@ -21,3 +21,12 @@
|
||||
|
||||
1. No tenants
|
||||
2. Create a tenant <-- consuming the TMA
|
||||
|
||||
## Database connections
|
||||
|
||||
### Redis Clients
|
||||
|
||||
1. Tenant RedisPubSub Subscriber
|
||||
2. Tenant RedisPubSub Publisher
|
||||
3. Management RedisPubSub Subscriber
|
||||
4. Management RedisPubSub Publisher
|
||||
|
||||
Generated
+261
-1
@@ -148,6 +148,15 @@
|
||||
"integrity": "sha512-IsX9aDHDzJohkm3VCDB8tkzl5RQ34E/PFA29TQk6uDGb7Oc869ZBtmdKVDBzY3+h9GnXB8ssrRXEPVZrlIOPOw==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/passport": {
|
||||
"version": "0.4.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/passport/-/passport-0.4.5.tgz",
|
||||
"integrity": "sha512-Ow5akVXwEZlOPCWGbEGy0GX4ocdwKz7JJH1K+BMd/BSOxmJTo2obH2AKbsgcncQvw5z7AGopdIu1Ap/j9sMRnQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/express": "*"
|
||||
}
|
||||
},
|
||||
"@types/range-parser": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.2.tgz",
|
||||
@@ -207,6 +216,18 @@
|
||||
"string-width": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"ansi-regex": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
|
||||
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
|
||||
"dev": true
|
||||
},
|
||||
"ansi-styles": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
|
||||
"integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
|
||||
"dev": true
|
||||
},
|
||||
"anymatch": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz",
|
||||
@@ -348,6 +369,32 @@
|
||||
"integrity": "sha1-ri1acpR38onWDdf5amMUoi3Wwio=",
|
||||
"dev": true
|
||||
},
|
||||
"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=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chalk": "^1.1.3",
|
||||
"esutils": "^2.0.2",
|
||||
"js-tokens": "^3.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"chalk": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
|
||||
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"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"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"backo2": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz",
|
||||
@@ -541,6 +588,12 @@
|
||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.0.tgz",
|
||||
"integrity": "sha512-c5mRlguI/Pe2dSZmpER62rSCu0ryKmWddzRYsuXc50U2/g8jMOulc31VZMa4mYx31U5xsmSOpDCgH88Vl9cDGQ=="
|
||||
},
|
||||
"builtin-modules": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
|
||||
"integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=",
|
||||
"dev": true
|
||||
},
|
||||
"bunyan": {
|
||||
"version": "1.8.12",
|
||||
"resolved": "https://registry.npmjs.org/bunyan/-/bunyan-1.8.12.tgz",
|
||||
@@ -585,6 +638,37 @@
|
||||
"integrity": "sha1-Sm+gc5nCa7pH8LJJa00PtAjFVQ0=",
|
||||
"dev": true
|
||||
},
|
||||
"chalk": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz",
|
||||
"integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "^3.2.1",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
"supports-color": "^5.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-styles": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-convert": "^1.9.0"
|
||||
}
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "5.4.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz",
|
||||
"integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"chokidar": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.3.tgz",
|
||||
@@ -670,6 +754,12 @@
|
||||
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
|
||||
"dev": true
|
||||
},
|
||||
"commander": {
|
||||
"version": "2.15.1",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz",
|
||||
"integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==",
|
||||
"dev": true
|
||||
},
|
||||
"component-emitter": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
|
||||
@@ -939,11 +1029,27 @@
|
||||
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
|
||||
"dev": true
|
||||
},
|
||||
"eslint-plugin-prettier": {
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-2.6.0.tgz",
|
||||
"integrity": "sha512-floiaI4F7hRkTrFe8V2ItOK97QYrX75DjmdzmVITZoAP6Cn06oEDPQRsO6MlHEP/u2SxI3xQ52Kpjw6j5WGfeQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fast-diff": "^1.1.1",
|
||||
"jest-docblock": "^21.0.0"
|
||||
}
|
||||
},
|
||||
"esprima": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz",
|
||||
"integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw=="
|
||||
},
|
||||
"esutils": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
|
||||
"integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
|
||||
"dev": true
|
||||
},
|
||||
"etag": {
|
||||
"version": "1.8.1",
|
||||
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
|
||||
@@ -1150,6 +1256,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"fast-diff": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.1.2.tgz",
|
||||
"integrity": "sha512-KaJUt+M9t1qaIteSvjc6P3RbMdXsNhK61GRftR6SNxqmhthcd9MGIi4T+o0jD8LUSpSnSKXE20nLtJ3fOHxQig==",
|
||||
"dev": true
|
||||
},
|
||||
"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",
|
||||
@@ -1228,6 +1340,12 @@
|
||||
"integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=",
|
||||
"dev": true
|
||||
},
|
||||
"fs.realpath": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
|
||||
"dev": true
|
||||
},
|
||||
"fsevents": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.4.tgz",
|
||||
@@ -1945,6 +2063,21 @@
|
||||
"uuid": "^3.1.0"
|
||||
}
|
||||
},
|
||||
"has-ansi": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
|
||||
"integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"has-flag": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
|
||||
"dev": true
|
||||
},
|
||||
"has-value": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
|
||||
@@ -2020,7 +2153,6 @@
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
||||
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"once": "^1.3.0",
|
||||
"wrappy": "1"
|
||||
@@ -2314,6 +2446,12 @@
|
||||
"resolved": "https://registry.npmjs.org/iterall/-/iterall-1.2.2.tgz",
|
||||
"integrity": "sha512-yynBb1g+RFUPY64fTrFv7nsjRrENBQJaX2UL+2Szc9REFrSNm1rpSXHGzhmAy7a9uv3vlvgBlXnf9RqmPH1/DA=="
|
||||
},
|
||||
"jest-docblock": {
|
||||
"version": "21.2.0",
|
||||
"resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-21.2.0.tgz",
|
||||
"integrity": "sha512-5IZ7sY9dBAYSV+YjQ0Ovb540Ku7AO9Z5o2Cg789xj167iQuZ2cG+z0f3Uct6WeYLbU6aQiM2pCs7sZ+4dotydw==",
|
||||
"dev": true
|
||||
},
|
||||
"joi": {
|
||||
"version": "13.4.0",
|
||||
"resolved": "https://registry.npmjs.org/joi/-/joi-13.4.0.tgz",
|
||||
@@ -2324,6 +2462,12 @@
|
||||
"topo": "3.x.x"
|
||||
}
|
||||
},
|
||||
"js-tokens": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
|
||||
"integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=",
|
||||
"dev": true
|
||||
},
|
||||
"js-yaml": {
|
||||
"version": "3.12.0",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz",
|
||||
@@ -2856,6 +3000,20 @@
|
||||
"integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=",
|
||||
"dev": true
|
||||
},
|
||||
"passport": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/passport/-/passport-0.4.0.tgz",
|
||||
"integrity": "sha1-xQlWkTR71a07XhgCOMORTRbwWBE=",
|
||||
"requires": {
|
||||
"passport-strategy": "1.x.x",
|
||||
"pause": "0.0.1"
|
||||
}
|
||||
},
|
||||
"passport-strategy": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz",
|
||||
"integrity": "sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ="
|
||||
},
|
||||
"path-dirname": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz",
|
||||
@@ -2879,11 +3037,22 @@
|
||||
"integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=",
|
||||
"dev": true
|
||||
},
|
||||
"path-parse": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz",
|
||||
"integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=",
|
||||
"dev": true
|
||||
},
|
||||
"path-to-regexp": {
|
||||
"version": "0.1.7",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
|
||||
"integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
|
||||
},
|
||||
"pause": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz",
|
||||
"integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10="
|
||||
},
|
||||
"pause-stream": {
|
||||
"version": "0.0.11",
|
||||
"resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz",
|
||||
@@ -3115,6 +3284,15 @@
|
||||
"semver": "^5.1.0"
|
||||
}
|
||||
},
|
||||
"resolve": {
|
||||
"version": "1.8.1",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz",
|
||||
"integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"path-parse": "^1.0.5"
|
||||
}
|
||||
},
|
||||
"resolve-from": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz",
|
||||
@@ -3503,6 +3681,15 @@
|
||||
"safe-buffer": "~5.1.0"
|
||||
}
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
|
||||
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"strip-bom": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
|
||||
@@ -3536,6 +3723,12 @@
|
||||
"ws": "^5.2.0"
|
||||
}
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
|
||||
"integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
|
||||
"dev": true
|
||||
},
|
||||
"symbol-observable": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz",
|
||||
@@ -3648,6 +3841,73 @@
|
||||
"strip-json-comments": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"tslib": {
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz",
|
||||
"integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==",
|
||||
"dev": true
|
||||
},
|
||||
"tslint": {
|
||||
"version": "5.10.0",
|
||||
"resolved": "https://registry.npmjs.org/tslint/-/tslint-5.10.0.tgz",
|
||||
"integrity": "sha1-EeJrzLiK+gLdDZlWyuPUVAtfVMM=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"babel-code-frame": "^6.22.0",
|
||||
"builtin-modules": "^1.1.1",
|
||||
"chalk": "^2.3.0",
|
||||
"commander": "^2.12.1",
|
||||
"diff": "^3.2.0",
|
||||
"glob": "^7.1.1",
|
||||
"js-yaml": "^3.7.0",
|
||||
"minimatch": "^3.0.4",
|
||||
"resolve": "^1.3.2",
|
||||
"semver": "^5.3.0",
|
||||
"tslib": "^1.8.0",
|
||||
"tsutils": "^2.12.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"glob": {
|
||||
"version": "7.1.2",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
|
||||
"integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
"inherits": "2",
|
||||
"minimatch": "^3.0.4",
|
||||
"once": "^1.3.0",
|
||||
"path-is-absolute": "^1.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tslint-config-prettier": {
|
||||
"version": "1.13.0",
|
||||
"resolved": "https://registry.npmjs.org/tslint-config-prettier/-/tslint-config-prettier-1.13.0.tgz",
|
||||
"integrity": "sha512-assE77K7K8Q9j8CVIHiU3d1uoKc8N5v7UPpkQ9IE8BEPWkvSYR37lDuYekDlAMFqR1IpD6CrS+uOJLl6pw7Wdw==",
|
||||
"dev": true
|
||||
},
|
||||
"tslint-plugin-prettier": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/tslint-plugin-prettier/-/tslint-plugin-prettier-1.3.0.tgz",
|
||||
"integrity": "sha512-6UqeeV6EABp0RdQkW6eC1vwnAXcKMGJgPeJ5soXiKdSm2vv7c3dp+835CM8pjgx9l4uSa7tICm1Kli+SMsADDg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"eslint-plugin-prettier": "^2.2.0",
|
||||
"tslib": "^1.7.1"
|
||||
}
|
||||
},
|
||||
"tsutils": {
|
||||
"version": "2.27.1",
|
||||
"resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.27.1.tgz",
|
||||
"integrity": "sha512-AE/7uzp32MmaHvNNFES85hhUDHFdFZp6OAiZcd6y4ZKKIg6orJTm8keYWBhIhrJQH3a4LzNKat7ZPXZt5aTf6w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"tslib": "^1.8.1"
|
||||
}
|
||||
},
|
||||
"type-is": {
|
||||
"version": "1.6.16",
|
||||
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz",
|
||||
|
||||
+6
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@coralproject/talk",
|
||||
"version": "1.0.0",
|
||||
"version": "5.0.0",
|
||||
"description": "A better commenting experience from Mozilla, The Washington Post, and The New York Times.",
|
||||
"scripts": {
|
||||
"start": "node dist/index.js",
|
||||
@@ -28,6 +28,7 @@
|
||||
"lodash": "^4.17.10",
|
||||
"luxon": "^1.2.1",
|
||||
"mongodb": "^3.0.10",
|
||||
"passport": "^0.4.0",
|
||||
"performance-now": "^2.1.0",
|
||||
"subscriptions-transport-ws": "^0.9.11",
|
||||
"uuid": "^3.2.1"
|
||||
@@ -43,6 +44,7 @@
|
||||
"@types/lodash": "^4.14.109",
|
||||
"@types/luxon": "^0.5.3",
|
||||
"@types/mongodb": "^3.0.19",
|
||||
"@types/passport": "^0.4.5",
|
||||
"@types/uuid": "^3.4.3",
|
||||
"@types/ws": "^5.1.2",
|
||||
"graphql-playground-middleware-express": "^1.7.0",
|
||||
@@ -50,6 +52,9 @@
|
||||
"prettier": "^1.13.4",
|
||||
"ts-node": "^6.1.1",
|
||||
"tsconfig-paths": "^3.4.0",
|
||||
"tslint": "^5.10.0",
|
||||
"tslint-config-prettier": "^1.13.0",
|
||||
"tslint-plugin-prettier": "^1.3.0",
|
||||
"typescript": "^2.9.1"
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,18 @@
|
||||
import { Express } from "express";
|
||||
import { Db } from "mongodb";
|
||||
import http from "http";
|
||||
import { Redis } from "ioredis";
|
||||
import { Db } from "mongodb";
|
||||
|
||||
import { Config } from "talk-server/config";
|
||||
import { Schemas } from "talk-server/graph/schemas";
|
||||
import { handleSubscriptions } from "talk-server/graph/common/subscriptions/middleware";
|
||||
import { Schemas } from "talk-server/graph/schemas";
|
||||
|
||||
import { createRouter } from "./router";
|
||||
import serveStatic from "./middleware/serveStatic";
|
||||
import {
|
||||
access as accessLogger,
|
||||
error as errorLogger,
|
||||
} from "./middleware/logging";
|
||||
import serveStatic from "./middleware/serveStatic";
|
||||
import { createRouter } from "./router";
|
||||
|
||||
export interface AppOptions {
|
||||
parent: Express;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { RequestHandler, ErrorRequestHandler } from "express";
|
||||
import logger from "../../logger";
|
||||
import { ErrorRequestHandler, RequestHandler } from "express";
|
||||
import now from "performance-now";
|
||||
import logger from "../../logger";
|
||||
|
||||
export const access: RequestHandler = (req, res, next) => {
|
||||
const startTime = now();
|
||||
const end = res.end;
|
||||
res.end = (chunk: any, encodingOrCb?: string | Function, cb?: Function) => {
|
||||
res.end = (chunk: any, encodingOrCb?: any, cb?: any) => {
|
||||
// Compute the end time.
|
||||
const responseTime = Math.round(now() - startTime);
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import { Db } from "mongodb";
|
||||
import passport, { Authenticator } from "passport";
|
||||
|
||||
export interface PassportOptions {
|
||||
db: Db;
|
||||
}
|
||||
|
||||
export function createPassport({
|
||||
db,
|
||||
}: PassportOptions): passport.Authenticator {
|
||||
// Create the authenticator.
|
||||
const auth = new Authenticator();
|
||||
|
||||
return auth;
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
import express, { Router } from "express";
|
||||
import express from "express";
|
||||
import passport from "passport";
|
||||
|
||||
import tenantGraphMiddleware from "talk-server/graph/tenant/middleware";
|
||||
import managementGraphMiddleware from "talk-server/graph/management/middleware";
|
||||
import tenantGraphMiddleware from "talk-server/graph/tenant/middleware";
|
||||
|
||||
import { AppOptions } from "./index";
|
||||
import playground from "./middleware/playground";
|
||||
@@ -9,17 +10,6 @@ import playground from "./middleware/playground";
|
||||
async function createManagementRouter(opts: AppOptions) {
|
||||
const router = express.Router();
|
||||
|
||||
if (opts.config.get("env") === "development") {
|
||||
// GraphiQL
|
||||
router.get(
|
||||
"/graphiql",
|
||||
playground({
|
||||
endpoint: "/api/management/graphql",
|
||||
subscriptionEndpoint: "/api/management/live",
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// Management API
|
||||
router.use(
|
||||
"/graphql",
|
||||
@@ -37,17 +27,6 @@ async function createManagementRouter(opts: AppOptions) {
|
||||
async function createTenantRouter(opts: AppOptions) {
|
||||
const router = express.Router();
|
||||
|
||||
if (opts.config.get("env") === "development") {
|
||||
// GraphiQL
|
||||
router.get(
|
||||
"/graphiql",
|
||||
playground({
|
||||
endpoint: "/api/tenant/graphql",
|
||||
subscriptionEndpoint: "/api/tenant/live",
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// Tenant API
|
||||
router.use(
|
||||
"/graphql",
|
||||
@@ -62,6 +41,9 @@ async function createAPIRouter(opts: AppOptions) {
|
||||
// Create a router.
|
||||
const router = express.Router();
|
||||
|
||||
// Setup Passport.
|
||||
router.use(passport.initialize());
|
||||
|
||||
// Configure the tenant routes.
|
||||
router.use("/tenant", await createTenantRouter(opts));
|
||||
|
||||
@@ -77,5 +59,25 @@ export async function createRouter(opts: AppOptions) {
|
||||
|
||||
router.use("/api", await createAPIRouter(opts));
|
||||
|
||||
if (opts.config.get("env") === "development") {
|
||||
// Tenant GraphiQL
|
||||
router.get(
|
||||
"/tenant/graphiql",
|
||||
playground({
|
||||
endpoint: "/api/tenant/graphql",
|
||||
subscriptionEndpoint: "/api/tenant/live",
|
||||
})
|
||||
);
|
||||
|
||||
// Management GraphiQL
|
||||
router.get(
|
||||
"/management/graphiql",
|
||||
playground({
|
||||
endpoint: "/api/management/graphql",
|
||||
subscriptionEndpoint: "/api/management/live",
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return router;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Joi from "joi";
|
||||
import convict from "convict";
|
||||
import dotenv from "dotenv";
|
||||
import Joi from "joi";
|
||||
|
||||
// Apply all the configuration provided in the .env file if it isn't already in
|
||||
// the environment.
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { resolveGraphqlOptions } from "apollo-server-core";
|
||||
import {
|
||||
graphqlExpress,
|
||||
ExpressGraphQLOptionsFunction,
|
||||
graphqlExpress,
|
||||
GraphQLOptions,
|
||||
} from "apollo-server-express";
|
||||
import { GraphQLError, FieldDefinitionNode, ValidationContext } from "graphql";
|
||||
import { resolveGraphqlOptions } from "apollo-server-core";
|
||||
import { FieldDefinitionNode, GraphQLError, ValidationContext } from "graphql";
|
||||
import { Config } from "talk-server/config";
|
||||
|
||||
// Sourced from: https://github.com/apollographql/apollo-server/blob/958846887598491fadea57b3f9373d129300f250/packages/apollo-server-core/src/ApolloServer.ts#L46-L57
|
||||
@@ -28,7 +28,7 @@ export const graphqlMiddleware = (
|
||||
// Generate the validation rules.
|
||||
const validationRules: Array<(context: ValidationContext) => any> = [];
|
||||
|
||||
if (config.get("env") !== "production") {
|
||||
if (config.get("env") === "production") {
|
||||
// Disable introspection in production.
|
||||
validationRules.push(NoIntrospection);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
export interface ClientMutationProps {
|
||||
clientMutationId: string;
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
import { DateTime } from "luxon";
|
||||
import { GraphQLScalarType } from "graphql";
|
||||
import { Kind } from "graphql/language";
|
||||
import { DateTime } from "luxon";
|
||||
import { Cursor } from "talk-server/models/connection";
|
||||
|
||||
function parseIntegerCursor(value: string): number {
|
||||
try {
|
||||
const cursor = parseInt(value);
|
||||
const cursor = parseInt(value, 10);
|
||||
|
||||
return cursor;
|
||||
} catch (err) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { addResolveFunctionsToSchema, IResolvers } from "graphql-tools";
|
||||
import { getGraphQLProjectConfig } from "graphql-config";
|
||||
import { addResolveFunctionsToSchema, IResolvers } from "graphql-tools";
|
||||
|
||||
export default function loadSchema(projectName: string, resolvers: IResolvers) {
|
||||
// Load the configuration from the provided `.graphqlconfig` file.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { execute, GraphQLSchema, subscribe } from "graphql";
|
||||
import http from "http";
|
||||
import { SubscriptionServer } from "subscriptions-transport-ws";
|
||||
import { GraphQLSchema, execute, subscribe } from "graphql";
|
||||
|
||||
export interface SubscriptionMiddlewareOptions {
|
||||
schema: GraphQLSchema;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { RedisPubSub } from "graphql-redis-subscriptions";
|
||||
import { createRedisClient } from "talk-server/services/redis";
|
||||
import { Config } from "talk-server/config";
|
||||
import { createRedisClient } from "talk-server/services/redis";
|
||||
|
||||
export async function createPubSub(config: Config): Promise<RedisPubSub> {
|
||||
// Create the Redis clients for the PubSub server.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Db } from "mongodb";
|
||||
import { GraphQLSchema } from "graphql";
|
||||
import { Db } from "mongodb";
|
||||
|
||||
import { graphqlMiddleware } from "talk-server/graph/common/middleware";
|
||||
import { Config } from "talk-server/config";
|
||||
import { graphqlMiddleware } from "talk-server/graph/common/middleware";
|
||||
|
||||
import Context from "./context";
|
||||
|
||||
|
||||
@@ -1,20 +1,27 @@
|
||||
import loaders from "./loaders";
|
||||
import { Db } from "mongodb";
|
||||
import { Tenant } from "talk-server/models/tenant";
|
||||
import { User } from "talk-server/models/user";
|
||||
import loaders from "./loaders";
|
||||
import mutators from "./mutators";
|
||||
|
||||
export interface TenantContextOptions {
|
||||
tenant?: Tenant;
|
||||
db: Db;
|
||||
tenant?: Tenant;
|
||||
user?: User;
|
||||
}
|
||||
|
||||
export default class TenantContext {
|
||||
public loaders: ReturnType<typeof loaders>;
|
||||
public mutators: ReturnType<typeof mutators>;
|
||||
public db: Db;
|
||||
public tenant?: Tenant;
|
||||
public user?: User;
|
||||
|
||||
constructor({ tenant, db }: TenantContextOptions) {
|
||||
constructor({ user, tenant, db }: TenantContextOptions) {
|
||||
this.tenant = tenant;
|
||||
this.user = user;
|
||||
this.loaders = loaders(this);
|
||||
this.mutators = mutators(this);
|
||||
this.db = db;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
import DataLoader from "dataloader";
|
||||
import {
|
||||
Asset,
|
||||
retrieveMany as retrieveManyAssets,
|
||||
} from "talk-server/models/asset";
|
||||
import Context from "talk-server/graph/tenant/context";
|
||||
import TenantContext from "talk-server/graph/tenant/context";
|
||||
import { Asset, retrieveManyAssets } from "talk-server/models/asset";
|
||||
|
||||
export default (ctx: Context) => ({
|
||||
export default (ctx: TenantContext) => ({
|
||||
asset: new DataLoader<string, Asset>(ids =>
|
||||
retrieveManyAssets(ctx.db, ctx.tenant.id, ids)
|
||||
),
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import DataLoader from "dataloader";
|
||||
import Context from "talk-server/graph/tenant/context";
|
||||
import {
|
||||
Comment,
|
||||
retrieveMany,
|
||||
retrieveAssetConnection,
|
||||
ConnectionInput,
|
||||
retrieveAssetConnection,
|
||||
retrieveMany,
|
||||
retrieveRepliesConnection,
|
||||
} from "talk-server/models/comment";
|
||||
import Context from "talk-server/graph/tenant/context";
|
||||
|
||||
export default (ctx: Context) => ({
|
||||
comment: new DataLoader((ids: string[]) =>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import Context from "talk-server/graph/tenant/context";
|
||||
import Assets from "./assets";
|
||||
import Comments from "./comments";
|
||||
import Users from "./users";
|
||||
import Context from "talk-server/graph/tenant/context";
|
||||
|
||||
export default (ctx: Context) => ({
|
||||
Assets: Assets(ctx),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import DataLoader from "dataloader";
|
||||
import { User, retrieveMany } from "talk-server/models/user";
|
||||
import Context from "talk-server/graph/tenant/context";
|
||||
import { retrieveMany, User } from "talk-server/models/user";
|
||||
|
||||
export default (ctx: Context) => ({
|
||||
user: new DataLoader<string, User>(ids =>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { Db } from "mongodb";
|
||||
import { GraphQLSchema } from "graphql";
|
||||
import { Db } from "mongodb";
|
||||
|
||||
import { retrieveByDomain } from "talk-server/models/tenant";
|
||||
import { createPubSub } from "talk-server/graph/common/subscriptions/pubsub";
|
||||
import { Config } from "talk-server/config";
|
||||
import { graphqlMiddleware } from "talk-server/graph/common/middleware";
|
||||
import { createPubSub } from "talk-server/graph/common/subscriptions/pubsub";
|
||||
import { retrieveTenantByDomain } from "talk-server/models/tenant";
|
||||
|
||||
import TenantContext from "./context";
|
||||
|
||||
@@ -14,11 +14,15 @@ export default async (schema: GraphQLSchema, config: Config, db: Db) => {
|
||||
|
||||
return graphqlMiddleware(config, async req => {
|
||||
// TODO: replace with shared synced cache instead of direct db access.
|
||||
const tenant = await retrieveByDomain(db, req.hostname);
|
||||
const tenant = await retrieveTenantByDomain(db, req.hostname);
|
||||
|
||||
// Load the user from the request.
|
||||
const user = req.user;
|
||||
|
||||
// Return the graph options.
|
||||
return {
|
||||
schema,
|
||||
context: new TenantContext({ db, tenant }),
|
||||
context: new TenantContext({ db, tenant, user }),
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import TenantContext from "talk-server/graph/tenant/context";
|
||||
import { CreateCommentInput } from "talk-server/graph/tenant/resolvers/mutation";
|
||||
import { Comment } from "talk-server/models/comment";
|
||||
import { create } from "talk-server/services/comments";
|
||||
|
||||
export default (ctx: TenantContext) => ({
|
||||
create: (input: CreateCommentInput): Promise<Comment> => {
|
||||
return create(ctx.db, ctx.tenant.id, {
|
||||
author_id: ctx.user.id,
|
||||
asset_id: input.assetID,
|
||||
body: input.body,
|
||||
parent_id: input.parentID,
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,6 @@
|
||||
import TenantContext from "talk-server/graph/tenant/context";
|
||||
import Comment from "./comment";
|
||||
|
||||
export default (ctx: TenantContext) => ({
|
||||
Comment: Comment(ctx),
|
||||
});
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Asset } from "talk-server/models/asset";
|
||||
import Context from "talk-server/graph/tenant/context";
|
||||
import { Asset } from "talk-server/models/asset";
|
||||
import { ConnectionInput } from "talk-server/models/comment";
|
||||
|
||||
export default {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Comment, ConnectionInput } from "talk-server/models/comment";
|
||||
import Context from "talk-server/graph/tenant/context";
|
||||
import { Comment, ConnectionInput } from "talk-server/models/comment";
|
||||
|
||||
export default {
|
||||
author: async (comment: Comment, _: any, ctx: Context) =>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import Cursor from "../../common/scalars/cursor";
|
||||
import Asset from "./asset";
|
||||
import Comment from "./comment";
|
||||
import Cursor from "../../common/scalars/cursor";
|
||||
import Mutation from "./mutation";
|
||||
import Query from "./query";
|
||||
|
||||
export default {
|
||||
@@ -8,4 +9,5 @@ export default {
|
||||
Comment,
|
||||
Cursor,
|
||||
Query,
|
||||
Mutation,
|
||||
};
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import { ClientMutationProps } from "talk-server/graph/common/resolvers/mutation";
|
||||
import TenantContext from "talk-server/graph/tenant/context";
|
||||
import { Comment } from "talk-server/models/comment";
|
||||
|
||||
export interface CreateCommentInput extends ClientMutationProps {
|
||||
assetID: string;
|
||||
parentID?: string;
|
||||
body: string;
|
||||
}
|
||||
|
||||
export interface CreateCommentPayload extends ClientMutationProps {
|
||||
comment: Comment;
|
||||
}
|
||||
|
||||
const Mutation = {
|
||||
createComment: async (
|
||||
source: void,
|
||||
input: CreateCommentInput,
|
||||
ctx: TenantContext
|
||||
): Promise<CreateCommentPayload> => ({
|
||||
comment: await ctx.mutators.Comment.create(input),
|
||||
clientMutationId: input.clientMutationId,
|
||||
}),
|
||||
};
|
||||
|
||||
export default Mutation;
|
||||
@@ -3,7 +3,7 @@ import { Asset } from "talk-server/models/asset";
|
||||
|
||||
export default {
|
||||
asset: async (
|
||||
_: any,
|
||||
source: void,
|
||||
{ id, url }: { id?: string; url: string },
|
||||
ctx: TenantContext
|
||||
): Promise<Asset> => {
|
||||
|
||||
@@ -18,146 +18,146 @@ scalar Cursor
|
||||
|
||||
# The moderation mode of the site.
|
||||
enum MODERATION_MODE {
|
||||
"""
|
||||
Comments posted while in `PRE` mode will be labeled with a `PREMOD`
|
||||
status and will require a moderator decision before being visible.
|
||||
"""
|
||||
PRE
|
||||
"""
|
||||
Comments posted while in `PRE` mode will be labeled with a `PREMOD`
|
||||
status and will require a moderator decision before being visible.
|
||||
"""
|
||||
PRE
|
||||
|
||||
"""
|
||||
Comments posted while in `POST` will be visible immediately.
|
||||
"""
|
||||
POST
|
||||
"""
|
||||
Comments posted while in `POST` will be visible immediately.
|
||||
"""
|
||||
POST
|
||||
}
|
||||
|
||||
"""
|
||||
Wordlist describes all the available wordlists.
|
||||
"""
|
||||
type Wordlist {
|
||||
"""
|
||||
banned words will by default reject the comment if it is found.
|
||||
"""
|
||||
banned: [String!]!
|
||||
"""
|
||||
banned words will by default reject the comment if it is found.
|
||||
"""
|
||||
banned: [String!]!
|
||||
|
||||
"""
|
||||
suspect words will simply flag the comment.
|
||||
"""
|
||||
suspect: [String!]!
|
||||
"""
|
||||
suspect words will simply flag the comment.
|
||||
"""
|
||||
suspect: [String!]!
|
||||
}
|
||||
|
||||
# Settings stores the global settings for a given installation.
|
||||
type Settings {
|
||||
"""
|
||||
moderation is the moderation mode for all Asset's on the site.
|
||||
"""
|
||||
moderation: MODERATION_MODE!
|
||||
"""
|
||||
moderation is the moderation mode for all Asset's on the site.
|
||||
"""
|
||||
moderation: MODERATION_MODE!
|
||||
|
||||
"""
|
||||
Enables a requirement for email confirmation before a user can login.
|
||||
"""
|
||||
requireEmailConfirmation: Boolean!
|
||||
"""
|
||||
Enables a requirement for email confirmation before a user can login.
|
||||
"""
|
||||
requireEmailConfirmation: Boolean!
|
||||
|
||||
"""
|
||||
infoBoxEnable will enable the Info Box content visible above the question
|
||||
box.
|
||||
"""
|
||||
infoBoxEnable: Boolean!
|
||||
"""
|
||||
infoBoxEnable will enable the Info Box content visible above the question
|
||||
box.
|
||||
"""
|
||||
infoBoxEnable: Boolean!
|
||||
|
||||
"""
|
||||
infoBoxContent is the content of the Info Box.
|
||||
"""
|
||||
infoBoxContent: String
|
||||
"""
|
||||
infoBoxContent is the content of the Info Box.
|
||||
"""
|
||||
infoBoxContent: String
|
||||
|
||||
"""
|
||||
questionBoxEnable will enable the Question Box's content to be visible above
|
||||
the comment box.
|
||||
"""
|
||||
questionBoxEnable: Boolean!
|
||||
"""
|
||||
questionBoxEnable will enable the Question Box's content to be visible above
|
||||
the comment box.
|
||||
"""
|
||||
questionBoxEnable: Boolean!
|
||||
|
||||
"""
|
||||
questionBoxContent is the content of the Question Box.
|
||||
"""
|
||||
questionBoxContent: String
|
||||
"""
|
||||
questionBoxContent is the content of the Question Box.
|
||||
"""
|
||||
questionBoxContent: String
|
||||
|
||||
"""
|
||||
questionBoxIcon is the icon for the Question Box.
|
||||
"""
|
||||
questionBoxIcon: String
|
||||
"""
|
||||
questionBoxIcon is the icon for the Question Box.
|
||||
"""
|
||||
questionBoxIcon: String
|
||||
|
||||
"""
|
||||
premodLinksEnable will put all comments that contain links into premod.
|
||||
"""
|
||||
premodLinksEnable: Boolean!
|
||||
"""
|
||||
premodLinksEnable will put all comments that contain links into premod.
|
||||
"""
|
||||
premodLinksEnable: Boolean!
|
||||
|
||||
"""
|
||||
autoCloseStream when true will auto close the stream when the `closeTimeout`
|
||||
amount of seconds have been reached.
|
||||
"""
|
||||
autoCloseStream: Boolean!
|
||||
"""
|
||||
autoCloseStream when true will auto close the stream when the `closeTimeout`
|
||||
amount of seconds have been reached.
|
||||
"""
|
||||
autoCloseStream: Boolean!
|
||||
|
||||
"""
|
||||
customCssUrl is the URL of the custom CSS used to display on the frontend.
|
||||
"""
|
||||
customCssUrl: String
|
||||
"""
|
||||
customCssUrl is the URL of the custom CSS used to display on the frontend.
|
||||
"""
|
||||
customCssUrl: String
|
||||
|
||||
"""
|
||||
closedTimeout is the amount of seconds from the created_at timestamp that a
|
||||
given asset will be considered closed.
|
||||
"""
|
||||
closedTimeout: Int!
|
||||
"""
|
||||
closedTimeout is the amount of seconds from the created_at timestamp that a
|
||||
given asset will be considered closed.
|
||||
"""
|
||||
closedTimeout: Int!
|
||||
|
||||
"""
|
||||
closedMessage is the message shown to the user when the given Asset is
|
||||
closed.
|
||||
"""
|
||||
closedMessage: String
|
||||
"""
|
||||
closedMessage is the message shown to the user when the given Asset is
|
||||
closed.
|
||||
"""
|
||||
closedMessage: String
|
||||
|
||||
"""
|
||||
disableCommenting will disable commenting site-wide.
|
||||
"""
|
||||
disableCommenting: Boolean!
|
||||
"""
|
||||
disableCommenting will disable commenting site-wide.
|
||||
"""
|
||||
disableCommenting: Boolean!
|
||||
|
||||
"""
|
||||
disableCommentingMessage will be shown above the comment stream while
|
||||
commenting is disabled site-wide.
|
||||
"""
|
||||
disableCommentingMessage: String
|
||||
"""
|
||||
disableCommentingMessage will be shown above the comment stream while
|
||||
commenting is disabled site-wide.
|
||||
"""
|
||||
disableCommentingMessage: String
|
||||
|
||||
"""
|
||||
editCommentWindowLength is the length of time (in milliseconds) after a
|
||||
comment is posted that it can still be edited by the author.
|
||||
"""
|
||||
editCommentWindowLength: Int!
|
||||
"""
|
||||
editCommentWindowLength is the length of time (in milliseconds) after a
|
||||
comment is posted that it can still be edited by the author.
|
||||
"""
|
||||
editCommentWindowLength: Int!
|
||||
|
||||
"""
|
||||
charCountEnable is true when the character count restriction is enabled.
|
||||
"""
|
||||
charCountEnable: Boolean!
|
||||
"""
|
||||
charCountEnable is true when the character count restriction is enabled.
|
||||
"""
|
||||
charCountEnable: Boolean!
|
||||
|
||||
"""
|
||||
charCount is the maximum number of characters a comment may be.
|
||||
"""
|
||||
charCount: Int
|
||||
"""
|
||||
charCount is the maximum number of characters a comment may be.
|
||||
"""
|
||||
charCount: Int
|
||||
|
||||
"""
|
||||
organizationName is the name of the organization.
|
||||
"""
|
||||
organizationName: String
|
||||
"""
|
||||
organizationName is the name of the organization.
|
||||
"""
|
||||
organizationName: String
|
||||
|
||||
"""
|
||||
organizationContactEmail is the email of the organization.
|
||||
"""
|
||||
organizationContactEmail: String
|
||||
"""
|
||||
organizationContactEmail is the email of the organization.
|
||||
"""
|
||||
organizationContactEmail: String
|
||||
|
||||
"""
|
||||
wordlist will return a given list of words.
|
||||
"""
|
||||
wordlist: Wordlist!
|
||||
"""
|
||||
wordlist will return a given list of words.
|
||||
"""
|
||||
wordlist: Wordlist!
|
||||
|
||||
"""
|
||||
domains will return a given list of whitelisted domains.
|
||||
"""
|
||||
domains: [String!]!
|
||||
"""
|
||||
domains will return a given list of whitelisted domains.
|
||||
"""
|
||||
domains: [String!]!
|
||||
}
|
||||
|
||||
################################################################################
|
||||
@@ -168,15 +168,15 @@ type Settings {
|
||||
User is someone that leaves Comments, and logs in.
|
||||
"""
|
||||
type User {
|
||||
"""
|
||||
id is the identifier of the User.
|
||||
"""
|
||||
id: ID!
|
||||
"""
|
||||
id is the identifier of the User.
|
||||
"""
|
||||
id: ID!
|
||||
|
||||
"""
|
||||
username is the name of the User visible to other Users.
|
||||
"""
|
||||
username: String!
|
||||
"""
|
||||
username is the name of the User visible to other Users.
|
||||
"""
|
||||
username: String!
|
||||
}
|
||||
|
||||
################################################################################
|
||||
@@ -184,95 +184,85 @@ type User {
|
||||
################################################################################
|
||||
|
||||
enum COMMENT_STATUS {
|
||||
NONE
|
||||
ACCEPTED
|
||||
NONE
|
||||
ACCEPTED
|
||||
}
|
||||
|
||||
"""
|
||||
Comment is a comment left by a User on an Asset or another Comment as a reply.
|
||||
"""
|
||||
type Comment {
|
||||
"""
|
||||
id is the identifier of the Comment.
|
||||
"""
|
||||
id: ID!
|
||||
"""
|
||||
id is the identifier of the Comment.
|
||||
"""
|
||||
id: ID!
|
||||
|
||||
"""
|
||||
body is the content of the Comment.
|
||||
"""
|
||||
body: String
|
||||
"""
|
||||
body is the content of the Comment.
|
||||
"""
|
||||
body: String
|
||||
|
||||
"""
|
||||
author is the User that authored the Comment.
|
||||
"""
|
||||
author: User
|
||||
"""
|
||||
author is the User that authored the Comment.
|
||||
"""
|
||||
author: User
|
||||
|
||||
"""
|
||||
status represents the Comment's current Status.
|
||||
"""
|
||||
status: COMMENT_STATUS!
|
||||
"""
|
||||
status represents the Comment's current Status.
|
||||
"""
|
||||
status: COMMENT_STATUS!
|
||||
|
||||
"""
|
||||
replyCount is the number of replies. Only direct replies to this Comment
|
||||
are counted. Deleted comments are included in this count.
|
||||
"""
|
||||
replyCount: Int
|
||||
"""
|
||||
replyCount is the number of replies. Only direct replies to this Comment
|
||||
are counted. Deleted comments are included in this count.
|
||||
"""
|
||||
replyCount: Int
|
||||
|
||||
"""
|
||||
replies will return the replies to this comment.
|
||||
"""
|
||||
replies(
|
||||
first: Int = 10
|
||||
orderBy: COMMENT_SORT = CREATED_AT_DESC
|
||||
after: Cursor
|
||||
): CommentsConnection
|
||||
"""
|
||||
replies will return the replies to this comment.
|
||||
"""
|
||||
replies(
|
||||
first: Int = 10
|
||||
orderBy: COMMENT_SORT = CREATED_AT_DESC
|
||||
after: Cursor
|
||||
): CommentsConnection
|
||||
}
|
||||
|
||||
type PageInfo {
|
||||
"""
|
||||
Cursor of first node in subset.
|
||||
"""
|
||||
startCursor: Cursor
|
||||
|
||||
"""
|
||||
Cursor of last node in subset.
|
||||
"""
|
||||
endCursor: Cursor
|
||||
|
||||
"""
|
||||
Indicates that there are more nodes after this subset.
|
||||
"""
|
||||
hasNextPage: Boolean!
|
||||
"""
|
||||
Indicates that there are more nodes after this subset.
|
||||
"""
|
||||
hasNextPage: Boolean!
|
||||
}
|
||||
|
||||
"""
|
||||
CommentEdge represents a unique Comment in a CommentConnection.
|
||||
"""
|
||||
type CommentEdge {
|
||||
"""
|
||||
node is the Comment for this edge.
|
||||
"""
|
||||
node: Comment
|
||||
"""
|
||||
node is the Comment for this edge.
|
||||
"""
|
||||
node: Comment
|
||||
|
||||
"""
|
||||
"""
|
||||
|
||||
"""
|
||||
cursor: Cursor
|
||||
"""
|
||||
cursor: Cursor
|
||||
}
|
||||
|
||||
"""
|
||||
CommentsConnection represents a subset of a comment list.
|
||||
"""
|
||||
type CommentsConnection {
|
||||
"""
|
||||
edges are a subset of CommentEdge's.
|
||||
"""
|
||||
edges: [CommentEdge!]!
|
||||
"""
|
||||
edges are a subset of CommentEdge's.
|
||||
"""
|
||||
edges: [CommentEdge!]!
|
||||
|
||||
"""
|
||||
pageInfo is
|
||||
"""
|
||||
pageInfo: PageInfo!
|
||||
"""
|
||||
pageInfo is
|
||||
"""
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
################################################################################
|
||||
@@ -280,84 +270,89 @@ type CommentsConnection {
|
||||
################################################################################
|
||||
|
||||
enum COMMENT_SORT {
|
||||
CREATED_AT_DESC
|
||||
CREATED_AT_ASC
|
||||
REPLIES_DESC
|
||||
RESPECT_DESC
|
||||
CREATED_AT_DESC
|
||||
CREATED_AT_ASC
|
||||
REPLIES_DESC
|
||||
RESPECT_DESC
|
||||
}
|
||||
|
||||
"""
|
||||
Asset is an Article or Page where Comments are written on by Users.
|
||||
"""
|
||||
type Asset {
|
||||
"""
|
||||
id is the identifier of the Asset.
|
||||
"""
|
||||
id: ID!
|
||||
"""
|
||||
id is the identifier of the Asset.
|
||||
"""
|
||||
id: ID!
|
||||
|
||||
"""
|
||||
url is the url that the Asset is located on.
|
||||
"""
|
||||
url: String!
|
||||
"""
|
||||
url is the url that the Asset is located on.
|
||||
"""
|
||||
url: String!
|
||||
|
||||
"""
|
||||
title is the title of the scraped Asset.
|
||||
"""
|
||||
title: String
|
||||
"""
|
||||
title is the title of the scraped Asset.
|
||||
"""
|
||||
title: String
|
||||
|
||||
"""
|
||||
comments are the comments on the Asset.
|
||||
"""
|
||||
comments(
|
||||
first: Int = 10
|
||||
orderBy: COMMENT_SORT = CREATED_AT_DESC
|
||||
after: Cursor
|
||||
): CommentsConnection
|
||||
"""
|
||||
comments are the comments on the Asset.
|
||||
"""
|
||||
comments(
|
||||
first: Int = 10
|
||||
orderBy: COMMENT_SORT = CREATED_AT_DESC
|
||||
after: Cursor
|
||||
): CommentsConnection
|
||||
|
||||
"""
|
||||
author is the authors listed in the meta tags for the Asset.
|
||||
"""
|
||||
author: String
|
||||
"""
|
||||
author is the authors listed in the meta tags for the Asset.
|
||||
"""
|
||||
author: String
|
||||
|
||||
"""
|
||||
closedAt is the Time that the Asset is closed for commenting.
|
||||
"""
|
||||
closedAt: Time
|
||||
"""
|
||||
closedAt is the Time that the Asset is closed for commenting.
|
||||
"""
|
||||
closedAt: Time
|
||||
|
||||
"""
|
||||
isClosed returns true when the Asset is currently closed for commenting.
|
||||
"""
|
||||
isClosed: Boolean!
|
||||
"""
|
||||
isClosed returns true when the Asset is currently closed for commenting.
|
||||
"""
|
||||
isClosed: Boolean!
|
||||
|
||||
"""
|
||||
createdAt is the date that the Asset was created at.
|
||||
"""
|
||||
createdAt: Time!
|
||||
"""
|
||||
createdAt is the date that the Asset was created at.
|
||||
"""
|
||||
createdAt: Time!
|
||||
}
|
||||
|
||||
"""
|
||||
AssetEdge represents a unique Asset in a AssetConnection.
|
||||
"""
|
||||
type AssetEdge {
|
||||
"""
|
||||
node is the Asset for this edge.
|
||||
"""
|
||||
node: Asset
|
||||
|
||||
"""
|
||||
|
||||
"""
|
||||
cursor: Cursor
|
||||
}
|
||||
|
||||
"""
|
||||
AssetsConnection represents a subset of a Asset list.
|
||||
"""
|
||||
type AssetsConnection {
|
||||
"""
|
||||
Indicates that there are more Assets after this subset.
|
||||
"""
|
||||
hasNextPage: Boolean!
|
||||
"""
|
||||
edges are a subset of AssetEdge's.
|
||||
"""
|
||||
edges: [AssetEdge!]!
|
||||
|
||||
"""
|
||||
Cursor of first Asset in subset.
|
||||
"""
|
||||
startCursor: Cursor
|
||||
|
||||
"""
|
||||
Cursor of last Asset in subset.
|
||||
"""
|
||||
endCursor: Cursor
|
||||
|
||||
"""
|
||||
Subset of Assets.
|
||||
"""
|
||||
nodes: [Asset!]!
|
||||
"""
|
||||
pageInfo is
|
||||
"""
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
################################################################################
|
||||
@@ -365,30 +360,30 @@ type AssetsConnection {
|
||||
################################################################################
|
||||
|
||||
type Query {
|
||||
"""
|
||||
comment returns a specific comment.
|
||||
"""
|
||||
comment(id: ID!): Comment
|
||||
"""
|
||||
comment returns a specific comment.
|
||||
"""
|
||||
comment(id: ID!): Comment
|
||||
|
||||
"""
|
||||
assets returns a AssetsConnection.
|
||||
"""
|
||||
assets(cursor: Cursor, limit: Int = 10): AssetsConnection
|
||||
"""
|
||||
assets returns a AssetsConnection.
|
||||
"""
|
||||
assets(cursor: Cursor, limit: Int = 10): AssetsConnection
|
||||
|
||||
"""
|
||||
asset is the Asset specified by its ID.
|
||||
"""
|
||||
asset(id: ID!): Asset
|
||||
"""
|
||||
asset is the Asset specified by its ID.
|
||||
"""
|
||||
asset(id: ID!): Asset
|
||||
|
||||
"""
|
||||
me is the current logged in User.
|
||||
"""
|
||||
me: User
|
||||
"""
|
||||
me is the current logged in User.
|
||||
"""
|
||||
me: User
|
||||
|
||||
"""
|
||||
settings is the Settings for a given Tenant.
|
||||
"""
|
||||
settings: Settings!
|
||||
"""
|
||||
settings is the Settings for a given Tenant.
|
||||
"""
|
||||
settings: Settings!
|
||||
}
|
||||
|
||||
################################################################################
|
||||
@@ -403,25 +398,25 @@ type Query {
|
||||
CreateCommentInput provides the input for the createComment Mutation.
|
||||
"""
|
||||
input CreateCommentInput {
|
||||
"""
|
||||
assetID is the ID of the Asset where we are creating a comment on.
|
||||
"""
|
||||
assetID: ID!
|
||||
"""
|
||||
assetID is the ID of the Asset where we are creating a comment on.
|
||||
"""
|
||||
assetID: ID!
|
||||
|
||||
"""
|
||||
parentID is the optional ID of the Comment that we are replying to.
|
||||
"""
|
||||
parentID: ID
|
||||
"""
|
||||
parentID is the optional ID of the Comment that we are replying to.
|
||||
"""
|
||||
parentID: ID
|
||||
|
||||
"""
|
||||
body is the Comment body, the content of the Comment.
|
||||
"""
|
||||
body: String!
|
||||
"""
|
||||
body is the Comment body, the content of the Comment.
|
||||
"""
|
||||
body: String!
|
||||
|
||||
"""
|
||||
clientMutationId is required for Relay support.
|
||||
"""
|
||||
clientMutationId: String!
|
||||
"""
|
||||
clientMutationId is required for Relay support.
|
||||
"""
|
||||
clientMutationId: String!
|
||||
}
|
||||
|
||||
"""
|
||||
@@ -429,15 +424,15 @@ CreateCommentPayload contains the created Comment after the createComment
|
||||
mutation.
|
||||
"""
|
||||
type CreateCommentPayload {
|
||||
"""
|
||||
comment is the possibly created comment.
|
||||
"""
|
||||
comment: Comment
|
||||
"""
|
||||
comment is the possibly created comment.
|
||||
"""
|
||||
comment: Comment
|
||||
|
||||
"""
|
||||
clientMutationId is required for Relay support.
|
||||
"""
|
||||
clientMutationId: String!
|
||||
"""
|
||||
clientMutationId is required for Relay support.
|
||||
"""
|
||||
clientMutationId: String!
|
||||
}
|
||||
|
||||
##################
|
||||
@@ -445,10 +440,10 @@ type CreateCommentPayload {
|
||||
##################
|
||||
|
||||
type Mutation {
|
||||
"""
|
||||
createComment will create a Comment as the current logged in User.
|
||||
"""
|
||||
createComment(input: CreateCommentInput!): CreateCommentPayload
|
||||
"""
|
||||
createComment will create a Comment as the current logged in User.
|
||||
"""
|
||||
createComment(input: CreateCommentInput!): CreateCommentPayload
|
||||
}
|
||||
|
||||
################################################################################
|
||||
@@ -456,5 +451,5 @@ type Mutation {
|
||||
################################################################################
|
||||
|
||||
type Subscription {
|
||||
commentCreated(assetID: ID!): Comment
|
||||
commentCreated(assetID: ID!): Comment
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import express, { Express } from "express";
|
||||
import http from "http";
|
||||
|
||||
import getManagementSchema from "talk-server/graph/management/schema";
|
||||
import { Schemas } from "talk-server/graph/schemas";
|
||||
import getTenantSchema from "talk-server/graph/tenant/schema";
|
||||
import { attachSubscriptionHandlers, createApp, listenAndServe } from "./app";
|
||||
import config, { Config } from "./config";
|
||||
import { createApp, listenAndServe, attachSubscriptionHandlers } from "./app";
|
||||
import logger from "./logger";
|
||||
import { createMongoDB } from "./services/mongodb";
|
||||
import { createRedisClient } from "./services/redis";
|
||||
import getManagementSchema from "talk-server/graph/management/schema";
|
||||
import getTenantSchema from "talk-server/graph/tenant/schema";
|
||||
import { Schemas } from "talk-server/graph/schemas";
|
||||
|
||||
export interface ServerOptions {
|
||||
config?: Config;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { Db, Collection } from "mongodb";
|
||||
import Query, { FilterQuery } from "./query";
|
||||
import { defaults } from "lodash";
|
||||
import uuid from "uuid";
|
||||
import { Omit } from "talk-common/types";
|
||||
import dotize from "dotize";
|
||||
import { defaults } from "lodash";
|
||||
import { Collection, Db } from "mongodb";
|
||||
import { Omit } from "talk-common/types";
|
||||
import { TenantResource } from "talk-server/models/tenant";
|
||||
import uuid from "uuid";
|
||||
import Query from "./query";
|
||||
|
||||
function collection(db: Db): Collection<Asset> {
|
||||
return db.collection<Asset>("assets");
|
||||
@@ -29,7 +29,7 @@ export interface Asset extends TenantResource {
|
||||
|
||||
export type CreateAssetInput = Pick<Asset, "id" | "url">;
|
||||
|
||||
export async function create(
|
||||
export async function createAsset(
|
||||
db: Db,
|
||||
tenantID: string,
|
||||
input: CreateAssetInput
|
||||
@@ -69,7 +69,7 @@ export async function create(
|
||||
return result.value;
|
||||
}
|
||||
|
||||
export async function retrieve(
|
||||
export async function retrieveAsset(
|
||||
db: Db,
|
||||
tenantID: string,
|
||||
id: string
|
||||
@@ -79,11 +79,11 @@ export async function retrieve(
|
||||
.findOne({ id, tenant_id: tenantID });
|
||||
}
|
||||
|
||||
export async function retrieveMany(
|
||||
export async function retrieveManyAssets(
|
||||
db: Db,
|
||||
tenantID: string,
|
||||
ids: string[]
|
||||
): Promise<Array<Asset>> {
|
||||
): Promise<Asset[]> {
|
||||
const cursor = await db
|
||||
.collection<Asset>("assets")
|
||||
.find({ id: { $in: ids }, tenant_id: tenantID });
|
||||
@@ -98,7 +98,7 @@ export type UpdateAssetInput = Omit<
|
||||
"id" | "tenant_id" | "url" | "created_at"
|
||||
>;
|
||||
|
||||
export async function update(
|
||||
export async function updateAsset(
|
||||
db: Db,
|
||||
tenantID: string,
|
||||
id: string,
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { Db, Collection } from "mongodb";
|
||||
import { Omit, Sub } from "talk-common/types";
|
||||
import { merge } from "lodash";
|
||||
import uuid from "uuid";
|
||||
import { Connection, Edge, Cursor } from "talk-server/models/connection";
|
||||
import Query from "talk-server/models/query";
|
||||
import { Collection, Db } from "mongodb";
|
||||
import { Omit, Sub } from "talk-common/types";
|
||||
import { ActionCounts } from "talk-server/models/actions";
|
||||
import { Connection, Cursor, Edge } from "talk-server/models/connection";
|
||||
import Query from "talk-server/models/query";
|
||||
import { TenantResource } from "talk-server/models/tenant";
|
||||
import uuid from "uuid";
|
||||
|
||||
function collection(db: Db): Collection<Comment> {
|
||||
return db.collection<Comment>("comments");
|
||||
@@ -116,7 +116,7 @@ export async function retrieveMany(
|
||||
db: Db,
|
||||
tenantID: string,
|
||||
ids: string[]
|
||||
): Promise<Readonly<Comment>[]> {
|
||||
): Promise<Array<Readonly<Comment>>> {
|
||||
const cursor = await collection(db).find({
|
||||
id: {
|
||||
$in: ids,
|
||||
@@ -152,7 +152,7 @@ export interface ConnectionInput {
|
||||
function nodesToEdge(
|
||||
input: ConnectionInput,
|
||||
nodes: Comment[]
|
||||
): Edge<Comment>[] {
|
||||
): Array<Edge<Comment>> {
|
||||
let getCursor: (comment: Comment, index: number) => Cursor;
|
||||
switch (input.orderBy) {
|
||||
case CommentSort.CREATED_AT_DESC:
|
||||
|
||||
@@ -10,6 +10,6 @@ export interface PageInfo {
|
||||
}
|
||||
|
||||
export interface Connection<T> {
|
||||
edges: Edge<T>[];
|
||||
edges: Array<Edge<T>>;
|
||||
pageInfo: PageInfo;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ export default class Query<T> {
|
||||
private collection: Collection<T>;
|
||||
private skip?: number;
|
||||
private limit?: number;
|
||||
private sort?: Object;
|
||||
private sort?: object;
|
||||
|
||||
constructor(collection: Collection<T>) {
|
||||
this.collection = collection;
|
||||
@@ -61,7 +61,7 @@ export default class Query<T> {
|
||||
*
|
||||
* @param sort the sorting option for the documents
|
||||
*/
|
||||
public orderBy(sort: Object): Query<T> {
|
||||
public orderBy(sort: object): Query<T> {
|
||||
this.sort = merge({}, this.sort || {}, sort);
|
||||
return this;
|
||||
}
|
||||
@@ -69,7 +69,7 @@ export default class Query<T> {
|
||||
/**
|
||||
* exec will return a cursor to the query.
|
||||
*/
|
||||
async exec(): Promise<Cursor<T>> {
|
||||
public async exec(): Promise<Cursor<T>> {
|
||||
let cursor = await this.collection.find(this.filter);
|
||||
|
||||
if (this.limit) {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Db, Collection } from "mongodb";
|
||||
import { merge } from "lodash";
|
||||
import dotize from "dotize";
|
||||
import { merge } from "lodash";
|
||||
import { Collection, Db } from "mongodb";
|
||||
import { Sub } from "talk-common/types";
|
||||
import uuid from "uuid";
|
||||
import { Omit, Sub } from "talk-common/types";
|
||||
|
||||
function collection(db: Db): Collection<Tenant> {
|
||||
return db.collection<Tenant>("tenants");
|
||||
@@ -75,7 +75,7 @@ export type CreateTenantInput = Pick<
|
||||
* @param db the MongoDB connection used to create the tenant.
|
||||
* @param input the customizable parts of the Tenant available during creation
|
||||
*/
|
||||
export async function create(
|
||||
export async function createTenant(
|
||||
db: Db,
|
||||
input: CreateTenantInput
|
||||
): Promise<Readonly<Tenant>> {
|
||||
@@ -113,7 +113,7 @@ export async function create(
|
||||
return tenant;
|
||||
}
|
||||
|
||||
export async function retrieveByDomain(
|
||||
export async function retrieveTenantByDomain(
|
||||
db: Db,
|
||||
domain: string
|
||||
): Promise<Readonly<Tenant>> {
|
||||
@@ -124,10 +124,10 @@ export async function retrieve(db: Db, id: string): Promise<Readonly<Tenant>> {
|
||||
return collection(db).findOne({ id });
|
||||
}
|
||||
|
||||
export async function retrieveMany(
|
||||
export async function retrieveManyTenants(
|
||||
db: Db,
|
||||
ids: string[]
|
||||
): Promise<Readonly<Tenant>[]> {
|
||||
): Promise<Array<Readonly<Tenant>>> {
|
||||
const cursor = await collection(db).find({
|
||||
id: {
|
||||
$in: ids,
|
||||
@@ -139,10 +139,10 @@ export async function retrieveMany(
|
||||
return ids.map(id => tenants.find(tenant => tenant.id === id));
|
||||
}
|
||||
|
||||
export async function retrieveManyByDomain(
|
||||
export async function retrieveManyTenantsByDomain(
|
||||
db: Db,
|
||||
domains: string[]
|
||||
): Promise<Readonly<Tenant>[]> {
|
||||
): Promise<Array<Readonly<Tenant>>> {
|
||||
const cursor = await collection(db).find({
|
||||
domain: {
|
||||
$in: domains,
|
||||
@@ -156,13 +156,15 @@ export async function retrieveManyByDomain(
|
||||
);
|
||||
}
|
||||
|
||||
export async function retrieveAll(db: Db): Promise<Readonly<Tenant>[]> {
|
||||
export async function retrieveAllTenants(
|
||||
db: Db
|
||||
): Promise<Array<Readonly<Tenant>>> {
|
||||
return collection(db)
|
||||
.find({})
|
||||
.toArray();
|
||||
}
|
||||
|
||||
export async function update(
|
||||
export async function updateTenant(
|
||||
db: Db,
|
||||
id: string,
|
||||
update: Partial<CreateTenantInput>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { ActionCounts } from "talk-server/models/actions";
|
||||
import { Db, Collection } from "mongodb";
|
||||
import uuid from "uuid";
|
||||
import { Omit, Sub } from "talk-common/types";
|
||||
import { merge } from "lodash";
|
||||
import { Collection, Db } from "mongodb";
|
||||
import { Omit, Sub } from "talk-common/types";
|
||||
import { ActionCounts } from "talk-server/models/actions";
|
||||
import { TenantResource } from "talk-server/models/tenant";
|
||||
import uuid from "uuid";
|
||||
|
||||
function collection(db: Db): Collection<User> {
|
||||
return db.collection<User>("users");
|
||||
@@ -61,7 +61,7 @@ export interface UserStatusHistory<T> {
|
||||
|
||||
export interface UserStatusItem<T> {
|
||||
status: T; // TODO: migrate field
|
||||
history: UserStatusHistory<T>[];
|
||||
history: Array<UserStatusHistory<T>>;
|
||||
}
|
||||
|
||||
export interface UserStatus {
|
||||
@@ -152,7 +152,7 @@ export async function retrieveMany(
|
||||
db: Db,
|
||||
tenantID: string,
|
||||
ids: string[]
|
||||
): Promise<Readonly<User>[]> {
|
||||
): Promise<Array<Readonly<User>>> {
|
||||
const cursor = await collection(db).find({
|
||||
id: {
|
||||
$in: ids,
|
||||
|
||||
@@ -1,6 +1,29 @@
|
||||
import { Db } from "mongodb";
|
||||
import { Comment } from "talk-server/models/comment";
|
||||
|
||||
export async function create(db: Db): Promise<Comment> {
|
||||
return null;
|
||||
import { Omit } from "talk-common/types";
|
||||
import {
|
||||
Comment,
|
||||
CommentStatus,
|
||||
create as createComment,
|
||||
CreateCommentInput,
|
||||
} from "talk-server/models/comment";
|
||||
|
||||
export type CreateComment = Omit<
|
||||
CreateCommentInput,
|
||||
"status" | "action_counts"
|
||||
>;
|
||||
|
||||
export async function create(
|
||||
db: Db,
|
||||
tenantID: string,
|
||||
input: CreateComment
|
||||
): Promise<Comment> {
|
||||
// TODO: run the comment through the moderation phases.
|
||||
const comment = await createComment(db, tenantID, {
|
||||
status: CommentStatus.ACCEPTED,
|
||||
action_counts: {},
|
||||
...input,
|
||||
});
|
||||
|
||||
return comment;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { MongoClient, Db } from "mongodb";
|
||||
import { Db, MongoClient } from "mongodb";
|
||||
import { Config } from "talk-server/config";
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
import { Db } from "mongodb";
|
||||
import { Redis } from "ioredis";
|
||||
import DataLoader from "dataloader";
|
||||
import { Redis } from "ioredis";
|
||||
import { Db } from "mongodb";
|
||||
|
||||
import { Tenant, retrieveAll, retrieveMany } from "talk-server/models/tenant";
|
||||
import {
|
||||
retrieveAllTenants,
|
||||
retrieveManyTenants,
|
||||
Tenant,
|
||||
} from "talk-server/models/tenant";
|
||||
|
||||
const CacheUpdateChannel = "tenant";
|
||||
|
||||
@@ -18,7 +22,7 @@ export default class Cache {
|
||||
this.db = db;
|
||||
|
||||
// Prepare the list of all tenant's maintained by this instance.
|
||||
this.tenants = new DataLoader(ids => retrieveMany(db, ids));
|
||||
this.tenants = new DataLoader(ids => retrieveManyTenants(db, ids));
|
||||
|
||||
// Subscribe to tenant notifications.
|
||||
subscriber.subscribe(CacheUpdateChannel);
|
||||
@@ -33,7 +37,7 @@ export default class Cache {
|
||||
*/
|
||||
public async primeAll() {
|
||||
// Grab all the tenants for this node.
|
||||
const tenants = await retrieveAll(this.db);
|
||||
const tenants = await retrieveAllTenants(this.db);
|
||||
|
||||
// Clear out all the items in the cache.
|
||||
this.tenants.clearAll();
|
||||
|
||||
+7
-2
@@ -1,6 +1,9 @@
|
||||
import createTalk from "./core";
|
||||
import express from "express";
|
||||
|
||||
import logger from "talk-server/logger";
|
||||
|
||||
import createTalk from "./core";
|
||||
|
||||
// Create the app that will serve as the mounting point for the Talk Server.
|
||||
const app = express();
|
||||
|
||||
@@ -11,7 +14,9 @@ async function bootstrap() {
|
||||
|
||||
// Start the server.
|
||||
await server.start(app);
|
||||
} catch (err) {}
|
||||
} catch (err) {
|
||||
logger.error({ err }, "can not bootstrap server");
|
||||
}
|
||||
}
|
||||
|
||||
bootstrap();
|
||||
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
import { User } from "talk-server/models/user";
|
||||
|
||||
declare module "express" {
|
||||
interface Request {
|
||||
user?: User;
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"extends": [
|
||||
"tslint:recommended",
|
||||
"tslint-config-prettier",
|
||||
"tslint-plugin-prettier"
|
||||
],
|
||||
"rules": {
|
||||
"prettier": true,
|
||||
"object-literal-sort-keys": false,
|
||||
"interface-name": [true, "never-prefix"],
|
||||
"no-switch-case-fall-through": true,
|
||||
"member-ordering": false
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user