Première implementation de sso

This commit is contained in:
2026-08-03 13:05:09 +00:00
commit a494199820
31 changed files with 440 additions and 0 deletions

View File

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

12
authentification/admin.py Normal file
View File

@@ -0,0 +1,12 @@
from django.contrib import admin
from authentification.models import Departement, Employe
@admin.register(Departement)
class DepartementAdmin(admin.ModelAdmin):
list_display = ('nom',)
@admin.register(Employe)
class EmployeAdmin(admin.ModelAdmin):
list_display = ('user', 'matricule', 'departement', 'fonction', 'date_embauche')
list_filter = ('departement', 'fonction')
search_fields = ('user__username', 'matricule')

5
authentification/apps.py Normal file
View File

@@ -0,0 +1,5 @@
from django.apps import AppConfig
class AuthentificationConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'authentification'

View File

@@ -0,0 +1,49 @@
from django.contrib.auth.models import User
from django.db import models
class Departement(models.Model):
"""Modèle représentant un département de l'entreprise."""
nom = models.CharField(max_length=100)
def __str__(self):
return self.nom
class Employe(models.Model):
"""Modèle représentant un employé de l'entreprise."""
FONCTION_LISTE = [
('directeur', 'Directeur'),
('assistant_direction', 'Assistante de direction'),
('assistant_technique_recherche', 'Assistant technique de recherche'),
('comptable', 'Comptable'),
('raf', 'RAF'),
('data_manager', 'Data Manager'),
('logisticien', 'Logisticien'),
('post_doctorant', 'Post-Doctorant'),
('qualiticien', 'Qualiticien'),
('technicien_surface', 'Technicien de surface'),
('chauffeur', 'Chauffeur'),
]
user = models.OneToOneField(User, on_delete=models.CASCADE)
matricule = models.CharField(max_length=10, unique=True, null=True, blank=True)
departement = models.ForeignKey(Departement, on_delete=models.SET_NULL, null=True, blank=True)
fonction = models.CharField(max_length=50, blank=True, null=True, choices=FONCTION_LISTE)
date_embauche = models.DateField(blank=True, null=True)
adresse = models.CharField(max_length=100, null=True, blank=True)
telephone = models.CharField(max_length=15, null=True, blank=True)
sexe = models.CharField(max_length=1, null=True, blank=True, choices=[('m', 'Masculin'), ('f', 'Féminin')])
date_naissance = models.DateField(blank=True, null=True)
CV = models.FileField(upload_to='cv/', blank=True, null=True)
diplome = models.FileField(upload_to='diplomes/', blank=True, null=True)
rib = models.FileField(upload_to='rib/', blank=True, null=True)
photo = models.ImageField(upload_to='photos/', blank=True, null=True)
casier_judiciaire = models.FileField(upload_to='casier/', blank=True, null=True)
chef = models.BooleanField(
default=False,
verbose_name="Cet utilisateur est-il chef de ce département ?"
)
def __str__(self):
return f"{self.user.first_name or 'N/A'} {self.user.last_name or ' '} ({self.matricule or ' '})"

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

View File

@@ -0,0 +1,44 @@
{% load static %}
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}">
<title>Login - SIRH</title>
</head>
<body>
<div class="container-fluid vh-100">
<div class="row">
<div class="col-6 vh-100 d-flex flex-column justify-content-center align-items-center">
<img src="{% static 'images/cerfig.jpg' %}" class="w-50">
<h5 class="text-center">Bienvenue sur les systèmes de gestion du CERFIG</h5>
</div>
<div class="col-6 vh-100 d-flex justify-content-center align-items-center">
<form method="POST" action="{% url 'login' %}" class="w-100 shadow rounded px-3 py-5">
<h2 class="text-center">Connexion</h2>
{% if messages %}
{% for message in messages %}
<div class="alert alert-{% if message.tags == 'error' %}danger{% else %}success{% endif %}">{{message}}</div>
{% endfor %}
{% endif %}
{% csrf_token %}
<input type="hidden" name="next" value="{{ request.GET.next }}">
<div class="mb-3">
<label for="mail">Votre adresse email :</label>
<input type="text" name="mail" class="form-control" placeholder="Entrez votre e-mail" required>
</div>
<div class="mb-3">
<label for="mot_de_passe">Mot de passe</label>
<input type="password" name="mot_de_passe" class="form-control" placeholder="Entrez votre mot de passe" required>
<i class="bi bi-eye toggle-password" onclick="togglePassword()"
style="position:absolute; right:10px; top:38px; cursor:pointer;"></i>
</div>
<button type="submit" class="btn btn-primary w-100">Se connecter</button>
</form>
</div>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

7
authentification/urls.py Normal file
View File

@@ -0,0 +1,7 @@
from django.urls import path
from .views import login_view, deconnexion_view
urlpatterns = [
path('login/', login_view, name='login'),
path('deconnexion/', deconnexion_view, name='deconnexion'),
]

71
authentification/views.py Normal file
View File

@@ -0,0 +1,71 @@
from django.contrib.auth import authenticate, login, logout
from django.shortcuts import render, redirect
# from django.contrib import messages
# from django.views.decorators.cache import never_cache
# from django.views.decorators.http import require_http_methods
# from django.contrib.auth import authenticate, login
# from django.shortcuts import render, redirect
def login_view(request):
if request.method == 'POST':
username = request.POST.get('mail')
password = request.POST.get('mot_de_passe')
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
next_url = request.GET.get('next') or request.POST.get('next') or '/'
return redirect(next_url)
else:
return render(request, 'authentification/login.html', {'error': 'Identifiants invalides'})
return render(request, 'authentification/login.html')
# @never_cache
# # @require_http_methods(["GET", "POST"])
# def login_view(request):
# """
# Gère la connexion des utilisateurs avec redirection selon le rôle et
# vérification de l'acceptation de la politique d'utilisation.
# """
# # if request.user.is_authenticated:
# # next_url = request.GET.get('next', '')
# # if next_url:
# # return redirect(next_url)
# # return redirect("gestion_conges:conge")
# if request.method == 'POST':
# email = request.POST.get('mail')
# password = request.POST.get('mot_de_passe')
# # next_url = request.POST.get('next', '')
# if not (email and password):
# messages.error(request, "Veuillez remplir tous les champs.")
# return render(request, 'authentification/login.html')
# user = authenticate(request, username=email, password=password)
# if user is None or not user.is_active:
# messages.error(request, "Nom dutilisateur ou mot de passe incorrect ou le compte est inactif.")
# return render(request, 'authentification/login.html')
# login(request, user)
# # if next_url:
# # return redirect(next_url)
# # return redirect("gestion_conges:conge")
# return render(
# request,
# 'authentification/login.html',
# {
# 'next': request.GET.get('next', ''),
# }
# )
def deconnexion_view(request):
"""Gère la déconnexion de l'utilisateur."""
logout(request)
return redirect('login')