From 843e98695fd4a77b8db9c0b497b816320a7402a9 Mon Sep 17 00:00:00 2001 From: phl0 Date: Sat, 31 Jan 2026 10:02:55 +0100 Subject: [PATCH 01/15] Add function to pull all worked grids at once --- application/controllers/Api.php | 65 ++++++++++++++++++++++++++++ application/models/Logbook_model.php | 44 +++++++++++++++++++ 2 files changed, 109 insertions(+) diff --git a/application/controllers/Api.php b/application/controllers/Api.php index 7dcfdf2d4..769f532b1 100644 --- a/application/controllers/Api.php +++ b/application/controllers/Api.php @@ -723,6 +723,71 @@ class API extends CI_Controller { } + // API function to check if a grid is in the logbook already + function logbook_get_worked_grids() { + $arr = array(); + header('Content-type: application/json'); + $this->load->model('api_model'); + $obj = json_decode(file_get_contents("php://input"), true); + if ($obj === NULL) { + echo json_encode(['status' => 'failed', 'reason' => "wrong JSON"]); + } + if(!isset($obj['key']) || $this->api_model->authorize($obj['key']) == 0) { + http_response_code(401); + echo json_encode(['status' => 'failed', 'reason' => "missing api key"]); + } + if(!isset($obj['logbook_public_slug'])) { + http_response_code(401); + echo json_encode(['status' => 'failed', 'reason' => "missing fields"]); + return; + } + if($obj['logbook_public_slug'] != "") { + $logbook_slug = $obj['logbook_public_slug']; + if(isset($obj['band'])) { + $band = $obj['band']; + } else { + $band = null; + } + if(isset($obj['cnfm'])) { + $cnfm = $obj['cnfm']; + } else { + $cnfm = null; + } + $this->load->model('logbooks_model'); + if($this->logbooks_model->public_slug_exists($logbook_slug)) { + $logbook_id = $this->logbooks_model->public_slug_exists_logbook_id($logbook_slug); + if($logbook_id != false) + { + $logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($logbook_id); + if (!$logbooks_locations_array) { + http_response_code(404); + echo json_encode(['status' => 'failed', 'reason' => "Empty Logbook"]); + die(); + } + } else { + http_response_code(404); + echo json_encode(['status' => 'failed', 'reason' => $logbook_slug." has no associated station locations"]); + die(); + } + $this->load->model('logbook_model'); + + $query = $this->logbook_model->get_grids_worked_in_logbook($logbooks_locations_array, $band, $cnfm); + http_response_code(201); + foreach($query->result() as $line) { + $arr[] = $line->gridorcnfm; + } + echo json_encode($arr); + + } else { + http_response_code(404); + echo json_encode(['status' => 'failed', 'reason' => "logbook not found"]); + die(); + } + + } + + } + /* ENDPOINT for Rig Control */ function radio() { diff --git a/application/models/Logbook_model.php b/application/models/Logbook_model.php index 78a6c99fb..a2672794b 100644 --- a/application/models/Logbook_model.php +++ b/application/models/Logbook_model.php @@ -3335,6 +3335,50 @@ class Logbook_model extends CI_Model { return $query; } + function get_grids_worked_in_logbook($StationLocationsArray = null, $band = null, $cnfm = null) { + + if ($StationLocationsArray == null) { + $this->load->model('logbooks_model'); + $logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($this->session->userdata('active_station_logbook')); + } else { + $logbooks_locations_array = $StationLocationsArray; + } + + switch ($cnfm) { + case 'qsl': + $this->db->select('COL_QSL_RCVD as gridorcnfm'); + $this->db->group_by('COL_QSL_RCVD'); + break; + case 'lotw': + $this->db->select('COL_LOTW_QSL_RCVD as gridorcnfm'); + $this->db->group_by('COL_LOTW_QSL_RCVD'); + break; + case 'eqsl': + $this->db->select('COL_EQSL_QSL_RCVD as gridorcnfm'); + $this->db->group_by('COL_EQSL_QSL_RCVD'); + break; + default: + $this->db->select('SUBSTR(COL_GRIDSQUARE,1 ,4) as gridorcnfm'); + $this->db->group_by('gridorcnfm'); + break; + } + $this->db->order_by('gridorcnfm'); + $this->db->where_in('station_id', $logbooks_locations_array); + + $band = ($band == 'All') ? null : $band; + if ($band != null && $band != 'SAT') { + $this->db->where('COL_BAND', $band); + } else if ($band == 'SAT') { + $this->db->where('COL_SAT_NAME !=', ''); + } + $this->db->having('gridorcnfm !=', ''); + $this->db->having('gridorcnfm is not null'); + + $query = $this->db->get($this->config->item('table_name')); + + return $query; + } + /* Get all QSOs with a valid grid for use in the KML export */ function kml_get_all_qsos($band, $mode, $dxcc, $cqz, $propagation, $fromdate, $todate) { $this->load->model('logbooks_model'); From f3d42f8b5147bb1ae264c2dd747c42fc5cf937d7 Mon Sep 17 00:00:00 2001 From: phl0 Date: Thu, 19 Feb 2026 18:30:46 +0100 Subject: [PATCH 02/15] Refactor SQL query --- application/controllers/Api.php | 2 +- application/models/Logbook_model.php | 46 +++++++++++----------------- 2 files changed, 19 insertions(+), 29 deletions(-) diff --git a/application/controllers/Api.php b/application/controllers/Api.php index 769f532b1..aeb01a353 100644 --- a/application/controllers/Api.php +++ b/application/controllers/Api.php @@ -774,7 +774,7 @@ class API extends CI_Controller { $query = $this->logbook_model->get_grids_worked_in_logbook($logbooks_locations_array, $band, $cnfm); http_response_code(201); foreach($query->result() as $line) { - $arr[] = $line->gridorcnfm; + $arr[] = $line->gridsquare; } echo json_encode($arr); diff --git a/application/models/Logbook_model.php b/application/models/Logbook_model.php index a2672794b..7aa6e133e 100644 --- a/application/models/Logbook_model.php +++ b/application/models/Logbook_model.php @@ -3344,38 +3344,28 @@ class Logbook_model extends CI_Model { $logbooks_locations_array = $StationLocationsArray; } - switch ($cnfm) { - case 'qsl': - $this->db->select('COL_QSL_RCVD as gridorcnfm'); - $this->db->group_by('COL_QSL_RCVD'); - break; - case 'lotw': - $this->db->select('COL_LOTW_QSL_RCVD as gridorcnfm'); - $this->db->group_by('COL_LOTW_QSL_RCVD'); - break; - case 'eqsl': - $this->db->select('COL_EQSL_QSL_RCVD as gridorcnfm'); - $this->db->group_by('COL_EQSL_QSL_RCVD'); - break; - default: - $this->db->select('SUBSTR(COL_GRIDSQUARE,1 ,4) as gridorcnfm'); - $this->db->group_by('gridorcnfm'); - break; - } - $this->db->order_by('gridorcnfm'); - $this->db->where_in('station_id', $logbooks_locations_array); - + $bindings = []; + $sql = 'SELECT DISTINCT UPPER(SUBSTR(COL_GRIDSQUARE, 1, 4)) AS gridsquare FROM ' . $this->config->item('table_name') . ' thcv '; + $sql .= ' WHERE COL_GRIDSQUARE <> "" AND station_id IN ('.implode(',', $logbooks_locations_array).')'; $band = ($band == 'All') ? null : $band; if ($band != null && $band != 'SAT') { - $this->db->where('COL_BAND', $band); + $sql .= ' AND COL_BAND = ? AND COL_PROP_MODE != "SAT"'; + $bindings[] = $band; } else if ($band == 'SAT') { - $this->db->where('COL_SAT_NAME !=', ''); + $sql .= ' AND COL_SAT_NAME != ""'; } - $this->db->having('gridorcnfm !=', ''); - $this->db->having('gridorcnfm is not null'); - - $query = $this->db->get($this->config->item('table_name')); - + switch ($cnfm) { + case 'qsl': + $sql .= ' AND COL_QSL_RCVD = "Y"'; + break; + case 'lotw': + $sql .= ' AND COL_LOTW_QSL_RCVD = "Y"'; + break; + case 'eqsl': + $sql .= ' AND COL_EQSL_QSL_RCVD = "Y"'; + break; + } + $query = $this->db->query($sql,$bindings); return $query; } From 0ee751a98d5a1ffead597567a03a7d133edf4c08 Mon Sep 17 00:00:00 2001 From: phl0 Date: Fri, 20 Feb 2026 10:29:28 +0100 Subject: [PATCH 03/15] Order gridsquares --- application/models/Logbook_model.php | 1 + 1 file changed, 1 insertion(+) diff --git a/application/models/Logbook_model.php b/application/models/Logbook_model.php index 7aa6e133e..3dee7f9af 100644 --- a/application/models/Logbook_model.php +++ b/application/models/Logbook_model.php @@ -3365,6 +3365,7 @@ class Logbook_model extends CI_Model { $sql .= ' AND COL_EQSL_QSL_RCVD = "Y"'; break; } + $sql .= ' ORDER BY gridsquare ASC;'; $query = $this->db->query($sql,$bindings); return $query; } From 84d38edac235f27726ee1e152447e469c37ae8d0 Mon Sep 17 00:00:00 2001 From: "Florian (DF2ET)" Date: Fri, 20 Feb 2026 11:30:28 +0100 Subject: [PATCH 04/15] Update application/controllers/Api.php Co-authored-by: Joerg (DJ7NT) --- application/controllers/Api.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/controllers/Api.php b/application/controllers/Api.php index aeb01a353..e3f1c51a7 100644 --- a/application/controllers/Api.php +++ b/application/controllers/Api.php @@ -737,7 +737,7 @@ class API extends CI_Controller { echo json_encode(['status' => 'failed', 'reason' => "missing api key"]); } if(!isset($obj['logbook_public_slug'])) { - http_response_code(401); + http_response_code(400); echo json_encode(['status' => 'failed', 'reason' => "missing fields"]); return; } From 61ac42143bd4414280d90bdd306208cf47f489b0 Mon Sep 17 00:00:00 2001 From: "Florian (DF2ET)" Date: Fri, 20 Feb 2026 11:30:36 +0100 Subject: [PATCH 05/15] Update application/controllers/Api.php Co-authored-by: Joerg (DJ7NT) --- application/controllers/Api.php | 1 + 1 file changed, 1 insertion(+) diff --git a/application/controllers/Api.php b/application/controllers/Api.php index e3f1c51a7..3abb6d03c 100644 --- a/application/controllers/Api.php +++ b/application/controllers/Api.php @@ -731,6 +731,7 @@ class API extends CI_Controller { $obj = json_decode(file_get_contents("php://input"), true); if ($obj === NULL) { echo json_encode(['status' => 'failed', 'reason' => "wrong JSON"]); + die(); } if(!isset($obj['key']) || $this->api_model->authorize($obj['key']) == 0) { http_response_code(401); From b2fbc478ede7ec4d363fde069f8ad7ce21b37f2c Mon Sep 17 00:00:00 2001 From: "Florian (DF2ET)" Date: Fri, 20 Feb 2026 11:30:42 +0100 Subject: [PATCH 06/15] Update application/controllers/Api.php Co-authored-by: Joerg (DJ7NT) --- application/controllers/Api.php | 1 + 1 file changed, 1 insertion(+) diff --git a/application/controllers/Api.php b/application/controllers/Api.php index 3abb6d03c..891e051ca 100644 --- a/application/controllers/Api.php +++ b/application/controllers/Api.php @@ -736,6 +736,7 @@ class API extends CI_Controller { if(!isset($obj['key']) || $this->api_model->authorize($obj['key']) == 0) { http_response_code(401); echo json_encode(['status' => 'failed', 'reason' => "missing api key"]); + die(); } if(!isset($obj['logbook_public_slug'])) { http_response_code(400); From dc7d941e65a6ff051b5f22f2fc524a9ffadd17e6 Mon Sep 17 00:00:00 2001 From: phl0 Date: Fri, 20 Feb 2026 11:36:36 +0100 Subject: [PATCH 07/15] Only use grids with length of at least 4 chars --- application/models/Logbook_model.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/application/models/Logbook_model.php b/application/models/Logbook_model.php index 3dee7f9af..b2c79c9ad 100644 --- a/application/models/Logbook_model.php +++ b/application/models/Logbook_model.php @@ -3346,7 +3346,8 @@ class Logbook_model extends CI_Model { $bindings = []; $sql = 'SELECT DISTINCT UPPER(SUBSTR(COL_GRIDSQUARE, 1, 4)) AS gridsquare FROM ' . $this->config->item('table_name') . ' thcv '; - $sql .= ' WHERE COL_GRIDSQUARE <> "" AND station_id IN ('.implode(',', $logbooks_locations_array).')'; + $sql .= ' WHERE COL_GRIDSQUARE <> "" AND CHAR_LENGTH(COL_GRIDSQUARE) >= 4'; + $sql .= ' AND station_id IN ('.implode(',', $logbooks_locations_array).')'; $band = ($band == 'All') ? null : $band; if ($band != null && $band != 'SAT') { $sql .= ' AND COL_BAND = ? AND COL_PROP_MODE != "SAT"'; From 6d00adf9a3f9f6075ae23ca4b5e640e969ae7734 Mon Sep 17 00:00:00 2001 From: phl0 Date: Fri, 20 Feb 2026 11:45:48 +0100 Subject: [PATCH 08/15] Move to API model --- application/controllers/Api.php | 3 ++- application/models/Api_model.php | 37 ++++++++++++++++++++++++++++ application/models/Logbook_model.php | 36 --------------------------- 3 files changed, 39 insertions(+), 37 deletions(-) diff --git a/application/controllers/Api.php b/application/controllers/Api.php index 891e051ca..0c4acd4ba 100644 --- a/application/controllers/Api.php +++ b/application/controllers/Api.php @@ -756,6 +756,7 @@ class API extends CI_Controller { $cnfm = null; } $this->load->model('logbooks_model'); + $this->load->model('api_model'); if($this->logbooks_model->public_slug_exists($logbook_slug)) { $logbook_id = $this->logbooks_model->public_slug_exists_logbook_id($logbook_slug); if($logbook_id != false) @@ -773,7 +774,7 @@ class API extends CI_Controller { } $this->load->model('logbook_model'); - $query = $this->logbook_model->get_grids_worked_in_logbook($logbooks_locations_array, $band, $cnfm); + $query = $this->api_model->get_grids_worked_in_logbook($logbooks_locations_array, $band, $cnfm); http_response_code(201); foreach($query->result() as $line) { $arr[] = $line->gridsquare; diff --git a/application/models/Api_model.php b/application/models/Api_model.php index b97d4753c..051a0a041 100644 --- a/application/models/Api_model.php +++ b/application/models/Api_model.php @@ -178,5 +178,42 @@ class API_Model extends CI_Model { "; return $this->db->query($sql, $binding); + + } + + function get_grids_worked_in_logbook($StationLocationsArray = null, $band = null, $cnfm = null) { + + if ($StationLocationsArray == null) { + $this->load->model('logbooks_model'); + $logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($this->session->userdata('active_station_logbook')); + } else { + $logbooks_locations_array = $StationLocationsArray; + } + + $bindings = []; + $sql = 'SELECT DISTINCT UPPER(SUBSTR(COL_GRIDSQUARE, 1, 4)) AS gridsquare FROM ' . $this->config->item('table_name') . ' thcv '; + $sql .= ' WHERE COL_GRIDSQUARE <> "" AND CHAR_LENGTH(COL_GRIDSQUARE) >= 4'; + $sql .= ' AND station_id IN ('.implode(',', $logbooks_locations_array).')'; + $band = ($band == 'All') ? null : $band; + if ($band != null && $band != 'SAT') { + $sql .= ' AND COL_BAND = ? AND COL_PROP_MODE != "SAT"'; + $bindings[] = $band; + } else if ($band == 'SAT') { + $sql .= ' AND COL_SAT_NAME != ""'; + } + switch ($cnfm) { + case 'qsl': + $sql .= ' AND COL_QSL_RCVD = "Y"'; + break; + case 'lotw': + $sql .= ' AND COL_LOTW_QSL_RCVD = "Y"'; + break; + case 'eqsl': + $sql .= ' AND COL_EQSL_QSL_RCVD = "Y"'; + break; + } + $sql .= ' ORDER BY gridsquare ASC;'; + $query = $this->db->query($sql,$bindings); + return $query; } } diff --git a/application/models/Logbook_model.php b/application/models/Logbook_model.php index b2c79c9ad..78a6c99fb 100644 --- a/application/models/Logbook_model.php +++ b/application/models/Logbook_model.php @@ -3335,42 +3335,6 @@ class Logbook_model extends CI_Model { return $query; } - function get_grids_worked_in_logbook($StationLocationsArray = null, $band = null, $cnfm = null) { - - if ($StationLocationsArray == null) { - $this->load->model('logbooks_model'); - $logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($this->session->userdata('active_station_logbook')); - } else { - $logbooks_locations_array = $StationLocationsArray; - } - - $bindings = []; - $sql = 'SELECT DISTINCT UPPER(SUBSTR(COL_GRIDSQUARE, 1, 4)) AS gridsquare FROM ' . $this->config->item('table_name') . ' thcv '; - $sql .= ' WHERE COL_GRIDSQUARE <> "" AND CHAR_LENGTH(COL_GRIDSQUARE) >= 4'; - $sql .= ' AND station_id IN ('.implode(',', $logbooks_locations_array).')'; - $band = ($band == 'All') ? null : $band; - if ($band != null && $band != 'SAT') { - $sql .= ' AND COL_BAND = ? AND COL_PROP_MODE != "SAT"'; - $bindings[] = $band; - } else if ($band == 'SAT') { - $sql .= ' AND COL_SAT_NAME != ""'; - } - switch ($cnfm) { - case 'qsl': - $sql .= ' AND COL_QSL_RCVD = "Y"'; - break; - case 'lotw': - $sql .= ' AND COL_LOTW_QSL_RCVD = "Y"'; - break; - case 'eqsl': - $sql .= ' AND COL_EQSL_QSL_RCVD = "Y"'; - break; - } - $sql .= ' ORDER BY gridsquare ASC;'; - $query = $this->db->query($sql,$bindings); - return $query; - } - /* Get all QSOs with a valid grid for use in the KML export */ function kml_get_all_qsos($band, $mode, $dxcc, $cqz, $propagation, $fromdate, $todate) { $this->load->model('logbooks_model'); From cf96ddbad8830b3af9b6a2cc2acf89e6d6c3536e Mon Sep 17 00:00:00 2001 From: phl0 Date: Fri, 20 Feb 2026 11:52:46 +0100 Subject: [PATCH 09/15] Prepare for adding VUCC_GRIDS --- application/controllers/Api.php | 5 +---- application/models/Api_model.php | 9 ++++++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/application/controllers/Api.php b/application/controllers/Api.php index 0c4acd4ba..ddd996010 100644 --- a/application/controllers/Api.php +++ b/application/controllers/Api.php @@ -774,11 +774,8 @@ class API extends CI_Controller { } $this->load->model('logbook_model'); - $query = $this->api_model->get_grids_worked_in_logbook($logbooks_locations_array, $band, $cnfm); + $arr = $this->api_model->get_grids_worked_in_logbook($logbooks_locations_array, $band, $cnfm); http_response_code(201); - foreach($query->result() as $line) { - $arr[] = $line->gridsquare; - } echo json_encode($arr); } else { diff --git a/application/models/Api_model.php b/application/models/Api_model.php index 051a0a041..a35651ff3 100644 --- a/application/models/Api_model.php +++ b/application/models/Api_model.php @@ -182,7 +182,7 @@ class API_Model extends CI_Model { } function get_grids_worked_in_logbook($StationLocationsArray = null, $band = null, $cnfm = null) { - + $grid_array = []; if ($StationLocationsArray == null) { $this->load->model('logbooks_model'); $logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($this->session->userdata('active_station_logbook')); @@ -190,7 +190,7 @@ class API_Model extends CI_Model { $logbooks_locations_array = $StationLocationsArray; } - $bindings = []; + $bindings = []; $sql = 'SELECT DISTINCT UPPER(SUBSTR(COL_GRIDSQUARE, 1, 4)) AS gridsquare FROM ' . $this->config->item('table_name') . ' thcv '; $sql .= ' WHERE COL_GRIDSQUARE <> "" AND CHAR_LENGTH(COL_GRIDSQUARE) >= 4'; $sql .= ' AND station_id IN ('.implode(',', $logbooks_locations_array).')'; @@ -214,6 +214,9 @@ class API_Model extends CI_Model { } $sql .= ' ORDER BY gridsquare ASC;'; $query = $this->db->query($sql,$bindings); - return $query; + foreach($query->result() as $line) { + $grid_array[] = $line->gridsquare; + } + return $grid_array; } } From 76826ce8c560a89f150450e7e240be1e07fdf5d4 Mon Sep 17 00:00:00 2001 From: phl0 Date: Fri, 20 Feb 2026 12:01:52 +0100 Subject: [PATCH 10/15] Prevent double loading of API model --- application/controllers/Api.php | 1 - 1 file changed, 1 deletion(-) diff --git a/application/controllers/Api.php b/application/controllers/Api.php index ddd996010..b221da1ba 100644 --- a/application/controllers/Api.php +++ b/application/controllers/Api.php @@ -756,7 +756,6 @@ class API extends CI_Controller { $cnfm = null; } $this->load->model('logbooks_model'); - $this->load->model('api_model'); if($this->logbooks_model->public_slug_exists($logbook_slug)) { $logbook_id = $this->logbooks_model->public_slug_exists_logbook_id($logbook_slug); if($logbook_id != false) From 2c0f68ece7db62e5ebb983e28e06a4287034ceda Mon Sep 17 00:00:00 2001 From: phl0 Date: Fri, 20 Feb 2026 12:20:30 +0100 Subject: [PATCH 11/15] Add VUCC grids --- application/models/Api_model.php | 58 ++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/application/models/Api_model.php b/application/models/Api_model.php index a35651ff3..d99778f77 100644 --- a/application/models/Api_model.php +++ b/application/models/Api_model.php @@ -190,33 +190,55 @@ class API_Model extends CI_Model { $logbooks_locations_array = $StationLocationsArray; } + $subsql = ''; + $band = ($band == 'All') ? null : $band; + if ($band != null && $band != 'SAT') { + $subsql .= ' AND COL_BAND = ? AND COL_PROP_MODE != "SAT"'; + $bindings[] = $band; + } else if ($band == 'SAT') { + $subsql .= ' AND COL_SAT_NAME != ""'; + } + switch ($cnfm) { + case 'qsl': + $subsql .= ' AND COL_QSL_RCVD = "Y"'; + break; + case 'lotw': + $subsql .= ' AND COL_LOTW_QSL_RCVD = "Y"'; + break; + case 'eqsl': + $subsql .= ' AND COL_EQSL_QSL_RCVD = "Y"'; + break; + } + $bindings = []; $sql = 'SELECT DISTINCT UPPER(SUBSTR(COL_GRIDSQUARE, 1, 4)) AS gridsquare FROM ' . $this->config->item('table_name') . ' thcv '; $sql .= ' WHERE COL_GRIDSQUARE <> "" AND CHAR_LENGTH(COL_GRIDSQUARE) >= 4'; $sql .= ' AND station_id IN ('.implode(',', $logbooks_locations_array).')'; - $band = ($band == 'All') ? null : $band; - if ($band != null && $band != 'SAT') { - $sql .= ' AND COL_BAND = ? AND COL_PROP_MODE != "SAT"'; - $bindings[] = $band; - } else if ($band == 'SAT') { - $sql .= ' AND COL_SAT_NAME != ""'; - } - switch ($cnfm) { - case 'qsl': - $sql .= ' AND COL_QSL_RCVD = "Y"'; - break; - case 'lotw': - $sql .= ' AND COL_LOTW_QSL_RCVD = "Y"'; - break; - case 'eqsl': - $sql .= ' AND COL_EQSL_QSL_RCVD = "Y"'; - break; - } + $sql .= $subsql; $sql .= ' ORDER BY gridsquare ASC;'; $query = $this->db->query($sql,$bindings); foreach($query->result() as $line) { $grid_array[] = $line->gridsquare; } + // Get and add VUCC grids + $sql = 'SELECT DISTINCT UPPER(COL_VUCC_GRIDS) AS vuccgrids FROM ' . $this->config->item('table_name') . ' thcv '; + $sql .= ' WHERE COL_VUCC_GRIDS <> ""'; + $sql .= ' AND station_id IN ('.implode(',', $logbooks_locations_array).')'; + $sql .= $subsql; + $sql .= ' ORDER BY vuccgrids ASC;'; + $query = $this->db->query($sql,$bindings); + foreach($query->result() as $line) { + $vucc_grids = explode(',', $line->vuccgrids); + foreach ($vucc_grids as $vucc_grid) { + if (strlen($vucc_grid) >= 4) { + $grid = substr($vucc_grid, 0, 4); + if (! in_array($grid, $grid_array)) { + $grid_array[] = $grid; + } + } + } + } + asort ($grid_array); return $grid_array; } } From fe95d2d7ed6b4a5d98c49a5d3481eb1320e2ebe6 Mon Sep 17 00:00:00 2001 From: phl0 Date: Fri, 20 Feb 2026 12:22:50 +0100 Subject: [PATCH 12/15] Fix sorting --- application/models/Api_model.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/models/Api_model.php b/application/models/Api_model.php index d99778f77..cbbf22a99 100644 --- a/application/models/Api_model.php +++ b/application/models/Api_model.php @@ -238,7 +238,7 @@ class API_Model extends CI_Model { } } } - asort ($grid_array); + sort ($grid_array); return $grid_array; } } From 1a85fea561494826fa624dccf23276a7f796e915 Mon Sep 17 00:00:00 2001 From: "Florian (DF2ET)" Date: Fri, 20 Feb 2026 12:23:55 +0100 Subject: [PATCH 13/15] Update application/controllers/Api.php Co-authored-by: Joerg (DJ7NT) --- application/controllers/Api.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/application/controllers/Api.php b/application/controllers/Api.php index b221da1ba..d0598d0ed 100644 --- a/application/controllers/Api.php +++ b/application/controllers/Api.php @@ -733,6 +733,10 @@ class API extends CI_Controller { echo json_encode(['status' => 'failed', 'reason' => "wrong JSON"]); die(); } + // Check rate limit + $identifier = isset($obj['key']) ? $obj['key'] : null; + $this->check_rate_limit('logbook_get_worked_grids', $identifier); + if(!isset($obj['key']) || $this->api_model->authorize($obj['key']) == 0) { http_response_code(401); echo json_encode(['status' => 'failed', 'reason' => "missing api key"]); From 3dd4adb55b46dfdf3a0d242b942c80f8e08a6a8e Mon Sep 17 00:00:00 2001 From: phl0 Date: Fri, 20 Feb 2026 12:25:16 +0100 Subject: [PATCH 14/15] Make it more injection safe --- application/models/Api_model.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/application/models/Api_model.php b/application/models/Api_model.php index cbbf22a99..c79ebabb5 100644 --- a/application/models/Api_model.php +++ b/application/models/Api_model.php @@ -211,9 +211,10 @@ class API_Model extends CI_Model { } $bindings = []; + $ids = array_map('intval', $logbooks_locations_array); $sql = 'SELECT DISTINCT UPPER(SUBSTR(COL_GRIDSQUARE, 1, 4)) AS gridsquare FROM ' . $this->config->item('table_name') . ' thcv '; $sql .= ' WHERE COL_GRIDSQUARE <> "" AND CHAR_LENGTH(COL_GRIDSQUARE) >= 4'; - $sql .= ' AND station_id IN ('.implode(',', $logbooks_locations_array).')'; + $sql .= ' AND station_id IN (' . implode(',', $ids) . ')'; $sql .= $subsql; $sql .= ' ORDER BY gridsquare ASC;'; $query = $this->db->query($sql,$bindings); @@ -223,7 +224,7 @@ class API_Model extends CI_Model { // Get and add VUCC grids $sql = 'SELECT DISTINCT UPPER(COL_VUCC_GRIDS) AS vuccgrids FROM ' . $this->config->item('table_name') . ' thcv '; $sql .= ' WHERE COL_VUCC_GRIDS <> ""'; - $sql .= ' AND station_id IN ('.implode(',', $logbooks_locations_array).')'; + $sql .= ' AND station_id IN (' . implode(',', $ids) . ')'; $sql .= $subsql; $sql .= ' ORDER BY vuccgrids ASC;'; $query = $this->db->query($sql,$bindings); From 82a1fdfa502cf1c71eea57a23f200b788b3ec279 Mon Sep 17 00:00:00 2001 From: phl0 Date: Fri, 20 Feb 2026 12:37:44 +0100 Subject: [PATCH 15/15] Put bindings to the right place --- application/models/Api_model.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/models/Api_model.php b/application/models/Api_model.php index c79ebabb5..eda1493dc 100644 --- a/application/models/Api_model.php +++ b/application/models/Api_model.php @@ -190,6 +190,7 @@ class API_Model extends CI_Model { $logbooks_locations_array = $StationLocationsArray; } + $bindings = []; $subsql = ''; $band = ($band == 'All') ? null : $band; if ($band != null && $band != 'SAT') { @@ -210,7 +211,6 @@ class API_Model extends CI_Model { break; } - $bindings = []; $ids = array_map('intval', $logbooks_locations_array); $sql = 'SELECT DISTINCT UPPER(SUBSTR(COL_GRIDSQUARE, 1, 4)) AS gridsquare FROM ' . $this->config->item('table_name') . ' thcv '; $sql .= ' WHERE COL_GRIDSQUARE <> "" AND CHAR_LENGTH(COL_GRIDSQUARE) >= 4';