Implemented batch state fixer

This commit is contained in:
Andreas Kristiansen
2025-12-07 19:52:26 +01:00
parent 2ddf698af7
commit 0fad755ce6
6 changed files with 178 additions and 52 deletions

View File

@@ -905,4 +905,19 @@ class Logbookadvanced extends CI_Controller {
}
}
public function fixStateBatch() {
if(!clubaccess_check(9)) return;
$this->load->model('logbook_model');
$this->load->model('logbookadvanced_model');
$dxcc = $this->input->post('dxcc', true);
// Process for batch QSO state fix
$result = $this->logbookadvanced_model->fixStateBatch($dxcc);
header("Content-Type: application/json");
echo json_encode($result);
}
}

View File

@@ -134,6 +134,15 @@ class Geojson {
return isset(self::SUPPORTED_STATES[$dxcc]) && self::SUPPORTED_STATES[$dxcc]['enabled'] === true;
}
/**
* Retrieve list of DXCC entities that support state/province lookups
*
* @return array List of supported DXCC entities
*/
public function getSupportedDxccs() {
return self::SUPPORTED_STATES;
}
// ============================================================================
// COORDINATE CONVERSION
// ============================================================================

View File

@@ -1457,18 +1457,18 @@ class Logbookadvanced_model extends CI_Model {
return $this->check_missing_dxcc();
case 'checkstate':
return $this->check_missing_state();
case 'checkcqzones':
return $this->check_missing_cq_zones();
case 'checkituzones':
return $this->check_missing_itu_zones();
return null;
}
}
public function check_missing_dxcc() {
$this->load->model('logbooks_model');
$logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($this->session->userdata('active_station_logbook'));
$sql = "select count(*) as count from " . $this->config->item('table_name') . "
join station_profile on " . $this->config->item('table_name') . ".station_id = station_profile.station_id
where " . $this->config->item('table_name') . ".station_id in (" . implode(',', array_map('intval', $logbooks_locations_array)) . ")
and user_id = ? and coalesce(col_dxcc, '') = ''";
where user_id = ? and coalesce(col_dxcc, '') = ''";
$bindings[] = [$this->session->userdata('user_id')];
@@ -1477,13 +1477,9 @@ class Logbookadvanced_model extends CI_Model {
}
public function check_qsos_missing_continent() {
$this->load->model('logbooks_model');
$logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($this->session->userdata('active_station_logbook'));
$sql = "select count(*) as count from " . $this->config->item('table_name') . "
join station_profile on " . $this->config->item('table_name') . ".station_id = station_profile.station_id
where " . $this->config->item('table_name') . ".station_id in (" . implode(',', array_map('intval', $logbooks_locations_array)) . ")
and user_id = ?
where user_id = ?
and (coalesce(col_cont, '') = '' or col_cont not in ('AF', 'AN', 'AS', 'EU', 'NA', 'OC', 'SA'))";
$bindings[] = [$this->session->userdata('user_id')];
@@ -1493,13 +1489,9 @@ class Logbookadvanced_model extends CI_Model {
}
public function check_missing_distance() {
$this->load->model('logbooks_model');
$logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($this->session->userdata('active_station_logbook'));
$sql = "select count(*) as count from " . $this->config->item('table_name') . "
join station_profile on " . $this->config->item('table_name') . ".station_id = station_profile.station_id
where " . $this->config->item('table_name') . ".station_id in (" . implode(',', array_map('intval', $logbooks_locations_array)) . ")
and user_id = ? and coalesce(col_distance, '') = ''";
where user_id = ? and coalesce(col_distance, '') = ''";
$bindings[] = [$this->session->userdata('user_id')];
@@ -1526,4 +1518,64 @@ class Logbookadvanced_model extends CI_Model {
$query = $this->db->query($sql, $bindings);
return $query->result();
}
public function check_missing_cq_zones() {
$sql = "select count(*) as count from " . $this->config->item('table_name') . "
join station_profile on " . $this->config->item('table_name') . ".station_id = station_profile.station_id
where user_id = ? and coalesce(col_cqz, '') = ''";
$bindings[] = [$this->session->userdata('user_id')];
$query = $this->db->query($sql, $bindings);
return $query->result();
}
public function check_missing_itu_zones() {
$sql = "select count(*) as count from " . $this->config->item('table_name') . "
join station_profile on " . $this->config->item('table_name') . ".station_id = station_profile.station_id
where user_id = ? and coalesce(col_ituz, '') = ''";
$bindings[] = [$this->session->userdata('user_id')];
$query = $this->db->query($sql, $bindings);
return $query->result();
}
/**
* Fix state for a batch of QSOs using GeoJSON lookup
*
* @param int $dxcc DXCC entity number for which to fix states
* @return array Result array with success, dxcc_name, dxcc_number, state_code, skipped
*/
function fixStateBatch($dxcc) {
$this->load->library('Geojson');
// Get QSO data
$sql = "SELECT COL_PRIMARY_KEY, COL_CALL, COL_GRIDSQUARE, COL_DXCC, COL_STATE, d.name as dxcc_name
FROM " . $this->config->item('table_name') . " qsos
JOIN station_profile ON qsos.station_id = station_profile.station_id
LEFT JOIN dxcc_entities d ON qsos.COL_DXCC = d.adif
WHERE qsos.COL_DXCC = ? AND station_profile.user_id = ?
AND (qsos.COL_STATE IS NULL OR qsos.COL_STATE = '')
AND LENGTH(COALESCE(qsos.COL_GRIDSQUARE, '')) >= 6";
$query = $this->db->query($sql, [$dxcc, $this->session->userdata('user_id')]);
if ($query->num_rows() === 0) {
return [
'success' => false,
'skipped' => true,
'reason' => 'QSOs not found'
];
}
$results = [];
foreach ($query->result() as $qso) {
$result = $this->fixStateSingle($qso->COL_PRIMARY_KEY);
$results []= $result;
}
return $results;
}
}

View File

@@ -1,15 +1,16 @@
<?php if (isset($result) && is_array($result) && count($result) > 0): ?>
<div class="col-md-12 result">
<h5>State Check Results</h5>
<p><strong>QSOs with missing state and gridsquares with 6 or more characters found for the following DXCC's:</strong></p>
<h5><?= __("State Check Results"); ?></h5>
<p><?= __("QSOs with missing state and gridsquares with 6 or more characters found for the following DXCC's:"); ?></p>
<div class="table-responsive" style="max-height:70vh; overflow:auto;">
<div class="table-responsive" style="max-height:50vh; overflow:auto;">
<table class="table table-sm table-striped table-bordered table-condensed mb-0">
<thead>
<tr>
<th>Prefix</th>
<th>DXCC</th>
<th>QSOs</th>
<th><?= __("Prefix"); ?></th>
<th><?= __("DXCC"); ?></th>
<th><?= __("QSOs"); ?></th>
<th><?= __("Action"); ?></th>
</tr>
</thead>
<tbody>
@@ -24,6 +25,11 @@
<td><?php echo $item->prefix; ?></td>
<td><?php echo $name; ?></td>
<td><?php echo $qsos; ?></td>
<td>
<button type="button" class="btn btn-sm btn-primary ld-ext-right" onclick="fixState(<?php echo $item->col_dxcc; ?>)">
<?= __("Run fix") ?><div class="ld ld-ring ld-spin"></div>
</button>
</td>
</tr>
<?php endforeach; ?>
</tbody>
@@ -32,7 +38,7 @@
</div>
<?php else: ?>
<div class="col-md-12 result">
<h5>State Check Results</h5>
<p>No issues found. All QSOs have proper state information.</p>
<h5></h5><?= __("State Check Results"); ?></h5>
<p><?= __("No QSOs were found where state information can be fixed."); ?></p>
</div>
<?php endif; ?>

View File

@@ -1,7 +1,11 @@
<div class="container">
<div class="row">
<div class="col-md-6">
<h5><?= __("Data Repair Tools") ?></h5>
<h5><?= __("Data Repair Tools") ?>
<button type="button" class="btn btn-sm btn-info me-1 ld-ext-right" id="checkFixCqZonesBtn" onclick="checkFixCqZones()">
<?= __("Info") ?><div class="ld ld-ring ld-spin"></div>
</button>
</h5>
<div class="list-group">
<div class="list-group-item d-flex justify-content-between align-items-center">
<div>
@@ -12,9 +16,6 @@
<button type="button" class="btn btn-sm btn-secondary me-1 ld-ext-right" id="checkFixCqZonesBtn" onclick="checkFixCqZones()">
<?= __("Check") ?><div class="ld ld-ring ld-spin"></div>
</button>
<button type="button" class="btn btn-sm btn-primary ld-ext-right" id="fixCqZonesBtn" onclick="runFixCqZones()">
<?= __("Run") ?><div class="ld ld-ring ld-spin"></div>
</button>
</div>
</div>
@@ -27,9 +28,6 @@
<button type="button" class="btn btn-sm btn-secondary me-1 ld-ext-right" id="checkFixItuZonesBtn" onclick="checkFixItuZones()">
<?= __("Check") ?><div class="ld ld-ring ld-spin"></div>
</button>
<button type="button" class="btn btn-sm btn-primary ld-ext-right" id="fixItuZonesBtn" onclick="runFixItuZones()">
<?= __("Run") ?><div class="ld ld-ring ld-spin"></div>
</button>
</div>
</div>
@@ -42,9 +40,6 @@
<button type="button" class="btn btn-sm btn-secondary me-1 ld-ext-right" id="checkFixContinentBtn" onclick="checkFixContinent()">
<?= __("Check") ?><div class="ld ld-ring ld-spin"></div>
</button>
<button type="button" class="btn btn-sm btn-primary ld-ext-right" id="fixContinentBtn" onclick="runFixContinent()">
<?= __("Run") ?><div class="ld ld-ring ld-spin"></div>
</button>
</div>
</div>
@@ -57,9 +52,6 @@
<button type="button" class="btn btn-sm btn-secondary me-1 ld-ext-right" id="checkFixStateBtn" onclick="checkFixState()">
<?= __("Check") ?><div class="ld ld-ring ld-spin"></div>
</button>
<button type="button" class="btn btn-sm btn-primary ld-ext-right" id="fixStateBtn" onclick="runFixState()">
<?= __("Run") ?><div class="ld ld-ring ld-spin"></div>
</button>
</div>
</div>
@@ -72,9 +64,6 @@
<button type="button" class="btn btn-sm btn-secondary me-1 ld-ext-right" id="checkUpdateDistancesBtn" onclick="checkUpdateDistances()">
<?= __("Check") ?><div class="ld ld-ring ld-spin"></div>
</button>
<button type="button" class="btn btn-sm btn-primary ld-ext-right" id="updateDistancesBtn" onclick="runUpdateDistances()">
<?= __("Run") ?><div class="ld ld-ring ld-spin"></div>
</button>
</div>
</div>
@@ -87,9 +76,6 @@
<button type="button" class="btn btn-sm btn-secondary me-1 ld-ext-right" id="checkMissingDxccsBtn" onclick="checkMissingDxcc()">
<?= __("Check") ?><div class="ld ld-ring ld-spin"></div>
</button>
<button type="button" class="btn btn-sm btn-primary ld-ext-right" id="updateDistancesBtn" onclick="runUpdateDistances()">
<?= __("Run") ?><div class="ld ld-ring ld-spin"></div>
</button>
</div>
</div>

View File

@@ -2044,7 +2044,7 @@ function saveOptions() {
$('#closeButton').prop("disabled", false);
// Create a nice display for the results
let resultHtml = '<h5>Distance Check Results</h5>';
resultHtml += '<p><strong>QSO to update found:</strong> ' + (response[0].count) + '</p>';
resultHtml += '<p>QSO to update found: ' + (response[0].count) + '</p>';
$('.result').html(resultHtml);
},
@@ -2082,7 +2082,7 @@ function saveOptions() {
$('#closeButton').prop("disabled", false);
// Create a nice display for the results
let resultHtml = '<h5>DXCC Check Results</h5>';
resultHtml += '<p><strong>QSOs without DXCC information found:</strong> ' + (response[0].count) + '</p>';
resultHtml += '<p>QSOs without DXCC information found: ' + (response[0].count) + '</p>';
$('.result').html(resultHtml);
},
@@ -2119,7 +2119,7 @@ function saveOptions() {
$('#closeButton').prop("disabled", false);
// Create a nice display for the results
let resultHtml = '<h5>Continent Check Results</h5>';
resultHtml += '<p><strong>QSOs with missing or invalid continent information found:</strong> ' + (response[0].count) + '</p>';
resultHtml += '<p>QSOs with missing or invalid continent information found: ' + (response[0].count) + '</p>';
$('.result').html(resultHtml);
},
@@ -2175,27 +2175,27 @@ function saveOptions() {
});
}
function checkFixState2() {
$('#checkFixStateBtn').prop("disabled", true).addClass("running");
function checkFixCqZones() {
$('#checkFixCqZonesBtn').prop("disabled", true).addClass("running");
$('#closeButton').prop("disabled", true);
$.ajax({
url: base_url + 'index.php/logbookadvanced/checkDb',
data: {
type: 'checkstate'
type: 'checkcqzones'
},
type: 'POST',
success: function(response) {
$('#checkFixStateBtn').prop("disabled", false).removeClass("running");
$('#checkFixCqZonesBtn').prop("disabled", false).removeClass("running");
$('#closeButton').prop("disabled", false);
// Create a nice display for the results
let resultHtml = '<h5>State Check Results</h5>';
resultHtml += '<p><strong>QSOs with missing state and gridsquares with 6 or more characters found:</strong> ' + (response[0].count) + '</p>';
let resultHtml = '<h5>CQ Zone Check Results</h5>';
resultHtml += '<p>QSOs with missing CQ zone information found: ' + (response[0].count) + '</p>';
$('.result').html(resultHtml);
},
error: function(xhr, status, error) {
$('#checkFixStateBtn').prop('disabled', false).text('<?= __("Check") ?>');
$('#checkFixCqZonesBtn').prop('disabled', false).text('<?= __("Check") ?>');
$('#closeButton').prop('disabled', false);
let errorMsg = '<?= __("Error checking distance information") ?>';
@@ -2211,3 +2211,61 @@ function saveOptions() {
}
});
}
function checkFixItuZones() {
$('#checkFixItuZonesBtn').prop("disabled", true).addClass("running");
$('#closeButton').prop("disabled", true);
$.ajax({
url: base_url + 'index.php/logbookadvanced/checkDb',
data: {
type: 'checkituzones'
},
type: 'POST',
success: function(response) {
$('#checkFixItuZonesBtn').prop("disabled", false).removeClass("running");
$('#closeButton').prop("disabled", false);
// Create a nice display for the results
let resultHtml = '<h5>ITU Zone Check Results</h5>';
resultHtml += '<p>QSOs with missing ITU zone information found: ' + (response[0].count) + '</p>';
$('.result').html(resultHtml);
},
error: function(xhr, status, error) {
$('#checkFixItuZonesBtn').prop('disabled', false).text('<?= __("Check") ?>');
$('#closeButton').prop('disabled', false);
let errorMsg = '<?= __("Error checking distance information") ?>';
if (xhr.responseJSON && xhr.responseJSON.message) {
errorMsg += ': ' + xhr.responseJSON.message;
}
BootstrapDialog.alert({
title: '<?= __("Error") ?>',
message: errorMsg,
type: BootstrapDialog.TYPE_DANGER
});
}
});
}
function fixState(dxcc) {
$('#fixStateButton').prop("disabled", true).addClass("running");
$.ajax({
url: base_url + 'index.php/logbookadvanced/fixStateBatch',
type: 'post',
data: {
'dxcc': dxcc
},
success: function (response) {
$('#fixStateButton').prop("disabled", false).removeClass("running");
},
error: function () {
$('#fixStateButton').prop("disabled", false).removeClass("running");
}
});
}