feat(graph): display social platform icons
This commit is contained in:
parent
e91c5f5ee0
commit
800dee9b76
7 changed files with 322 additions and 13 deletions
13
Makefile
13
Makefile
|
|
@ -122,6 +122,7 @@ TEST_OSINT_EXECUTION_DAO := tests/test_osint_execution_dao
|
||||||
TEST_OSINT_EXECUTION_INTEGRITY := tests/test_osint_execution_integrity
|
TEST_OSINT_EXECUTION_INTEGRITY := tests/test_osint_execution_integrity
|
||||||
TEST_EVIDENCE_RECLASSIFICATION := tests/test_evidence_reclassification
|
TEST_EVIDENCE_RECLASSIFICATION := tests/test_evidence_reclassification
|
||||||
TEST_SOCIAL_ACCOUNT_SERVICE := tests/test_social_account_service
|
TEST_SOCIAL_ACCOUNT_SERVICE := tests/test_social_account_service
|
||||||
|
TEST_SOCIAL_PLATFORM := tests/test_social_platform
|
||||||
|
|
||||||
all: $(TARGET)
|
all: $(TARGET)
|
||||||
|
|
||||||
|
|
@ -623,6 +624,11 @@ $(TEST_SOCIAL_ACCOUNT_SERVICE): \
|
||||||
src/database/error.c
|
src/database/error.c
|
||||||
$(CC) $(TEST_CFLAGS) $^ -o $@ $(TEST_LDFLAGS) -lsqlite3
|
$(CC) $(TEST_CFLAGS) $^ -o $@ $(TEST_LDFLAGS) -lsqlite3
|
||||||
|
|
||||||
|
$(TEST_SOCIAL_PLATFORM): \
|
||||||
|
tests/test_social_platform.c \
|
||||||
|
src/models/social_platform.c
|
||||||
|
$(CC) $(TEST_CFLAGS) $^ -o $@ $(TEST_LDFLAGS)
|
||||||
|
|
||||||
$(TEST_INVESTIGATION_GRAPH_LOAD_TASK): \
|
$(TEST_INVESTIGATION_GRAPH_LOAD_TASK): \
|
||||||
tests/test_investigation_graph_load_task.c \
|
tests/test_investigation_graph_load_task.c \
|
||||||
src/core/investigation_graph_load_task.c \
|
src/core/investigation_graph_load_task.c \
|
||||||
|
|
@ -699,7 +705,8 @@ test: \
|
||||||
$(TEST_OSINT_EXECUTION_DAO) \
|
$(TEST_OSINT_EXECUTION_DAO) \
|
||||||
$(TEST_OSINT_EXECUTION_INTEGRITY) \
|
$(TEST_OSINT_EXECUTION_INTEGRITY) \
|
||||||
$(TEST_EVIDENCE_RECLASSIFICATION) \
|
$(TEST_EVIDENCE_RECLASSIFICATION) \
|
||||||
$(TEST_SOCIAL_ACCOUNT_SERVICE)
|
$(TEST_SOCIAL_ACCOUNT_SERVICE) \
|
||||||
|
$(TEST_SOCIAL_PLATFORM)
|
||||||
@echo "Exécution des tests..."
|
@echo "Exécution des tests..."
|
||||||
@./$(TEST_NODE)
|
@./$(TEST_NODE)
|
||||||
@./$(TEST_TREE_MODEL)
|
@./$(TEST_TREE_MODEL)
|
||||||
|
|
@ -756,6 +763,7 @@ test: \
|
||||||
@$(TEST_OSINT_EXECUTION_INTEGRITY)
|
@$(TEST_OSINT_EXECUTION_INTEGRITY)
|
||||||
@$(TEST_EVIDENCE_RECLASSIFICATION)
|
@$(TEST_EVIDENCE_RECLASSIFICATION)
|
||||||
@$(TEST_SOCIAL_ACCOUNT_SERVICE)
|
@$(TEST_SOCIAL_ACCOUNT_SERVICE)
|
||||||
|
@$(TEST_SOCIAL_PLATFORM)
|
||||||
@echo "Tous les tests sont valides."
|
@echo "Tous les tests sont valides."
|
||||||
|
|
||||||
%.o: %.c
|
%.o: %.c
|
||||||
|
|
@ -818,7 +826,8 @@ clean:
|
||||||
$(TEST_OSINT_EXECUTION_DAO) \
|
$(TEST_OSINT_EXECUTION_DAO) \
|
||||||
$(TEST_OSINT_EXECUTION_INTEGRITY) \
|
$(TEST_OSINT_EXECUTION_INTEGRITY) \
|
||||||
$(TEST_EVIDENCE_RECLASSIFICATION) \
|
$(TEST_EVIDENCE_RECLASSIFICATION) \
|
||||||
$(TEST_SOCIAL_ACCOUNT_SERVICE)
|
$(TEST_SOCIAL_ACCOUNT_SERVICE) \
|
||||||
|
$(TEST_SOCIAL_PLATFORM)
|
||||||
|
|
||||||
-include $(DEP)
|
-include $(DEP)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -161,6 +161,8 @@ Le socle actuel comprend notamment :
|
||||||
- comptes sociaux structurés en SQLite V4 (TikTok, Instagram, Facebook, X,
|
- comptes sociaux structurés en SQLite V4 (TikTok, Instagram, Facebook, X,
|
||||||
Telegram ou autre), avec URL, pseudonyme, identifiant stable facultatif,
|
Telegram ou autre), avec URL, pseudonyme, identifiant stable facultatif,
|
||||||
première observation, état, notes et rattachement à une preuve ;
|
première observation, état, notes et rattachement à une preuve ;
|
||||||
|
- pictogrammes vectoriels des plateformes sociales dans les nœuds du graphe,
|
||||||
|
conservant leur lisibilité pendant le zoom ;
|
||||||
- historique OSINT contextuel en lecture seule avec détail des exécutions,
|
- historique OSINT contextuel en lecture seule avec détail des exécutions,
|
||||||
sorties standard et d'erreur, et objets créés ou réutilisés ;
|
sorties standard et d'erreur, et objets créés ou réutilisés ;
|
||||||
- vérification manuelle de l'intégrité des sorties OSINT enregistrées, sans
|
- vérification manuelle de l'intégrité des sorties OSINT enregistrées, sans
|
||||||
|
|
|
||||||
45
include/models/social_platform.h
Normal file
45
include/models/social_platform.h
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* @file social_platform.h
|
||||||
|
* @brief Identification visuelle des plateformes sociales du graphe.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef LABFY_INVESTIGATION_SOCIAL_PLATFORM_H
|
||||||
|
#define LABFY_INVESTIGATION_SOCIAL_PLATFORM_H
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
/** @brief Plateformes possédant un pictogramme dans le graphe. */
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
SOCIAL_PLATFORM_NONE,
|
||||||
|
SOCIAL_PLATFORM_TIKTOK,
|
||||||
|
SOCIAL_PLATFORM_INSTAGRAM,
|
||||||
|
SOCIAL_PLATFORM_FACEBOOK,
|
||||||
|
SOCIAL_PLATFORM_X,
|
||||||
|
SOCIAL_PLATFORM_TELEGRAM,
|
||||||
|
SOCIAL_PLATFORM_OTHER
|
||||||
|
} SocialPlatform;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Déduit la plateforme depuis le code du type d'entité.
|
||||||
|
* @param entity_type_identifier Code métier du type d'entité.
|
||||||
|
* @return Plateforme correspondante, ou SOCIAL_PLATFORM_NONE.
|
||||||
|
*/
|
||||||
|
SocialPlatform social_platform_from_entity_type(
|
||||||
|
const char *entity_type_identifier
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Retourne le libellé français affichable d'une plateforme.
|
||||||
|
* @param platform Plateforme à décrire.
|
||||||
|
* @return Chaîne statique, ou NULL pour SOCIAL_PLATFORM_NONE.
|
||||||
|
*/
|
||||||
|
const char *social_platform_get_label(
|
||||||
|
SocialPlatform platform
|
||||||
|
);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif
|
||||||
42
src/models/social_platform.c
Normal file
42
src/models/social_platform.c
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* @file social_platform.c
|
||||||
|
* @brief Identification visuelle des plateformes sociales du graphe.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#include "models/social_platform.h"
|
||||||
|
|
||||||
|
SocialPlatform social_platform_from_entity_type(
|
||||||
|
const char *entity_type_identifier
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (g_strcmp0(entity_type_identifier, "tiktok_account") == 0)
|
||||||
|
return SOCIAL_PLATFORM_TIKTOK;
|
||||||
|
if (g_strcmp0(entity_type_identifier, "instagram_account") == 0)
|
||||||
|
return SOCIAL_PLATFORM_INSTAGRAM;
|
||||||
|
if (g_strcmp0(entity_type_identifier, "facebook_account") == 0)
|
||||||
|
return SOCIAL_PLATFORM_FACEBOOK;
|
||||||
|
if (g_strcmp0(entity_type_identifier, "x_account") == 0)
|
||||||
|
return SOCIAL_PLATFORM_X;
|
||||||
|
if (g_strcmp0(entity_type_identifier, "telegram_account") == 0)
|
||||||
|
return SOCIAL_PLATFORM_TELEGRAM;
|
||||||
|
if (g_strcmp0(entity_type_identifier, "social_account") == 0)
|
||||||
|
return SOCIAL_PLATFORM_OTHER;
|
||||||
|
return SOCIAL_PLATFORM_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *social_platform_get_label(
|
||||||
|
SocialPlatform platform
|
||||||
|
)
|
||||||
|
{
|
||||||
|
switch (platform)
|
||||||
|
{
|
||||||
|
case SOCIAL_PLATFORM_TIKTOK: return "TikTok";
|
||||||
|
case SOCIAL_PLATFORM_INSTAGRAM: return "Instagram";
|
||||||
|
case SOCIAL_PLATFORM_FACEBOOK: return "Facebook";
|
||||||
|
case SOCIAL_PLATFORM_X: return "X";
|
||||||
|
case SOCIAL_PLATFORM_TELEGRAM: return "Telegram";
|
||||||
|
case SOCIAL_PLATFORM_OTHER: return "Réseau social";
|
||||||
|
case SOCIAL_PLATFORM_NONE: return NULL;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
@ -110,17 +110,34 @@ static void create_social_account_dialog_on_create(GtkButton *button, gpointer u
|
||||||
const char *username = gtk_editable_get_text(GTK_EDITABLE(state->username));
|
const char *username = gtk_editable_get_text(GTK_EDITABLE(state->username));
|
||||||
const char *observed_at = gtk_editable_get_text(GTK_EDITABLE(state->observed_at));
|
const char *observed_at = gtk_editable_get_text(GTK_EDITABLE(state->observed_at));
|
||||||
(void) button;
|
(void) button;
|
||||||
date = g_date_time_new_from_iso8601(observed_at, NULL);
|
|
||||||
if (platform >= G_N_ELEMENTS(platform_codes) ||
|
if (platform >= G_N_ELEMENTS(platform_codes) ||
|
||||||
account_state >= G_N_ELEMENTS(state_codes) ||
|
account_state >= G_N_ELEMENTS(state_codes))
|
||||||
url == NULL ||
|
{
|
||||||
(!g_str_has_prefix(url, "https://") && !g_str_has_prefix(url, "http://")) ||
|
gtk_label_set_text(state->error, "Sélectionnez une plateforme et un état.");
|
||||||
username == NULL || username[0] == '\0' || date == NULL)
|
gtk_widget_set_visible(GTK_WIDGET(state->error), TRUE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (url == NULL ||
|
||||||
|
(!g_str_has_prefix(url, "https://") && !g_str_has_prefix(url, "http://")))
|
||||||
{
|
{
|
||||||
gtk_label_set_text(state->error,
|
gtk_label_set_text(state->error,
|
||||||
"Renseignez une URL http(s), un pseudonyme et une date ISO 8601 valide.");
|
"L'URL du profil doit commencer par https:// ou http://.");
|
||||||
|
gtk_widget_set_visible(GTK_WIDGET(state->error), TRUE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (username == NULL || username[0] == '\0')
|
||||||
|
{
|
||||||
|
gtk_label_set_text(state->error,
|
||||||
|
"Le pseudonyme affiché est obligatoire (par exemple @compte).");
|
||||||
|
gtk_widget_set_visible(GTK_WIDGET(state->error), TRUE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
date = g_date_time_new_from_iso8601(observed_at, NULL);
|
||||||
|
if (date == NULL)
|
||||||
|
{
|
||||||
|
gtk_label_set_text(state->error,
|
||||||
|
"La date doit respecter le format UTC AAAA-MM-JJTHH:MM:SSZ.");
|
||||||
gtk_widget_set_visible(GTK_WIDGET(state->error), TRUE);
|
gtk_widget_set_visible(GTK_WIDGET(state->error), TRUE);
|
||||||
g_clear_pointer(&date, g_date_time_unref);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
notes = create_social_account_dialog_notes(state);
|
notes = create_social_account_dialog_notes(state);
|
||||||
|
|
@ -217,7 +234,8 @@ gboolean create_social_account_dialog_present(
|
||||||
}
|
}
|
||||||
state->evidence = GTK_DROP_DOWN(gtk_drop_down_new(
|
state->evidence = GTK_DROP_DOWN(gtk_drop_down_new(
|
||||||
G_LIST_MODEL(evidence_labels), NULL));
|
G_LIST_MODEL(evidence_labels), NULL));
|
||||||
g_object_unref(evidence_labels);
|
/* gtk_drop_down_new() prend possession de la référence du modèle. */
|
||||||
|
evidence_labels = NULL;
|
||||||
state->notes = GTK_TEXT_VIEW(gtk_text_view_new());
|
state->notes = GTK_TEXT_VIEW(gtk_text_view_new());
|
||||||
gtk_text_view_set_wrap_mode(state->notes, GTK_WRAP_WORD_CHAR);
|
gtk_text_view_set_wrap_mode(state->notes, GTK_WRAP_WORD_CHAR);
|
||||||
gtk_widget_set_size_request(GTK_WIDGET(state->notes), -1, 100);
|
gtk_widget_set_size_request(GTK_WIDGET(state->notes), -1, 100);
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
#include "models/investigation_graph_layout.h"
|
#include "models/investigation_graph_layout.h"
|
||||||
#include "models/investigation_graph_model.h"
|
#include "models/investigation_graph_model.h"
|
||||||
#include "models/relation_record.h"
|
#include "models/relation_record.h"
|
||||||
|
#include "models/social_platform.h"
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include <pango/pangocairo.h>
|
#include <pango/pangocairo.h>
|
||||||
|
|
@ -23,6 +24,8 @@
|
||||||
#define INVESTIGATION_GRAPH_VIEW_NODE_RADIUS 12.0
|
#define INVESTIGATION_GRAPH_VIEW_NODE_RADIUS 12.0
|
||||||
#define INVESTIGATION_GRAPH_VIEW_RELATION_NODE_RADIUS 10.0
|
#define INVESTIGATION_GRAPH_VIEW_RELATION_NODE_RADIUS 10.0
|
||||||
#define INVESTIGATION_GRAPH_VIEW_NODE_PADDING 12
|
#define INVESTIGATION_GRAPH_VIEW_NODE_PADDING 12
|
||||||
|
#define INVESTIGATION_GRAPH_VIEW_SOCIAL_ICON_SIZE 38.0
|
||||||
|
#define INVESTIGATION_GRAPH_VIEW_SOCIAL_ICON_GAP 10.0
|
||||||
#define INVESTIGATION_GRAPH_VIEW_RELATION_NODE_GAP 72.0
|
#define INVESTIGATION_GRAPH_VIEW_RELATION_NODE_GAP 72.0
|
||||||
#define INVESTIGATION_GRAPH_VIEW_RELATION_NODE_CLEARANCE 16.0
|
#define INVESTIGATION_GRAPH_VIEW_RELATION_NODE_CLEARANCE 16.0
|
||||||
#define INVESTIGATION_GRAPH_VIEW_ARROW_LENGTH 9.0
|
#define INVESTIGATION_GRAPH_VIEW_ARROW_LENGTH 9.0
|
||||||
|
|
@ -3127,6 +3130,130 @@ static void investigation_graph_view_draw_relations(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Configure la couleur de fond propre à une plateforme sociale. */
|
||||||
|
static void investigation_graph_view_set_social_icon_color(
|
||||||
|
cairo_t *cairo_context,
|
||||||
|
SocialPlatform platform
|
||||||
|
)
|
||||||
|
{
|
||||||
|
switch (platform)
|
||||||
|
{
|
||||||
|
case SOCIAL_PLATFORM_TIKTOK:
|
||||||
|
cairo_set_source_rgb(cairo_context, 0.06, 0.06, 0.08);
|
||||||
|
break;
|
||||||
|
case SOCIAL_PLATFORM_INSTAGRAM:
|
||||||
|
cairo_set_source_rgb(cairo_context, 0.76, 0.18, 0.48);
|
||||||
|
break;
|
||||||
|
case SOCIAL_PLATFORM_FACEBOOK:
|
||||||
|
cairo_set_source_rgb(cairo_context, 0.10, 0.36, 0.72);
|
||||||
|
break;
|
||||||
|
case SOCIAL_PLATFORM_X:
|
||||||
|
cairo_set_source_rgb(cairo_context, 0.05, 0.06, 0.08);
|
||||||
|
break;
|
||||||
|
case SOCIAL_PLATFORM_TELEGRAM:
|
||||||
|
cairo_set_source_rgb(cairo_context, 0.12, 0.60, 0.84);
|
||||||
|
break;
|
||||||
|
case SOCIAL_PLATFORM_OTHER:
|
||||||
|
case SOCIAL_PLATFORM_NONE:
|
||||||
|
cairo_set_source_rgb(cairo_context, 0.34, 0.39, 0.50);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Dessine le symbole blanc propre à une plateforme sociale. */
|
||||||
|
static void investigation_graph_view_draw_social_symbol(
|
||||||
|
cairo_t *cairo_context,
|
||||||
|
SocialPlatform platform,
|
||||||
|
double center_x,
|
||||||
|
double center_y
|
||||||
|
)
|
||||||
|
{
|
||||||
|
cairo_set_source_rgb(cairo_context, 1.0, 1.0, 1.0);
|
||||||
|
cairo_set_line_width(cairo_context, 2.3);
|
||||||
|
cairo_set_line_cap(cairo_context, CAIRO_LINE_CAP_ROUND);
|
||||||
|
cairo_set_line_join(cairo_context, CAIRO_LINE_JOIN_ROUND);
|
||||||
|
switch (platform)
|
||||||
|
{
|
||||||
|
case SOCIAL_PLATFORM_TIKTOK:
|
||||||
|
cairo_arc(cairo_context, center_x - 4.0, center_y + 6.0,
|
||||||
|
4.2, 0.0, 2.0 * G_PI);
|
||||||
|
cairo_fill(cairo_context);
|
||||||
|
cairo_move_to(cairo_context, center_x, center_y + 6.0);
|
||||||
|
cairo_line_to(cairo_context, center_x, center_y - 9.0);
|
||||||
|
cairo_line_to(cairo_context, center_x + 4.0, center_y - 6.0);
|
||||||
|
cairo_line_to(cairo_context, center_x + 8.0, center_y - 5.0);
|
||||||
|
cairo_stroke(cairo_context);
|
||||||
|
break;
|
||||||
|
case SOCIAL_PLATFORM_INSTAGRAM:
|
||||||
|
investigation_graph_view_rounded_rectangle(cairo_context,
|
||||||
|
center_x - 10.0, center_y - 10.0, 20.0, 20.0, 5.0);
|
||||||
|
cairo_stroke(cairo_context);
|
||||||
|
cairo_arc(cairo_context, center_x, center_y, 4.7,
|
||||||
|
0.0, 2.0 * G_PI);
|
||||||
|
cairo_stroke(cairo_context);
|
||||||
|
cairo_arc(cairo_context, center_x + 6.0, center_y - 6.0,
|
||||||
|
1.4, 0.0, 2.0 * G_PI);
|
||||||
|
cairo_fill(cairo_context);
|
||||||
|
break;
|
||||||
|
case SOCIAL_PLATFORM_FACEBOOK:
|
||||||
|
investigation_graph_view_draw_text(cairo_context, "f",
|
||||||
|
center_x - 5.0, center_y - 14.0, 14,
|
||||||
|
"Sans Bold 21", 1.0, 1.0, 1.0);
|
||||||
|
break;
|
||||||
|
case SOCIAL_PLATFORM_X:
|
||||||
|
cairo_move_to(cairo_context, center_x - 8.0, center_y - 9.0);
|
||||||
|
cairo_line_to(cairo_context, center_x + 8.0, center_y + 9.0);
|
||||||
|
cairo_move_to(cairo_context, center_x + 8.0, center_y - 9.0);
|
||||||
|
cairo_line_to(cairo_context, center_x - 8.0, center_y + 9.0);
|
||||||
|
cairo_stroke(cairo_context);
|
||||||
|
break;
|
||||||
|
case SOCIAL_PLATFORM_TELEGRAM:
|
||||||
|
cairo_move_to(cairo_context, center_x - 11.0, center_y - 1.0);
|
||||||
|
cairo_line_to(cairo_context, center_x + 11.0, center_y - 9.0);
|
||||||
|
cairo_line_to(cairo_context, center_x + 5.0, center_y + 10.0);
|
||||||
|
cairo_line_to(cairo_context, center_x, center_y + 3.0);
|
||||||
|
cairo_line_to(cairo_context, center_x - 5.0, center_y + 7.0);
|
||||||
|
cairo_close_path(cairo_context);
|
||||||
|
cairo_fill(cairo_context);
|
||||||
|
break;
|
||||||
|
case SOCIAL_PLATFORM_OTHER:
|
||||||
|
cairo_arc(cairo_context, center_x, center_y - 6.0, 4.0,
|
||||||
|
0.0, 2.0 * G_PI);
|
||||||
|
cairo_arc(cairo_context, center_x - 8.0, center_y + 7.0, 3.0,
|
||||||
|
0.0, 2.0 * G_PI);
|
||||||
|
cairo_arc(cairo_context, center_x + 8.0, center_y + 7.0, 3.0,
|
||||||
|
0.0, 2.0 * G_PI);
|
||||||
|
cairo_fill(cairo_context);
|
||||||
|
cairo_move_to(cairo_context, center_x, center_y - 2.0);
|
||||||
|
cairo_line_to(cairo_context, center_x - 7.0, center_y + 4.0);
|
||||||
|
cairo_move_to(cairo_context, center_x, center_y - 2.0);
|
||||||
|
cairo_line_to(cairo_context, center_x + 7.0, center_y + 4.0);
|
||||||
|
cairo_stroke(cairo_context);
|
||||||
|
break;
|
||||||
|
case SOCIAL_PLATFORM_NONE:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Dessine le badge vectoriel d'un compte social. */
|
||||||
|
static void investigation_graph_view_draw_social_icon(
|
||||||
|
cairo_t *cairo_context,
|
||||||
|
SocialPlatform platform,
|
||||||
|
double x,
|
||||||
|
double y
|
||||||
|
)
|
||||||
|
{
|
||||||
|
double center_x = x + (INVESTIGATION_GRAPH_VIEW_SOCIAL_ICON_SIZE / 2.0);
|
||||||
|
double center_y = y + (INVESTIGATION_GRAPH_VIEW_SOCIAL_ICON_SIZE / 2.0);
|
||||||
|
investigation_graph_view_set_social_icon_color(cairo_context, platform);
|
||||||
|
cairo_arc(cairo_context, center_x, center_y,
|
||||||
|
INVESTIGATION_GRAPH_VIEW_SOCIAL_ICON_SIZE / 2.0,
|
||||||
|
0.0, 2.0 * G_PI);
|
||||||
|
cairo_fill(cairo_context);
|
||||||
|
investigation_graph_view_draw_social_symbol(
|
||||||
|
cairo_context, platform, center_x, center_y);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Dessine un nœud d'entité.
|
* @brief Dessine un nœud d'entité.
|
||||||
*/
|
*/
|
||||||
|
|
@ -3144,6 +3271,15 @@ static void investigation_graph_view_draw_entity(
|
||||||
const char *type_identifier =
|
const char *type_identifier =
|
||||||
NULL;
|
NULL;
|
||||||
|
|
||||||
|
const char *type_label =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
SocialPlatform social_platform =
|
||||||
|
SOCIAL_PLATFORM_NONE;
|
||||||
|
|
||||||
|
double text_x =
|
||||||
|
x + INVESTIGATION_GRAPH_VIEW_NODE_PADDING;
|
||||||
|
|
||||||
int text_width =
|
int text_width =
|
||||||
(int) INVESTIGATION_GRAPH_VIEW_NODE_WIDTH -
|
(int) INVESTIGATION_GRAPH_VIEW_NODE_WIDTH -
|
||||||
(2 * INVESTIGATION_GRAPH_VIEW_NODE_PADDING);
|
(2 * INVESTIGATION_GRAPH_VIEW_NODE_PADDING);
|
||||||
|
|
@ -3228,10 +3364,27 @@ static void investigation_graph_view_draw_entity(
|
||||||
entity_record
|
entity_record
|
||||||
);
|
);
|
||||||
|
|
||||||
|
social_platform = social_platform_from_entity_type(type_identifier);
|
||||||
|
|
||||||
|
if (social_platform != SOCIAL_PLATFORM_NONE)
|
||||||
|
{
|
||||||
|
investigation_graph_view_draw_social_icon(
|
||||||
|
cairo_context,
|
||||||
|
social_platform,
|
||||||
|
x + INVESTIGATION_GRAPH_VIEW_NODE_PADDING,
|
||||||
|
y + 20.0
|
||||||
|
);
|
||||||
|
text_x += INVESTIGATION_GRAPH_VIEW_SOCIAL_ICON_SIZE +
|
||||||
|
INVESTIGATION_GRAPH_VIEW_SOCIAL_ICON_GAP;
|
||||||
|
text_width -= (int) (INVESTIGATION_GRAPH_VIEW_SOCIAL_ICON_SIZE +
|
||||||
|
INVESTIGATION_GRAPH_VIEW_SOCIAL_ICON_GAP);
|
||||||
|
type_label = social_platform_get_label(social_platform);
|
||||||
|
}
|
||||||
|
|
||||||
investigation_graph_view_draw_text(
|
investigation_graph_view_draw_text(
|
||||||
cairo_context,
|
cairo_context,
|
||||||
title,
|
title,
|
||||||
x + INVESTIGATION_GRAPH_VIEW_NODE_PADDING,
|
text_x,
|
||||||
y + 13.0,
|
y + 13.0,
|
||||||
text_width,
|
text_width,
|
||||||
"Sans Bold 11",
|
"Sans Bold 11",
|
||||||
|
|
@ -3242,11 +3395,13 @@ static void investigation_graph_view_draw_entity(
|
||||||
|
|
||||||
investigation_graph_view_draw_text(
|
investigation_graph_view_draw_text(
|
||||||
cairo_context,
|
cairo_context,
|
||||||
type_identifier != NULL &&
|
type_label != NULL
|
||||||
|
? type_label
|
||||||
|
: type_identifier != NULL &&
|
||||||
type_identifier[0] != '\0'
|
type_identifier[0] != '\0'
|
||||||
? type_identifier
|
? type_identifier
|
||||||
: "(type inconnu)",
|
: "(type inconnu)",
|
||||||
x + INVESTIGATION_GRAPH_VIEW_NODE_PADDING,
|
text_x,
|
||||||
y + 44.0,
|
y + 44.0,
|
||||||
text_width,
|
text_width,
|
||||||
"Sans 9",
|
"Sans 9",
|
||||||
|
|
|
||||||
38
tests/test_social_platform.c
Normal file
38
tests/test_social_platform.c
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* @file test_social_platform.c
|
||||||
|
* @brief Tests de la correspondance visuelle des plateformes sociales.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#include "models/social_platform.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/** @brief Vérifie tous les types sociaux persistés et le cas générique. */
|
||||||
|
static void test_social_platform_mapping(void)
|
||||||
|
{
|
||||||
|
assert(social_platform_from_entity_type("tiktok_account") ==
|
||||||
|
SOCIAL_PLATFORM_TIKTOK);
|
||||||
|
assert(social_platform_from_entity_type("instagram_account") ==
|
||||||
|
SOCIAL_PLATFORM_INSTAGRAM);
|
||||||
|
assert(social_platform_from_entity_type("facebook_account") ==
|
||||||
|
SOCIAL_PLATFORM_FACEBOOK);
|
||||||
|
assert(social_platform_from_entity_type("x_account") == SOCIAL_PLATFORM_X);
|
||||||
|
assert(social_platform_from_entity_type("telegram_account") ==
|
||||||
|
SOCIAL_PLATFORM_TELEGRAM);
|
||||||
|
assert(social_platform_from_entity_type("social_account") ==
|
||||||
|
SOCIAL_PLATFORM_OTHER);
|
||||||
|
assert(social_platform_from_entity_type("person") == SOCIAL_PLATFORM_NONE);
|
||||||
|
assert(social_platform_from_entity_type(NULL) == SOCIAL_PLATFORM_NONE);
|
||||||
|
assert(strcmp(social_platform_get_label(SOCIAL_PLATFORM_INSTAGRAM),
|
||||||
|
"Instagram") == 0);
|
||||||
|
assert(social_platform_get_label(SOCIAL_PLATFORM_NONE) == NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
test_social_platform_mapping();
|
||||||
|
puts("SocialPlatform : tous les tests sont valides.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue