Compare commits
79 Commits
375549cb30
...
affichage_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1da9d4ca5f | ||
|
|
e81c29a586 | ||
|
|
d28bf85556 | ||
|
|
3b587d2a1a | ||
|
|
e3f0befff6 | ||
|
|
55e5a2819c | ||
|
|
7e28b25497 | ||
| 643205a4bb | |||
| 4934b42ed9 | |||
| f9ca539670 | |||
| 7b4778252f | |||
| 2c086187e7 | |||
| 5aff49600e | |||
| 8c6e59e15a | |||
| 415860f233 | |||
| 8503689aa4 | |||
| b03a4214c0 | |||
| d4f4b7d954 | |||
| 489eeb439f | |||
| 5277b7f355 | |||
| 9d9e6c6549 | |||
| 784822478e | |||
| ab87baaa3a | |||
| 6026af5498 | |||
| 91bdd791f1 | |||
| 671072864d | |||
| bb93a853db | |||
| 99434a21e0 | |||
| f6b90e7dd0 | |||
| fcfac71026 | |||
| 34a261a4af | |||
| f0e8b025a4 | |||
| 62b2938c71 | |||
| 06125b0900 | |||
| 0047b1f91c | |||
| 7ee14e7b3f | |||
| d12b014b20 | |||
| d9b45ac364 | |||
| 44faeac222 | |||
| e1436e8f4e | |||
| 4ee7dd9fc7 | |||
| a9e708c778 | |||
| e427561cc1 | |||
| 78fafebc4d | |||
| ecdaa9f9f9 | |||
| 9951719b26 | |||
| 1391a5ea3b | |||
| 357b50dfa4 | |||
| bda80fae85 | |||
| 9c1eb543ff | |||
| f55b1a6f2d | |||
| a6412341cf | |||
| ab2d8b479c | |||
| 8f412cb031 | |||
| 69764b74a2 | |||
| e1dc510af1 | |||
| fa21850c6b | |||
| 4a8cbf02b9 | |||
| 798784a163 | |||
| 86ad99de76 | |||
| 5680677865 | |||
| 886c3246af | |||
| 7b66250832 | |||
| 80b3573674 | |||
| efadd66483 | |||
| c9431063de | |||
| 15c33efc14 | |||
| 5257901e75 | |||
| b3294a823e | |||
| 2a182830a6 | |||
| 14631c3744 | |||
| f0894bb66f | |||
| 75285a140a | |||
| 3cc8e292b3 | |||
| 34d1464391 | |||
| 6c12131fab | |||
| 19e4675f32 | |||
| b9f9de19f5 | |||
| 6b977d5809 |
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
db.sqlite3
|
||||||
|
venv/
|
||||||
|
media/
|
||||||
|
staticfiles/
|
||||||
|
.env
|
||||||
|
migrations/
|
||||||
|
*.pyc
|
||||||
52
Jenkinsfile
vendored
Normal file
52
Jenkinsfile
vendored
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
pipeline
|
||||||
|
{
|
||||||
|
agent any
|
||||||
|
options {
|
||||||
|
// This is required if you want to clean before build
|
||||||
|
skipDefaultCheckout(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
environment
|
||||||
|
{
|
||||||
|
SUDO_PASSWORD = credentials('sudo-password')
|
||||||
|
}
|
||||||
|
|
||||||
|
stages
|
||||||
|
{
|
||||||
|
stage ( 'checkout' )
|
||||||
|
{
|
||||||
|
steps
|
||||||
|
{
|
||||||
|
sh 'echo "Debut du pipeline"'
|
||||||
|
cleanWs()
|
||||||
|
checkout scm
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage ( 'Deploiement' )
|
||||||
|
{
|
||||||
|
when { branch 'main' }
|
||||||
|
steps {
|
||||||
|
sh '''
|
||||||
|
cd /var/www/sirh
|
||||||
|
echo $SUDO_PASSWORD | sudo -S chown -R jenkins:jenkins /var/www/sirh
|
||||||
|
|
||||||
|
git fetch origin main
|
||||||
|
git reset --hard origin/main
|
||||||
|
|
||||||
|
python3 -m venv venv
|
||||||
|
. venv/bin/activate
|
||||||
|
pip install -r requirements.txt
|
||||||
|
|
||||||
|
python manage.py makemigrations
|
||||||
|
python manage.py migrate
|
||||||
|
echo $SUDO_PASSWORD | sudo -S rm -r staticfiles
|
||||||
|
python manage.py collectstatic --noinput
|
||||||
|
|
||||||
|
echo $SUDO_PASSWORD | sudo -S chown -R www-data:www-data /var/www/sirh
|
||||||
|
echo "Deploiement reussi"
|
||||||
|
echo $SUDO_PASSWORD | sudo -S supervisorctl restart sirh
|
||||||
|
'''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
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,21 +12,22 @@ https://docs.djangoproject.com/en/5.2/ref/settings/
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from decouple import config
|
||||||
|
|
||||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||||
|
|
||||||
|
|
||||||
# Quick-start development settings - unsuitable for production
|
# Quick-start development settings - unsuitable for production
|
||||||
# See https://docs.djangoproject.com/en/5.2/howto/deployment/checklist/
|
# See https://docs.djangoproject.com/en/5.2/howto/deployment/checklist/
|
||||||
|
|
||||||
# SECURITY WARNING: keep the secret key used in production secret!
|
# SECURITY WARNING: keep the secret key used in production secret!
|
||||||
SECRET_KEY = 'django-insecure--wdb9t(77rvyac$_q!n5gw86&0r(0&&j171v9h!-_$jahsza*5'
|
SECRET_KEY = config('SECRET_KEY')
|
||||||
|
|
||||||
# SECURITY WARNING: don't run with debug turned on in production!
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
DEBUG = False
|
DEBUG = config('DEBUG', default=True, cast=bool)
|
||||||
|
|
||||||
ALLOWED_HOSTS = ["https://support.cerfig.org", "support.cerfig.org"]
|
ALLOWED_HOSTS = config('ALLOWED_HOSTS', default=[]).split(',')
|
||||||
|
#CSRF_TRUSTED_ORIGINS = config("CSRF_TRUSTED_ORIGINS", default=[]).split(",")
|
||||||
|
|
||||||
# Application definition
|
# Application definition
|
||||||
|
|
||||||
@@ -40,12 +41,9 @@ INSTALLED_APPS = [
|
|||||||
'gestion_employe',
|
'gestion_employe',
|
||||||
'gestion_conge',
|
'gestion_conge',
|
||||||
'gestion_projet',
|
'gestion_projet',
|
||||||
'gestion_salle',
|
'gestion_salle'
|
||||||
'simple_sso.sso_server'
|
|
||||||
]
|
]
|
||||||
|
|
||||||
LOGIN_URL = 'login'
|
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
'django.middleware.security.SecurityMiddleware',
|
'django.middleware.security.SecurityMiddleware',
|
||||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||||
@@ -68,6 +66,7 @@ TEMPLATES = [
|
|||||||
'django.template.context_processors.request',
|
'django.template.context_processors.request',
|
||||||
'django.contrib.auth.context_processors.auth',
|
'django.contrib.auth.context_processors.auth',
|
||||||
'django.contrib.messages.context_processors.messages',
|
'django.contrib.messages.context_processors.messages',
|
||||||
|
'contexte_universel.contexte_universel',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -79,18 +78,18 @@ WSGI_APPLICATION = 'SIRH.wsgi.application'
|
|||||||
# Database
|
# Database
|
||||||
# https://docs.djangoproject.com/en/5.2/ref/settings/#databases
|
# https://docs.djangoproject.com/en/5.2/ref/settings/#databases
|
||||||
|
|
||||||
|
|
||||||
DATABASES = {
|
DATABASES = {
|
||||||
'default': {
|
'default': {
|
||||||
'ENGINE': 'django.db.backends.mysql',
|
'ENGINE': 'django.db.backends.mysql',
|
||||||
'NAME': 'sirh',
|
'NAME': config("DB_NAME"),
|
||||||
'USER': 'sirh',
|
'USER': config("DB_USER"),
|
||||||
'PASSWORD': 'sirh-cerfig',
|
'PASSWORD': config("DB_PASSWORD"),
|
||||||
'HOST': 'localhost', # Or the server IP
|
'HOST': config("DB_HOST"),
|
||||||
'PORT': '3306', # Default MySQL port
|
'PORT': config("DB_PORT", cast=int),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# Password validation
|
# Password validation
|
||||||
# https://docs.djangoproject.com/en/5.2/ref/settings/#auth-password-validators
|
# https://docs.djangoproject.com/en/5.2/ref/settings/#auth-password-validators
|
||||||
|
|
||||||
@@ -142,11 +141,21 @@ MEDIA_ROOT = BASE_DIR / "media"
|
|||||||
|
|
||||||
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
||||||
|
|
||||||
|
# Connexion sso
|
||||||
|
# LOGIN_URL = '/client/'
|
||||||
|
LOGIN_URL = 'simple-sso-login'
|
||||||
|
|
||||||
|
SSO_PRIVATE_KEY = config('SSO_PRIVATE_KEY')
|
||||||
|
SSO_PUBLIC_KEY = config('SSO_PUBLIC_KEY')
|
||||||
|
SSO_SERVER = config('SSO_SERVER')
|
||||||
|
#SSO_LOGOUT_URL = 'http://test-authentification.cerfig.org:89/deconnexion'
|
||||||
|
|
||||||
|
# Configuration de l'email
|
||||||
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
|
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
|
||||||
EMAIL_HOST = 'ssl0.ovh.net'
|
EMAIL_HOST = 'ssl0.ovh.net'
|
||||||
EMAIL_PORT = 465
|
EMAIL_PORT = 465
|
||||||
EMAIL_USE_SSL = True
|
EMAIL_USE_SSL = True
|
||||||
EMAIL_USE_TLS = False
|
EMAIL_USE_TLS = False
|
||||||
EMAIL_HOST_USER = 'support.it@cerfig.org'
|
EMAIL_HOST_USER = config("EMAIL_HOST_USER")
|
||||||
EMAIL_HOST_PASSWORD = 'Cerfig2025'
|
EMAIL_HOST_PASSWORD = config("EMAIL_HOST_PASSWORD")
|
||||||
DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
|
DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
|
||||||
|
|||||||
39
SIRH/sso.py
Normal file
39
SIRH/sso.py
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
# SGL/sso.py
|
||||||
|
from gestion_employe.models import Employe, Departement
|
||||||
|
from simple_sso.sso_client.client import Client
|
||||||
|
from django.contrib.auth import get_user_model
|
||||||
|
from django.contrib.auth.models import Group
|
||||||
|
|
||||||
|
User = get_user_model()
|
||||||
|
|
||||||
|
class SIRHClient(Client):
|
||||||
|
def build_user(self, user_data):
|
||||||
|
"""Crée le User et son Profile avec les infos reçues du serveur."""
|
||||||
|
user_data_copy = user_data.copy()
|
||||||
|
|
||||||
|
print("Un petit test", user_data_copy)
|
||||||
|
|
||||||
|
user_data.pop("departement", None)
|
||||||
|
user_data.pop("chef_departement", None)
|
||||||
|
user_data.pop("groups", None)
|
||||||
|
|
||||||
|
user = super().build_user(user_data)
|
||||||
|
departement = None
|
||||||
|
|
||||||
|
if "departement" in user_data_copy:
|
||||||
|
departement = Departement.objects.get_or_create(
|
||||||
|
nom=user_data_copy.get("departement", ""))[0]
|
||||||
|
|
||||||
|
Employe.objects.update_or_create(
|
||||||
|
user = user,
|
||||||
|
defaults = {
|
||||||
|
"departement": departement,
|
||||||
|
"chef": user_data_copy.get("chef_departement", None),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
for group_name in user_data_copy.get("groups", []):
|
||||||
|
group, _ = Group.objects.get_or_create(name=group_name)
|
||||||
|
user.groups.add(group)
|
||||||
|
|
||||||
|
return user
|
||||||
@@ -15,8 +15,9 @@
|
|||||||
<body>
|
<body>
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="row flex-nowrap">
|
<div class="row flex-nowrap">
|
||||||
|
{% include 'parts/menu_application.html' %}
|
||||||
{% include 'parts/menu_principal.html' %}
|
{% include 'parts/menu_principal.html' %}
|
||||||
<div class="col-9 p-4">
|
<div class="col p-4">
|
||||||
{% block 'contenu' %} {% endblock %}
|
{% block 'contenu' %} {% endblock %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
<input type="hidden" name="next" value="{{ next }}">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="mail">Votre adresse email :</label>
|
<label for="mail">Votre adresse email :</label>
|
||||||
<input type="text" name="mail" class="form-control" placeholder="Entrez votre e-mail" required>
|
<input type="text" name="mail" class="form-control" placeholder="Entrez votre e-mail" required>
|
||||||
|
|||||||
8
SIRH/templates/SIRH/parts/menu_application.html
Normal file
8
SIRH/templates/SIRH/parts/menu_application.html
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<div class="col-1 bg-danger border d-flex flex-column vh-100 pt-5 sticky-top">
|
||||||
|
<a href="{{ SIRH_LIEN }}" class="text-white text-center fw-bold text-decoration-none mb-4" style="font-size:1.4em">
|
||||||
|
<i class="bi bi-people-fill fs-1 d-block"></i>SIRH
|
||||||
|
</a>
|
||||||
|
<a href="{{ SGL_LIEN }}" class="text-white text-center fw-bold text-decoration-none mb-4" style="font-size:1.4em">
|
||||||
|
<i class="bi bi-building-gear fs-1 d-block"></i> SGL
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
@@ -2,40 +2,47 @@
|
|||||||
{% load tags_personnaliser %}
|
{% load tags_personnaliser %}
|
||||||
|
|
||||||
<div class="col-3 bg-danger d-flex flex-column vh-100 pt-5 sticky-top">
|
<div class="col-3 bg-danger d-flex flex-column vh-100 pt-5 sticky-top">
|
||||||
<a href="{% url 'gestion_employe:mon-profil' %}" class="text-white fw-bold text-decoration-none mb-4" style="font-size:1.4em">
|
<div class="text-center mb-4">
|
||||||
|
{% if user.employe.photo %}
|
||||||
|
<img src="{{ user.employe.photo.url }}"
|
||||||
|
class="rounded-circle"
|
||||||
|
width="100"
|
||||||
|
height="100"
|
||||||
|
style="object-fit:cover;">
|
||||||
|
{% else %}
|
||||||
|
<i class="bi bi-person-circle text-white" style="font-size:60px;"></i>
|
||||||
|
{% endif %}
|
||||||
|
<div class="text-white mt-2 fw-bold fs-5">
|
||||||
|
{{ user.first_name }} {{ user.last_name }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a href="{% url 'gestion_employe:mon-profil' %}" class="text-white fw-bold text-decoration-none mb-4" style="font-size: 1.2em;">
|
||||||
<i class="bi bi-person-circle"></i> Mon profil
|
<i class="bi bi-person-circle"></i> Mon profil
|
||||||
</a>
|
</a>
|
||||||
{% if user|has_group:"ressource_humaine" or user|has_group:"direction" %}
|
{% if user|has_group:"ressource_humaine" or user|has_group:"direction" %}
|
||||||
<a href="{% url 'gestion_employe:index' %}" class="text-white fw-bold text-decoration-none mb-4" style="font-size:1.4em">
|
<a href="{% url 'gestion_employe:index' %}" class="text-white fw-bold text-decoration-none mb-4" style="font-size: 1.2em;">
|
||||||
<i class="bi bi-speedometer2"></i> Tableau de bord
|
<i class="bi bi-speedometer2"></i> Tableau de bord
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if user|has_group:"ressource_humaine" or user|has_group:"direction" %}
|
{% if user|has_group:"ressource_humaine" or user|has_group:"direction" %}
|
||||||
<a href="{% url 'gestion_projet:index' %}" class="text-white fw-bold text-decoration-none mb-4" style="font-size:1.4em">
|
<a href="{% url 'gestion_projet:index' %}" class="text-white fw-bold text-decoration-none mb-4" style="font-size: 1.2em;">
|
||||||
<i class="bi bi-folder"></i> Gestion des Projets
|
<i class="bi bi-folder"></i> Gestion des Projets
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a href="{% url 'gestion_conges:conge' %}" class="text-white fw-bold text-decoration-none mb-4" style="font-size:1.4em">
|
<a href="{% url 'gestion_conges:conge' %}" class="text-white fw-bold text-decoration-none mb-4" style="font-size: 1.2em;">
|
||||||
<i class="bi bi-airplane"></i> Gestion des congés
|
<i class="bi bi-airplane"></i> Gestion des congés
|
||||||
</a>
|
</a>
|
||||||
{% if user|is_chef_projet %}
|
{% if user|is_chef_projet %}
|
||||||
<a href="{% url 'gestion_projet:activites-projet' %}" class="text-white fw-bold text-decoration-none mb-4" style="font-size:1.4em">
|
<a href="{% url 'gestion_projet:activites-projet' %}" class="text-white fw-bold text-decoration-none mb-4" style="font-size: 1.2em;">
|
||||||
<i class="bi bi-list-task"></i> Suivi des Activités
|
<i class="bi bi-list-task"></i> Suivi des Activités
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a href="{% url 'gestion_salle:reservation-salle' %}" class="text-white fw-bold text-decoration-none mb-4" style="font-size:1.4em">
|
<a href="{% url 'gestion_salle:reservation-salle' %}" class="text-white fw-bold text-decoration-none mb-4" style="font-size: 1.2em;">
|
||||||
<i class="bi bi-calendar-check"></i> Réservation
|
<i class="bi bi-calendar-check"></i> Réservation
|
||||||
</a>
|
</a>
|
||||||
{% comment %} <a href="{% url 'rapport-rh' %}" class="text-white fw-bold text-decoration-none mb-2" style="font-size:1.2em">
|
{% comment %} {% url 'deconnexion' %} {% endcomment %}
|
||||||
<i class="bi bi-graph-up"></i> Rapports et Statistiques
|
<a href="{% url 'deconnexion' %}" class="text-white fw-bold text-decoration-none mb-4" style="font-size: 1.2em;">
|
||||||
</a> {% endcomment %}
|
|
||||||
{% comment %} <a href="" class="text-white fw-bold text-decoration-none mb-2" style="font-size:1.2em">
|
|
||||||
<i class="bi bi-person-gear"></i> Gestion des Utilisateurs
|
|
||||||
</a> {% endcomment %}
|
|
||||||
{% comment %} <a href="{% url 'gestion_employe:departement' %}" class="text-white fw-bold text-decoration-none mb-2" style="font-size:1.2em">
|
|
||||||
<i class="bi bi-gear"></i> Paramètres
|
|
||||||
</a> {% endcomment %}
|
|
||||||
<a href="{% url 'deconnexion' %}" class="text-white fw-bold text-decoration-none mb-4" style="font-size:1.4em">
|
|
||||||
<i class="bi bi-box-arrow-right"></i> Déconnexion
|
<i class="bi bi-box-arrow-right"></i> Déconnexion
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
31
SIRH/urls.py
31
SIRH/urls.py
@@ -16,32 +16,29 @@ Including another URLconf
|
|||||||
"""
|
"""
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.urls import include, path
|
from django.urls import include, path
|
||||||
from django.conf.urls.static import static
|
# from django.conf.urls.static import static
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
# from simple_sso.sso_server.server import Server
|
|
||||||
|
|
||||||
from . import views
|
from . import views
|
||||||
|
from .sso import SIRHClient
|
||||||
|
|
||||||
# server_sso = Server()
|
client_sirh = SIRHClient(
|
||||||
|
settings.SSO_SERVER,
|
||||||
|
settings.SSO_PUBLIC_KEY,
|
||||||
|
settings.SSO_PRIVATE_KEY
|
||||||
|
)
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path(
|
|
||||||
'',
|
|
||||||
views.login_view,
|
|
||||||
name='index'
|
|
||||||
),
|
|
||||||
|
|
||||||
path('login/',
|
path('login/',
|
||||||
views.login_view,
|
views.connexion,
|
||||||
name='login'
|
name='login'
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
'deconnexion/',
|
'deconnexion/',
|
||||||
views.deconnexion_view,
|
views.deconnexion,
|
||||||
name='deconnexion'
|
name='deconnexion'
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
'employé/',
|
'',
|
||||||
include("gestion_employe.urls")
|
include("gestion_employe.urls")
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
@@ -60,8 +57,6 @@ urlpatterns = [
|
|||||||
'admin/',
|
'admin/',
|
||||||
admin.site.urls
|
admin.site.urls
|
||||||
),
|
),
|
||||||
# path(
|
path("client/", include(client_sirh.get_urls())),
|
||||||
# 'sso',
|
]
|
||||||
# include(server_sso.get_urls())
|
# + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||||
# )
|
|
||||||
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
|
||||||
|
|||||||
@@ -1,37 +1,16 @@
|
|||||||
from django.contrib.auth import authenticate, login, logout
|
from django.contrib.auth import logout
|
||||||
from django.shortcuts import render, redirect
|
from django.shortcuts import redirect
|
||||||
from django.contrib import messages
|
from django.urls import reverse_lazy
|
||||||
|
|
||||||
def login_view(request):
|
from django.conf import settings
|
||||||
"""
|
|
||||||
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.method == 'POST':
|
|
||||||
email = request.POST.get('mail')
|
|
||||||
password = request.POST.get('mot_de_passe')
|
|
||||||
|
|
||||||
if not (email and password):
|
|
||||||
messages.error(request, "Veuillez remplir tous les champs.")
|
|
||||||
return render(request, 'login.html')
|
|
||||||
|
|
||||||
user = authenticate(request, username=email, password=password)
|
def connexion(request):
|
||||||
|
"""Redirige vers le serveur SSO pour l'authentification."""
|
||||||
|
return redirect(reverse_lazy("simple-sso-login"))
|
||||||
|
|
||||||
if user is None:
|
def deconnexion(request):
|
||||||
messages.error(request, "Nom d’utilisateur ou mot de passe incorrect.")
|
"""Gérez la déconnexion des utilisateurs."""
|
||||||
return render(request, 'login.html')
|
|
||||||
|
|
||||||
if not user.is_active:
|
|
||||||
messages.error(request, "Compte inactif. Contactez l'administrateur.")
|
|
||||||
return render(request, 'login.html')
|
|
||||||
|
|
||||||
login(request, user)
|
|
||||||
|
|
||||||
return redirect("gestion_conges:conge")
|
|
||||||
|
|
||||||
return render(request, 'login.html')
|
|
||||||
|
|
||||||
def deconnexion_view(request):
|
|
||||||
"""Gère la déconnexion de l'utilisateur."""
|
|
||||||
logout(request)
|
logout(request)
|
||||||
return redirect('login')
|
#return redirect(settings.SSO_LOGOUT_URL)
|
||||||
|
return redirect("http://authentification.cerfig.org/login")
|
||||||
|
|||||||
7
contexte_universel.py
Normal file
7
contexte_universel.py
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
from decouple import config
|
||||||
|
|
||||||
|
def contexte_universel(request):
|
||||||
|
return {
|
||||||
|
"SIRH_LIEN": config("SIRH_LIEN"),
|
||||||
|
"SGL_LIEN": config("SGL_LIEN")
|
||||||
|
}
|
||||||
Binary file not shown.
Binary file not shown.
@@ -1,5 +1,5 @@
|
|||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from gestion_employe.models import Contrat
|
from gestion_employe.models import Contrat, Employe
|
||||||
from gestion_conge.models import Conge
|
from gestion_conge.models import Conge
|
||||||
|
|
||||||
|
|
||||||
@@ -8,6 +8,11 @@ NOMBRE_PAGINATION = 8
|
|||||||
DEBUT_RAPPEL = 60
|
DEBUT_RAPPEL = 60
|
||||||
DUREE_FIN_CONTRAT = 90
|
DUREE_FIN_CONTRAT = 90
|
||||||
|
|
||||||
|
try:
|
||||||
|
EMAIL_ASSISTANTE_DE_DIRECTION = list(Employe.objects.filter(fonction="assistant_direction").values_list('user__email', flat=True))
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
def solde_conge(employe):
|
def solde_conge(employe):
|
||||||
"""Fonction de calcul du solde de congé restant l'employé"""
|
"""Fonction de calcul du solde de congé restant l'employé"""
|
||||||
contrat = Contrat.objects.filter(employe=employe, statut='actif').order_by('-date_debut').first()
|
contrat = Contrat.objects.filter(employe=employe, statut='actif').order_by('-date_debut').first()
|
||||||
@@ -32,3 +37,25 @@ def solde_conge(employe):
|
|||||||
"quota_annuel": QUOTA_CONGE_ANNUEL - jours_conges_valider,
|
"quota_annuel": QUOTA_CONGE_ANNUEL - jours_conges_valider,
|
||||||
"nombre_jours_valide": jours_conges_valider
|
"nombre_jours_valide": jours_conges_valider
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def envoyer_mail(sujet, message, destinataires):
|
||||||
|
"""Fonction d'envoi de mail"""
|
||||||
|
from django.core.mail import send_mail
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
send_mail(
|
||||||
|
sujet,
|
||||||
|
message,
|
||||||
|
settings.EMAIL_HOST_USER,
|
||||||
|
destinataires,
|
||||||
|
fail_silently=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
def destinataire_mail_demande_conges(employe):
|
||||||
|
"""Fonction de récupération des destinataires pour les mails de demande de congés"""
|
||||||
|
if employe.chef:
|
||||||
|
return EMAIL_ASSISTANTE_DE_DIRECTION
|
||||||
|
else:
|
||||||
|
if employe.departement:
|
||||||
|
chefs_departement = Employe.objects.filter(departement=employe.departement, chef=True)
|
||||||
|
return list(chefs_departement.values_list('user__email', flat=True))
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,4 +1,4 @@
|
|||||||
# Generated by Django 5.2.13 on 2026-04-17 12:03
|
# Generated by Django 5.2.13 on 2026-06-16 11:06
|
||||||
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -3,7 +3,7 @@ const $ = (element) => document.getElementById(element);
|
|||||||
const url_liste_conge_attente = $("liste-demande-conges").dataset.url
|
const url_liste_conge_attente = $("liste-demande-conges").dataset.url
|
||||||
|
|
||||||
const tableau_liste_demande_conge = new Tabulator("#liste-demande-conges", {
|
const tableau_liste_demande_conge = new Tabulator("#liste-demande-conges", {
|
||||||
layout : "fitColumns",
|
// layout : "fitColumns",
|
||||||
columns: [
|
columns: [
|
||||||
{"title": "Nom et Prénom", "field": "prenom_nom"},
|
{"title": "Nom et Prénom", "field": "prenom_nom"},
|
||||||
{"title": "Date de début", "field": "date_debut", formatter:"datetime", formatterParams:{
|
{"title": "Date de début", "field": "date_debut", formatter:"datetime", formatterParams:{
|
||||||
@@ -15,7 +15,7 @@ const tableau_liste_demande_conge = new Tabulator("#liste-demande-conges", {
|
|||||||
outputFormat:"dd/MM/yy",
|
outputFormat:"dd/MM/yy",
|
||||||
}},
|
}},
|
||||||
{"title": "Type de congé", "field": "type"},
|
{"title": "Type de congé", "field": "type"},
|
||||||
{"title": "Date de la demande", "field": "date_demande"},
|
{"title": "Date de la demande", "field": "date_demande", responsive: 1},
|
||||||
{"title": "Validation par supérieur hiérarchique", "field": "validation_hierarchique", formatter:"tickCross", formatterParams :{
|
{"title": "Validation par supérieur hiérarchique", "field": "validation_hierarchique", formatter:"tickCross", formatterParams :{
|
||||||
allowEmpty : true ,
|
allowEmpty : true ,
|
||||||
}},
|
}},
|
||||||
@@ -24,7 +24,7 @@ const tableau_liste_demande_conge = new Tabulator("#liste-demande-conges", {
|
|||||||
}},
|
}},
|
||||||
],
|
],
|
||||||
pagination: true,
|
pagination: true,
|
||||||
paginationSize: 5
|
paginationSize: 5,
|
||||||
})
|
})
|
||||||
|
|
||||||
const bouton_demande_conges = $("bouton-demande-conge");
|
const bouton_demande_conges = $("bouton-demande-conge");
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
<div class="alert alert-{% if message.tags == 'error' %}danger{% else %}success{% endif %}">{{message}}</div>
|
<div class="alert alert-{% if message.tags == 'error' %}danger{% else %}success{% endif %}">{{message}}</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<div class="row d-flex justify-content-center mb-4">
|
<div class="row d-flex justify-content-center mb-4">
|
||||||
<div class="col text-white bg-danger d-flex flex-column justify-content-center align-items-center border rounded p-4">
|
<div class="col text-white bg-danger d-flex flex-column justify-content-center align-items-center border rounded p-4">
|
||||||
<div class="card-header fw-bold">
|
<div class="card-header fw-bold">
|
||||||
@@ -32,11 +33,17 @@
|
|||||||
<h5 class="fw-bold">{{ nombre_conges_valide }}</h5>
|
<h5 class="fw-bold">{{ nombre_conges_valide }}</h5>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex justify-content-between my-4">
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col d-flex justify-content-between align-items-center">
|
||||||
<h3><i class="bi bi-list-ul"></i> Liste des demandes de congé</h3>
|
<h3><i class="bi bi-list-ul"></i> Liste des demandes de congé</h3>
|
||||||
<button class='btn btn-primary' id="bouton-demande-conge">Demande de congé</button>
|
<button class='btn btn-primary' id="bouton-demande-conge">Demande de congé</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="table-responsive">
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
<div id="liste-demande-conges" data-url="{% url 'gestion_conges:liste-des-conges' %}"></div>
|
<div id="liste-demande-conges" data-url="{% url 'gestion_conges:liste-des-conges' %}"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -83,7 +83,6 @@ def index(request):
|
|||||||
Q(validation_hierarchique = True) | Q(validation_hierarchique = False)
|
Q(validation_hierarchique = True) | Q(validation_hierarchique = False)
|
||||||
).order_by('-date_demande')
|
).order_by('-date_demande')
|
||||||
|
|
||||||
|
|
||||||
return render(request, 'gestion_conge/index.html', {
|
return render(request, 'gestion_conge/index.html', {
|
||||||
"nombre_conges_valide": nombre_conges_valide,
|
"nombre_conges_valide": nombre_conges_valide,
|
||||||
"nombre_conges_refuse": nombre_conges_refuse,
|
"nombre_conges_refuse": nombre_conges_refuse,
|
||||||
@@ -123,56 +122,66 @@ def demander_conge(request):
|
|||||||
|
|
||||||
conge_obj.save()
|
conge_obj.save()
|
||||||
messages.success(request, "Votre demande de congé a été enregistrée.")
|
messages.success(request, "Votre demande de congé a été enregistrée.")
|
||||||
|
|
||||||
|
fonctions_utilitaire.envoyer_mail(
|
||||||
|
sujet = "Demande de congé",
|
||||||
|
message = f"""Bonjour {employe.user.first_name} {employe.user.last_name}, votre demande de congé a été enregistrée. Veuillez consulter votre profil pour plus de détails.""",
|
||||||
|
destinataires = fonctions_utilitaire.destinataire_mail_demande_conges() + [employe.user.email]
|
||||||
|
)
|
||||||
|
|
||||||
return redirect("gestion_conges:conge")
|
return redirect("gestion_conges:conge")
|
||||||
|
|
||||||
return redirect("gestion_conges:conge")
|
return redirect("gestion_conges:conge")
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def liste_demande_conges(request):
|
def liste_demande_conges(request):
|
||||||
"""Vue de liste des demandes de congés en attente de validation selon le statut de l'utilisateur actuel"""
|
|
||||||
try:
|
try:
|
||||||
employe = Employe.objects.get(user__username = request.user)
|
employe = Employe.objects.get(user=request.user)
|
||||||
except Employe.DoesNotExist:
|
except Employe.DoesNotExist:
|
||||||
return JsonResponse({
|
return JsonResponse({
|
||||||
"success": False,
|
"success": False,
|
||||||
"message": "Votre profil Utilisateur n'est lié à aucun profil Employé. Veuillez contacter l'administrateur."
|
"message": "Profil employé introuvable"
|
||||||
})
|
})
|
||||||
|
|
||||||
try:
|
affectation = Affectation.objects.filter(
|
||||||
affectation = Affectation.objects.get(
|
|
||||||
employe=employe,
|
employe=employe,
|
||||||
date_fin_daffectation__gte=timezone.now().date()
|
date_fin_daffectation__gte=timezone.now().date()
|
||||||
)
|
).first()
|
||||||
except Affectation.DoesNotExist:
|
|
||||||
affectation = None
|
is_direction = employe.user.groups.filter(name='direction').exists()
|
||||||
|
|
||||||
if employe.chef:
|
if employe.chef:
|
||||||
print("chef")
|
|
||||||
conges_en_attente = Conge.objects.filter(
|
conges = Conge.objects.filter(
|
||||||
employe__departement = employe.departement,
|
Q(employe__departement=employe.departement) |
|
||||||
validation_hierarchique = None
|
Q(employe=employe)
|
||||||
).order_by('-date_demande')
|
).order_by('-date_demande')
|
||||||
|
|
||||||
elif affectation and affectation.role == "chef_projet":
|
elif affectation and affectation.role == "chef_projet":
|
||||||
|
|
||||||
employes_du_projet = Affectation.objects.filter(
|
employes_du_projet = Affectation.objects.filter(
|
||||||
projet=affectation.projet,
|
projet=affectation.projet,
|
||||||
date_fin_daffectation__gte=timezone.now().date()
|
date_fin_daffectation__gte=timezone.now().date()
|
||||||
).values('employe')
|
).values_list('employe', flat=True)
|
||||||
|
|
||||||
conges_en_attente = Conge.objects.filter(
|
conges = Conge.objects.filter(
|
||||||
employe__in = employes_du_projet,
|
Q(employe__in=employes_du_projet) |
|
||||||
validation_hierarchique = None
|
Q(employe=employe)
|
||||||
).order_by('-date_demande')
|
).order_by('-date_demande')
|
||||||
|
|
||||||
elif 'direction' in employe.user.groups.values_list('name', flat=True):
|
|
||||||
conges_en_attente = Conge.objects.filter(
|
elif is_direction:
|
||||||
validation_hierarchique = True,
|
|
||||||
validation_direction = None
|
conges = Conge.objects.filter(
|
||||||
).order_by('-date_demande')
|
Q(validation_hierarchique=True) |
|
||||||
|
Q(employe__user__groups__name='direction')
|
||||||
|
).distinct().order_by('-date_demande')
|
||||||
|
|
||||||
else:
|
else:
|
||||||
conges_en_attente = Conge.objects.filter(
|
|
||||||
employe__user__username = request.user
|
conges = Conge.objects.filter(
|
||||||
|
employe=employe
|
||||||
).order_by('-date_demande')
|
).order_by('-date_demande')
|
||||||
|
|
||||||
return JsonResponse({
|
return JsonResponse({
|
||||||
@@ -186,9 +195,9 @@ def liste_demande_conges(request):
|
|||||||
"type": dict(conge.TYPE_CHOICES).get(conge.type),
|
"type": dict(conge.TYPE_CHOICES).get(conge.type),
|
||||||
"solde_conge": fonctions_utilitaire.solde_conge(conge.employe)["quota_annuel"]
|
"solde_conge": fonctions_utilitaire.solde_conge(conge.employe)["quota_annuel"]
|
||||||
}
|
}
|
||||||
for conge in conges_en_attente]},
|
for conge in conges
|
||||||
safe=False
|
]
|
||||||
)
|
})
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def validation_de_conge(request):
|
def validation_de_conge(request):
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user