From 4ecd15918468add7a92fca1e7c97e29bf5540e7b Mon Sep 17 00:00:00 2001 From: adrian Date: Wed, 3 Apr 2024 02:04:31 +0200 Subject: [PATCH 1/6] modified userSchema --- users/userservice/user-model.js | 114 ++++++++++++++++++++++++++++++-- 1 file changed, 108 insertions(+), 6 deletions(-) diff --git a/users/userservice/user-model.js b/users/userservice/user-model.js index 5654d84..611e085 100644 --- a/users/userservice/user-model.js +++ b/users/userservice/user-model.js @@ -18,12 +18,114 @@ const userSchema = new mongoose.Schema({ type: Date, default: Date.now, }, - points: { - type: Number, - default: function() { - // Generate a random integer between 0 and 100 - return Math.floor(Math.random() * 101); - } + ranking: { + total_points: { + type: Number, + default: 0, + }, + total_questions: { + type: Number, + default: 0, + }, + total_correct: { + type: Number, + default: 0, + }, + total_wrong: { + type: Number, + default: 0, + }, + + score_flags: { + points_flags: { + type: Number, + default: 0, + }, + questions_flags: { + type: Number, + default: 0, + }, + correct_flags: { + type: Number, + default: 0, + }, + wrong_flags: { + type: Number, + default: 0, + }, + }, + score_cities: { + points_cities: { + type: Number, + default: 0, + }, + questions_cities: { + type: Number, + default: 0, + }, + correct_cities: { + type: Number, + default: 0, + }, + wrong_cities: { + type: Number, + default: 0, + }, + }, + score_monuments: { + points_monuments: { + type: Number, + default: 0, + }, + questions_monuments: { + type: Number, + default: 0, + }, + correct_monuments: { + type: Number, + default: 0, + }, + wrong_monuments: { + type: Number, + default: 0, + }, + }, + score_tourist: { + points_tourist: { + type: Number, + default: 0, + }, + questions_tourist: { + type: Number, + default: 0, + }, + correct_tourist: { + type: Number, + default: 0, + }, + wrong_tourist: { + type: Number, + default: 0, + }, + }, + score_foods: { + points_foods: { + type: Number, + default: 0, + }, + questions_foods: { + type: Number, + default: 0, + }, + correct_foods: { + type: Number, + default: 0, + }, + wrong_foods: { + type: Number, + default: 0, + }, + }, } }); From 6db3610465ba38e14f7f5a8a4dc9beafbb1296b4 Mon Sep 17 00:00:00 2001 From: adrian Date: Wed, 3 Apr 2024 02:43:48 +0200 Subject: [PATCH 2/6] modified "/rankings" endpoint returned data --- users/userservice/user-service.js | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/users/userservice/user-service.js b/users/userservice/user-service.js index c85da76..e078dcd 100644 --- a/users/userservice/user-service.js +++ b/users/userservice/user-service.js @@ -43,10 +43,22 @@ app.get('/rankings', async (req, res) => { const loggedUser = await User.findById(userId) const userRanking = getRankingFor(loggedUser) */ const usersRanking = (await User.find().sort({points: -1})).map( (user, index) => { - return { - ranking: index+1, - points: user.points, - user: user.username } + return { + // User global data + user: user.username, + ranking: index+1, + points: user.ranking.total_points, + questions: user.ranking.total_questions, + correct: user.ranking.total_correct, + wrong: user.ranking.total_wrong, + + // User cathegories data + flags: user.ranking.score_flags, + cities: user.ranking.score_cities, + foods: user.ranking.score_foods, + monuments: user.ranking.score_monuments, + tourist: user.ranking.score_tourist, + } }) //res.json(userRanking, usersRanking) From 9f4f997536b6e5a45d0345221fad23cd6a843679 Mon Sep 17 00:00:00 2001 From: adrian Date: Thu, 4 Apr 2024 19:13:30 +0200 Subject: [PATCH 3/6] added a new rankings layout --- users/userservice/user-service.js | 4 +- webapp/src/App.jsx | 4 +- webapp/src/components/Rankings.jsx | 2 +- .../src/components/ranking/RankingLayout.jsx | 62 +++++++++++++++++++ .../src/components/ranking/RankingTable.jsx | 12 ++++ 5 files changed, 80 insertions(+), 4 deletions(-) create mode 100644 webapp/src/components/ranking/RankingLayout.jsx create mode 100644 webapp/src/components/ranking/RankingTable.jsx diff --git a/users/userservice/user-service.js b/users/userservice/user-service.js index e078dcd..0b3bd6a 100644 --- a/users/userservice/user-service.js +++ b/users/userservice/user-service.js @@ -42,7 +42,9 @@ app.get('/rankings', async (req, res) => { const userId = decoded.userId const loggedUser = await User.findById(userId) const userRanking = getRankingFor(loggedUser) */ - const usersRanking = (await User.find().sort({points: -1})).map( (user, index) => { + const usersRanking = (await User.find() + .sort({"ranking.total_points": -1})) // TODO: fix total_points property is not found + .map( (user, index) => { return { // User global data user: user.username, diff --git a/webapp/src/App.jsx b/webapp/src/App.jsx index d967959..80e81ba 100644 --- a/webapp/src/App.jsx +++ b/webapp/src/App.jsx @@ -3,7 +3,7 @@ import {BrowserRouter, Routes, Route} from 'react-router-dom' import AddUser from './components/AddUser'; import Navbar from './components/Navbar'; import Login from './components/Login'; -import Rankings from './components/Rankings'; +import RankingsLayout from './components/ranking/RankingLayout'; import Game from './components/Game'; import MainPage from './components/MainPage'; @@ -21,7 +21,7 @@ function App() { }/> } /> } /> - } /> + } /> } /> diff --git a/webapp/src/components/Rankings.jsx b/webapp/src/components/Rankings.jsx index 9cdc79d..84d88c4 100644 --- a/webapp/src/components/Rankings.jsx +++ b/webapp/src/components/Rankings.jsx @@ -15,7 +15,7 @@ const Rankings = () => { console.error('Error fetching data:', error); } }; - + fetchData(); }, []); diff --git a/webapp/src/components/ranking/RankingLayout.jsx b/webapp/src/components/ranking/RankingLayout.jsx new file mode 100644 index 0000000..5469b1d --- /dev/null +++ b/webapp/src/components/ranking/RankingLayout.jsx @@ -0,0 +1,62 @@ +import React, { useState, useEffect } from "react"; +import RankingsTable from "./RankingTable"; + +const apiEndpoint = process.env.REACT_APP_API_ENDPOINT ||'http://localhost:8000'; + +const RankingsLayout = () => { + const [filter, setFilter] = useState('global'); // default ranking = global + + const handleFilterClick = (filter) => { + setFilter(filter); + } + + return ( +
+ + +
+
+

{filter}

+
+
+ +
+
+
+ ) +} + +export default RankingsLayout; \ No newline at end of file diff --git a/webapp/src/components/ranking/RankingTable.jsx b/webapp/src/components/ranking/RankingTable.jsx new file mode 100644 index 0000000..1889599 --- /dev/null +++ b/webapp/src/components/ranking/RankingTable.jsx @@ -0,0 +1,12 @@ +import React from "react"; +import axios from "axios"; + +const RankingsTable = ({ filter }) => { + return ( +
+

{filter} table

+
+ ) +} + +export default RankingsTable; \ No newline at end of file From c7afae76e1b88e6d27220316eabdde266e542e3d Mon Sep 17 00:00:00 2001 From: adrian Date: Fri, 5 Apr 2024 02:46:27 +0200 Subject: [PATCH 4/6] new Ranking page and model finished --- gatewayservice/gateway-service.js | 4 +- users/userservice/package-lock.json | 12 +++- users/userservice/package.json | 3 +- users/userservice/user-model.js | 72 ++++++++----------- users/userservice/user-service.js | 34 +++++---- .../src/components/ranking/RankingLayout.jsx | 34 ++++----- .../src/components/ranking/RankingTable.jsx | 54 +++++++++++++- 7 files changed, 126 insertions(+), 87 deletions(-) diff --git a/gatewayservice/gateway-service.js b/gatewayservice/gateway-service.js index 41540bf..17d7417 100644 --- a/gatewayservice/gateway-service.js +++ b/gatewayservice/gateway-service.js @@ -110,10 +110,10 @@ app.post('/imgs/answer', async (req, res) => { }); -app.get('/rankings', async (req, res) => { +app.get('/rankings/:filter', async (req, res) => { try { // Forward the request to the user service - const userResponse = await axios.get(userServiceUrl+'/rankings', req.body); + const userResponse = await axios.get(userServiceUrl+'/rankings/' + req.params.filter, req.body); res.json(userResponse.data); } catch (error) { res.status(error.response.status).json({ error: error.response.data.error }); diff --git a/users/userservice/package-lock.json b/users/userservice/package-lock.json index f21b26c..56afbed 100644 --- a/users/userservice/package-lock.json +++ b/users/userservice/package-lock.json @@ -12,7 +12,8 @@ "bcrypt": "^5.1.1", "body-parser": "^1.20.2", "express": "^4.18.2", - "mongoose": "^8.0.4" + "mongoose": "^8.0.4", + "ramda": "^0.29.1" }, "devDependencies": { "jest": "^29.7.0", @@ -4524,6 +4525,15 @@ "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==", "dev": true }, + "node_modules/ramda": { + "version": "0.29.1", + "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.29.1.tgz", + "integrity": "sha512-OfxIeWzd4xdUNxlWhgFazxsA/nl3mS4/jGZI5n00uWOoSSFRhC1b6gl6xvmzUamgmqELraWp0J/qqVlXYPDPyA==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/ramda" + } + }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", diff --git a/users/userservice/package.json b/users/userservice/package.json index 3da52b0..2113d2f 100644 --- a/users/userservice/package.json +++ b/users/userservice/package.json @@ -21,7 +21,8 @@ "bcrypt": "^5.1.1", "body-parser": "^1.20.2", "express": "^4.18.2", - "mongoose": "^8.0.4" + "mongoose": "^8.0.4", + "ramda": "^0.29.1" }, "devDependencies": { "jest": "^29.7.0", diff --git a/users/userservice/user-model.js b/users/userservice/user-model.js index 611e085..f7334d6 100644 --- a/users/userservice/user-model.js +++ b/users/userservice/user-model.js @@ -18,110 +18,98 @@ const userSchema = new mongoose.Schema({ type: Date, default: Date.now, }, - ranking: { - total_points: { - type: Number, - default: 0, - }, - total_questions: { - type: Number, - default: 0, - }, - total_correct: { - type: Number, - default: 0, - }, - total_wrong: { - type: Number, - default: 0, - }, - score_flags: { - points_flags: { + ranking: { + global: { + points: { type: Number, default: 0, }, - questions_flags: { + questions: { type: Number, default: 0, }, - correct_flags: { + correct: { type: Number, default: 0, }, - wrong_flags: { + wrong: { type: Number, default: 0, }, }, - score_cities: { - points_cities: { + + flags: { + points: { type: Number, default: 0, }, - questions_cities: { + questions: { type: Number, default: 0, }, - correct_cities: { + correct: { type: Number, default: 0, }, - wrong_cities: { + wrong: { type: Number, default: 0, }, }, - score_monuments: { - points_monuments: { + + cities: { + points: { type: Number, default: 0, }, - questions_monuments: { + questions: { type: Number, default: 0, }, - correct_monuments: { + correct: { type: Number, default: 0, }, - wrong_monuments: { + wrong: { type: Number, default: 0, }, }, - score_tourist: { - points_tourist: { + + monuments: { + points: { type: Number, default: 0, }, - questions_tourist: { + questions: { type: Number, default: 0, }, - correct_tourist: { + correct: { type: Number, default: 0, }, - wrong_tourist: { + wrong: { type: Number, default: 0, }, }, - score_foods: { - points_foods: { + + food: { + points: { type: Number, default: 0, }, - questions_foods: { + questions: { type: Number, default: 0, }, - correct_foods: { + correct: { type: Number, default: 0, }, - wrong_foods: { + wrong: { type: Number, default: 0, }, diff --git a/users/userservice/user-service.js b/users/userservice/user-service.js index 0b3bd6a..8154980 100644 --- a/users/userservice/user-service.js +++ b/users/userservice/user-service.js @@ -3,6 +3,7 @@ const express = require('express'); const mongoose = require('mongoose'); const bcrypt = require('bcrypt'); const bodyParser = require('body-parser'); +const R = require('ramda'); const User = require('./user-model') @@ -35,36 +36,33 @@ async function getRankingFor(loggedUser) { return { ranking: ranking, points: loggedUser.points, user: loggedUser.username } } -app.get('/rankings', async (req, res) => { +app.get('/rankings/:filter', async (req, res) => { try { /* const { token } = req.cookies const decoded = jwt.verify(token, 'your-secret-key') const userId = decoded.userId const loggedUser = await User.findById(userId) const userRanking = getRankingFor(loggedUser) */ - const usersRanking = (await User.find() - .sort({"ranking.total_points": -1})) // TODO: fix total_points property is not found - .map( (user, index) => { + + const category = req.params.filter; + console.log(category); + const usersRanking = (await User.find()); + const ascendingUsers = R.sortBy(R.prop("ranking." + category + ".points"), usersRanking); + const sortedUsers = R.reverse(ascendingUsers); + const sortedRanking = sortedUsers.map( (user, index) => { return { // User global data - user: user.username, - ranking: index+1, - points: user.ranking.total_points, - questions: user.ranking.total_questions, - correct: user.ranking.total_correct, - wrong: user.ranking.total_wrong, - - // User cathegories data - flags: user.ranking.score_flags, - cities: user.ranking.score_cities, - foods: user.ranking.score_foods, - monuments: user.ranking.score_monuments, - tourist: user.ranking.score_tourist, + name: user.username, + position: index+1, + points: user.ranking[category].points, + questions: user.ranking[category].questions, + correct: user.ranking[category].correct, + wrong: user.ranking[category].wrong } }) //res.json(userRanking, usersRanking) - res.json(usersRanking) + res.json(sortedRanking) } catch (error) { res.status(400).json({ error: error.message }); } diff --git a/webapp/src/components/ranking/RankingLayout.jsx b/webapp/src/components/ranking/RankingLayout.jsx index 5469b1d..63377d3 100644 --- a/webapp/src/components/ranking/RankingLayout.jsx +++ b/webapp/src/components/ranking/RankingLayout.jsx @@ -1,8 +1,6 @@ import React, { useState, useEffect } from "react"; import RankingsTable from "./RankingTable"; -const apiEndpoint = process.env.REACT_APP_API_ENDPOINT ||'http://localhost:8000'; - const RankingsLayout = () => { const [filter, setFilter] = useState('global'); // default ranking = global @@ -11,36 +9,32 @@ const RankingsLayout = () => { } return ( -
-