diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a147ac10..cd15e8ba 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -54,7 +54,7 @@ jobs: uses: elgohr/Publish-Docker-Github-Action@v5 env: API_URI: http://${{ secrets.DEPLOY_HOST }}:8000 - API_GENERATOR_URI: http://${{ secrets.DEPLOY_HOST }}:8003 + API_GENERATOR_URI: http://${{ secrets.DEPLOY_HOST }}:3000 with: name: arquisoft/wiq_es2c/webapp username: ${{ github.actor }} diff --git a/gatewayservice/gateway-service.js b/gatewayservice/gateway-service.js index 9a0e4601..7f4ddc63 100644 --- a/gatewayservice/gateway-service.js +++ b/gatewayservice/gateway-service.js @@ -46,7 +46,19 @@ app.post('/adduser', async (req, res) => { app.get(`/generateQuestion`, async (req, res) => { try { // Forward the add user request to the user service - const response = await axios.get(generatorUrl+'/generateQuestion', req.body); + const URL = generatorUrl + '/generateQuestion?user=' + req.query.user + '&newGame=' + req.query.newGame + + '&numberOfQuestions=' + req.query.numberOfQuestions; + const response = await axios.get(URL); + res.json(response.data); + } catch (error) { + res.status(error.response.status).json({ error: error.response.data.error }); + } +}); + +app.get(`/updateQuestion`, async (req, res) => { + try { + // Forward the add user request to the user service + const response = await axios.get(generatorUrl+'/updateQuestion', req.body); res.json(response.data); } catch (error) { res.status(error.response.status).json({ error: error.response.data.error }); diff --git a/questiongenerator/Dockerfile b/questiongenerator/Dockerfile index dea484cb..067e5357 100644 --- a/questiongenerator/Dockerfile +++ b/questiongenerator/Dockerfile @@ -16,5 +16,8 @@ COPY . . # Expose the port the app runs on EXPOSE 8003 +ARG API_GENERATOR_URI="http://localhost:3000" +ENV REACT_APP_API_GENERATOR_ENDPOINT=$API_GENERATOR_URI + # Define the command to run your app CMD ["node", "question.js"] diff --git a/questiongenerator/image_questions.js b/questiongenerator/image_questions.js new file mode 100644 index 00000000..0e2b558c --- /dev/null +++ b/questiongenerator/image_questions.js @@ -0,0 +1,28 @@ +// Todas las consultas +var queries = + // pregunta = Imagen de un presidente de EE.UU., opcion = Nombres de presidentes de EE.UU. + [`SELECT ?option ?optionLabel ?imageLabel + WHERE { + ?option wdt:P31 wd:Q5; + wdt:P39 wd:Q11696; + wdt:P18 ?imageLabel. + SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE],es". } + } + `, + // pregunta = Imagen de un país, opcion = Pais + `SELECT DISTINCT ?option ?optionLabel ?imageLabel + WHERE { + ?option wdt:P31 wd:Q6256; + rdfs:label ?optionLabel; + + OPTIONAL { ?option wdt:P18 ?imageLabel. } + FILTER(lang(?optionLabel) = "es") + FILTER EXISTS { ?option wdt:P18 ?imageLabel } + } + `]; + +// Todas las preguntas, en el mismo orden que las consultas +var questions = ["¿Que presidente de EE.UU es el que se muestra en la imagen?", + "¿Que país es el que aparece en la siguiente imagen?"]; + +module.exports = { queries, questions }; \ No newline at end of file diff --git a/questiongenerator/question.js b/questiongenerator/question.js index 00b9b1b1..48ad3889 100644 --- a/questiongenerator/question.js +++ b/questiongenerator/question.js @@ -4,6 +4,9 @@ const mongoose = require('mongoose'); const bodyParser = require('body-parser'); const Question = require('./question-model'); const Game = require('./game-model'); +const { queries:textQueries, questions:textQuestions } = require('./text_questions'); +const { queries:imagesQueries, questions:imagesQuestions } = require('./image_questions'); + const app = express(); const port = 8003; @@ -13,53 +16,34 @@ const port = 8003; app.use(bodyParser.json()); // Necesario para poder hacer las peticiones desde Game -// http://localhost:3000 -// app.use((req, res, next) => { - res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000'); + res.setHeader('Access-Control-Allow-Origin', process.env.REACT_APP_API_GENERATOR_ENDPOINT); res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE'); res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization'); res.setHeader('Access-Control-Allow-Credentials', true); next(); }); +var queries = []; +queries = queries.concat(textQueries); +queries = queries.concat(imagesQueries); +console.log(queries.length); +var questions = []; +questions = questions.concat(textQuestions); +questions = questions.concat(imagesQuestions); + var correctOption = ""; var options = []; var question = ""; +var image = ""; var url = 'https://query.wikidata.org/sparql'; var questionToSave = null; var gameId = null; var numberOfQuestions = 0; -// Todas las consultas -var queries = [`SELECT ?question ?questionLabel ?option ?optionLabel - WHERE { - ?question wdt:P31 wd:Q6256; wdt:P36 ?option. - SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE],es". } - } - `,` - SELECT ?question ?questionLabel ?option ?optionLabel - WHERE { - ?question wdt:P31 wd:Q476028. - ?question wdt:P115 ?option. - ?question wdt:P17 wd:Q29. - SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE],es". } - } - `,` - SELECT ?option ?optionLabel ?questionLabel (SUBSTR(?símbolo, 1, 1) AS ?sym) - WHERE { - ?option wdt:P31 wd:Q11344; - wdt:P1086 ?questionLabel. - SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE], es". } - } - `]; -// Todas las preguntas, en el mismo orden que las consultas -var questions = ["¿Cuál es la capital de ", - "¿En que campo juega el ", - "¿Cual es el elemento de la tabla periódica número "]; + // Número aleatorio que decide la consulta y la pregunta que se mostrarán var randomNumber; - const mongoUri = process.env.MONGODB_URI || 'mongodb://localhost:27017/questiondb'; mongoose.connect(mongoUri); @@ -69,22 +53,21 @@ app.get('/generateQuestion', async (req, res) => { gameId = null; } const user = req.query.user; + console.log(user); await generarPregunta(); - numberOfQuestions++; if(numberOfQuestions>=5){ numberOfQuestions = 0; } - var id = await saveData(); - await saveGame(user, id); - - + + // Construcción de la respuesta var response = { responseQuestion: question, responseOptions: options, responseCorrectOption: correctOption, + responseImage: image, question_Id: id }; @@ -99,6 +82,7 @@ var server = app.listen(port, () => { }); async function generarPregunta() { + randomNumber = Math.floor(Math.random() * 2); try { // Petición a la API de WikiData randomNumber = Math.floor(Math.random() * queries.length); @@ -131,12 +115,21 @@ function procesarDatos(data) { while (randomIndexes.length < 4) { var randomIndex = Math.floor(Math.random() * data.length); var option = data[randomIndex].optionLabel.value; - var quest = data[randomIndex].questionLabel.value; + var quest = ""; + + // Si es una pregunta de texto hay que coger la parte de la pregunta que falta; si es una pregunta de imagen + // la pregunta ya viene en el array + if('questionLabel' in data[randomIndex]) { + quest = data[randomIndex].questionLabel.value; + } - // Comprobamos que tanto la opción como la pregunta no sean entidades de WikiData ni enlaces - if (!randomIndexes.includes(randomIndex) - && !(option.startsWith("Q") || option.startsWith("http")) - && !(quest.startsWith("Q") || quest.startsWith("http"))) { + // Comprobamos que tanto la opción como la pregunta no sean entidades de WikiData ni enlaces o que la pregunta ya + // venga en el array (estara vacia) + if (!randomIndexes.includes(randomIndex) && (quest == "" + || (!(option.startsWith("Q") || option.startsWith("http")) + && !(quest.startsWith("Q") || quest.startsWith("http")) + ) + )) { randomIndexes.push(randomIndex); } } @@ -144,17 +137,22 @@ function procesarDatos(data) { // Escogemos un índice aleatorio como la opción correcta var correctIndex = Math.floor(Math.random() * 4); correctOption = data[randomIndexes[correctIndex]].optionLabel.value; - questionValue = data[randomIndexes[correctIndex]].questionLabel.value; - question = questions[randomNumber] + questionValue + "?"; + + if(quest == "") { + question = questions[randomNumber]; + image = data[randomIndexes[correctIndex]].imageLabel.value; + } else { + image = ""; + questionValue = data[randomIndexes[correctIndex]].questionLabel.value; + question = questions[randomNumber] + questionValue + "?"; + } + // Varriamos las opciones, incluyendo la correcta for (let i = 0; i < 4; i++) { var optionIndex = randomIndexes[i]; options.push(data[optionIndex].optionLabel.value); } - - - } async function saveGame(username,id) { @@ -201,7 +199,6 @@ async function saveGame(username,id) { async function saveData(){ - try { var false_options = options.filter(o => o != correctOption); @@ -239,4 +236,4 @@ app.get('/updateQuestion', async (req, res) => { }); -module.exports = server +module.exports = server \ No newline at end of file diff --git a/questiongenerator/text_questions.js b/questiongenerator/text_questions.js new file mode 100644 index 00000000..3e353113 --- /dev/null +++ b/questiongenerator/text_questions.js @@ -0,0 +1,50 @@ +// Todas las consultas +var queries = + // pregunta = Pais, opcion = capitales + [`SELECT ?question ?questionLabel ?option ?optionLabel + WHERE { + ?question wdt:P31 wd:Q6256; wdt:P36 ?option. + SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE],es". } + } + LIMIT 200 + `, + // pregunta = Club de futbol, opcion = estadio + ` + SELECT ?question ?questionLabel ?option ?optionLabel + WHERE { + ?question wdt:P31 wd:Q476028. + ?question wdt:P115 ?option. + ?question wdt:P17 wd:Q29. + SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE],es". } + } + LIMIT 100 + `, + // Pregunta = Numero en la tabla periodica, opcion = Elemento + ` + SELECT ?option ?optionLabel ?questionLabel (SUBSTR(?símbolo, 1, 1) AS ?sym) + WHERE { + ?option wdt:P31 wd:Q11344; + wdt:P1086 ?questionLabel. + SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE], es". } + } + LIMIT 100 + `, + // Pregunta = Batalla historica, opcion = año + `SELECT ?question ?questionLabel ?optionLabel + WHERE { + ?question wdt:P31 wd:Q178561. + ?question wdt:P580 ?date. + FILTER (YEAR(?date) >= 1500 && YEAR(?date) <= 2000) + BIND(YEAR(?date) as ?optionLabel) + SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE],es". } + } + LIMIT 100 + `]; + +// Todas las preguntas, en el mismo orden que las consultas +var questions = ["¿Cuál es la capital de ", + "¿En que campo juega el ", + "¿Cuál es el elemento de la tabla periódica número ", + "¿En que año ocurrio la "]; + +module.exports = { queries, questions }; \ No newline at end of file diff --git a/webapp/.env b/webapp/.env index edddf932..c421c87a 100644 --- a/webapp/.env +++ b/webapp/.env @@ -1,2 +1,2 @@ REACT_APP_API_ENDPOINT=http://localhost:8000 -REACT_APP_API_GENERATOR_ENDPOINT=http://localhost:8003 \ No newline at end of file +REACT_GENERATOR_APP_API_ENDPOINT=http://localhost:8003 \ No newline at end of file diff --git a/webapp/Dockerfile b/webapp/Dockerfile index d3cdd542..3cbad8b7 100644 --- a/webapp/Dockerfile +++ b/webapp/Dockerfile @@ -8,8 +8,6 @@ RUN npm install ARG API_URI="http://localhost:8000" ENV REACT_APP_API_ENDPOINT=$API_URI -ARG API_GENERATOR_URI="http://localhost:8003" -ENV REACT_APP_API_GENERATOR_ENDPOINT=$API_GENERATOR_URI #Create an optimized version of the webapp RUN npm run build diff --git a/webapp/src/components/Game.js b/webapp/src/components/Game.js index 6b405cf2..bd2b0884 100644 --- a/webapp/src/components/Game.js +++ b/webapp/src/components/Game.js @@ -5,12 +5,12 @@ import { Container, Typography, Button, Snackbar } from '@mui/material'; import { useNavigate } from 'react-router-dom'; import { useUser } from './UserContext'; -// Cambio de prueba -const apiEndpoint = process.env.REACT_APP_API_GENERATOR_ENDPOINT || 'http://localhost:8003'; +const apiEndpoint = process.env.REACT_APP_API_ENDPOINT || 'http://localhost:8000'; const Game = () => { const { usernameGlobal } = useUser(); const [question, setQuestion] = useState(''); + const [image, setImage] = useState(''); const [options, setOptions] = useState([]); const [correctOption, setCorrectOption] = useState(""); const [questionId,setQuestionId] = useState(null); @@ -28,26 +28,28 @@ const Game = () => { const getQuestion = useCallback(async (answeredQuestionsValue) => { try { - console.log(" NUMERO DE PREGUNTA " + answeredQuestionsValue); + //console.log(" NUMERO DE PREGUNTA " + answeredQuestionsValue); const createNewGame = answeredQuestionsValue > 0 ? false : true; - console.log(" HAY QUE CREAR UN NUEVO JUEGO? " + createNewGame); - + //console.log(" HAY QUE CREAR UN NUEVO JUEGO? " + createNewGame); + const response = await axios.get(`${apiEndpoint}/generateQuestion`, { params: { user: usernameGlobal, newGame: createNewGame, - numberOfQuestiona: answeredQuestionsValue + numberOfQuestions: answeredQuestionsValue } }); setQuestionId(response.data.question_Id); setQuestion(response.data.responseQuestion); setOptions(response.data.responseOptions); setCorrectOption(response.data.responseCorrectOption); + setImage(response.data.responseImage); setOpenSnackbar(true); setElapsedTime(MAX_TIME); } catch (error) { + console.log(error.message); setError(error.response.data.error); } }, []) @@ -125,6 +127,9 @@ const Game = () => { {question} +
+ {image != null && image != "" && Imagen de la pregunta} +
{options.map((option, index) => (