diff --git a/README.md b/README.md index 4f956f6..0028164 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ docker compose --profile dev up --build ## Meet our Team We are students of Software Architecture in the University of Oviedo. This web application is the laboratory project of the subject. We hope you like our webapp and we are welcomed to proposals of new content by our Issues. -You can check our Documentation [here](https://arquisoft.github.io/wiq_en1a/) where all the tecnical details are explained +You can check our Documentation [here](https://arquisoft.github.io/wiq_en1a/) where all the tecnical details are explained. Moreover, you can check our API for your free use, using Swagger, [here](http://158.179.217.182:8000/api-doc). ### Developers diff --git a/gatewayservice/gateway-service.js b/gatewayservice/gateway-service.js index 0a1dfe5..822dc57 100644 --- a/gatewayservice/gateway-service.js +++ b/gatewayservice/gateway-service.js @@ -3,6 +3,11 @@ const axios = require('axios'); const cors = require('cors'); const promBundle = require('express-prom-bundle'); +//libraries required for OpenAPI-Swagger +const swaggerUi = require('swagger-ui-express'); +const fs = require("fs") +const YAML = require('yaml') + const app = express(); const port = 8000; @@ -75,21 +80,6 @@ app.post('/imgs/answer', async (req, res) => { }); -app.get('/self', async (req, res) => { - try { - // Forward the self request to the user service - - const userResponse = await axios.get(authServiceUrl+'/self', { - headers: { - Authorization: req.headers.authorization, - }, - }); - - res.status(200).json(userResponse.data); - } catch (error) { -res.status(error.response.status).json({ error: error.response.data.error }); - } -}); app.get('/rankings', async (req, res) => { try { // Forward the request to the user service @@ -100,9 +90,26 @@ app.get('/rankings', async (req, res) => { } }); +// Read the OpenAPI YAML file synchronously +openapiPath='./openapi.yaml' +if (fs.existsSync(openapiPath)) { + const file = fs.readFileSync(openapiPath, 'utf8'); + + // Parse the YAML content into a JavaScript object representing the Swagger document + const swaggerDocument = YAML.parse(file); + + // Serve the Swagger UI documentation at the '/api-doc' endpoint + // This middleware serves the Swagger UI files and sets up the Swagger UI page + // It takes the parsed Swagger document as input + app.use('/api-doc', swaggerUi.serve, swaggerUi.setup(swaggerDocument)); +} else { + console.log("Not configuring OpenAPI. Configuration file not present.") +} + // Start the gateway service const server = app.listen(port, () => { console.log(`Gateway Service listening at http://localhost:${port}`); }); + module.exports = server diff --git a/gatewayservice/openapi.yaml b/gatewayservice/openapi.yaml new file mode 100644 index 0000000..9c8b335 --- /dev/null +++ b/gatewayservice/openapi.yaml @@ -0,0 +1,360 @@ +openapi: 3.1.0 +info: + title: Gatewayservice API + description: Gateway OpenAPI specification. + version: 0.2.0 +servers: + - url: http://localhost:8000 + description: Local Server + - url: http://158.179.217.182:8000 + description: WIQ Server +paths: + /adduser: + post: + summary: Register in WIQ. + operationId: addUser + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + username: + type: string + description: User ID. + example: student + email: + type: string + description: User email. + example: UOXXXXXX@uniovi.es + password: + type: string + description: User password. + example: securepass + responses: + '200': + description: User added successfully. + content: + application/json: + schema: + type: object + properties: + username: + type: string + description: User ID + emial: + type: string + description: User ID + password: + type: string + description: Hashed password + example: $2b$10$ZKdNYLWFQxzt5Rei/YTc/OsZNi12YiWz30JeUFHNdAt7MyfmkTuvC + _id: + type: string + description: Identification + example: 65f756db3fa22d227a4b7c7d + createdAt: + type: string + description: Creation date. + example: '2024-03-17T20:47:23.935Z' + points: + type: integer + example: '0' + ___v: + type: integer + example: '0' + '400': + description: Failed to add user. + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Error information. + example: getaddrinfo EAI_AGAIN mongodb + /health: + get: + summary: Check the health status of the service. + operationId: checkHealth + responses: + '200': + description: Service is healthy. + content: + application/json: + schema: + type: object + properties: + status: + type: string + description: Health status. + example: OK + /login: + post: + summary: Log in to the system. + operationId: loginUser + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + username: + type: string + description: User ID. + example: student + password: + type: string + description: User password. + example: pass + responses: + '200': + description: Login successful. Returns user token, username, and creation date. + content: + application/json: + schema: + type: object + properties: + token: + type: string + description: User token. + example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiI2NWY3NTZkYjNmYTIyZDIyN2E0YjdjN2QiLCJpYXQiOjE3MTA3MDg3NDUsImV4cCI6MTcxMDcxMjM0NX0.VMG_5DOyQ4GYlJQRcu1I6ICG1IGzuo2Xuei093ONHxw + username: + type: string + description: Username. + example: student + email: + type: string + description: Email. + example: UOXXXXXX@uniovi.es + createdAt: + type: string + description: Creation date. + example: '2024-03-17T20:47:23.935Z' + '401': + description: Invalid credentials. + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Shows the error info.. + example: Invalid credentials + '500': + description: Internal server error. + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Error information. + example: Internal Server Error + /imgs/flags/question: + get: + summary: Get the flags for a question. + operationId: getFlags + responses: + '200': + description: Flags retrieved successfully. + content: + application/json: + schema: + type: object + properties: + question: + type: string + description: Question. + example: "Which of these flags belongs to Kenya?" + flags: + type: array + items: + type: string + example: + - "http://commons.wikimedia.org/wiki/Special:FilePath/Flag%20of%20Kenya.svg" + - "http://commons.wikimedia.org/wiki/Special:FilePath/Flag%20of%20Grenada.svg" + - "http://commons.wikimedia.org/wiki/Special:FilePath/Flag%20of%20Wales.svg" + - "http://commons.wikimedia.org/wiki/Special:FilePath/Flag%20of%20Palau.svg" + '500': + description: Internal server error. + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Error information. + example: Internal Server Error + # '400': + # description: Failed to retrieve flags. + # content: + # application/json: + # schema: + # type: object + # properties: + # error: + # type: string + # description: Error information. + # example: Failed to retrieve flags + /imgs/cities/question: + get: + summary: Get the cities for a question. + operationId: getCities + responses: + '200': + description: cities retrieved successfully. + content: + application/json: + schema: + type: object + properties: + question: + type: string + description: Question. + example: "Which of the following images corresponds to Łódź?" + cities: + type: array + items: + type: string + example: + - "http://commons.wikimedia.org/wiki/Special:FilePath/00%20sea%20towers%20%28April%202018%29.jpg" + - "http://commons.wikimedia.org/wiki/Special:FilePath/Sebastian%20Glapinski%202017%20%28Unsplash%29.jpg" + - "http://commons.wikimedia.org/wiki/Special:FilePath/2019%20-%20Schweriner%20Schloss%20-%201.jpg" + - "http://commons.wikimedia.org/wiki/Special:FilePath/Stockholm%20gamlastan%20etc.jpg" + '500': + description: Internal server error. + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Error information. + example: Internal Server Error + # '400': + # description: Failed to retrieve cities. + # content: + # application/json: + # schema: + # type: object + # properties: + # error: + # type: string + # description: Error information. + # example: Failed to retrieve cities + + /imgs/answer: + post: + summary: Check the answer to a question. + operationId: checkAnswer + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + answer: + type: string + description: Answer. + example: "http://commons.wikimedia.org/wiki/Special:FilePath/Flag%20of%20Kenya.svg" + responses: + '200': + description: Answer is correct. + content: + application/json: + schema: + type: object + properties: + correct: + type: string + description: Result. + example: "true" + '400': + description: Answer is incorrect. + content: + application/json: + schema: + type: object + properties: + correct: + type: string + description: Result. + example: "false" + country: + type: string + description: Correct answer. + example: "http://commons.wikimedia.org/wiki/Special:FilePath/Flag%20of%20Kenya.svg" + '500': + description: Internal server error. + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Error information. + example: Internal Server Error + /rankings: + get: + summary: Get the rankings. + operationId: getRankings + responses: + '200': + description: Rankings retrieved successfully. + content: + application/json: + schema: + type: object + properties: + + ranking: + type: integer + description: User ranking position + points: + type: integer + description: User points + user: + type: string + description: User ID + example: + - ranking: 1 + points: 100 + user: student + - ranking: 2 + points: 90 + user: student2 + - ranking: 3 + points: 80 + user: student3 + '500': + description: Internal server error. + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Error information. + example: Internal Server Error + '400': + description: Failed to retrieve rankings. + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Error information. + example: Failed to retrieve rankings \ No newline at end of file diff --git a/gatewayservice/package-lock.json b/gatewayservice/package-lock.json index 5ef04ef..8f9d68e 100644 --- a/gatewayservice/package-lock.json +++ b/gatewayservice/package-lock.json @@ -13,7 +13,10 @@ "cookie-parser": "^1.4.6", "cors": "^2.8.5", "express": "^4.18.2", - "express-prom-bundle": "^7.0.0" + "express-openapi": "^12.1.3", + "express-prom-bundle": "^7.0.0", + "swagger-ui-express": "^5.0.0", + "yaml": "^2.4.1" }, "devDependencies": { "jest": "^29.7.0", @@ -1278,6 +1281,37 @@ "node": ">= 0.6" } }, + "node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "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/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, "node_modules/ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -1334,7 +1368,6 @@ "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, "dependencies": { "sprintf-js": "~1.0.2" } @@ -1475,8 +1508,7 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "node_modules/bintrees": { "version": "1.0.2", @@ -1511,7 +1543,6 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1752,8 +1783,7 @@ "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, "node_modules/content-disposition": { "version": "0.5.4", @@ -1963,6 +1993,14 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/difunc": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/difunc/-/difunc-0.0.4.tgz", + "integrity": "sha512-zBiL4ALDmviHdoLC0g0G6wVme5bwAow9WfhcZLLopXCAWgg3AEf7RYTs2xugszIGulRHzEVDF/SHl9oyQU07Pw==", + "dependencies": { + "esprima": "^4.0.0" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -2036,7 +2074,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, "bin": { "esparse": "bin/esparse.js", "esvalidate": "bin/esvalidate.js" @@ -2142,6 +2179,21 @@ "node": ">= 0.10.0" } }, + "node_modules/express-normalize-query-params-middleware": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/express-normalize-query-params-middleware/-/express-normalize-query-params-middleware-0.5.1.tgz", + "integrity": "sha512-KUBjEukYL9KJkrphVX3ZgMHgMTdgaSJe+FIOeWwJIJpCw8UZQPIylt0MYddSyUwbms4LQ8RC4wmavcLUP9uduA==" + }, + "node_modules/express-openapi": { + "version": "12.1.3", + "resolved": "https://registry.npmjs.org/express-openapi/-/express-openapi-12.1.3.tgz", + "integrity": "sha512-F570dVC5ENSkLu1SpDFPRQ13Y3a/7Udh0rfHyn3O1QrE81fPmlhnAo1JRgoNtbMRJ6goHNymxU1TVSllgFZBlQ==", + "dependencies": { + "express-normalize-query-params-middleware": "^0.5.0", + "openapi-framework": "^12.1.3", + "openapi-types": "^12.1.3" + } + }, "node_modules/express-prom-bundle": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/express-prom-bundle/-/express-prom-bundle-7.0.0.tgz", @@ -2159,6 +2211,11 @@ "prom-client": ">=15.0.0" } }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -2285,11 +2342,18 @@ "node": ">= 0.6" } }, + "node_modules/fs-routes": { + "version": "12.1.3", + "resolved": "https://registry.npmjs.org/fs-routes/-/fs-routes-12.1.3.tgz", + "integrity": "sha512-Vwxi5StpKj/pgH7yRpNpVFdaZr16z71KNTiYuZEYVET+MfZ31Zkf7oxUmNgyZxptG8BolRtdMP90agIhdyiozg==", + "peerDependencies": { + "glob": ">=7.1.6" + } + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, "node_modules/fsevents": { "version": "2.3.3", @@ -2370,7 +2434,6 @@ "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -2547,7 +2610,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -2584,6 +2646,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-dir/-/is-dir-1.0.0.tgz", + "integrity": "sha512-vLwCNpTNkFC5k7SBRxPubhOCryeulkOsSkjbGyZ8eOzZmzMS+hSEO/Kn9ZOVhFNAlRZTFc4ZKql48hESuYUPIQ==" + }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -3349,7 +3416,6 @@ "version": "3.14.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -3376,6 +3442,11 @@ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "dev": true }, + "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/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -3424,6 +3495,11 @@ "node": ">=8" } }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" + }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -3573,7 +3649,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -3664,7 +3739,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, "dependencies": { "wrappy": "1" } @@ -3684,6 +3758,97 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/openapi-default-setter": { + "version": "12.1.3", + "resolved": "https://registry.npmjs.org/openapi-default-setter/-/openapi-default-setter-12.1.3.tgz", + "integrity": "sha512-wHKwvEuOWwke5WcQn8pyCTXT5WQ+rm9FpJmDeEVECEBWjEyB/MVLYfXi+UQeSHTTu2Tg4VDHHmzbjOqN6hYeLQ==", + "dependencies": { + "openapi-types": "^12.1.3" + } + }, + "node_modules/openapi-framework": { + "version": "12.1.3", + "resolved": "https://registry.npmjs.org/openapi-framework/-/openapi-framework-12.1.3.tgz", + "integrity": "sha512-p30PHWVXda9gGxm+t/1X2XvEcufW1YhzeDQwc5SsgDnBXt8gkuu1SwrioGJ66wxVYEzfSRTTf/FMLhI49ut8fQ==", + "dependencies": { + "difunc": "0.0.4", + "fs-routes": "^12.1.3", + "glob": "*", + "is-dir": "^1.0.0", + "js-yaml": "^3.10.0", + "openapi-default-setter": "^12.1.3", + "openapi-request-coercer": "^12.1.3", + "openapi-request-validator": "^12.1.3", + "openapi-response-validator": "^12.1.3", + "openapi-schema-validator": "^12.1.3", + "openapi-security-handler": "^12.1.3", + "openapi-types": "^12.1.3", + "ts-log": "^2.1.4" + } + }, + "node_modules/openapi-jsonschema-parameters": { + "version": "12.1.3", + "resolved": "https://registry.npmjs.org/openapi-jsonschema-parameters/-/openapi-jsonschema-parameters-12.1.3.tgz", + "integrity": "sha512-aHypKxWHwu2lVqfCIOCZeJA/2NTDiP63aPwuoIC+5ksLK5/IQZ3oKTz7GiaIegz5zFvpMDxDvLR2DMQQSkOAug==", + "dependencies": { + "openapi-types": "^12.1.3" + } + }, + "node_modules/openapi-request-coercer": { + "version": "12.1.3", + "resolved": "https://registry.npmjs.org/openapi-request-coercer/-/openapi-request-coercer-12.1.3.tgz", + "integrity": "sha512-CT2ZDhBmAZpHhAzHhEN+/J5oMK3Ds99ayLLdXh2Aw1DCcn72EM8VuIGVwG5fSjvkMsgtn7FgltFosHqeM6PRFQ==", + "dependencies": { + "openapi-types": "^12.1.3", + "ts-log": "^2.1.4" + } + }, + "node_modules/openapi-request-validator": { + "version": "12.1.3", + "resolved": "https://registry.npmjs.org/openapi-request-validator/-/openapi-request-validator-12.1.3.tgz", + "integrity": "sha512-HW1sG00A9Hp2oS5g8CBvtaKvRAc4h5E4ksmuC5EJgmQ+eAUacL7g+WaYCrC7IfoQaZrjxDfeivNZUye/4D8pwA==", + "dependencies": { + "ajv": "^8.3.0", + "ajv-formats": "^2.1.0", + "content-type": "^1.0.4", + "openapi-jsonschema-parameters": "^12.1.3", + "openapi-types": "^12.1.3", + "ts-log": "^2.1.4" + } + }, + "node_modules/openapi-response-validator": { + "version": "12.1.3", + "resolved": "https://registry.npmjs.org/openapi-response-validator/-/openapi-response-validator-12.1.3.tgz", + "integrity": "sha512-beZNb6r1SXAg1835S30h9XwjE596BYzXQFAEZlYAoO2imfxAu5S7TvNFws5k/MMKMCOFTzBXSjapqEvAzlblrQ==", + "dependencies": { + "ajv": "^8.4.0", + "openapi-types": "^12.1.3" + } + }, + "node_modules/openapi-schema-validator": { + "version": "12.1.3", + "resolved": "https://registry.npmjs.org/openapi-schema-validator/-/openapi-schema-validator-12.1.3.tgz", + "integrity": "sha512-xTHOmxU/VQGUgo7Cm0jhwbklOKobXby+/237EG967+3TQEYJztMgX9Q5UE2taZKwyKPUq0j11dngpGjUuxz1hQ==", + "dependencies": { + "ajv": "^8.1.0", + "ajv-formats": "^2.0.2", + "lodash.merge": "^4.6.1", + "openapi-types": "^12.1.3" + } + }, + "node_modules/openapi-security-handler": { + "version": "12.1.3", + "resolved": "https://registry.npmjs.org/openapi-security-handler/-/openapi-security-handler-12.1.3.tgz", + "integrity": "sha512-25UTAflxqqpjCLrN6rRhINeM1L+MCDixMltiAqtBa9Zz/i7UkWwYwdzqgZY3Cx3vRZElFD09brYxo5VleeP3HQ==", + "dependencies": { + "openapi-types": "^12.1.3" + } + }, + "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==" + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -3774,7 +3939,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -3907,6 +4071,14 @@ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "engines": { + "node": ">=6" + } + }, "node_modules/pure-rand": { "version": "6.0.4", "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.4.tgz", @@ -3974,6 +4146,14 @@ "node": ">=0.10.0" } }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/resolve": { "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", @@ -4192,8 +4372,7 @@ "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" }, "node_modules/stack-utils": { "version": "2.0.6", @@ -4410,6 +4589,25 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/swagger-ui-dist": { + "version": "5.13.0", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.13.0.tgz", + "integrity": "sha512-uaWhh6j18IIs5tOX0arvIBnVINAzpTXaQXkr7qAk8zoupegJVg0UU/5+S/FgsgVCnzVsJ9d7QLjIxkswEeTg0Q==" + }, + "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/tdigest": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/tdigest/-/tdigest-0.1.2.tgz", @@ -4468,6 +4666,11 @@ "node": ">=0.6" } }, + "node_modules/ts-log": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/ts-log/-/ts-log-2.2.5.tgz", + "integrity": "sha512-PGcnJoTBnVGy6yYNFxWVNkdcAuAMstvutN9MgDJIV6L0oG8fB+ZNNy1T+wJzah8RPGor1mZuPQkVfXNDpy9eHA==" + }, "node_modules/type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", @@ -4544,6 +4747,14 @@ "browserslist": ">= 4.21.0" } }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, "node_modules/url-value-parser": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/url-value-parser/-/url-value-parser-2.2.0.tgz", @@ -4626,8 +4837,7 @@ "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "node_modules/write-file-atomic": { "version": "4.0.2", @@ -4657,6 +4867,17 @@ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true }, + "node_modules/yaml": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.1.tgz", + "integrity": "sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg==", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", diff --git a/gatewayservice/package.json b/gatewayservice/package.json index 313b29f..860d449 100644 --- a/gatewayservice/package.json +++ b/gatewayservice/package.json @@ -22,7 +22,10 @@ "cookie-parser": "^1.4.6", "cors": "^2.8.5", "express": "^4.18.2", - "express-prom-bundle": "^7.0.0" + "express-openapi": "^12.1.3", + "express-prom-bundle": "^7.0.0", + "swagger-ui-express": "^5.0.0", + "yaml": "^2.4.1" }, "devDependencies": { "jest": "^29.7.0", diff --git a/questionservice/question-service.js b/questionservice/question-service.js index 49a7f41..95bad70 100644 --- a/questionservice/question-service.js +++ b/questionservice/question-service.js @@ -135,11 +135,11 @@ app.post('/imgs/answer', (req, res) => { const answer = req.body; if(correctImg==answer){ - res.json({ + res.status(200).json({ correct: "true" }) } else { - res.json({ + res.status(400).json({ correct: "false", country: `${imgToAssociatedMap.get(answer)}` }) diff --git a/users/authservice/auth-service.js b/users/authservice/auth-service.js index c6a21df..73b9a4d 100644 --- a/users/authservice/auth-service.js +++ b/users/authservice/auth-service.js @@ -53,29 +53,7 @@ const server = app.listen(port, () => { console.log(`Auth Service listening at http://localhost:${port}`); }); -app.get('/self', async (req, res) => { - try { - const token = req.headers.authorization; - let id = {}; - if (!token) { - return res.status(403).json({ error: 'No token provided' }); - } - jwt.verify(token, 'your-secret-key', (err, decoded) => { - if (err) { - return res.status(500).json({ error: 'Failed to authenticate token' }); - } - - // If everything is good, save the user id to request for use in other routes - id = decoded.userId; - - }); - const user = await User.findById(id); - res.status(200).json(user); - } catch (error) { - res.status(500).json({ error: error.message }); - } -}); server.on('close', () => { // Close the Mongoose connection diff --git a/users/userservice/user-service.js b/users/userservice/user-service.js index 85d43c8..c85da76 100644 --- a/users/userservice/user-service.js +++ b/users/userservice/user-service.js @@ -57,22 +57,22 @@ app.get('/rankings', async (req, res) => { }) -app.post("/addpoints", async (req, res) => { - try { - validateRequiredFields(req, ['username']); - const user = await User.findOne({ - username: req.body.username - }); - if (!user) { - throw new Error('User not found'); - } - user.points += 1; - await user.save(); - res.status(200).json(user); - } catch (error) { - res.status(400).json({ error: error.message }); - } -}); +// app.post("/addpoints", async (req, res) => { +// try { +// validateRequiredFields(req, ['username']); +// const user = await User.findOne({ +// username: req.body.username +// }); +// if (!user) { +// throw new Error('User not found'); +// } +// user.points += 1; +// await user.save(); +// res.status(200).json(user); +// } catch (error) { +// res.status(400).json({ error: error.message }); +// } +// }); app.post('/adduser', async (req, res) => { try { diff --git a/webapp/src/components/Game.jsx b/webapp/src/components/Game.jsx index c39df49..1c6566e 100644 --- a/webapp/src/components/Game.jsx +++ b/webapp/src/components/Game.jsx @@ -24,7 +24,7 @@ const Game = () => { return (