feat: Gestion des secteurs et migration v3.0.4+304
- Ajout système complet de gestion des secteurs avec contours géographiques - Import des contours départementaux depuis GeoJSON - API REST pour la gestion des secteurs (/api/sectors) - Service de géolocalisation pour déterminer les secteurs - Migration base de données avec tables x_departements_contours et sectors_adresses - Interface Flutter pour visualisation et gestion des secteurs - Ajout thème sombre dans l'application - Corrections diverses et optimisations 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
0
api/scripts/README.md
Normal file → Executable file
0
api/scripts/README.md
Normal file → Executable file
33
api/scripts/check_geometry_validity.sql
Normal file
33
api/scripts/check_geometry_validity.sql
Normal file
@@ -0,0 +1,33 @@
|
||||
-- Script de diagnostic pour vérifier les problèmes de géométrie dans x_departements_contours
|
||||
|
||||
-- 1. Vérifier les contours NULL
|
||||
SELECT 'Contours NULL:' as diagnostic;
|
||||
SELECT code_dept, nom_dept
|
||||
FROM x_departements_contours
|
||||
WHERE contour IS NULL;
|
||||
|
||||
-- 2. Vérifier les types de géométrie et si elles sont vides
|
||||
SELECT 'Types de géométrie:' as diagnostic;
|
||||
SELECT
|
||||
code_dept,
|
||||
nom_dept,
|
||||
ST_GeometryType(contour) as geometry_type,
|
||||
ST_IsEmpty(contour) as is_empty
|
||||
FROM x_departements_contours
|
||||
WHERE contour IS NOT NULL;
|
||||
|
||||
-- 3. Statistiques générales
|
||||
SELECT 'Statistiques:' as diagnostic;
|
||||
SELECT
|
||||
COUNT(*) as total,
|
||||
SUM(CASE WHEN contour IS NULL THEN 1 ELSE 0 END) as contours_null,
|
||||
SUM(CASE WHEN contour IS NOT NULL THEN 1 ELSE 0 END) as contours_non_null
|
||||
FROM x_departements_contours;
|
||||
|
||||
-- 4. Lister spécifiquement les DOM-TOM et Corse
|
||||
SELECT 'DOM-TOM et Corse:' as diagnostic;
|
||||
SELECT code_dept, nom_dept,
|
||||
CASE WHEN contour IS NULL THEN 'NULL' ELSE 'OK' END as contour_status
|
||||
FROM x_departements_contours
|
||||
WHERE code_dept IN ('20', '2A', '2B', '971', '972', '973', '974', '975', '976')
|
||||
ORDER BY code_dept;
|
||||
0
api/scripts/config.php
Normal file → Executable file
0
api/scripts/config.php
Normal file → Executable file
32
api/scripts/create_addresses_users.sql
Normal file
32
api/scripts/create_addresses_users.sql
Normal file
@@ -0,0 +1,32 @@
|
||||
-- Script de création des utilisateurs pour la base de données des adresses
|
||||
-- À exécuter sur chaque serveur MariaDB (dva-maria, rca-maria, pra-maria)
|
||||
|
||||
-- Créer l'utilisateur avec accès depuis l'IP du container API correspondant
|
||||
-- IMPORTANT: Remplacer 'API_CONTAINER_IP' par l'IP réelle du container API
|
||||
|
||||
-- Pour l'environnement DEV (dva-maria)
|
||||
-- Si l'API est dans le container dva-api avec l'IP 13.23.33.45 par exemple :
|
||||
CREATE USER IF NOT EXISTS 'adresses_user'@'13.23.33.45' IDENTIFIED BY 'd66,AdrGeo.User';
|
||||
GRANT SELECT ON adresses.* TO 'adresses_user'@'13.23.33.45';
|
||||
|
||||
-- Pour l'environnement RECETTE (rca-maria)
|
||||
-- Si l'API est dans le container rca-api avec l'IP 13.23.33.35 par exemple :
|
||||
CREATE USER IF NOT EXISTS 'adresses_user'@'13.23.33.35' IDENTIFIED BY 'd66,AdrGeo.User';
|
||||
GRANT SELECT ON adresses.* TO 'adresses_user'@'13.23.33.35';
|
||||
|
||||
-- Pour l'environnement PROD (pra-maria)
|
||||
-- Si l'API est dans le container pra-api avec l'IP 13.23.33.25 par exemple :
|
||||
CREATE USER IF NOT EXISTS 'adresses_user'@'13.23.33.25' IDENTIFIED BY 'd66,AdrGeo.User';
|
||||
GRANT SELECT ON adresses.* TO 'adresses_user'@'13.23.33.25';
|
||||
|
||||
-- Alternative : Créer un utilisateur accessible depuis tout le sous-réseau
|
||||
-- ATTENTION : Moins sécurisé, à utiliser uniquement si les containers sont dans un réseau privé isolé
|
||||
CREATE USER IF NOT EXISTS 'adresses_user'@'13.23.33.%' IDENTIFIED BY 'd66,AdrGeo.User';
|
||||
GRANT SELECT ON adresses.* TO 'adresses_user'@'13.23.33.%';
|
||||
|
||||
-- Appliquer les privilèges
|
||||
FLUSH PRIVILEGES;
|
||||
|
||||
-- Vérifier la création
|
||||
SELECT user, host FROM mysql.user WHERE user = 'adresses_user';
|
||||
SHOW GRANTS FOR 'adresses_user'@'13.23.33.%';
|
||||
41
api/scripts/create_addresses_users_by_env.sql
Normal file
41
api/scripts/create_addresses_users_by_env.sql
Normal file
@@ -0,0 +1,41 @@
|
||||
-- Script de création des utilisateurs pour la base de données des adresses
|
||||
-- Avec segmentation par environnement basée sur les plages d'IPs
|
||||
|
||||
-- ===================================
|
||||
-- DÉVELOPPEMENT (dva-maria)
|
||||
-- IPs autorisées : 13.23.33.40-49
|
||||
-- ===================================
|
||||
CREATE USER IF NOT EXISTS 'adresses_user'@'13.23.33.4%' IDENTIFIED BY 'd66,AdrGeo.User';
|
||||
GRANT SELECT ON adresses.* TO 'adresses_user'@'13.23.33.4%';
|
||||
|
||||
-- Aussi créer un accès localhost pour les tests directs
|
||||
CREATE USER IF NOT EXISTS 'adresses_user'@'localhost' IDENTIFIED BY 'd66,AdrGeo.User';
|
||||
GRANT SELECT ON adresses.* TO 'adresses_user'@'localhost';
|
||||
|
||||
-- ===================================
|
||||
-- RECETTE (rca-maria)
|
||||
-- IPs autorisées : 13.23.33.30-39
|
||||
-- ===================================
|
||||
CREATE USER IF NOT EXISTS 'adresses_user'@'13.23.33.3%' IDENTIFIED BY 'd66,AdrGeo.User';
|
||||
GRANT SELECT ON adresses.* TO 'adresses_user'@'13.23.33.3%';
|
||||
|
||||
-- Aussi créer un accès localhost pour les tests directs
|
||||
CREATE USER IF NOT EXISTS 'adresses_user'@'localhost' IDENTIFIED BY 'd66,AdrGeo.User';
|
||||
GRANT SELECT ON adresses.* TO 'adresses_user'@'localhost';
|
||||
|
||||
-- ===================================
|
||||
-- PRODUCTION (pra-maria)
|
||||
-- IPs autorisées : 13.23.33.20-29
|
||||
-- ===================================
|
||||
CREATE USER IF NOT EXISTS 'adresses_user'@'13.23.33.2%' IDENTIFIED BY 'd66,AdrGeo.User';
|
||||
GRANT SELECT ON adresses.* TO 'adresses_user'@'13.23.33.2%';
|
||||
|
||||
-- Aussi créer un accès localhost pour les tests directs
|
||||
CREATE USER IF NOT EXISTS 'adresses_user'@'localhost' IDENTIFIED BY 'd66,AdrGeo.User';
|
||||
GRANT SELECT ON adresses.* TO 'adresses_user'@'localhost';
|
||||
|
||||
-- Appliquer les privilèges
|
||||
FLUSH PRIVILEGES;
|
||||
|
||||
-- Vérifier la création
|
||||
SELECT user, host FROM mysql.user WHERE user = 'adresses_user' ORDER BY host;
|
||||
0
api/scripts/cron/sync_databases.php
Normal file → Executable file
0
api/scripts/cron/sync_databases.php
Normal file → Executable file
37
api/scripts/fix_geometry_for_spatial_index.sql
Normal file
37
api/scripts/fix_geometry_for_spatial_index.sql
Normal file
@@ -0,0 +1,37 @@
|
||||
-- Script pour diagnostiquer et corriger les problèmes d'index spatial
|
||||
|
||||
-- 1. Vérifier s'il y a des géométries vides
|
||||
SELECT 'Géométries vides:' as diagnostic;
|
||||
SELECT code, libelle
|
||||
FROM x_departements
|
||||
WHERE contour IS NOT NULL AND ST_IsEmpty(contour) = 1;
|
||||
|
||||
-- 2. Essayer de créer un index spatial sur une copie de la table pour tester
|
||||
CREATE TABLE x_departements_test LIKE x_departements;
|
||||
|
||||
-- 3. Copier uniquement les départements métropolitains avec contours
|
||||
INSERT INTO x_departements_test
|
||||
SELECT * FROM x_departements
|
||||
WHERE contour IS NOT NULL
|
||||
AND code NOT IN ('20', '971', '972', '973', '974', '975', '976');
|
||||
|
||||
-- 4. Tenter de créer l'index spatial sur la table de test
|
||||
ALTER TABLE x_departements_test ADD SPATIAL INDEX idx_contour_test (contour);
|
||||
|
||||
-- Si ça fonctionne, le problème vient des départements spécifiques
|
||||
-- Si ça ne fonctionne pas, il y a un problème avec les données géométriques
|
||||
|
||||
-- 5. Alternative : recréer les géométries à partir du texte WKT
|
||||
-- Cela peut corriger certains problèmes de format
|
||||
UPDATE x_departements d
|
||||
INNER JOIN x_departements_contours dc ON d.code = dc.code_dept
|
||||
SET d.contour = ST_GeomFromText(ST_AsText(dc.contour))
|
||||
WHERE dc.contour IS NOT NULL
|
||||
AND d.code IN (SELECT code FROM x_departements WHERE contour IS NOT NULL LIMIT 1);
|
||||
|
||||
-- 6. Nettoyer
|
||||
DROP TABLE IF EXISTS x_departements_test;
|
||||
|
||||
-- Note : Pour l'instant, l'index normal créé avec contour(32) permettra
|
||||
-- le fonctionnement de l'API, même si les performances seront moindres
|
||||
-- qu'avec un vrai index spatial.
|
||||
0
api/scripts/geosector.sql
Normal file → Executable file
0
api/scripts/geosector.sql
Normal file → Executable file
0
api/scripts/geosector_app.sql
Normal file → Executable file
0
api/scripts/geosector_app.sql
Normal file → Executable file
263
api/scripts/import_departements_from_file.php
Normal file
263
api/scripts/import_departements_from_file.php
Normal file
@@ -0,0 +1,263 @@
|
||||
<?php
|
||||
/**
|
||||
* Script d'import des contours départementaux depuis un fichier GeoJSON local
|
||||
*/
|
||||
|
||||
class DepartementContoursFileImporter {
|
||||
private PDO $db;
|
||||
private array $log = [];
|
||||
|
||||
public function __construct(PDO $db) {
|
||||
$this->db = $db;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si la table existe
|
||||
*/
|
||||
public function tableExists(): bool {
|
||||
try {
|
||||
$sql = "SHOW TABLES LIKE 'x_departements_contours'";
|
||||
$stmt = $this->db->query($sql);
|
||||
return $stmt->rowCount() > 0;
|
||||
} catch (Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si la table est vide
|
||||
*/
|
||||
private function isTableEmpty(): bool {
|
||||
try {
|
||||
$sql = "SELECT COUNT(*) as count FROM x_departements_contours";
|
||||
$stmt = $this->db->query($sql);
|
||||
$result = $stmt->fetch();
|
||||
return $result['count'] == 0;
|
||||
} catch (Exception $e) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Importe les départements depuis un fichier GeoJSON
|
||||
*/
|
||||
public function importFromFile(string $filePath): array {
|
||||
$this->log[] = "Début de l'import depuis le fichier : $filePath";
|
||||
$this->log[] = "";
|
||||
|
||||
// Vérifier que le fichier existe
|
||||
if (!file_exists($filePath)) {
|
||||
$this->log[] = "✗ Fichier non trouvé : $filePath";
|
||||
return $this->log;
|
||||
}
|
||||
|
||||
// Vérifier que la table existe
|
||||
if (!$this->tableExists()) {
|
||||
$this->log[] = "✗ La table x_departements_contours n'existe pas";
|
||||
return $this->log;
|
||||
}
|
||||
|
||||
// Vérifier que la table est vide
|
||||
if (!$this->isTableEmpty()) {
|
||||
$this->log[] = "✗ La table x_departements_contours contient déjà des données";
|
||||
return $this->log;
|
||||
}
|
||||
|
||||
// Lire le fichier GeoJSON
|
||||
$this->log[] = "Lecture du fichier GeoJSON...";
|
||||
$jsonContent = file_get_contents($filePath);
|
||||
|
||||
if ($jsonContent === false) {
|
||||
$this->log[] = "✗ Impossible de lire le fichier";
|
||||
return $this->log;
|
||||
}
|
||||
|
||||
// Parser le JSON
|
||||
$geojson = json_decode($jsonContent, true);
|
||||
|
||||
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||
$this->log[] = "✗ Erreur JSON : " . json_last_error_msg();
|
||||
return $this->log;
|
||||
}
|
||||
|
||||
if (!isset($geojson['features']) || !is_array($geojson['features'])) {
|
||||
$this->log[] = "✗ Format GeoJSON invalide : pas de features";
|
||||
return $this->log;
|
||||
}
|
||||
|
||||
$this->log[] = "✓ Fichier chargé : " . count($geojson['features']) . " départements trouvés";
|
||||
$this->log[] = "";
|
||||
|
||||
// Préparer la requête d'insertion
|
||||
$sql = "INSERT INTO x_departements_contours
|
||||
(code_dept, nom_dept, contour, bbox_min_lat, bbox_max_lat, bbox_min_lng, bbox_max_lng)
|
||||
VALUES
|
||||
(:code, :nom, ST_GeomFromText(:polygon, 4326), :min_lat, :max_lat, :min_lng, :max_lng)";
|
||||
|
||||
$stmt = $this->db->prepare($sql);
|
||||
|
||||
$success = 0;
|
||||
$errors = 0;
|
||||
|
||||
// Démarrer une transaction
|
||||
$this->db->beginTransaction();
|
||||
|
||||
try {
|
||||
foreach ($geojson['features'] as $feature) {
|
||||
// Extraire les informations
|
||||
$code = $feature['properties']['code'] ?? null;
|
||||
$nom = $feature['properties']['nom'] ?? null;
|
||||
$geometry = $feature['geometry'] ?? null;
|
||||
|
||||
if (!$code || !$nom || !$geometry) {
|
||||
$this->log[] = "✗ Données manquantes pour un département";
|
||||
$errors++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Convertir la géométrie en WKT
|
||||
$wktData = $this->geometryToWkt($geometry);
|
||||
|
||||
if (!$wktData) {
|
||||
$this->log[] = "✗ Conversion échouée pour $code ($nom)";
|
||||
$errors++;
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$stmt->execute([
|
||||
'code' => $code,
|
||||
'nom' => $nom,
|
||||
'polygon' => $wktData['wkt'],
|
||||
'min_lat' => $wktData['bbox']['min_lat'],
|
||||
'max_lat' => $wktData['bbox']['max_lat'],
|
||||
'min_lng' => $wktData['bbox']['min_lng'],
|
||||
'max_lng' => $wktData['bbox']['max_lng']
|
||||
]);
|
||||
|
||||
$this->log[] = "✓ $code - $nom importé";
|
||||
$success++;
|
||||
|
||||
} catch (Exception $e) {
|
||||
$this->log[] = "✗ Erreur SQL pour $code ($nom) : " . $e->getMessage();
|
||||
$errors++;
|
||||
}
|
||||
}
|
||||
|
||||
// Valider ou annuler la transaction
|
||||
if ($success > 0) {
|
||||
$this->db->commit();
|
||||
$this->log[] = "";
|
||||
$this->log[] = "✓ Transaction validée";
|
||||
} else {
|
||||
$this->db->rollBack();
|
||||
$this->log[] = "";
|
||||
$this->log[] = "✗ Transaction annulée (aucun import réussi)";
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
$this->db->rollBack();
|
||||
$this->log[] = "";
|
||||
$this->log[] = "✗ Erreur fatale : " . $e->getMessage();
|
||||
$this->log[] = "✗ Transaction annulée";
|
||||
}
|
||||
|
||||
$this->log[] = "";
|
||||
$this->log[] = "Import terminé : $success réussis, $errors erreurs";
|
||||
|
||||
return $this->log;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convertit une géométrie GeoJSON en WKT
|
||||
*/
|
||||
private function geometryToWkt(array $geometry): ?array {
|
||||
$type = $geometry['type'] ?? null;
|
||||
$coordinates = $geometry['coordinates'] ?? null;
|
||||
|
||||
if (!$type || !$coordinates) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$wkt = null;
|
||||
$allPoints = [];
|
||||
|
||||
switch ($type) {
|
||||
case 'Polygon':
|
||||
// Un seul polygone
|
||||
$ring = $coordinates[0]; // Anneau extérieur
|
||||
$points = [];
|
||||
foreach ($ring as $point) {
|
||||
$points[] = $point[0] . ' ' . $point[1];
|
||||
$allPoints[] = $point;
|
||||
}
|
||||
$wkt = 'POLYGON((' . implode(',', $points) . '))';
|
||||
break;
|
||||
|
||||
case 'MultiPolygon':
|
||||
// Plusieurs polygones
|
||||
$polygons = [];
|
||||
foreach ($coordinates as $polygon) {
|
||||
$ring = $polygon[0]; // Anneau extérieur du polygone
|
||||
$points = [];
|
||||
foreach ($ring as $point) {
|
||||
$points[] = $point[0] . ' ' . $point[1];
|
||||
$allPoints[] = $point;
|
||||
}
|
||||
$polygons[] = '((' . implode(',', $points) . '))';
|
||||
}
|
||||
$wkt = 'MULTIPOLYGON(' . implode(',', $polygons) . ')';
|
||||
break;
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!$wkt || empty($allPoints)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Calculer la bounding box
|
||||
$lats = array_map(function($p) { return $p[1]; }, $allPoints);
|
||||
$lngs = array_map(function($p) { return $p[0]; }, $allPoints);
|
||||
|
||||
return [
|
||||
'wkt' => $wkt,
|
||||
'bbox' => [
|
||||
'min_lat' => min($lats),
|
||||
'max_lat' => max($lats),
|
||||
'min_lng' => min($lngs),
|
||||
'max_lng' => max($lngs)
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// Si le script est exécuté directement
|
||||
if (php_sapi_name() === 'cli' && basename(__FILE__) === basename($_SERVER['PHP_SELF'] ?? __FILE__)) {
|
||||
require_once __DIR__ . '/../src/Config/AppConfig.php';
|
||||
require_once __DIR__ . '/../src/Core/Database.php';
|
||||
|
||||
// Chemin vers le fichier GeoJSON
|
||||
$filePath = __DIR__ . '/../docs/contour-des-departements.geojson';
|
||||
|
||||
// Vérifier les arguments
|
||||
if ($argc > 1) {
|
||||
$filePath = $argv[1];
|
||||
}
|
||||
|
||||
echo "Import des contours départementaux depuis un fichier\n";
|
||||
echo "==================================================\n\n";
|
||||
echo "Fichier : $filePath\n\n";
|
||||
|
||||
$appConfig = AppConfig::getInstance();
|
||||
Database::init($appConfig->getDatabaseConfig());
|
||||
$db = Database::getInstance();
|
||||
|
||||
$importer = new DepartementContoursFileImporter($db);
|
||||
$log = $importer->importFromFile($filePath);
|
||||
|
||||
foreach ($log as $line) {
|
||||
echo $line . "\n";
|
||||
}
|
||||
}
|
||||
175
api/scripts/import_department_boundaries.php
Normal file
175
api/scripts/import_department_boundaries.php
Normal file
@@ -0,0 +1,175 @@
|
||||
<?php
|
||||
/**
|
||||
* Script d'import des contours des départements français
|
||||
*
|
||||
* Les données peuvent provenir de :
|
||||
* - IGN Admin Express : https://geoservices.ign.fr/adminexpress
|
||||
* - data.gouv.fr : https://www.data.gouv.fr/fr/datasets/contours-des-departements-francais-issus-d-openstreetmap/
|
||||
* - OpenStreetMap via Overpass API
|
||||
*
|
||||
* Format attendu : GeoJSON ou Shapefile converti en SQL
|
||||
*/
|
||||
|
||||
require_once __DIR__ . '/../src/Config/AppConfig.php';
|
||||
require_once __DIR__ . '/../src/Core/Database.php';
|
||||
|
||||
echo "Import des contours des départements\n";
|
||||
echo "===================================\n\n";
|
||||
|
||||
// Initialiser la base de données
|
||||
$appConfig = AppConfig::getInstance();
|
||||
Database::init($appConfig->getDatabaseConfig());
|
||||
$db = Database::getInstance();
|
||||
|
||||
// Exemple de données pour quelques départements bretons
|
||||
// En production, ces données viendraient d'un fichier GeoJSON ou d'une API
|
||||
$departements = [
|
||||
[
|
||||
'code' => '22',
|
||||
'nom' => 'Côtes-d\'Armor',
|
||||
// Contour simplifié - en réalité il faudrait des centaines de points
|
||||
'points' => [
|
||||
[-3.6546, 48.9012], [-3.3856, 48.8756], [-3.1234, 48.8234],
|
||||
[-2.7856, 48.7845], [-2.4567, 48.7234], [-2.1234, 48.6456],
|
||||
[-2.0123, 48.5234], [-2.0456, 48.3456], [-2.1567, 48.1234],
|
||||
[-2.3456, 48.0567], [-2.6789, 48.0789], [-3.0123, 48.1234],
|
||||
[-3.3456, 48.2345], [-3.5678, 48.4567], [-3.6234, 48.6789],
|
||||
[-3.6546, 48.9012] // Fermer le polygone
|
||||
]
|
||||
],
|
||||
[
|
||||
'code' => '29',
|
||||
'nom' => 'Finistère',
|
||||
'points' => [
|
||||
[-5.1423, 48.7523], [-4.8234, 48.6845], [-4.5123, 48.6234],
|
||||
[-4.2345, 48.5678], [-3.9876, 48.4567], [-3.7234, 48.3456],
|
||||
[-3.4567, 48.2345], [-3.3876, 48.0123], [-3.4234, 47.8234],
|
||||
[-3.5678, 47.6456], [-3.8765, 47.6789], [-4.2345, 47.7234],
|
||||
[-4.5678, 47.8234], [-4.8765, 47.9345], [-5.0876, 48.1234],
|
||||
[-5.1234, 48.3456], [-5.1345, 48.5678], [-5.1423, 48.7523]
|
||||
]
|
||||
],
|
||||
[
|
||||
'code' => '35',
|
||||
'nom' => 'Ille-et-Vilaine',
|
||||
'points' => [
|
||||
[-2.0123, 48.6456], [-1.7234, 48.5678], [-1.4567, 48.4567],
|
||||
[-1.2345, 48.3456], [-1.0234, 48.2345], [-1.0567, 48.0123],
|
||||
[-1.1234, 47.8234], [-1.2567, 47.6456], [-1.4678, 47.6789],
|
||||
[-1.7234, 47.7234], [-1.9876, 47.8234], [-2.1234, 47.9345],
|
||||
[-2.2345, 48.1234], [-2.1567, 48.3456], [-2.0678, 48.5234],
|
||||
[-2.0123, 48.6456]
|
||||
]
|
||||
],
|
||||
[
|
||||
'code' => '56',
|
||||
'nom' => 'Morbihan',
|
||||
'points' => [
|
||||
[-3.4567, 48.2345], [-3.2345, 48.1234], [-2.9876, 48.0123],
|
||||
[-2.7234, 47.9234], [-2.4567, 47.8345], [-2.2345, 47.7456],
|
||||
[-2.1234, 47.6234], [-2.2567, 47.4567], [-2.4678, 47.3456],
|
||||
[-2.7234, 47.3789], [-3.0123, 47.4234], [-3.2876, 47.5234],
|
||||
[-3.5234, 47.6345], [-3.6789, 47.7456], [-3.7234, 47.9234],
|
||||
[-3.6567, 48.0789], [-3.4567, 48.2345]
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
try {
|
||||
$db->beginTransaction();
|
||||
|
||||
// Préparer la requête d'insertion
|
||||
$sql = "INSERT INTO departements_contours
|
||||
(code_dept, nom_dept, contour, bbox_min_lat, bbox_max_lat, bbox_min_lng, bbox_max_lng)
|
||||
VALUES
|
||||
(:code, :nom, ST_GeomFromText(:polygon, 4326), :min_lat, :max_lat, :min_lng, :max_lng)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
nom_dept = VALUES(nom_dept),
|
||||
contour = VALUES(contour),
|
||||
bbox_min_lat = VALUES(bbox_min_lat),
|
||||
bbox_max_lat = VALUES(bbox_max_lat),
|
||||
bbox_min_lng = VALUES(bbox_min_lng),
|
||||
bbox_max_lng = VALUES(bbox_max_lng),
|
||||
updated_at = CURRENT_TIMESTAMP";
|
||||
|
||||
$stmt = $db->prepare($sql);
|
||||
|
||||
foreach ($departements as $dept) {
|
||||
echo "Import du département {$dept['code']} - {$dept['nom']}...\n";
|
||||
|
||||
// Créer le polygone WKT
|
||||
$polygonPoints = [];
|
||||
$lats = [];
|
||||
$lngs = [];
|
||||
|
||||
foreach ($dept['points'] as $point) {
|
||||
$lng = $point[0];
|
||||
$lat = $point[1];
|
||||
$polygonPoints[] = "$lng $lat";
|
||||
$lats[] = $lat;
|
||||
$lngs[] = $lng;
|
||||
}
|
||||
|
||||
$polygon = 'POLYGON((' . implode(',', $polygonPoints) . '))';
|
||||
|
||||
// Calculer la bounding box
|
||||
$minLat = min($lats);
|
||||
$maxLat = max($lats);
|
||||
$minLng = min($lngs);
|
||||
$maxLng = max($lngs);
|
||||
|
||||
// Exécuter l'insertion
|
||||
$stmt->execute([
|
||||
'code' => $dept['code'],
|
||||
'nom' => $dept['nom'],
|
||||
'polygon' => $polygon,
|
||||
'min_lat' => $minLat,
|
||||
'max_lat' => $maxLat,
|
||||
'min_lng' => $minLng,
|
||||
'max_lng' => $maxLng
|
||||
]);
|
||||
|
||||
echo "✓ Département {$dept['code']} importé\n";
|
||||
}
|
||||
|
||||
$db->commit();
|
||||
|
||||
echo "\n✓ Import terminé avec succès!\n\n";
|
||||
|
||||
// Vérifier les données importées
|
||||
$checkSql = "SELECT code_dept, nom_dept,
|
||||
ST_Area(contour) as area,
|
||||
ST_NumPoints(ST_ExteriorRing(contour)) as num_points
|
||||
FROM x_departements_contours
|
||||
ORDER BY code_dept";
|
||||
|
||||
$result = $db->query($checkSql);
|
||||
echo "Départements importés:\n";
|
||||
echo "---------------------\n";
|
||||
|
||||
foreach ($result as $row) {
|
||||
echo sprintf("- %s (%s) : %d points, aire: %.4f\n",
|
||||
$row['nom_dept'],
|
||||
$row['code_dept'],
|
||||
$row['num_points'],
|
||||
$row['area']
|
||||
);
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
$db->rollBack();
|
||||
echo "✗ Erreur lors de l'import : " . $e->getMessage() . "\n";
|
||||
}
|
||||
|
||||
echo "\n";
|
||||
echo "Note importante:\n";
|
||||
echo "---------------\n";
|
||||
echo "Ce script utilise des données simplifiées pour l'exemple.\n";
|
||||
echo "Pour un usage en production, vous devez :\n";
|
||||
echo "1. Télécharger les vrais contours depuis l'IGN ou data.gouv.fr\n";
|
||||
echo "2. Les convertir en format GeoJSON ou SQL\n";
|
||||
echo "3. Adapter ce script pour lire ces fichiers\n";
|
||||
echo "\n";
|
||||
echo "Sources recommandées:\n";
|
||||
echo "- IGN Admin Express: https://geoservices.ign.fr/adminexpress\n";
|
||||
echo "- data.gouv.fr: https://www.data.gouv.fr/fr/datasets/contours-des-departements-francais-issus-d-openstreetmap/\n";
|
||||
318
api/scripts/init_departements_contours.php
Normal file
318
api/scripts/init_departements_contours.php
Normal file
@@ -0,0 +1,318 @@
|
||||
<?php
|
||||
/**
|
||||
* Script d'initialisation des contours des départements français
|
||||
* À exécuter une seule fois lors de la connexion de l'admin d6soft
|
||||
*
|
||||
* Utilise l'API geo.api.gouv.fr pour récupérer les contours GeoJSON
|
||||
*/
|
||||
|
||||
class DepartementContoursInitializer {
|
||||
private PDO $db;
|
||||
private array $log = [];
|
||||
|
||||
// Liste complète des départements français (métropole + DOM-TOM)
|
||||
private array $departements = [
|
||||
// Métropole
|
||||
'01' => 'Ain', '02' => 'Aisne', '03' => 'Allier', '04' => 'Alpes-de-Haute-Provence',
|
||||
'05' => 'Hautes-Alpes', '06' => 'Alpes-Maritimes', '07' => 'Ardèche', '08' => 'Ardennes',
|
||||
'09' => 'Ariège', '10' => 'Aube', '11' => 'Aude', '12' => 'Aveyron',
|
||||
'13' => 'Bouches-du-Rhône', '14' => 'Calvados', '15' => 'Cantal', '16' => 'Charente',
|
||||
'17' => 'Charente-Maritime', '18' => 'Cher', '19' => 'Corrèze', '2A' => 'Corse-du-Sud',
|
||||
'2B' => 'Haute-Corse', '21' => 'Côte-d\'Or', '22' => 'Côtes-d\'Armor', '23' => 'Creuse',
|
||||
'24' => 'Dordogne', '25' => 'Doubs', '26' => 'Drôme', '27' => 'Eure',
|
||||
'28' => 'Eure-et-Loir', '29' => 'Finistère', '30' => 'Gard', '31' => 'Haute-Garonne',
|
||||
'32' => 'Gers', '33' => 'Gironde', '34' => 'Hérault', '35' => 'Ille-et-Vilaine',
|
||||
'36' => 'Indre', '37' => 'Indre-et-Loire', '38' => 'Isère', '39' => 'Jura',
|
||||
'40' => 'Landes', '41' => 'Loir-et-Cher', '42' => 'Loire', '43' => 'Haute-Loire',
|
||||
'44' => 'Loire-Atlantique', '45' => 'Loiret', '46' => 'Lot', '47' => 'Lot-et-Garonne',
|
||||
'48' => 'Lozère', '49' => 'Maine-et-Loire', '50' => 'Manche', '51' => 'Marne',
|
||||
'52' => 'Haute-Marne', '53' => 'Mayenne', '54' => 'Meurthe-et-Moselle', '55' => 'Meuse',
|
||||
'56' => 'Morbihan', '57' => 'Moselle', '58' => 'Nièvre', '59' => 'Nord',
|
||||
'60' => 'Oise', '61' => 'Orne', '62' => 'Pas-de-Calais', '63' => 'Puy-de-Dôme',
|
||||
'64' => 'Pyrénées-Atlantiques', '65' => 'Hautes-Pyrénées', '66' => 'Pyrénées-Orientales', '67' => 'Bas-Rhin',
|
||||
'68' => 'Haut-Rhin', '69' => 'Rhône', '70' => 'Haute-Saône', '71' => 'Saône-et-Loire',
|
||||
'72' => 'Sarthe', '73' => 'Savoie', '74' => 'Haute-Savoie', '75' => 'Paris',
|
||||
'76' => 'Seine-Maritime', '77' => 'Seine-et-Marne', '78' => 'Yvelines', '79' => 'Deux-Sèvres',
|
||||
'80' => 'Somme', '81' => 'Tarn', '82' => 'Tarn-et-Garonne', '83' => 'Var',
|
||||
'84' => 'Vaucluse', '85' => 'Vendée', '86' => 'Vienne', '87' => 'Haute-Vienne',
|
||||
'88' => 'Vosges', '89' => 'Yonne', '90' => 'Territoire de Belfort', '91' => 'Essonne',
|
||||
'92' => 'Hauts-de-Seine', '93' => 'Seine-Saint-Denis', '94' => 'Val-de-Marne', '95' => 'Val-d\'Oise',
|
||||
// DOM-TOM
|
||||
'971' => 'Guadeloupe', '972' => 'Martinique', '973' => 'Guyane', '974' => 'La Réunion',
|
||||
'975' => 'Saint-Pierre-et-Miquelon', '976' => 'Mayotte', '977' => 'Saint-Barthélemy',
|
||||
'978' => 'Saint-Martin', '984' => 'Terres australes et antarctiques françaises',
|
||||
'986' => 'Wallis-et-Futuna', '987' => 'Polynésie française', '988' => 'Nouvelle-Calédonie'
|
||||
];
|
||||
|
||||
public function __construct(PDO $db) {
|
||||
$this->db = $db;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si la table existe
|
||||
*/
|
||||
public function tableExists(): bool {
|
||||
try {
|
||||
$sql = "SHOW TABLES LIKE 'x_departements_contours'";
|
||||
$stmt = $this->db->query($sql);
|
||||
return $stmt->rowCount() > 0;
|
||||
} catch (Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si la table est vide
|
||||
*/
|
||||
private function isTableEmpty(): bool {
|
||||
try {
|
||||
$sql = "SELECT COUNT(*) as count FROM x_departements_contours";
|
||||
$stmt = $this->db->query($sql);
|
||||
$result = $stmt->fetch();
|
||||
return $result['count'] == 0;
|
||||
} catch (Exception $e) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupère le contour d'un département depuis l'API geo.api.gouv.fr
|
||||
*/
|
||||
private function fetchDepartementContour(string $code, string $nom): ?array {
|
||||
// URL de l'API pour récupérer le contour du département en GeoJSON
|
||||
$url = "https://geo.api.gouv.fr/departements/{$code}?geometry=contour";
|
||||
|
||||
$context = stream_context_create([
|
||||
'http' => [
|
||||
'timeout' => 30,
|
||||
'header' => "User-Agent: Geosector/1.0\r\n"
|
||||
]
|
||||
]);
|
||||
|
||||
$response = @file_get_contents($url, false, $context);
|
||||
|
||||
if ($response === false) {
|
||||
$this->log[] = "✗ Erreur API pour département $code ($nom)";
|
||||
return null;
|
||||
}
|
||||
|
||||
$data = json_decode($response, true);
|
||||
|
||||
// L'API peut retourner le contour dans 'contour' ou 'geometry'
|
||||
if (isset($data['contour']) && isset($data['contour']['coordinates'])) {
|
||||
return $data['contour'];
|
||||
} elseif (isset($data['geometry']) && isset($data['geometry']['coordinates'])) {
|
||||
return $data['geometry'];
|
||||
} else {
|
||||
$this->log[] = "✗ Pas de contour pour département $code ($nom)";
|
||||
// Debug : afficher les clés disponibles
|
||||
if (is_array($data)) {
|
||||
$this->log[] = " Clés disponibles : " . implode(', ', array_keys($data));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convertit les coordonnées GeoJSON en WKT Polygon pour MySQL
|
||||
*/
|
||||
private function geoJsonToWkt(array $coordinates): ?array {
|
||||
if (empty($coordinates) || !is_array($coordinates[0])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// GeoJSON peut avoir plusieurs niveaux d'imbrication selon le type
|
||||
// Pour un Polygon simple
|
||||
if (isset($coordinates[0][0]) && is_numeric($coordinates[0][0])) {
|
||||
$ring = $coordinates;
|
||||
}
|
||||
// Pour un MultiPolygon, prendre le premier polygone
|
||||
elseif (isset($coordinates[0][0][0])) {
|
||||
$ring = $coordinates[0][0];
|
||||
}
|
||||
// Pour un Polygon standard
|
||||
else {
|
||||
$ring = $coordinates[0];
|
||||
}
|
||||
|
||||
$points = [];
|
||||
$lats = [];
|
||||
$lngs = [];
|
||||
|
||||
foreach ($ring as $point) {
|
||||
if (count($point) >= 2) {
|
||||
$lng = $point[0];
|
||||
$lat = $point[1];
|
||||
$points[] = "$lng $lat";
|
||||
$lats[] = $lat;
|
||||
$lngs[] = $lng;
|
||||
}
|
||||
}
|
||||
|
||||
if (count($points) < 3) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Fermer le polygone si nécessaire
|
||||
if ($points[0] !== $points[count($points) - 1]) {
|
||||
$points[] = $points[0];
|
||||
}
|
||||
|
||||
return [
|
||||
'wkt' => 'POLYGON((' . implode(',', $points) . '))',
|
||||
'bbox' => [
|
||||
'min_lat' => min($lats),
|
||||
'max_lat' => max($lats),
|
||||
'min_lng' => min($lngs),
|
||||
'max_lng' => max($lngs)
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Importe tous les départements
|
||||
*/
|
||||
public function importAll(): array {
|
||||
$this->log[] = "Début de l'import des contours départementaux";
|
||||
$this->log[] = "Source : API geo.api.gouv.fr";
|
||||
$this->log[] = "";
|
||||
|
||||
// Vérifier que la table est vide avant d'importer
|
||||
if (!$this->isTableEmpty()) {
|
||||
$this->log[] = "✗ La table x_departements_contours contient déjà des données";
|
||||
return $this->log;
|
||||
}
|
||||
|
||||
// Préparer la requête d'insertion
|
||||
$sql = "INSERT INTO x_departements_contours
|
||||
(code_dept, nom_dept, contour, bbox_min_lat, bbox_max_lat, bbox_min_lng, bbox_max_lng)
|
||||
VALUES
|
||||
(:code, :nom, ST_GeomFromText(:polygon, 4326), :min_lat, :max_lat, :min_lng, :max_lng)";
|
||||
|
||||
$stmt = $this->db->prepare($sql);
|
||||
|
||||
$success = 0;
|
||||
$errors = 0;
|
||||
|
||||
// Démarrer une transaction
|
||||
$this->db->beginTransaction();
|
||||
|
||||
try {
|
||||
foreach ($this->departements as $code => $nom) {
|
||||
// Petite pause pour ne pas surcharger l'API
|
||||
usleep(100000); // 100ms
|
||||
|
||||
$contour = $this->fetchDepartementContour($code, $nom);
|
||||
|
||||
if (!$contour) {
|
||||
$errors++;
|
||||
continue;
|
||||
}
|
||||
|
||||
$wktData = $this->geoJsonToWkt($contour['coordinates']);
|
||||
|
||||
if (!$wktData) {
|
||||
$this->log[] = "✗ Conversion échouée pour $code ($nom)";
|
||||
$errors++;
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$stmt->execute([
|
||||
'code' => $code,
|
||||
'nom' => $nom,
|
||||
'polygon' => $wktData['wkt'],
|
||||
'min_lat' => $wktData['bbox']['min_lat'],
|
||||
'max_lat' => $wktData['bbox']['max_lat'],
|
||||
'min_lng' => $wktData['bbox']['min_lng'],
|
||||
'max_lng' => $wktData['bbox']['max_lng']
|
||||
]);
|
||||
|
||||
$this->log[] = "✓ $code - $nom importé";
|
||||
$success++;
|
||||
|
||||
} catch (Exception $e) {
|
||||
$this->log[] = "✗ Erreur SQL pour $code ($nom) : " . $e->getMessage();
|
||||
$errors++;
|
||||
}
|
||||
}
|
||||
|
||||
// Si tout s'est bien passé, valider la transaction
|
||||
if ($success > 0) {
|
||||
$this->db->commit();
|
||||
$this->log[] = "";
|
||||
$this->log[] = "✓ Transaction validée";
|
||||
} else {
|
||||
$this->db->rollBack();
|
||||
$this->log[] = "";
|
||||
$this->log[] = "✗ Transaction annulée (aucun import réussi)";
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
$this->db->rollBack();
|
||||
$this->log[] = "";
|
||||
$this->log[] = "✗ Erreur fatale : " . $e->getMessage();
|
||||
$this->log[] = "✗ Transaction annulée";
|
||||
$errors = count($this->departements);
|
||||
}
|
||||
|
||||
$this->log[] = "";
|
||||
$this->log[] = "Import terminé : $success réussis, $errors erreurs";
|
||||
|
||||
return $this->log;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exécute l'initialisation si nécessaire
|
||||
*/
|
||||
public static function runIfNeeded(PDO $db, string $username): ?array {
|
||||
// Vérifier que c'est bien l'admin d6soft
|
||||
if ($username !== 'd6soft') {
|
||||
return null;
|
||||
}
|
||||
|
||||
$initializer = new self($db);
|
||||
|
||||
// Vérifier si la table existe
|
||||
if (!$initializer->tableExists()) {
|
||||
return ["✗ La table x_departements_contours n'existe pas. Veuillez la créer avec le script SQL fourni."];
|
||||
}
|
||||
|
||||
// Vérifier si elle est vide
|
||||
if (!$initializer->isTableEmpty()) {
|
||||
return null; // Table déjà remplie, rien à faire
|
||||
}
|
||||
|
||||
// Vérifier si le fichier local existe
|
||||
$localFile = __DIR__ . '/../docs/contour-des-departements.geojson';
|
||||
if (file_exists($localFile)) {
|
||||
// Utiliser le fichier local
|
||||
require_once __DIR__ . '/import_departements_from_file.php';
|
||||
$fileImporter = new \DepartementContoursFileImporter($db);
|
||||
return $fileImporter->importFromFile($localFile);
|
||||
}
|
||||
|
||||
// Sinon, utiliser l'API (qui ne fonctionne pas bien actuellement)
|
||||
return $initializer->importAll();
|
||||
}
|
||||
}
|
||||
|
||||
// Si le script est exécuté directement (pour tests)
|
||||
if (php_sapi_name() === 'cli' && basename(__FILE__) === basename($_SERVER['PHP_SELF'] ?? __FILE__)) {
|
||||
require_once __DIR__ . '/../src/Config/AppConfig.php';
|
||||
require_once __DIR__ . '/../src/Core/Database.php';
|
||||
|
||||
$appConfig = AppConfig::getInstance();
|
||||
Database::init($appConfig->getDatabaseConfig());
|
||||
$db = Database::getInstance();
|
||||
|
||||
echo "Test d'import des contours départementaux\n";
|
||||
echo "========================================\n\n";
|
||||
|
||||
$initializer = new DepartementContoursInitializer($db);
|
||||
$log = $initializer->importAll();
|
||||
|
||||
foreach ($log as $line) {
|
||||
echo $line . "\n";
|
||||
}
|
||||
}
|
||||
0
api/scripts/php/MigrationConfig.php
Normal file → Executable file
0
api/scripts/php/MigrationConfig.php
Normal file → Executable file
0
api/scripts/php/migrate.php
Normal file → Executable file
0
api/scripts/php/migrate.php
Normal file → Executable file
0
api/scripts/php/migrate_entites.php
Normal file → Executable file
0
api/scripts/php/migrate_entites.php
Normal file → Executable file
0
api/scripts/php/migrate_medias.php
Normal file → Executable file
0
api/scripts/php/migrate_medias.php
Normal file → Executable file
0
api/scripts/php/migrate_ope_pass.php
Normal file → Executable file
0
api/scripts/php/migrate_ope_pass.php
Normal file → Executable file
0
api/scripts/php/migrate_ope_pass_histo.php
Normal file → Executable file
0
api/scripts/php/migrate_ope_pass_histo.php
Normal file → Executable file
0
api/scripts/php/migrate_ope_sectors.php
Normal file → Executable file
0
api/scripts/php/migrate_ope_sectors.php
Normal file → Executable file
0
api/scripts/php/migrate_ope_users.php
Normal file → Executable file
0
api/scripts/php/migrate_ope_users.php
Normal file → Executable file
0
api/scripts/php/migrate_ope_users_sectors.php
Normal file → Executable file
0
api/scripts/php/migrate_ope_users_sectors.php
Normal file → Executable file
0
api/scripts/php/migrate_operations.php
Normal file → Executable file
0
api/scripts/php/migrate_operations.php
Normal file → Executable file
0
api/scripts/php/migrate_sectors_adresses.php
Normal file → Executable file
0
api/scripts/php/migrate_sectors_adresses.php
Normal file → Executable file
0
api/scripts/php/migrate_users.php
Normal file → Executable file
0
api/scripts/php/migrate_users.php
Normal file → Executable file
0
api/scripts/php/migrate_x_departements.php
Normal file → Executable file
0
api/scripts/php/migrate_x_departements.php
Normal file → Executable file
0
api/scripts/php/migrate_x_devises.php
Normal file → Executable file
0
api/scripts/php/migrate_x_devises.php
Normal file → Executable file
0
api/scripts/php/migrate_x_entites_types.php
Normal file → Executable file
0
api/scripts/php/migrate_x_entites_types.php
Normal file → Executable file
0
api/scripts/php/migrate_x_pays.php
Normal file → Executable file
0
api/scripts/php/migrate_x_pays.php
Normal file → Executable file
0
api/scripts/php/migrate_x_regions.php
Normal file → Executable file
0
api/scripts/php/migrate_x_regions.php
Normal file → Executable file
0
api/scripts/php/migrate_x_types_passages.php
Normal file → Executable file
0
api/scripts/php/migrate_x_types_passages.php
Normal file → Executable file
0
api/scripts/php/migrate_x_types_reglements.php
Normal file → Executable file
0
api/scripts/php/migrate_x_types_reglements.php
Normal file → Executable file
0
api/scripts/php/migrate_x_users_roles.php
Normal file → Executable file
0
api/scripts/php/migrate_x_users_roles.php
Normal file → Executable file
0
api/scripts/php/migrate_x_villes.php
Normal file → Executable file
0
api/scripts/php/migrate_x_villes.php
Normal file → Executable file
106
api/scripts/setup_addresses_access.sh
Normal file
106
api/scripts/setup_addresses_access.sh
Normal file
@@ -0,0 +1,106 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Script pour configurer l'accès à la base de données des adresses
|
||||
# sur chaque environnement Incus
|
||||
|
||||
echo "Configuration de l'accès à la base de données des adresses"
|
||||
echo "=========================================================="
|
||||
|
||||
# Fonction pour créer l'utilisateur sur un container
|
||||
create_user_on_container() {
|
||||
local container=$1
|
||||
local api_ip=$2
|
||||
local maria_ip=$3
|
||||
|
||||
echo ""
|
||||
echo "Configuration pour $container..."
|
||||
echo "Container MariaDB IP: $maria_ip"
|
||||
echo "Container API IP: $api_ip"
|
||||
|
||||
# Se connecter au container MariaDB et créer l'utilisateur
|
||||
incus exec $container -- mysql -u root -p -e "
|
||||
-- Créer l'utilisateur pour l'accès depuis l'API
|
||||
CREATE USER IF NOT EXISTS 'adresses_user'@'$api_ip' IDENTIFIED BY 'd66,AdrGeo.User';
|
||||
GRANT SELECT ON adresses.* TO 'adresses_user'@'$api_ip';
|
||||
|
||||
-- Créer aussi un utilisateur localhost pour les tests directs
|
||||
CREATE USER IF NOT EXISTS 'adresses_user'@'localhost' IDENTIFIED BY 'd66,AdrGeo.User';
|
||||
GRANT SELECT ON adresses.* TO 'adresses_user'@'localhost';
|
||||
|
||||
-- Optionnel : créer un utilisateur pour tout le sous-réseau
|
||||
CREATE USER IF NOT EXISTS 'adresses_user'@'13.23.33.%' IDENTIFIED BY 'd66,AdrGeo.User';
|
||||
GRANT SELECT ON adresses.* TO 'adresses_user'@'13.23.33.%';
|
||||
|
||||
FLUSH PRIVILEGES;
|
||||
|
||||
-- Vérifier
|
||||
SELECT user, host FROM mysql.user WHERE user = 'adresses_user';
|
||||
"
|
||||
|
||||
echo "✓ Utilisateur créé sur $container"
|
||||
}
|
||||
|
||||
# Fonction pour tester la connexion
|
||||
test_connection() {
|
||||
local api_container=$1
|
||||
local maria_ip=$2
|
||||
|
||||
echo ""
|
||||
echo "Test de connexion depuis $api_container vers $maria_ip..."
|
||||
|
||||
incus exec $api_container -- mysql -h $maria_ip -u adresses_user -p'd66,AdrGeo.User' -e "
|
||||
SELECT DATABASE();
|
||||
SHOW TABLES FROM adresses LIMIT 5;
|
||||
"
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "✓ Connexion réussie!"
|
||||
else
|
||||
echo "✗ Échec de la connexion"
|
||||
fi
|
||||
}
|
||||
|
||||
# Configuration pour chaque environnement
|
||||
echo ""
|
||||
echo "1. DÉVELOPPEMENT (DVA)"
|
||||
read -p "IP du container dva-api [par défaut: 13.23.33.45]: " DVA_API_IP
|
||||
DVA_API_IP=${DVA_API_IP:-13.23.33.45}
|
||||
create_user_on_container "dva-maria" "$DVA_API_IP" "13.23.33.46"
|
||||
|
||||
echo ""
|
||||
echo "2. RECETTE (RCA)"
|
||||
read -p "IP du container rca-api [par défaut: 13.23.33.35]: " RCA_API_IP
|
||||
RCA_API_IP=${RCA_API_IP:-13.23.33.35}
|
||||
create_user_on_container "rca-maria" "$RCA_API_IP" "13.23.33.36"
|
||||
|
||||
echo ""
|
||||
echo "3. PRODUCTION (PRA)"
|
||||
read -p "IP du container pra-api [par défaut: 13.23.33.25]: " PRA_API_IP
|
||||
PRA_API_IP=${PRA_API_IP:-13.23.33.25}
|
||||
create_user_on_container "pra-maria" "$PRA_API_IP" "13.23.33.26"
|
||||
|
||||
# Tests de connexion
|
||||
echo ""
|
||||
echo "=========================================================="
|
||||
echo "Tests de connexion"
|
||||
echo "=========================================================="
|
||||
|
||||
read -p "Voulez-vous tester les connexions? (o/n): " test_choice
|
||||
if [ "$test_choice" = "o" ]; then
|
||||
test_connection "dva-api" "13.23.33.46"
|
||||
test_connection "rca-api" "13.23.33.36"
|
||||
test_connection "pra-api" "13.23.33.26"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Configuration terminée!"
|
||||
echo ""
|
||||
echo "Notes importantes:"
|
||||
echo "- Les utilisateurs ont été créés avec accès SELECT uniquement sur la base 'adresses'"
|
||||
echo "- Trois types d'accès ont été configurés:"
|
||||
echo " 1. Depuis l'IP spécifique de chaque container API"
|
||||
echo " 2. Depuis localhost (pour les tests directs)"
|
||||
echo " 3. Depuis tout le sous-réseau 13.23.33.% (optionnel, moins sécurisé)"
|
||||
echo ""
|
||||
echo "Pour tester manuellement depuis un container API:"
|
||||
echo "incus exec [container-api] -- mysql -h [ip-maria] -u adresses_user -p'd66,AdrGeo.User' adresses"
|
||||
136
api/scripts/setup_addresses_access_by_env.sh
Normal file
136
api/scripts/setup_addresses_access_by_env.sh
Normal file
@@ -0,0 +1,136 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Script pour configurer l'accès à la base de données des adresses
|
||||
# avec segmentation par environnement basée sur les plages d'IPs
|
||||
|
||||
echo "Configuration de l'accès à la base de données des adresses"
|
||||
echo "=========================================================="
|
||||
echo ""
|
||||
echo "Architecture des IPs par environnement :"
|
||||
echo "- DÉVELOPPEMENT : 13.23.33.40-49 (13.23.33.4%)"
|
||||
echo "- RECETTE : 13.23.33.30-39 (13.23.33.3%)"
|
||||
echo "- PRODUCTION : 13.23.33.20-29 (13.23.33.2%)"
|
||||
echo ""
|
||||
|
||||
# Fonction pour créer l'utilisateur sur un container
|
||||
create_user_on_container() {
|
||||
local container=$1
|
||||
local ip_pattern=$2
|
||||
local env_name=$3
|
||||
|
||||
echo ""
|
||||
echo "Configuration pour $env_name ($container)..."
|
||||
echo "Pattern IP autorisé : $ip_pattern"
|
||||
|
||||
# Se connecter au container MariaDB et créer l'utilisateur
|
||||
incus exec $container -- mysql -u root -p -e "
|
||||
-- Créer l'utilisateur pour l'accès depuis la plage IP de l'environnement
|
||||
CREATE USER IF NOT EXISTS 'adresses_user'@'$ip_pattern' IDENTIFIED BY 'd66,AdrGeo.User';
|
||||
GRANT SELECT ON adresses.* TO 'adresses_user'@'$ip_pattern';
|
||||
|
||||
-- Créer aussi un utilisateur localhost pour les tests directs
|
||||
CREATE USER IF NOT EXISTS 'adresses_user'@'localhost' IDENTIFIED BY 'd66,AdrGeo.User';
|
||||
GRANT SELECT ON adresses.* TO 'adresses_user'@'localhost';
|
||||
|
||||
FLUSH PRIVILEGES;
|
||||
|
||||
-- Vérifier
|
||||
SELECT user, host FROM mysql.user WHERE user = 'adresses_user' ORDER BY host;
|
||||
"
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "✓ Utilisateur créé sur $container"
|
||||
else
|
||||
echo "✗ Erreur lors de la création sur $container"
|
||||
fi
|
||||
}
|
||||
|
||||
# Fonction pour tester la connexion
|
||||
test_connection() {
|
||||
local api_container=$1
|
||||
local maria_ip=$2
|
||||
local env_name=$3
|
||||
|
||||
echo ""
|
||||
echo "Test de connexion $env_name : $api_container -> $maria_ip..."
|
||||
|
||||
incus exec $api_container -- mysql -h $maria_ip -u adresses_user -p'd66,AdrGeo.User' -e "
|
||||
SELECT CONCAT('Connexion réussie depuis ', @@hostname, ' vers ', '$maria_ip') as Status;
|
||||
SELECT DATABASE();
|
||||
SHOW TABLES FROM adresses LIMIT 3;
|
||||
" 2>/dev/null
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "✓ Connexion réussie!"
|
||||
else
|
||||
echo "✗ Échec de la connexion"
|
||||
fi
|
||||
}
|
||||
|
||||
# Menu de sélection
|
||||
echo ""
|
||||
echo "Que voulez-vous configurer ?"
|
||||
echo "1. Environnement DÉVELOPPEMENT uniquement (dva-maria)"
|
||||
echo "2. Environnement RECETTE uniquement (rca-maria)"
|
||||
echo "3. Environnement PRODUCTION uniquement (pra-maria)"
|
||||
echo "4. Tous les environnements"
|
||||
echo ""
|
||||
read -p "Votre choix (1-4): " choice
|
||||
|
||||
case $choice in
|
||||
1)
|
||||
create_user_on_container "dva-maria" "13.23.33.4%" "DÉVELOPPEMENT"
|
||||
;;
|
||||
2)
|
||||
create_user_on_container "rca-maria" "13.23.33.3%" "RECETTE"
|
||||
;;
|
||||
3)
|
||||
create_user_on_container "pra-maria" "13.23.33.2%" "PRODUCTION"
|
||||
;;
|
||||
4)
|
||||
create_user_on_container "dva-maria" "13.23.33.4%" "DÉVELOPPEMENT"
|
||||
create_user_on_container "rca-maria" "13.23.33.3%" "RECETTE"
|
||||
create_user_on_container "pra-maria" "13.23.33.2%" "PRODUCTION"
|
||||
;;
|
||||
*)
|
||||
echo "Choix invalide"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# Tests de connexion
|
||||
echo ""
|
||||
echo "=========================================================="
|
||||
echo "Tests de connexion"
|
||||
echo "=========================================================="
|
||||
|
||||
read -p "Voulez-vous tester les connexions? (o/n): " test_choice
|
||||
if [ "$test_choice" = "o" ]; then
|
||||
case $choice in
|
||||
1)
|
||||
test_connection "dva-api" "13.23.33.46" "DÉVELOPPEMENT"
|
||||
;;
|
||||
2)
|
||||
test_connection "rca-api" "13.23.33.36" "RECETTE"
|
||||
;;
|
||||
3)
|
||||
test_connection "pra-api" "13.23.33.26" "PRODUCTION"
|
||||
;;
|
||||
4)
|
||||
test_connection "dva-api" "13.23.33.46" "DÉVELOPPEMENT"
|
||||
test_connection "rca-api" "13.23.33.36" "RECETTE"
|
||||
test_connection "pra-api" "13.23.33.26" "PRODUCTION"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Configuration terminée!"
|
||||
echo ""
|
||||
echo "Récapitulatif de la sécurité mise en place :"
|
||||
echo "- Chaque environnement a sa propre plage d'IPs autorisée"
|
||||
echo "- DÉVELOPPEMENT : seuls les containers en 13.23.33.4x peuvent accéder à dva-maria"
|
||||
echo "- RECETTE : seuls les containers en 13.23.33.3x peuvent accéder à rca-maria"
|
||||
echo "- PRODUCTION : seuls les containers en 13.23.33.2x peuvent accéder à pra-maria"
|
||||
echo ""
|
||||
echo "Cela empêche un container de DEV d'accéder aux données de PROD par exemple."
|
||||
Reference in New Issue
Block a user