diff --git a/find_largest_commit.sh b/find_largest_commit.sh
new file mode 100755
index 00000000..519c595c
--- /dev/null
+++ b/find_largest_commit.sh
@@ -0,0 +1,222 @@
+#!/bin/bash
+
+# Script to find which commit made the biggest change in repository size
+#
+# This script analyzes git commit history to determine which commit caused
+# the largest change in the repository's size. It checks out each commit,
+# measures the repository size, and identifies the commit with the biggest
+# size difference.
+#
+# Usage: ./find_largest_commit.sh [number_of_commits_to_check]
+#
+# Arguments:
+# number_of_commits_to_check: Optional. Number of recent commits to analyze.
+# Defaults to 100 if not specified.
+#
+# Output:
+# - Detailed information about the commit with the largest size change
+# - A CSV file with data for all analyzed commits
+#
+# Requirements:
+# - git
+# - bc (for floating-point calculations)
+# - du (for measuring directory sizes)
+#
+# Author: Junie (JetBrains AI)
+# Date: 2025-08-31
+
+# Exit on error
+set -e
+
+# Trap for cleanup in case of unexpected exit
+trap cleanup EXIT
+
+cleanup() {
+ # Make sure we return to the original branch
+ if [ -n "$CURRENT_BRANCH" ]; then
+ git checkout -q "$CURRENT_BRANCH" 2>/dev/null || true
+
+ # Restore stashed changes if needed
+ if [ "$STASH_NEEDED" = true ]; then
+ echo "Restoring stashed changes..."
+ git stash pop -q 2>/dev/null || true
+ fi
+ fi
+}
+
+# Default to checking the last 100 commits if not specified
+NUM_COMMITS=${1:-100}
+
+# Validate input
+if ! [[ "$NUM_COMMITS" =~ ^[0-9]+$ ]]; then
+ echo "Error: Number of commits must be a positive integer."
+ echo "Usage: $0 [number_of_commits_to_check]"
+ exit 1
+fi
+
+if [ "$NUM_COMMITS" -lt 1 ]; then
+ echo "Error: Number of commits must be at least 1."
+ echo "Usage: $0 [number_of_commits_to_check]"
+ exit 1
+fi
+
+echo "Analyzing the last $NUM_COMMITS commits to find the largest size change..."
+echo "This may take some time depending on repository size and history."
+echo
+
+# Get the list of commit hashes
+COMMITS=$(git log --pretty=format:"%H" -n "$NUM_COMMITS")
+
+# Initialize variables to track the largest change
+LARGEST_CHANGE=0
+LARGEST_COMMIT=""
+LARGEST_SIZE_BEFORE=0
+LARGEST_SIZE_AFTER=0
+
+# Function to get repository size at a specific commit
+get_repo_size() {
+ local commit=$1
+ # Checkout the commit
+ git checkout -q "$commit"
+ # Calculate size in bytes (excluding .git directory)
+ local size=$(du -sb --exclude=.git . | cut -f1)
+ echo "$size"
+}
+
+# Store current branch to return to it later
+CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
+
+# Check if there are uncommitted changes
+if [[ -n $(git status -s) ]]; then
+ echo "Stashing uncommitted changes before proceeding..."
+ STASH_NEEDED=true
+ git stash push -m "Temporary stash by find_largest_commit.sh script"
+else
+ STASH_NEEDED=false
+fi
+
+# Temporary file to store results
+TEMP_FILE=$(mktemp)
+
+echo "Commit Hash,Author,Date,Size Before (bytes),Size After (bytes),Change (bytes),Change (%),Message" > "$TEMP_FILE"
+
+# Counter for progress display
+COUNTER=0
+TOTAL_COMMITS=$(echo "$COMMITS" | wc -l)
+
+# Process each commit
+PREV_SIZE=""
+for COMMIT in $COMMITS; do
+ COUNTER=$((COUNTER + 1))
+ echo -ne "Processing commit $COUNTER/$TOTAL_COMMITS...\r"
+
+ # Get commit details
+ AUTHOR=$(git show -s --format="%an" "$COMMIT")
+ DATE=$(git show -s --format="%cd" --date=format:"%Y-%m-%d %H:%M:%S" "$COMMIT")
+ MESSAGE=$(git show -s --format="%s" "$COMMIT" | sed 's/,/;/g') # Replace commas with semicolons
+
+ # Get size after this commit
+ SIZE_AFTER=$(get_repo_size "$COMMIT")
+
+ # If this is the first commit we're checking, we don't have a previous size
+ if [ -z "$PREV_SIZE" ]; then
+ PREV_SIZE="$SIZE_AFTER"
+ continue
+ fi
+
+ # Calculate size before (which is the size after the previous commit)
+ SIZE_BEFORE="$PREV_SIZE"
+ PREV_SIZE="$SIZE_AFTER"
+
+ # Calculate change
+ CHANGE=$((SIZE_AFTER - SIZE_BEFORE))
+ ABS_CHANGE=${CHANGE#-} # Absolute value
+
+ # Calculate percentage change
+ if [ "$SIZE_BEFORE" -ne 0 ]; then
+ PERCENT_CHANGE=$(echo "scale=2; 100 * $CHANGE / $SIZE_BEFORE" | bc)
+ else
+ PERCENT_CHANGE="N/A"
+ fi
+
+ # Record the data
+ echo "$COMMIT,$AUTHOR,$DATE,$SIZE_BEFORE,$SIZE_AFTER,$CHANGE,$PERCENT_CHANGE%,$MESSAGE" >> "$TEMP_FILE"
+
+ # Check if this is the largest change so far
+ if [ "$ABS_CHANGE" -gt "$LARGEST_CHANGE" ]; then
+ LARGEST_CHANGE="$ABS_CHANGE"
+ LARGEST_COMMIT="$COMMIT"
+ LARGEST_SIZE_BEFORE="$SIZE_BEFORE"
+ LARGEST_SIZE_AFTER="$SIZE_AFTER"
+ fi
+done
+
+# Return to the original branch
+# (Cleanup function will handle restoring stashed changes)
+git checkout -q "$CURRENT_BRANCH"
+
+echo -e "\nAnalysis complete!"
+
+# Function to format size in human-readable format
+format_size() {
+ local size=$1
+ if [ "$size" -ge 1073741824 ]; then
+ echo "$(echo "scale=2; $size / 1073741824" | bc) GB"
+ elif [ "$size" -ge 1048576 ]; then
+ echo "$(echo "scale=2; $size / 1048576" | bc) MB"
+ elif [ "$size" -ge 1024 ]; then
+ echo "$(echo "scale=2; $size / 1024" | bc) KB"
+ else
+ echo "$size bytes"
+ fi
+}
+
+# Display the result
+if [ -n "$LARGEST_COMMIT" ]; then
+ echo
+ echo "Commit with the largest size change:"
+ echo "-----------------------------------"
+ echo "Commit: $LARGEST_COMMIT"
+ echo "Author: $(git show -s --format="%an" "$LARGEST_COMMIT")"
+ echo "Date: $(git show -s --format="%cd" --date=format:"%Y-%m-%d %H:%M:%S" "$LARGEST_COMMIT")"
+ echo "Message: $(git show -s --format="%s" "$LARGEST_COMMIT")"
+ echo
+ echo "Size before: $(format_size "$LARGEST_SIZE_BEFORE")"
+ echo "Size after: $(format_size "$LARGEST_SIZE_AFTER")"
+
+ CHANGE=$((LARGEST_SIZE_AFTER - LARGEST_SIZE_BEFORE))
+ if [ "$CHANGE" -ge 0 ]; then
+ echo "Change: +$(format_size "${CHANGE#-}") (increased)"
+ else
+ echo "Change: -$(format_size "${CHANGE#-}") (decreased)"
+ fi
+
+ if [ "$LARGEST_SIZE_BEFORE" -ne 0 ]; then
+ PERCENT_CHANGE=$(echo "scale=2; 100 * $CHANGE / $LARGEST_SIZE_BEFORE" | bc)
+ echo "Percentage change: $PERCENT_CHANGE%"
+ fi
+
+ echo
+ echo "Files changed in this commit:"
+
+ # Get the list of changed files
+ CHANGED_FILES=$(git show --stat "$LARGEST_COMMIT" | grep '|' | sort -rn -k3)
+ TOTAL_FILES=$(echo "$CHANGED_FILES" | wc -l)
+
+ # If there are too many files, show only the top 10 with the most changes
+ if [ "$TOTAL_FILES" -gt 10 ]; then
+ echo "$CHANGED_FILES" | head -n 10
+ echo "... and $(($TOTAL_FILES - 10)) more files (total: $TOTAL_FILES files changed)"
+ else
+ echo "$CHANGED_FILES"
+ fi
+else
+ echo "No commits analyzed."
+fi
+
+echo
+echo "Full results saved to: $TEMP_FILE"
+echo "You can import this CSV file into a spreadsheet for further analysis."
+
+# Make the script executable
+chmod +x "$0"
\ No newline at end of file
diff --git a/src/Controller/AdminController.php b/src/Controller/AdminController.php
index 79164936..90c4736f 100644
--- a/src/Controller/AdminController.php
+++ b/src/Controller/AdminController.php
@@ -2334,8 +2334,74 @@ final class AdminController extends AbstractController
$city = $statsRepo->findOneBy(['zone' => $inseeCode]);
if (!$city) {
- $this->addFlash('error', 'Ville non trouvée pour le code INSEE ' . $inseeCode);
- return $this->redirectToRoute('app_admin');
+ // Si aucune stats n'existe, rechercher dans l'API geo.api.gouv.fr
+ $apiUrl = "https://geo.api.gouv.fr/communes/{$inseeCode}";
+ $response = @file_get_contents($apiUrl);
+
+ if ($response === false) {
+ $this->addFlash('error', 'Ville non trouvée pour le code INSEE ' . $inseeCode . ' et impossible de récupérer les informations depuis l\'API geo.api.gouv.fr.');
+ return $this->redirectToRoute('app_admin');
+ }
+
+ $communeData = json_decode($response, true);
+ if (!$communeData || !isset($communeData['nom'])) {
+ $this->addFlash('error', 'Aucune commune trouvée avec ce code INSEE dans l\'API geo.api.gouv.fr.');
+ return $this->redirectToRoute('app_admin');
+ }
+
+ // Créer un nouvel objet Stats avec les données de l'API
+ $city = new Stats();
+ $city->setZone($inseeCode)
+ ->setName($communeData['nom'])
+ ->setDateCreated(new \DateTime())
+ ->setDateModified(new \DateTime())
+ ->setKind('osmose_request');
+
+ // Ajouter la population si disponible
+ if (isset($communeData['population'])) {
+ $city->setPopulation($communeData['population']);
+ }
+
+ // Ajouter les coordonnées si disponibles
+ if (isset($communeData['centre']) && isset($communeData['centre']['coordinates'])) {
+ $city->setLon((string)$communeData['centre']['coordinates'][0]);
+ $city->setLat((string)$communeData['centre']['coordinates'][1]);
+ } else {
+ // Si les coordonnées ne sont pas dans la réponse initiale, faire une requête spécifique
+ try {
+ $apiUrl = 'https://geo.api.gouv.fr/communes/' . $inseeCode . '?fields=centre';
+ $response = @file_get_contents($apiUrl);
+ if ($response !== false) {
+ $data = json_decode($response, true);
+ if (isset($data['centre']['coordinates']) && count($data['centre']['coordinates']) === 2) {
+ $city->setLon((string)$data['centre']['coordinates'][0]);
+ $city->setLat((string)$data['centre']['coordinates'][1]);
+ }
+ }
+ } catch (\Exception $e) {
+ // Ignorer les erreurs lors de la récupération des coordonnées
+ }
+ }
+
+ // Ajouter les codes postaux si disponibles
+ if (isset($communeData['codesPostaux']) && !empty($communeData['codesPostaux'])) {
+ $city->setCodesPostaux(implode(',', $communeData['codesPostaux']));
+ }
+
+ // Ajouter le code EPCI si disponible
+ if (isset($communeData['codeEpci'])) {
+ $city->setCodeEpci((int)$communeData['codeEpci']);
+ }
+
+ // Ajouter le SIREN si disponible
+ if (isset($communeData['siren'])) {
+ $city->setSiren((int)$communeData['siren']);
+ }
+
+ // Ne pas faire de labourage des Places pour cette ville
+ // Persister l'objet Stats
+ $this->entityManager->persist($city);
+ $this->entityManager->flush();
}
// Récupérer le thème sélectionné (par défaut: tous)
@@ -2347,11 +2413,86 @@ final class AdminController extends AbstractController
// Récupérer les problèmes Osmose pour cette ville
$osmoseIssues = $this->getOsmoseIssuesForCity($city, $theme);
+ // Créer un mapping inverse des items Osmose vers les thèmes
+ $itemToThemeMapping = [];
+ $themeToItemsMapping = [
+ 'charging_station' => [8410, 8411],
+ 'school' => [8031],
+ 'healthcare' => [8211, 7220, 8331],
+ 'laboratory' => [7240, 8351],
+ 'police' => [8190, 8191],
+ 'defibrillator' => [8370],
+ 'places' => [7240, 8351, 8211, 7220, 8331, 8031],
+ 'restaurants' => [8030, 8031, 8032],
+ 'hotels' => [8040, 8041, 8042],
+ 'tourism' => [8010, 8011, 8012, 8013],
+ 'leisure' => [8050, 8051, 8052],
+ 'transportation' => [4010, 4020, 4030, 4040],
+ 'amenities' => [8080, 8081, 8082],
+ ];
+
+ foreach ($themeToItemsMapping as $themeName => $itemIds) {
+ foreach ($itemIds as $itemId) {
+ if (!isset($itemToThemeMapping[$itemId])) {
+ $itemToThemeMapping[$itemId] = [];
+ }
+ $itemToThemeMapping[$itemId][] = $themeName;
+ }
+ }
+
+ // Compter les problèmes par thème
+ $issuesByTheme = [];
+ foreach ($themes as $themeKey => $themeLabel) {
+ $issuesByTheme[$themeKey] = 0;
+ }
+
+ // Ajouter un compteur pour "Autres" (problèmes qui ne correspondent à aucun thème)
+ $issuesByTheme['other'] = 0;
+
+ // Compter les problèmes par niveau de sévérité
+ $issuesByLevel = [
+ 1 => 0, // Critique
+ 2 => 0, // Important
+ 3 => 0, // Avertissement
+ ];
+
+ foreach ($osmoseIssues as $issue) {
+ // Compter par niveau de sévérité
+ $level = (int)$issue['level'];
+ if (isset($issuesByLevel[$level])) {
+ $issuesByLevel[$level]++;
+ }
+
+ // Compter par thème
+ $itemId = (int)$issue['item'];
+ $counted = false;
+
+ if (isset($itemToThemeMapping[$itemId])) {
+ foreach ($itemToThemeMapping[$itemId] as $themeName) {
+ if (isset($issuesByTheme[$themeName])) {
+ $issuesByTheme[$themeName]++;
+ $counted = true;
+ }
+ }
+ }
+
+ // Si le problème n'a été compté dans aucun thème, l'ajouter à "Autres"
+ if (!$counted) {
+ $issuesByTheme['other']++;
+ }
+ }
+
+ // Ajouter le libellé pour "Autres"
+ $themes['other'] = 'Autres problèmes';
+
return $this->render('admin/osmose_issues_map.html.twig', [
'city' => $city,
'theme' => $theme,
'themes' => $themes,
- 'osmoseIssues' => $osmoseIssues
+ 'osmoseIssues' => $osmoseIssues,
+ 'issuesByTheme' => $issuesByTheme,
+ 'issuesByLevel' => $issuesByLevel,
+ 'osmoseApiUrl' => 'https://osmose.openstreetmap.fr/fr/map/#zoom=14&lat=' . $city->getLat() . '&lon=' . $city->getLon()
]);
}
@@ -2478,20 +2619,33 @@ final class AdminController extends AbstractController
{
// Mapping des thèmes vers les items Osmose
$themeToItemsMapping = [
- 'places' => [8230, 8240, 8250, 8260], // Commerces et services
+ 'charging_station' => [8410, 8411],
+ 'school' => [8031],
+ 'healthcare' => [8211, 7220, 8331],
+ 'laboratory' => [7240, 8351],
+ 'police' => [8190, 8191],
+ 'defibrillator' => [8370],
+ 'places' => [7240, 8351, 8211, 7220, 8331, 8031],
'restaurants' => [8030, 8031, 8032], // Restaurants et cafés
'hotels' => [8040, 8041, 8042], // Hébergements
'tourism' => [8010, 8011, 8012, 8013], // Tourisme
'leisure' => [8050, 8051, 8052], // Loisirs
- 'healthcare' => [8060, 8061, 8062], // Santé
- 'education' => [8070, 8071, 8072], // Éducation
'transportation' => [4010, 4020, 4030, 4040], // Transport
'amenities' => [8080, 8081, 8082], // Équipements
// Si d'autres thèmes sont nécessaires, ajoutez-les ici
];
- // Si le thème est 'all' ou n'existe pas dans le mapping, retourner un tableau vide
- if ($theme === 'all' || !isset($themeToItemsMapping[$theme])) {
+ // Si le thème est 'all', retourner tous les items uniques de tous les thèmes
+ if ($theme === 'all') {
+ $allItems = [];
+ foreach ($themeToItemsMapping as $items) {
+ $allItems = array_merge($allItems, $items);
+ }
+ return array_unique($allItems);
+ }
+
+ // Si le thème n'existe pas dans le mapping, retourner un tableau vide
+ if (!isset($themeToItemsMapping[$theme])) {
return [];
}
diff --git a/templates/admin/followup_theme_graph.html.twig b/templates/admin/followup_theme_graph.html.twig
index eb92abc1..4d004d36 100644
--- a/templates/admin/followup_theme_graph.html.twig
+++ b/templates/admin/followup_theme_graph.html.twig
@@ -282,7 +282,35 @@
-
+
+
+
Alertes Osmose
+
+
+
Chargement des alertes...
+
+
Liste complète des alertes
+
+
+
+
+
ID
+
Élément
+
Position
+
Actions
+
+
+
+
+
+
+
+
+
Répartition des alertes par thème
+
+
+
+
@@ -885,38 +913,70 @@
.then(data => {
if (!data.issues || data.issues.length === 0) {
console.log('Aucune analyse Osmose trouvée pour ce thème dans cette zone.');
+ document.querySelector('#alertes_osmose').innerHTML = '
Aucune alerte Osmose trouvée pour ce thème dans cette zone.
';
return;
}
- const divOsmose = document.querySelector(('#alertes_osmose'))
+ // Stocker les données Osmose globalement pour pouvoir les utiliser ailleurs
+ window.osmoseData = data.issues;
+
+ // Mettre à jour le résumé des alertes
+ const divOsmose = document.querySelector('#alertes_osmose');
if(divOsmose){
if (data.issues.length === 1) {
// Si un seul objet, rendre tout le texte cliquable
const issueId = data.issues[0].id;
- divOsmose.innerHTML = `
- ${data.issues.length} objet à ajouter selon Osmose
- `;
+ divOsmose.innerHTML = `