Files
pta/database/migration_v7_8_securite_acces.sql
PTA 66cc8c8ade Base de travail V7.8 reprise du répertoire de travail
Commit technique : reproduit à l'identique l'état non commité de la copie
de travail (sécurisation V7.8, CSP à nonce, Session, migration des droits)
afin que le travail d'ergonomie qui suit soit isolable.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 16:32:10 +02:00

202 lines
8.2 KiB
SQL

-- ============================================================================
-- PTA V7.8 — Sécurisation : les règles d'accès descendent en base
-- ============================================================================
-- À exécuter UNE SEULE FOIS sur une base PTA V7.7 existante :
-- SOURCE database/migration_v7_8_securite_acces.sql;
--
-- Objectif : plus aucune règle de périmètre ni de droit n'est reconstruite en
-- PHP. Le contrôleur pose une question à la base, la base répond oui ou non.
-- Toute évolution des droits se fait désormais en SQL, sans redéploiement.
-- ============================================================================
-- ----------------------------------------------------------------------------
-- 1. MATRICE DES DROITS : rôle -> pages et rôle -> permissions
-- ----------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS acces_role_page (
role ENUM('AGENT', 'RESPONSABLE_STRUCTURE', 'SERVICE_ENFANCE') NOT NULL,
page VARCHAR(50) NOT NULL,
ordre_affichage SMALLINT UNSIGNED NOT NULL DEFAULT 100,
PRIMARY KEY (role, page)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS acces_role_permission (
role ENUM('AGENT', 'RESPONSABLE_STRUCTURE', 'SERVICE_ENFANCE') NOT NULL,
permission VARCHAR(50) NOT NULL,
autorise BOOLEAN NOT NULL DEFAULT FALSE,
PRIMARY KEY (role, permission)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- Pages autorisées — reprise à l'identique des droits V7.7.
INSERT INTO acces_role_page (role, page, ordre_affichage) VALUES
('AGENT', 'agents', 10),
('AGENT', 'structures', 20),
('RESPONSABLE_STRUCTURE', 'planning', 10),
('RESPONSABLE_STRUCTURE', 'structures', 20),
('RESPONSABLE_STRUCTURE', 'agents', 30),
('RESPONSABLE_STRUCTURE', 'coverage', 40),
('SERVICE_ENFANCE', 'planning', 10),
('SERVICE_ENFANCE', 'pending', 20),
('SERVICE_ENFANCE', 'coverage', 30),
('SERVICE_ENFANCE', 'structures', 40),
('SERVICE_ENFANCE', 'agents', 50),
('SERVICE_ENFANCE', 'annual', 60),
('SERVICE_ENFANCE', 'pta', 70),
('SERVICE_ENFANCE', 'teams', 80),
('SERVICE_ENFANCE', 'vacations', 90),
('SERVICE_ENFANCE', 'administration', 100)
ON DUPLICATE KEY UPDATE ordre_affichage = VALUES(ordre_affichage);
-- Permissions fonctionnelles — reprise à l'identique des droits V7.7.
INSERT INTO acces_role_permission (role, permission, autorise) VALUES
('AGENT', 'read_only', TRUE),
('AGENT', 'can_edit_draft', FALSE),
('AGENT', 'can_edit_cross_structure', FALSE),
('AGENT', 'can_validate', FALSE),
('AGENT', 'can_reopen', FALSE),
('AGENT', 'can_use_templates', FALSE),
('AGENT', 'can_copy_full_week', FALSE),
('AGENT', 'can_view_pending', FALSE),
('AGENT', 'can_manage_coverage', FALSE),
('AGENT', 'can_manage_agents', FALSE),
('AGENT', 'can_manage_structures', FALSE),
('AGENT', 'can_manage_vacations', FALSE),
('AGENT', 'can_manage_teams', FALSE),
('AGENT', 'can_manage_pta', FALSE),
('AGENT', 'can_forecast_next_year', FALSE),
('RESPONSABLE_STRUCTURE', 'read_only', FALSE),
('RESPONSABLE_STRUCTURE', 'can_edit_draft', TRUE),
('RESPONSABLE_STRUCTURE', 'can_edit_cross_structure', FALSE),
('RESPONSABLE_STRUCTURE', 'can_validate', FALSE),
('RESPONSABLE_STRUCTURE', 'can_reopen', TRUE),
('RESPONSABLE_STRUCTURE', 'can_use_templates', FALSE),
('RESPONSABLE_STRUCTURE', 'can_copy_full_week', FALSE),
('RESPONSABLE_STRUCTURE', 'can_view_pending', FALSE),
('RESPONSABLE_STRUCTURE', 'can_manage_coverage', FALSE),
('RESPONSABLE_STRUCTURE', 'can_manage_agents', FALSE),
('RESPONSABLE_STRUCTURE', 'can_manage_structures', FALSE),
('RESPONSABLE_STRUCTURE', 'can_manage_vacations', FALSE),
('RESPONSABLE_STRUCTURE', 'can_manage_teams', FALSE),
('RESPONSABLE_STRUCTURE', 'can_manage_pta', FALSE),
('RESPONSABLE_STRUCTURE', 'can_forecast_next_year', FALSE),
('SERVICE_ENFANCE', 'read_only', FALSE),
('SERVICE_ENFANCE', 'can_edit_draft', TRUE),
('SERVICE_ENFANCE', 'can_edit_cross_structure', TRUE),
('SERVICE_ENFANCE', 'can_validate', TRUE),
('SERVICE_ENFANCE', 'can_reopen', TRUE),
('SERVICE_ENFANCE', 'can_use_templates', TRUE),
('SERVICE_ENFANCE', 'can_copy_full_week', TRUE),
('SERVICE_ENFANCE', 'can_view_pending', TRUE),
('SERVICE_ENFANCE', 'can_manage_coverage', TRUE),
('SERVICE_ENFANCE', 'can_manage_agents', TRUE),
('SERVICE_ENFANCE', 'can_manage_structures', TRUE),
('SERVICE_ENFANCE', 'can_manage_vacations', TRUE),
('SERVICE_ENFANCE', 'can_manage_teams', TRUE),
('SERVICE_ENFANCE', 'can_manage_pta', TRUE),
('SERVICE_ENFANCE', 'can_forecast_next_year', TRUE)
ON DUPLICATE KEY UPDATE autorise = VALUES(autorise);
-- ----------------------------------------------------------------------------
-- 2. VUES DE DROITS
-- ----------------------------------------------------------------------------
CREATE OR REPLACE VIEW v_acces_role_page AS
SELECT role, page, ordre_affichage
FROM acces_role_page;
CREATE OR REPLACE VIEW v_acces_role_permission AS
SELECT role, permission, autorise
FROM acces_role_permission;
-- ----------------------------------------------------------------------------
-- 3. VUES D'IDENTITÉ
-- ----------------------------------------------------------------------------
-- Identité complète d'un agent actif : sert à valider la sélection de rôle et
-- à construire le bandeau de profil. Un agent inactif n'apparaît jamais ici,
-- il ne peut donc pas être choisi comme identité.
CREATE OR REPLACE VIEW v_acces_identite_agent AS
SELECT
a.id_agent,
a.matricule,
a.nom,
a.prenom,
a.id_structure,
s.nom AS structure_nom,
s.code AS structure_code
FROM agent a
LEFT JOIN structure s
ON s.id_structure = a.id_structure
AND s.actif = TRUE
WHERE a.actif = TRUE;
-- Lieux d'affectation sélectionnables par un responsable de structure.
CREATE OR REPLACE VIEW v_acces_identite_structure AS
SELECT
s.id_structure,
s.code,
s.nom,
s.type_affectation
FROM structure s
WHERE s.actif = TRUE;
-- ----------------------------------------------------------------------------
-- 4. VUES DE PÉRIMÈTRE
-- ----------------------------------------------------------------------------
-- Quels agents un lieu d'affectation a-t-il le droit de consulter ?
-- Deux origines : le rattachement principal, ou une planification effective
-- sur ce lieu. C'est la règle exacte que le PHP reconstruisait à la main.
CREATE OR REPLACE VIEW v_acces_agent_par_structure AS
SELECT DISTINCT
a.id_agent,
a.id_structure AS id_structure_autorisee,
'RATTACHEMENT' AS origine
FROM agent a
WHERE a.actif = TRUE
AND a.id_structure IS NOT NULL
UNION
SELECT DISTINCT
a.id_agent,
p.id_structure AS id_structure_autorisee,
'PLANIFICATION' AS origine
FROM agent a
INNER JOIN planning p ON p.id_agent = a.id_agent
WHERE a.actif = TRUE;
-- Périmètre d'un créneau : à quel lieu et à quel planning appartient-il ?
-- Utilisé avant toute modification ou suppression d'affectation.
CREATE OR REPLACE VIEW v_acces_perimetre_creneau AS
SELECT
c.id_creneau,
c.id_planning,
p.id_structure,
p.id_agent,
p.statut AS statut_planning,
s.nom AS structure_nom
FROM creneau_horaire c
INNER JOIN planning p ON p.id_planning = c.id_planning
INNER JOIN structure s ON s.id_structure = p.id_structure;
-- Périmètre d'un planning : utilisé avant validation ou réouverture.
CREATE OR REPLACE VIEW v_acces_perimetre_planning AS
SELECT
p.id_planning,
p.id_structure,
p.id_agent,
p.statut AS statut_planning,
s.nom AS structure_nom,
a.nom AS agent_nom,
a.prenom AS agent_prenom
FROM planning p
INNER JOIN structure s ON s.id_structure = p.id_structure
INNER JOIN agent a ON a.id_agent = p.id_agent;
-- ============================================================================
-- Vérification recommandée après import :
-- SELECT role, COUNT(*) FROM acces_role_page GROUP BY role;
-- SELECT * FROM v_acces_agent_par_structure LIMIT 10;
-- ============================================================================