labfy-investigation/docs/tickets/closed/TICKET-032.md
2026-07-17 10:05:29 +02:00

537 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Ticket #032 — Factoriser le chargement et linstallation dune enquête
## Contexte
Après le ticket #031.1, lapplication sait :
- créer une enquête ;
- ouvrir une enquête existante ;
- remplacer la session active ;
- fermer proprement lapplication.
Cependant, les flux « Nouvelle enquête » et « Ouvrir une enquête » dupliquent encore une partie importante de la logique :
```text
investigation_session_open()
→ récupération du projet
→ récupération du chemin racine
→ investigation_tree_builder_build()
→ application_install_session()
→ nettoyage en cas déchec
```
Cette duplication augmentera avec les futures fonctions :
- enquêtes récentes ;
- ouverture depuis la ligne de commande ;
- restauration de session ;
- ouverture depuis un rapport ou une archive.
## Objectif
Créer dans `src/core/application.c` une fonction interne unique qui ouvre et installe une enquête à partir de son dossier racine.
Contrat attendu :
```c
static gboolean application_open_and_install_investigation(
Application *application,
const char *root_path,
GError **error
);
```
Cette fonction doit garantir :
```text
succès :
Application devient propriétaire de la nouvelle session
Application devient propriétaire du nouvel arbre
ancienne session libérée
ancien arbre libéré
fenêtre mise à jour
échec :
ancienne session conservée
ancien arbre conservé
nouvelle session libérée
nouvel arbre libéré
erreur transmise à lappelant
```
---
# Travail à réaliser
## 1. Ajouter un domaine derreur privé
Dans `src/core/application.c`, ajouter un domaine derreur uniquement utilisé par le contrôleur.
Exemple :
```c
typedef enum
{
APPLICATION_OPEN_ERROR_INVALID_ARGUMENT,
APPLICATION_OPEN_ERROR_INVALID_PROJECT,
APPLICATION_OPEN_ERROR_TREE_BUILD,
APPLICATION_OPEN_ERROR_INSTALL
} ApplicationOpenError;
```
Ajouter :
```c
#define APPLICATION_OPEN_ERROR \
application_open_error_quark()
```
Puis :
```c
static GQuark application_open_error_quark(void)
{
return g_quark_from_static_string(
"labfy-investigation-application-open-error"
);
}
```
Le domaine reste privé à `application.c`.
---
## 2. Créer la fonction factorisée
Ajouter :
```c
static gboolean application_open_and_install_investigation(
Application *application,
const char *root_path,
GError **error
);
```
La fonction doit :
1. valider `application` ;
2. valider `application->main_window` ;
3. valider `root_path` ;
4. ouvrir une nouvelle `InvestigationSession` ;
5. récupérer son `InvestigationProject` ;
6. récupérer le chemin racine canonique ;
7. construire un nouvel `InvestigationTreeModel` ;
8. appeler `application_install_session()` ;
9. transférer la propriété uniquement en cas de succès.
### Règle de propriété
Avant `application_install_session()` :
```text
la fonction possède new_session
la fonction possède new_tree_model
```
Après succès :
```text
Application possède new_session
Application possède new_tree_model
```
Après échec :
```text
la fonction doit libérer les objets quelle possède encore
```
### Validation de `GError`
La fonction doit respecter la convention GLib :
```c
g_return_val_if_fail(
error == NULL || *error == NULL,
FALSE
);
```
Lutilisation de `g_return_val_if_fail()` est acceptable ici pour vérifier le contrat du développeur.
Les erreurs utilisateur doivent être produites avec :
```c
g_set_error()
g_set_error_literal()
g_propagate_prefixed_error()
```
---
## 3. Propager lerreur de `InvestigationSession`
Si :
```c
investigation_session_open()
```
échoue, la fonction doit conserver lerreur métier dorigine et lui ajouter du contexte.
Exemple conceptuel :
```text
Impossible douvrir lenquête : la base SQLite est absente
```
Ne pas remplacer lerreur précise par un simple :
```text
Erreur inconnue
```
lorsquun `GError` est disponible.
---
## 4. Refactoriser louverture dune enquête existante
`application_on_folder_selected()` ne doit plus contenir directement :
```c
investigation_session_open()
investigation_tree_builder_build()
application_install_session()
```
Elle doit seulement :
1. accepter lannulation ;
2. appeler `application_open_and_install_investigation()` ;
3. journaliser lerreur ;
4. libérer le `GError`.
Structure attendue :
```c
static void application_on_folder_selected(
const char *folder_path,
gpointer user_data
)
{
Application *application = user_data;
GError *error = NULL;
if (application == NULL ||
folder_path == NULL)
{
return;
}
if (!application_open_and_install_investigation(
application,
folder_path,
&error
))
{
g_warning(
"Impossible d'ouvrir l'enquête '%s' : %s",
folder_path,
error != NULL
? error->message
: "erreur inconnue"
);
g_clear_error(&error);
}
}
```
Lannulation ne doit pas produire de warning.
---
## 5. Refactoriser la création dune enquête
`application_on_create_investigation()` doit conserver uniquement :
1. la création physique du projet ;
2. lappel à la fonction factorisée ;
3. le message spécifique indiquant que le projet existe sur le disque si son ouverture échoue.
Le flux devient :
```text
investigation_project_create()
→ application_open_and_install_investigation()
```
La fonction ne doit plus reconstruire elle-même :
```text
session
projet
chemin canonique
arbre
installation
```
En cas déchec après création, le dossier créé reste volontairement sur le disque.
Le message doit être explicite :
```text
Lenquête a été créée dans « ... », mais son ouverture a échoué : ...
```
---
## 6. Ne pas modifier `application_install_session()`
Cette fonction conserve sa responsabilité actuelle :
- valider les objets prêts à installer ;
- libérer lancien état ;
- transférer la propriété ;
- mettre à jour `MainWindow`.
Le nouveau helper prépare les objets.
`application_install_session()` réalise le remplacement final.
---
# Pseudo-code de la fonction factorisée
```c
static gboolean application_open_and_install_investigation(
Application *application,
const char *root_path,
GError **error
)
{
InvestigationSession *new_session = NULL;
InvestigationTreeModel *new_tree_model = NULL;
const InvestigationProject *project = NULL;
const char *canonical_root_path = NULL;
GError *session_error = NULL;
valider les arguments;
new_session = investigation_session_open(
root_path,
&session_error
);
si échec :
propager session_error avec contexte;
return FALSE;
project = investigation_session_get_project(
new_session
);
valider project;
canonical_root_path =
investigation_project_get_root_path(project);
valider canonical_root_path;
new_tree_model =
investigation_tree_builder_build(
canonical_root_path
);
si échec :
produire GError;
fermer new_session;
return FALSE;
si application_install_session() échoue :
produire GError;
libérer new_tree_model;
fermer new_session;
return FALSE;
return TRUE;
}
```
---
# Tests manuels
## Création valide
1. lancer lapplication ;
2. créer une enquête ;
3. vérifier le titre ;
4. vérifier la barre détat ;
5. vérifier larborescence.
## Ouverture valide
1. fermer et relancer ;
2. ouvrir lenquête créée ;
3. vérifier le même résultat.
## Remplacement valide
1. ouvrir une enquête A ;
2. ouvrir une enquête B ;
3. vérifier que B remplace A.
## Échec douverture
1. ouvrir une enquête valide A ;
2. tenter douvrir un dossier invalide ;
3. vérifier que A reste active ;
4. vérifier que lerreur est journalisée.
## Échec après création
Provoquer si possible un échec douverture après création.
Vérifier :
- le dossier créé reste présent ;
- lancienne session reste active ;
- aucun double `free` ;
- aucun crash.
## Annulation
Annuler le sélecteur de dossier.
Vérifier :
- aucun warning ;
- aucun changement détat ;
- aucun crash.
---
# Critères dacceptation
- [ ] Une seule fonction ouvre une session et construit son arbre.
- [ ] La création utilise cette fonction.
- [ ] Louverture utilise cette fonction.
- [ ] `application_install_session()` nest pas dupliquée.
- [ ] Lancienne session reste active en cas déchec.
- [ ] Lancien arbre reste actif en cas déchec.
- [ ] Les nouveaux objets sont libérés en cas déchec.
- [ ] Les erreurs de `InvestigationSession` sont propagées.
- [ ] Lannulation ne produit pas derreur.
- [ ] Aucun code SQLite direct nest ajouté.
- [ ] Aucun comportement GTK visible nest cassé.
- [ ] `make` réussit.
- [ ] `make test` réussit.
- [ ] `git diff --check` ne retourne aucune erreur.
---
# Audit attendu
La logique douverture ne doit apparaître quune seule fois :
```bash
rg -n \
'investigation_session_open|investigation_tree_builder_build' \
src/core/application.c
```
Résultat attendu :
```text
une occurrence de investigation_session_open
une occurrence de investigation_tree_builder_build
```
La création et louverture doivent appeler le helper :
```bash
rg -n \
'application_open_and_install_investigation' \
src/core/application.c
```
Vérifier labsence de SQLite direct :
```bash
rg -n \
'sqlite3_|#include <sqlite3.h>' \
src/core/application.c
```
Résultat attendu :
```text
aucune sortie
```
Vérifier le format :
```bash
git diff --check
```
---
# Fichiers concernés
```text
src/core/application.c
```
Aucune modification publique nest normalement nécessaire dans :
```text
include/core/application.h
```
---
# Commit attendu
```bash
make clean
make
make test
git diff --check
git status --short
```
```bash
git add src/core/application.c
```
```bash
git diff --cached --stat
git diff --cached
```
```bash
git commit -m "refactor(core): centralize investigation loading"
git push
```
---
# Résultat attendu
Après ce ticket, tous les futurs points dentrée utiliseront le même flux :
```text
Création
Ouverture manuelle
Enquêtes récentes
Ligne de commande
Restauration de session
application_open_and_install_investigation()
```
Le ticket #033 pourra ensuite afficher graphiquement les `GError` déjà correctement produits par ce flux.