mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Merge pull request #10901 from overleaf/lg-openapi-chat
Migrate chat service to OpenAPI GitOrigin-RevId: dc49c52e5e23aa6650e9a3fbe57ae6ac9be1c1da
This commit is contained in:
parent
b7d8fa44b4
commit
d07a7ce4a2
11 changed files with 802 additions and 150 deletions
288
package-lock.json
generated
288
package-lock.json
generated
|
@ -1022,6 +1022,17 @@
|
|||
"name": "@overleaf/settings",
|
||||
"version": "3.0.0"
|
||||
},
|
||||
"node_modules/@apidevtools/json-schema-ref-parser": {
|
||||
"version": "9.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.0.9.tgz",
|
||||
"integrity": "sha512-GBD2Le9w2+lVFoc4vswGI/TjkNIZSVp7+9xPf+X3uidBfWnAeUWmquteSyt0+VCrhNMWj/FTABISQrD3Z/YA+w==",
|
||||
"dependencies": {
|
||||
"@jsdevtools/ono": "^7.1.3",
|
||||
"@types/json-schema": "^7.0.6",
|
||||
"call-me-maybe": "^1.0.1",
|
||||
"js-yaml": "^4.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@arrows/array": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@arrows/array/-/array-1.4.1.tgz",
|
||||
|
@ -5149,6 +5160,11 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/@jsdevtools/ono": {
|
||||
"version": "7.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz",
|
||||
"integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg=="
|
||||
},
|
||||
"node_modules/@juggle/resize-observer": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@juggle/resize-observer/-/resize-observer-3.3.1.tgz",
|
||||
|
@ -10383,7 +10399,6 @@
|
|||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz",
|
||||
"integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"ajv": "^8.0.0"
|
||||
},
|
||||
|
@ -10400,7 +10415,6 @@
|
|||
"version": "8.11.0",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz",
|
||||
"integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==",
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"json-schema-traverse": "^1.0.0",
|
||||
|
@ -10415,8 +10429,7 @@
|
|||
"node_modules/ajv-formats/node_modules/json-schema-traverse": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
|
||||
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
|
||||
"devOptional": true
|
||||
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
|
||||
},
|
||||
"node_modules/ajv-keywords": {
|
||||
"version": "3.5.2",
|
||||
|
@ -12416,6 +12429,11 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/call-me-maybe": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz",
|
||||
"integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ=="
|
||||
},
|
||||
"node_modules/callsites": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
|
||||
|
@ -14747,6 +14765,11 @@
|
|||
"node": ">=4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/deep-freeze": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/deep-freeze/-/deep-freeze-0.0.1.tgz",
|
||||
"integrity": "sha512-Z+z8HiAvsGwmjqlphnHW5oz6yWlOwu6EQfFTjmeTWlDeda3FS2yv3jhq35TX/ewmsnqB+RX2IdsIOyjJCQN5tg=="
|
||||
},
|
||||
"node_modules/deep-is": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
|
||||
|
@ -16825,6 +16848,11 @@
|
|||
"node": ">=0.4.x"
|
||||
}
|
||||
},
|
||||
"node_modules/events-listener": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/events-listener/-/events-listener-1.1.0.tgz",
|
||||
"integrity": "sha512-Kd3EgYfODHueq6GzVfs/VUolh2EgJsS8hkO3KpnDrxVjU3eq63eXM2ujXkhPP+OkeUOhL8CxdfZbQXzryb5C4g=="
|
||||
},
|
||||
"node_modules/execa": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
|
||||
|
@ -16881,6 +16909,96 @@
|
|||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/exegesis": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/exegesis/-/exegesis-4.1.1.tgz",
|
||||
"integrity": "sha512-PvSqaMOw2absLBgsthtJyVOeCHN4lxQ1dM7ibXb6TfZZJaoXtGELoEAGJRFvdN16+u9kg8oy1okZXRk8VpimWA==",
|
||||
"dependencies": {
|
||||
"@apidevtools/json-schema-ref-parser": "^9.0.3",
|
||||
"ajv": "^8.3.0",
|
||||
"ajv-formats": "^2.1.0",
|
||||
"body-parser": "^1.18.3",
|
||||
"content-type": "^1.0.4",
|
||||
"deep-freeze": "0.0.1",
|
||||
"events-listener": "^1.1.0",
|
||||
"glob": "^7.1.3",
|
||||
"json-ptr": "^3.0.1",
|
||||
"json-schema-traverse": "^1.0.0",
|
||||
"lodash": "^4.17.11",
|
||||
"openapi3-ts": "^3.1.1",
|
||||
"promise-breaker": "^6.0.0",
|
||||
"pump": "^3.0.0",
|
||||
"qs": "^6.6.0",
|
||||
"raw-body": "^2.3.3",
|
||||
"semver": "^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0.0",
|
||||
"npm": ">5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/exegesis-express": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/exegesis-express/-/exegesis-express-4.0.0.tgz",
|
||||
"integrity": "sha512-V2hqwTtYRj0bj43K4MCtm0caD97YWkqOUHFMRCBW5L1x9IjyqOEc7Xa4oQjjiFbeFOSQzzwPV+BzXsQjSz08fw==",
|
||||
"dependencies": {
|
||||
"exegesis": "^4.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0.0",
|
||||
"npm": ">5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/exegesis/node_modules/ajv": {
|
||||
"version": "8.11.2",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.2.tgz",
|
||||
"integrity": "sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg==",
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"json-schema-traverse": "^1.0.0",
|
||||
"require-from-string": "^2.0.2",
|
||||
"uri-js": "^4.2.2"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/epoberezkin"
|
||||
}
|
||||
},
|
||||
"node_modules/exegesis/node_modules/json-schema-traverse": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
|
||||
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
|
||||
},
|
||||
"node_modules/exegesis/node_modules/lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"dependencies": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/exegesis/node_modules/semver": {
|
||||
"version": "7.3.8",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
|
||||
"integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/exegesis/node_modules/yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||
},
|
||||
"node_modules/exifr": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/exifr/-/exifr-6.3.0.tgz",
|
||||
|
@ -22420,6 +22538,11 @@
|
|||
"integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/json-ptr": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/json-ptr/-/json-ptr-3.1.1.tgz",
|
||||
"integrity": "sha512-SiSJQ805W1sDUCD1+/t1/1BIrveq2Fe9HJqENxZmMCILmrPI7WhS/pePpIOx85v6/H2z1Vy7AI08GV2TzfXocg=="
|
||||
},
|
||||
"node_modules/json-refs": {
|
||||
"version": "3.0.15",
|
||||
"resolved": "https://registry.npmjs.org/json-refs/-/json-refs-3.0.15.tgz",
|
||||
|
@ -26796,6 +26919,22 @@
|
|||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/openapi3-ts": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/openapi3-ts/-/openapi3-ts-3.1.2.tgz",
|
||||
"integrity": "sha512-S8fijNOqe/ut0kEDAwHZnI7sVYqb8Q3XnISmSyXmK76jgrcf4ableI75KTY1qdksd9EI/t39Vi5M4VYKrkNKfQ==",
|
||||
"dependencies": {
|
||||
"yaml": "^2.1.3"
|
||||
}
|
||||
},
|
||||
"node_modules/openapi3-ts/node_modules/yaml": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.1.3.tgz",
|
||||
"integrity": "sha512-AacA8nRULjKMX2DvWvOAdBZMOfQlypSFkjcOcu9FalllIDJ1kvlREzcdIZmidQUqqeMv7jorHjq2HlLv/+c2lg==",
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/openid-client": {
|
||||
"version": "3.15.10",
|
||||
"resolved": "https://registry.npmjs.org/openid-client/-/openid-client-3.15.10.tgz",
|
||||
|
@ -28335,6 +28474,11 @@
|
|||
"asap": "~2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/promise-breaker": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/promise-breaker/-/promise-breaker-6.0.0.tgz",
|
||||
"integrity": "sha512-BthzO9yTPswGf7etOBiHCVuugs2N01/Q/94dIPls48z2zCmrnDptUUZzfIb+41xq0MnYZ/BzmOd6ikDR4ibNZA=="
|
||||
},
|
||||
"node_modules/promise.prototype.finally": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/promise.prototype.finally/-/promise.prototype.finally-3.1.3.tgz",
|
||||
|
@ -35771,12 +35915,15 @@
|
|||
},
|
||||
"services/chat": {
|
||||
"name": "@overleaf/chat",
|
||||
"version": "1.0.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@overleaf/logger": "*",
|
||||
"@overleaf/metrics": "*",
|
||||
"@overleaf/settings": "*",
|
||||
"async": "^3.2.2",
|
||||
"body-parser": "^1.19.0",
|
||||
"exegesis-express": "^4.0.0",
|
||||
"express": "4.17.1",
|
||||
"mongodb": "^4.11.0"
|
||||
},
|
||||
|
@ -41597,6 +41744,17 @@
|
|||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@apidevtools/json-schema-ref-parser": {
|
||||
"version": "9.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.0.9.tgz",
|
||||
"integrity": "sha512-GBD2Le9w2+lVFoc4vswGI/TjkNIZSVp7+9xPf+X3uidBfWnAeUWmquteSyt0+VCrhNMWj/FTABISQrD3Z/YA+w==",
|
||||
"requires": {
|
||||
"@jsdevtools/ono": "^7.1.3",
|
||||
"@types/json-schema": "^7.0.6",
|
||||
"call-me-maybe": "^1.0.1",
|
||||
"js-yaml": "^4.1.0"
|
||||
}
|
||||
},
|
||||
"@arrows/array": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@arrows/array/-/array-1.4.1.tgz",
|
||||
|
@ -44801,6 +44959,11 @@
|
|||
"integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==",
|
||||
"dev": true
|
||||
},
|
||||
"@jsdevtools/ono": {
|
||||
"version": "7.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz",
|
||||
"integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg=="
|
||||
},
|
||||
"@juggle/resize-observer": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@juggle/resize-observer/-/resize-observer-3.3.1.tgz",
|
||||
|
@ -46756,6 +46919,7 @@
|
|||
"body-parser": "^1.19.0",
|
||||
"chai": "^4.3.6",
|
||||
"chai-as-promised": "^7.1.1",
|
||||
"exegesis-express": "^4.0.0",
|
||||
"express": "4.17.1",
|
||||
"mocha": "^8.4.0",
|
||||
"mongodb": "^4.11.0",
|
||||
|
@ -53498,7 +53662,6 @@
|
|||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz",
|
||||
"integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
|
||||
"devOptional": true,
|
||||
"requires": {
|
||||
"ajv": "^8.0.0"
|
||||
},
|
||||
|
@ -53507,7 +53670,6 @@
|
|||
"version": "8.11.0",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz",
|
||||
"integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==",
|
||||
"devOptional": true,
|
||||
"requires": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"json-schema-traverse": "^1.0.0",
|
||||
|
@ -53518,8 +53680,7 @@
|
|||
"json-schema-traverse": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
|
||||
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
|
||||
"devOptional": true
|
||||
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -55091,6 +55252,11 @@
|
|||
"get-intrinsic": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"call-me-maybe": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz",
|
||||
"integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ=="
|
||||
},
|
||||
"callsites": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
|
||||
|
@ -56929,6 +57095,11 @@
|
|||
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
|
||||
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="
|
||||
},
|
||||
"deep-freeze": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/deep-freeze/-/deep-freeze-0.0.1.tgz",
|
||||
"integrity": "sha512-Z+z8HiAvsGwmjqlphnHW5oz6yWlOwu6EQfFTjmeTWlDeda3FS2yv3jhq35TX/ewmsnqB+RX2IdsIOyjJCQN5tg=="
|
||||
},
|
||||
"deep-is": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
|
||||
|
@ -58522,6 +58693,11 @@
|
|||
"resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz",
|
||||
"integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ="
|
||||
},
|
||||
"events-listener": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/events-listener/-/events-listener-1.1.0.tgz",
|
||||
"integrity": "sha512-Kd3EgYfODHueq6GzVfs/VUolh2EgJsS8hkO3KpnDrxVjU3eq63eXM2ujXkhPP+OkeUOhL8CxdfZbQXzryb5C4g=="
|
||||
},
|
||||
"execa": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
|
||||
|
@ -58562,6 +58738,77 @@
|
|||
"pify": "^2.2.0"
|
||||
}
|
||||
},
|
||||
"exegesis": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/exegesis/-/exegesis-4.1.1.tgz",
|
||||
"integrity": "sha512-PvSqaMOw2absLBgsthtJyVOeCHN4lxQ1dM7ibXb6TfZZJaoXtGELoEAGJRFvdN16+u9kg8oy1okZXRk8VpimWA==",
|
||||
"requires": {
|
||||
"@apidevtools/json-schema-ref-parser": "^9.0.3",
|
||||
"ajv": "^8.3.0",
|
||||
"ajv-formats": "^2.1.0",
|
||||
"body-parser": "^1.18.3",
|
||||
"content-type": "^1.0.4",
|
||||
"deep-freeze": "0.0.1",
|
||||
"events-listener": "^1.1.0",
|
||||
"glob": "^7.1.3",
|
||||
"json-ptr": "^3.0.1",
|
||||
"json-schema-traverse": "^1.0.0",
|
||||
"lodash": "^4.17.11",
|
||||
"openapi3-ts": "^3.1.1",
|
||||
"promise-breaker": "^6.0.0",
|
||||
"pump": "^3.0.0",
|
||||
"qs": "^6.6.0",
|
||||
"raw-body": "^2.3.3",
|
||||
"semver": "^7.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"ajv": {
|
||||
"version": "8.11.2",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.2.tgz",
|
||||
"integrity": "sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg==",
|
||||
"requires": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"json-schema-traverse": "^1.0.0",
|
||||
"require-from-string": "^2.0.2",
|
||||
"uri-js": "^4.2.2"
|
||||
}
|
||||
},
|
||||
"json-schema-traverse": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
|
||||
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
|
||||
},
|
||||
"lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"requires": {
|
||||
"yallist": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "7.3.8",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
|
||||
"integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
|
||||
"requires": {
|
||||
"lru-cache": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"exegesis-express": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/exegesis-express/-/exegesis-express-4.0.0.tgz",
|
||||
"integrity": "sha512-V2hqwTtYRj0bj43K4MCtm0caD97YWkqOUHFMRCBW5L1x9IjyqOEc7Xa4oQjjiFbeFOSQzzwPV+BzXsQjSz08fw==",
|
||||
"requires": {
|
||||
"exegesis": "^4.1.0"
|
||||
}
|
||||
},
|
||||
"exifr": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/exifr/-/exifr-6.3.0.tgz",
|
||||
|
@ -62925,6 +63172,11 @@
|
|||
"integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
|
||||
"dev": true
|
||||
},
|
||||
"json-ptr": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/json-ptr/-/json-ptr-3.1.1.tgz",
|
||||
"integrity": "sha512-SiSJQ805W1sDUCD1+/t1/1BIrveq2Fe9HJqENxZmMCILmrPI7WhS/pePpIOx85v6/H2z1Vy7AI08GV2TzfXocg=="
|
||||
},
|
||||
"json-refs": {
|
||||
"version": "3.0.15",
|
||||
"resolved": "https://registry.npmjs.org/json-refs/-/json-refs-3.0.15.tgz",
|
||||
|
@ -66450,6 +66702,21 @@
|
|||
"is-wsl": "^2.2.0"
|
||||
}
|
||||
},
|
||||
"openapi3-ts": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/openapi3-ts/-/openapi3-ts-3.1.2.tgz",
|
||||
"integrity": "sha512-S8fijNOqe/ut0kEDAwHZnI7sVYqb8Q3XnISmSyXmK76jgrcf4ableI75KTY1qdksd9EI/t39Vi5M4VYKrkNKfQ==",
|
||||
"requires": {
|
||||
"yaml": "^2.1.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"yaml": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.1.3.tgz",
|
||||
"integrity": "sha512-AacA8nRULjKMX2DvWvOAdBZMOfQlypSFkjcOcu9FalllIDJ1kvlREzcdIZmidQUqqeMv7jorHjq2HlLv/+c2lg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"openid-client": {
|
||||
"version": "3.15.10",
|
||||
"resolved": "https://registry.npmjs.org/openid-client/-/openid-client-3.15.10.tgz",
|
||||
|
@ -68105,6 +68372,11 @@
|
|||
"asap": "~2.0.3"
|
||||
}
|
||||
},
|
||||
"promise-breaker": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/promise-breaker/-/promise-breaker-6.0.0.tgz",
|
||||
"integrity": "sha512-BthzO9yTPswGf7etOBiHCVuugs2N01/Q/94dIPls48z2zCmrnDptUUZzfIb+41xq0MnYZ/BzmOd6ikDR4ibNZA=="
|
||||
},
|
||||
"promise.prototype.finally": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/promise.prototype.finally/-/promise.prototype.finally-3.1.3.tgz",
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
import logger from '@overleaf/logger'
|
||||
import settings from '@overleaf/settings'
|
||||
import { mongoClient } from './app/js/mongodb.js'
|
||||
import { server } from './app/js/server.js'
|
||||
import { createServer } from './app/js/server.js'
|
||||
|
||||
const port = settings.internal.chat.port
|
||||
const host = settings.internal.chat.host
|
||||
mongoClient
|
||||
.connect()
|
||||
.then(() => {
|
||||
.then(async () => {
|
||||
const { server } = await createServer()
|
||||
server.listen(port, host, function (err) {
|
||||
if (err) {
|
||||
logger.fatal({ err }, `Cannot bind to ${host}:${port}. Exiting.`)
|
||||
|
|
|
@ -3,24 +3,105 @@ import * as MessageManager from './MessageManager.js'
|
|||
import * as MessageFormatter from './MessageFormatter.js'
|
||||
import * as ThreadManager from '../Threads/ThreadManager.js'
|
||||
import { ObjectId } from '../../mongodb.js'
|
||||
import { expressify } from '../../util/promises.js'
|
||||
|
||||
const DEFAULT_MESSAGE_LIMIT = 50
|
||||
const MAX_MESSAGE_LENGTH = 10 * 1024 // 10kb, about 1,500 words
|
||||
|
||||
export const getGlobalMessages = expressify(async (req, res) => {
|
||||
async function readContext(context, req) {
|
||||
req.body = context.requestBody
|
||||
req.params = context.params.path
|
||||
req.query = context.params.query
|
||||
if (typeof req.params.projectId !== 'undefined') {
|
||||
if (!ObjectId.isValid(req.params.projectId)) {
|
||||
context.res.status(400).setBody('Invalid projectId')
|
||||
}
|
||||
}
|
||||
if (typeof req.params.threadId !== 'undefined') {
|
||||
if (!ObjectId.isValid(req.params.threadId)) {
|
||||
context.res.status(400).setBody('Invalid threadId')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function callMessageHttpController(context, ControllerMethod) {
|
||||
const req = {}
|
||||
readContext(context, req)
|
||||
if (context.res.statusCode !== 400) {
|
||||
return await ControllerMethod(req, context.res)
|
||||
} else {
|
||||
return context.res.body
|
||||
}
|
||||
}
|
||||
|
||||
export async function getGlobalMessages(context) {
|
||||
return await callMessageHttpController(context, _getGlobalMessages)
|
||||
}
|
||||
|
||||
export async function sendGlobalMessage(context) {
|
||||
return await callMessageHttpController(context, _sendGlobalMessage)
|
||||
}
|
||||
|
||||
export async function sendMessage(context) {
|
||||
return await callMessageHttpController(context, _sendThreadMessage)
|
||||
}
|
||||
|
||||
export async function getThreads(context) {
|
||||
return await callMessageHttpController(context, _getAllThreads)
|
||||
}
|
||||
|
||||
export async function resolveThread(context) {
|
||||
return await callMessageHttpController(context, _resolveThread)
|
||||
}
|
||||
|
||||
export async function reopenThread(context) {
|
||||
return await callMessageHttpController(context, _reopenThread)
|
||||
}
|
||||
|
||||
export async function deleteThread(context) {
|
||||
return await callMessageHttpController(context, _deleteThread)
|
||||
}
|
||||
|
||||
export async function editMessage(context) {
|
||||
return await callMessageHttpController(context, _editMessage)
|
||||
}
|
||||
|
||||
export async function deleteMessage(context) {
|
||||
return await callMessageHttpController(context, _deleteMessage)
|
||||
}
|
||||
|
||||
export async function destroyProject(context) {
|
||||
return await callMessageHttpController(context, _destroyProject)
|
||||
}
|
||||
|
||||
export async function getStatus(context) {
|
||||
const message = 'chat is alive'
|
||||
context.res.status(200).setBody(message)
|
||||
return message
|
||||
}
|
||||
|
||||
const _getGlobalMessages = async (req, res) => {
|
||||
await _getMessages(ThreadManager.GLOBAL_THREAD, req, res)
|
||||
})
|
||||
}
|
||||
|
||||
export const sendGlobalMessage = expressify(async (req, res) => {
|
||||
await _sendMessage(ThreadManager.GLOBAL_THREAD, req, res)
|
||||
})
|
||||
async function _sendGlobalMessage(req, res) {
|
||||
const { user_id: userId, content } = req.body
|
||||
const { projectId } = req.params
|
||||
return await _sendMessage(
|
||||
userId,
|
||||
projectId,
|
||||
content,
|
||||
ThreadManager.GLOBAL_THREAD,
|
||||
res
|
||||
)
|
||||
}
|
||||
|
||||
export const sendThreadMessage = expressify(async (req, res) => {
|
||||
await _sendMessage(req.params.threadId, req, res)
|
||||
})
|
||||
async function _sendThreadMessage(req, res) {
|
||||
const { user_id: userId, content } = req.body
|
||||
const { projectId, threadId } = req.params
|
||||
return await _sendMessage(userId, projectId, content, threadId, res)
|
||||
}
|
||||
|
||||
export const getAllThreads = expressify(async (req, res) => {
|
||||
const _getAllThreads = async (req, res) => {
|
||||
const { projectId } = req.params
|
||||
logger.debug({ projectId }, 'getting all threads')
|
||||
const rooms = await ThreadManager.findAllThreadRooms(projectId)
|
||||
|
@ -28,32 +109,32 @@ export const getAllThreads = expressify(async (req, res) => {
|
|||
const messages = await MessageManager.findAllMessagesInRooms(roomIds)
|
||||
const threads = MessageFormatter.groupMessagesByThreads(rooms, messages)
|
||||
res.json(threads)
|
||||
})
|
||||
}
|
||||
|
||||
export const resolveThread = expressify(async (req, res) => {
|
||||
const _resolveThread = async (req, res) => {
|
||||
const { projectId, threadId } = req.params
|
||||
const { user_id: userId } = req.body
|
||||
logger.debug({ userId, projectId, threadId }, 'marking thread as resolved')
|
||||
await ThreadManager.resolveThread(projectId, threadId, userId)
|
||||
res.sendStatus(204)
|
||||
})
|
||||
res.status(204)
|
||||
}
|
||||
|
||||
export const reopenThread = expressify(async (req, res) => {
|
||||
const _reopenThread = async (req, res) => {
|
||||
const { projectId, threadId } = req.params
|
||||
logger.debug({ projectId, threadId }, 'reopening thread')
|
||||
await ThreadManager.reopenThread(projectId, threadId)
|
||||
res.sendStatus(204)
|
||||
})
|
||||
res.status(204)
|
||||
}
|
||||
|
||||
export const deleteThread = expressify(async (req, res) => {
|
||||
const _deleteThread = async (req, res) => {
|
||||
const { projectId, threadId } = req.params
|
||||
logger.debug({ projectId, threadId }, 'deleting thread')
|
||||
const roomId = await ThreadManager.deleteThread(projectId, threadId)
|
||||
await MessageManager.deleteAllMessagesInRoom(roomId)
|
||||
res.sendStatus(204)
|
||||
})
|
||||
res.status(204)
|
||||
}
|
||||
|
||||
export const editMessage = expressify(async (req, res) => {
|
||||
const _editMessage = async (req, res) => {
|
||||
const { content, userId } = req.body
|
||||
const { projectId, threadId, messageId } = req.params
|
||||
logger.debug({ projectId, threadId, messageId, content }, 'editing message')
|
||||
|
@ -66,20 +147,21 @@ export const editMessage = expressify(async (req, res) => {
|
|||
Date.now()
|
||||
)
|
||||
if (!found) {
|
||||
return res.sendStatus(404)
|
||||
res.status(404)
|
||||
return
|
||||
}
|
||||
res.sendStatus(204)
|
||||
})
|
||||
res.status(204)
|
||||
}
|
||||
|
||||
export const deleteMessage = expressify(async (req, res) => {
|
||||
const _deleteMessage = async (req, res) => {
|
||||
const { projectId, threadId, messageId } = req.params
|
||||
logger.debug({ projectId, threadId, messageId }, 'deleting message')
|
||||
const room = await ThreadManager.findOrCreateThread(projectId, threadId)
|
||||
await MessageManager.deleteMessage(room._id, messageId)
|
||||
res.sendStatus(204)
|
||||
})
|
||||
res.status(204)
|
||||
}
|
||||
|
||||
export const destroyProject = expressify(async (req, res) => {
|
||||
const _destroyProject = async (req, res) => {
|
||||
const { projectId } = req.params
|
||||
logger.debug({ projectId }, 'destroying project')
|
||||
const rooms = await ThreadManager.findAllThreadRoomsAndGlobalThread(projectId)
|
||||
|
@ -88,22 +170,24 @@ export const destroyProject = expressify(async (req, res) => {
|
|||
await MessageManager.deleteAllMessagesInRooms(roomIds)
|
||||
logger.debug({ projectId }, 'deleting all threads in project')
|
||||
await ThreadManager.deleteAllThreadsInProject(projectId)
|
||||
res.sendStatus(204)
|
||||
})
|
||||
res.status(204)
|
||||
}
|
||||
|
||||
async function _sendMessage(clientThreadId, req, res) {
|
||||
const { user_id: userId, content } = req.body
|
||||
const { projectId } = req.params
|
||||
async function _sendMessage(userId, projectId, content, clientThreadId, res) {
|
||||
if (!ObjectId.isValid(userId)) {
|
||||
return res.status(400).send('Invalid userId')
|
||||
const message = 'Invalid userId'
|
||||
res.status(400).setBody(message)
|
||||
return message
|
||||
}
|
||||
if (!content) {
|
||||
return res.status(400).send('No content provided')
|
||||
const message = 'No content provided'
|
||||
res.status(400).setBody(message)
|
||||
return message
|
||||
}
|
||||
if (content.length > MAX_MESSAGE_LENGTH) {
|
||||
return res
|
||||
.status(400)
|
||||
.send(`Content too long (> ${MAX_MESSAGE_LENGTH} bytes)`)
|
||||
const message = `Content too long (> ${MAX_MESSAGE_LENGTH} bytes)`
|
||||
res.status(400).setBody(message)
|
||||
return message
|
||||
}
|
||||
logger.debug(
|
||||
{ clientThreadId, projectId, userId, content },
|
||||
|
@ -121,7 +205,7 @@ async function _sendMessage(clientThreadId, req, res) {
|
|||
)
|
||||
message = MessageFormatter.formatMessageForClientSide(message)
|
||||
message.room_id = projectId
|
||||
res.status(201).send(message)
|
||||
res.status(201).setBody(message)
|
||||
}
|
||||
|
||||
async function _getMessages(clientThreadId, req, res) {
|
||||
|
@ -153,5 +237,5 @@ async function _getMessages(clientThreadId, req, res) {
|
|||
let messages = await MessageManager.getMessages(threadObjectId, limit, before)
|
||||
messages = MessageFormatter.formatMessagesForClientSide(messages)
|
||||
logger.debug({ projectId, messages }, 'got messages')
|
||||
res.status(200).send(messages)
|
||||
res.status(200).setBody(messages)
|
||||
}
|
||||
|
|
|
@ -1,65 +0,0 @@
|
|||
import * as MessageHttpController from './Features/Messages/MessageHttpController.js'
|
||||
import { ObjectId } from './mongodb.js'
|
||||
|
||||
export function route(app) {
|
||||
app.param('projectId', function (req, res, next, projectId) {
|
||||
if (ObjectId.isValid(projectId)) {
|
||||
next()
|
||||
} else {
|
||||
res.status(400).send('Invalid projectId')
|
||||
}
|
||||
})
|
||||
|
||||
app.param('threadId', function (req, res, next, threadId) {
|
||||
if (ObjectId.isValid(threadId)) {
|
||||
next()
|
||||
} else {
|
||||
res.status(400).send('Invalid threadId')
|
||||
}
|
||||
})
|
||||
|
||||
// These are for backwards compatibility
|
||||
app.get('/room/:projectId/messages', MessageHttpController.getGlobalMessages)
|
||||
app.post('/room/:projectId/messages', MessageHttpController.sendGlobalMessage)
|
||||
|
||||
app.get(
|
||||
'/project/:projectId/messages',
|
||||
MessageHttpController.getGlobalMessages
|
||||
)
|
||||
app.post(
|
||||
'/project/:projectId/messages',
|
||||
MessageHttpController.sendGlobalMessage
|
||||
)
|
||||
|
||||
app.post(
|
||||
'/project/:projectId/thread/:threadId/messages',
|
||||
MessageHttpController.sendThreadMessage
|
||||
)
|
||||
app.get('/project/:projectId/threads', MessageHttpController.getAllThreads)
|
||||
|
||||
app.post(
|
||||
'/project/:projectId/thread/:threadId/messages/:messageId/edit',
|
||||
MessageHttpController.editMessage
|
||||
)
|
||||
app.delete(
|
||||
'/project/:projectId/thread/:threadId/messages/:messageId',
|
||||
MessageHttpController.deleteMessage
|
||||
)
|
||||
|
||||
app.post(
|
||||
'/project/:projectId/thread/:threadId/resolve',
|
||||
MessageHttpController.resolveThread
|
||||
)
|
||||
app.post(
|
||||
'/project/:projectId/thread/:threadId/reopen',
|
||||
MessageHttpController.reopenThread
|
||||
)
|
||||
app.delete(
|
||||
'/project/:projectId/thread/:threadId',
|
||||
MessageHttpController.deleteThread
|
||||
)
|
||||
|
||||
app.delete('/project/:projectId', MessageHttpController.destroyProject)
|
||||
|
||||
app.get('/status', (req, res, next) => res.send('chat is alive'))
|
||||
}
|
|
@ -2,18 +2,45 @@ import http from 'http'
|
|||
import metrics from '@overleaf/metrics'
|
||||
import logger from '@overleaf/logger'
|
||||
import express from 'express'
|
||||
import bodyParser from 'body-parser'
|
||||
import * as Router from './router.js'
|
||||
import exegesisExpress from 'exegesis-express'
|
||||
import path from 'path'
|
||||
import { fileURLToPath } from 'url'
|
||||
import * as messagesController from './Features/Messages/MessageHttpController.js'
|
||||
|
||||
const __dirname = fileURLToPath(new URL('.', import.meta.url))
|
||||
|
||||
metrics.initialize('chat')
|
||||
logger.initialize('chat')
|
||||
|
||||
export const app = express()
|
||||
export const server = http.createServer(app)
|
||||
export async function createServer() {
|
||||
const app = express()
|
||||
|
||||
app.use(bodyParser.json())
|
||||
app.use(bodyParser.urlencoded({ extended: true }))
|
||||
app.use(metrics.http.monitor(logger))
|
||||
metrics.injectMetricsRoute(app)
|
||||
// See https://github.com/exegesis-js/exegesis/blob/master/docs/Options.md
|
||||
const options = {
|
||||
controllers: { messagesController },
|
||||
ignoreServers: true,
|
||||
allowMissingControllers: false,
|
||||
}
|
||||
|
||||
Router.route(app)
|
||||
// const exegesisMiddleware = await exegesisExpress.middleware(
|
||||
const exegesisMiddleware = await exegesisExpress.middleware(
|
||||
path.resolve(__dirname, '../../chat.yaml'),
|
||||
options
|
||||
)
|
||||
|
||||
// If you have any body parsers, this should go before them.
|
||||
app.use(exegesisMiddleware)
|
||||
|
||||
// Return a 404
|
||||
app.use((req, res) => {
|
||||
res.status(404).json({ message: `Not found` })
|
||||
})
|
||||
|
||||
// Handle any unexpected errors
|
||||
app.use((err, req, res, next) => {
|
||||
res.status(500).json({ message: `Internal error: ${err.message}` })
|
||||
})
|
||||
|
||||
const server = http.createServer(app)
|
||||
return { app, server }
|
||||
}
|
||||
|
|
317
services/chat/chat.yaml
Normal file
317
services/chat/chat.yaml
Normal file
|
@ -0,0 +1,317 @@
|
|||
openapi: 3.1.0
|
||||
x-stoplight:
|
||||
id: okoe8mh50pjec
|
||||
info:
|
||||
title: chat
|
||||
version: '1.0'
|
||||
servers:
|
||||
- url: 'http://chat:3010'
|
||||
x-exegesis-controller: messagesController
|
||||
paths:
|
||||
'/project/{projectId}/messages':
|
||||
parameters:
|
||||
- schema:
|
||||
type: string
|
||||
name: projectId
|
||||
in: path
|
||||
required: true
|
||||
get:
|
||||
summary: Get Global messages
|
||||
tags: []
|
||||
responses:
|
||||
'201':
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/Message'
|
||||
operationId: getGlobalMessages
|
||||
description: Get global messages for the project with Project ID provided
|
||||
parameters:
|
||||
- schema:
|
||||
type: string
|
||||
in: query
|
||||
name: before
|
||||
- schema:
|
||||
type: string
|
||||
in: query
|
||||
name: limit
|
||||
post:
|
||||
summary: Send Global message
|
||||
operationId: sendGlobalMessage
|
||||
responses:
|
||||
'201':
|
||||
description: OK
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Message'
|
||||
examples:
|
||||
example-1:
|
||||
value:
|
||||
user_id: string
|
||||
content: string
|
||||
description: 'UserID and Content of the message to be posted. '
|
||||
description: Send global message for the project with Project ID provided
|
||||
'/project/{projectId}/thread/{threadId}/messages':
|
||||
parameters:
|
||||
- schema:
|
||||
type: string
|
||||
name: projectId
|
||||
in: path
|
||||
required: true
|
||||
- schema:
|
||||
type: string
|
||||
name: threadId
|
||||
in: path
|
||||
required: true
|
||||
post:
|
||||
summary: Send message
|
||||
operationId: sendMessage
|
||||
responses:
|
||||
'201':
|
||||
description: Created
|
||||
description: Add a message to the thread with thread ID provided from the Project with Project ID provided.
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Message'
|
||||
description: |-
|
||||
JSON object with :
|
||||
- user_id: Id of the user
|
||||
- content: Content of the message
|
||||
'/project/{projectId}/threads':
|
||||
parameters:
|
||||
- schema:
|
||||
type: string
|
||||
name: projectId
|
||||
in: path
|
||||
required: true
|
||||
get:
|
||||
summary: Get Threads
|
||||
tags: []
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/Thread'
|
||||
examples: {}
|
||||
'404':
|
||||
description: Not Found
|
||||
operationId: getThreads
|
||||
description: Get the list of threads for the project with Project ID provided
|
||||
'/project/{projectId}/thread/{threadId}/messages/{messageId}/edit':
|
||||
parameters:
|
||||
- schema:
|
||||
type: string
|
||||
name: projectId
|
||||
in: path
|
||||
required: true
|
||||
- schema:
|
||||
type: string
|
||||
name: threadId
|
||||
in: path
|
||||
required: true
|
||||
- schema:
|
||||
type: string
|
||||
name: messageId
|
||||
in: path
|
||||
required: true
|
||||
post:
|
||||
summary: Edit message
|
||||
operationId: editMessage
|
||||
responses:
|
||||
'204':
|
||||
description: No Content
|
||||
'404':
|
||||
description: Not Found
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
content:
|
||||
type: string
|
||||
user_id:
|
||||
type: string
|
||||
readOnly: true
|
||||
required:
|
||||
- content
|
||||
examples: {}
|
||||
description: |-
|
||||
JSON object with :
|
||||
- content: Content of the message to edit
|
||||
- user_id: Id of the user (optional)
|
||||
description: |
|
||||
Update message with Message ID provided from the Thread ID and Project ID provided
|
||||
'/project/{projectId}/thread/{threadId}/messages/{messageId}':
|
||||
parameters:
|
||||
- schema:
|
||||
type: string
|
||||
name: projectId
|
||||
in: path
|
||||
required: true
|
||||
- schema:
|
||||
type: string
|
||||
name: threadId
|
||||
in: path
|
||||
required: true
|
||||
- schema:
|
||||
type: string
|
||||
name: messageId
|
||||
in: path
|
||||
required: true
|
||||
delete:
|
||||
summary: Delete message
|
||||
operationId: deleteMessage
|
||||
responses:
|
||||
'204':
|
||||
description: No Content
|
||||
description: 'Delete message with Message ID provided, from the Thread with ThreadID and ProjectID provided'
|
||||
'/project/{projectId}/thread/{threadId}/resolve':
|
||||
parameters:
|
||||
- schema:
|
||||
type: string
|
||||
name: projectId
|
||||
in: path
|
||||
required: true
|
||||
- schema:
|
||||
type: string
|
||||
name: threadId
|
||||
in: path
|
||||
required: true
|
||||
post:
|
||||
summary: Resolve Thread
|
||||
operationId: resolveThread
|
||||
responses:
|
||||
'204':
|
||||
description: No Content
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
user_id:
|
||||
type: string
|
||||
required:
|
||||
- user_id
|
||||
description: |-
|
||||
JSON object with :
|
||||
- user_id: Id of the user.
|
||||
description: Mark Thread with ThreadID and ProjectID provided owned by the user with UserID provided as resolved.
|
||||
'/project/{projectId}/thread/{threadId}/reopen':
|
||||
parameters:
|
||||
- schema:
|
||||
type: string
|
||||
name: projectId
|
||||
in: path
|
||||
required: true
|
||||
- schema:
|
||||
type: string
|
||||
name: threadId
|
||||
in: path
|
||||
required: true
|
||||
post:
|
||||
summary: Reopen Thread
|
||||
operationId: reopenThread
|
||||
responses:
|
||||
'204':
|
||||
description: No Content
|
||||
description: |-
|
||||
Reopen Thread with ThreadID and ProjectID provided.
|
||||
i.e unmark it as resolved.
|
||||
'/project/{projectId}/thread/{threadId}':
|
||||
parameters:
|
||||
- schema:
|
||||
type: string
|
||||
name: projectId
|
||||
in: path
|
||||
required: true
|
||||
- schema:
|
||||
type: string
|
||||
name: threadId
|
||||
in: path
|
||||
required: true
|
||||
delete:
|
||||
summary: Delete thread
|
||||
operationId: deleteThread
|
||||
responses:
|
||||
'204':
|
||||
description: No Content
|
||||
description: Delete thread with ThreadID and ProjectID provided
|
||||
'/project/{projectId}':
|
||||
parameters:
|
||||
- schema:
|
||||
type: string
|
||||
name: projectId
|
||||
in: path
|
||||
required: true
|
||||
delete:
|
||||
summary: Destroy project
|
||||
operationId: destroyProject
|
||||
responses:
|
||||
'204':
|
||||
description: No Content
|
||||
description: 'Delete all threads from Project with Project ID provided, and all messages in those threads.'
|
||||
/status:
|
||||
get:
|
||||
summary: Check status
|
||||
tags: []
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: string
|
||||
description: chat is alive
|
||||
operationId: getStatus
|
||||
description: Check that the Chat service is alive
|
||||
head:
|
||||
summary: Check status
|
||||
tags: []
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: string
|
||||
description: chat is alive
|
||||
operationId: getStatus
|
||||
description: Check that the Chat service is alive
|
||||
components:
|
||||
schemas:
|
||||
Message:
|
||||
title: Message
|
||||
x-stoplight:
|
||||
id: ue9n1vvezlutw
|
||||
type: object
|
||||
examples:
|
||||
- user_id: string
|
||||
- content: string
|
||||
properties:
|
||||
user_id:
|
||||
type: string
|
||||
content:
|
||||
type: string
|
||||
required:
|
||||
- user_id
|
||||
- content
|
||||
Thread:
|
||||
title: Thread
|
||||
x-stoplight:
|
||||
id: 0ppt3jw4h5bua
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/Message'
|
|
@ -22,6 +22,7 @@
|
|||
"@overleaf/settings": "*",
|
||||
"async": "^3.2.2",
|
||||
"body-parser": "^1.19.0",
|
||||
"exegesis-express": "^4.0.0",
|
||||
"express": "4.17.1",
|
||||
"mongodb": "^4.11.0"
|
||||
},
|
||||
|
@ -35,5 +36,12 @@
|
|||
"sandboxed-module": "^2.0.4",
|
||||
"sinon": "^9.2.4",
|
||||
"timekeeper": "^2.2.0"
|
||||
}
|
||||
},
|
||||
"version": "1.0.0",
|
||||
"directories": {
|
||||
"test": "test"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "AGPL-3.0"
|
||||
}
|
||||
|
|
|
@ -28,6 +28,9 @@ describe('Getting messages', async function () {
|
|||
content2
|
||||
)
|
||||
expect(response2.statusCode).to.equal(201)
|
||||
const { response: response3, body } = await ChatClient.checkStatus()
|
||||
expect(response3.statusCode).to.equal(200)
|
||||
expect(body).to.equal('chat is alive')
|
||||
})
|
||||
|
||||
it('should contain the messages and populated users when getting the messages', async function () {
|
||||
|
|
|
@ -122,7 +122,9 @@ describe('Sending a message', async function () {
|
|||
null
|
||||
)
|
||||
expect(response.statusCode).to.equal(400)
|
||||
expect(body).to.equal('No content provided')
|
||||
// Exegesis is responding with validation errors. I can´t find a way to choose the validation error yet.
|
||||
// expect(body).to.equal('No content provided')
|
||||
expect(body.message).to.equal('Validation errors')
|
||||
})
|
||||
})
|
||||
|
||||
|
|
|
@ -1,20 +1,15 @@
|
|||
import { server } from '../../../../app/js/server.js'
|
||||
import { createServer } from '../../../../app/js/server.js'
|
||||
import { promisify } from 'util'
|
||||
|
||||
export { db } from '../../../../app/js/mongodb.js'
|
||||
|
||||
let serverPromise = null
|
||||
function startServer(resolve, reject) {
|
||||
server.listen(3010, 'localhost', error => {
|
||||
if (error) {
|
||||
return reject(error)
|
||||
}
|
||||
resolve()
|
||||
})
|
||||
}
|
||||
|
||||
export async function ensureRunning() {
|
||||
if (!serverPromise) {
|
||||
serverPromise = new Promise(startServer)
|
||||
const { app } = await createServer()
|
||||
const startServer = promisify(app.listen.bind(app))
|
||||
serverPromise = startServer(3010, 'localhost')
|
||||
}
|
||||
return serverPromise
|
||||
}
|
||||
|
|
|
@ -64,20 +64,6 @@ export async function resolveThread(projectId, threadId, userId) {
|
|||
})
|
||||
}
|
||||
|
||||
export async function reopenThread(projectId, threadId) {
|
||||
return asyncRequest({
|
||||
method: 'post',
|
||||
url: `/project/${projectId}/thread/${threadId}/reopen`,
|
||||
})
|
||||
}
|
||||
|
||||
export async function deleteThread(projectId, threadId) {
|
||||
return asyncRequest({
|
||||
method: 'delete',
|
||||
url: `/project/${projectId}/thread/${threadId}`,
|
||||
})
|
||||
}
|
||||
|
||||
export async function editMessage(projectId, threadId, messageId, content) {
|
||||
return asyncRequest({
|
||||
method: 'post',
|
||||
|
@ -105,6 +91,28 @@ export async function editMessageWithUser(
|
|||
})
|
||||
}
|
||||
|
||||
export async function checkStatus() {
|
||||
return asyncRequest({
|
||||
method: 'get',
|
||||
url: `/status`,
|
||||
json: true,
|
||||
})
|
||||
}
|
||||
|
||||
export async function reopenThread(projectId, threadId) {
|
||||
return asyncRequest({
|
||||
method: 'post',
|
||||
url: `/project/${projectId}/thread/${threadId}/reopen`,
|
||||
})
|
||||
}
|
||||
|
||||
export async function deleteThread(projectId, threadId) {
|
||||
return asyncRequest({
|
||||
method: 'delete',
|
||||
url: `/project/${projectId}/thread/${threadId}`,
|
||||
})
|
||||
}
|
||||
|
||||
export async function deleteMessage(projectId, threadId, messageId) {
|
||||
return asyncRequest({
|
||||
method: 'delete',
|
||||
|
|
Loading…
Reference in a new issue