feat(evidence): ajouter l’évaluation humaine d’authenticité
This commit is contained in:
parent
11cbc061ae
commit
b8debcde2d
18 changed files with 280 additions and 12 deletions
|
|
@ -2,6 +2,9 @@
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
- Saisie et consultation, depuis la fiche preuve, d’un historique immuable
|
||||||
|
d’appréciations humaines d’authenticité documentaire avec justification et
|
||||||
|
`OcrRun` facultatif appartenant à la preuve, sans verdict automatique.
|
||||||
- OCR d’identité contrôlé et révisable dans la création d’une personne,
|
- OCR d’identité contrôlé et révisable dans la création d’une personne,
|
||||||
l’import normal et la fiche de preuve, avec texte brut immuable,
|
l’import normal et la fiche de preuve, avec texte brut immuable,
|
||||||
transcription corrigée persistante, `manual_override`, `manual_entry` et
|
transcription corrigée persistante, `manual_override`, `manual_entry` et
|
||||||
|
|
|
||||||
19
Makefile
19
Makefile
|
|
@ -197,6 +197,7 @@ TEST_EVIDENCE_IDENTITY_IMPORT_GTK := tests/test_evidence_identity_import_gtk
|
||||||
TEST_WORKSPACE_IDENTITY_OCR_GTK := tests/test_workspace_identity_ocr_gtk
|
TEST_WORKSPACE_IDENTITY_OCR_GTK := tests/test_workspace_identity_ocr_gtk
|
||||||
TEST_DIALOG_GEOMETRY_GTK := tests/test_dialog_geometry_gtk
|
TEST_DIALOG_GEOMETRY_GTK := tests/test_dialog_geometry_gtk
|
||||||
TEST_PERSON_FACTUAL_RELATION_EDITOR_GTK := tests/test_person_factual_relation_editor_gtk
|
TEST_PERSON_FACTUAL_RELATION_EDITOR_GTK := tests/test_person_factual_relation_editor_gtk
|
||||||
|
TEST_DOCUMENT_AUTHENTICITY_EDITOR_GTK := tests/test_document_authenticity_editor_gtk
|
||||||
FAKE_DOCUMENT_TOOL := tests/fake_document_tool
|
FAKE_DOCUMENT_TOOL := tests/fake_document_tool
|
||||||
|
|
||||||
DOCUMENT_ANALYSIS_TEST_SOURCES := \
|
DOCUMENT_ANALYSIS_TEST_SOURCES := \
|
||||||
|
|
@ -225,6 +226,16 @@ $(TEST_PERSON_FACTUAL_RELATION_EDITOR_GTK): \
|
||||||
src/database/error.c src/core/relation_type_normalizer.c
|
src/database/error.c src/core/relation_type_normalizer.c
|
||||||
$(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS)
|
$(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS)
|
||||||
|
|
||||||
|
$(TEST_DOCUMENT_AUTHENTICITY_EDITOR_GTK): \
|
||||||
|
tests/test_document_authenticity_editor_gtk.c \
|
||||||
|
src/views/document_authenticity_editor.c \
|
||||||
|
src/core/document_authenticity_service.c src/models/identity_traceability.c \
|
||||||
|
src/models/identity_ocr.c src/dao/identity_ocr_dao.c \
|
||||||
|
src/dao/identity_traceability_dao.c src/database/database.c \
|
||||||
|
src/database/schema.c src/database/statement.c src/database/transaction.c \
|
||||||
|
src/database/error.c src/core/relation_type_normalizer.c
|
||||||
|
$(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS)
|
||||||
|
|
||||||
all: $(TARGET)
|
all: $(TARGET)
|
||||||
|
|
||||||
$(TEST_IDENTITY_OCR): tests/test_identity_ocr.c \
|
$(TEST_IDENTITY_OCR): tests/test_identity_ocr.c \
|
||||||
|
|
@ -244,6 +255,7 @@ $(TEST_IDENTITY_OCR_PREPROCESSOR): tests/test_identity_ocr_preprocessor.c \
|
||||||
|
|
||||||
$(TEST_IDENTITY_TRACEABILITY): tests/test_identity_traceability.c \
|
$(TEST_IDENTITY_TRACEABILITY): tests/test_identity_traceability.c \
|
||||||
src/models/identity_traceability.c src/dao/identity_traceability_dao.c \
|
src/models/identity_traceability.c src/dao/identity_traceability_dao.c \
|
||||||
|
src/core/document_authenticity_service.c \
|
||||||
src/views/person_vocabulary_adapter.c \
|
src/views/person_vocabulary_adapter.c \
|
||||||
src/views/person_factual_relation_editor.c \
|
src/views/person_factual_relation_editor.c \
|
||||||
src/models/person_role_assignment.c \
|
src/models/person_role_assignment.c \
|
||||||
|
|
@ -1199,7 +1211,8 @@ test: \
|
||||||
$(TEST_EVIDENCE_IDENTITY_IMPORT_GTK) \
|
$(TEST_EVIDENCE_IDENTITY_IMPORT_GTK) \
|
||||||
$(TEST_WORKSPACE_IDENTITY_OCR_GTK) \
|
$(TEST_WORKSPACE_IDENTITY_OCR_GTK) \
|
||||||
$(TEST_DIALOG_GEOMETRY_GTK) \
|
$(TEST_DIALOG_GEOMETRY_GTK) \
|
||||||
$(TEST_PERSON_FACTUAL_RELATION_EDITOR_GTK)
|
$(TEST_PERSON_FACTUAL_RELATION_EDITOR_GTK) \
|
||||||
|
$(TEST_DOCUMENT_AUTHENTICITY_EDITOR_GTK)
|
||||||
@echo "Exécution des tests..."
|
@echo "Exécution des tests..."
|
||||||
@./$(TEST_NODE)
|
@./$(TEST_NODE)
|
||||||
@./$(TEST_TREE_MODEL)
|
@./$(TEST_TREE_MODEL)
|
||||||
|
|
@ -1296,6 +1309,7 @@ test: \
|
||||||
@$(TEST_WORKSPACE_IDENTITY_OCR_GTK)
|
@$(TEST_WORKSPACE_IDENTITY_OCR_GTK)
|
||||||
@$(TEST_DIALOG_GEOMETRY_GTK)
|
@$(TEST_DIALOG_GEOMETRY_GTK)
|
||||||
@$(TEST_PERSON_FACTUAL_RELATION_EDITOR_GTK)
|
@$(TEST_PERSON_FACTUAL_RELATION_EDITOR_GTK)
|
||||||
|
@$(TEST_DOCUMENT_AUTHENTICITY_EDITOR_GTK)
|
||||||
@echo "Tous les tests sont valides."
|
@echo "Tous les tests sont valides."
|
||||||
|
|
||||||
%.o: %.c
|
%.o: %.c
|
||||||
|
|
@ -1396,7 +1410,8 @@ clean:
|
||||||
$(TEST_WORKSPACE_IDENTITY_OCR_GTK) \
|
$(TEST_WORKSPACE_IDENTITY_OCR_GTK) \
|
||||||
$(TEST_DIALOG_GEOMETRY_GTK) \
|
$(TEST_DIALOG_GEOMETRY_GTK) \
|
||||||
$(TEST_PERSON_FACTUAL_RELATION_EDITOR_GTK) \
|
$(TEST_PERSON_FACTUAL_RELATION_EDITOR_GTK) \
|
||||||
$(FAKE_DOCUMENT_TOOL)
|
$(TEST_DOCUMENT_AUTHENTICITY_EDITOR_GTK) \
|
||||||
|
$(FAKE_DOCUMENT_TOOL)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,10 @@ Labfy Investigation est un poste de travail libre d’investigation numérique e
|
||||||
|
|
||||||
Le projet vise à fournir un environnement local, modulaire et traçable pour organiser une enquête, préserver les preuves originales, analyser des données, corréler des entités et produire des rapports exploitables.
|
Le projet vise à fournir un environnement local, modulaire et traçable pour organiser une enquête, préserver les preuves originales, analyser des données, corréler des entités et produire des rapports exploitables.
|
||||||
|
|
||||||
|
La fiche d’une preuve permet aussi de consigner une appréciation humaine
|
||||||
|
d’authenticité documentaire. Cet historique est immuable, justifié selon le
|
||||||
|
statut choisi et ne peut jamais être produit automatiquement par l’OCR.
|
||||||
|
|
||||||
> **État du projet : développement actif**
|
> **État du projet : développement actif**
|
||||||
>
|
>
|
||||||
> Le logiciel n’est pas encore prêt pour un usage opérationnel en production. Les formats internes, l’interface et les mécanismes d’intégration peuvent encore évoluer.
|
> Le logiciel n’est pas encore prêt pour un usage opérationnel en production. Les formats internes, l’interface et les mécanismes d’intégration peuvent encore évoluer.
|
||||||
|
|
|
||||||
|
|
@ -122,7 +122,11 @@ humaine et la qualification `complete`, `partial`, `uncertain` ou `invalid`
|
||||||
sont orthogonales au statut de révision. Les contraintes SQLite et le service
|
sont orthogonales au statut de révision. Les contraintes SQLite et le service
|
||||||
de validation interdisent la projection des valeurs rejetées, en conflit,
|
de validation interdisent la projection des valeurs rejetées, en conflit,
|
||||||
incertaines ou invalides. Cette tranche ne réalise encore aucune projection
|
incertaines ou invalides. Cette tranche ne réalise encore aucune projection
|
||||||
automatique et ne fournit pas l’interface GTK complète de saisie.
|
automatique. La fiche preuve délègue la saisie et la consultation de
|
||||||
|
l’authenticité à `DocumentAuthenticityEditor`, qui appelle
|
||||||
|
`DocumentAuthenticityService`; le widget n’accède jamais directement à
|
||||||
|
SQLite. Le service ajoute chaque appréciation humaine dans une transaction et
|
||||||
|
chaîne son identifiant à l’appréciation courante.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,12 @@ répertoire temporaire : JPEG avec APP1 EXIF, HEIC/HEIF via libheif et PDF
|
||||||
multipage via Cairo. Elles ne doivent jamais être remplacées par un document
|
multipage via Cairo. Elles ne doivent jamais être remplacées par un document
|
||||||
réel.
|
réel.
|
||||||
|
|
||||||
|
L’authenticité documentaire se valide avec
|
||||||
|
`tests/test_identity_traceability` et
|
||||||
|
`tests/test_document_authenticity_editor_gtk`. Ce dernier doit être exécuté
|
||||||
|
sur un affichage GTK réel avec `G_DEBUG=fatal-criticals`; ses données et sa
|
||||||
|
base SQLite sont exclusivement temporaires et marquées `SPECIMEN`.
|
||||||
|
|
||||||
La validation ciblée de l’aperçu partagé comprend
|
La validation ciblée de l’aperçu partagé comprend
|
||||||
`test_evidence_preview_widget_gtk`, `test_evidence_preview`,
|
`test_evidence_preview_widget_gtk`, `test_evidence_preview`,
|
||||||
`test_evidence_video_preview_controller` et
|
`test_evidence_video_preview_controller` et
|
||||||
|
|
|
||||||
|
|
@ -178,13 +178,15 @@ PARTIEL — VALIDATION MANUELLE DES TRANCHES LIVRÉES RÉUSSIE
|
||||||
- fondations V18 : authenticité humaine historisée, relations factuelles
|
- fondations V18 : authenticité humaine historisée, relations factuelles
|
||||||
typées, vocabulaires d’identification et de rôles, cycle OCR jusqu’à la
|
typées, vocabulaires d’identification et de rôles, cycle OCR jusqu’à la
|
||||||
valeur explicitement confirmée et contraintes anti-automatisme.
|
valeur explicitement confirmée et contraintes anti-automatisme.
|
||||||
|
- interface GTK de saisie et de consultation de l’authenticité documentaire
|
||||||
|
depuis la fiche preuve, avec OcrRun facultatif filtré et historique immuable.
|
||||||
|
|
||||||
Limitations restantes :
|
Limitations restantes :
|
||||||
|
|
||||||
1. l’OCR groupé de plusieurs preuves dans une même opération n’est pas pris en
|
1. l’OCR groupé de plusieurs preuves dans une même opération n’est pas pris en
|
||||||
charge ;
|
charge ;
|
||||||
2. l’interface GTK complète de saisie de l’authenticité, des relations
|
2. les interfaces GTK complètes des états d’identification et des rôles V18
|
||||||
factuelles, des états et des rôles V18 reste à construire ;
|
restent à construire ;
|
||||||
3. la provenance uniforme de tous les dérivés et la projection des seules
|
3. la provenance uniforme de tous les dérivés et la projection des seules
|
||||||
valeurs OCR confirmées vers les attributs structurés de la personne restent
|
valeurs OCR confirmées vers les attributs structurés de la personne restent
|
||||||
partielles ;
|
partielles ;
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,13 @@ contraintes refusent toute confirmation d’un champ rejeté, en conflit,
|
||||||
incertain ou invalide. Aucun OCR ne crée une évaluation d’authenticité, une
|
incertain ou invalide. Aucun OCR ne crée une évaluation d’authenticité, une
|
||||||
relation factuelle, un rôle sensible ou un état `confirmed`.
|
relation factuelle, un rôle sensible ou un état `confirmed`.
|
||||||
|
|
||||||
|
Les insertions d’authenticité vérifient hors GTK qu’un `ocr_run_id` facultatif
|
||||||
|
appartient à la même preuve. `previous_assessment_id` forme une chaîne
|
||||||
|
append-only ; l’ajout et la détermination du maillon courant sont coordonnés
|
||||||
|
dans une transaction.
|
||||||
|
|
||||||
> **Statut :** architecture courante
|
> **Statut :** architecture courante
|
||||||
> **Version du schéma :** V10
|
> **Version du schéma :** V18
|
||||||
> **Dernière mise à jour :** 2026-07-24
|
> **Dernière mise à jour :** 2026-07-24
|
||||||
> **Source de vérité détaillée :** `SCHEMA_AUDIT_CURRENT.md`
|
> **Source de vérité détaillée :** `SCHEMA_AUDIT_CURRENT.md`
|
||||||
|
|
||||||
|
|
|
||||||
16
include/core/document_authenticity_service.h
Normal file
16
include/core/document_authenticity_service.h
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
#ifndef LABFY_DOCUMENT_AUTHENTICITY_SERVICE_H
|
||||||
|
#define LABFY_DOCUMENT_AUTHENTICITY_SERVICE_H
|
||||||
|
#include "database/database.h"
|
||||||
|
#include "models/identity_traceability.h"
|
||||||
|
#include <glib.h>
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
typedef struct { const char *code,*label,*description; gboolean requires_justification; } DocumentAuthenticityStatus;
|
||||||
|
const DocumentAuthenticityStatus *document_authenticity_service_statuses(gsize *count);
|
||||||
|
const DocumentAuthenticityStatus *document_authenticity_service_status(const char *code);
|
||||||
|
GPtrArray *document_authenticity_service_list_runs(Database *database,const char *evidence_identifier,GError **error);
|
||||||
|
GPtrArray *document_authenticity_service_history(Database *database,const char *evidence_identifier,GError **error);
|
||||||
|
gboolean document_authenticity_service_add(Database *database,const char *evidence_identifier,
|
||||||
|
const char *status,const char *justification,const char *technical_note,
|
||||||
|
const char *ocr_run_identifier,DocumentAuthenticityAssessment **created,GError **error);
|
||||||
|
G_END_DECLS
|
||||||
|
#endif
|
||||||
|
|
@ -41,6 +41,15 @@ DocumentAuthenticityAssessment *document_authenticity_assessment_copy(
|
||||||
const DocumentAuthenticityAssessment *assessment);
|
const DocumentAuthenticityAssessment *assessment);
|
||||||
void document_authenticity_assessment_free(
|
void document_authenticity_assessment_free(
|
||||||
DocumentAuthenticityAssessment *assessment);
|
DocumentAuthenticityAssessment *assessment);
|
||||||
|
const char *document_authenticity_assessment_get_identifier(const DocumentAuthenticityAssessment *assessment);
|
||||||
|
const char *document_authenticity_assessment_get_evidence_identifier(const DocumentAuthenticityAssessment *assessment);
|
||||||
|
const char *document_authenticity_assessment_get_ocr_run_identifier(const DocumentAuthenticityAssessment *assessment);
|
||||||
|
const char *document_authenticity_assessment_get_status(const DocumentAuthenticityAssessment *assessment);
|
||||||
|
const char *document_authenticity_assessment_get_justification(const DocumentAuthenticityAssessment *assessment);
|
||||||
|
const char *document_authenticity_assessment_get_assessed_at(const DocumentAuthenticityAssessment *assessment);
|
||||||
|
const char *document_authenticity_assessment_get_previous_identifier(const DocumentAuthenticityAssessment *assessment);
|
||||||
|
const char *document_authenticity_assessment_get_technical_note(const DocumentAuthenticityAssessment *assessment);
|
||||||
|
const char *document_authenticity_assessment_get_origin(const DocumentAuthenticityAssessment *assessment);
|
||||||
|
|
||||||
PersonEvidenceFactualRelation *person_evidence_factual_relation_new(
|
PersonEvidenceFactualRelation *person_evidence_factual_relation_new(
|
||||||
const char *identifier, const char *person_identifier,
|
const char *identifier, const char *person_identifier,
|
||||||
|
|
|
||||||
12
include/views/document_authenticity_editor.h
Normal file
12
include/views/document_authenticity_editor.h
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
#ifndef LABFY_DOCUMENT_AUTHENTICITY_EDITOR_H
|
||||||
|
#define LABFY_DOCUMENT_AUTHENTICITY_EDITOR_H
|
||||||
|
#include "database/database.h"
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
typedef struct DocumentAuthenticityEditor DocumentAuthenticityEditor;
|
||||||
|
DocumentAuthenticityEditor *document_authenticity_editor_new(Database *database,const char *evidence_identifier);
|
||||||
|
GtkWidget *document_authenticity_editor_get_widget(DocumentAuthenticityEditor *editor);
|
||||||
|
gboolean document_authenticity_editor_refresh(DocumentAuthenticityEditor *editor,GError **error);
|
||||||
|
void document_authenticity_editor_free(DocumentAuthenticityEditor *editor);
|
||||||
|
G_END_DECLS
|
||||||
|
#endif
|
||||||
44
src/core/document_authenticity_service.c
Normal file
44
src/core/document_authenticity_service.c
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
#include "core/document_authenticity_service.h"
|
||||||
|
#include "dao/identity_ocr_dao.h"
|
||||||
|
#include "dao/identity_traceability_dao.h"
|
||||||
|
#include "database/transaction.h"
|
||||||
|
|
||||||
|
static GQuark domain(void){return g_quark_from_static_string("document-authenticity-service");}
|
||||||
|
static const DocumentAuthenticityStatus statuses[]={
|
||||||
|
{"indeterminate","Authenticité indéterminée","Appréciation humaine ne concluant pas sur l’authenticité.",FALSE},
|
||||||
|
{"presumed_authentic","Document présumé authentique","Appréciation humaine provisoire, sans certification automatique.",TRUE},
|
||||||
|
{"suspicious","Document présentant des éléments suspects","Appréciation humaine signalant des éléments à examiner.",TRUE},
|
||||||
|
{"presumed_forged","Document présumé falsifié","Appréciation humaine provisoire nécessitant une justification.",TRUE},
|
||||||
|
{"confirmed_forged","Falsification confirmée","Conclusion humaine documentée, jamais déduite automatiquement.",TRUE}};
|
||||||
|
const DocumentAuthenticityStatus *document_authenticity_service_statuses(gsize*c)
|
||||||
|
{if(c)*c=G_N_ELEMENTS(statuses);return statuses;}
|
||||||
|
const DocumentAuthenticityStatus *document_authenticity_service_status(const char*code)
|
||||||
|
{for(guint i=0;i<G_N_ELEMENTS(statuses);i++)if(g_strcmp0(code,statuses[i].code)==0)return &statuses[i];return NULL;}
|
||||||
|
GPtrArray *document_authenticity_service_list_runs(Database*d,const char*e,GError**error)
|
||||||
|
{IdentityOcrDao*dao=identity_ocr_dao_new(d);if(!dao)return NULL;GPtrArray*a=identity_ocr_dao_list_runs_by_evidence(dao,e,error);identity_ocr_dao_free(dao);return a;}
|
||||||
|
GPtrArray *document_authenticity_service_history(Database*d,const char*e,GError**error)
|
||||||
|
{IdentityTraceabilityDao*dao=identity_traceability_dao_new(d);if(!dao)return NULL;GPtrArray*a=identity_traceability_dao_list_authenticity(dao,e,error);identity_traceability_dao_free(dao);return a;}
|
||||||
|
gboolean document_authenticity_service_add(Database*d,const char*evidence,
|
||||||
|
const char*status,const char*justification,const char*note,const char*run,
|
||||||
|
DocumentAuthenticityAssessment**created,GError**error)
|
||||||
|
{
|
||||||
|
if(created)*created=NULL;
|
||||||
|
const DocumentAuthenticityStatus*entry=document_authenticity_service_status(status);
|
||||||
|
char*j=justification?g_strdup(justification):NULL;if(j)g_strstrip(j);
|
||||||
|
if(!d||!g_uuid_string_is_valid(evidence)||!entry||(entry->requires_justification&&(!j||!*j))){
|
||||||
|
g_free(j);g_set_error_literal(error,domain(),1,"Une justification est requise pour cette appréciation.");return FALSE;}
|
||||||
|
IdentityTraceabilityDao*dao=identity_traceability_dao_new(d);GError*local=NULL;
|
||||||
|
if(!database_transaction_begin(d)){identity_traceability_dao_free(dao);g_free(j);
|
||||||
|
g_set_error_literal(error,domain(),2,"Impossible de démarrer la transaction d’authenticité.");return FALSE;}
|
||||||
|
DocumentAuthenticityAssessment*previous=identity_traceability_dao_current_authenticity(dao,evidence,&local);
|
||||||
|
if(local){database_transaction_rollback(d);g_propagate_error(error,local);identity_traceability_dao_free(dao);g_free(j);return FALSE;}
|
||||||
|
char*id=g_uuid_string_random();GDateTime*now=g_date_time_new_now_utc();char*at=g_date_time_format(now,"%Y-%m-%dT%H:%M:%SZ");
|
||||||
|
DocumentAuthenticityAssessment*a=document_authenticity_assessment_new(id,evidence,run,status,
|
||||||
|
j&&*j?j:NULL,at,previous?document_authenticity_assessment_get_identifier(previous):NULL,note);
|
||||||
|
gboolean ok=a&&identity_traceability_dao_insert_authenticity(dao,a,&local)&&database_transaction_commit(d);
|
||||||
|
if(!ok&&database_transaction_is_active(d))database_transaction_rollback(d);
|
||||||
|
if(!ok&&!local)g_set_error_literal(&local,domain(),2,"Impossible d’enregistrer l’appréciation d’authenticité.");
|
||||||
|
if(ok&&created)*created=document_authenticity_assessment_copy(a);else if(local)g_propagate_error(error,local);
|
||||||
|
document_authenticity_assessment_free(a);document_authenticity_assessment_free(previous);identity_traceability_dao_free(dao);
|
||||||
|
g_date_time_unref(now);g_free(at);g_free(id);g_free(j);return ok;
|
||||||
|
}
|
||||||
|
|
@ -15,12 +15,37 @@ gboolean identity_traceability_dao_insert_authenticity(
|
||||||
{
|
{
|
||||||
DocumentAuthenticityAssessment*valid=a?document_authenticity_assessment_copy(a):NULL;
|
DocumentAuthenticityAssessment*valid=a?document_authenticity_assessment_copy(a):NULL;
|
||||||
if(!d||!valid){fail(e,"Évaluation d’authenticité invalide.");return FALSE;}
|
if(!d||!valid){fail(e,"Évaluation d’authenticité invalide.");return FALSE;}
|
||||||
|
const char*run=document_authenticity_assessment_get_ocr_run_identifier(valid);
|
||||||
|
if(run){
|
||||||
|
DatabaseStatement*check=database_statement_prepare(d->database,
|
||||||
|
"SELECT 1 FROM identity_ocr_runs WHERE id=? AND evidence_id=?;");
|
||||||
|
gboolean compatible=check&&bind(check,1,run)&&bind(check,2,
|
||||||
|
document_authenticity_assessment_get_evidence_identifier(valid))&&
|
||||||
|
database_statement_step(check)==DATABASE_STATEMENT_STEP_ROW;
|
||||||
|
database_statement_finalize(check);
|
||||||
|
if(!compatible){document_authenticity_assessment_free(valid);
|
||||||
|
fail(e,"L’exécution OCR ne correspond pas à la preuve évaluée.");return FALSE;}
|
||||||
|
}
|
||||||
|
const char*previous=document_authenticity_assessment_get_previous_identifier(valid);
|
||||||
|
if(previous){
|
||||||
|
DatabaseStatement*check=database_statement_prepare(d->database,
|
||||||
|
"SELECT 1 FROM document_authenticity_assessments WHERE id=? AND evidence_id=?;");
|
||||||
|
gboolean compatible=check&&bind(check,1,previous)&&bind(check,2,
|
||||||
|
document_authenticity_assessment_get_evidence_identifier(valid))&&
|
||||||
|
database_statement_step(check)==DATABASE_STATEMENT_STEP_ROW;
|
||||||
|
database_statement_finalize(check);
|
||||||
|
if(!compatible){document_authenticity_assessment_free(valid);
|
||||||
|
fail(e,"L’appréciation précédente ne correspond pas à la preuve évaluée.");return FALSE;}
|
||||||
|
}
|
||||||
DatabaseStatement*s=database_statement_prepare(d->database,
|
DatabaseStatement*s=database_statement_prepare(d->database,
|
||||||
"INSERT INTO document_authenticity_assessments VALUES(?,?,?,?,?,?,?,?,?);");
|
"INSERT INTO document_authenticity_assessments VALUES(?,?,?,?,?,?,?,?,?);");
|
||||||
gboolean ok=s&&bind(s,1,a->identifier)&&bind(s,2,a->evidence_identifier)&&
|
gboolean ok=s&&bind(s,1,document_authenticity_assessment_get_identifier(valid))&&
|
||||||
bind(s,3,a->ocr_run_identifier)&&bind(s,4,a->status)&&bind(s,5,a->justification)&&
|
bind(s,2,document_authenticity_assessment_get_evidence_identifier(valid))&&
|
||||||
bind(s,6,a->assessed_at)&&bind(s,7,a->previous_identifier)&&
|
bind(s,3,run)&&bind(s,4,document_authenticity_assessment_get_status(valid))&&
|
||||||
bind(s,8,a->technical_note)&&bind(s,9,"human")&&
|
bind(s,5,document_authenticity_assessment_get_justification(valid))&&
|
||||||
|
bind(s,6,document_authenticity_assessment_get_assessed_at(valid))&&
|
||||||
|
bind(s,7,document_authenticity_assessment_get_previous_identifier(valid))&&
|
||||||
|
bind(s,8,document_authenticity_assessment_get_technical_note(valid))&&bind(s,9,"human")&&
|
||||||
database_statement_step(s)==DATABASE_STATEMENT_STEP_DONE;
|
database_statement_step(s)==DATABASE_STATEMENT_STEP_DONE;
|
||||||
database_statement_finalize(s);document_authenticity_assessment_free(valid);
|
database_statement_finalize(s);document_authenticity_assessment_free(valid);
|
||||||
if(!ok)fail(e,"Impossible de conserver l’évaluation d’authenticité.");
|
if(!ok)fail(e,"Impossible de conserver l’évaluation d’authenticité.");
|
||||||
|
|
@ -66,8 +91,10 @@ GPtrArray *identity_traceability_dao_list_authenticity(
|
||||||
DocumentAuthenticityAssessment *identity_traceability_dao_current_authenticity(
|
DocumentAuthenticityAssessment *identity_traceability_dao_current_authenticity(
|
||||||
IdentityTraceabilityDao*d,const char*id,GError**e)
|
IdentityTraceabilityDao*d,const char*id,GError**e)
|
||||||
{
|
{
|
||||||
GPtrArray*a=auth_query(d,"SELECT * FROM document_authenticity_assessments "
|
GPtrArray*a=auth_query(d,"SELECT a.* FROM document_authenticity_assessments a "
|
||||||
"WHERE evidence_id=? ORDER BY assessed_at DESC,id DESC LIMIT 1;",id,e);
|
"WHERE a.evidence_id=? AND NOT EXISTS(SELECT 1 FROM "
|
||||||
|
"document_authenticity_assessments n WHERE n.previous_assessment_id=a.id) "
|
||||||
|
"ORDER BY a.assessed_at DESC,a.id DESC LIMIT 1;",id,e);
|
||||||
if(!a)return NULL;
|
if(!a)return NULL;
|
||||||
DocumentAuthenticityAssessment*r=a->len?
|
DocumentAuthenticityAssessment*r=a->len?
|
||||||
document_authenticity_assessment_copy(g_ptr_array_index(a,0)):NULL;
|
document_authenticity_assessment_copy(g_ptr_array_index(a,0)):NULL;
|
||||||
|
|
|
||||||
|
|
@ -77,6 +77,18 @@ void document_authenticity_assessment_free(DocumentAuthenticityAssessment*a)
|
||||||
g_free(a->ocr_run_identifier);g_free(a->status);g_free(a->justification);
|
g_free(a->ocr_run_identifier);g_free(a->status);g_free(a->justification);
|
||||||
g_free(a->assessed_at);g_free(a->previous_identifier);
|
g_free(a->assessed_at);g_free(a->previous_identifier);
|
||||||
g_free(a->technical_note);g_free(a->origin);g_free(a);}
|
g_free(a->technical_note);g_free(a->origin);g_free(a);}
|
||||||
|
#define AUTH_GETTER(name,field) \
|
||||||
|
const char *document_authenticity_assessment_get_##name( \
|
||||||
|
const DocumentAuthenticityAssessment*a){return a?a->field:NULL;}
|
||||||
|
AUTH_GETTER(identifier,identifier)
|
||||||
|
AUTH_GETTER(evidence_identifier,evidence_identifier)
|
||||||
|
AUTH_GETTER(ocr_run_identifier,ocr_run_identifier)
|
||||||
|
AUTH_GETTER(status,status)
|
||||||
|
AUTH_GETTER(justification,justification)
|
||||||
|
AUTH_GETTER(assessed_at,assessed_at)
|
||||||
|
AUTH_GETTER(previous_identifier,previous_identifier)
|
||||||
|
AUTH_GETTER(technical_note,technical_note)
|
||||||
|
AUTH_GETTER(origin,origin)
|
||||||
|
|
||||||
PersonEvidenceFactualRelation *person_evidence_factual_relation_new(
|
PersonEvidenceFactualRelation *person_evidence_factual_relation_new(
|
||||||
const char *id,const char *person,const char *evidence,const char *run,
|
const char *id,const char *person,const char *evidence,const char *run,
|
||||||
|
|
|
||||||
52
src/views/document_authenticity_editor.c
Normal file
52
src/views/document_authenticity_editor.c
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
#include "views/document_authenticity_editor.h"
|
||||||
|
#include "core/document_authenticity_service.h"
|
||||||
|
#include "dao/identity_ocr_dao.h"
|
||||||
|
|
||||||
|
struct DocumentAuthenticityEditor{Database*database;char*evidence;GtkWidget*root;
|
||||||
|
GtkDropDown*status;GtkStringList*status_labels;GtkDropDown*run;GtkStringList*run_labels;
|
||||||
|
GPtrArray*run_ids;GtkTextBuffer*justification;GtkTextBuffer*note;GtkLabel*error;GtkBox*history;};
|
||||||
|
static void clear_box(GtkBox*b){GtkWidget*c=gtk_widget_get_first_child(GTK_WIDGET(b));while(c){GtkWidget*n=gtk_widget_get_next_sibling(c);gtk_box_remove(b,c);c=n;}}
|
||||||
|
static char *buffer_text(GtkTextBuffer*b){GtkTextIter s,e;gtk_text_buffer_get_bounds(b,&s,&e);char*t=gtk_text_buffer_get_text(b,&s,&e,FALSE);g_strstrip(t);return t;}
|
||||||
|
gboolean document_authenticity_editor_refresh(DocumentAuthenticityEditor*x,GError**error)
|
||||||
|
{
|
||||||
|
if(!x)return FALSE;
|
||||||
|
clear_box(x->history);GPtrArray*h=document_authenticity_service_history(x->database,x->evidence,error);if(!h)return FALSE;
|
||||||
|
if(h->len==0)gtk_box_append(x->history,gtk_label_new("Aucune appréciation humaine enregistrée."));
|
||||||
|
for(gint i=(gint)h->len-1;i>=0;i--){DocumentAuthenticityAssessment*a=g_ptr_array_index(h,(guint)i);
|
||||||
|
const DocumentAuthenticityStatus*s=document_authenticity_service_status(document_authenticity_assessment_get_status(a));
|
||||||
|
const char*j=document_authenticity_assessment_get_justification(a),*n=document_authenticity_assessment_get_technical_note(a),*r=document_authenticity_assessment_get_ocr_run_identifier(a);
|
||||||
|
char*t=g_strdup_printf("%s — %s — origine humaine%s%s%s%s%s%s",s?s->label:"Statut inconnu",
|
||||||
|
document_authenticity_assessment_get_assessed_at(a),r?" — OcrRun : ":"",r?r:"",j?"\nJustification : ":"",j?j:"",n?"\nNote technique : ":"",n?n:"");
|
||||||
|
GtkWidget*l=gtk_label_new(t);gtk_label_set_xalign(GTK_LABEL(l),0);gtk_label_set_wrap(GTK_LABEL(l),TRUE);gtk_box_append(x->history,l);g_free(t);}
|
||||||
|
g_ptr_array_unref(h);return TRUE;
|
||||||
|
}
|
||||||
|
static void save(GtkButton*b,gpointer data)
|
||||||
|
{
|
||||||
|
(void)b;DocumentAuthenticityEditor*x=data;guint si=gtk_drop_down_get_selected(x->status),ri=gtk_drop_down_get_selected(x->run);gsize count=0;
|
||||||
|
const DocumentAuthenticityStatus*s=document_authenticity_service_statuses(&count);if(si>=count)return;
|
||||||
|
char*j=buffer_text(x->justification),*n=buffer_text(x->note);const char*run=ri>0&&ri-1<x->run_ids->len?g_ptr_array_index(x->run_ids,ri-1):NULL;GError*error=NULL;
|
||||||
|
if(!document_authenticity_service_add(x->database,x->evidence,s[si].code,j,
|
||||||
|
n&&*n?n:NULL,run,NULL,&error)){
|
||||||
|
gtk_label_set_text(x->error,error?error->message:"Erreur d’enregistrement.");gtk_widget_set_visible(GTK_WIDGET(x->error),TRUE);g_clear_error(&error);
|
||||||
|
}else{gtk_widget_set_visible(GTK_WIDGET(x->error),FALSE);gtk_text_buffer_set_text(x->justification,"",-1);gtk_text_buffer_set_text(x->note,"",-1);document_authenticity_editor_refresh(x,NULL);}
|
||||||
|
g_free(j);g_free(n);
|
||||||
|
}
|
||||||
|
DocumentAuthenticityEditor *document_authenticity_editor_new(Database*d,const char*evidence)
|
||||||
|
{
|
||||||
|
if(!d||!g_uuid_string_is_valid(evidence))return NULL;
|
||||||
|
DocumentAuthenticityEditor*x=g_new0(DocumentAuthenticityEditor,1);x->database=d;x->evidence=g_strdup(evidence);
|
||||||
|
x->root=gtk_box_new(GTK_ORIENTATION_VERTICAL,6);gtk_widget_set_name(x->root,"document-authenticity-editor");
|
||||||
|
GtkWidget*title=gtk_label_new("Authenticité documentaire — appréciation humaine");gtk_label_set_xalign(GTK_LABEL(title),0);gtk_box_append(GTK_BOX(x->root),title);
|
||||||
|
x->status_labels=gtk_string_list_new(NULL);gsize count=0;const DocumentAuthenticityStatus*s=document_authenticity_service_statuses(&count);for(guint i=0;i<count;i++)gtk_string_list_append(x->status_labels,s[i].label);
|
||||||
|
x->status=GTK_DROP_DOWN(gtk_drop_down_new(G_LIST_MODEL(g_object_ref(x->status_labels)),NULL));gtk_widget_set_name(GTK_WIDGET(x->status),"authenticity-status");gtk_box_append(GTK_BOX(x->root),GTK_WIDGET(x->status));
|
||||||
|
x->run_labels=gtk_string_list_new(NULL);gtk_string_list_append(x->run_labels,"Aucune exécution OCR");x->run_ids=g_ptr_array_new_with_free_func(g_free);GPtrArray*runs=document_authenticity_service_list_runs(d,evidence,NULL);
|
||||||
|
if(runs){for(guint i=0;i<runs->len;i++){IdentityOcrRunRecord*r=g_ptr_array_index(runs,i);char*l=g_strdup_printf("%s — %s",r->executed_at,r->engine);gtk_string_list_append(x->run_labels,l);g_ptr_array_add(x->run_ids,g_strdup(r->id));g_free(l);}g_ptr_array_unref(runs);}
|
||||||
|
x->run=GTK_DROP_DOWN(gtk_drop_down_new(G_LIST_MODEL(g_object_ref(x->run_labels)),NULL));gtk_widget_set_name(GTK_WIDGET(x->run),"authenticity-ocr-run");gtk_box_append(GTK_BOX(x->root),GTK_WIDGET(x->run));
|
||||||
|
GtkWidget*jv=gtk_text_view_new();x->justification=gtk_text_view_get_buffer(GTK_TEXT_VIEW(jv));gtk_widget_set_name(jv,"authenticity-justification");gtk_widget_set_size_request(jv,-1,60);gtk_box_append(GTK_BOX(x->root),gtk_label_new("Justification factuelle"));gtk_box_append(GTK_BOX(x->root),jv);
|
||||||
|
GtkWidget*nv=gtk_text_view_new();x->note=gtk_text_view_get_buffer(GTK_TEXT_VIEW(nv));gtk_widget_set_name(nv,"authenticity-technical-note");gtk_widget_set_size_request(nv,-1,45);gtk_box_append(GTK_BOX(x->root),gtk_label_new("Note technique facultative"));gtk_box_append(GTK_BOX(x->root),nv);
|
||||||
|
x->error=GTK_LABEL(gtk_label_new(""));gtk_widget_set_name(GTK_WIDGET(x->error),"authenticity-error");gtk_widget_add_css_class(GTK_WIDGET(x->error),"error");gtk_widget_set_visible(GTK_WIDGET(x->error),FALSE);gtk_box_append(GTK_BOX(x->root),GTK_WIDGET(x->error));
|
||||||
|
GtkWidget*button=gtk_button_new_with_label("Enregistrer l’appréciation humaine");gtk_widget_set_name(button,"authenticity-save");g_signal_connect(button,"clicked",G_CALLBACK(save),x);gtk_box_append(GTK_BOX(x->root),button);
|
||||||
|
x->history=GTK_BOX(gtk_box_new(GTK_ORIENTATION_VERTICAL,4));gtk_widget_set_name(GTK_WIDGET(x->history),"authenticity-history");gtk_box_append(GTK_BOX(x->root),GTK_WIDGET(x->history));document_authenticity_editor_refresh(x,NULL);return x;
|
||||||
|
}
|
||||||
|
GtkWidget *document_authenticity_editor_get_widget(DocumentAuthenticityEditor*x){return x?x->root:NULL;}
|
||||||
|
void document_authenticity_editor_free(DocumentAuthenticityEditor*x){if(!x)return;g_clear_object(&x->status_labels);g_clear_object(&x->run_labels);g_ptr_array_unref(x->run_ids);g_free(x->evidence);g_free(x);}
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
#include "dao/entity_dao.h"
|
#include "dao/entity_dao.h"
|
||||||
#include "views/evidence_identity_ocr_dialog.h"
|
#include "views/evidence_identity_ocr_dialog.h"
|
||||||
#include "views/person_vocabulary_adapter.h"
|
#include "views/person_vocabulary_adapter.h"
|
||||||
|
#include "views/document_authenticity_editor.h"
|
||||||
#include "widgets/ocr_provenance_overlay.h"
|
#include "widgets/ocr_provenance_overlay.h"
|
||||||
|
|
||||||
struct EvidenceMetadataDialogResult
|
struct EvidenceMetadataDialogResult
|
||||||
|
|
@ -48,6 +49,7 @@ typedef struct
|
||||||
guint64 ocr_generation;
|
guint64 ocr_generation;
|
||||||
gpointer user_data;
|
gpointer user_data;
|
||||||
gboolean completed;
|
gboolean completed;
|
||||||
|
DocumentAuthenticityEditor *authenticity_editor;
|
||||||
} EvidenceMetadataDialogContext;
|
} EvidenceMetadataDialogContext;
|
||||||
|
|
||||||
static void evidence_metadata_dialog_complete(
|
static void evidence_metadata_dialog_complete(
|
||||||
|
|
@ -89,6 +91,7 @@ static void evidence_metadata_dialog_context_free(gpointer data)
|
||||||
g_clear_pointer(&context->ocr_documents, g_ptr_array_unref);
|
g_clear_pointer(&context->ocr_documents, g_ptr_array_unref);
|
||||||
g_clear_pointer(&context->ocr_run_identifiers, g_ptr_array_unref);
|
g_clear_pointer(&context->ocr_run_identifiers, g_ptr_array_unref);
|
||||||
g_clear_object(&context->ocr_run_labels);
|
g_clear_object(&context->ocr_run_labels);
|
||||||
|
document_authenticity_editor_free(context->authenticity_editor);
|
||||||
g_free(context->investigation_root);
|
g_free(context->investigation_root);
|
||||||
g_free(context->evidence_identifier);
|
g_free(context->evidence_identifier);
|
||||||
g_free(context);
|
g_free(context);
|
||||||
|
|
@ -542,6 +545,15 @@ gboolean evidence_metadata_dialog_present_with_ocr(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (database != NULL) {
|
if (database != NULL) {
|
||||||
|
context->authenticity_editor = document_authenticity_editor_new(
|
||||||
|
database, evidence_record_get_identifier(record));
|
||||||
|
if (context->authenticity_editor != NULL) {
|
||||||
|
GtkWidget *auth_scroll = gtk_scrolled_window_new();
|
||||||
|
gtk_widget_set_size_request(auth_scroll, -1, 300);
|
||||||
|
gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(auth_scroll),
|
||||||
|
document_authenticity_editor_get_widget(context->authenticity_editor));
|
||||||
|
gtk_box_append(GTK_BOX(main_box), auth_scroll);
|
||||||
|
}
|
||||||
IdentityTraceabilityDao *trace_dao = identity_traceability_dao_new(database);
|
IdentityTraceabilityDao *trace_dao = identity_traceability_dao_new(database);
|
||||||
if (trace_dao != NULL) {
|
if (trace_dao != NULL) {
|
||||||
GPtrArray *relations = identity_traceability_dao_list_factual_relations_by_evidence(
|
GPtrArray *relations = identity_traceability_dao_list_factual_relations_by_evidence(
|
||||||
|
|
|
||||||
24
tests/test_document_authenticity_editor_gtk.c
Normal file
24
tests/test_document_authenticity_editor_gtk.c
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
#include "views/document_authenticity_editor.h"
|
||||||
|
#include "core/document_authenticity_service.h"
|
||||||
|
#include "database/database.h"
|
||||||
|
#include <glib/gstdio.h>
|
||||||
|
#include <sqlite3.h>
|
||||||
|
#define EVIDENCE "10000000-0000-4000-8000-000000000018"
|
||||||
|
#define RUN "30000000-0000-4000-8000-000000000018"
|
||||||
|
#define AT "2026-07-30T10:00:00Z"
|
||||||
|
static GtkWidget *named(GtkWidget*w,const char*n){if(g_strcmp0(gtk_widget_get_name(w),n)==0)return w;for(GtkWidget*c=gtk_widget_get_first_child(w);c;c=gtk_widget_get_next_sibling(c)){GtkWidget*f=named(c,n);if(f)return f;}return NULL;}
|
||||||
|
static void exec_ok(sqlite3*d,const char*s){char*m=NULL;g_assert_cmpint(sqlite3_exec(d,s,NULL,NULL,&m),==,SQLITE_OK);sqlite3_free(m);}
|
||||||
|
static void remove_fixture(char*dir,char*path){g_remove(path);g_rmdir(dir);g_free(path);g_free(dir);}
|
||||||
|
static void test_editor(void)
|
||||||
|
{
|
||||||
|
GError*error=NULL;char*dir=g_dir_make_tmp("labfy-auth-gtk-XXXXXX",&error);g_assert_no_error(error);char*path=g_build_filename(dir,"SPECIMEN.sqlite",NULL);g_assert_true(database_initialize(path,"SPECIMEN",dir));
|
||||||
|
sqlite3*sql=NULL;g_assert_cmpint(sqlite3_open(path,&sql),==,SQLITE_OK);exec_ok(sql,"PRAGMA foreign_keys=ON;INSERT INTO preuves(id,name,relative_path,type_id,size_bytes,sha256,imported_at,updated_at,status,locked,original_name) VALUES('" EVIDENCE "','specimen.png','specimen.png',2,8,'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa','" AT "','" AT "','active',0,'specimen.png');INSERT INTO identity_ocr_runs(id,evidence_id,expected_sha256,page_number,document_type,document_side,engine,requested_languages,available_languages,parameters,preprocessing_profile,executed_at,status,text_relative_path,text_sha256,tsv_relative_path,tsv_sha256) VALUES('" RUN "','" EVIDENCE "','aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',1,'identity_card','front','tesseract','fra','fra','SPECIMEN','none','" AT "','success','raw.txt','bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb','raw.tsv','cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc');");sqlite3_close(sql);
|
||||||
|
Database*d=database_open(path);g_assert_nonnull(d);g_assert_true(database_migrate_to_latest(d));DocumentAuthenticityEditor*x=document_authenticity_editor_new(d,EVIDENCE);g_assert_nonnull(x);GtkWidget*root=document_authenticity_editor_get_widget(x);g_object_ref_sink(root);
|
||||||
|
GtkDropDown*status=GTK_DROP_DOWN(named(root,"authenticity-status"));GtkDropDown*run=GTK_DROP_DOWN(named(root,"authenticity-ocr-run"));GtkWidget*save=named(root,"authenticity-save");GtkLabel*message=GTK_LABEL(named(root,"authenticity-error"));g_assert_cmpuint(g_list_model_get_n_items(gtk_drop_down_get_model(status)),==,5);g_assert_cmpuint(g_list_model_get_n_items(gtk_drop_down_get_model(run)),==,2);
|
||||||
|
GPtrArray*h=document_authenticity_service_history(d,EVIDENCE,&error);g_assert_no_error(error);g_assert_cmpuint(h->len,==,0);g_ptr_array_unref(h);
|
||||||
|
gtk_drop_down_set_selected(status,2);g_signal_emit_by_name(save,"clicked");g_assert_true(gtk_widget_get_visible(GTK_WIDGET(message)));g_assert_nonnull(g_strstr_len(gtk_label_get_text(message),-1,"justification"));
|
||||||
|
GtkTextBuffer*j=gtk_text_view_get_buffer(GTK_TEXT_VIEW(named(root,"authenticity-justification")));gtk_text_buffer_set_text(j,"Élément factuel SPECIMEN",-1);gtk_drop_down_set_selected(run,1);g_signal_emit_by_name(save,"clicked");g_assert_false(gtk_widget_get_visible(GTK_WIDGET(message)));
|
||||||
|
h=document_authenticity_service_history(d,EVIDENCE,&error);g_assert_cmpuint(h->len,==,1);DocumentAuthenticityAssessment*a=g_ptr_array_index(h,0);g_assert_cmpstr(document_authenticity_assessment_get_status(a),==,"suspicious");g_assert_cmpstr(document_authenticity_assessment_get_ocr_run_identifier(a),==,RUN);g_assert_cmpstr(document_authenticity_assessment_get_origin(a),==,"human");g_ptr_array_unref(h);
|
||||||
|
g_object_unref(root);document_authenticity_editor_free(x);database_close(d);d=database_open(path);h=document_authenticity_service_history(d,EVIDENCE,&error);g_assert_no_error(error);g_assert_cmpuint(h->len,==,1);g_ptr_array_unref(h);database_close(d);remove_fixture(dir,path);
|
||||||
|
}
|
||||||
|
int main(int argc,char**argv){gtk_init();g_test_init(&argc,&argv,NULL);g_test_add_func("/authenticity/editor",test_editor);return g_test_run();}
|
||||||
|
|
@ -327,6 +327,8 @@ static gboolean drive(gpointer data)
|
||||||
context->main_window);
|
context->main_window);
|
||||||
g_assert_true(gtk_window_get_modal(dialog));
|
g_assert_true(gtk_window_get_modal(dialog));
|
||||||
g_assert_true(gtk_window_get_destroy_with_parent(dialog));
|
g_assert_true(gtk_window_get_destroy_with_parent(dialog));
|
||||||
|
g_assert_nonnull(find_named(GTK_WIDGET(dialog),
|
||||||
|
"document-authenticity-editor"));
|
||||||
}
|
}
|
||||||
if (dialog == NULL) {
|
if (dialog == NULL) {
|
||||||
if (context->phase == 1) {
|
if (context->phase == 1) {
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
#include "dao/identity_ocr_dao.h"
|
#include "dao/identity_ocr_dao.h"
|
||||||
#include "database/database.h"
|
#include "database/database.h"
|
||||||
#include "models/identity_traceability.h"
|
#include "models/identity_traceability.h"
|
||||||
|
#include "core/document_authenticity_service.h"
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include <glib/gstdio.h>
|
#include <glib/gstdio.h>
|
||||||
#include <sqlite3.h>
|
#include <sqlite3.h>
|
||||||
|
|
@ -66,6 +67,11 @@ static void fixture_free(Fixture*f)
|
||||||
|
|
||||||
static void test_models(void)
|
static void test_models(void)
|
||||||
{
|
{
|
||||||
|
gsize status_count=0;const DocumentAuthenticityStatus*auth_statuses=
|
||||||
|
document_authenticity_service_statuses(&status_count);
|
||||||
|
static const char*auth_codes[]={"indeterminate","presumed_authentic","suspicious","presumed_forged","confirmed_forged"};
|
||||||
|
static const char*auth_labels[]={"Authenticité indéterminée","Document présumé authentique","Document présentant des éléments suspects","Document présumé falsifié","Falsification confirmée"};
|
||||||
|
g_assert_cmpuint(status_count,==,5);for(guint i=0;i<status_count;i++){g_assert_cmpstr(auth_statuses[i].code,==,auth_codes[i]);g_assert_cmpstr(auth_statuses[i].label,==,auth_labels[i]);g_assert_nonnull(auth_statuses[i].description);}
|
||||||
static const char *codes[]={"identity_observed_in",
|
static const char *codes[]={"identity_observed_in",
|
||||||
"document_presented_in_name_of","declared_holder_in","data_extracted_from"};
|
"document_presented_in_name_of","declared_holder_in","data_extracted_from"};
|
||||||
static const char *labels[]={"Identité observée dans la preuve",
|
static const char *labels[]={"Identité observée dans la preuve",
|
||||||
|
|
@ -96,6 +102,18 @@ static void test_models(void)
|
||||||
document_authenticity_assessment_copy(a);g_assert_cmpstr(c->status,==,a->status);
|
document_authenticity_assessment_copy(a);g_assert_cmpstr(c->status,==,a->status);
|
||||||
document_authenticity_assessment_free(c);document_authenticity_assessment_free(a);
|
document_authenticity_assessment_free(c);document_authenticity_assessment_free(a);
|
||||||
}
|
}
|
||||||
|
static void test_authenticity_service(void)
|
||||||
|
{
|
||||||
|
Fixture f=fixture_new();GError*error=NULL;DocumentAuthenticityAssessment*created=NULL;
|
||||||
|
g_assert_false(document_authenticity_service_add(f.database,EVIDENCE,"suspicious"," ",NULL,NULL,&created,&error));g_assert_error(error,g_quark_from_static_string("document-authenticity-service"),1);g_clear_error(&error);
|
||||||
|
g_assert_true(document_authenticity_service_add(f.database,EVIDENCE,"indeterminate",NULL,"Note SPECIMEN",NULL,&created,&error));g_assert_no_error(error);g_assert_null(document_authenticity_assessment_get_previous_identifier(created));document_authenticity_assessment_free(created);
|
||||||
|
g_assert_true(document_authenticity_service_add(f.database,EVIDENCE,"suspicious","Élément SPECIMEN",NULL,RUN,&created,&error));g_assert_no_error(error);g_assert_nonnull(document_authenticity_assessment_get_previous_identifier(created));document_authenticity_assessment_free(created);
|
||||||
|
GPtrArray*h=document_authenticity_service_history(f.database,EVIDENCE,&error);g_assert_no_error(error);g_assert_cmpuint(h->len,==,2);g_ptr_array_unref(h);
|
||||||
|
g_assert_false(document_authenticity_service_add(f.database,EVIDENCE,
|
||||||
|
"indeterminate",NULL,NULL,"30000000-0000-4000-8000-000000000099",
|
||||||
|
NULL,&error));g_assert_nonnull(error);g_clear_error(&error);
|
||||||
|
h=document_authenticity_service_history(f.database,EVIDENCE,&error);g_assert_cmpuint(h->len,==,2);g_ptr_array_unref(h);fixture_free(&f);
|
||||||
|
}
|
||||||
static void test_dao_history_and_relations(void)
|
static void test_dao_history_and_relations(void)
|
||||||
{
|
{
|
||||||
Fixture f=fixture_new();GError*e=NULL;
|
Fixture f=fixture_new();GError*e=NULL;
|
||||||
|
|
@ -248,6 +266,7 @@ static void test_migrate_v17_preserves_ocr(void)
|
||||||
int main(int argc,char**argv)
|
int main(int argc,char**argv)
|
||||||
{g_test_init(&argc,&argv,NULL);g_test_add_func("/v18/models",test_models);
|
{g_test_init(&argc,&argv,NULL);g_test_add_func("/v18/models",test_models);
|
||||||
g_test_add_func("/v18/dao-history-relations",test_dao_history_and_relations);
|
g_test_add_func("/v18/dao-history-relations",test_dao_history_and_relations);
|
||||||
|
g_test_add_func("/v18/authenticity-service",test_authenticity_service);
|
||||||
g_test_add_func("/v18/sqlite-negative-guards",test_sqlite_negative_guards);
|
g_test_add_func("/v18/sqlite-negative-guards",test_sqlite_negative_guards);
|
||||||
g_test_add_func("/v18/migrate-v17",test_migrate_v17_preserves_ocr);
|
g_test_add_func("/v18/migrate-v17",test_migrate_v17_preserves_ocr);
|
||||||
return g_test_run();}
|
return g_test_run();}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue