📝 OpenApi docs and endpoint for the BackEnd Routes
Signed-off-by: Pau Costa <mico@micodev.es>pull/2/head
parent
c09b56b0cd
commit
e5a65086be
|
|
@ -12,19 +12,65 @@
|
|||
"body-parser": "^1.19.1",
|
||||
"express": "^4.17.2",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"ms": "^2.1.3",
|
||||
"mysql": "^2.14.1",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"swagger-jsdoc": "^6.2.8",
|
||||
"swagger-ui-express": "^5.0.0",
|
||||
"typeorm": "0.3.20"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bcrypt": "^5.0.2",
|
||||
"@types/express": "^4.17.21",
|
||||
"@types/jsonwebtoken": "^9.0.5",
|
||||
"@types/ms": "^0.7.34",
|
||||
"@types/node": "^16.11.10",
|
||||
"@types/swagger-jsdoc": "^6.0.4",
|
||||
"@types/swagger-ui-express": "^4.1.6",
|
||||
"ts-node": "10.9.1",
|
||||
"typescript": "4.5.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@apidevtools/json-schema-ref-parser": {
|
||||
"version": "9.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.1.2.tgz",
|
||||
"integrity": "sha512-r1w81DpR+KyRWd3f+rk6TNqMgedmAxZP5v5KWlXQWlgMUUtyEJch0DKEci1SorPMiSeM8XPl7MZ3miJ60JIpQg==",
|
||||
"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/@apidevtools/openapi-schemas": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz",
|
||||
"integrity": "sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@apidevtools/swagger-methods": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz",
|
||||
"integrity": "sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg=="
|
||||
},
|
||||
"node_modules/@apidevtools/swagger-parser": {
|
||||
"version": "10.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@apidevtools/swagger-parser/-/swagger-parser-10.0.3.tgz",
|
||||
"integrity": "sha512-sNiLY51vZOmSPFZA5TF35KZ2HbgYklQnTSDnkghamzLb3EkNtcQnrBQEj5AOCxHpTtXpqMCRM1CrmV2rG6nw4g==",
|
||||
"dependencies": {
|
||||
"@apidevtools/json-schema-ref-parser": "^9.0.6",
|
||||
"@apidevtools/openapi-schemas": "^2.0.4",
|
||||
"@apidevtools/swagger-methods": "^3.0.2",
|
||||
"@jsdevtools/ono": "^7.1.3",
|
||||
"call-me-maybe": "^1.0.1",
|
||||
"z-schema": "^5.0.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"openapi-types": ">=7"
|
||||
}
|
||||
},
|
||||
"node_modules/@cspotcode/source-map-support": {
|
||||
"version": "0.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
|
||||
|
|
@ -78,6 +124,11 @@
|
|||
"@jridgewell/sourcemap-codec": "^1.4.10"
|
||||
}
|
||||
},
|
||||
"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/@mapbox/node-pre-gyp": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz",
|
||||
|
|
@ -193,6 +244,11 @@
|
|||
"integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/json-schema": {
|
||||
"version": "7.0.15",
|
||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
|
||||
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="
|
||||
},
|
||||
"node_modules/@types/jsonwebtoken": {
|
||||
"version": "9.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.5.tgz",
|
||||
|
|
@ -253,6 +309,22 @@
|
|||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/swagger-jsdoc": {
|
||||
"version": "6.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/swagger-jsdoc/-/swagger-jsdoc-6.0.4.tgz",
|
||||
"integrity": "sha512-W+Xw5epcOZrF/AooUM/PccNMSAFOKWZA5dasNyMujTwsBkU74njSJBpvCCJhHAJ95XRMzQrrW844Btu0uoetwQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/swagger-ui-express": {
|
||||
"version": "4.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/swagger-ui-express/-/swagger-ui-express-4.1.6.tgz",
|
||||
"integrity": "sha512-UVSiGYXa5IzdJJG3hrc86e8KdZWLYxyEsVoUI4iPXc7CO4VZ3AfNP8d/8+hrDRIqz+HAaSMtZSqAsF3Nq2X/Dg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/express": "*",
|
||||
"@types/serve-static": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/abbrev": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
||||
|
|
@ -397,6 +469,11 @@
|
|||
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/argparse": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
|
||||
},
|
||||
"node_modules/array-flatten": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
||||
|
|
@ -527,6 +604,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/chalk": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
||||
|
|
@ -748,6 +830,14 @@
|
|||
"color-support": "bin.js"
|
||||
}
|
||||
},
|
||||
"node_modules/commander": {
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-6.2.0.tgz",
|
||||
"integrity": "sha512-zP4jEKbe8SHzKJYQmq8Y9gYjtO/POJLgIdKgV7B9qNmABVFVc+ctqSX6iXh4mCpJfRBOabiZ2YKPg8ciDw6C+Q==",
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
|
|
@ -884,6 +974,17 @@
|
|||
"node": ">=0.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/doctrine": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
|
||||
"integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
|
||||
"dependencies": {
|
||||
"esutils": "^2.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/dotenv": {
|
||||
"version": "16.4.1",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.1.tgz",
|
||||
|
|
@ -939,6 +1040,14 @@
|
|||
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
|
||||
"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
|
||||
},
|
||||
"node_modules/esutils": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
|
||||
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/etag": {
|
||||
"version": "1.8.1",
|
||||
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
|
||||
|
|
@ -1423,6 +1532,17 @@
|
|||
"@pkgjs/parseargs": "^0.11.0"
|
||||
}
|
||||
},
|
||||
"node_modules/js-yaml": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
|
||||
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
|
||||
"dependencies": {
|
||||
"argparse": "^2.0.1"
|
||||
},
|
||||
"bin": {
|
||||
"js-yaml": "bin/js-yaml.js"
|
||||
}
|
||||
},
|
||||
"node_modules/jsonwebtoken": {
|
||||
"version": "9.0.2",
|
||||
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",
|
||||
|
|
@ -1463,6 +1583,11 @@
|
|||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/lodash.get": {
|
||||
"version": "4.4.2",
|
||||
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
|
||||
"integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ=="
|
||||
},
|
||||
"node_modules/lodash.includes": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
|
||||
|
|
@ -1473,6 +1598,11 @@
|
|||
"resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
|
||||
"integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg=="
|
||||
},
|
||||
"node_modules/lodash.isequal": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
|
||||
"integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ=="
|
||||
},
|
||||
"node_modules/lodash.isinteger": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
|
||||
|
|
@ -1493,6 +1623,11 @@
|
|||
"resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
|
||||
"integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw=="
|
||||
},
|
||||
"node_modules/lodash.mergewith": {
|
||||
"version": "4.6.2",
|
||||
"resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz",
|
||||
"integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ=="
|
||||
},
|
||||
"node_modules/lodash.once": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
|
||||
|
|
@ -1770,6 +1905,12 @@
|
|||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/openapi-types": {
|
||||
"version": "12.1.3",
|
||||
"resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz",
|
||||
"integrity": "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/parse5": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz",
|
||||
|
|
@ -2264,6 +2405,94 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/swagger-jsdoc": {
|
||||
"version": "6.2.8",
|
||||
"resolved": "https://registry.npmjs.org/swagger-jsdoc/-/swagger-jsdoc-6.2.8.tgz",
|
||||
"integrity": "sha512-VPvil1+JRpmJ55CgAtn8DIcpBs0bL5L3q5bVQvF4tAW/k/9JYSj7dCpaYCAv5rufe0vcCbBRQXGvzpkWjvLklQ==",
|
||||
"dependencies": {
|
||||
"commander": "6.2.0",
|
||||
"doctrine": "3.0.0",
|
||||
"glob": "7.1.6",
|
||||
"lodash.mergewith": "^4.6.2",
|
||||
"swagger-parser": "^10.0.3",
|
||||
"yaml": "2.0.0-1"
|
||||
},
|
||||
"bin": {
|
||||
"swagger-jsdoc": "bin/swagger-jsdoc.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/swagger-jsdoc/node_modules/brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/swagger-jsdoc/node_modules/glob": {
|
||||
"version": "7.1.6",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
|
||||
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
|
||||
"dependencies": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
"inherits": "2",
|
||||
"minimatch": "^3.0.4",
|
||||
"once": "^1.3.0",
|
||||
"path-is-absolute": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/swagger-jsdoc/node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/swagger-parser": {
|
||||
"version": "10.0.3",
|
||||
"resolved": "https://registry.npmjs.org/swagger-parser/-/swagger-parser-10.0.3.tgz",
|
||||
"integrity": "sha512-nF7oMeL4KypldrQhac8RyHerJeGPD1p2xDh900GPvc+Nk7nWP6jX2FcC7WmkinMoAmoO774+AFXcWsW8gMWEIg==",
|
||||
"dependencies": {
|
||||
"@apidevtools/swagger-parser": "10.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/swagger-ui-dist": {
|
||||
"version": "5.11.2",
|
||||
"resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.11.2.tgz",
|
||||
"integrity": "sha512-jQG0cRgJNMZ7aCoiFofnoojeSaa/+KgWaDlfgs8QN+BXoGMpxeMVY5OEnjq4OlNvF3yjftO8c9GRAgcHlO+u7A=="
|
||||
},
|
||||
"node_modules/swagger-ui-express": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-5.0.0.tgz",
|
||||
"integrity": "sha512-tsU9tODVvhyfkNSvf03E6FAk+z+5cU3lXAzMy6Pv4av2Gt2xA0++fogwC4qo19XuFf6hdxevPuVCSKFuMHJhFA==",
|
||||
"dependencies": {
|
||||
"swagger-ui-dist": ">=5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= v0.10.32"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"express": ">=4.0.0 || >=5.0.0-beta"
|
||||
}
|
||||
},
|
||||
"node_modules/tar": {
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz",
|
||||
|
|
@ -2574,6 +2803,14 @@
|
|||
"integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/validator": {
|
||||
"version": "13.11.0",
|
||||
"resolved": "https://registry.npmjs.org/validator/-/validator-13.11.0.tgz",
|
||||
"integrity": "sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ==",
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/vary": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||
|
|
@ -2754,6 +2991,14 @@
|
|||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||
},
|
||||
"node_modules/yaml": {
|
||||
"version": "2.0.0-1",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.0.0-1.tgz",
|
||||
"integrity": "sha512-W7h5dEhywMKenDJh2iX/LABkbFnBxasD27oyXWDS/feDsxiw0dD5ncXdYXgkvAsXIY2MpW/ZKkr9IU30DBdMNQ==",
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs": {
|
||||
"version": "17.7.2",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
|
||||
|
|
@ -2824,6 +3069,34 @@
|
|||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/z-schema": {
|
||||
"version": "5.0.5",
|
||||
"resolved": "https://registry.npmjs.org/z-schema/-/z-schema-5.0.5.tgz",
|
||||
"integrity": "sha512-D7eujBWkLa3p2sIpJA0d1pr7es+a7m0vFAnZLlCEKq/Ij2k0MLi9Br2UPxoxdYystm5K1yeBGzub0FlYUEWj2Q==",
|
||||
"dependencies": {
|
||||
"lodash.get": "^4.4.2",
|
||||
"lodash.isequal": "^4.5.0",
|
||||
"validator": "^13.7.0"
|
||||
},
|
||||
"bin": {
|
||||
"z-schema": "bin/z-schema"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"commander": "^9.4.1"
|
||||
}
|
||||
},
|
||||
"node_modules/z-schema/node_modules/commander": {
|
||||
"version": "9.5.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz",
|
||||
"integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": "^12.20.0 || >=14"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@
|
|||
"@types/jsonwebtoken": "^9.0.5",
|
||||
"@types/ms": "^0.7.34",
|
||||
"@types/node": "^16.11.10",
|
||||
"@types/swagger-jsdoc": "^6.0.4",
|
||||
"@types/swagger-ui-express": "^4.1.6",
|
||||
"ts-node": "10.9.1",
|
||||
"typescript": "4.5.2"
|
||||
},
|
||||
|
|
@ -20,6 +22,8 @@
|
|||
"ms": "^2.1.3",
|
||||
"mysql": "^2.14.1",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"swagger-jsdoc": "^6.2.8",
|
||||
"swagger-ui-express": "^5.0.0",
|
||||
"typeorm": "0.3.20"
|
||||
},
|
||||
"scripts": {
|
||||
|
|
|
|||
|
|
@ -11,8 +11,28 @@ export class UserController {
|
|||
private userRepository = AppDataSource.getRepository(User)
|
||||
|
||||
private notificationRepository = AppDataSource.getRepository(Notification)
|
||||
public getAllUsers = catchAsync(async (req: Request, res: Response, next: NextFunction) => {
|
||||
const users = await this.userRepository.find()
|
||||
/**
|
||||
* @swagger
|
||||
* /users:
|
||||
* get:
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* tags:
|
||||
* - Users
|
||||
* summary: Get all users
|
||||
* responses:
|
||||
* 200:
|
||||
* description: A list of all users
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: array
|
||||
* items:
|
||||
* $ref: '#/components/schemas/User'
|
||||
*/
|
||||
public getAllUsers = catchAsync(
|
||||
async (req: Request, res: Response, next: NextFunction) => {
|
||||
const users = await this.userRepository.find();
|
||||
|
||||
// remove sensitive fields
|
||||
users.forEach(user => {
|
||||
|
|
@ -22,11 +42,36 @@ export class UserController {
|
|||
res.status(200).send(users)
|
||||
})
|
||||
|
||||
public getUser = catchAsync( async (req: Request, res: Response, next: NextFunction) => {
|
||||
const id = req.params.id
|
||||
const parsedId = parseInt(id)
|
||||
/**
|
||||
* @swagger
|
||||
* /users/{id}:
|
||||
* get:
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* tags:
|
||||
* - Users
|
||||
* summary: Get a single user
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* description: ID of the user
|
||||
* schema:
|
||||
* type: integer
|
||||
* responses:
|
||||
* 200:
|
||||
* description: A single user
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/UserWithRelations'
|
||||
*/
|
||||
public getUser = catchAsync(
|
||||
async (req: Request, res: Response, next: NextFunction) => {
|
||||
const id = req.params.id;
|
||||
const parsedId = parseInt(id);
|
||||
// Check if ID is a number
|
||||
if(isNaN(parsedId)) return next(new AppError('Invalid ID', 400))
|
||||
if (isNaN(parsedId)) return next(new AppError("Invalid ID", 400));
|
||||
|
||||
const user = await this.userRepository.findOne({where: {id: parsedId}, relations:{
|
||||
followed: true,
|
||||
|
|
@ -46,7 +91,25 @@ export class UserController {
|
|||
return res.send(user)
|
||||
})
|
||||
|
||||
public getMe = catchAsync(async (req: AppRequest, res: Response, next: NextFunction) => {
|
||||
/**
|
||||
* @swagger
|
||||
* /users/me:
|
||||
* get:
|
||||
* tags:
|
||||
* - Users
|
||||
* summary: Get the currently logged in user
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* responses:
|
||||
* 200:
|
||||
* description: The currently logged in user
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/UserWithRelations'
|
||||
*/
|
||||
public getMe = catchAsync(
|
||||
async (req: AppRequest, res: Response, next: NextFunction) => {
|
||||
const user = await this.userRepository.findOne({
|
||||
where: { id: req.user.id },
|
||||
relations: {
|
||||
|
|
@ -54,8 +117,8 @@ export class UserController {
|
|||
followers: true,
|
||||
posts: true,
|
||||
comments: true,
|
||||
}
|
||||
})
|
||||
},
|
||||
});
|
||||
|
||||
user.followed.forEach(followedUser => followedUser.deleteSensitiveFields())
|
||||
user.followers.forEach(follower => follower.deleteSensitiveFields())
|
||||
|
|
@ -63,11 +126,40 @@ export class UserController {
|
|||
return res.status(200).send(user)
|
||||
})
|
||||
|
||||
public followUser = catchAsync(async (req: AppRequest, res: Response, next: NextFunction) => {
|
||||
const userToFollowId = req.params.id
|
||||
const parsedId = parseInt(userToFollowId)
|
||||
/**
|
||||
* @swagger
|
||||
* /users/{id}/follow:
|
||||
* post:
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* tags:
|
||||
* - Users
|
||||
* summary: Follow a user
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* description: The ID of the user to follow
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Successfully followed the user
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/UserWithRelations'
|
||||
* 400:
|
||||
* description: Invalid ID
|
||||
* 404:
|
||||
* description: No user found with that ID
|
||||
*/
|
||||
public followUser = catchAsync(
|
||||
async (req: AppRequest, res: Response, next: NextFunction) => {
|
||||
const userToFollowId = req.params.id;
|
||||
const parsedId = parseInt(userToFollowId);
|
||||
// Check if ID is a number
|
||||
if(isNaN(parsedId)) return next(new AppError('Invalid ID', 400))
|
||||
if (isNaN(parsedId)) return next(new AppError("Invalid ID", 400));
|
||||
|
||||
const user = req.user
|
||||
const userToFollow = await this.userRepository.findOne({
|
||||
|
|
@ -104,11 +196,40 @@ export class UserController {
|
|||
})
|
||||
})
|
||||
|
||||
public unfollowUser = catchAsync(async (req: AppRequest, res: Response, next: NextFunction) => {
|
||||
const userToUnfollowId = req.params.id
|
||||
const parsedId = parseInt(userToUnfollowId)
|
||||
/**
|
||||
* @swagger
|
||||
* /users/{id}/follow:
|
||||
* delete:
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* tags:
|
||||
* - Users
|
||||
* summary: Unfollow a user
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* description: The ID of the user to unfollow
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Successfully unfollowed the user
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/UserWithRelations'
|
||||
* 400:
|
||||
* description: Invalid ID
|
||||
* 404:
|
||||
* description: No user found with that ID
|
||||
*/
|
||||
public unfollowUser = catchAsync(
|
||||
async (req: AppRequest, res: Response, next: NextFunction) => {
|
||||
const userToUnfollowId = req.params.id;
|
||||
const parsedId = parseInt(userToUnfollowId);
|
||||
// Check if ID is a number
|
||||
if(isNaN(parsedId)) return next(new AppError('Invalid ID', 400))
|
||||
if (isNaN(parsedId)) return next(new AppError("Invalid ID", 400));
|
||||
|
||||
const user = req.user
|
||||
const userToUnfollow = await this.userRepository.findOne({
|
||||
|
|
|
|||
|
|
@ -38,6 +38,45 @@ export class AuthController {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /auth/signup:
|
||||
* post:
|
||||
* tags:
|
||||
* - Authentication
|
||||
* summary: Sign up a new user
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* email:
|
||||
* type: string
|
||||
* description: The email of the user
|
||||
* password:
|
||||
* type: string
|
||||
* description: The password of the user
|
||||
* passwordValidation:
|
||||
* type: string
|
||||
* description: Password validation field
|
||||
* firstName:
|
||||
* type: string
|
||||
* description: The first name of the user
|
||||
* lastName:
|
||||
* type: string
|
||||
* description: The last name of the user
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Successfully signed up the user
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/User'
|
||||
* 400:
|
||||
* description: Invalid input or user already exists
|
||||
*/
|
||||
public handleSignUp = catchAsync(async (req, res, next) => {
|
||||
const {email, password, passwordValidation, firstName, lastName} = req.body
|
||||
// Body Validation
|
||||
|
|
@ -64,10 +103,52 @@ export class AuthController {
|
|||
this.sendToken(await this.userRepository.save(newUser), res)
|
||||
})
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /auth/login:
|
||||
* post:
|
||||
* tags:
|
||||
* - Authentication
|
||||
* summary: Log in a user
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* email:
|
||||
* type: string
|
||||
* description: The email of the user
|
||||
* password:
|
||||
* type: string
|
||||
* description: The password of the user
|
||||
* longExpiration:
|
||||
* type: boolean
|
||||
* description: Whether to keep the user logged in for a long time
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Successfully logged in the user
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* status:
|
||||
* type: string
|
||||
* example: "success"
|
||||
* token:
|
||||
* type: string
|
||||
* description: The JWT token for the user
|
||||
* 400:
|
||||
* description: Missing email or password
|
||||
* 401:
|
||||
* description: Incorrect email or password
|
||||
*/
|
||||
public handleLogin = catchAsync(async (req, res, next) => {
|
||||
const {email, password, longExpiration} = req.body
|
||||
const { email, password, longExpiration } = req.body;
|
||||
if (!email || !password) {
|
||||
return next(new AppError('Please provide email and password', 400))
|
||||
return next(new AppError("Please provide email and password", 400));
|
||||
}
|
||||
|
||||
const user = await this.userRepository.findOne({where: {email}})
|
||||
|
|
@ -79,14 +160,35 @@ export class AuthController {
|
|||
this.sendToken(user, res, {long: longExpiration})
|
||||
})
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /auth/logout:
|
||||
* get:
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* tags:
|
||||
* - Authentication
|
||||
* summary: Log out the user
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Successfully logged out the user
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* status:
|
||||
* type: string
|
||||
* example: "success"
|
||||
*/
|
||||
public handleLogout = catchAsync(async (req: AppRequest, res, next) => {
|
||||
// Set the jwt cookie to a dummy value and set the expiration to a date in the past
|
||||
res.cookie('jwt', 'loggedout', {
|
||||
res.cookie("jwt", "loggedout", {
|
||||
expires: new Date(Date.now() - 10000),
|
||||
httpOnly: true
|
||||
})
|
||||
res.status(200).json({status: 'success'})
|
||||
})
|
||||
httpOnly: true,
|
||||
});
|
||||
res.status(200).json({ status: "success" });
|
||||
});
|
||||
|
||||
public protect = catchAsync(async (req: AppRequest, res, next) => {
|
||||
let token: string | undefined;
|
||||
|
|
|
|||
|
|
@ -16,20 +16,72 @@ export class PostController {
|
|||
|
||||
private userRepository = AppDataSource.getRepository(User)
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /posts:
|
||||
* get:
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* tags:
|
||||
* - Posts
|
||||
* operationId: getAllPosts
|
||||
* summary: Get all posts
|
||||
* responses:
|
||||
* 200:
|
||||
* description: A list of all posts
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: array
|
||||
* items:
|
||||
* $ref: '#/components/schemas/Post'
|
||||
*/
|
||||
public getAllPosts = catchAsync(async (_req, res, _next) => {
|
||||
const posts = await this.postRepository.find({relations: {createdBy: true}})
|
||||
const posts = await this.postRepository.find({
|
||||
relations: { createdBy: true },
|
||||
});
|
||||
|
||||
// Remove sensitive fields
|
||||
posts.forEach(post => {
|
||||
post.deleteSensitiveFields()
|
||||
})
|
||||
|
||||
res.status(200).send(posts)
|
||||
})
|
||||
res.status(200).send(posts);
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /posts/{id}:
|
||||
* get:
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* tags:
|
||||
* - Posts
|
||||
* operationId: getPost
|
||||
* summary: Get a post by ID
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* description: ID of the post
|
||||
* schema:
|
||||
* type: integer
|
||||
* responses:
|
||||
* 200:
|
||||
* description: A post
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/Post'
|
||||
* 400:
|
||||
* description: Invalid ID
|
||||
* 404:
|
||||
* description: No post found with that ID
|
||||
*/
|
||||
public getPost = catchAsync(async (req, res, next) => {
|
||||
const { post, errorMessage} =
|
||||
await this.validateRequestAndGetEntities(req)
|
||||
const { post, errorMessage } = await this.validateRequestAndGetEntities(
|
||||
req
|
||||
);
|
||||
|
||||
if(errorMessage == 'Invalid ID') return next(new AppError('Invalid ID', 400))
|
||||
if(errorMessage == 'No post found with that ID'){
|
||||
|
|
@ -39,8 +91,29 @@ export class PostController {
|
|||
// Remove sensitive fields
|
||||
post.deleteSensitiveFields()
|
||||
|
||||
res.send(post)
|
||||
})
|
||||
res.send(post);
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /posts/followed:
|
||||
* get:
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* tags:
|
||||
* - Posts
|
||||
* operationId: getFollowedPosts
|
||||
* summary: Get posts of followed users
|
||||
* responses:
|
||||
* 200:
|
||||
* description: A list of posts
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: array
|
||||
* items:
|
||||
* $ref: '#/components/schemas/Post'
|
||||
*/
|
||||
|
||||
public getFollowedPosts = catchAsync(async (req : AppRequest, res, _next) => {
|
||||
const user = await this.userRepository.findOne({
|
||||
|
|
@ -54,8 +127,42 @@ export class PostController {
|
|||
post.deleteSensitiveFields()
|
||||
})
|
||||
|
||||
res.send(followedPosts)
|
||||
})
|
||||
res.send(followedPosts);
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /posts:
|
||||
* post:
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* tags:
|
||||
* - Posts
|
||||
* operationId: createPost
|
||||
* summary: Create a post
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* title:
|
||||
* type: string
|
||||
* description: Post title
|
||||
* content:
|
||||
* type: string
|
||||
* description: Post content
|
||||
* responses:
|
||||
* 201:
|
||||
* description: A post
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/Post'
|
||||
* 400:
|
||||
* description: Title and content are required
|
||||
*/
|
||||
|
||||
public createPost = catchAsync(async (req : AppRequest, res, next) => {
|
||||
const user = await this.userRepository.findOne({where: {id: req.user.id}})
|
||||
|
|
@ -75,8 +182,51 @@ export class PostController {
|
|||
// Remove sensitive fields
|
||||
post.deleteSensitiveFields()
|
||||
|
||||
res.status(201).send(post)
|
||||
})
|
||||
res.status(201).send(post);
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /posts/{id}:
|
||||
* patch:
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* tags:
|
||||
* - Posts
|
||||
* operationId: updatePost
|
||||
* summary: Update a post by ID
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* description: ID of the post
|
||||
* schema:
|
||||
* type: integer
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* title:
|
||||
* type: string
|
||||
* description: Post title
|
||||
* content:
|
||||
* type: string
|
||||
* description: Post content
|
||||
* responses:
|
||||
* 200:
|
||||
* description: A post
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/Post'
|
||||
* 400:
|
||||
* description: Invalid ID or Title and content are required
|
||||
* 404:
|
||||
* description: No post found with that ID
|
||||
*/
|
||||
|
||||
public updatePost = catchAsync(async (req : AppRequest, res, next) => {
|
||||
const {user, post, errorMessage} = await this.validateRequestAndGetEntities(req)
|
||||
|
|
@ -100,8 +250,34 @@ export class PostController {
|
|||
// Remove sensitive fields
|
||||
post.deleteSensitiveFields()
|
||||
|
||||
res.status(200).send(post)
|
||||
})
|
||||
res.status(200).send(post);
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /posts/{id}:
|
||||
* delete:
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* tags:
|
||||
* - Posts
|
||||
* operationId: deletePost
|
||||
* summary: Delete a post by ID
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* description: ID of the post
|
||||
* schema:
|
||||
* type: integer
|
||||
* responses:
|
||||
* 204:
|
||||
* description: No content
|
||||
* 400:
|
||||
* description: Invalid ID
|
||||
* 404:
|
||||
* description: No post found with that ID
|
||||
*/
|
||||
|
||||
public deletePost = catchAsync(async (req : AppRequest, res, next) => {
|
||||
const {user, post, errorMessage} = await this.validateRequestAndGetEntities(req)
|
||||
|
|
@ -113,9 +289,39 @@ export class PostController {
|
|||
return next(new AppError('You are not authorized to delete this post', 403))
|
||||
}
|
||||
|
||||
await this.postRepository.remove(post)
|
||||
res.status(204).send()
|
||||
})
|
||||
await this.postRepository.remove(post);
|
||||
res.status(204).send();
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /posts/{id}/like:
|
||||
* post:
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* tags:
|
||||
* - Posts
|
||||
* operationId: likePost
|
||||
* summary: Like a post by ID
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* description: ID of the post
|
||||
* schema:
|
||||
* type: integer
|
||||
* responses:
|
||||
* 200:
|
||||
* description: A post
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/Post'
|
||||
* 400:
|
||||
* description: Invalid ID or You have already liked this post
|
||||
* 404:
|
||||
* description: No post found with that ID
|
||||
*/
|
||||
|
||||
public likePost = catchAsync(async (req : AppRequest, res, next) => {
|
||||
const {user, post, errorMessage} = await this.validateRequestAndGetEntities(req)
|
||||
|
|
@ -146,8 +352,38 @@ export class PostController {
|
|||
// Remove sensitive fields
|
||||
post.deleteSensitiveFields()
|
||||
|
||||
res.status(200).send(post)
|
||||
})
|
||||
res.status(200).send(post);
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /posts/{id}/like:
|
||||
* delete:
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* tags:
|
||||
* - Posts
|
||||
* operationId: unlikePost
|
||||
* summary: Unlike a post by ID
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* description: ID of the post
|
||||
* schema:
|
||||
* type: integer
|
||||
* responses:
|
||||
* 200:
|
||||
* description: A post
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/Post'
|
||||
* 400:
|
||||
* description: Invalid ID or You have not liked this post
|
||||
* 404:
|
||||
* description: No post found with that ID
|
||||
*/
|
||||
|
||||
public unlikePost = catchAsync(async (req : AppRequest, res, next) => {
|
||||
const {user, post, errorMessage} = await this.validateRequestAndGetEntities(req)
|
||||
|
|
@ -166,8 +402,48 @@ export class PostController {
|
|||
// Remove sensitive fields
|
||||
post.deleteSensitiveFields()
|
||||
|
||||
res.status(200).send(post)
|
||||
})
|
||||
res.status(200).send(post);
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /posts/{id}/comment:
|
||||
* post:
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* tags:
|
||||
* - Posts
|
||||
* operationId: commentPost
|
||||
* summary: Comment on a post by ID
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* description: ID of the post
|
||||
* schema:
|
||||
* type: integer
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* content:
|
||||
* type: string
|
||||
* description: Comment content
|
||||
* responses:
|
||||
* 201:
|
||||
* description: A comment
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/Comment'
|
||||
* 400:
|
||||
* description: Invalid Request
|
||||
* 404:
|
||||
* description: No post found with that ID
|
||||
*/
|
||||
|
||||
public commentPost = catchAsync(async (req : AppRequest, res, next) => {
|
||||
const {user, post, errorMessage} = await this.validateRequestAndGetEntities(req)
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import {AuthRoutes} from "./routes/authRoutes";
|
|||
import {UserRoutes} from "./routes/userRoutes";
|
||||
import {AuthController} from "./controller/authController";
|
||||
import {PostRoutes} from "./routes/postRoutes";
|
||||
import {swaggerRouter} from "./routes/swaggerRoutes";
|
||||
|
||||
AppDataSource.initialize().then(async () => {
|
||||
|
||||
|
|
@ -16,6 +17,10 @@ AppDataSource.initialize().then(async () => {
|
|||
// register express routes from defined application routes
|
||||
// Auth Routes
|
||||
app.use('/auth', AuthRoutes)
|
||||
|
||||
// Swagger Routes
|
||||
app.use('/docs', swaggerRouter);
|
||||
|
||||
// All routes after this one require authentication
|
||||
const authController = new AuthController();
|
||||
app.use(authController.protect)
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ PostRoutes.route("/:id")
|
|||
.get(postController.getPost)
|
||||
.patch(postController.updatePost)
|
||||
.delete(postController.deletePost)
|
||||
PostRoutes.route("/:id/like").post(postController.likePost)
|
||||
PostRoutes.route("/:id/unlike").post(postController.unlikePost)
|
||||
PostRoutes.route("/:id/like")
|
||||
.post(postController.likePost)
|
||||
.delete(postController.unlikePost)
|
||||
PostRoutes.route("/:id/comment").post(postController.commentPost)
|
||||
|
|
@ -0,0 +1,158 @@
|
|||
import * as swaggerJSdoc from "swagger-jsdoc";
|
||||
import {Router} from "express";
|
||||
import * as swaggerUi from "swagger-ui-express";
|
||||
import { catchAsync } from "../util/catchAsync";
|
||||
|
||||
const swaggerOptions = {
|
||||
swaggerDefinition: {
|
||||
openapi: "3.0.0",
|
||||
info: {
|
||||
title: "DevSpace API",
|
||||
description: "API for DevSpace",
|
||||
version: "0.1.0",
|
||||
},
|
||||
|
||||
components: {
|
||||
securitySchemes: {
|
||||
bearerAuth: {
|
||||
type: "http",
|
||||
scheme: "bearer",
|
||||
bearerFormat: "JWT",
|
||||
},
|
||||
},
|
||||
schemas: {
|
||||
Post: {
|
||||
type: "object",
|
||||
properties: {
|
||||
id: {
|
||||
type: "integer",
|
||||
description: "Post ID",
|
||||
},
|
||||
title: {
|
||||
type: "string",
|
||||
description: "Post title",
|
||||
},
|
||||
content: {
|
||||
type: "string",
|
||||
description: "Post content",
|
||||
},
|
||||
createdAt: {
|
||||
type: "string",
|
||||
description: "Post creation date",
|
||||
},
|
||||
createdBy: {
|
||||
$ref: "#/components/schemas/User",
|
||||
},
|
||||
likedBy: {
|
||||
type: "array",
|
||||
items: {
|
||||
$ref: "#/components/schemas/User",
|
||||
},
|
||||
},
|
||||
comments: {
|
||||
type: "array",
|
||||
items: {
|
||||
$ref: "#/components/schemas/Comment",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Comment: {
|
||||
type: "object",
|
||||
properties: {
|
||||
id: {
|
||||
type: "integer",
|
||||
description: "Comment ID",
|
||||
},
|
||||
content: {
|
||||
type: "string",
|
||||
description: "Comment content",
|
||||
},
|
||||
createdAt: {
|
||||
type: "string",
|
||||
description: "Comment creation date",
|
||||
},
|
||||
createdBy: {
|
||||
$ref: "#/components/schemas/User",
|
||||
},
|
||||
likedBy: {
|
||||
type: "array",
|
||||
items: {
|
||||
$ref: "#/components/schemas/User",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
User: {
|
||||
type: "object",
|
||||
properties: {
|
||||
id: {
|
||||
type: "integer",
|
||||
description: "User ID",
|
||||
},
|
||||
firstName: {
|
||||
type: "string",
|
||||
description: "User first name",
|
||||
},
|
||||
lastName: {
|
||||
type: "string",
|
||||
description: "User last name",
|
||||
},
|
||||
},
|
||||
},
|
||||
UserWithRelations: {
|
||||
allOf: [
|
||||
{
|
||||
$ref: "#/components/schemas/User",
|
||||
},
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
posts: {
|
||||
type: "array",
|
||||
items: {
|
||||
$ref: "#/components/schemas/Post",
|
||||
},
|
||||
},
|
||||
comments: {
|
||||
type: "array",
|
||||
items: {
|
||||
$ref: "#/components/schemas/Comment", // Assuming you have a Comment schema
|
||||
},
|
||||
},
|
||||
followed: {
|
||||
type: "array",
|
||||
items: {
|
||||
$ref: "#/components/schemas/User",
|
||||
},
|
||||
},
|
||||
followers: {
|
||||
type: "array",
|
||||
items: {
|
||||
$ref: "#/components/schemas/User",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
apis: ["**/controller/*.ts"],
|
||||
};
|
||||
|
||||
const swaggerDocs = swaggerJSdoc(swaggerOptions);
|
||||
|
||||
|
||||
console.log(swaggerDocs)
|
||||
export const swaggerRouter = Router()
|
||||
|
||||
|
||||
swaggerRouter.get(
|
||||
"/json", catchAsync(async (req, res, next) => {
|
||||
res.json(swaggerDocs);
|
||||
})
|
||||
);
|
||||
swaggerRouter.use("/", swaggerUi.serve, swaggerUi.setup(swaggerDocs));
|
||||
|
|
@ -8,5 +8,6 @@ const userController = new UserController()
|
|||
UserRoutes.route("/").get(userController.getAllUsers)
|
||||
UserRoutes.route("/me").get(userController.getMe)
|
||||
UserRoutes.route("/:id").get(userController.getUser)
|
||||
UserRoutes.route("/follow/:id").post(userController.followUser)
|
||||
UserRoutes.route("/unfollow/:id").post(userController.unfollowUser)
|
||||
UserRoutes.route("/follow/:id")
|
||||
.post(userController.followUser)
|
||||
.delete(userController.unfollowUser)
|
||||
Loading…
Reference in New Issue