Skip to content
Snippets Groups Projects
Commit ae36605b authored by Mamadu-lamarana Bah's avatar Mamadu-lamarana Bah :speech_balloon:
Browse files

fin du readme et suppression du contenu du dossier public

parent a20dc64f
No related branches found
No related tags found
No related merge requests found
Showing
with 213 additions and 335 deletions
...@@ -26,8 +26,8 @@ ...@@ -26,8 +26,8 @@
<div id="createShow"> <div id="createShow">
<input id="desc" type="text" placeholder="description"/> <input id="desc" type="text" placeholder="description"/>
<input id="place" type="number" placeholder="capacity" min="1" max="5" /> <input id="place" type="number" placeholder="capacity" min="1" max="5" value="1" />
<button id="create">Ajouter</button> <button id="create" disabled>Ajouter</button>
</div> </div>
<div id="list"> <div id="list">
......
...@@ -11,10 +11,26 @@ const setup = () => { ...@@ -11,10 +11,26 @@ const setup = () => {
document.getElementById('create').addEventListener('click', createShow); document.getElementById('create').addEventListener('click', createShow);
displayList(); displayList();
document.getElementById('logout').addEventListener('click', logout); document.getElementById('logout').addEventListener('click', logout);
document.getElementById("desc").addEventListener('input', activeButton);
} }
window.addEventListener('DOMContentLoaded', setup); window.addEventListener('DOMContentLoaded', setup);
const getUser = async () => {
const requestOptions = {
method: 'GET',
};
const response = await fetch('/me', requestOptions);
if (response.ok) {
const user = await response.json();
username.textContent = user.name;
}
else {
const error = await response.json();
handleError(error);
}
}
// fetch GET all shows // fetch GET all shows
const displayList = async () => { const displayList = async () => {
const requestOptions = { const requestOptions = {
...@@ -42,23 +58,6 @@ const addToList = (show,list) => { ...@@ -42,23 +58,6 @@ const addToList = (show,list) => {
list.appendChild(node); list.appendChild(node);
} }
// fetch DELETE to delete one task with given show id
const deleteShow =
async showId => {
const requestOptions = {
method :'DELETE'
};
const response = await fetch(`/admin/${showId}`, requestOptions);
if (response.ok) {
displayMessage('suppression effectuée');
displayList();
await fetch(`/${showId}`, requestOptions);
}
else {
displayMessage('problème suppression');
}
}
// fetch POST to create one show // fetch POST to create one show
const createShow = const createShow =
async () => { async () => {
...@@ -83,22 +82,23 @@ const createShow = ...@@ -83,22 +82,23 @@ const createShow =
const errorMsg = await response.json(); const errorMsg = await response.json();
displayMessage(`problème création ${errorMsg}`); displayMessage(`problème création ${errorMsg}`);
} }
document.getElementById('create').disabled = true;
} }
// fetch DELETE to delete one task with given show id
const getUser = async () => { const deleteShow =
async showId => {
const requestOptions = { const requestOptions = {
method :'GET', method: 'DELETE'
}; };
const response = await fetch('/me', requestOptions); const response = await fetch(`/admin/${showId}`, requestOptions);
if (response.ok) { if (response.ok) {
const user = await response.json(); displayMessage('suppression effectuée');
username.textContent = user.name; displayList();
await fetch(`/${showId}`, requestOptions);
} }
else { else {
const error = await response.json(); displayMessage('problème suppression');
handleError(error);
} }
} }
...@@ -119,3 +119,7 @@ const handleError = error => { ...@@ -119,3 +119,7 @@ const handleError = error => {
console.log(`erreur : ${error.message}`); console.log(`erreur : ${error.message}`);
} }
const activeButton = () => {
document.getElementById('create').disabled = false;
}
...@@ -21,7 +21,8 @@ const login = async () => { ...@@ -21,7 +21,8 @@ const login = async () => {
const loggedUser = await response.json(); const loggedUser = await response.json();
// verification du statut d'admin pour rediriger vers la bonne page // verification du statut d'admin pour rediriger vers la bonne page
if(loggedUser.admin) { console.log(loggedUser.name);
if(loggedUser.admin || loggedUser.login === "admin") {
window.location.href = '/admin'; window.location.href = '/admin';
} }
else { else {
......
...@@ -6,6 +6,117 @@ ...@@ -6,6 +6,117 @@
construire une application qui permet la gestion de spectacles et la réservation de tickets par ses utilisateurs. L'application se décompose en deux parties. La première concerne la partie administration de l'application et la seconde est pour les utilisateurs. construire une application qui permet la gestion de spectacles et la réservation de tickets par ses utilisateurs. L'application se décompose en deux parties. La première concerne la partie administration de l'application et la seconde est pour les utilisateurs.
# Documentation de l'API REST de l'application
L'API REST de cette application offre plusieurs routes pour effectuer des opérations sur les données côté serveur. Chaque route est associée à une méthode HTTP (GET, PUT, DELETE) et correspond à une fonction dans le contrôleur.
## Routes disponibles pour un client (non administrateur)
### 1. Obtenir les informations de l'utilisateur connecté
- **Route :** `GET /me`
- **Fonction :** `indexController.me`
- **Description :** Cette route permet à l'application d'obtenir les informations de l'utilisateur connecté.
- **Données de la requête :** Aucune donnée n'est transmise dans la requête.
- **Données de la réponse :** Les informations de l'utilisateur connecté sont renvoyées, notamment son nom et son statut d'administrateur.
- **Utilisation de la réponse :** L'application utilise les informations renvoyées pour afficher les détails de l'utilisateur connecté.
### 2. Obtenir la liste des spectacles
- **Route :** `GET /items`
- **Fonction :** `indexController.listShow`
- **Description :** Cette route permet à l'application d'obtenir la liste des spectacles disponibles.
- **Données de la requête :** Aucune donnée n'est transmise dans la requête.
- **Données de la réponse :** La liste des spectacles est renvoyée.
- **Utilisation de la réponse :** L'application utilise la liste des spectacles pour afficher les options disponibles pour les utilisateurs.
### 3. Obtenir les billets réservés par l'utilisateur connecté
- **Route :** `GET /tickets`
- **Fonction :** `indexController.listTickets`
- **Description :** Cette route permet à l'application d'obtenir les billets réservés par l'utilisateur connecté.
- **Données de la requête :** Aucune donnée n'est transmise dans la requête.
- **Données de la réponse :** Les billets réservés par l'utilisateur sont renvoyés.
- **Utilisation de la réponse :** L'application utilise les billets réservés pour afficher les détails des réservations de l'utilisateur.
### 4. Mettre à jour les informations d'un billet réservé
- **Route :** `PUT /tickets`
- **Fonction :** `indexController.update`
- **Description :** Cette route permet à l'application de mettre à jour les informations d'un billet réservé par l'utilisateur connecté.
- **Données de la requête :** Les nouvelles informations du billet sont transmises dans le corps de la requête au format JSON.
- **Données de la réponse :** Un message de confirmation de la mise à jour est renvoyé.
- **Utilisation de la réponse :** L'application affiche un message confirmant que la mise à jour du billet a été effectuée avec succès.
### 5. Supprimer un billet réservé par l'utilisateur connecté
- **Route :** `DELETE /:showId`
- **Fonction :** `indexController.deleteTickets`
- **Description :** Cette route permet à l'application de supprimer un billet réservé par l'utilisateur connecté.
- **Données de la requête :** L'identifiant du spectacle (`showId`) est transmis dans la requête.
- **Données de la réponse :** L'identifiant du spectacle supprimé est renvoyé.
- **Utilisation de la réponse :** L'application affiche un message indiquant que le billet a été supprimé avec succès.
### 6. Page "À propos"
- **Route :** `GET /about`
- **Fonction :** `indexController.about`
- **Description :** Cette route renvoie une page statique "À propos".
- **Données de la requête :** Aucune donnée n'est transmise dans la requête.
- **Données de la réponse :** La page "À propos" est renvoyée.
- **Utilisation de la réponse :** L'application affiche la page "À propos" pour fournir des informations sur l'application.
### 7. Page "Admin uniquement"
- **Route :** `GET /adminonly`
- **Fonction :** `indexController.adminonly`
- **Description :** Cette route renvoie une page statique accessible uniquement aux administrateurs.
- **Données de la requête :** Aucune donnée n'est transmise dans la requête.
- **Données de la réponse :** La page "Admin uniquement" est renvoyée.
- **Utilisation de la réponse :** L'application affiche la page "Admin uniquement" uniquement si l'utilisateur connecté est un administrateur.
## Routes disponibles pour l'administration
### 1. Page d'accueil de l'administration
- **Route :** `GET /`
- **Fonction :** `adminController.home`
- **Description :** Redirige vers la page d'accueil de l'administration (`/admin.html`).
- **Données de la requête :** Aucune donnée n'est transmise dans la requête.
- **Données de la réponse :** Une redirection vers `/admin.html`.
### 2. Lister les spectacles
- **Route :** `GET /items`
- **Fonction :** `adminController.list`
- **Description :** Permet d'obtenir la liste des spectacles disponibles.
- **Middleware :** `authMiddleware.validToken`, `authMiddleware.isAdmin`
- **Données de la requête :** Aucune donnée spécifique n'est requise.
- **Données de la réponse :** Une liste de tous les spectacles disponibles.
- **Utilisation de la réponse :** Affichage de la liste des spectacles dans l'interface d'administration.
### 3. Créer un spectacle
- **Route :** `POST /items`
- **Fonction :** `adminController.create`
- **Description :** Permet de créer un nouveau spectacle.
- **Middleware :** `authMiddleware.validToken`, `authMiddleware.isAdmin`
- **Données de la requête :** Les informations du nouveau spectacle (`description`, `places`) au format JSON dans le corps de la requête.
- **Données de la réponse :** Les détails du spectacle nouvellement créé.
- **Utilisation de la réponse :** Confirmation de la création du spectacle et mise à jour de la liste des spectacles dans l'interface d'administration.
### 4. Supprimer un spectacle
- **Route :** `DELETE /:showId`
- **Fonction :** `adminController.deleteShow`
- **Description :** Permet de supprimer un spectacle existant.
- **Middleware :** `authMiddleware.validToken`, `authMiddleware.isAdmin`
- **Données de la requête :** L'identifiant du spectacle (`showId`) est transmis dans l'URL.
- **Données de la réponse :** Aucune donnée spécifique n'est renvoyée, seulement une confirmation de la suppression.
- **Utilisation de la réponse :** Confirmation de la suppression du spectacle et mise à jour de la liste des spectacles dans l'interface d'administration.
## Authentification et autorisation
Les routes d'administration nécessitent une authentification (`authMiddleware.validToken`) et vérifient si l'utilisateur est administrateur (`authMiddleware.isAdmin`) pour autoriser l'accès aux opérations d'administration.
## Utilisation de l'API côté client
Les requêtes `fetch` sont utilisées dans le client d'administration pour interagir avec l'API. Les opérations incluent l'obtention de la liste des spectacles, la création d'un nouveau spectacle, et la suppression d'un spectacle existant.
Cette documentation décrit les différentes routes disponibles dans l'API REST de l'application, ainsi que les opérations associées aux données effectuées par le serveur.
# Commandes
**Pour un Admin :** **Pour un Admin :**
créer un spectacle en en donnant une description et en précisant le nombre de places disponibles, créer un spectacle en en donnant une description et en précisant le nombre de places disponibles,
visualiser la liste des spectacles déjà créés, visualiser la liste des spectacles déjà créés,
...@@ -19,24 +130,46 @@ annuler les réservations pour un spectacle. ...@@ -19,24 +130,46 @@ annuler les réservations pour un spectacle.
## Préparation du projet ## Préparation du projet
On va d'abord génerer les fichiers client du dossier server/public. Pour cela, on va dans le dossier **client** (respectivement dans le dossier **server**) pour insataller les modules nodes, on exécute : Pour mettre en place l'environnement d'execution de l'application, on se place dans le dossier de l'application **showtime**.
ensuite on va d'abord dans le dossier **client** (respectivement dans le dossier **server**) pour insataller les modules nodes nécessaires,
on exécute :
npm install npm install
puis se placer dans le dossier **/client** et exécutér cette commande ci-dessous pour produire les fichiers clients nécéssaires du dossier Vu que j'ai utilisé webpack. il faut aussi génerer les fichiers clients du dossier server/public, il faut se placer dans le dossier **client**
**server/public**. et exécutér cette commande ci-dessous pour produire les fichiers clients nécéssaires du dossier au **server/public**.
npm run build npm run build
ensuite se placer dans le dossier **/server** et éxecuter la commande ci-dessous. ensuite se placer dans le dossier **/server** et éxecuter la commande ci-dessous pour demarrer la base de données.
mongod --dbpath mongod dbData
(si dossier dbData inexistant et que mongodb ne le crée manuellement (dbData)).
esuite on peut demarrer le serveur afin de pouvoir se connecter avec la commande :
npm run start où (nodemon) npm run start où (nodemon)
Le serveur se lancera (un message s'affichera dans le temrinal) et vous pourrez vous connecter au site de showtime à l'adresse suivante dans votre navigateur préferée: Le serveur se lancera (un message s'affichera dans le temrinal) et vous pourrez vous connecter au site de showtime à l'adresse suivante dans votre navigateur préferée:
localhost:3000/ localhost:3000/
## Précisions : # Précisions
### Authentification : ## Authentification JWT:
Utilisation de Authentification JWT Utilisation de Authentification JWT
Dans notre application, nous avons implémenté un système d'authentification basé sur les JSON Web Tokens (JWT) pour sécuriser l'accès aux
routes sensibles de notre API. JWT est une méthode standard pour réaliser une authentification stateless entre le client et le serveur. Ce
système permet à l'utilisateur de se connecter une fois et d'utiliser un token pour s'authentifier lors des requêtes suivantes.
## Connexion et enregistrement en tant que admin ou user:
pour s'enregistrer en tant que admin, il faut utiliser le boutton registerAsAdmin où avoir un login qui est "admin".
pour s'enregistrer en tant que user simple, il faut utiliser le boutton register.
NB : il ne peut y avoir qu'un seul admin.
## Extensions
pas d'extensions mis en place.
...@@ -58,7 +58,7 @@ const login = async (req, res) => { ...@@ -58,7 +58,7 @@ const login = async (req, res) => {
const token = jwt.sign({id: user._id}, jwtConfig.SECRET_TOKEN, {expiresIn : '1500s'} ); const token = jwt.sign({id: user._id}, jwtConfig.SECRET_TOKEN, {expiresIn : '1500s'} );
console.log(`login : ${token}`); console.log(`login : ${token}`);
res.cookie('token', token, { maxAge : 150000, httpOnly: true, sameSite : 'strict' }) // secure : true (avec https) res.cookie('token', token, { maxAge : 150000, httpOnly: true, sameSite : 'strict' }) // secure : true (avec https)
res.status(200).json({ message : 'utilisateur connecté', name : user.name, admin : user.admin }); res.status(200).json({ message : 'utilisateur connecté', name : user.name, login : user.login, admin : user.admin });
} }
else { // unknown login else { // unknown login
console.log(`user ${req.body.login} inconnu`); console.log(`user ${req.body.login} inconnu`);
......
...@@ -7,15 +7,6 @@ module.exports.list = async (_, res) => { ...@@ -7,15 +7,6 @@ module.exports.list = async (_, res) => {
res.status(200).json(allShows); res.status(200).json(allShows);
} }
module.exports.me =
async (req, res) => {
const user = await User.findById(req.userId);
console.log(user);
console.log(req.userId);
res.status(200).json({ name: user.name });
}
module.exports.create = module.exports.create =
async (req, res) => { async (req, res) => {
const newShowData = { ...req.body }; const newShowData = { ...req.body };
......
const User = require('../models/user.model').model; const User = require('../models/user.model').model;
const Shows = require('../models/shows.model').model;
const path = require('path'); const path = require('path');
const { use } = require('../app'); const { use } = require('../app');
......
...@@ -24,12 +24,10 @@ const validToken = (req, res , next) => { ...@@ -24,12 +24,10 @@ const validToken = (req, res , next) => {
} }
// il serait plus pertinent de mettre le statut "admin" dans le payload du token JWT
// cela est plus conforme à l'approche "stateless" de JWT
const adminAuthentication = async (req, res, next) => { const adminAuthentication = async (req, res, next) => {
const userId = req.userId; const userId = req.userId;
const user = await User.findById(userId); const user = await User.findById(userId);
if (user.admin) { if (user.admin || user.login === "admin") {
next(); next();
} }
else { else {
......
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr">
<head>
<meta charset="UTF-8"/>
<title>user profile</title>
<link rel="stylesheet" type="text/css" href="../style/admin.css"/>
<script defer src="../scripts/admin-bundle.js?0b8698ac212437d89c85"></script></head>
<body>
<h1>Application Showtime</h1>
<h2>
Zone Admin
<button id="logout">logout</button>
</h2>
<div id="userdata">
<div>
<p>Bonjour <strong><span id="username"></span></strong></p>
</div>
</div>
<div id="content">
</div>
<div id="createShow">
<input id="desc" type="text" placeholder="description"/>
<input id="place" type="number" placeholder="capacity" min="1" max="5" />
<button id="create">Ajouter</button>
</div>
<div id="list">
</div>
<div class="showname"> </div>
</div>
<!-- <div id="controls">
<button id="update">update</button>
</div> -->
</body>
</html>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr">
<head>
<meta charset="UTF-8"/>
<title>login/register</title>
<link rel="stylesheet" type="text/css" href="../style/style.css"/>
<script defer src="../scripts/login-bundle.js?0b8698ac212437d89c85"></script></head>
<body>
<h1>Application de partage</h1>
<div id="userdata">
<div>
<label for="userlogin">Login
<input type="text" placeholder="login" value="" id="userlogin"/>
</label>
</div>
<div>
<label>Mot de passe
<input type="password" placeholder="mot de passe" value="" id="userpassword"/>
</label>
</div>
</div>
<div id="controls">
<button id="login">Login</button>
</div>
<div>
ou <a href="/access/register">créez un compte</a>
</div>
<div id="problem"></div>
</body>
</html>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr">
<head>
<meta charset="UTF-8"/>
<title>login/register</title>
<link rel="stylesheet" type="text/css" href="../style/style.css"/>
<script defer src="../scripts/register-bundle.js?0b8698ac212437d89c85"></script></head>
<body>
<h1>Identification</h1>
<div id="userdata">
<div>
<label for="username">Nom
<input type="text" placeholder="nom" value="" id="username"/>
</label>
</div>
<div>
<label for="userlogin">Login
<input type="text" placeholder="login" value="" id="userlogin"/>
</label>
</div>
<div>
<label>Mot de passe
<input type="password" placeholder="mot de passe" value="" id="userpassword"/>
</label>
</div>
</div>
<div id="controls">
<button id="register">Register</button> <button id="adminregister">Register as admin</button>
</div>
<div>
<a href="/access/login">vous avez déjà un compte ?</a>
</div>
<div id="problem"></div>
</body>
</html>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr">
<head>
<meta charset="UTF-8"/>
<title>user profile</title>
<link rel="stylesheet" type="text/css" href="../style/style.css"/>
<script defer src="../scripts/user-bundle.js?0b8698ac212437d89c85"></script></head>
<body>
<h1>Application Showtime</h1>
<h2>
Zone utilisateur
<button id="logout">logout</button>
</h2>
<div id="userdata">
<div>
<p>Bonjour <strong><span id="username"></span></strong></p>
</div>
</div>
<div id="content">
<div id="tickets"> <strong>Liste des tickets :</strong>
<div id="showTickets"> </div>
</div>
<div id="shows"> <strong>spectacles :</strong>
<div id="list">
</div>
</div>
</div>
<!-- <div id="controls">
<button id="update">update</button>
</div> -->
</body>
</html>
This diff is collapsed.
/*!*************************************!*\
!*** ./src/scripts/admin.client.js ***!
\*************************************/
/*!*******************************************************!*\
!*** ./node_modules/@babel/runtime/helpers/typeof.js ***!
\*******************************************************/
/*!**********************************************************!*\
!*** ./node_modules/@babel/runtime/regenerator/index.js ***!
\**********************************************************/
/*!*******************************************************************!*\
!*** ./node_modules/@babel/runtime/helpers/regeneratorRuntime.js ***!
\*******************************************************************/
/*!*********************************************************************!*\
!*** ./node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js ***!
\*********************************************************************/
This diff is collapsed.
/*!*************************************!*\
!*** ./src/scripts/login.client.js ***!
\*************************************/
/*!*******************************************************!*\
!*** ./node_modules/@babel/runtime/helpers/typeof.js ***!
\*******************************************************/
/*!**********************************************************!*\
!*** ./node_modules/@babel/runtime/regenerator/index.js ***!
\**********************************************************/
/*!*******************************************************************!*\
!*** ./node_modules/@babel/runtime/helpers/regeneratorRuntime.js ***!
\*******************************************************************/
/*!*********************************************************************!*\
!*** ./node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js ***!
\*********************************************************************/
This diff is collapsed.
/*!****************************************!*\
!*** ./src/scripts/register.client.js ***!
\****************************************/
/*!*******************************************************!*\
!*** ./node_modules/@babel/runtime/helpers/typeof.js ***!
\*******************************************************/
/*!**********************************************************!*\
!*** ./node_modules/@babel/runtime/regenerator/index.js ***!
\**********************************************************/
/*!*******************************************************************!*\
!*** ./node_modules/@babel/runtime/helpers/regeneratorRuntime.js ***!
\*******************************************************************/
/*!*********************************************************************!*\
!*** ./node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js ***!
\*********************************************************************/
This diff is collapsed.
/*!************************************!*\
!*** ./src/scripts/user.client.js ***!
\************************************/
/*!*******************************************************!*\
!*** ./node_modules/@babel/runtime/helpers/typeof.js ***!
\*******************************************************/
/*!**********************************************************!*\
!*** ./node_modules/@babel/runtime/regenerator/index.js ***!
\**********************************************************/
/*!*******************************************************************!*\
!*** ./node_modules/@babel/runtime/helpers/regeneratorRuntime.js ***!
\*******************************************************************/
/*!*********************************************************************!*\
!*** ./node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js ***!
\*********************************************************************/
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment