prepare('SELECT country_id FROM operators WHERE id = ?'); $opCheck->execute([$operatorId]); $countryId = $opCheck->fetchColumn(); if ($stagingIds && $operatorId && $countryId !== false) { $db->beginTransaction(); try { $near = $db->prepare('SELECT id FROM sites WHERE operator_id = ? AND ABS(lat - ?) < 0.0003 AND ABS(lon - ?) < 0.0003 LIMIT 1'); $near->execute([$operatorId, $lat, $lon]); $siteId = $near->fetchColumn(); if (!$siteId) { $addrStmt = $db->prepare('SELECT address_desc FROM staging_cells WHERE id = ? LIMIT 1'); $addrStmt->execute([$stagingIds[0]]); $addressDesc = $addrStmt->fetchColumn() ?: null; $insertSite = $db->prepare('INSERT INTO sites (country_id, operator_id, lat, lon, location_desc, address_desc, created_by) VALUES (?, ?, ?, ?, ?, ?, ?)'); $insertSite->execute([$countryId, $operatorId, $lat, $lon, $locationDesc, $addressDesc, $user]); $siteId = (int)$db->lastInsertId(); } $fetchStaging = $db->prepare('SELECT * FROM staging_cells WHERE id = ? AND status = "pending"'); $insertCell = $db->prepare(' INSERT INTO cells (site_id, tech, mcc, mnc, cell_id, area_code, sub_id, sub_id2, band, frequency, azimuth, bandwidth, arfcn, validated_by) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE site_id = VALUES(site_id), band = VALUES(band), frequency = VALUES(frequency), azimuth = VALUES(azimuth), bandwidth = VALUES(bandwidth), validated_by = VALUES(validated_by), validated_at = NOW() '); $markValidated = $db->prepare('UPDATE staging_cells SET status = "validated", reviewed_at = NOW(), reviewed_by = ? WHERE id = ?'); foreach ($stagingIds as $sid) { $fetchStaging->execute([$sid]); $cell = $fetchStaging->fetch(PDO::FETCH_ASSOC); if (!$cell) continue; $insertCell->execute([ $siteId, $cell['tech'], $cell['mcc'], $cell['mnc'], $cell['cell_id'], $cell['area_code'], $cell['sub_id'], $cell['sub_id2'], $cell['band'], $cell['frequency'], $cell['azimuth'], $cell['bandwidth'], $cell['arfcn'], $user, ]); $markValidated->execute([$user, $sid]); } $db->commit(); } catch (Throwable $e) { $db->rollBack(); // Corrige : l'echec n'est plus silencieux. On loggue le // detail technique cote serveur et on informe // l'administrateur qu'aucune validation n'a ete // appliquee, plutot que de rediriger comme si de rien // n'etait alors que la transaction a echoue. error_log('[review] validate_group: ' . $e->getMessage()); $flashError = "La validation du site a echoue et a ete annulee (aucune donnee ecrite). Consultez les journaux du serveur si le probleme persiste."; } } else { $flashError = "Validation refusee : operateur invalide ou selection de cellules vide."; } } if ($action === 'reject') { $stagingId = (int)($_POST['staging_id'] ?? 0); try { $db->prepare('UPDATE staging_cells SET status = "rejected", reviewed_at = NOW(), reviewed_by = ?, reject_reason = ? WHERE id = ? AND status = "pending"') ->execute([$user, $_POST['reject_reason'] ?? null, $stagingId]); } catch (Throwable $e) { error_log('[review] reject: ' . $e->getMessage()); $flashError = 'Le rejet de cette cellule a echoue.'; } } if ($action === 'add_missing_cell') { // Verifie que l'operateur/pays declares existent reellement (coherence // MCC/MNC) avant d'inserer une nouvelle ligne staging manuelle. $operatorId = (int)($_POST['operator_id'] ?? 0); $opCheck = $db->prepare('SELECT mcc, mnc FROM operators WHERE id = ?'); $opCheck->execute([$operatorId]); $op = $opCheck->fetch(PDO::FETCH_ASSOC); if ($op && in_array($_POST['tech'] ?? '', ['2G', '3G', '4G', '5G', 'CDMA'], true)) { try { $db->prepare(' INSERT INTO staging_cells (tech, mcc, mnc, operator_guess, cell_id, area_code, sub_id, sub_id2, band, frequency, azimuth, bandwidth, lat, lon, location_desc, arfcn, source, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, "manual_form", "pending") ')->execute([ $_POST['tech'], $op['mcc'], $op['mnc'], $operatorId, $_POST['cell_id'], $_POST['area_code'], $_POST['sub_id'] !== '' ? $_POST['sub_id'] : null, $_POST['sub_id2'] !== '' ? $_POST['sub_id2'] : null, $_POST['band'] !== '' ? $_POST['band'] : null, $_POST['frequency'] !== '' ? $_POST['frequency'] : null, $_POST['azimuth'] !== '' ? (int)$_POST['azimuth'] : null, $_POST['bandwidth'] !== '' ? $_POST['bandwidth'] : null, $_POST['lat'], $_POST['lon'], $_POST['location_desc'], $_POST['arfcn'] !== '' ? $_POST['arfcn'] : null, ]); } catch (Throwable $e) { error_log('[review] add_missing_cell: ' . $e->getMessage()); $flashError = "L'ajout de la cellule manquante a echoue."; } } else { $flashError = "Ajout refuse : operateur ou technologie invalide."; } } if ($flashError !== null) { $_SESSION['review_flash_error'] = $flashError; } header('Location: review.php' . (isset($_GET['country']) ? '?country=' . urlencode($_GET['country']) : '')); exit; } $flashError = $_SESSION['review_flash_error'] ?? null; unset($_SESSION['review_flash_error']); $countryFilter = $_GET['country'] ?? ''; $operatorFilter = $_GET['operator'] ?? ''; $sql = ' SELECT sc.*, o.brand AS operator_brand, c.name AS country_name FROM staging_cells sc LEFT JOIN operators o ON o.id = sc.operator_guess LEFT JOIN countries c ON c.mcc = sc.mcc WHERE sc.status = "pending" '; $params = []; if ($countryFilter !== '') { $sql .= ' AND c.iso2 = ?'; $params[] = $countryFilter; } if ($operatorFilter !== '') { $sql .= ' AND sc.operator_guess = ?'; $params[] = $operatorFilter; } $sql .= ' ORDER BY sc.submitted_at DESC LIMIT 500'; $stmt = $db->prepare($sql); $stmt->execute($params); $allPending = $stmt->fetchAll(PDO::FETCH_ASSOC); $groups = []; foreach ($allPending as $row) { $key = deriveSiteKey($row); $groups[$key]['cells'][] = $row; $groups[$key]['operator_brand'] = $row['operator_brand']; $groups[$key]['operator_id'] = $row['operator_guess']; $groups[$key]['mcc'] = $row['mcc']; $groups[$key]['mnc'] = $row['mnc']; $groups[$key]['lat'] = $groups[$key]['lat'] ?? $row['lat']; $groups[$key]['lon'] = $groups[$key]['lon'] ?? $row['lon']; $groups[$key]['location_desc'] = $groups[$key]['location_desc'] ?? $row['location_desc']; $groups[$key]['country_name'] = $row['country_name']; $groups[$key]['has_dup'] = ($groups[$key]['has_dup'] ?? false) || (bool)$row['possible_dup_of']; } $operators = $db->query('SELECT id, mcc, mnc, brand FROM operators ORDER BY brand')->fetchAll(PDO::FETCH_ASSOC); $countries = $db->query('SELECT iso2, name, mcc, default_lat, default_lon, default_zoom, cadastre_wms_url, cadastre_wms_layer, cadastre_attribution_html, cadastre_srs FROM countries ORDER BY name')->fetchAll(PDO::FETCH_ASSOC); $activeCountry = null; if ($countryFilter !== '') { foreach ($countries as $c) { if ($c['iso2'] === $countryFilter) { $activeCountry = $c; break; } } } elseif (!empty($groups)) { $firstMcc = reset($groups)['mcc']; foreach ($countries as $c) { if ($c['mcc'] === $firstMcc) { $activeCountry = $c; break; } } } if (!$activeCountry) { $activeCountry = ['default_lat' => 20, 'default_lon' => 0, 'default_zoom' => 2, 'cadastre_wms_url' => null, 'cadastre_wms_layer' => null, 'cadastre_attribution_html' => null, 'cadastre_srs' => 'EPSG:3857']; } $mapPoints = []; foreach ($groups as $key => $g) { if ($g['lat'] && $g['lon']) { $mapPoints[] = ['key' => $key, 'lat' => (float)$g['lat'], 'lon' => (float)$g['lon'], 'operator' => $g['operator_brand'], 'count' => count($g['cells']), 'has_dup' => $g['has_dup']]; } } $hasCadastre = !empty($activeCountry['cadastre_wms_url']) && !empty($activeCountry['cadastre_wms_layer']); $totalPending = count($allPending); $totalDup = count(array_filter($allPending, fn($r) => (bool)$r['possible_dup_of'])); ?>
Verifiez chaque site avant qu'il ne rejoigne la base finale.
= htmlspecialchars($flashError, ENT_QUOTES, 'UTF-8') ?>
| Techno | Cell ID | Area code | Sub ID | eNB/RNC | Bande | Frequence | Azimut | Largeur | ARFCN | Dup. | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| = htmlspecialchars((string)$c['tech'], ENT_QUOTES, 'UTF-8') ?> | = htmlspecialchars((string)$c['cell_id'], ENT_QUOTES, 'UTF-8') ?> | = htmlspecialchars((string)$c['area_code'], ENT_QUOTES, 'UTF-8') ?> | = htmlspecialchars((string)($c['sub_id'] ?? ''), ENT_QUOTES, 'UTF-8') ?> | = htmlspecialchars((string)($c['sub_id2'] ?? ''), ENT_QUOTES, 'UTF-8') ?> | = htmlspecialchars((string)($c['band'] ?? ''), ENT_QUOTES, 'UTF-8') ?> | = htmlspecialchars((string)($c['frequency'] ?? ''), ENT_QUOTES, 'UTF-8') ?> | = $c['azimuth'] !== null ? htmlspecialchars((string)$c['azimuth'], ENT_QUOTES, 'UTF-8') . '°' : '' ?> | = htmlspecialchars((string)($c['bandwidth'] ?? ''), ENT_QUOTES, 'UTF-8') ?> | = htmlspecialchars((string)($c['arfcn'] ?? ''), ENT_QUOTES, 'UTF-8') ?> | = $c['possible_dup_of'] ? '#' . htmlspecialchars((string)$c['possible_dup_of'], ENT_QUOTES, 'UTF-8') : '—' ?> |