diff --git a/docs/images/06_game.png b/docs/images/06_game.png index e16f9067..63f7aa99 100644 Binary files a/docs/images/06_game.png and b/docs/images/06_game.png differ diff --git a/docs/images/GameView.png b/docs/images/GameView.png index ce9814a8..51bfb03a 100644 Binary files a/docs/images/GameView.png and b/docs/images/GameView.png differ diff --git a/docs/images/HomeView.png b/docs/images/HomeView.png index 7de67fa0..050b4457 100644 Binary files a/docs/images/HomeView.png and b/docs/images/HomeView.png differ diff --git a/docs/images/StartView.png b/docs/images/StartView.png deleted file mode 100644 index 4787dd22..00000000 Binary files a/docs/images/StartView.png and /dev/null differ diff --git a/docs/images/UserView.png b/docs/images/UserView.png index e3811f7b..8d9bc1e4 100644 Binary files a/docs/images/UserView.png and b/docs/images/UserView.png differ diff --git a/docs/images/level3.png b/docs/images/level3.png index b032ff5a..552f7ae5 100644 Binary files a/docs/images/level3.png and b/docs/images/level3.png differ diff --git a/docs/src/04_solution_strategy.adoc b/docs/src/04_solution_strategy.adoc index 8a7330d3..3c362dd8 100644 --- a/docs/src/04_solution_strategy.adoc +++ b/docs/src/04_solution_strategy.adoc @@ -12,6 +12,7 @@ This page contains a short summary and explanation of the fundamental decisions Below, all the technologies to be used in the development of the application are listed: * *JavaScript / React:* A JavaScript library designed to facilitate the development of web applications. +* *Material UI:* Set of user interface components for web applications. * *JavaScript / NodeJS:* An asynchronous runtime environment based on JavaScript. * *MongoDB:* A document-oriented NoSQL database system. * *Docker:* Used for deploying applications locally. @@ -76,9 +77,8 @@ This section addresses the fundamental decisions for the project's architecture. |=== -| *Data Management* | -| *Deployment* | -| *Security* | -| *Monitoring* | +| *Deployment* | Use of Azure for application deployment +| *Security* | User access control +| *Monitoring* | Prometheus and Grafana for monitoring |=== \ No newline at end of file diff --git a/docs/src/06_runtime_view.adoc b/docs/src/06_runtime_view.adoc index 5fa74cb5..a87c5aa7 100644 --- a/docs/src/06_runtime_view.adoc +++ b/docs/src/06_runtime_view.adoc @@ -49,18 +49,4 @@ In this view, the user can watch this options about his past games: - Best times - Correct/incorrect questions -[plantuml,"sequencediagram-history",png] ----- -actor User as user -participant HistoryMS as MS -participant MongoDB as db - -activate MS - -user -> MS: Request history -MS -> db: Asks for the history -db -> MS: Gives the user's history -MS -> user: Shows the history - -deactivate MS ----- +image::06_history.png["Game"] diff --git a/docs/src/08_concepts.adoc b/docs/src/08_concepts.adoc index 5cf661fe..95b5a3e3 100644 --- a/docs/src/08_concepts.adoc +++ b/docs/src/08_concepts.adoc @@ -1,10 +1,14 @@ ifndef::imagesdir[:imagesdir: ../images] [[section-concepts]] -## First Designs -### Home Page +## 1.0 Designs + +### User Page :imagesdir: ../images +image::UserView.png[User View] +--- +### Home Page image::HomeView.png[Home Menu View] --- ### Game page @@ -36,4 +40,4 @@ Various expansions to the application are proposed, such as a multiplayer versio ### Data persistence and availability: Application data is stored using MongoDB, one of the most commonly used NoSQL databases. -The application can be deployed at any time locally or in an environment such as a virtual machine. \ No newline at end of file +The application can be deployed at any time locally or in an environment such as a virtual machine. diff --git a/gameservice/game-service.js b/gameservice/game-service.js index d3f8b426..2f016811 100644 --- a/gameservice/game-service.js +++ b/gameservice/game-service.js @@ -156,9 +156,9 @@ app.get('/getParticipation/:userId', async (req, res) => { }, ]); - if (participationData.length === 0) { + if (participationData.length === 0 || (participationData.length > 0 && participationData[0].totalGames === 0)) { // No se encontraron datos para el usuario - res.status(404).json({ error: 'No participation data found for the user.' }); + res.status(204).send(); return; } diff --git a/gameservice/game-service.test.js b/gameservice/game-service.test.js index a16d95b6..7b28457f 100644 --- a/gameservice/game-service.test.js +++ b/gameservice/game-service.test.js @@ -39,7 +39,6 @@ beforeEach(async () => { totalTime: 1200, gameMode: 'normal' }); - }); afterEach(async () => { @@ -82,13 +81,33 @@ describe('Game Service', () => { totalTime: 1200, }; - const response = await request(app).get(`/getParticipation/${userId}`); expect(response.status).toBe(200); expect(response.body).toEqual(mockParticipationData); }); + // Test para manejar el caso de usuario no encontrado al obtener los datos de participación + it('should return 404 when getting participation data for non-existent user', async () => { + const nonExistentUserId = 'nonExistentUserId'; + const response = await request(app).get(`/getParticipation/${nonExistentUserId}`); + + expect(response.status).toBe(404); + expect(response.body).toEqual({ error: 'User not found.' }); + }); + it('should return 204 when getting participation data for user with totalGames equal to 0', async () => { + const userNoGames = await User.create({ + username: 'noGames', + profileImage: 'defaultProfileImg', + password: 'password123' + }); + userNGId = userNoGames._id; + + const response = await request(app).get(`/getParticipation/${userNGId}`); + + expect(response.status).toBe(204); + }); +}); describe('Api info users', () => { it('should get user information on GET /api/info/users', async () => { const axiosMock = jest.spyOn(axios, 'get'); diff --git a/users/authservice/auth-service.js b/users/authservice/auth-service.js index 22044d66..5df0c90b 100644 --- a/users/authservice/auth-service.js +++ b/users/authservice/auth-service.js @@ -39,7 +39,7 @@ app.post('/login', async (req, res) => { // Generate a JWT token const token = jwt.sign({ userId: user._id }, 'your-secret-key', { expiresIn: '1h' }); // Respond with the token and user information - res.json({ token: token, username: username, createdAt: user.createdAt, userId: user._id }); + res.json({ token: token, username: username, createdAt: user.createdAt, profileImage: user.profileImage, userId: user._id }); return; } else { res.status(401).json({ error: 'Invalid credentials' }); diff --git a/webapp/src/components/AddUser.js b/webapp/src/components/AddUser.js index ab68a737..d72f9029 100644 --- a/webapp/src/components/AddUser.js +++ b/webapp/src/components/AddUser.js @@ -35,7 +35,7 @@ const AddUser = ({goTo}) => { setOpenSnackbar(true); try{ const response = await axios.post(`${apiEndpoint}/login`, { username, password }); - const { createdAt: userCreatedAt, username: loggedInUsername, token, profileImage, userId: id } = response.data; + const { createdAt: userCreatedAt, username: loggedInUsername, token: token, profileImage: profileImage, userId: id } = response.data; setLoginSuccess(true); saveSessionData({ username: loggedInUsername, createdAt: userCreatedAt, token: token, profileImage: profileImage, userId: id }); } catch (error) { diff --git a/webapp/src/components/Login.js b/webapp/src/components/Login.js index e53c5d8d..8c5aa14e 100644 --- a/webapp/src/components/Login.js +++ b/webapp/src/components/Login.js @@ -27,7 +27,7 @@ const Login = ({ goTo }) => { const response = await axios.post(`${apiEndpoint}/login`, { username, password }); // Extract data from the response - const { createdAt: userCreatedAt, username: loggedInUsername, token, profileImage, userId: id } = response.data; + const { createdAt: userCreatedAt, username: loggedInUsername, token: token, profileImage: profileImage, userId: id } = response.data; setTimeStart(Date.now()); setCreatedAt(userCreatedAt); diff --git a/webapp/src/components/Participation.jsx b/webapp/src/components/Participation.jsx index db02fe30..d3043988 100644 --- a/webapp/src/components/Participation.jsx +++ b/webapp/src/components/Participation.jsx @@ -7,15 +7,22 @@ const gatewayUrl = process.env.REACT_APP_API_ENDPOINT || "http://localhost:8000" export const Participation = ({ goTo }) => { const { sessionData } = useContext(SessionContext); // Obtener datos de sesión del contexto const [participationData, setParticipationData] = useState(null); + const [loading, setLoading] = useState(true); useEffect(() => { // Realizar la solicitud al servidor para obtener los datos de participación const fetchData = async () => { try { const response = await axios.get(`${gatewayUrl}/getParticipation/${sessionData.userId}`); - setParticipationData(response.data); + if (response.status === 204) { + setLoading(false); + } else { + setParticipationData(response.data); + setLoading(false); + } } catch (error) { console.error('Error al obtener los datos de participación:', error); + setLoading(false); } }; @@ -28,15 +35,19 @@ export const Participation = ({ goTo }) => {

Participación

- {participationData !== null ? ( -
-

Número de partidas jugadas: {participationData.totalGames}

-

Preguntas acertadas: {participationData.correctAnswers}

-

Preguntas falladas: {participationData.incorrectAnswers}

-

Tiempo total jugando: {participationData.totalTime} segundos

-
+ {loading ? ( +

{participationData ? 'Cargando datos de participación...' : 'No hay datos de participación'}

) : ( -

Cargando datos de participación...

+ participationData !== null ? ( +
+

Número de partidas jugadas: {participationData.totalGames}

+

Preguntas acertadas: {participationData.correctAnswers}

+

Preguntas falladas: {participationData.incorrectAnswers}

+

Tiempo total jugando: {participationData.totalTime} segundos

+
+ ) : ( +

No hay datos de participación

+ ) )}