add: merged front with back

This commit is contained in:
Lukian LEIZOUR 2025-04-15 22:52:15 +02:00
parent 1832ed12ec
commit 48f50a1daa
42 changed files with 5458 additions and 20 deletions

3
back/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
/node_modules
.env
package-lock.json

9
back/api/hello.js Normal file
View file

@ -0,0 +1,9 @@
const express = require('express');
const router = express.Router();
router.get('/', (req, res) => {
res.send('Hello World!');
});
module.exports = router;

View file

@ -0,0 +1,76 @@
const express = require('express');
const multer = require('multer')
const upload = multer()
const { getConnection, getGame, addGame } = require("../../../libs/mysql.js")
const router = express.Router();
router.post('/', upload.single('file'), async (req, res) => {
const file = req.file.buffer.toString().replace(/"/g, "");
const lines = file.split("\n");
const fields = lines[0].split(";");
const assoc = {
'ID': 'id',
'Titre': 'title',
'Sous-titre': 'subtitle',
'Édition': 'edition',
'Type': 'type',
'Joueur(s)': 'players',
'Durée': 'duration',
'Age(s)': 'ages',
'Langues': 'language',
'Univers': 'universe',
'Gamme(s)': 'ranges',
'Catégorie(s)': "categories",
'Thème(s)': 'themes',
'Mécanisme(s)': 'mecanisms',
'Éditeur(s)': 'editor',
'Auteur(s)': 'authors',
'Illustrateur(s)': 'illustrators'
}
const positions = {}
for (i = 0; i < fields.length; i++) {
if (assoc[fields[i]]) {
positions[assoc[fields[i]]] = i;
}
}
const games = []
for (i = 1; i < lines.length; i++) {
games.push(lines[i].split(";"))
}
const connection = await getConnection();
games.forEach(async game => {
const game_db = await getGame(connection, game[positions['id']]);
if (!game_db[0]) {
addGame(connection,
game[positions['id']],
game[positions['title']],
game[positions['subtitle']] ? game[positions['subtitle']] : "NULL",
game[positions['edition']] ? game[positions['edition']] : "NULL",
game[positions['type']] ? game[positions['type']] : "NULL",
game[positions['players']] ? game[positions['players']] : "NULL",
game[positions['duration']] ? game[positions['duration']] : "NULL",
game[positions['ages']] ? game[positions['ages']] : "NULL",
game[positions['language']] ? game[positions['language']] : "NULL",
game[positions['universe']] ? game[positions['universe']] : "NULL",
game[positions['ranges']] ? game[positions['ranges']] : "NULL",
game[positions['categories']] ? game[positions['categories']] : "NULL",
game[positions['themes']] ? game[positions['themes']] : "NULL",
game[positions['mecanisms']] ? game[positions['mecanisms']] : "NULL",
game[positions['editor']],
game[positions['authors']],
game[positions['illustrators']])
}
})
//connection.end();
res.status(200).send({message: "success"});
});
module.exports = router;

View file

@ -0,0 +1,35 @@
const express = require('express');
const jwt = require('jsonwebtoken');
const { getConnection, getUnverifiedUsers } = require("../../../libs/mysql.js")
const router = express.Router();
router.post('/', async (req, res) => {
const {token} = req.body;
if (!token) {
return res.status(400).send({error: "invalid token"});
}
try {
const user = jwt.verify(token, process.env.JWTSecret);
if (user.expiration < Date.now()) {
return res.status(400).send({error: "token expired"});
}
if (!user.user.admin) {
return res.status(400).send({error: "unauthorized"});
}
} catch {
return res.status(400).send({error: "invalid token"});
}
const connection = await getConnection();
const users = await getUnverifiedUsers(connection);
connection.end();
res.status(200).send(users);
});
module.exports = router;

View file

@ -0,0 +1,45 @@
const express = require('express');
const jwt = require('jsonwebtoken');
const { getConnection, setVerified, getUser } = require("../../../libs/mysql.js")
const router = express.Router();
router.post('/', async (req, res) => {
const {token, username} = req.body;
if (!token) {
return res.status(400).send({error: "invalid token"});
}
try {
const user = jwt.verify(token, process.env.JWTSecret);
if (user.expiration < Date.now()) {
return res.status(400).send({error: "token expired"});
}
if (!user.user.admin) {
return res.status(400).send({error: "unauthorized"});
}
} catch {
return res.status(400).send({error: "invalid token"});
}
const connection = await getConnection();
const user = await getUser(connection, username);
if (!user[0]) {
return res.status(400).send({error: "invalid userid"});
}
if (user[0].verified) {
return res.status(400).send({error: "user already verified"});
}
await setVerified(connection, username);
connection.end()
res.status(200).send({message: "user verified"});
});
module.exports = router;

36
back/api/v1/auth/login.js Normal file
View file

@ -0,0 +1,36 @@
const express = require('express');
const jwt = require('jsonwebtoken');
const sha256 = require("sha256");
const { getConnection, getUser } = require("../../../libs/mysql");
const router = express.Router();
router.post('/', async (req, res) => {
const {username, password} = req.body;
if (!username || !password) {
return res.status(400).send({error: "missing parameters"});
}
const connection = await getConnection();
const user = await getUser(connection, username);
if (!user[0]) {
return res.status(400).send({error: "wrong login informations"});
}
if (!(sha256(password) == user[0].password)) {
return res.status(400).send({error: "wrong login informations"});
}
if (!user[0].verified) {
return res.status(400).send({error: "you need to be verified to login"})
}
const expiration = new Date().getTime() + 1000 * 60 * 60 * 24 * 7;
res.status(200).send({message: "connection successful", token: jwt.sign({user: {id: user[0].id, username: user[0].username, name: user[0].name, lastname: user[0].lastname, admin: user[0].admin}, expiration: expiration}, process.env.JWTSecret)});
});
module.exports = router;

View file

@ -0,0 +1,28 @@
const express = require('express');
const sha256 = require("sha256");
const { getConnection, getUser, addUser } = require("../../../libs/mysql");
const router = express.Router();
router.post('/', async (req, res) => {
const {username, name, lastname, password} = req.body;
if (!username || !name || !lastname || !password) {
return res.status(400).send({error: "invalid request"});
}
const connection = await getConnection();
const user = await getUser(connection, username);
if (user[0]) {
return res.status(400).send({error: "user already exist"});
}
await addUser(connection, username, name, lastname, sha256(password));
connection.end();
res.status(200).send({message: "success"});
});
module.exports = router;

View file

@ -0,0 +1,49 @@
const express = require('express');
const jwt = require('jsonwebtoken');
const { getConnection, addHelper, getGame, getHelpers } = require("../../../libs/mysql.js")
const router = express.Router();
router.post('/', async (req, res) => {
const {token, gameid} = req.body;
if (!token) {
return res.status(400).send({error: "invalid token"});
}
if (!gameid) {
return res.status(400).send({error: "invalid gameid"});
}
try {
const user = jwt.verify(token, process.env.JWTSecret);
if (user.expiration < Date.now()) {
return res.status(400).send({error: "token expired"});
}
const connection = await getConnection();
const game = await getGame(connection, gameid);
if (!game[0]) {
return res.status(400).send({error: "this game doesn't exist"});
}
const helpers = await getHelpers(connection, gameid);
if (JSON.stringify(helpers).includes(user.user.id)) {
return res.status(400).send({error: "you are already an helper for this game"});
}
await addHelper(connection, gameid, user.user.id);
connection.end();
} catch (error) {
console.log(error);
return res.status(400).send({error: "invalid token"});
}
res.status(200).send({message: "success"});
});
module.exports = router;

View file

@ -0,0 +1,40 @@
const express = require('express');
const jwt = require('jsonwebtoken');
const { getConnection, getGame } = require("../../../libs/mysql.js")
const router = express.Router();
router.post('/', async (req, res) => {
const {token, gameid} = req.body;
if (!token) {
return res.status(400).send({error: "invalid token"});
}
if (!gameid) {
return res.status(400).send({error: "invalid gameid"});
}
try {
const user = jwt.verify(token, process.env.JWTSecret);
if (user.expiration < Date.now()) {
return res.status(400).send({error: "token expired"});
}
} catch {
return res.status(400).send({error: "invalid token"});
}
const connection = await getConnection();
const game = await getGame(connection, gameid)
connection.end();
if (!game[0]) {
return res.status(400).send({error: "this game doesn't exist in the data base"})
};
res.status(200).send(game[0]);
});
module.exports = router;

View file

@ -0,0 +1,36 @@
const express = require('express');
const jwt = require('jsonwebtoken');
const { getConnection, getHelpers } = require("../../../libs/mysql.js")
const router = express.Router();
router.post('/', async (req, res) => {
const {token, gameid} = req.body;
if (!token) {
return res.status(400).send({error: "invalid token"});
}
if (!gameid) {
return res.status(400).send({error: "invalid gameid"});
}
try {
const user = jwt.verify(token, process.env.JWTSecret);
if (user.expiration < Date.now()) {
return res.status(400).send({error: "token expired"});
}
} catch {
return res.status(400).send({error: "invalid token"});
}
const connection = await getConnection();
const helpers = await getHelpers(connection, gameid)
connection.end();
res.status(200).send(helpers);
});
module.exports = router;

View file

@ -0,0 +1,31 @@
const express = require('express');
const jwt = require('jsonwebtoken');
const { getConnection, getGames } = require("../../../libs/mysql.js")
const router = express.Router();
router.post('/', async (req, res) => {
const {token} = req.body;
if (!token) {
return res.status(400).send({error: "invalid token"});
}
try {
const user = jwt.verify(token, process.env.JWTSecret);
if (user.expiration < Date.now()) {
return res.status(400).send({error: "token expired"});
}
} catch {
return res.status(400).send({error: "invalid token"});
}
const connection = await getConnection();
const games = await getGames(connection);
connection.end();
res.status(200).send(games);
});
module.exports = router;

View file

@ -0,0 +1,36 @@
const express = require('express');
const jwt = require('jsonwebtoken');
const { getConnection, removeHelper, getHelpers } = require("../../../libs/mysql.js")
const router = express.Router();
router.post('/', async (req, res) => {
const {token, gameid} = req.body;
if (!token) {
return res.status(400).send({error: "invalid token"});
}
if (!gameid) {
return res.status(400).send({error: "invalid gameid"});
}
try {
const user = jwt.verify(token, process.env.JWTSecret);
if (user.expiration < Date.now()) {
return res.status(400).send({error: "token expired"});
}
const connection = await getConnection();
await removeHelper(connection, gameid, user.user.id)
connection.end();
} catch {
return res.status(400).send({error: "invalid token"});
}
res.status(200).send({message: "success"});
});
module.exports = router;

32
back/index.js Normal file
View file

@ -0,0 +1,32 @@
const express = require("express");
const fs = require("fs");
const path = require("path");
const cookieParser = require("cookie-parser");
const cors = require("cors");
require("dotenv").config();
const app = express();
app.use(express.json());
app.use(cookieParser());
app.use(cors());
function loadRoutes(folderName) {
const routesPath = path.join(__dirname, folderName);
const files = fs.readdirSync(routesPath);
files.forEach((file) => {
if (fs.lstatSync(path.join(routesPath, file)).isDirectory()) {
loadRoutes(`${folderName}/${file}`);
return;
}
const filePath = path.join(routesPath, file);
const route = require(filePath);
app.use(`/${folderName}/${file.split(".")[0]}`, route);
});
}
loadRoutes("api");
app.listen(3000, () => {
console.log(`Server listening on http://localhost:3000/`);
});

181
back/libs/mysql.js Normal file
View file

@ -0,0 +1,181 @@
const mysql = require("mysql");
function getConnection() {
return mysql.createConnection({
host: process.env.MysqlHost,
user: process.env.MysqlUser,
password: process.env.MysqlPassword,
database: process.env.MysqlDb,
});
}
// +-----------------------------------+
// | GAMES |
// +-----------------------------------+
function getGames(connection) {
return new Promise((resolve, reject) => {
connection.query(
`SELECT id, title, subtitle, type, players, duration, ages FROM games`,
(error, result) => {
if (error) {
reject(new Error(error));
}
resolve(result);
}
);
});
}
function getGame(connection, gameid) {
return new Promise((resolve, reject) => {
connection.query(
`SELECT * FROM games WHERE id = ${gameid}`,
(error, result) => {
if (error) {
reject(new Error(error));
}
resolve(result);
}
)
})
}
function addGame(connection, id, title, subtitle, edition, type, players, duration, ages, languages, universe, ranges, categories, themes, mecanisms, editor, authors, illustrators) {
console.log(`INSERT INTO games (id, title, subtitle, edition, type, players, duration, ages, languages, universe, ranges, categories, themes, mecanisms, editor, authors, illustrators) VALUES (${id}, "${title}", "${subtitle}", ${edition}, "${type}", "${players}", "${duration}", "${ages}", "${languages}", "${universe}", "${ranges}", "${categories}", "${themes}", "${mecanisms}", "${editor}", "${authors}", "${illustrators}")`)
return new Promise((resolve, reject) => {
connection.query(
`INSERT INTO games (id, title, subtitle, edition, type, players, duration, ages, languages, universe, ranges, categories, themes, mecanisms, editor, authors, illustrators) VALUES (${id}, "${title}", "${subtitle}", ${edition}, "${type}", "${players}", "${duration}", "${ages}", "${languages}", "${universe}", "${ranges}", "${categories}", "${themes}", "${mecanisms}", "${editor}", "${authors}", "${illustrators}")`,
(error, result) => {
if (error) {
reject(new Error(error));
}
resolve(result);
}
)
})
}
// +-----------------------------------+
// | HELPERS |
// +-----------------------------------+
function addHelper(connection, game_id, user_id) {
return new Promise((resolve, reject) => {
connection.query(
`INSERT INTO helpers (game_id, user_id) VALUES (${game_id}, ${user_id})`,
(error, result) => {
if (error) {
reject(new Error(error));
}
resolve(result);
}
)
})
}
function removeHelper(connection, game_id, user_id) {
return new Promise((resolve, reject) => {
connection.query(
`DELETE FROM helpers WHERE game_id = ${game_id} and user_id = ${user_id}`,
(error, result) => {
if (error) {
reject(new Error(error));
}
resolve(result);
}
);
});
}
function getHelpers(connection, game_id) {
return new Promise((resolve, reject) => {
connection.query(
`SELECT name, helpers.user_id FROM helpers JOIN users ON helpers.user_id = users.id WHERE game_id = ${game_id}`,
(error, result) => {
if (error) {
reject(new Error(error));
}
resolve(result);
}
)
})
}
// +-----------------------------------+
// | AUTH |
// +-----------------------------------+
function getUser(connection, username) {
return new Promise((resolve, reject) => {
connection.query(
`SELECT * FROM users WHERE username = "${username}"`,
(error, result) => {
if (error) {
reject(new Error(error));
}
resolve(result);
})
})
}
function addUser(connection, username, name, lastname, password) {
return new Promise((resolve, reject) => {
connection.query(
`INSERT INTO users(username, name, lastname, password) VALUES("${username}", "${name}", "${lastname}", "${password}")`,
(error, result) => {
if (error) {
reject(new Error(error));
}
resolve(result);
})
})
}
// +-----------------------------------+
// | ADMIN |
// +-----------------------------------+
function getUnverifiedUsers(connection) {
return new Promise((resolve, reject) => {
connection.query(
`SELECT * FROM users WHERE verified = 0`,
(error, result) => {
if (error) {
reject(new Error(error));
}
resolve(result);
})
})
}
function setVerified(connection, username) {
return new Promise((resolve, reject) => {
connection.query(
`UPDATE users SET verified = 1 WHERE username = "${username}"`,
(error, result) => {
if (error) {
reject(new Error(error));
}
resolve(result);
})
})
}
module.exports = {
getConnection,
getGames,
getGame,
addGame,
addHelper,
removeHelper,
getHelpers,
getUser,
addUser,
getUnverifiedUsers,
setVerified,
};

27
back/package.json Normal file
View file

@ -0,0 +1,27 @@
{
"name": "api-template",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "nodemon index.js",
"start": "node index.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"axios": "^1.6.5",
"cookie-parser": "^1.4.6",
"cors": "^2.8.5",
"dotenv": "^16.4.5",
"express": "^4.18.2",
"fs": "^0.0.1-security",
"https": "^1.0.0",
"jsonwebtoken": "^9.0.2",
"multer": "^1.4.5-lts.1",
"mysql": "^2.18.1",
"nodemon": "^3.1.4",
"sha256": "^0.2.0"
}
}