diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index cf43cc9a..49ffe7c5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,6 +14,8 @@ jobs: node-version: 20 - run: npm --prefix users/authservice ci - run: npm --prefix users/userservice ci + - run: npm --prefix question_generator ci + - run: npm --prefix questionservice ci - run: npm --prefix gatewayservice ci - run: npm --prefix webapp ci - run: npm --prefix users/authservice test -- --coverage @@ -35,6 +37,8 @@ jobs: node-version: 20 - run: npm --prefix users/authservice install - run: npm --prefix users/userservice install + - run: npm --prefix question_generator install + - run: npm --prefix questionservice install - run: npm --prefix gatewayservice install - run: npm --prefix webapp install - run: npm --prefix webapp run build @@ -93,6 +97,43 @@ jobs: password: ${{ secrets.GITHUB_TOKEN }} registry: ghcr.io workdir: users/userservice + + docker-push-questiongenerationservice: + name: Push question service Docker Image to GitHub Packages + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + needs: [e2e-tests] + steps: + - uses: actions/checkout@v4 + - name: Publish to Registry + uses: elgohr/Publish-Docker-Github-Action@v5 + with: + name: arquisoft/wiq_es3b/questiongenerationservice + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + registry: ghcr.io + workdir: questiongenerationservice + + docker-push-questionservice: + name: Push question service Docker Image to GitHub Packages + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + needs: [e2e-tests] + steps: + - uses: actions/checkout@v4 + - name: Publish to Registry + uses: elgohr/Publish-Docker-Github-Action@v5 + with: + name: arquisoft/wiq_es3b/questionservice + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + registry: ghcr.io + workdir: questionservice + docker-push-gatewayservice: name: Push gateway service Docker Image to GitHub Packages runs-on: ubuntu-latest @@ -113,7 +154,7 @@ jobs: deploy: name: Deploy over SSH runs-on: ubuntu-latest - needs: [docker-push-userservice,docker-push-authservice,docker-push-gatewayservice,docker-push-webapp] + needs: [docker-push-userservice,docker-push-authservice,docker-push-questiongenerationservice,docker-push-questionservice,docker-push-gatewayservice,docker-push-webapp] steps: - name: Deploy over SSH uses: fifsky/ssh-action@master diff --git a/gatewayservice/gateway-service.js b/gatewayservice/gateway-service.js index 88679a43..c0af0ad0 100644 --- a/gatewayservice/gateway-service.js +++ b/gatewayservice/gateway-service.js @@ -44,11 +44,13 @@ app.post('/adduser', async (req, res) => { }); app.get('/api/questions/create', async (req, res) => { - console.log('Create Question') try { + let apiUrl=questionGenerationServiceUrl+'/api/questions/create'; + if(Object.keys(req.query).length > 0) { + apiUrl+='?'+new URLSearchParams(req.query); + } // Forward the add user request to the user service - const userResponse = await axios.get(questionGenerationServiceUrl+'/api/questions/create'); - console.log(userResponse.data); + const userResponse = await axios.get(apiUrl); res.json(userResponse.data); } catch (error) { res.status(error.response.status).json({ error: error.response.data.error }); diff --git a/gatewayservice/gateway-service.test.js b/gatewayservice/gateway-service.test.js index bc532ffe..73547264 100644 --- a/gatewayservice/gateway-service.test.js +++ b/gatewayservice/gateway-service.test.js @@ -36,6 +36,14 @@ describe('Gateway Service', () => { incorrects: ['Mocked Option 1', 'Mocked Option 2'] } }); + }else if(url.endsWith('/api/questions/create?lang=es&category=sports')){ + return Promise.resolve({ + data: { + question: 'Mocked Question', + correct: 'Mocked Correct Answer', + incorrects: ['Mocked Option 1', 'Mocked Option 2'] + } + }); } }); // Test /health endpoint @@ -76,6 +84,15 @@ describe('Gateway Service', () => { expect(response.body).toHaveProperty('correct'); expect(response.body).toHaveProperty('incorrects'); },10000); + it('should forward create question request to question generation service', async () => { + const response = await request(app) + .get('/api/questions/create?lang=es&category=sports'); + expect(response.statusCode).toBe(200); + expect(response.body).toHaveProperty('question'); + expect(response.body).toHaveProperty('correct'); + expect(response.body).toHaveProperty('incorrects'); + },10000); + // Test /addquestion endpoint diff --git a/question_generator/cities/citiesQuestions.js b/question_generator/geography/cities/citiesQuestions.js similarity index 98% rename from question_generator/cities/citiesQuestions.js rename to question_generator/geography/cities/citiesQuestions.js index 144a264d..c0f6fba5 100644 --- a/question_generator/cities/citiesQuestions.js +++ b/question_generator/geography/cities/citiesQuestions.js @@ -1,4 +1,4 @@ -const queryExecutor=require("../queryExecutor") +const queryExecutor=require("../../queryExecutor") class CitiesQuestions{ #citiesQuestions=null; static getInstance(){ diff --git a/question_generator/cities/citiesTemplates.js b/question_generator/geography/cities/citiesTemplates.js similarity index 91% rename from question_generator/cities/citiesTemplates.js rename to question_generator/geography/cities/citiesTemplates.js index 399eeb4a..cbda0b18 100644 --- a/question_generator/cities/citiesTemplates.js +++ b/question_generator/geography/cities/citiesTemplates.js @@ -17,7 +17,8 @@ const templates=[ { const results= await citiesQuery.getCityForCountry(); return{ - "question":"Which city is in "+results.country+"?", + "question":"Which city is in?", + "question_param":results.country, "correct":results.correct, "incorrects":results.incorrects } diff --git a/question_generator/geography/geographyTemplate.js b/question_generator/geography/geographyTemplate.js new file mode 100644 index 00000000..ddf64a8d --- /dev/null +++ b/question_generator/geography/geographyTemplate.js @@ -0,0 +1,9 @@ +const citiesTemplate=require('./cities/citiesTemplates') +function loadData(){ + citiesTemplate.loadData(); +} +const templates=[ + citiesTemplate.getRandomQuestion +] +module.exports.getRandomQuestion = () => templates[Math.floor(Math.random()*templates.length)](); +module.exports.loadData = () =>loadData(); \ No newline at end of file diff --git a/question_generator/locales/en.json b/question_generator/locales/en.json new file mode 100644 index 00000000..5ec8060c --- /dev/null +++ b/question_generator/locales/en.json @@ -0,0 +1,15 @@ +{ + + "Which city is higher above sea level?": "Which city is higher above sea level?", + "Which city has more population?": "Which city has more population?", + "Which city is in?": "Which city is in %s?", + + + + "Which planet is bigger?": "Which planet is bigger?", + + + + + "Who has more Grand Slams?": "Who has more Grand Slams?" +} \ No newline at end of file diff --git a/question_generator/locales/es.json b/question_generator/locales/es.json new file mode 100644 index 00000000..37c8d2da --- /dev/null +++ b/question_generator/locales/es.json @@ -0,0 +1,15 @@ +{ + + "Which city is higher above sea level?": "¿Qué ciudad tiene más altitud sobre el nivel del mar?", + "Which city has more population?": "¿Qué ciudad tiene más población?", + "Which city is in?": "¿Qué ciudad está en %s?", + + + + "Which planet is bigger?": "¿Qué planeta tiene un tamaño mayor?", + + + + + "Who has more Grand Slams?": "¿Quién tiene más Grand Slams?" +} \ No newline at end of file diff --git a/question_generator/package-lock.json b/question_generator/package-lock.json index 5c2de634..9c049b45 100644 --- a/question_generator/package-lock.json +++ b/question_generator/package-lock.json @@ -11,7 +11,8 @@ "dependencies": { "axios": "^1.6.7", "body-parser": "^1.20.2", - "express": "^4.18.2" + "express": "^4.18.2", + "i18n": "^0.15.1" }, "devDependencies": { "jest": "^29.7.0", @@ -1050,6 +1051,45 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@messageformat/core": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@messageformat/core/-/core-3.3.0.tgz", + "integrity": "sha512-YcXd3remTDdeMxAlbvW6oV9d/01/DZ8DHUFwSttO3LMzIZj3iO0NRw+u1xlsNNORFI+u0EQzD52ZX3+Udi0T3g==", + "dependencies": { + "@messageformat/date-skeleton": "^1.0.0", + "@messageformat/number-skeleton": "^1.0.0", + "@messageformat/parser": "^5.1.0", + "@messageformat/runtime": "^3.0.1", + "make-plural": "^7.0.0", + "safe-identifier": "^0.4.1" + } + }, + "node_modules/@messageformat/date-skeleton": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@messageformat/date-skeleton/-/date-skeleton-1.0.1.tgz", + "integrity": "sha512-jPXy8fg+WMPIgmGjxSlnGJn68h/2InfT0TNSkVx0IGXgp4ynnvYkbZ51dGWmGySEK+pBiYUttbQdu5XEqX5CRg==" + }, + "node_modules/@messageformat/number-skeleton": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@messageformat/number-skeleton/-/number-skeleton-1.2.0.tgz", + "integrity": "sha512-xsgwcL7J7WhlHJ3RNbaVgssaIwcEyFkBqxHdcdaiJzwTZAWEOD8BuUFxnxV9k5S0qHN3v/KzUpq0IUpjH1seRg==" + }, + "node_modules/@messageformat/parser": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@messageformat/parser/-/parser-5.1.0.tgz", + "integrity": "sha512-jKlkls3Gewgw6qMjKZ9SFfHUpdzEVdovKFtW1qRhJ3WI4FW5R/NnGDqr8SDGz+krWDO3ki94boMmQvGke1HwUQ==", + "dependencies": { + "moo": "^0.5.1" + } + }, + "node_modules/@messageformat/runtime": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@messageformat/runtime/-/runtime-3.0.1.tgz", + "integrity": "sha512-6RU5ol2lDtO8bD9Yxe6CZkl0DArdv0qkuoZC+ZwowU+cdRlVE1157wjCmlA5Rsf1Xc/brACnsZa5PZpEDfTFFg==", + "dependencies": { + "make-plural": "^7.0.0" + } + }, "node_modules/@sinclair/typebox": { "version": "0.27.8", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", @@ -1413,6 +1453,11 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/boolean": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz", + "integrity": "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==" + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -2072,6 +2117,17 @@ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "dev": true }, + "node_modules/fast-printf": { + "version": "1.6.9", + "resolved": "https://registry.npmjs.org/fast-printf/-/fast-printf-1.6.9.tgz", + "integrity": "sha512-FChq8hbz65WMj4rstcQsFB0O7Cy++nmbNfLYnD9cYv2cRn8EG6k/MGn9kO/tjO66t09DLDugj3yL+V2o6Qftrg==", + "dependencies": { + "boolean": "^3.1.4" + }, + "engines": { + "node": ">=10.0" + } + }, "node_modules/fast-safe-stringify": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", @@ -2415,6 +2471,46 @@ "node": ">=10.17.0" } }, + "node_modules/i18n": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/i18n/-/i18n-0.15.1.tgz", + "integrity": "sha512-yue187t8MqUPMHdKjiZGrX+L+xcUsDClGO0Cz4loaKUOK9WrGw5pgan4bv130utOwX7fHE9w2iUeHFalVQWkXA==", + "dependencies": { + "@messageformat/core": "^3.0.0", + "debug": "^4.3.3", + "fast-printf": "^1.6.9", + "make-plural": "^7.0.0", + "math-interval-parser": "^2.0.1", + "mustache": "^4.2.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/mashpie" + } + }, + "node_modules/i18n/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/i18n/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -3392,6 +3488,11 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, + "node_modules/make-plural": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/make-plural/-/make-plural-7.3.0.tgz", + "integrity": "sha512-/K3BC0KIsO+WK2i94LkMPv3wslMrazrQhfi5We9fMbLlLjzoOSJWr7TAdupLlDWaJcWxwoNosBkhFDejiu5VDw==" + }, "node_modules/makeerror": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", @@ -3401,6 +3502,14 @@ "tmpl": "1.0.5" } }, + "node_modules/math-interval-parser": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/math-interval-parser/-/math-interval-parser-2.0.1.tgz", + "integrity": "sha512-VmlAmb0UJwlvMyx8iPhXUDnVW1F9IrGEd9CIOmv+XL8AErCUUuozoDMrgImvnYt2A+53qVX/tPW6YJurMKYsvA==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -3492,11 +3601,24 @@ "node": "*" } }, + "node_modules/moo": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/moo/-/moo-0.5.2.tgz", + "integrity": "sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q==" + }, "node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, + "node_modules/mustache": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", + "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", + "bin": { + "mustache": "bin/mustache" + } + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -3930,6 +4052,11 @@ } ] }, + "node_modules/safe-identifier": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/safe-identifier/-/safe-identifier-0.4.2.tgz", + "integrity": "sha512-6pNbSMW6OhAi9j+N8V+U715yBQsaWJ7eyEUaOrawX+isg5ZxhUlV1NipNtgaKHmFGiABwt+ZF04Ii+3Xjkg+8w==" + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -5369,6 +5496,45 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "@messageformat/core": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@messageformat/core/-/core-3.3.0.tgz", + "integrity": "sha512-YcXd3remTDdeMxAlbvW6oV9d/01/DZ8DHUFwSttO3LMzIZj3iO0NRw+u1xlsNNORFI+u0EQzD52ZX3+Udi0T3g==", + "requires": { + "@messageformat/date-skeleton": "^1.0.0", + "@messageformat/number-skeleton": "^1.0.0", + "@messageformat/parser": "^5.1.0", + "@messageformat/runtime": "^3.0.1", + "make-plural": "^7.0.0", + "safe-identifier": "^0.4.1" + } + }, + "@messageformat/date-skeleton": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@messageformat/date-skeleton/-/date-skeleton-1.0.1.tgz", + "integrity": "sha512-jPXy8fg+WMPIgmGjxSlnGJn68h/2InfT0TNSkVx0IGXgp4ynnvYkbZ51dGWmGySEK+pBiYUttbQdu5XEqX5CRg==" + }, + "@messageformat/number-skeleton": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@messageformat/number-skeleton/-/number-skeleton-1.2.0.tgz", + "integrity": "sha512-xsgwcL7J7WhlHJ3RNbaVgssaIwcEyFkBqxHdcdaiJzwTZAWEOD8BuUFxnxV9k5S0qHN3v/KzUpq0IUpjH1seRg==" + }, + "@messageformat/parser": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@messageformat/parser/-/parser-5.1.0.tgz", + "integrity": "sha512-jKlkls3Gewgw6qMjKZ9SFfHUpdzEVdovKFtW1qRhJ3WI4FW5R/NnGDqr8SDGz+krWDO3ki94boMmQvGke1HwUQ==", + "requires": { + "moo": "^0.5.1" + } + }, + "@messageformat/runtime": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@messageformat/runtime/-/runtime-3.0.1.tgz", + "integrity": "sha512-6RU5ol2lDtO8bD9Yxe6CZkl0DArdv0qkuoZC+ZwowU+cdRlVE1157wjCmlA5Rsf1Xc/brACnsZa5PZpEDfTFFg==", + "requires": { + "make-plural": "^7.0.0" + } + }, "@sinclair/typebox": { "version": "0.27.8", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", @@ -5685,6 +5851,11 @@ "unpipe": "1.0.0" } }, + "boolean": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz", + "integrity": "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==" + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -6163,6 +6334,14 @@ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "dev": true }, + "fast-printf": { + "version": "1.6.9", + "resolved": "https://registry.npmjs.org/fast-printf/-/fast-printf-1.6.9.tgz", + "integrity": "sha512-FChq8hbz65WMj4rstcQsFB0O7Cy++nmbNfLYnD9cYv2cRn8EG6k/MGn9kO/tjO66t09DLDugj3yL+V2o6Qftrg==", + "requires": { + "boolean": "^3.1.4" + } + }, "fast-safe-stringify": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", @@ -6398,6 +6577,34 @@ "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true }, + "i18n": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/i18n/-/i18n-0.15.1.tgz", + "integrity": "sha512-yue187t8MqUPMHdKjiZGrX+L+xcUsDClGO0Cz4loaKUOK9WrGw5pgan4bv130utOwX7fHE9w2iUeHFalVQWkXA==", + "requires": { + "@messageformat/core": "^3.0.0", + "debug": "^4.3.3", + "fast-printf": "^1.6.9", + "make-plural": "^7.0.0", + "math-interval-parser": "^2.0.1", + "mustache": "^4.2.0" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -7138,6 +7345,11 @@ } } }, + "make-plural": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/make-plural/-/make-plural-7.3.0.tgz", + "integrity": "sha512-/K3BC0KIsO+WK2i94LkMPv3wslMrazrQhfi5We9fMbLlLjzoOSJWr7TAdupLlDWaJcWxwoNosBkhFDejiu5VDw==" + }, "makeerror": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", @@ -7147,6 +7359,11 @@ "tmpl": "1.0.5" } }, + "math-interval-parser": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/math-interval-parser/-/math-interval-parser-2.0.1.tgz", + "integrity": "sha512-VmlAmb0UJwlvMyx8iPhXUDnVW1F9IrGEd9CIOmv+XL8AErCUUuozoDMrgImvnYt2A+53qVX/tPW6YJurMKYsvA==" + }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -7211,11 +7428,21 @@ "brace-expansion": "^1.1.7" } }, + "moo": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/moo/-/moo-0.5.2.tgz", + "integrity": "sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q==" + }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, + "mustache": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", + "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==" + }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -7515,6 +7742,11 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" }, + "safe-identifier": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/safe-identifier/-/safe-identifier-0.4.2.tgz", + "integrity": "sha512-6pNbSMW6OhAi9j+N8V+U715yBQsaWJ7eyEUaOrawX+isg5ZxhUlV1NipNtgaKHmFGiABwt+ZF04Ii+3Xjkg+8w==" + }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", diff --git a/question_generator/package.json b/question_generator/package.json index 4cde5565..401587dd 100644 --- a/question_generator/package.json +++ b/question_generator/package.json @@ -4,26 +4,27 @@ "description": "Question generation service", "main": "service.js", "scripts": { - "start": "node questionGenerationService.js", - "test": "jest" + "start": "node questionGenerationService.js", + "test": "jest" }, "repository": { - "type": "git", - "url": "git+https://github.com/arquisoft/wiq_es3b.git" + "type": "git", + "url": "git+https://github.com/arquisoft/wiq_es3b.git" }, "author": "", "license": "ISC", "bugs": { - "url": "https://github.com/arquisoft/wiq_es3b/issues" + "url": "https://github.com/arquisoft/wiq_es3b/issues" }, "homepage": "https://github.com/arquisoft/wiq_es3b#readme", "dependencies": { "axios": "^1.6.7", "body-parser": "^1.20.2", - "express": "^4.18.2" + "express": "^4.18.2", + "i18n": "^0.15.1" }, "devDependencies": { - "jest": "^29.7.0", - "supertest": "^6.3.4" + "jest": "^29.7.0", + "supertest": "^6.3.4" } } diff --git a/question_generator/queryExecutor.js b/question_generator/queryExecutor.js index 435508e6..5af84116 100644 --- a/question_generator/queryExecutor.js +++ b/question_generator/queryExecutor.js @@ -7,7 +7,7 @@ class QueryExecutor{ // Configuración de la solicitud HTTP const config = { headers: { - 'User-Agent': 'QueryExecutor/1.0 (uo287687@email.com)', + 'User-Agent': 'QueryExecutor/1.0 (uo287687@uniovi.es)', 'Accept': 'application/json', }, }; diff --git a/question_generator/questionGenerationService.js b/question_generator/questionGenerationService.js index 79a6fa4a..abe61661 100644 --- a/question_generator/questionGenerationService.js +++ b/question_generator/questionGenerationService.js @@ -1,41 +1,69 @@ const express = require('express'); const bodyParser = require('body-parser'); +const i18n = require('i18n'); -const citiesTemplate=require('./cities/citiesTemplates'); +const geographyTemplate=require('./geography/geographyTemplate'); const planetTemplate=require('./planets/planetsTemplates'); -const generalTemplate=require('./questionTemplate') +const sportTemplate=require('./sports/sportTemplate'); +const generalTemplate=require('./questionTemplate'); const app = express(); const port = 8003; +i18n.configure({ + locales: ['en', 'es'], + directory: './locales', + defaultLocale: 'en', + cookie: 'lang', +}); + app.use(bodyParser.json()); +app.use(i18n.init); + +//i18n middleware +app.use( + (req, res, next) => { + const userLocale = req.query.lang; + const localeToSet = userLocale || i18n.getLocale(); + i18n.setLocale(localeToSet); + next(); + } +) app.get('/api/questions/create', async (req, res) => { try { - const randomQuestion = await generalTemplate.getRandomQuestion(); - res.status(200).json(randomQuestion); - } catch (error) { - res.status(500).json({ error: 'Internal Server Error' }); - } -}); -app.get('/api/questions/planets/create', async (req, res) => { - try { - const randomQuestion = await planetTemplate.getRandomQuestion(); - res.status(200).json(randomQuestion); - } catch (error) { - res.status(500).json({ error: 'Internal Server Error' }); - } -}); -app.get('/api/questions/cities/create', async (req, res) => { - try { - const randomQuestion = await citiesTemplate.getRandomQuestion(); - res.status(200).json(randomQuestion); + const category = req.query.category; + let randomQuestion; + + switch (category) { + case 'planets': + randomQuestion = await planetTemplate.getRandomQuestion(); + break; + case 'geography': + randomQuestion = await geographyTemplate.getRandomQuestion(); + break; + case 'sports': + randomQuestion = await sportTemplate.getRandomQuestion(); + break; + default: + randomQuestion = await generalTemplate.getRandomQuestion(); + } + randomQuestion.question = i18n.__(randomQuestion.question, randomQuestion.question_param); + + res.status(200).json( + { + question: randomQuestion.question, + correct: randomQuestion.correct, + incorrects: randomQuestion.incorrects + } + ); } catch (error) { res.status(500).json({ error: 'Internal Server Error' }); } }); + generalTemplate.loadData(); const server = app.listen(port, () => { diff --git a/question_generator/questionGenerationService.test.js b/question_generator/questionGenerationService.test.js index 4de404bf..2b00f2c5 100644 --- a/question_generator/questionGenerationService.test.js +++ b/question_generator/questionGenerationService.test.js @@ -22,7 +22,7 @@ describe('Question generation service', () => { it('should forward create question request to question generation service', async () => { const response = await request(app) - .get('/api/questions/planets/create'); + .get('/api/questions/create?category=sports'); expect(response.statusCode).toBe(200); expect(response.body).toHaveProperty('question'); @@ -32,7 +32,7 @@ describe('Question generation service', () => { it('should forward create question request to question generation service', async () => { const response = await request(app) - .get('/api/questions/cities/create'); + .get('/api/questions/create?category=geography'); expect(response.statusCode).toBe(200); expect(response.body).toHaveProperty('question'); diff --git a/question_generator/questionTemplate.js b/question_generator/questionTemplate.js index a9a4bf46..4211e196 100644 --- a/question_generator/questionTemplate.js +++ b/question_generator/questionTemplate.js @@ -1,12 +1,15 @@ const planetsTemplates=require('./planets/planetsTemplates'); -const citiesTemplates=require('./cities/citiesTemplates') +const geographyTemplates=require('./geography/geographyTemplate') +const sportTemplates=require('./sports/sportTemplate') function loadData(){ - citiesTemplates.loadData() + geographyTemplates.loadData() planetsTemplates.loadData() + sportTemplates.loadData() } const templates=[ planetsTemplates.getRandomQuestion, - citiesTemplates.getRandomQuestion + geographyTemplates.getRandomQuestion, + sportTemplates.getRandomQuestion ] module.exports.getRandomQuestion = () => templates[Math.floor(Math.random()*templates.length)](); diff --git a/question_generator/sports/sportTemplate.js b/question_generator/sports/sportTemplate.js new file mode 100644 index 00000000..21af6e9d --- /dev/null +++ b/question_generator/sports/sportTemplate.js @@ -0,0 +1,10 @@ +const tennisTemplates=require('./tennis/tennisTemplates'); +function loadData(){ + tennisTemplates.loadData() +} +const templates=[ + tennisTemplates.getRandomQuestion + +] +module.exports.getRandomQuestion = () => templates[Math.floor(Math.random()*templates.length)](); +module.exports.loadData = ()=>loadData(); \ No newline at end of file diff --git a/question_generator/sports/tennis/tennisQuestions.js b/question_generator/sports/tennis/tennisQuestions.js new file mode 100644 index 00000000..3fde8517 --- /dev/null +++ b/question_generator/sports/tennis/tennisQuestions.js @@ -0,0 +1,41 @@ +const queryExecutor=require("../../queryExecutor") +class TennisQuestions{ + #tennisQuestions=null; + static getInstance(){ + if (!this.questions) { + this.questions = new TennisQuestions(); + } + return this.questions; + } + constructor(){ + this.data={} + } + async loadData(){ + /* + if(Object.keys(this.data).length==0){ + const query= ` + + `; + const results=await queryExecutor.execute(query) + results.forEach(result => { + //this.data.push(); + }); + } + */ + } + async getRandomPlayer(number){ + await this.loadData(); + const array = Object.values(this.data); + const randomResults = array.sort(() => Math.random() - 0.5).slice(0, number); + return randomResults + } + async getPlayerWithMoreGrandSlams() { + const results=await this.getRandomPlayer(4); + //... + return { + correct: "Rafa Nadal", + incorrects: ["Persona 2", "Persona 3"] + } + } +} +module.exports =TennisQuestions; \ No newline at end of file diff --git a/question_generator/sports/tennis/tennisTemplates.js b/question_generator/sports/tennis/tennisTemplates.js new file mode 100644 index 00000000..a535e6f4 --- /dev/null +++ b/question_generator/sports/tennis/tennisTemplates.js @@ -0,0 +1,20 @@ +const tennisQuestions=require('./tennisQuestions'); +const tennisQuery=tennisQuestions.getInstance(); +function loadData(){ + tennisQuery.loadData(); +} +const templates=[ + async ()=> + { + const result= await tennisQuery.getPlayerWithMoreGrandSlams(); + return{ + "question":"Who has more Grand Slams?", + "correct":result.correct, + "incorrects":result.incorrects + } + } + + +] +module.exports.getRandomQuestion = () => templates[Math.floor(Math.random()*templates.length)](); +module.exports.loadData = ()=>loadData(); \ No newline at end of file