feat(persons): allow confidence editing from details
This commit is contained in:
parent
f585041736
commit
18e59cc5e6
9 changed files with 225 additions and 0 deletions
|
|
@ -32,5 +32,15 @@ gboolean person_entity_service_create(Database *database,
|
|||
/** @brief Enregistre le rôle d'une personne existante. */
|
||||
gboolean person_entity_service_update_role(Database *database,
|
||||
const char *entity_identifier, PersonRole role, GError **error);
|
||||
/**
|
||||
* @brief Enregistre le niveau de confiance d'une personne existante.
|
||||
* @param database Connexion ouverte empruntée.
|
||||
* @param entity_identifier UUID de la personne.
|
||||
* @param confidence Valeur comprise entre 0 et 100.
|
||||
* @param error Destination facultative d'une erreur.
|
||||
* @return TRUE lorsque la modification est validée.
|
||||
*/
|
||||
gboolean person_entity_service_update_confidence(Database *database,
|
||||
const char *entity_identifier, gint confidence, GError **error);
|
||||
G_END_DECLS
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -152,6 +152,9 @@ typedef void (*MainWindowRelationSelectedCallback)(
|
|||
/** @brief Callback appelé pour catégoriser une personne. */
|
||||
typedef void (*MainWindowPersonRoleCallback)(const char *entity_identifier,
|
||||
PersonRole role, gpointer user_data);
|
||||
/** @brief Callback appelé pour modifier la confiance d'une personne. */
|
||||
typedef void (*MainWindowPersonConfidenceCallback)(
|
||||
const char *entity_identifier, gint confidence, gpointer user_data);
|
||||
|
||||
/**
|
||||
* @brief Callback appelé lors du déclenchement d'une action OSINT.
|
||||
|
|
@ -266,6 +269,9 @@ void main_window_set_relation_evidences(
|
|||
/** @brief Définit le callback de catégorisation d'une personne. */
|
||||
void main_window_set_person_role_callback(MainWindow *main_window,
|
||||
MainWindowPersonRoleCallback callback, gpointer user_data);
|
||||
/** @brief Définit le callback de confiance d'une personne. */
|
||||
void main_window_set_person_confidence_callback(MainWindow *main_window,
|
||||
MainWindowPersonConfidenceCallback callback, gpointer user_data);
|
||||
|
||||
/**
|
||||
* @brief Définit le callback de déclenchement des actions OSINT.
|
||||
|
|
|
|||
|
|
@ -53,6 +53,13 @@ typedef void (*EntityDetailsPanelPersonRoleCallback)(
|
|||
gpointer user_data
|
||||
);
|
||||
|
||||
/** @brief Callback appelé pour enregistrer la confiance d'une personne. */
|
||||
typedef void (*EntityDetailsPanelPersonConfidenceCallback)(
|
||||
const char *entity_identifier,
|
||||
gint confidence,
|
||||
gpointer user_data
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Crée un volet de détails fermé.
|
||||
*
|
||||
|
|
@ -135,6 +142,19 @@ void entity_details_panel_set_person_role_callback(
|
|||
gpointer user_data
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Définit le callback de modification de la confiance d'une personne.
|
||||
*
|
||||
* @param details_panel Volet à configurer.
|
||||
* @param callback Callback à appeler, ou NULL.
|
||||
* @param user_data Données empruntées du callback.
|
||||
*/
|
||||
void entity_details_panel_set_person_confidence_callback(
|
||||
EntityDetailsPanel *details_panel,
|
||||
EntityDetailsPanelPersonConfidenceCallback callback,
|
||||
gpointer user_data
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Indique si le volet est actuellement ouvert.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -94,6 +94,9 @@ typedef void (*WorkspaceRelationSelectedCallback)(
|
|||
/** @brief Callback appelé pour catégoriser une personne. */
|
||||
typedef void (*WorkspacePersonRoleCallback)(const char *entity_identifier,
|
||||
PersonRole role, gpointer user_data);
|
||||
/** @brief Callback appelé pour modifier la confiance d'une personne. */
|
||||
typedef void (*WorkspacePersonConfidenceCallback)(
|
||||
const char *entity_identifier, gint confidence, gpointer user_data);
|
||||
|
||||
/**
|
||||
* @brief Callback appelé lors du déclenchement d'une action OSINT.
|
||||
|
|
@ -348,6 +351,9 @@ void workspace_set_relation_evidences(
|
|||
/** @brief Définit le callback de catégorisation d'une personne. */
|
||||
void workspace_set_person_role_callback(Workspace *workspace,
|
||||
WorkspacePersonRoleCallback callback, gpointer user_data);
|
||||
/** @brief Définit le callback de confiance d'une personne. */
|
||||
void workspace_set_person_confidence_callback(Workspace *workspace,
|
||||
WorkspacePersonConfidenceCallback callback, gpointer user_data);
|
||||
|
||||
/**
|
||||
* @brief Affiche l'état de chargement du graphe.
|
||||
|
|
|
|||
|
|
@ -5004,6 +5004,35 @@ static void application_on_person_role_changed(const char *entity_identifier,
|
|||
investigation_project_get_database_path(project));
|
||||
}
|
||||
|
||||
/** @brief Enregistre la confiance choisie dans la fiche personne. */
|
||||
static void application_on_person_confidence_changed(
|
||||
const char *entity_identifier, gint confidence, gpointer user_data)
|
||||
{
|
||||
Application *application = user_data;
|
||||
Database *database = NULL;
|
||||
const InvestigationProject *project = NULL;
|
||||
GError *error = NULL;
|
||||
if (application == NULL || application->session == NULL) return;
|
||||
database = investigation_session_get_database(application->session);
|
||||
project = investigation_session_get_project(application->session);
|
||||
if (!person_entity_service_update_confidence(database, entity_identifier,
|
||||
confidence, &error))
|
||||
{
|
||||
application_present_error(application, "Confiance non enregistrée",
|
||||
error != NULL ? error->message :
|
||||
"Impossible de modifier la confiance de cette personne.");
|
||||
g_clear_error(&error);
|
||||
return;
|
||||
}
|
||||
g_free(application->pending_entity_selection_identifier);
|
||||
application->pending_entity_selection_identifier =
|
||||
g_strdup(entity_identifier);
|
||||
main_window_set_status(application->main_window,
|
||||
"Confiance enregistrée. Actualisation du graphe…");
|
||||
application_start_graph_loading(application,
|
||||
investigation_project_get_database_path(project));
|
||||
}
|
||||
|
||||
/** @brief Libère le contexte d'édition d'une relation. */
|
||||
static void application_edit_relation_context_free(
|
||||
ApplicationEditRelationContext *context)
|
||||
|
|
@ -6674,6 +6703,8 @@ static void application_on_activate(
|
|||
application_on_relation_selected, application);
|
||||
main_window_set_person_role_callback(application->main_window,
|
||||
application_on_person_role_changed, application);
|
||||
main_window_set_person_confidence_callback(application->main_window,
|
||||
application_on_person_confidence_changed, application);
|
||||
|
||||
main_window_set_osint_action_callback(
|
||||
application->main_window,
|
||||
|
|
|
|||
|
|
@ -17,6 +17,68 @@ static gboolean person_entity_service_status_valid(const char *status)
|
|||
g_strcmp0(status, "confirmed") == 0;
|
||||
}
|
||||
|
||||
gboolean person_entity_service_update_confidence(Database *database,
|
||||
const char *entity_identifier, gint confidence, GError **error)
|
||||
{
|
||||
static const char validate_sql[] =
|
||||
"SELECT 1 FROM entites e JOIN types_entite t ON t.id=e.type_id "
|
||||
"WHERE e.id=? AND t.code='person';";
|
||||
static const char sql[] =
|
||||
"UPDATE entites SET confiance=?, updated_at=? WHERE id=? AND "
|
||||
"type_id=(SELECT id FROM types_entite WHERE code='person');";
|
||||
DatabaseStatement *statement = NULL;
|
||||
GDateTime *now = NULL;
|
||||
char *timestamp = NULL;
|
||||
gboolean active = FALSE, success = FALSE;
|
||||
g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
|
||||
if (database == NULL || entity_identifier == NULL ||
|
||||
!g_uuid_string_is_valid(entity_identifier) || confidence < 0 ||
|
||||
confidence > 100)
|
||||
{
|
||||
g_set_error_literal(error, g_quark_from_static_string(
|
||||
"person-entity-service-error"), 4,
|
||||
"La personne ou le niveau de confiance est invalide.");
|
||||
return FALSE;
|
||||
}
|
||||
statement = database_statement_prepare(database, validate_sql);
|
||||
if (statement == NULL || !database_statement_bind_text(statement, 1,
|
||||
entity_identifier) || database_statement_step(statement) !=
|
||||
DATABASE_STATEMENT_STEP_ROW)
|
||||
{
|
||||
database_statement_finalize(statement);
|
||||
g_set_error_literal(error, g_quark_from_static_string(
|
||||
"person-entity-service-error"), 4,
|
||||
"La personne sélectionnée n'existe pas.");
|
||||
return FALSE;
|
||||
}
|
||||
database_statement_finalize(statement); statement = NULL;
|
||||
now = g_date_time_new_now_utc();
|
||||
timestamp = now != NULL ? g_date_time_format(now,
|
||||
"%Y-%m-%dT%H:%M:%SZ") : NULL;
|
||||
if (timestamp == NULL || !database_transaction_begin(database))
|
||||
goto cleanup;
|
||||
active = TRUE;
|
||||
statement = database_statement_prepare(database, sql);
|
||||
if (statement == NULL ||
|
||||
!database_statement_bind_int64(statement, 1, confidence) ||
|
||||
!database_statement_bind_text(statement, 2, timestamp) ||
|
||||
!database_statement_bind_text(statement, 3, entity_identifier) ||
|
||||
database_statement_step(statement) != DATABASE_STATEMENT_STEP_DONE)
|
||||
goto cleanup;
|
||||
database_statement_finalize(statement); statement = NULL;
|
||||
if (!database_transaction_commit(database)) goto cleanup;
|
||||
active = FALSE; success = TRUE;
|
||||
cleanup:
|
||||
database_statement_finalize(statement);
|
||||
if (!success && active) database_transaction_rollback(database);
|
||||
if (!success && error != NULL && *error == NULL)
|
||||
g_set_error_literal(error, g_quark_from_static_string(
|
||||
"person-entity-service-error"), 5,
|
||||
"Le niveau de confiance n'a pas pu être enregistré.");
|
||||
g_free(timestamp); g_clear_pointer(&now, g_date_time_unref);
|
||||
return success;
|
||||
}
|
||||
|
||||
gboolean person_entity_service_update_role(Database *database,
|
||||
const char *entity_identifier, PersonRole role, GError **error)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -133,6 +133,8 @@ struct MainWindow
|
|||
gpointer edit_relation_user_data;
|
||||
MainWindowPersonRoleCallback person_role_callback;
|
||||
gpointer person_role_user_data;
|
||||
MainWindowPersonConfidenceCallback person_confidence_callback;
|
||||
gpointer person_confidence_user_data;
|
||||
|
||||
MainWindowOsintActionCallback
|
||||
osint_action_callback;
|
||||
|
|
@ -538,6 +540,17 @@ static void main_window_on_person_role_changed(const char *entity_identifier,
|
|||
main_window->person_role_user_data);
|
||||
}
|
||||
|
||||
/** @brief Relaie la modification de confiance d'une personne. */
|
||||
static void main_window_on_person_confidence_changed(
|
||||
const char *entity_identifier, gint confidence, gpointer user_data)
|
||||
{
|
||||
MainWindow *main_window = user_data;
|
||||
if (main_window != NULL &&
|
||||
main_window->person_confidence_callback != NULL)
|
||||
main_window->person_confidence_callback(entity_identifier, confidence,
|
||||
main_window->person_confidence_user_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Relaie la demande de vérification provenant du Workspace.
|
||||
*/
|
||||
|
|
@ -880,6 +893,8 @@ MainWindow *main_window_new(
|
|||
main_window_on_edit_relation_requested, main_window);
|
||||
workspace_set_person_role_callback(main_window->workspace,
|
||||
main_window_on_person_role_changed, main_window);
|
||||
workspace_set_person_confidence_callback(main_window->workspace,
|
||||
main_window_on_person_confidence_changed, main_window);
|
||||
|
||||
workspace_set_osint_action_callback(
|
||||
main_window->workspace,
|
||||
|
|
@ -1695,6 +1710,14 @@ void main_window_set_person_role_callback(MainWindow *main_window,
|
|||
main_window->person_role_user_data = user_data;
|
||||
}
|
||||
|
||||
void main_window_set_person_confidence_callback(MainWindow *main_window,
|
||||
MainWindowPersonConfidenceCallback callback, gpointer user_data)
|
||||
{
|
||||
if (main_window == NULL) return;
|
||||
main_window->person_confidence_callback = callback;
|
||||
main_window->person_confidence_user_data = user_data;
|
||||
}
|
||||
|
||||
void main_window_set_quit_callback(
|
||||
MainWindow *main_window,
|
||||
MainWindowQuitCallback callback,
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ struct EntityDetailsPanel
|
|||
GtkWidget *entity_identifier_label;
|
||||
GtkWidget *person_role_box;
|
||||
GtkDropDown *person_role_dropdown;
|
||||
GtkSpinButton *person_confidence_spin;
|
||||
GtkWidget *person_confidence_button;
|
||||
|
||||
char *selected_entity_identifier;
|
||||
|
||||
|
|
@ -46,8 +48,26 @@ struct EntityDetailsPanel
|
|||
EntityDetailsPanelPersonRoleCallback person_role_callback;
|
||||
gpointer person_role_user_data;
|
||||
gboolean updating_person_role;
|
||||
EntityDetailsPanelPersonConfidenceCallback person_confidence_callback;
|
||||
gpointer person_confidence_user_data;
|
||||
};
|
||||
|
||||
/** @brief Relaie la confiance explicitement enregistrée par l'utilisateur. */
|
||||
static void entity_details_panel_on_person_confidence_clicked(
|
||||
GtkButton *button, gpointer user_data)
|
||||
{
|
||||
EntityDetailsPanel *details_panel = user_data;
|
||||
(void) button;
|
||||
if (details_panel == NULL ||
|
||||
details_panel->person_confidence_callback == NULL ||
|
||||
details_panel->selected_entity_identifier == NULL) return;
|
||||
details_panel->person_confidence_callback(
|
||||
details_panel->selected_entity_identifier,
|
||||
gtk_spin_button_get_value_as_int(
|
||||
details_panel->person_confidence_spin),
|
||||
details_panel->person_confidence_user_data);
|
||||
}
|
||||
|
||||
/** @brief Relaie une catégorie choisie explicitement par l'utilisateur. */
|
||||
static void entity_details_panel_on_person_role_changed(GObject *object,
|
||||
GParamSpec *parameter, gpointer user_data)
|
||||
|
|
@ -734,9 +754,22 @@ EntityDetailsPanel *entity_details_panel_new(void)
|
|||
gtk_label_new("Catégorie dans l’enquête"));
|
||||
gtk_box_append(GTK_BOX(details_panel->person_role_box),
|
||||
GTK_WIDGET(details_panel->person_role_dropdown));
|
||||
details_panel->person_confidence_spin = GTK_SPIN_BUTTON(
|
||||
gtk_spin_button_new_with_range(0.0, 100.0, 1.0));
|
||||
details_panel->person_confidence_button = gtk_button_new_with_label(
|
||||
"Enregistrer la confiance");
|
||||
gtk_box_append(GTK_BOX(details_panel->person_role_box),
|
||||
gtk_label_new("Niveau de confiance (%)"));
|
||||
gtk_box_append(GTK_BOX(details_panel->person_role_box),
|
||||
GTK_WIDGET(details_panel->person_confidence_spin));
|
||||
gtk_box_append(GTK_BOX(details_panel->person_role_box),
|
||||
details_panel->person_confidence_button);
|
||||
gtk_box_append(GTK_BOX(details_box), details_panel->person_role_box);
|
||||
g_signal_connect(details_panel->person_role_dropdown, "notify::selected",
|
||||
G_CALLBACK(entity_details_panel_on_person_role_changed), details_panel);
|
||||
g_signal_connect(details_panel->person_confidence_button, "clicked",
|
||||
G_CALLBACK(entity_details_panel_on_person_confidence_clicked),
|
||||
details_panel);
|
||||
|
||||
if (details_panel->entity_value_label == NULL ||
|
||||
details_panel->entity_type_label == NULL ||
|
||||
|
|
@ -861,6 +894,8 @@ void entity_details_panel_set_entity(
|
|||
details_panel->updating_person_role = TRUE;
|
||||
gtk_drop_down_set_selected(details_panel->person_role_dropdown,
|
||||
(guint) entity_record_get_person_role(entity_record));
|
||||
gtk_spin_button_set_value(details_panel->person_confidence_spin,
|
||||
entity_record_get_confidence(entity_record));
|
||||
details_panel->updating_person_role = FALSE;
|
||||
|
||||
entity_details_panel_update_add_relation_button(
|
||||
|
|
@ -1117,6 +1152,15 @@ void entity_details_panel_set_person_role_callback(
|
|||
details_panel->person_role_user_data = user_data;
|
||||
}
|
||||
|
||||
void entity_details_panel_set_person_confidence_callback(
|
||||
EntityDetailsPanel *details_panel,
|
||||
EntityDetailsPanelPersonConfidenceCallback callback, gpointer user_data)
|
||||
{
|
||||
if (details_panel == NULL) return;
|
||||
details_panel->person_confidence_callback = callback;
|
||||
details_panel->person_confidence_user_data = user_data;
|
||||
}
|
||||
|
||||
gboolean entity_details_panel_is_open(
|
||||
const EntityDetailsPanel *details_panel
|
||||
)
|
||||
|
|
|
|||
|
|
@ -136,6 +136,8 @@ struct Workspace
|
|||
gpointer edit_relation_user_data;
|
||||
WorkspacePersonRoleCallback person_role_callback;
|
||||
gpointer person_role_user_data;
|
||||
WorkspacePersonConfidenceCallback person_confidence_callback;
|
||||
gpointer person_confidence_user_data;
|
||||
|
||||
WorkspaceOsintActionCallback
|
||||
osint_action_callback;
|
||||
|
|
@ -882,6 +884,16 @@ static void workspace_on_person_role_changed(const char *entity_identifier,
|
|||
workspace->person_role_user_data);
|
||||
}
|
||||
|
||||
/** @brief Relaie la modification de confiance d'une personne. */
|
||||
static void workspace_on_person_confidence_changed(
|
||||
const char *entity_identifier, gint confidence, gpointer user_data)
|
||||
{
|
||||
Workspace *workspace = user_data;
|
||||
if (workspace != NULL && workspace->person_confidence_callback != NULL)
|
||||
workspace->person_confidence_callback(entity_identifier, confidence,
|
||||
workspace->person_confidence_user_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Désélectionne le nœud lorsque le volet est fermé manuellement.
|
||||
*/
|
||||
|
|
@ -1801,6 +1813,9 @@ Workspace *workspace_new(void)
|
|||
entity_details_panel_set_person_role_callback(
|
||||
workspace->entity_details_panel, workspace_on_person_role_changed,
|
||||
workspace);
|
||||
entity_details_panel_set_person_confidence_callback(
|
||||
workspace->entity_details_panel,
|
||||
workspace_on_person_confidence_changed, workspace);
|
||||
|
||||
gtk_overlay_set_child(
|
||||
GTK_OVERLAY(
|
||||
|
|
@ -3258,6 +3273,14 @@ void workspace_set_person_role_callback(Workspace *workspace,
|
|||
workspace->person_role_user_data = user_data;
|
||||
}
|
||||
|
||||
void workspace_set_person_confidence_callback(Workspace *workspace,
|
||||
WorkspacePersonConfidenceCallback callback, gpointer user_data)
|
||||
{
|
||||
if (workspace == NULL) return;
|
||||
workspace->person_confidence_callback = callback;
|
||||
workspace->person_confidence_user_data = user_data;
|
||||
}
|
||||
|
||||
void workspace_reset_graph_layout(
|
||||
Workspace *workspace
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in a new issue