diff --git a/src/Controller/AdminController.php b/src/Controller/AdminController.php index ce4152df..e4b16d6d 100644 --- a/src/Controller/AdminController.php +++ b/src/Controller/AdminController.php @@ -18,6 +18,7 @@ use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\HttpFoundation\JsonResponse; use Twig\Environment; use App\Service\ActionLogger; +use DateTime; final class AdminController extends AbstractController { @@ -36,6 +37,9 @@ final class AdminController extends AbstractController public function labourer_tout(): Response { + + + $this->actionLogger->log('labourer_toutes_les_zones', []); $updateExisting =true; $stats_all = $this->entityManager->getRepository(Stats::class)->findAll(); @@ -245,9 +249,7 @@ final class AdminController extends AbstractController #[Route('/admin/stats/{insee_code}', name: 'app_admin_stats')] public function calculer_stats(string $insee_code): Response { - // Récupérer tous les commerces de la zone - // $commerces = $this->entityManager->getRepository(Place::class)->findBy(['zip_code' => $insee_code, 'dead' => false]); - + // Récupérer les stats existantes pour la zone $stats = $this->entityManager->getRepository(Stats::class)->findOneBy(['zone' => $insee_code]); if (!$stats) { @@ -255,7 +257,10 @@ final class AdminController extends AbstractController return $this->redirectToRoute('app_admin_labourer', ['insee_code' => $insee_code]); } $commerces = $stats->getPlaces(); - + + $this->actionLogger->log('stats_de_ville', ['insee_code' => $insee_code, 'nom' => $stats->getZone()]); + // Récupérer tous les commerces de la zone + // $commerces = $this->entityManager->getRepository(Place::class)->findBy(['zip_code' => $insee_code, 'dead' => false]); if(!$stats) { // Si aucune stat n'existe, on en crée une vide pour éviter les erreurs, mais sans la sauvegarder $stats = new Stats(); @@ -269,7 +274,7 @@ final class AdminController extends AbstractController ->where('sh.stats = :stats') ->setParameter('stats', $stats) ->orderBy('sh.id', 'DESC') - ->setMaxResults(365) + ->setMaxResults(100) ->getQuery() ->getResult(); @@ -330,6 +335,7 @@ final class AdminController extends AbstractController #[Route('/admin/placeType/{osm_kind}/{osm_id}', name: 'app_admin_by_osm_id')] public function placeType(string $osm_kind, string $osm_id): Response { + $this->actionLogger->log('admin/placeType', ['osm_kind' => $osm_kind, 'osm_id' => $osm_id]); $place = $this->entityManager->getRepository(Place::class)->findOneBy(['osm_kind' => $osm_kind, 'osmId' => $osm_id]); if($place) { return $this->redirectToRoute('app_admin_commerce', ['id' => $place->getId()]); @@ -376,9 +382,12 @@ final class AdminController extends AbstractController { $deleteMissing = $request->query->getBoolean('deleteMissing', true); + $this->actionLogger->log('labourer', ['insee_code' => $insee_code]); + // Vérifier si le code INSEE est valide (composé uniquement de chiffres) if (!ctype_digit($insee_code) || $insee_code == 'undefined' || $insee_code == '') { $this->addFlash('error', 'Code INSEE invalide : il doit être composé uniquement de chiffres.'); + $this->actionLogger->log('ERROR_labourer_bad_insee', ['insee_code' => $insee_code]); return $this->redirectToRoute('app_public_index'); } try { @@ -427,6 +436,9 @@ final class AdminController extends AbstractController } catch (\Exception $e) { $this->addFlash('error', 'Erreur lors de la récupération des données de l\'API : ' . $e->getMessage()); + $this->actionLogger->log('ERROR_labourer_geoapi', ['insee_code' => $insee_code, 'message' => $e->getMessage()]); + + } // Récupérer le budget annuel via l'API des finances publiques @@ -695,6 +707,8 @@ final class AdminController extends AbstractController // Compter les Places avec email et SIRET $placesWithEmail = 0; $placesWithSiret = 0; + $placesWithName = 0; + foreach ($stats->getPlaces() as $place) { if ($place->getEmail() && $place->getEmail() !== '') { $placesWithEmail++; @@ -702,16 +716,19 @@ final class AdminController extends AbstractController if ($place->getSiret() && $place->getSiret() !== '') { $placesWithSiret++; } + if ($place->getName() && $place->getName() !== '') { + $placesWithName++; + } + } $statsHistory->setPlacesCount($stats->getPlaces()->count()) ->setOpeningHoursCount($stats->getAvecHoraires()) ->setAddressCount($stats->getAvecAdresse()) ->setWebsiteCount($stats->getAvecSite()) + ->setNamesCount($placesWithName) ->setSiretCount($placesWithSiret) ->setEmailsCount($placesWithEmail) - // ->setAccessibiliteCount($stats->getAvecAccessibilite()) - // ->setNoteCount($stats->getAvecNote()) ->setCompletionPercent($stats->getCompletionPercent()) ->setStats($stats); @@ -802,6 +819,7 @@ final class AdminController extends AbstractController #[Route('/admin/export', name: 'app_admin_export')] public function export(): Response { + $this->actionLogger->log('export_all_places', []); $places = $this->entityManager->getRepository(Place::class)->findAll(); $csvData = []; @@ -857,17 +875,22 @@ final class AdminController extends AbstractController $response->setContent(stream_get_contents($handle)); fclose($handle); + + return $response; } #[Route('/admin/export_csv/{insee_code}', name: 'app_admin_export_csv')] public function export_csv(string $insee_code): Response { + $stats = $this->entityManager->getRepository(Stats::class)->findOneBy(['zone' => $insee_code]); $response = new Response($this->motocultrice->export($insee_code)); $response->headers->set('Content-Type', 'text/csv'); - + $slug_name = str_replace(' ', '-', $stats->getName()); + $this->actionLogger->log('export_csv', ['insee_code'=> $insee_code, 'slug_name' => $slug_name]); + $response->headers->set('Content-Disposition', 'attachment; filename="osm-commerces-export_' . $insee_code . '_' . $slug_name . '_' . date('Y-m-d_H-i-s') . '.csv"'); return $response; @@ -883,6 +906,8 @@ final class AdminController extends AbstractController #[Route('/admin/no_more_sollicitation_for_place/{id}', name: 'app_admin_no_more_sollicitation_for_place')] public function no_more_sollicitation_for_place(Place $place): Response { + $this->actionLogger->log('no_more_sollicitation_for_place', ['place_id'=> $place->getId()]); + $place->setOptedOut(true); $this->entityManager->persist($place); $this->entityManager->flush(); @@ -895,10 +920,14 @@ final class AdminController extends AbstractController #[Route('/admin/send_email_to_place/{id}', name: 'app_admin_send_email_to_place')] public function send_email_to_place(Place $place, \Symfony\Component\Mailer\MailerInterface $mailer): Response { + $this->actionLogger->log('send_email_to_place', ['place_id'=> $place->getId()]); + // Vérifier si le lieu est opted out if ($place->isOptedOut()) { $this->addFlash('error', 'Ce lieu a demandé à ne plus être sollicité pour mettre à jour ses informations.'); + $this->actionLogger->log('could_not_send_email_to_opted_out_place', ['place_id'=> $place->getId()]); + return $this->redirectToRoute('app_public_index'); } // Vérifier si le lieu a déjà été contacté @@ -919,14 +948,24 @@ final class AdminController extends AbstractController ->subject('Mise à jour des informations de votre établissement dans OpenStreetMap') ->html($emailContent); - $mailer->send($email); - + try { + $mailer->send($email); + } catch (\Throwable $e) { + $this->actionLogger->log('ERROR_envoi_email', [ + 'place_id' => $place->getId(), + 'message' => $e->getMessage(), + ]); + $this->addFlash('error', 'Erreur lors de l\'envoi de l\'email : ' . $e->getMessage()); + return $this->redirectToRoute('app_public_index'); + } // Mettre à jour la date de dernier contact $place->setLastContactAttemptDate(new \DateTime()); $this->entityManager->persist($place); $this->entityManager->flush(); + $place->setLastContactAttemptDate(new \DateTime()); + $this->addFlash('success', 'Email envoyé avec succès à ' . $place->getName() . ' le ' . $place->getLastContactAttemptDate()->format('d/m/Y H:i:s')); return $this->redirectToRoute('app_public_index'); } @@ -945,6 +984,8 @@ final class AdminController extends AbstractController #[Route('/admin/fraicheur/calculate', name: 'admin_fraicheur_calculate')] public function calculateFraicheur(): Response { + // Ajout d'un log d'action avec le service ActionLogger + $this->actionLogger->log('fraicheur/calculate' , []); $filesystem = new Filesystem(); $jsonPath = $this->getParameter('kernel.project_dir') . '/var/fraicheur_osm.json'; $now = new \DateTime(); @@ -1113,6 +1154,8 @@ final class AdminController extends AbstractController #[Route('/admin/podium-contributeurs-osm', name: 'app_admin_podium_contributeurs_osm')] public function podiumContributeursOsm(): Response { + // Ajout d'un log d'action avec le service ActionLogger + $this->actionLogger->log('podium_contributeurs_osm', []); // On suppose que le champ "osmUser" existe sur l'entité Place $placeRepo = $this->entityManager->getRepository(\App\Entity\Place::class); diff --git a/src/Controller/FraicheurController.php b/src/Controller/FraicheurController.php index 367d77ea..74171b77 100644 --- a/src/Controller/FraicheurController.php +++ b/src/Controller/FraicheurController.php @@ -200,8 +200,8 @@ class FraicheurController extends AbstractController $villesByBinEcart = []; foreach ($budgetParHabitant as $ville) { - // Histogramme budget par habitant (pas de 100€) - $binBudget = (string)(ceil($ville['budget_par_habitant'] / 100) * 100); + // Histogramme budget par habitant (pas de 50€) + $binBudget = (string)(ceil($ville['budget_par_habitant'] / 50) * 50); if (!isset($histogramBudgetParHabitant[$binBudget])) { $histogramBudgetParHabitant[$binBudget] = 0; } diff --git a/src/Controller/PublicController.php b/src/Controller/PublicController.php index 5c887ea0..2edddd8b 100644 --- a/src/Controller/PublicController.php +++ b/src/Controller/PublicController.php @@ -130,8 +130,7 @@ class PublicController extends AbstractController public function edit_with_uuid($zipcode, $name, $uuid): Response { $this->actionLogger->log('dashboard', [ - 'zipcode' => $zipcode, - + 'zipcode' => $zipcode, ]); @@ -400,14 +399,14 @@ class PublicController extends AbstractController } #[Route('/request_email_to_modify/{osm_object_id}', name: 'app_public_request_email')] - public function request_email($osm_object_id): Response + public function request_email($osm_object_id, Request $request): Response { $this->actionLogger->log('request_email_to_modify', [ 'osm_id' => $osm_object_id, ]); - if ($this->getRequest()->isMethod('POST')) { - $email = $this->getRequest()->request->get('email'); + if ($request->isMethod('POST')) { + $email = $request->request->get('email'); try { // TODO: Implémenter l'envoi réel du mail @@ -450,6 +449,7 @@ class PublicController extends AbstractController } $place->setClosed(true); + $place->setDead(true); $this->entityManager->flush(); return $this->render('public/closed_commerce.html.twig', [ @@ -519,6 +519,9 @@ class PublicController extends AbstractController $this->addFlash('warning', 'Ce commerce n\'existe pas.'); return $this->redirectToRoute('app_public_index'); } + + $place->setOptedOut(true); + } #[Route('/ask-for-help', name: 'app_public_ask_for_help')] diff --git a/templates/admin/fraicheur_histogramme.html.twig b/templates/admin/fraicheur_histogramme.html.twig index 924de5b8..7cafb748 100644 --- a/templates/admin/fraicheur_histogramme.html.twig +++ b/templates/admin/fraicheur_histogramme.html.twig @@ -20,7 +20,7 @@ Une ville avec un petit nombre d'habitants par lieu sera très fournie en services divers et variés, sur la gauche de ce graphique de répartition. Survolez pour voir les noms des villes les plus civilisées. À droite du graphique, vous êtes plus proche d'habiter dans un désert.
-Ce graphique montre la répartition des villes selon leur budget annuel par habitant. Les villes avec un budget élevé par habitant sont sur la droite du graphique. @@ -322,7 +322,7 @@ document.addEventListener('DOMContentLoaded', function() { plugins: { legend: { display: false }, - title: { display: true, text: "Distribution des villes par budget par habitant (par pas de 100€)" }, + title: { display: true, text: "Distribution des villes par budget par habitant (par pas de 50€)" }, tooltip: { callbacks: { afterBody: function(context) { @@ -338,7 +338,7 @@ document.addEventListener('DOMContentLoaded', function() { }, scales: { y: { beginAtZero: true, title: { display: true, text: 'Nombre de villes' } }, - x: { title: { display: true, text: 'Budget par habitant (€, arrondi à 100)' } } + x: { title: { display: true, text: 'Budget par habitant (€, arrondi à 50)' } } } } });