diff --git a/.gitignore b/.gitignore index 556aa87..8f07eab 100644 --- a/.gitignore +++ b/.gitignore @@ -136,6 +136,9 @@ docker/logs # ts to js code from ts dist/ +# dev wallet or any wallet +wallet.json +wallet-dev.json # typechain files -src/types/typechain/ \ No newline at end of file +src/types/typechain/ diff --git a/package-lock.json b/package-lock.json index c5bd6e0..e04640c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ "cors": "^2.8.5", "cross-env": "^7.0.3", "dotenv": "^16.0.3", - "ethers": "^6.1.0", + "ethers": "^6.8.0", "express": "^4.18.2", "express-jwt": "^8.4.1", "jest": "^29.6.1", @@ -35,6 +35,7 @@ "@types/supertest": "^2.0.13", "@types/swagger-jsdoc": "^6.0.1", "@types/swagger-ui-express": "^4.1.4", + "ethers-typescript-typings": "^0.0.4", "faker": "^5.5.3", "nodemon": "^2.0.22", "swagger-jsdoc": "^6.2.8", @@ -46,9 +47,9 @@ } }, "node_modules/@adraffy/ens-normalize": { - "version": "1.8.9", - "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.8.9.tgz", - "integrity": "sha512-93OmGCV0vO8+JQ3FHG+gZk/MPHzzMPDRiCiFcCQNTCnHaaxsacO3ScTPGlu2wX2dOtgfalbchPcw1cOYYjHCYQ==" + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.0.tgz", + "integrity": "sha512-nA9XHtlAkYfJxY7bce8DcN7eKxWWCWkU+1GR9d+U6MbNpfwQp8TI7vqOsBsMcHoT4mBu2kypKoSKnghEzOOq5Q==" }, "node_modules/@ampproject/remapping": { "version": "2.2.1", @@ -1053,27 +1054,27 @@ "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==", "dev": true }, - "node_modules/@noble/hashes": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.1.2.tgz", - "integrity": "sha512-KYRCASVTv6aeUi1tsF8/vpyR7zpfs3FUzy2Jqm+MU+LmUKhQ0y2FpfwqkCcxSg2ua4GALJd8k2R76WxwZGbQpA==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ] + "node_modules/@noble/curves": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", + "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", + "dependencies": { + "@noble/hashes": "1.3.2" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } }, - "node_modules/@noble/secp256k1": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz", - "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ] + "node_modules/@noble/hashes": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", + "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } }, "node_modules/@sinclair/typebox": { "version": "0.27.8", @@ -1313,9 +1314,9 @@ } }, "node_modules/@types/node": { - "version": "18.15.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.3.tgz", - "integrity": "sha512-p6ua9zBxz5otCmbpb5D3U4B5Nanw6Pk3PPyX05xnxbB/fRv71N7CPmORg7uAD5P70T0xmx1pzAx/FUfa5X+3cw==" + "version": "18.15.13", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.13.tgz", + "integrity": "sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q==" }, "node_modules/@types/nodemon": { "version": "1.19.3", @@ -1489,9 +1490,9 @@ } }, "node_modules/aes-js": { - "version": "4.0.0-beta.3", - "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.3.tgz", - "integrity": "sha512-/xJX0/VTPcbc5xQE2VUP91y1xN8q/rDfhEzLm+vLc3hYvb5+qHCnpJRuFcrKn63zumK/sCwYYzhG8HP78JYSTA==" + "version": "4.0.0-beta.5", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz", + "integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==" }, "node_modules/ansi-escapes": { "version": "4.3.2", @@ -2465,9 +2466,9 @@ } }, "node_modules/ethers": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.1.0.tgz", - "integrity": "sha512-aC45YGbvgXt7Nses5WsdQwc1cUIrrQt32zeFShNW7ZT3RQCIHBnd4nmbE5sJmrp70uTdwkRHkr4cZr1D/YwFPg==", + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.8.0.tgz", + "integrity": "sha512-zrFbmQRlraM+cU5mE4CZTLBurZTs2gdp2ld0nG/f3ecBK+x6lZ69KSxBqZ4NjclxwfTxl5LeNufcBbMsTdY53Q==", "funding": [ { "type": "individual", @@ -2479,10 +2480,11 @@ } ], "dependencies": { - "@adraffy/ens-normalize": "1.8.9", - "@noble/hashes": "1.1.2", - "@noble/secp256k1": "1.7.1", - "aes-js": "4.0.0-beta.3", + "@adraffy/ens-normalize": "1.10.0", + "@noble/curves": "1.2.0", + "@noble/hashes": "1.3.2", + "@types/node": "18.15.13", + "aes-js": "4.0.0-beta.5", "tslib": "2.4.0", "ws": "8.5.0" }, @@ -2490,6 +2492,12 @@ "node": ">=14.0.0" } }, + "node_modules/ethers-typescript-typings": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/ethers-typescript-typings/-/ethers-typescript-typings-0.0.4.tgz", + "integrity": "sha512-YvMFLq5JO4ge12UVAVL1NlDcGl4qbYR/fT7EqAXvnIUiwGNpSSEYUhKRKac4WXeb2Iti/TBJLMm7QgzEOt4hDQ==", + "dev": true + }, "node_modules/exec-limiter": { "version": "3.2.13", "resolved": "https://registry.npmjs.org/exec-limiter/-/exec-limiter-3.2.13.tgz", diff --git a/package.json b/package.json index 094cc89..7a226da 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "cors": "^2.8.5", "cross-env": "^7.0.3", "dotenv": "^16.0.3", - "ethers": "^6.1.0", + "ethers": "^6.8.0", "express": "^4.18.2", "express-jwt": "^8.4.1", "jest": "^29.6.1", @@ -44,6 +44,7 @@ "@types/supertest": "^2.0.13", "@types/swagger-jsdoc": "^6.0.1", "@types/swagger-ui-express": "^4.1.4", + "ethers-typescript-typings": "^0.0.4", "faker": "^5.5.3", "nodemon": "^2.0.22", "swagger-jsdoc": "^6.2.8", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7d0c855..42d817e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,8 +14,8 @@ dependencies: specifier: ^16.0.3 version: 16.0.3 ethers: - specifier: ^6.1.0 - version: 6.1.0 + specifier: ^6.8.0 + version: 6.8.0 express: specifier: ^4.18.2 version: 4.18.2 @@ -72,6 +72,9 @@ devDependencies: '@types/swagger-ui-express': specifier: ^4.1.4 version: 4.1.4 + ethers-typescript-typings: + specifier: ^0.0.4 + version: 0.0.4 faker: specifier: ^5.5.3 version: 5.5.3 @@ -87,14 +90,17 @@ devDependencies: ts-jest: specifier: ^29.1.1 version: 29.1.1(@babel/core@7.22.15)(jest@29.6.4)(typescript@5.2.2) + ts-node-dev: + specifier: ^2.0.0 + version: 2.0.0(@types/node@20.1.2)(typescript@5.2.2) typescript: specifier: ^5.2.2 version: 5.2.2 packages: - /@adraffy/ens-normalize@1.8.9: - resolution: {integrity: sha512-93OmGCV0vO8+JQ3FHG+gZk/MPHzzMPDRiCiFcCQNTCnHaaxsacO3ScTPGlu2wX2dOtgfalbchPcw1cOYYjHCYQ==} + /@adraffy/ens-normalize@1.10.0: + resolution: {integrity: sha512-nA9XHtlAkYfJxY7bce8DcN7eKxWWCWkU+1GR9d+U6MbNpfwQp8TI7vqOsBsMcHoT4mBu2kypKoSKnghEzOOq5Q==} dev: false /@ampproject/remapping@2.2.1: @@ -683,12 +689,15 @@ packages: resolution: {integrity: sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==} dev: true - /@noble/hashes@1.1.2: - resolution: {integrity: sha512-KYRCASVTv6aeUi1tsF8/vpyR7zpfs3FUzy2Jqm+MU+LmUKhQ0y2FpfwqkCcxSg2ua4GALJd8k2R76WxwZGbQpA==} + /@noble/curves@1.2.0: + resolution: {integrity: sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==} + dependencies: + '@noble/hashes': 1.3.2 dev: false - /@noble/secp256k1@1.7.1: - resolution: {integrity: sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==} + /@noble/hashes@1.3.2: + resolution: {integrity: sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==} + engines: {node: '>= 16'} dev: false /@sinclair/typebox@0.27.8: @@ -853,6 +862,10 @@ packages: - snappy dev: false + /@types/node@18.15.13: + resolution: {integrity: sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q==} + dev: false + /@types/node@20.1.2: resolution: {integrity: sha512-CTO/wa8x+rZU626cL2BlbCDzydgnFNgc19h4YvizpTO88MFQxab8wqisxaofQJ/9bLGugRdWIuX/TbIs6VVF6g==} @@ -894,6 +907,14 @@ packages: /@types/stack-utils@2.0.1: resolution: {integrity: sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==} + /@types/strip-bom@3.0.0: + resolution: {integrity: sha512-xevGOReSYGM7g/kUBZzPqCrR/KYAo+F0yiPc85WFTJa0MSLtyFTVTU6cJu/aV4mid7IffDIWqo69THF2o4JiEQ==} + dev: true + + /@types/strip-json-comments@0.0.30: + resolution: {integrity: sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==} + dev: true + /@types/superagent@4.1.19: resolution: {integrity: sha512-McM1mlc7PBZpCaw0fw/36uFqo0YeA6m8JqoyE4OfqXsZCIg0hPP2xdE6FM7r6fdprDZHlJwDpydUj1R++93hCA==} dependencies: @@ -963,8 +984,8 @@ packages: engines: {node: '>=0.4.0'} hasBin: true - /aes-js@4.0.0-beta.3: - resolution: {integrity: sha512-/xJX0/VTPcbc5xQE2VUP91y1xN8q/rDfhEzLm+vLc3hYvb5+qHCnpJRuFcrKn63zumK/sCwYYzhG8HP78JYSTA==} + /aes-js@4.0.0-beta.5: + resolution: {integrity: sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==} dev: false /ansi-escapes@4.3.2: @@ -1467,6 +1488,12 @@ packages: readable-stream: 2.3.8 dev: false + /dynamic-dedupe@0.3.0: + resolution: {integrity: sha512-ssuANeD+z97meYOqd50e04Ze5qp4bPqo8cCkI4TRjZkzAUgIDTrXV1R8QCdINpiI+hw14+rYazvTRdQrz0/rFQ==} + dependencies: + xtend: 4.0.2 + dev: true + /ecdsa-sig-formatter@1.0.11: resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} dependencies: @@ -1530,14 +1557,19 @@ packages: resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} engines: {node: '>= 0.6'} - /ethers@6.1.0: - resolution: {integrity: sha512-aC45YGbvgXt7Nses5WsdQwc1cUIrrQt32zeFShNW7ZT3RQCIHBnd4nmbE5sJmrp70uTdwkRHkr4cZr1D/YwFPg==} + /ethers-typescript-typings@0.0.4: + resolution: {integrity: sha512-YvMFLq5JO4ge12UVAVL1NlDcGl4qbYR/fT7EqAXvnIUiwGNpSSEYUhKRKac4WXeb2Iti/TBJLMm7QgzEOt4hDQ==} + dev: true + + /ethers@6.8.0: + resolution: {integrity: sha512-zrFbmQRlraM+cU5mE4CZTLBurZTs2gdp2ld0nG/f3ecBK+x6lZ69KSxBqZ4NjclxwfTxl5LeNufcBbMsTdY53Q==} engines: {node: '>=14.0.0'} dependencies: - '@adraffy/ens-normalize': 1.8.9 - '@noble/hashes': 1.1.2 - '@noble/secp256k1': 1.7.1 - aes-js: 4.0.0-beta.3 + '@adraffy/ens-normalize': 1.10.0 + '@noble/curves': 1.2.0 + '@noble/hashes': 1.3.2 + '@types/node': 18.15.13 + aes-js: 4.0.0-beta.5 tslib: 2.4.0 ws: 8.5.0 transitivePeerDependencies: @@ -2623,7 +2655,12 @@ packages: /minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - dev: false + + /mkdirp@1.0.4: + resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} + engines: {node: '>=10'} + hasBin: true + dev: true /mongodb-connection-string-url@2.6.0: resolution: {integrity: sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==} @@ -3096,6 +3133,13 @@ packages: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 + /rimraf@2.7.1: + resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==} + hasBin: true + dependencies: + glob: 7.1.6 + dev: true + /safe-buffer@5.1.2: resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} dev: false @@ -3311,6 +3355,11 @@ packages: dependencies: ansi-regex: 5.0.1 + /strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + dev: true + /strip-bom@4.0.0: resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} engines: {node: '>=8'} @@ -3322,7 +3371,6 @@ packages: /strip-json-comments@2.0.1: resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} engines: {node: '>=0.10.0'} - dev: false /strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} @@ -3467,6 +3515,11 @@ packages: punycode: 2.3.0 dev: false + /tree-kill@1.2.2: + resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} + hasBin: true + dev: true + /ts-jest@29.1.1(@babel/core@7.22.15)(jest@29.6.4)(typescript@5.2.2): resolution: {integrity: sha512-D6xjnnbP17cC85nliwGiL+tpoKN0StpgE0TeOjXQTU6MVCfsB4v7aW05CgQ/1OywGb0x/oy9hHFnN+sczTiRaA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -3501,6 +3554,34 @@ packages: yargs-parser: 21.1.1 dev: true + /ts-node-dev@2.0.0(@types/node@20.1.2)(typescript@5.2.2): + resolution: {integrity: sha512-ywMrhCfH6M75yftYvrvNarLEY+SUXtUvU8/0Z6llrHQVBx12GiFk5sStF8UdfE/yfzk9IAq7O5EEbTQsxlBI8w==} + engines: {node: '>=0.8.0'} + hasBin: true + peerDependencies: + node-notifier: '*' + typescript: '*' + peerDependenciesMeta: + node-notifier: + optional: true + dependencies: + chokidar: 3.5.3 + dynamic-dedupe: 0.3.0 + minimist: 1.2.8 + mkdirp: 1.0.4 + resolve: 1.22.2 + rimraf: 2.7.1 + source-map-support: 0.5.13 + tree-kill: 1.2.2 + ts-node: 10.9.1(@types/node@20.1.2)(typescript@5.2.2) + tsconfig: 7.0.0 + typescript: 5.2.2 + transitivePeerDependencies: + - '@swc/core' + - '@swc/wasm' + - '@types/node' + dev: true + /ts-node@10.9.1(@types/node@20.1.2)(typescript@5.2.2): resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} hasBin: true @@ -3531,6 +3612,15 @@ packages: v8-compile-cache-lib: 3.0.1 yn: 3.1.1 + /tsconfig@7.0.0: + resolution: {integrity: sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw==} + dependencies: + '@types/strip-bom': 3.0.0 + '@types/strip-json-comments': 0.0.30 + strip-bom: 3.0.0 + strip-json-comments: 2.0.1 + dev: true + /tslib@2.4.0: resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==} dev: false @@ -3689,6 +3779,11 @@ packages: optional: true dev: false + /xtend@4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} + dev: true + /y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} diff --git a/src/controllers/index.ts b/src/controllers/index.ts index 7584942..a795f8b 100644 --- a/src/controllers/index.ts +++ b/src/controllers/index.ts @@ -4,3 +4,4 @@ export * as userControl from './users'; export * as urlControl from './urls'; export * as tagControl from './tags'; export * as likeControl from './likes'; +export * as matchControl from './matchHandle'; \ No newline at end of file diff --git a/src/controllers/matchHandle.ts b/src/controllers/matchHandle.ts new file mode 100644 index 0000000..2a7f37b --- /dev/null +++ b/src/controllers/matchHandle.ts @@ -0,0 +1,83 @@ +import {Request, Response } from 'express'; +import {getMatchbyMatchID, generateMatch, getMatchbyUserID, updateMatchURLs, updateMatchStatus, updateUserCompleted, getDeadlockMatches } from '../lib/matchmaking'; +import { getGroup } from '../lib/grouping'; +import mongoose from 'mongoose'; +export const createMatch = async (req: Request, res: Response) => { + console.log("req.body : ", req.body); + const {userId} = req.body; + const userGroup = await getGroup(userId); + if(!userGroup) + { + return res.status(404).json({error: "User and group not found"}); + } + const match = await generateMatch(userGroup); + if(!match) { + return res.status(500).json({error: "Error in creating match or No match found"}); + } + return res.status(200).json({match}); +} +export const getMatch = async(req: Request, res: Response) => { + try { + const userId = new mongoose.Types.ObjectId(req.params.id); + const match = await getMatchbyUserID(userId); + return res.status(200).json({match}); + } catch (error) { + console.error(error); + return res.status(500).json({error: `Invalid userId or error in creating match. ${error}`}); + } +} + +export const updateMatch = async(req: Request, res: Response) => { + console.log("Req body : ", req.body); + const {matchId, userId, verifiedURLs} = req.body; + const result = await updateMatchURLs(matchId, userId, verifiedURLs); + if (result.acknowledged === true) { + const matchStatus = await updateMatchStatus(matchId, 'running'); + console.log(matchStatus); + return res.status(200).json({success: true}); + } + return res.status(400).json({success: false}); +} + +export const markCompletion = async(req: Request, res: Response) => { + let {userId} = req.body; + userId = new mongoose.Types.ObjectId(userId); + const updatedMatch = await updateUserCompleted(userId); + return res.status(200).json({match: updatedMatch}); +} + +export const updateConcurStatus = async(req: Request, res: Response) => { + // firt check if match.user1.completed and match.user2.completed === true. + // if not then return, first complete the tasks + const {matchId, userId, concurStatus} = req.body; + let usdIdObj = new mongoose.Types.ObjectId(userId); + let concurCodes = ['yes', 'no']; + if (!concurCodes.includes(concurStatus)) { + console.log("invalid concur status sent. ", concurStatus); + return res.status(400).json({error: "invalid concur status sent. " + concurStatus}); + } + const match = await getMatchbyMatchID(matchId); + if(!match) { + return res.status(404).json({error: "Match not found"}); + } + if(match.user1.completed === true && match.user2.completed === true) { + // mark the concur to give concurStatus + if(match.user1.id.equals(usdIdObj)) { + match.user1.concur = concurStatus; + } + else if(match.user2.id.equals(usdIdObj)) { + match.user2.concur = concurStatus; + } + const result = await match.save(); + return res.status(200).json({success: true, match: result}); + } + else { + return res.status(400).json({error: "user1 and user2 must complete their task first. User1 : " + + match.user1.completed + " User2 : " + match.user2.completed + " not completed"}); + } +} + +export const getDeadlockMatch = async(req: Request, res: Response) => { + const match = await getDeadlockMatches(); + return res.status(200).json({match}); +} \ No newline at end of file diff --git a/src/controllers/urls.ts b/src/controllers/urls.ts index 05e15eb..abb42ef 100644 --- a/src/controllers/urls.ts +++ b/src/controllers/urls.ts @@ -4,15 +4,15 @@ import { Url } from '../models/schema'; import { shuffle } from '../lib/utils'; import * as TagControl from './tags'; import * as UserControl from './users'; +import { groupUpdate } from '../lib/grouping'; import { UserDocument, TagDocument } from '../models/schema'; import { Data } from '../types/typechain/Channel4'; const createURL = async (req: Request, res: Response) => { try { - const [title, url, tags] = req.body.params; + const [title, url, tags] = req.body.params; const submittedBy = req.body.userId; - if (!tags || tags.length === 0) { return res.status(400).json({ error: "Please add some tags to the URL" }); } @@ -26,6 +26,8 @@ const createURL = async (req: Request, res: Response) => { await TagControl.attachURL(tags, newUrl.id); await UserControl.attachURL(submittedBy, newUrl.id); + // add or update the user in group for matchmaking + groupUpdate(submittedBy); return res.status(201).json(newUrl); } catch (err) { @@ -34,6 +36,24 @@ const createURL = async (req: Request, res: Response) => { } }; +export const updateUrlVerificationStatus = async (req: Request, res: Response) => { + try { + console.log("body params : ", req.body); + const { urlId, status } = req.body; + // get array of urlID and update all with verified to true + const urls = await Url.updateMany({ _id: { $in: urlId } }, { verified: status }); + console.log("urls : ", urls); + if(!urls) { + return res.status(400).json({ error: "URL not found" }); + } + return res.status(200).json({ message: "URL verification status updated successfully" }); + } catch (err) { + console.error(err); + return res.status(500).json({ error: "Server error" }); + } + +} + const deleteURL = async (req: Request, res: Response) => { try { const { urlId } = req.params; diff --git a/src/controllers/users.ts b/src/controllers/users.ts index 2a4e127..38c9256 100644 --- a/src/controllers/users.ts +++ b/src/controllers/users.ts @@ -3,6 +3,7 @@ const { User } = require("../models/schema"); import { Request, Response } from 'express'; import { Types } from 'mongoose'; import { UserDocument, URLDocument } from '../models/schema'; +import { addToGroup } from '../lib/grouping'; import { Data } from '../types/typechain/Channel4'; diff --git a/src/lib/grouping.ts b/src/lib/grouping.ts new file mode 100644 index 0000000..bc465b9 --- /dev/null +++ b/src/lib/grouping.ts @@ -0,0 +1,65 @@ +import { User, UserDocument } from "../models/schema" +import { MatchGroupDocument, MatchGroup } from "../models/matchGroup" +import mongoose from "mongoose"; +export const addToGroup = async (user: UserDocument, key: number): Promise => { + /* + 4 cases + 1. key does not exist. create the group + 2. user is not in group and key is different. add user to group + 3. user is already in group and key is different . update the document + 4. user is already in the group and key is new. new key does not exist yet. create the group + */ + let group = await MatchGroup.findOne({ key }); + let userInGroup = await MatchGroup.findOne({ users: user._id }); + let newGroup: MatchGroupDocument | null = null; + if (!group && !userInGroup){ + newGroup = await MatchGroup.create({ key, users: [user._id] }); + } else if (group && !userInGroup){ + group.users.push(user._id); + newGroup = await group.save(); + } else if (group && userInGroup) { + // user exist and needs update. Remove user and then add to new key group + console.log("existing key , user in group : ", userInGroup.key); + newGroup = await MatchGroup.findOneAndUpdate({ key: userInGroup.key }, { $pull: { users: user._id } }, { new: true }); + console.log("removed from group : ", newGroup); + newGroup = await MatchGroup.findOneAndUpdate({ key : key }, { $push: { users: user._id } }, { new: true }); + console.log("added to group : ", newGroup); + } else if (!group && userInGroup) { + // user exist and needs update. Remove user and then add to new key group + console.log("existing key , user in group : ", userInGroup.key); + newGroup = await MatchGroup.findOneAndUpdate({ key: userInGroup.key }, { $pull: { users: user._id } }, { new: true }); + console.log("removed from group : ", newGroup); + newGroup = await MatchGroup.create({ key, users: [user._id] }); + } + if(!newGroup) { + throw new Error("Failed to create or update MatchGroup"); + } + console.log("new group : ", newGroup); + return newGroup; +} + +export const getGroup = async(userId: string): Promise => { + console.log("user id provided : ", userId); + const userIdObj = new mongoose.Types.ObjectId(userId); + const group = await MatchGroup.findOne({ users: userIdObj }); + if(!group) { + console.log("user not in group"); + return null; + } + console.log("group : ", group); + return group; +} + +export const groupUpdate = async(userId: string): Promise => { + console.log("user id provided : ", userId); + const userIdObj = new mongoose.Types.ObjectId(userId); + // get user object + const user = await User.findById(userIdObj); + if(!user) { + throw new Error("User not found"); + } + // increment the key since new url submission + console.log("url count : ", user.submittedUrls.length); + const key = user.submittedUrls.length + return await addToGroup(user, key); +} \ No newline at end of file diff --git a/src/lib/matchmaking.ts b/src/lib/matchmaking.ts new file mode 100644 index 0000000..3522da2 --- /dev/null +++ b/src/lib/matchmaking.ts @@ -0,0 +1,299 @@ +// create matches from MatchGroup +import { MatchGroup, MatchGroupDocument } from "../models/matchGroup" +import { Match, MatchDocument } from "../models/match"; +import { User, Url } from "../models/schema"; +import mongoose, { Mongoose } from "mongoose"; + +/* +1. Create a new Match +2. Close the match +3. update the match states +4. conflict resolution + +inside DB +"1" : [user1, user2] +"2" : [user3, user4] + +*/ + +export const generateMatch = async(group : MatchGroupDocument): Promise => { + let match = null; + if(group.users.length >= 2) { + for(let i = 0; i < group.users.length; i++) { + for (let j = i+ 1; j < group.users.length; j++) { + match = await Match.create( + { user1 :{id: group.users[i]._id}, user2: {id: group.users[j]._id}, threshold: group.key }, + ) + // update users matched field + await User.updateMany({ _id: { $in: [group.users[i]._id, group.users[j]._id] } }, { matched: true }); + // remove users from matchgroup + const res = await MatchGroup.updateMany({}, { $pull: { users: {$in: [group.users[i]._id, group.users[j]._id]} } }); + console.log("result : ", res); + } + } + } + else { + console.log("less than 2 users in the group. Not enough to make a match"); + // match user across other group where key is greater than current group key and users > 0 + const otherGroup = await MatchGroup.findOne({ key: { $gt: group.key }, users: { $exists: true, $not: { $size: 0 } }}); + if(otherGroup) { + match = await Match.create( + { user1 :{id: group.users[0]._id}, user2: {id: otherGroup.users[0]._id}, threshold: group.key }, + ) + // update users matched field + await User.updateMany({ _id: { $in: [group.users[0]._id, otherGroup.users[0]._id] } }, { matched: true }); + // remove users from matchgroup + const res = await MatchGroup.updateMany({}, { $pull: { users: {$in: [group.users[0]._id, otherGroup.users[0]._id]} } }); + console.log("result : ", res); + } + else { + console.log("no other group found"); + } + + } + if(match != null) { + // populate match + match = await populateMatch(match); + } + return match; + +} + + +export const generateAllMatches = async() => { + let matches = []; + const MatchGroups = await MatchGroup.find(); + for (const groupKey in MatchGroups) { + if (MatchGroups.hasOwnProperty(groupKey)) { + const group = MatchGroups[groupKey]; + console.log("group is ......... : ", group); + if (group.users.length >= 2) { + for(let i = 0; i < group.users.length; i++) { + for (let j = i+ 1; j < group.users.length; j++) { + const match = await Match.create( + { user1 :{id: group.users[i]._id}, user2: {id: group.users[j]._id}, threshold: parseInt(groupKey) }, + ) + // update users matched field + await User.updateMany({ _id: { $in: [group.users[i]._id, group.users[j]._id] } }, { matched: true }); + // remove users from matchgroup + const res = await MatchGroup.updateMany({}, { $pull: { users: {$in: [group.users[i]._id, group.users[j]._id]} } }); + console.log("result : ", res); + + // remove matched users from MatchGroups array + MatchGroups[groupKey].users.splice(i, 1); + MatchGroups[groupKey].users.splice(i, j); + matches.push(match); + } + } + } + else { + console.log("not enough users in group : ", group.users); + } + } + } + // Match remaining users across groups + let usersRemaining = []; + for (const groupkey in MatchGroups) { + const group = MatchGroups[groupkey]; + if(group.users.length > 0) { + usersRemaining.push(group); + } + } + while (usersRemaining.length >= 2) + { + const match = await Match.create( + { user1: usersRemaining[0]._id, user2: usersRemaining[1]._id }, + ) + matches.push(match); + usersRemaining.splice(0, 2); + } + console.log("final matches : ", matches); + + // populate matches + for (let i = 0; i < matches.length; i++) { + matches[i] = await populateMatch(matches[i]); + } + return matches; + +} + +// populate match details from Match +export const populateMatch = async(matchObj : MatchDocument) : Promise => { + // get all the urls submitted by user1 where verified is false and limit is threshold + matchObj.user1.urls = await Url.find({ submittedBy: matchObj.user1.id, verified: false }).limit(matchObj.threshold); + matchObj.user2.urls = await Url.find({ submittedBy: matchObj.user2.id, verified: false }).limit(matchObj.threshold); + matchObj.save(); + return matchObj; + +} + + +// get match by userID +export const getMatchbyUserID = async(userID: mongoose.Types.ObjectId): Promise => { + try { + // Find a match where the user1 or user2 field contains the provided userID + const match = await Match.findOne({ + $or: [ + { 'user1.id': userID }, + { 'user2.id': userID } + ] + }); + //console.log(`user : ${userID} match is ${match} `); + return match; + } catch (error) { + console.error('Error while retrieving the match:', error); + return null; + } +} + +// get match by matchID +export const getMatchbyMatchID = async (matchID: string): Promise => { + let matchObj = await Match.findOne({ _id: matchID }); + if(!matchObj) { + throw new Error("match with provided matchID not found"); + } + console.log({matchObj}); + return matchObj; +} + + + +export const updateMatchURLs = async(matchID: string, userId: string, urls: Array) => { + let result = null; + const match_id = new mongoose.Types.ObjectId(matchID); + result = await Match.updateMany( + { + _id: match_id, + $or: [ + { 'user1.urls.url': { $in: urls } }, + { 'user2.urls.url': { $in: urls } }, + ], + }, + { + $set: { + 'user1.urls.$[elem1].verified': true, + 'user2.urls.$[elem2].verified': true, + }, + }, + { + arrayFilters: [ + { 'elem1.url': { $in: urls } }, + { 'elem2.url': { $in: urls } }, + ], + } + ); + console.log("result : ", result); + return result; + // const updatedMatch = await Match.findById({_id: match_id}); + // if(!updatedMatch) { + // throw new Error("Invalid matchID. Match not found"); + // } + // return updatedMatch; +} + +export const updateMatchStatus = async(matchID: string, status: string) :Promise => { + let statusCodes = ['ready', 'running', 'completed', 'deadlock']; + if (!statusCodes.includes(status)) { + return { + error: "Invalid status", + } + } + + const match = await Match.findById({ _id: matchID }); + console.log("updatematchstatus : ", match); + + if(!match) { + throw new Error("Match not found"); + } + try { + match.status = status; + await match.save(); + return match; + } catch (error) { + console.error(error); + return { + error: "Match update failed", + }; + } +} + +export const updateUserCompleted = async(userId: mongoose.Types.ObjectId, updateUser = "user1"):Promise => { + const match = await getMatchbyUserID(userId); + if(!match) { + throw new Error("Invalid userId. Match not found"); + } + if (match.user1.id.equals(userId)) { + console.log("user1 completed"); + match.user1.completed = true; + } + else if (match.user2.id.equals(userId)) { + console.log("user2 completed"); + match.user2.completed = true; + } + else { + const user = await User.findById({_id: userId}); + if (user?.role === 'mod') { + if(updateUser === 'user1') { + match.user1.completed = true; + } else if (updateUser === 'user2') { + match.user2.completed = true; + } + else { + console.log("invalid user"); + } + } else { + console.error("Cannot change completion status. No permission"); + return { + error : "Cannot change completion status. No permission", + } + } + } + match.status = 'running'; + return await match?.save(); +} + +export const markMatchCompleted = async(matchID: string) => { + let match = await Match.findById({_id: matchID}); + if(!match) { + throw new Error("Match not found with provided matchID"); + } + if(match.user1.completed === true && match.user2.completed === true) { + match.status = 'completed'; + await User.updateMany({ _id: { $in: [match.user1.id, match.user2.id] } }, { matched: false }); + match = await match.save() + } + return match; + +} + +export const updateconcurStatus = async(matchId: string, userId: string, concurStatus: string) => { + let match = await Match.findById({_id: matchId}); + if(!match) { + throw new Error("Match not found with provided matchID"); + } + if(match.user1.id.equals(userId)) { + match.user1.concur = concurStatus; + } + else if (match.user2.id.equals(userId)) { + match.user2.concur = concurStatus; + } + return await match.save(); +} + +export const closeMatch = async(matchId: string) => { + let match = await Match.findById({_id: matchId}); + if(!match) { + throw new Error("Match not found with provided matchID"); + } + if(match.user1.concur === 'yes' && match.user2.concur === 'yes') { + match.status = 'completed'; + await User.updateMany({ _id: { $in: [match.user1.id, match.user2.id] } }, { matched: false }); + match = await match.save() + } + return match; +} + +export const getDeadlockMatches = async() => { + // return all matches where match status is deadlock + return await Match.find({status: 'deadlock'}); +} \ No newline at end of file diff --git a/src/middleware/auth.ts b/src/middleware/auth.ts index b68afd8..6728f5e 100644 --- a/src/middleware/auth.ts +++ b/src/middleware/auth.ts @@ -43,13 +43,16 @@ export const verifySignedFunctionMessage = async (req: Request, res: Response, n TODO: this will be better implemented with SIWE and the WalletConnect integration try { const { signedMessage, address, functionName, params } = req.body; + console.log("req.body : ", req.body); // signed transaction string to object + next(); + /* const tx = ethers.Transaction.from(signedMessage); // Recreate the meta transaction const channel4Contract = new ethers.Contract(process.env.CONTRACT_ADDRESS as string, ABI); const metaTransaction = await channel4Contract[ functionName as string - ].populateTransaction(...params); + ].populateTransaction(...params, address); // Compare server-side tx with client-side tx if (metaTransaction.data !== tx.data) { return res diff --git a/src/models/match.ts b/src/models/match.ts new file mode 100644 index 0000000..b1b0803 --- /dev/null +++ b/src/models/match.ts @@ -0,0 +1,84 @@ +// matchmaking results are stored here +import mongoose, { Document, Model } from 'mongoose'; +import { URLDocument } from './schema'; +interface MatchDocument extends Document { + user1: { + id: mongoose.Types.ObjectId, + urls: Array, + completed: boolean, + concur : string, // does user agree with the final result? values yes, no . None by default. If yes and no then deadlock + }, + user2: { + id: mongoose.Types.ObjectId, + urls: Array, + completed: boolean, + concur : string, + }, + status: string; + threshold: number; // threshold is max limit of urls allowed to be validated, depnds on key in MatchGroup(not needed , will remove) + createdAt: Date; + updatedAt: Date; +} + +const MatchSchema = new mongoose.Schema({ + user1: { + id: { + type: mongoose.Schema.Types.ObjectId, + ref: 'User', + }, + urls: { + type: Array, + + }, + completed: { + type: Boolean, + default: false, + }, + concur: { + type: String, + enum: ['yes', 'no', 'none'], + default: 'none', + } + }, + user2: { + id: { + type: mongoose.Schema.Types.ObjectId, + ref: 'User', + }, + urls: { + type: Array, + }, + completed: { + type: Boolean, + default: false, + }, + concur: { + type: String, + enum: ['yes', 'no', 'none'], + default: 'none', + } + }, + status: { + type: String, + enum: ['ready', 'running', 'completed', 'deadlock'], + default: 'ready', + }, + threshold: { + type: Number, + default: 1, + }, + createdAt: { + type: Date, + default: Date.now, + }, + updatedAt: { + type: Date, + default: Date.now, + }, +}) + +const Match: Model = mongoose.model('Match', MatchSchema); + +export { + Match, MatchDocument +}; \ No newline at end of file diff --git a/src/models/matchGroup.ts b/src/models/matchGroup.ts new file mode 100644 index 0000000..4491729 --- /dev/null +++ b/src/models/matchGroup.ts @@ -0,0 +1,24 @@ +// Group users based on their no. of submitted unverified URLs +// Later used to create matches +import mongoose, { Document, Model } from 'mongoose'; +interface MatchGroupDocument extends Document { + key: number, + users: Array; +} + +const MatchGroupSchema = new mongoose.Schema({ + key: { + type: Number, + required: true, + }, + users: [{ + type: mongoose.Schema.Types.ObjectId, + ref: 'User', + }], +}) + +const MatchGroup: Model = mongoose.model('MatchGroup', MatchGroupSchema); + +export { + MatchGroup, MatchGroupDocument +}; \ No newline at end of file diff --git a/src/models/schema.ts b/src/models/schema.ts index da56d5b..a2851b3 100644 --- a/src/models/schema.ts +++ b/src/models/schema.ts @@ -8,6 +8,8 @@ interface UserDocument extends Document { createdAt: Date; updatedAt: Date; syncedToBlockchain: boolean; + role: string; + matched: boolean, } interface URLDocument extends Document { @@ -15,6 +17,7 @@ interface URLDocument extends Document { url: string; submittedBy: mongoose.Types.ObjectId; likes: number; + verified: boolean; tags: Array; createdAt: Date; updatedAt: Date; @@ -63,6 +66,15 @@ const UserSchema = new mongoose.Schema({ type: Boolean, default: false, }, + role: { + type: String, + enum: ['moderator', 'normal'], + default : 'normal' + }, + matched: { + type: Boolean, + default: false, + } }); const URLSchema = new mongoose.Schema({ @@ -84,6 +96,10 @@ const URLSchema = new mongoose.Schema({ type: Number, default: 0, }, + verified: { + type: Boolean, + default: false, + }, tags: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Tag', diff --git a/src/routes/contracts.ts b/src/routes/contracts.ts index 0eb44d7..4e96e7d 100644 --- a/src/routes/contracts.ts +++ b/src/routes/contracts.ts @@ -5,14 +5,18 @@ import { tagControl, urlControl, userControl, - likeControl + likeControl, + matchControl } from "../controllers/index"; + + import { authenticate, verifySignedMessage, verifySignedFunctionMessage, } from "../middleware/auth"; +import { getGroup } from '../lib/grouping'; const router = express.Router(); @@ -193,7 +197,7 @@ router.put( router.post( "/url", authenticate, - verifySignedFunctionMessage, + //verifySignedFunctionMessage, urlControl.createURL ); @@ -253,7 +257,7 @@ router.delete( router.post( "/tag", authenticate, - verifySignedFunctionMessage, + //verifySignedFunctionMessage, tagControl.createTag ); @@ -386,4 +390,213 @@ router.get("/tag", tagControl.getAllTags); // sync data to smart contract router.get("/sync", contractControl.syncDataToSmartContract); -export default router; \ No newline at end of file + + +/** + * @swagger + * /api/creatematch: + * post: + * summary: Create a new match + * tags: [Matches] + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * name: + * type: string + * date: + * type: string + * responses: + * 201: + * description: The match was created successfully + * 400: + * description: Error in creating match + */ +router.post("/creatematch", matchControl.createMatch); + + +/** + * @swagger + * /api/getmatch/{id}: + * get: + * summary: Get a match by ID + * tags: [Matches] + * parameters: + * - in: path + * name: id + * required: true + * schema: + * type: string + * description: The ID of the match + * responses: + * 200: + * description: The match was found successfully + * 404: + * description: Match not found + */ +router.get("/getmatch/:id", matchControl.getMatch); + + +/** + * @swagger + * /api/updatematch: + * post: + * summary: Update a match + * tags: [Matches] + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * matchId: + * type: string + * status: + * type: string + * responses: + * 200: + * description: The match was updated successfully + * 400: + * description: Error in updating match + */ +router.post("/updatematch", matchControl.updateMatch); + +/** + * @swagger + * /api/markcompletion: + * post: + * summary: Mark a match as completed + * tags: [Matches] + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * matchId: + * type: string + * responses: + * 200: + * description: The match was marked as completed successfully + * 400: + * description: Error in marking match as completed + */ +router.post("/markcompletion", matchControl.markCompletion); + + +/** + * @swagger + * /api/updatematch: + * post: + * summary: Update a match + * tags: [Matches] + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * matchId: + * type: string + * status: + * type: string + * responses: + * 200: + * description: The match was updated successfully + * 400: + * description: Error in updating match + */ +router.post("/updatematch", matchControl.updateMatch); + + +/** + * @swagger + * /api/markcompletion: + * post: + * summary: Mark a match as completed + * tags: [Matches] + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * matchId: + * type: string + * responses: + * 200: + * description: The match was marked as completed successfully + * 400: + * description: Error in marking match as completed + */ +router.post("/markcompletion", matchControl.markCompletion); + + +/** + * @swagger + * /api/getgroup: + * get: + * summary: Get group information + * tags: [Matches] + * responses: + * 200: + * description: Group information retrieved successfully + * 500: + * description: Server error + */ +router.get("/getgroup", getGroup); + + +// concur match +/** + * @swagger + * /api/concurmatch: + * post: + * summary: Update the concur status of a match + * tags: [Matches] + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * matchId: + * type: string + * userId: + * type: string + * concurStatus: + * type: string + * responses: + * 200: + * description: The concur status of the match was updated successfully + * 400: + * description: Error in updating the concur status of the match + */ +router.post("/concurmatch", matchControl.updateConcurStatus); + +// get getDeadlockMatch +/** + * @swagger + * /api/deadlockedmatches: + * get: + * summary: Get all matches that are deadlocked + * tags: [Matches] + * responses: + * 200: + * description: The match was found successfully + * 404: + * description: Match not found + * + */ +router.get("/deadlockedmatches", matchControl.getDeadlockMatch); + + +export default router; diff --git a/src/swaggerOptions.js b/src/swaggerOptions.js index 2539c76..b5fb058 100644 --- a/src/swaggerOptions.js +++ b/src/swaggerOptions.js @@ -1,3 +1,5 @@ +const path = require('path'); + const options = { definition: { openapi: "3.0.0", @@ -12,7 +14,7 @@ const options = { }, ], }, - apis: ["./routes/*.js"], // files containing annotations as above + apis: [path.resolve(__dirname, '../src/routes/*.ts')], }; module.exports = options; diff --git a/src/types/contract.ts b/src/types/contract.ts index 6b37b74..4169574 100644 --- a/src/types/contract.ts +++ b/src/types/contract.ts @@ -27,4 +27,9 @@ export interface UrlToSync { submittedBy: string, likes: number, tagIds: string[], +} + +export interface MatchGroupType { + key: number, + users: string[], } \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 825dc81..30e02a1 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -33,7 +33,7 @@ // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ "types": [ - "node", + //"node", "jest" ] /* Specify type package names to be included without being referenced in a source file. */, // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */