diff --git a/Back-End/Auth/models.py b/Back-End/Auth/models.py index f148dd7..2728edb 100644 --- a/Back-End/Auth/models.py +++ b/Back-End/Auth/models.py @@ -9,7 +9,7 @@ class Profile(AbstractUser): USERNAME_FIELD = 'email' REQUIRED_FIELDS = ('password', ) - + roleIndexLoginDefault = models.IntegerField(default=0) code = models.CharField(max_length=200, default="", blank=True) datePeremption = models.CharField(max_length=200, default="", blank=True) diff --git a/Back-End/Auth/serializers.py b/Back-End/Auth/serializers.py index 5085eb3..0ba320e 100644 --- a/Back-End/Auth/serializers.py +++ b/Back-End/Auth/serializers.py @@ -14,7 +14,7 @@ class ProfileSerializer(serializers.ModelSerializer): class Meta: model = Profile - fields = ['id', 'password', 'email', 'code', 'datePeremption', 'username', 'roles'] + fields = ['id', 'password', 'email', 'code', 'datePeremption', 'username', 'roles', 'roleIndexLoginDefault'] extra_kwargs = {'password': {'write_only': True}} def get_roles(self, obj): @@ -53,10 +53,10 @@ class ProfileSerializer(serializers.ModelSerializer): def update(self, instance, validated_data): password = validated_data.pop('password', None) instance = super().update(instance, validated_data) - + if password: instance.set_password(password) - + instance.full_clean() instance.save() return instance @@ -114,7 +114,7 @@ class ProfileRoleSerializer(serializers.ModelSerializer): if obj.profile: return obj.profile.email return None - + def get_associated_person(self, obj): if obj.role_type == ProfileRole.RoleType.PROFIL_PARENT: guardian = Guardian.objects.filter(profile_role=obj).first() diff --git a/Back-End/Auth/views.py b/Back-End/Auth/views.py index 8955b40..69f6f03 100644 --- a/Back-End/Auth/views.py +++ b/Back-End/Auth/views.py @@ -54,6 +54,7 @@ class SessionView(APIView): 'user': openapi.Schema(type=openapi.TYPE_OBJECT, properties={ 'id': openapi.Schema(type=openapi.TYPE_INTEGER), 'email': openapi.Schema(type=openapi.TYPE_STRING), + 'roleIndexLoginDefault': openapi.Schema(type=openapi.TYPE_INTEGER), 'roles': openapi.Schema(type=openapi.TYPE_ARRAY, items=openapi.Items(type=openapi.TYPE_OBJECT, properties={ 'role_type': openapi.Schema(type=openapi.TYPE_STRING), 'establishment': openapi.Schema(type=openapi.TYPE_STRING) @@ -65,18 +66,16 @@ class SessionView(APIView): ) def get(self, request): token = request.META.get('HTTP_AUTHORIZATION', '').split('Bearer ')[-1] - try: decoded_token = jwt.decode(token, settings.SECRET_KEY, algorithms=['HS256']) userid = decoded_token.get('user_id') user = Profile.objects.get(id=userid) - roles = ProfileRole.objects.filter(profile=user).values('role_type', 'establishment__name') - response_data = { 'user': { 'id': user.id, 'email': user.email, + 'roleIndexLoginDefault': user.roleIndexLoginDefault, 'roles': list(roles) } } @@ -157,11 +156,10 @@ class LoginView(APIView): operation_description="Connexion utilisateur", request_body=openapi.Schema( type=openapi.TYPE_OBJECT, - required=['email', 'password', 'role_type'], + required=['email', 'password'], properties={ 'email': openapi.Schema(type=openapi.TYPE_STRING), - 'password': openapi.Schema(type=openapi.TYPE_STRING), - 'role_type': openapi.Schema(type=openapi.TYPE_STRING) + 'password': openapi.Schema(type=openapi.TYPE_STRING) } ), responses={ @@ -194,38 +192,15 @@ class LoginView(APIView): password=data.get('password'), ) if user is not None: - role_type = data.get('role_type') - primary_role = ProfileRole.objects.filter(profile=user, role_type=role_type, is_active=True).first() - - if not primary_role: + # Vérifier si l'utilisateur a un role actif + has_active_role = ProfileRole.objects.filter(profile=user, is_active=True).first() + if not has_active_role: return JsonResponse({"errorMessage": "Profil inactif"}, status=status.HTTP_401_UNAUTHORIZED) login(request, user) user.save() retour = '' - - # Récupérer tous les rôles de l'utilisateur avec le type spécifié - roles = ProfileRole.objects.filter(profile=user, role_type=role_type).values('role_type', 'establishment__id', 'establishment__name') - - # Générer le JWT avec la bonne syntaxe datetime - access_payload = { - 'user_id': user.id, - 'email': user.email, - 'roles': list(roles), - 'type': 'access', - 'exp': datetime.utcnow() + settings.SIMPLE_JWT['ACCESS_TOKEN_LIFETIME'], - 'iat': datetime.utcnow(), - } - - access_token = jwt.encode(access_payload, settings.SIMPLE_JWT['SIGNING_KEY'], algorithm=settings.SIMPLE_JWT['ALGORITHM']) - # Générer le Refresh Token (exp: 7 jours) - refresh_payload = { - 'user_id': user.id, - 'type': 'refresh', - 'exp': datetime.utcnow() + settings.SIMPLE_JWT['REFRESH_TOKEN_LIFETIME'], - 'iat': datetime.utcnow(), - } - refresh_token = jwt.encode(refresh_payload, settings.SIMPLE_JWT['SIGNING_KEY'], algorithm=settings.SIMPLE_JWT['ALGORITHM']) + access_token, refresh_token = makeToken(user) return JsonResponse({ 'token': access_token, @@ -299,35 +274,10 @@ class RefreshJWTView(APIView): # Récupérer les informations utilisateur user = Profile.objects.get(id=payload['user_id']) - role_type = payload.get('role_type') + if not user: + return JsonResponse({'errorMessage': 'Utilisateur non trouvé'}, status=404) - # Récupérer le rôle principal de l'utilisateur - primary_role = ProfileRole.objects.filter(profile=user, role_type=role_type, is_active=True).first() - - if not primary_role: - return JsonResponse({'errorMessage': 'Profil inactif'}, status=400) - - # Générer un nouveau Access Token avec les informations complètes - new_access_payload = { - 'user_id': user.id, - 'email': user.email, - 'role_type': primary_role.get_role_type_display(), - 'establishment': primary_role.establishment.id, - 'type': 'access', - 'exp': datetime.utcnow() + settings.SIMPLE_JWT['ACCESS_TOKEN_LIFETIME'], - 'iat': datetime.utcnow(), - } - - new_access_token = jwt.encode(new_access_payload, settings.SIMPLE_JWT['SIGNING_KEY'], algorithm=settings.SIMPLE_JWT['ALGORITHM']) - - new_refresh_payload = { - 'user_id': user.id, - 'role_type': role_type, - 'type': 'refresh', - 'exp': datetime.utcnow() + settings.SIMPLE_JWT['REFRESH_TOKEN_LIFETIME'], - 'iat': datetime.utcnow(), - } - new_refresh_token = jwt.encode(new_refresh_payload, settings.SIMPLE_JWT['SIGNING_KEY'], algorithm=settings.SIMPLE_JWT['ALGORITHM']) + new_access_payload, new_refresh_token = makeToken(user) return JsonResponse({'token': new_access_token, 'refresh': new_refresh_token}, status=200) @@ -341,6 +291,38 @@ class RefreshJWTView(APIView): logger.error(f"Erreur inattendue: {str(e)}") return JsonResponse({'errorMessage': f'Erreur inattendue: {str(e)}'}, status=400) +def makeToken(user): + """ + Fonction pour créer un token JWT pour l'utilisateur donné. + """ + try: + # Récupérer tous les rôles de l'utilisateur actifs + roles = ProfileRole.objects.filter(profile=user, is_active=True).values('role_type', 'establishment__id', 'establishment__name') + + # Générer le JWT avec la bonne syntaxe datetime + access_payload = { + 'user_id': user.id, + 'email': user.email, + 'roleIndexLoginDefault':user.roleIndexLoginDefault, + 'roles': list(roles), + 'type': 'access', + 'exp': datetime.utcnow() + settings.SIMPLE_JWT['ACCESS_TOKEN_LIFETIME'], + 'iat': datetime.utcnow(), + } + + access_token = jwt.encode(access_payload, settings.SIMPLE_JWT['SIGNING_KEY'], algorithm=settings.SIMPLE_JWT['ALGORITHM']) + # Générer le Refresh Token (exp: 7 jours) + refresh_payload = { + 'user_id': user.id, + 'type': 'refresh', + 'exp': datetime.utcnow() + settings.SIMPLE_JWT['REFRESH_TOKEN_LIFETIME'], + 'iat': datetime.utcnow(), + } + refresh_token = jwt.encode(refresh_payload, settings.SIMPLE_JWT['SIGNING_KEY'], algorithm=settings.SIMPLE_JWT['ALGORITHM']) + return access_token, refresh_token + except Exception as e: + logger.error(f"Erreur lors de la création du token: {str(e)}") + return None @method_decorator(csrf_protect, name='dispatch') @method_decorator(ensure_csrf_cookie, name='dispatch') diff --git a/Front-End/src/app/[locale]/admin/layout.js b/Front-End/src/app/[locale]/admin/layout.js index 72d15b8..b3c7f3f 100644 --- a/Front-End/src/app/[locale]/admin/layout.js +++ b/Front-End/src/app/[locale]/admin/layout.js @@ -131,7 +131,6 @@ export default function Layout({ if (roleIndex === -1) { roleIndex = 0; } - setCurrentRoleIndex(roleIndex); const role = session.user.roles[roleIndex].role_type; setProfileRole(role); }} diff --git a/Front-End/src/app/[locale]/admin/page.js b/Front-End/src/app/[locale]/admin/page.js index dc129ae..db781da 100644 --- a/Front-End/src/app/[locale]/admin/page.js +++ b/Front-End/src/app/[locale]/admin/page.js @@ -10,7 +10,7 @@ import logger from '@/utils/logger'; import { fetchRegisterForms } from '@/app/actions/subscriptionAction'; import { fetchUpcomingEvents } from '@/app/actions/planningAction'; import { getSession } from 'next-auth/react'; -import { getCurrentRoleIndex } from '@/store/Store'; +import { useEstablishment } from '@/context/EstablishmentContext'; // Composant EventCard pour afficher les événements @@ -42,14 +42,11 @@ export default function DashboardPage() { const [classes, setClasses] = useState([]); const [establishmentId, setEstablishmentId] = useState(null); - + const { selectedEstablishmentId } = useEstablishment(); useEffect(() => { getSession() .then(session => { - if (session && session.user) { - const establishmentId = session.user.roles[getCurrentRoleIndex()].establishment__id; - setEstablishmentId(establishmentId); - } + setEstablishmentId(selectedEstablishmentId); }) .catch(err => { logger.error('Error fetching session:', err); diff --git a/Front-End/src/app/[locale]/parents/layout.js b/Front-End/src/app/[locale]/parents/layout.js index a94fb6e..3076328 100644 --- a/Front-End/src/app/[locale]/parents/layout.js +++ b/Front-End/src/app/[locale]/parents/layout.js @@ -2,6 +2,7 @@ // src/components/Layout.js import React, { useState, useEffect } from 'react'; import DropdownMenu from '@/components/DropdownMenu'; +import ProfileSelector from '@/components/ProfileSelector'; import { useRouter } from 'next/navigation'; // Ajout de l'importation import { User, MessageSquare, LogOut, Settings, Home } from 'lucide-react'; // Ajout de l'importation de l'icône Home import Logo from '@/components/Logo'; // Ajout de l'importation du composant Logo @@ -11,11 +12,11 @@ import ProtectedRoute from '@/components/ProtectedRoute'; import { disconnect } from '@/app/actions/authAction'; import Popup from '@/components/Popup'; import logger from '@/utils/logger'; -import { useSession } from 'next-auth/react'; -import { FE_USERS_LOGIN_URL } from '@/utils/Url'; import { getRightStr, RIGHTS } from '@/utils/rights'; import { getGravatarUrl } from '@/utils/gravatar'; +import { useEstablishment } from '@/context/EstablishmentContext'; import Image from 'next/image'; +import Footer from '@/components/Footer'; export default function Layout({ children, @@ -23,11 +24,12 @@ export default function Layout({ const router = useRouter(); // Définition de router const [messages, setMessages] = useState([]); - const { data: session, status } = useSession(); - const [userId, setUserId] = useState(null); - const [user, setUser] = useState(null); const [isLoading, setIsLoading] = useState(true); const [isPopupVisible, setIsPopupVisible] = useState(false); + const { profileRole, user } = useEstablishment(); + const softwareName = "N3WT School"; + const softwareVersion = `${process.env.NEXT_PUBLIC_APP_VERSION}`; + const handleDisconnect = () => { setIsPopupVisible(true); @@ -36,42 +38,15 @@ export default function Layout({ const confirmDisconnect = () => { setIsPopupVisible(false); disconnect(); - }; + }; - // useEffect(() => { - // if (status === 'loading') return; - // if (!session) { - // router.push(`${FE_USERS_LOGIN_URL}`); - // } - - // const userIdFromSession = session.user.id; - // setUserId(userIdFromSession); - // setIsLoading(true); - // fetchMessages(userId) - // .then(data => { - // if (data) { - // setMessages(data); - // } - // logger.debug('Success :', data); - // }) - // .catch(error => { - // logger.error('Error fetching data:', error); - // }) - // .finally(() => { - // setIsLoading(false); - // }); - // }, [userId]); - - // if (isLoading) { - // return
Loading...
; - // } const dropdownItems = [ { type: 'info', content: (
{user?.email || 'Utilisateur'}
-
{getRightStr(user?.roles[0]?.role_type) || ''}
+
{getRightStr(profileRole) || ''}
) }, @@ -91,11 +66,14 @@ const dropdownItems = [
{/* Entête */} -
+
- {/* Utilisation du composant Logo */} - -
Accueil
+
+ +
+
Accueil
+ {/* Ajout de flex-1 pour utiliser toute la hauteur disponible */} {children}
+ {/* Footer responsive */} +