From 0ba4c8bd9c9422191cd45439c988985e8198d998 Mon Sep 17 00:00:00 2001 From: Andreas Kristiansen <6977712+AndreasK79@users.noreply.github.com> Date: Sat, 18 Oct 2025 19:36:17 +0200 Subject: [PATCH] [Gridmap] Added country grids --- application/config/migration.php | 2 +- application/controllers/Gridmap.php | 13 +++- application/controllers/Update.php | 5 ++ .../migrations/261_add_grid_country.php | 36 +++++++++ application/models/Gridmap_model.php | 73 ++++++++++++------- application/models/Update_model.php | 43 +++++++++++ application/views/gridmap/index.php | 12 +++ .../js/leaflet/L.MaidenheadColouredGridMap.js | 25 ++++--- assets/js/sections/gridmap.js | 46 ++++++++---- 9 files changed, 200 insertions(+), 55 deletions(-) create mode 100644 application/migrations/261_add_grid_country.php diff --git a/application/config/migration.php b/application/config/migration.php index 799667887..30ec72cee 100644 --- a/application/config/migration.php +++ b/application/config/migration.php @@ -22,7 +22,7 @@ $config['migration_enabled'] = TRUE; | */ -$config['migration_version'] = 260; +$config['migration_version'] = 261; /* |-------------------------------------------------------------------------- diff --git a/application/controllers/Gridmap.php b/application/controllers/Gridmap.php index 4343b87b2..6aaffe088 100644 --- a/application/controllers/Gridmap.php +++ b/application/controllers/Gridmap.php @@ -20,6 +20,7 @@ class Gridmap extends CI_Controller { $data['bands'] = $this->bands->get_worked_bands(); $data['orbits'] = $this->bands->get_worked_orbits(); $data['sats_available'] = $this->bands->get_worked_sats(); + $data['countries'] = $this->gridmap_model->get_countries(); $data['user_default_band'] = $this->session->userdata('user_default_band'); $data['user_default_confirmation'] = $this->session->userdata('user_default_confirmation'); @@ -60,8 +61,12 @@ class Gridmap extends CI_Controller { $sat = $this->input->post('sat', TRUE); $orbit = $this->input->post('orbit', TRUE); $propagation = $this->input->post('propagation', TRUE); + $dxcc = $this->input->post('dxcc', TRUE); $this->load->model('gridmap_model'); + $data['grids'] = $this->gridmap_model->get_grids_for_country($dxcc); + $data['grid_count'] = count($data['grids']); + $array_grid_2char = array(); $array_grid_4char = array(); $array_grid_6char = array(); @@ -78,7 +83,7 @@ class Gridmap extends CI_Controller { $grid_4char_confirmed = ""; $grid_6char_confirmed = ""; - $query = $this->gridmap_model->get_band_confirmed($band, $mode, $qsl, $lotw, $eqsl, $qrz, $sat, $orbit, $propagation); + $query = $this->gridmap_model->get_band_confirmed($band, $mode, $qsl, $lotw, $eqsl, $qrz, $sat, $orbit, $propagation, $dxcc); if ($query && $query->num_rows() > 0) { foreach ($query->result() as $row) { @@ -105,7 +110,7 @@ class Gridmap extends CI_Controller { } } - $query = $this->gridmap_model->get_band($band, $mode, $qsl, $lotw, $eqsl, $qrz, $sat, $orbit, $propagation); + $query = $this->gridmap_model->get_band($band, $mode, $qsl, $lotw, $eqsl, $qrz, $sat, $orbit, $propagation, $dxcc); if ($query && $query->num_rows() > 0) { foreach ($query->result() as $row) { @@ -132,7 +137,7 @@ class Gridmap extends CI_Controller { } } } - $query_vucc = $this->gridmap_model->get_band_worked_vucc_squares($band, $mode, $qsl, $lotw, $eqsl, $qrz, $sat, $orbit, $propagation); + $query_vucc = $this->gridmap_model->get_band_worked_vucc_squares($band, $mode, $qsl, $lotw, $eqsl, $qrz, $sat, $orbit, $propagation, $dxcc); if ($query_vucc && $query_vucc->num_rows() > 0) { foreach ($query_vucc->result() as $row) { @@ -157,7 +162,7 @@ class Gridmap extends CI_Controller { } // // Confirmed Squares - $query_vucc = $this->gridmap_model->get_band_confirmed_vucc_squares($band, $mode, $qsl, $lotw, $eqsl, $qrz, $sat, $orbit, $propagation); + $query_vucc = $this->gridmap_model->get_band_confirmed_vucc_squares($band, $mode, $qsl, $lotw, $eqsl, $qrz, $sat, $orbit, $propagation, $dxcc); if ($query_vucc && $query_vucc->num_rows() > 0) { foreach ($query_vucc->result() as $row) { diff --git a/application/controllers/Update.php b/application/controllers/Update.php index ca7ebf33d..ac54c9cef 100644 --- a/application/controllers/Update.php +++ b/application/controllers/Update.php @@ -704,5 +704,10 @@ class Update extends CI_Controller { $this->load->model('Update_model'); $this->Update_model->update_check(); } + + public function update_vucc_grids() { + $this->load->model('Update_model'); + $this->Update_model->update_vucc_grids(); + } } ?> diff --git a/application/migrations/261_add_grid_country.php b/application/migrations/261_add_grid_country.php new file mode 100644 index 000000000..7e1dd60e4 --- /dev/null +++ b/application/migrations/261_add_grid_country.php @@ -0,0 +1,36 @@ +dbtry($sql); + } + + public function down() + { + $sql = "DROP TABLE IF EXISTS vuccgrids;"; + $this->dbtry($sql); + } + + function dbtry($what) { + try { + $this->db->query($what); + } catch (Exception $e) { + log_message("error", "Something gone wrong while altering a table: ".$e." // Executing: ".$this->db->last_query()); + } + } +} diff --git a/application/models/Gridmap_model.php b/application/models/Gridmap_model.php index f8ef605d4..4d412a426 100644 --- a/application/models/Gridmap_model.php +++ b/application/models/Gridmap_model.php @@ -2,11 +2,9 @@ class Gridmap_model extends CI_Model { - function get_band_confirmed($band, $mode, $qsl, $lotw, $eqsl, $qrz, $sat, $orbit, $propagation, $logbooks_locations_array = NULL) { - if ($logbooks_locations_array == NULL) { - $this->load->model('logbooks_model'); - $logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($this->session->userdata('active_station_logbook')); - } + function get_band_confirmed($band, $mode, $qsl, $lotw, $eqsl, $qrz, $sat, $orbit, $propagation, $dxcc) { + $this->load->model('logbooks_model'); + $logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($this->session->userdata('active_station_logbook')); if (!$logbooks_locations_array) { return null; @@ -63,17 +61,24 @@ class Gridmap_model extends CI_Model { $binding[] = $orbit; } + if ($dxcc != 'All') { + $gridsql = 'select gridsquare from vuccgrids where adif = ?'; + $gridquery = $this->db->query($gridsql, array($dxcc)); + $gridarray = array_column($gridquery->result_array(), 'gridsquare'); // ✅ extract values + + if (!empty($gridarray)) { + $sql .= ' AND substring(COL_GRIDSQUARE,1,4) IN (\'' . implode("','", $gridarray) . '\')'; + } + } + $sql .= $this->addQslToQuery($qsl, $lotw, $eqsl, $qrz); return $this->db->query($sql, $binding); } - function get_band($band, $mode, $qsl, $lotw, $eqsl, $qrz, $sat, $orbit, $propagation, $logbooks_locations_array = NULL) { - if ($logbooks_locations_array == NULL) { - - $this->load->model('logbooks_model'); - $logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($this->session->userdata('active_station_logbook')); - } + function get_band($band, $mode, $qsl, $lotw, $eqsl, $qrz, $sat, $orbit, $propagation, $dxcc) { + $this->load->model('logbooks_model'); + $logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($this->session->userdata('active_station_logbook')); if (!$logbooks_locations_array) { return null; @@ -130,15 +135,22 @@ class Gridmap_model extends CI_Model { $binding[] = $orbit; } + if ($dxcc != 'All') { + $gridsql = 'select gridsquare from vuccgrids where adif = ?'; + $gridquery = $this->db->query($gridsql, array($dxcc)); + $gridarray = array_column($gridquery->result_array(), 'gridsquare'); // ✅ extract values + + if (!empty($gridarray)) { + $sql .= ' AND substring(COL_GRIDSQUARE,1,4) IN (\'' . implode("','", $gridarray) . '\')'; + } + } + return $this->db->query($sql, $binding); } - function get_band_worked_vucc_squares($band, $mode, $qsl, $lotw, $eqsl, $qrz, $sat, $orbit, $propagation, $logbooks_locations_array = NULL) { - if ($logbooks_locations_array == NULL) { - - $this->load->model('logbooks_model'); - $logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($this->session->userdata('active_station_logbook')); - } + function get_band_worked_vucc_squares($band, $mode, $qsl, $lotw, $eqsl, $qrz, $sat, $orbit, $propagation, $dxcc) { + $this->load->model('logbooks_model'); + $logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($this->session->userdata('active_station_logbook')); if (!$logbooks_locations_array) { return null; @@ -198,18 +210,14 @@ class Gridmap_model extends CI_Model { return $this->db->query($sql, $binding); } - function get_band_confirmed_vucc_squares($band, $mode, $qsl, $lotw, $eqsl, $qrz, $sat, $orbit, $propagation, $logbooks_locations_array = NULL) { - if ($logbooks_locations_array == NULL) { - - $this->load->model('logbooks_model'); - $logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($this->session->userdata('active_station_logbook')); - } + function get_band_confirmed_vucc_squares($band, $mode, $qsl, $lotw, $eqsl, $qrz, $sat, $orbit, $propagation, $dxcc) { + $this->load->model('logbooks_model'); + $logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($this->session->userdata('active_station_logbook')); if (!$logbooks_locations_array) { return null; } - $location_list = "'".implode("','",$logbooks_locations_array)."'"; $binding = []; @@ -300,7 +308,7 @@ class Gridmap_model extends CI_Model { * Get's the worked modes from the log */ function get_worked_modes() { - + $this->load->model('logbooks_model'); $logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($this->session->userdata('active_station_logbook')); @@ -331,4 +339,19 @@ class Gridmap_model extends CI_Model { return $results; } + + function get_countries() { + $sql = 'SELECT distinct vuccgrids.adif, dxcc_entities.name, dxcc_entities.prefix from vuccgrids join dxcc_entities on vuccgrids.adif = dxcc_entities.adif + where name is not null and name != "" order by prefix'; + + return $this->db->query($sql); + } + + function get_grids_for_country($dxcc) { + $gridsql = 'select gridsquare from vuccgrids where adif = ?'; + $gridquery = $this->db->query($gridsql, array($dxcc)); + $gridarray = array_column($gridquery->result_array(), 'gridsquare'); + + return $gridarray; + } } diff --git a/application/models/Update_model.php b/application/models/Update_model.php index 28ff993ca..4ed0ce838 100644 --- a/application/models/Update_model.php +++ b/application/models/Update_model.php @@ -625,4 +625,47 @@ class Update_model extends CI_Model { return $result; } + function update_vucc_grids() { + // set the last run in cron table for the correct cron id + $this->load->model('cron_model'); + $this->cron_model->set_last_run($this->router->class . '_' . $this->router->method); + + // $url = 'https://sourceforge.net/p/trustedqsl/tqsl/ci/master/plain/apps/vuccgrids.dat'; + $url = 'https://sourceforge.net/p/trustedqsl/tqsl/ci/master/tree/apps/vuccgrids.dat?format=raw'; + $curl = curl_init($url); + + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); + + $response = curl_exec($curl); + + $xml = @simplexml_load_string($response); + + if ($xml === false) { + die("Failed to parse XML."); + } + + // Truncate the table first + $this->db->query("TRUNCATE TABLE vuccgrids;"); + + // Loop through elements + foreach ($xml->vucc as $vucc) { + $adif = (int)$vucc['entity']; // assuming "entity" attribute is ADIF + $grid = strtoupper(trim((string)$vucc['grid'])); + + if ($adif > 0 && $grid !== '') { + // Insert with duplicate handling + $sql = "INSERT INTO vuccgrids (adif, gridsquare) + VALUES (?, ?) + ON DUPLICATE KEY UPDATE id = id"; + + $this->db->query($sql, [$adif, $grid]); + } + } + + curl_close($curl); + + return; + } + } diff --git a/application/views/gridmap/index.php b/application/views/gridmap/index.php index 92627dd1a..968011082 100644 --- a/application/views/gridmap/index.php +++ b/application/views/gridmap/index.php @@ -108,6 +108,18 @@ ?> + result()) > 0) { ?> + +
+ +
+
diff --git a/assets/js/leaflet/L.MaidenheadColouredGridMap.js b/assets/js/leaflet/L.MaidenheadColouredGridMap.js index 4ebf6fc2f..51fc3b175 100644 --- a/assets/js/leaflet/L.MaidenheadColouredGridMap.js +++ b/assets/js/leaflet/L.MaidenheadColouredGridMap.js @@ -86,13 +86,22 @@ L.Maidenhead = L.LayerGroup.extend({ this.addLayer(L.rectangle(bounds, {className: 'grid-rectangle', color: this.options.color, weight: 1, fill:false, interactive: false})); } } else { - if (zoom < 3 || zoom > 5) { - this.addLayer(L.rectangle(bounds, {className: 'grid-rectangle', color: this.options.color, weight: 1, fill:false, interactive: false})); + if (grids.includes(locator) && grids !== '') { + var rect = L.rectangle(bounds, {className: 'grid-rectangle grid-unworked', color: 'rgba(0,0,0, 0.3)', weight: 1, fillOpacity: 0.15, fill:true, interactive: false}); + this.addLayer(rect); + this.addLayer(this._getLabel(lon+unit-(unit/lcor),lat+(unit/2)+(unit/lcor*c))); + } + if (grids == '') { + if (zoom < 3 || zoom > 5) { // Controls if grid lines are shown according to zoom level + this.addLayer(L.rectangle(bounds, {className: 'grid-rectangle', color: this.options.color, weight: 1, fill:false, interactive: false})); + } } } // This one shows all grids, not just the worked/confirmed - if (zoom < 3 || zoom > 5) { - this.addLayer(this._getLabel(lon+unit-(unit/lcor),lat+(unit/2)+(unit/lcor*c))); + if (grids == '') { + if (zoom < 3 || zoom > 5) { + this.addLayer(this._getLabel(lon+unit-(unit/lcor),lat+(unit/2)+(unit/lcor*c))); + } } } } @@ -134,6 +143,7 @@ L.Maidenhead = L.LayerGroup.extend({ } else { title = '' + locator + ''; } + } var myIcon = L.divIcon({className: 'my-div-icon', html: title}); var marker = L.marker([lat,lon], {icon: myIcon}, clickable=false); @@ -183,12 +193,7 @@ L.Maidenhead = L.LayerGroup.extend({ var title_size = new Array(0, 10, 12, 16, 20, 26, 26, 16, 24, 36, 12, 14, 20, 36, 60, 12, 20, 36, 60, 12, 24); var zoom = map.getZoom(); var size = title_size[zoom]+'px'; - if(grid_four.includes(locator) || grid_four_confirmed.includes(locator) || grid_two.includes(locator) || grid_two_confirmed.includes(locator)) { - var title = '' + this._getLocator2(lon,lat) + ''; - } else { - var title = '' + this._getLocator2(lon,lat) + ''; - } - + var title = '' + this._getLocator2(lon,lat) + ''; var myIcon = L.divIcon({className: 'my-div-icon', html: title}); var marker = L.marker([lat,lon], {icon: myIcon}, clickable=false); return marker; diff --git a/assets/js/sections/gridmap.js b/assets/js/sections/gridmap.js index f4a2304f6..08d8b163d 100644 --- a/assets/js/sections/gridmap.js +++ b/assets/js/sections/gridmap.js @@ -79,7 +79,8 @@ function gridPlot(form, visitor=true) { qrz: $("#qrz").is(":checked"), sat: $("#sat").val(), orbit: $("#orbits").val(), - propagation: $('#propagation').val() + propagation: $('#propagation').val(), + dxcc: $('#dxcc').val(), }, success: function (data) { $('.cohidden').show(); @@ -93,7 +94,9 @@ function gridPlot(form, visitor=true) { grid_two_confirmed = data.grid_2char_confirmed; grid_four_confirmed = data.grid_4char_confirmed; grid_six_confirmed = data.grid_6char_confirmed; - plot(visitor, grid_two, grid_four, grid_six, grid_two_confirmed, grid_four_confirmed, grid_six_confirmed); + grids = data.grids; + grid_max = data.grid_count; + plot(visitor, grid_two, grid_four, grid_six, grid_two_confirmed, grid_four_confirmed, grid_six_confirmed, grids, grid_max); }, error: function (data) { @@ -104,7 +107,7 @@ function gridPlot(form, visitor=true) { }; } -function plot(visitor, grid_two, grid_four, grid_six, grid_two_confirmed, grid_four_confirmed, grid_six_confirmed) { +function plot(visitor, grid_two, grid_four, grid_six, grid_two_confirmed, grid_four_confirmed, grid_six_confirmed, grids, grid_max) { var layer = L.tileLayer(jslayer, { maxZoom: 12, attribution: jsattribution, @@ -135,18 +138,31 @@ function plot(visitor, grid_two, grid_four, grid_six, grid_two_confirmed, grid_f /*Legend specific*/ var legend = L.control({ position: "topright" }); - legend.onAdd = function(map) { - var div = L.DomUtil.create("div", "legend"); - div.innerHTML += "

" + gridsquares_gridsquares + "

"; - div.innerHTML += '' + gridsquares_gridsquares_confirmed + ' ('+grid_four_confirmed.length+')
'; - div.innerHTML += '' + gridsquares_gridsquares_not_confirmed + ' ('+(grid_four.length - grid_four_confirmed.length)+')
'; - div.innerHTML += '' + gridsquares_gridsquares_total_worked + ' ('+grid_four.length+')
'; - div.innerHTML += "

" + gridsquares_fields + "

"; - div.innerHTML += '' + gridsquares_fields_confirmed + ' ('+grid_two_confirmed.length+')
'; - div.innerHTML += '' + gridsquares_fields_not_confirmed + ' ('+(grid_two.length - grid_two_confirmed.length)+')
'; - div.innerHTML += '' + gridsquares_fields_total_worked + ' ('+grid_two.length+')
'; - return div; - }; + if (grids != '') { + legend.onAdd = function(map) { + let div = L.DomUtil.create("div", "legend"); + html = ""; + html += '' + gridsquares_gridsquares_confirmed + ' ('+grid_four_confirmed.length+')
'; + html += '' + gridsquares_gridsquares_not_confirmed + ' ('+(grid_four.length - grid_four_confirmed.length)+')
'; + html += ''; + html += "
' + gridsquares_gridsquares_total_worked + ' ('+(Math.round((grid_four.length / grid_max) * 10000) / 100)+'%):'+(grid_four.length)+' / '+grid_max+'
"; + div.innerHTML = html; + return div; + }; + } else { + legend.onAdd = function(map) { + let div = L.DomUtil.create("div", "legend"); + div.innerHTML += "

" + gridsquares_gridsquares + "

"; + div.innerHTML += '' + gridsquares_gridsquares_confirmed + ' ('+grid_four_confirmed.length+')
'; + div.innerHTML += '' + gridsquares_gridsquares_not_confirmed + ' ('+(grid_four.length - grid_four_confirmed.length)+')
'; + div.innerHTML += '' + gridsquares_gridsquares_total_worked + ' ('+grid_four.length+')
'; + div.innerHTML += "

Fields

"; + div.innerHTML += 'Fields confirmed ('+grid_two_confirmed.length+')
'; + div.innerHTML += 'Fields not confirmed ('+(grid_two.length - grid_two_confirmed.length)+')
'; + div.innerHTML += 'Total fields worked ('+grid_two.length+')
'; + return div; + }; + } legend.addTo(map);