diff --git a/client/package-lock.json b/client/package-lock.json index be0ca9d..666c61e 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -22,6 +22,7 @@ "esbuild": "^0.23.1", "gift-pegjs": "^1.0.2", "jest-environment-jsdom": "^29.7.0", + "jwt-decode": "^4.0.0", "katex": "^0.16.11", "marked": "^14.1.2", "nanoid": "^5.0.2", @@ -9417,6 +9418,14 @@ "node": ">= 10.0.0" } }, + "node_modules/jwt-decode": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-4.0.0.tgz", + "integrity": "sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==", + "engines": { + "node": ">=18" + } + }, "node_modules/katex": { "version": "0.16.11", "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.11.tgz", diff --git a/client/package.json b/client/package.json index 6a7de25..8f2a8ad 100644 --- a/client/package.json +++ b/client/package.json @@ -26,6 +26,7 @@ "esbuild": "^0.23.1", "gift-pegjs": "^1.0.2", "jest-environment-jsdom": "^29.7.0", + "jwt-decode": "^4.0.0", "katex": "^0.16.11", "marked": "^14.1.2", "nanoid": "^5.0.2", diff --git a/client/src/App.tsx b/client/src/App.tsx index fd0ee1a..5199afa 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -26,23 +26,24 @@ import ApiService from './services/ApiService'; import OAuthCallback from './pages/AuthManager/callback/AuthCallback'; const App: React.FC = () => { - const [isAuthenticated, setIsAuthenticated] = useState(ApiService.isLoggedIn()); // Initial check - const location = useLocation(); // Hook to detect route changes + const [isAuthenticated, setIsAuthenticated] = useState(ApiService.isLoggedIn()); + const [isTeacherAuthenticated, setIsTeacherAuthenticated] = useState(ApiService.isLoggedInTeacher()); + const location = useLocation(); // Check login status every time the route changes useEffect(() => { const checkLoginStatus = () => { - const loggedIn = ApiService.isLoggedIn(); - setIsAuthenticated(loggedIn); // Update state if login status changes - console.log('App.tsx - Login status:', loggedIn); + setIsAuthenticated(ApiService.isLoggedIn()); + setIsTeacherAuthenticated(ApiService.isLoggedInTeacher()); }; - checkLoginStatus(); // Check login status whenever the route changes - }, [location]); // Re-run when the location (route) changes + checkLoginStatus(); + }, [location]); const handleLogout = () => { ApiService.logout(); - setIsAuthenticated(false); // Ensure we log out the user in the state as well + setIsAuthenticated(false); + setIsTeacherAuthenticated(false); }; return ( @@ -57,19 +58,19 @@ const App: React.FC = () => { {/* Pages espace enseignant */} : } + element={isTeacherAuthenticated ? : } /> : } + element={isTeacherAuthenticated ? : } /> : } + element={isTeacherAuthenticated ? : } /> : } + element={isTeacherAuthenticated ? : } /> {/* Pages espace étudiant */} diff --git a/client/src/pages/AuthManager/callback/AuthCallback.tsx b/client/src/pages/AuthManager/callback/AuthCallback.tsx index a5a4138..c9b4997 100644 --- a/client/src/pages/AuthManager/callback/AuthCallback.tsx +++ b/client/src/pages/AuthManager/callback/AuthCallback.tsx @@ -1,6 +1,7 @@ import { useEffect } from 'react'; import { useNavigate, useLocation } from 'react-router-dom'; import apiService from '../../../services/ApiService'; +import { jwtDecode } from 'jwt-decode'; const OAuthCallback: React.FC = () => { const navigate = useNavigate(); @@ -15,6 +16,10 @@ const OAuthCallback: React.FC = () => { console.log(user); apiService.saveToken(user); + const decodedToken = jwtDecode(user); + const { email } = decodedToken as { email: string;}; + console.log(email + " connected!"); + // Navigate to the dashboard or another page navigate('/'); } else { diff --git a/client/src/pages/AuthManager/providers/SimpleLogin/Register.tsx b/client/src/pages/AuthManager/providers/SimpleLogin/Register.tsx index 5683e6d..305b5ab 100644 --- a/client/src/pages/AuthManager/providers/SimpleLogin/Register.tsx +++ b/client/src/pages/AuthManager/providers/SimpleLogin/Register.tsx @@ -1,13 +1,12 @@ - import { useNavigate } from 'react-router-dom'; // JoinRoom.tsx import React, { useEffect, useState } from 'react'; -import { TextField } from '@mui/material'; +import { TextField, FormLabel, RadioGroup, FormControlLabel, Radio, Box } from '@mui/material'; import LoadingButton from '@mui/lab/LoadingButton'; -import LoginContainer from '../../../../components/LoginContainer/LoginContainer' +import LoginContainer from '../../../../components/LoginContainer/LoginContainer'; import ApiService from '../../../../services/ApiService'; const Register: React.FC = () => { @@ -15,33 +14,31 @@ const Register: React.FC = () => { const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); + const [role, setRole] = useState('etudiant'); const [connectionError, setConnectionError] = useState(''); const [isConnecting] = useState(false); useEffect(() => { - return () => { - - }; + return () => { }; }, []); const register = async () => { - const result = await ApiService.register(email, password); + const result = await ApiService.register(email, password, role); - if (result != true) { + if (result !== true) { setConnectionError(result); return; } - navigate("/login") + navigate("/login"); }; - return ( - + title="Créer un compte" + error={connectionError} + > { fullWidth /> + + Choisir votre rôle + setRole(e.target.value)} + > + } label="Étudiant" /> + } label="Professeur" /> + + + { > S'inscrire - - ); }; diff --git a/client/src/pages/Teacher/Register/Register.tsx b/client/src/pages/Teacher/Register/Register.tsx index 29d5f2b..2dd1f3c 100644 --- a/client/src/pages/Teacher/Register/Register.tsx +++ b/client/src/pages/Teacher/Register/Register.tsx @@ -26,7 +26,7 @@ const Register: React.FC = () => { }, []); const register = async () => { - const result = await ApiService.register(email, password); + const result = await ApiService.register(email, password, "temp"); // "temp", car ce fichier n'est plus utilisé. il est déplacer dans /AuthManager if (result != true) { setConnectionError(result); diff --git a/client/src/services/ApiService.tsx b/client/src/services/ApiService.tsx index ab667b2..5b1ba7b 100644 --- a/client/src/services/ApiService.tsx +++ b/client/src/services/ApiService.tsx @@ -1,4 +1,5 @@ import axios, { AxiosError, AxiosResponse } from 'axios'; +import {jwtDecode} from 'jwt-decode'; import { ENV_VARIABLES } from '../constants'; import { QuizType } from '../Types/QuizType'; @@ -66,8 +67,6 @@ class ApiService { public isLoggedIn(): boolean { const token = this.getToken() - console.log("Check if loggedIn : " + token); - if (token == null) { return false; } @@ -78,6 +77,35 @@ class ApiService { return true; } + public isLoggedInTeacher(): boolean { + const token = this.getToken(); + + console.log("Check if loggedIn : " + token); + + if (token == null) { + return false; + } + + try { + const decodedToken = jwtDecode(token) as { role: string }; + + const userRole = decodedToken.role; + const requiredRole = 'professeur'; + + if (userRole !== requiredRole) { + return false; + } + + // Update token expiry + this.saveToken(token); + + return true; + } catch (error) { + console.error("Error decoding token:", error); + return false; + } + } + public logout(): void { return localStorage.removeItem("jwt"); } @@ -88,7 +116,7 @@ class ApiService { * @returns true if successful * @returns A error string if unsuccessful, */ - public async register(email: string, password: string): Promise { + public async register(email: string, password: string, role: string): Promise { try { if (!email || !password) { @@ -97,7 +125,7 @@ class ApiService { const url: string = this.constructRequestUrl(`/user/register`); const headers = this.constructRequestHeaders(); - const body = { email, password }; + const body = { email, password, role }; const result: AxiosResponse = await axios.post(url, body, { headers: headers }); @@ -881,4 +909,4 @@ class ApiService { } const apiService = new ApiService(); -export default apiService; +export default apiService; \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yaml index b116e82..898a78a 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -4,7 +4,7 @@ services: frontend: build: - context: ./server + context: ./client dockerfile: Dockerfile container_name: frontend ports: