mirror of
https://github.com/JMP-MS/ASPIC.git
synced 2026-10-27 16:07:10 +00:00
V 1.004 ToDoList et Journal découpé
This commit is contained in:
+280
@@ -0,0 +1,280 @@
|
||||
<?php
|
||||
/**
|
||||
* ASPIC — todolist.php
|
||||
* API CRUD sur ASP_ToDoList (GET liste triée par urgence + fiche / POST
|
||||
* création / PUT modification / DELETE suppression logique).
|
||||
*
|
||||
* Affichage volontairement non filtré par utilisateur (voir journal de
|
||||
* développement) : un agent IA pourrait ajouter une tâche pour un autre
|
||||
* utilisateur, même en usage mono-utilisateur — toutes les tâches actives
|
||||
* sont donc renvoyées, quel que soit TDL_ToDoUser.
|
||||
*
|
||||
* Tri par urgence (calculé ici plutôt qu'en SQL, pour rester lisible — voir
|
||||
* journal) : trois groupes, dans cet ordre —
|
||||
* 0 = rouge : non réalisée, sans date de réalisation souhaitée OU date
|
||||
* dépassée ("à faire tout de suite" et "en retard" partagent
|
||||
* le même groupe — une tâche sans échéance est jugée aussi
|
||||
* urgente qu'une tâche en retard, décision de Jean-Marc).
|
||||
* 1 = orange : non réalisée, date de réalisation souhaitée renseignée et
|
||||
* pas encore dépassée.
|
||||
* 2 = vert : réalisée (TDL_RealDate renseignée), qu'elle ait été faite
|
||||
* en retard ou non.
|
||||
* Sous-tri : dans le groupe rouge, TDL_ToDoDateSouhaitée croissante avec les
|
||||
* tâches sans date en tête (NULL trié avant toute date, comportement natif
|
||||
* de la comparaison PHP utilisé ici), puis TDL_ToDoDate croissante en cas
|
||||
* d'égalité (le cas le plus courant : deux tâches "à faire tout de suite",
|
||||
* donc sans date souhaitée toutes les deux — la plus anciennement notée
|
||||
* remonte en premier) ; dans le groupe orange, échéance la plus proche en
|
||||
* premier, TDL_ToDoDate en second critère ; dans le groupe vert,
|
||||
* réalisation la plus récente en premier.
|
||||
*
|
||||
* GET ?id=<TDL_Incr> : une tâche active.
|
||||
* GET (sans id) : toutes les tâches actives, triées par urgence.
|
||||
* POST : création. Tous les champs sont saisissables dès la
|
||||
* création, y compris les champs de réalisation (TDL_RealDate/
|
||||
* TDL_RealUser/TDL_RealText) — permet de journaliser une tâche déjà
|
||||
* faite, pour en garder une trace (demande explicite de Jean-Marc).
|
||||
* TDL_ToDoDate est initialisée au jour de saisie par défaut (colonne
|
||||
* DEFAULT CURRENT_TIMESTAMP, laissée à MySQL si absente du corps de la
|
||||
* requête), mais reste éditable : Jean-Marc doit pouvoir noter
|
||||
* aujourd'hui une tâche oubliée en la datant rétroactivement à son vrai
|
||||
* jour d'apparition, pour qu'elle se classe correctement (voir le tri du
|
||||
* groupe rouge ci-dessous). TDL_ToDoUser est saisi par le client mais
|
||||
* retombe sur l'utilisateur de la session si absent.
|
||||
* PUT ?id=<TDL_Incr> : modification, tous les champs sont modifiables
|
||||
* (y compris TDL_ToDoDate et les champs de réalisation — c'est ainsi
|
||||
* qu'une tâche se marque "réalisée", pas d'action contextuelle séparée
|
||||
* pour ça). TDL_ToDoDate n'est écrasée que si explicitement fournie
|
||||
* (jamais remise à vide).
|
||||
* DELETE ?id=<TDL_Incr> : suppression logique (TDL_Actif = 0). Contrairement
|
||||
* à la suppression d'un contact, aucun commentaire n'est demandé ici :
|
||||
* ASP_ToDoList n'a pas d'équivalent d'ASP_Realisations pour journaliser
|
||||
* un commentaire de suppression avec horodatage/auteur — l'ajouter
|
||||
* obligerait à inventer une table d'audit dédiée pour ce seul usage,
|
||||
* non demandé à ce stade (voir journal, principe "pas de
|
||||
* sur-ingénierie").
|
||||
*
|
||||
* Session utilisateur : accès réservé aux utilisateurs identifiés, même
|
||||
* principe que contacts.php/realisations.php.
|
||||
*/
|
||||
|
||||
session_start();
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
require __DIR__ . '/db.php';
|
||||
|
||||
if (empty($_SESSION['USR_Code'])) {
|
||||
http_response_code(401);
|
||||
echo json_encode(['error' => 'Non identifié — veuillez vous connecter.']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$method = $_SERVER['REQUEST_METHOD'];
|
||||
|
||||
try {
|
||||
$pdo = getDbConnection();
|
||||
} catch (PDOException $e) {
|
||||
http_response_code(500);
|
||||
echo json_encode(['error' => 'Connexion base de données impossible']);
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calcule le groupe d'urgence (0 rouge / 1 orange / 2 vert) d'une tâche.
|
||||
*/
|
||||
function calculerGroupe(array $t, string $aujourdhui): int
|
||||
{
|
||||
if ($t['TDL_RealDate'] !== null) {
|
||||
return 2;
|
||||
}
|
||||
if ($t['TDL_ToDoDateSouhaitée'] === null || $t['TDL_ToDoDateSouhaitée'] < $aujourdhui) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare deux dates (chaînes "YYYY-MM-DD" ou null), null se classant avant
|
||||
* toute date — utilisé pour le sous-tri du groupe rouge (une tâche sans
|
||||
* échéance passe avant une tâche en retard avec échéance connue).
|
||||
*/
|
||||
function comparerDateNullEnPremier(?string $a, ?string $b): int
|
||||
{
|
||||
if ($a === $b) return 0;
|
||||
if ($a === null) return -1;
|
||||
if ($b === null) return 1;
|
||||
return strcmp($a, $b);
|
||||
}
|
||||
|
||||
try {
|
||||
switch ($method) {
|
||||
case 'GET':
|
||||
if (isset($_GET['id'])) {
|
||||
$stmt = $pdo->prepare('SELECT * FROM ASP_ToDoList WHERE TDL_Incr = ? AND TDL_Actif = 1');
|
||||
$stmt->execute([$_GET['id']]);
|
||||
$tache = $stmt->fetch();
|
||||
if (!$tache) {
|
||||
http_response_code(404);
|
||||
echo json_encode(['error' => 'Tâche introuvable']);
|
||||
exit;
|
||||
}
|
||||
echo json_encode($tache);
|
||||
exit;
|
||||
}
|
||||
|
||||
$stmt = $pdo->query('SELECT * FROM ASP_ToDoList WHERE TDL_Actif = 1');
|
||||
$taches = $stmt->fetchAll();
|
||||
|
||||
$aujourdhui = date('Y-m-d');
|
||||
foreach ($taches as &$t) {
|
||||
$t['TDL_Groupe'] = calculerGroupe($t, $aujourdhui);
|
||||
}
|
||||
unset($t);
|
||||
|
||||
usort($taches, function ($a, $b) {
|
||||
if ($a['TDL_Groupe'] !== $b['TDL_Groupe']) {
|
||||
return $a['TDL_Groupe'] <=> $b['TDL_Groupe'];
|
||||
}
|
||||
if ($a['TDL_Groupe'] === 0) {
|
||||
$cmp = comparerDateNullEnPremier($a['TDL_ToDoDateSouhaitée'], $b['TDL_ToDoDateSouhaitée']);
|
||||
if ($cmp !== 0) return $cmp;
|
||||
// À échéance égale (souvent : aucune échéance des deux
|
||||
// côtés), la tâche notée le plus tôt remonte en premier.
|
||||
return strcmp((string)$a['TDL_ToDoDate'], (string)$b['TDL_ToDoDate']);
|
||||
}
|
||||
if ($a['TDL_Groupe'] === 1) {
|
||||
$cmp = strcmp((string)$a['TDL_ToDoDateSouhaitée'], (string)$b['TDL_ToDoDateSouhaitée']);
|
||||
if ($cmp !== 0) return $cmp;
|
||||
return strcmp((string)$a['TDL_ToDoDate'], (string)$b['TDL_ToDoDate']);
|
||||
}
|
||||
// Groupe 2 (vert) : réalisation la plus récente en premier.
|
||||
return strcmp((string)$b['TDL_RealDate'], (string)$a['TDL_RealDate']);
|
||||
});
|
||||
|
||||
echo json_encode(['taches' => $taches, 'total' => count($taches)]);
|
||||
break;
|
||||
|
||||
case 'POST':
|
||||
$data = json_decode(file_get_contents('php://input'), true) ?? [];
|
||||
$texte = trim($data['TDL_ToDoTxt'] ?? '');
|
||||
if ($texte === '') {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Le texte de la tâche est obligatoire']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$todoUser = trim($data['TDL_ToDoUser'] ?? '');
|
||||
if ($todoUser === '') {
|
||||
$todoUser = $_SESSION['USR_Code'];
|
||||
}
|
||||
|
||||
// TDL_ToDoDate : incluse dans l'INSERT seulement si fournie par le
|
||||
// client (permet de dater rétroactivement une tâche oubliée) —
|
||||
// sinon on laisse MySQL appliquer DEFAULT CURRENT_TIMESTAMP
|
||||
// (aujourd'hui), plutôt que de dupliquer cette valeur par défaut
|
||||
// ici en PHP.
|
||||
$colonnes = ['TDL_ToDoUser', 'TDL_ToDoTxt', 'TDL_ToDoDateSouhaitée', 'TDL_RealDate', 'TDL_RealUser', 'TDL_RealText'];
|
||||
$params = [
|
||||
$todoUser,
|
||||
$texte,
|
||||
$data['TDL_ToDoDateSouhaitée'] ?? null ?: null,
|
||||
$data['TDL_RealDate'] ?? null ?: null,
|
||||
$data['TDL_RealUser'] ?? null ?: null,
|
||||
$data['TDL_RealText'] ?? null ?: null,
|
||||
];
|
||||
if (!empty($data['TDL_ToDoDate'])) {
|
||||
$colonnes[] = 'TDL_ToDoDate';
|
||||
$params[] = $data['TDL_ToDoDate'];
|
||||
}
|
||||
$placeholders = array_fill(0, count($colonnes), '?');
|
||||
|
||||
$stmt = $pdo->prepare(
|
||||
'INSERT INTO ASP_ToDoList (' . implode(', ', $colonnes) . ')
|
||||
VALUES (' . implode(', ', $placeholders) . ')'
|
||||
);
|
||||
$stmt->execute($params);
|
||||
|
||||
echo json_encode(['id' => (int) $pdo->lastInsertId()]);
|
||||
break;
|
||||
|
||||
case 'PUT':
|
||||
if (!isset($_GET['id'])) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'id manquant']);
|
||||
exit;
|
||||
}
|
||||
$data = json_decode(file_get_contents('php://input'), true) ?? [];
|
||||
$texte = trim($data['TDL_ToDoTxt'] ?? '');
|
||||
if ($texte === '') {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Le texte de la tâche est obligatoire']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Vérification d'existence séparée de l'UPDATE (même précaution
|
||||
// que contacts.php : rowCount() ne reflète que les lignes
|
||||
// réellement modifiées, pas les lignes trouvées par le WHERE).
|
||||
$verif = $pdo->prepare('SELECT TDL_Incr FROM ASP_ToDoList WHERE TDL_Incr = ? AND TDL_Actif = 1');
|
||||
$verif->execute([$_GET['id']]);
|
||||
if (!$verif->fetch()) {
|
||||
http_response_code(404);
|
||||
echo json_encode(['error' => 'Tâche introuvable ou déjà désactivée']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$todoUser = trim($data['TDL_ToDoUser'] ?? '');
|
||||
if ($todoUser === '') {
|
||||
$todoUser = $_SESSION['USR_Code'];
|
||||
}
|
||||
|
||||
$assignations = ['TDL_ToDoUser = ?', 'TDL_ToDoTxt = ?', 'TDL_ToDoDateSouhaitée = ?',
|
||||
'TDL_RealDate = ?', 'TDL_RealUser = ?', 'TDL_RealText = ?'];
|
||||
$params = [
|
||||
$todoUser,
|
||||
$texte,
|
||||
$data['TDL_ToDoDateSouhaitée'] ?? null ?: null,
|
||||
$data['TDL_RealDate'] ?? null ?: null,
|
||||
$data['TDL_RealUser'] ?? null ?: null,
|
||||
$data['TDL_RealText'] ?? null ?: null,
|
||||
];
|
||||
// TDL_ToDoDate : n'est écrasée que si explicitement fournie —
|
||||
// jamais remise à vide (contrairement aux autres champs, une date
|
||||
// de création n'a pas de sens "effacée").
|
||||
if (!empty($data['TDL_ToDoDate'])) {
|
||||
$assignations[] = 'TDL_ToDoDate = ?';
|
||||
$params[] = $data['TDL_ToDoDate'];
|
||||
}
|
||||
$params[] = $_GET['id'];
|
||||
|
||||
$stmt = $pdo->prepare(
|
||||
'UPDATE ASP_ToDoList SET ' . implode(', ', $assignations) . ' WHERE TDL_Incr = ? AND TDL_Actif = 1'
|
||||
);
|
||||
$stmt->execute($params);
|
||||
|
||||
echo json_encode(['success' => true]);
|
||||
break;
|
||||
|
||||
case 'DELETE':
|
||||
if (!isset($_GET['id'])) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'id manquant']);
|
||||
exit;
|
||||
}
|
||||
$stmt = $pdo->prepare('UPDATE ASP_ToDoList SET TDL_Actif = 0 WHERE TDL_Incr = ? AND TDL_Actif = 1');
|
||||
$stmt->execute([$_GET['id']]);
|
||||
|
||||
if ($stmt->rowCount() === 0) {
|
||||
http_response_code(404);
|
||||
echo json_encode(['error' => 'Tâche introuvable ou déjà désactivée']);
|
||||
exit;
|
||||
}
|
||||
echo json_encode(['success' => true]);
|
||||
break;
|
||||
|
||||
default:
|
||||
http_response_code(405);
|
||||
echo json_encode(['error' => 'Méthode non autorisée']);
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
http_response_code(500);
|
||||
echo json_encode(['error' => 'Erreur base de données : ' . $e->getMessage()]);
|
||||
}
|
||||
Reference in New Issue
Block a user