From be4b34feec9af7044765ddecfcf6a28c115f6d7e Mon Sep 17 00:00:00 2001 From: Peter Goodhall Date: Tue, 24 Jun 2025 15:24:20 +0100 Subject: [PATCH 01/15] [API] Adds logbook_check_country call --- application/controllers/Api.php | 175 ++++++++++++++++++++++++++++++++ 1 file changed, 175 insertions(+) diff --git a/application/controllers/Api.php b/application/controllers/Api.php index 7bb18b5a..3cc8bb03 100644 --- a/application/controllers/Api.php +++ b/application/controllers/Api.php @@ -427,6 +427,181 @@ class API extends CI_Controller { } + + /** + * Check if a country has been worked before and confirmed in various ways + * + * This API endpoint checks if a specific country (derived from callsign) has been + * worked before in a given logbook, and whether it has been confirmed via different + * confirmation methods (QSL, LoTW, eQSL, QRZ). + * + * @api POST /api/logbook_check_country + * @header Content-Type application/json + * + * @param string key Required. API authentication key + * @param string logbook_public_slug Required. Public slug identifier for the logbook + * @param string callsign Required. Callsign to lookup country for + * @param string type Optional. Type of contact ("sat" for satellite, empty for regular) + * @param string band Optional. Amateur radio band (required for non-satellite contacts) + * @param string mode Optional. Amateur radio mode (required for non-satellite contacts) + * + * @return json Returns JSON object with: + * - workedBefore: boolean indicating if country was worked before + * - confirmed: object with confirmation status for qsl, lotw, eqsl, qrz + * + * @throws 401 Unauthorized - Missing or invalid API key, missing required fields + * @throws 404 Not Found - Logbook not found or empty logbook + * @throws 400 Bad Request - Invalid JSON format + * + * @example + * Request: + * { + * "key": "your-api-key", + * "logbook_public_slug": "my-logbook", + * "callsign": "W1AW", + * "band": "20M", + * "mode": "SSB" + * } + * + * Response: + * { + * "workedBefore": true, + * "confirmed": { + * "qsl": true, + * "lotw": false, + * "eqsl": false, + * "qrz": false + * } + * } + */ + function logbook_check_country() + { + header('Content-type: application/json'); + + $this->load->model('api_model'); + + // Decode JSON and store + $obj = json_decode(file_get_contents("php://input"), true); + if ($obj === NULL) { + echo json_encode(['status' => 'failed', 'reason' => "wrong JSON"]); + return; + } + + if(!isset($obj['key']) || $this->api_model->authorize($obj['key']) == 0) { + http_response_code(401); + echo json_encode(['status' => 'failed', 'reason' => "missing api key"]); + return; + } + + if(!isset($obj['logbook_public_slug']) || !isset($obj['callsign'])) { + http_response_code(401); + echo json_encode(['status' => 'failed', 'reason' => "missing fields"]); + return; + } + + // Load models + $this->load->model('logbook_model'); + $this->load->model('logbooks_model'); + + $date = date("Y-m-d"); + $callsign = $obj['callsign']; + $logbook_slug = $obj['logbook_public_slug']; + $type = isset($obj['type']) ? $obj['type'] : ''; + $band = isset($obj['band']) ? $obj['band'] : ''; + $mode = isset($obj['mode']) ? $obj['mode'] : ''; + + $callsign_dxcc_lookup = $this->logbook_model->dxcc_lookup($callsign, $date); + $country = $callsign_dxcc_lookup['entity']; + + $return = [ + "workedBefore" => false, + "confirmed" => [ + "qsl" => false, + "lotw" => false, + "eqsl" => false, + "qrz" => false + ] + ]; + + 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) + { + // Get associated station locations for mysql queries + $logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($logbook_id); + + if (!$logbooks_locations_array) { + // Logbook not found + http_response_code(404); + echo json_encode(['status' => 'failed', 'reason' => "Empty Logbook"]); + die(); + } + } else { + // Logbook not found + http_response_code(404); + echo json_encode(['status' => 'failed', 'reason' => $logbook_slug." has no associated station locations"]); + die(); + } + + if (!empty($logbooks_locations_array)) { + if ($type == "sat") { + $this->db->where('COL_PROP_MODE', 'SAT'); + } else { + $this->db->where('COL_MODE', $this->logbook_model->get_main_mode_from_mode($mode)); + $this->db->where('COL_BAND', $band); + $this->db->where('COL_PROP_MODE !=', 'SAT'); + } + + $this->db->where_in('station_id', $logbooks_locations_array); + $this->db->where('COL_COUNTRY', urldecode($country)); + + $query = $this->db->get($this->config->item('table_name'), 1, 0); + foreach ($query->result() as $workedBeforeRow) { + $return['workedBefore'] = true; + } + + // Check each confirmation type separately + $confirmation_types = [ + 'qsl' => "COL_QSL_RCVD='Y'", + 'lotw' => "COL_LOTW_QSL_RCVD='Y'", + 'eqsl' => "COL_EQSL_QSL_RCVD='Y'", + 'qrz' => "COL_QRZCOM_QSO_DOWNLOAD_STATUS='Y'" + ]; + + foreach ($confirmation_types as $type_key => $where_clause) { + if ($type == "SAT") { + $this->db->where('COL_PROP_MODE', 'SAT'); + } else { + $this->db->where('COL_MODE', $this->logbook_model->get_main_mode_from_mode($mode)); + $this->db->where('COL_BAND', $band); + $this->db->where('COL_PROP_MODE !=', 'SAT'); + } + + $this->db->where_in('station_id', $logbooks_locations_array); + $this->db->where('COL_COUNTRY', urldecode($country)); + $this->db->where($where_clause); + + $query = $this->db->get($this->config->item('table_name'), 1, 0); + + if ($query->num_rows() > 0) { + $return['confirmed'][$type_key] = true; + } + } + + http_response_code(201); + echo json_encode($return, JSON_PRETTY_PRINT); + } else { + http_response_code(201); + echo json_encode($return, JSON_PRETTY_PRINT); + } + } else { + // Logbook not found + http_response_code(404); + echo json_encode(['status' => 'failed', 'reason' => "logbook not found"]); + die(); + } + } + /* ENDPOINT for Rig Control */ function radio() { From bf43158f7e211cb2e4f8c65bfe9e159bfb9bc7be Mon Sep 17 00:00:00 2001 From: Rodrigo Freire Date: Thu, 10 Jul 2025 23:23:23 -0300 Subject: [PATCH 02/15] DXCC database: Fix Brazilian data There's a number of issues in Brazilian DXCC entities, namely: - Misspeled state names - Wrong time zone - Wrong ITU zone - Wrong callsign assignment plan This commit addresses these issues, while allowing for a full reversion of the old data, by using UPDATE statements, changing the database to a minimum and being as safe as possible. --- application/config/migration.php | 2 +- .../migrations/200_fix_brazil_dxcc_data.php | 68 +++++++++++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 application/migrations/200_fix_brazil_dxcc_data.php diff --git a/application/config/migration.php b/application/config/migration.php index 2eb36735..39ced0cf 100644 --- a/application/config/migration.php +++ b/application/config/migration.php @@ -22,7 +22,7 @@ $config['migration_enabled'] = TRUE; | */ -$config['migration_version'] = 199; +$config['migration_version'] = 200; /* |-------------------------------------------------------------------------- diff --git a/application/migrations/200_fix_brazil_dxcc_data.php b/application/migrations/200_fix_brazil_dxcc_data.php new file mode 100644 index 00000000..c8b25e77 --- /dev/null +++ b/application/migrations/200_fix_brazil_dxcc_data.php @@ -0,0 +1,68 @@ +db->query("UPDATE `dxcc_master` SET TimeZone = 3 WHERE CountryCode = 108 AND DXCCSort = 1;"); + $this->db->query("UPDATE `dxcc_master` SET TimeZone = 3, ITUZone = 15, PrefixList = 'PP1, PU1[A-I], ZV1[A-I], ZW1[A-I], ZX1[A-I], ZY1[A-I], ZZ1[A-I]', location = 'Espirito Santo ' WHERE CountryCode = 108 AND DXCCSort = 12;"); + $this->db->query("UPDATE `dxcc_master` SET TimeZone = 3, ITUZone = 13, PrefixList = 'PP2, PU2[F-H], Z[V-Z]2F, Z[V-Z]2G, Z[V-Z]2H', location = 'Goias ' WHERE CountryCode = 108 AND DXCCSort = 22;"); + $this->db->query("UPDATE `dxcc_master` SET TimeZone = 3, ITUZone = 15, PrefixList = 'PP5, PU5[A-L], ZV5[A-L], ZW5[A-L], ZX5[A-L], ZY5[A-L], ZZ5[A-L]', location = 'Santa Catarina ' WHERE CountryCode = 108 AND DXCCSort = 52;"); + $this->db->query("UPDATE `dxcc_master` SET TimeZone = 3, ITUZone = 13, PrefixList = 'PP6, PU6[A-I], ZV6[A-I], ZW6[A-I], ZX6[A-I], ZY6[A-I], ZZ6[A-I]', location = 'Sergipe ' WHERE CountryCode = 108 AND DXCCSort = 62;"); + $this->db->query("UPDATE `dxcc_master` SET TimeZone = 3, ITUZone = 13, PrefixList = 'PP7, PU7[A-D], Z[V-Z]7A, Z[V-Z]7B, Z[V-Z]7C, Z[V-Z]7D', location = 'Alagoas ' WHERE CountryCode = 108 AND DXCCSort = 72;"); + $this->db->query("UPDATE `dxcc_master` SET TimeZone = 4, ITUZone = 13, PrefixList = 'PP8, PU8[A-C], Z[V-Z]8A, Z[V-Z]8B, Z[V-Z]8C', location = 'Amazonas ' WHERE CountryCode = 108 AND DXCCSort = 82;"); + $this->db->query("UPDATE `dxcc_master` SET TimeZone = 3, ITUZone = 13, PrefixList = 'PQ2, PU2[I-J], Z[V-Z]2I, Z[V-Z]2J', location = 'Tocantins ' WHERE CountryCode = 108 AND DXCCSort = 23;"); + $this->db->query("UPDATE `dxcc_master` SET TimeZone = 3, ITUZone = 13, PrefixList = 'PQ8, PU8[G-I], Z[V-Z]8G, Z[V-Z]8H, Z[V-Z]8I', location = 'Amapa ' WHERE CountryCode = 108 AND DXCCSort = 83;"); + $this->db->query("UPDATE `dxcc_master` SET TimeZone = 3, ITUZone = 13, PrefixList = 'PR7, PU7[E-H], Z[V-Z]7E, Z[V-Z]7F, Z[V-Z]7G, Z[V-Z]7H', location = 'Paraiba ' WHERE CountryCode = 108 AND DXCCSort = 73;"); + $this->db->query("UPDATE `dxcc_master` SET TimeZone = 3, ITUZone = 13, PrefixList = 'PR8, PU8[M-O], Z[V-Z]8M, Z[V-Z]8N, Z[V-Z]8O', location = 'Maranhao ' WHERE CountryCode = 108 AND DXCCSort = 84;"); + $this->db->query("UPDATE `dxcc_master` SET TimeZone = 3, ITUZone = 13, PrefixList = 'PS7, PU7[I-L], Z[V-Z]7I, Z[V-Z]7J, Z[V-Z]7K, Z[V-Z]7L', location = 'Rio Grande do Norte ' WHERE CountryCode = 108 AND DXCCSort = 74;"); + $this->db->query("UPDATE `dxcc_master` SET TimeZone = 3, ITUZone = 13, PrefixList = 'PS8, PU8[P-S], Z[V-Z]8P, Z[V-Z]8Q, Z[V-Z]8R, Z[V-Z]8S', location = 'Piaui ' WHERE CountryCode = 108 AND DXCCSort = 85;"); + $this->db->query("UPDATE `dxcc_master` SET TimeZone = 3, ITUZone = 13, PrefixList = 'PT2, PU2[A-E], Z[V-Z]2A, Z[V-Z]2B, Z[V-Z]2C, Z[V-Z]2D, Z[V-Z]2E', location = 'Brasilia ' WHERE CountryCode = 108 AND DXCCSort = 24;"); + $this->db->query("UPDATE `dxcc_master` SET TimeZone = 3, ITUZone = 13, PrefixList = 'PT7, PU7[M-P], Z[V-Z]7M, Z[V-Z]7N, Z[V-Z]7O, Z[V-Z]7P', location = 'Ceara ' WHERE CountryCode = 108 AND DXCCSort = 75;"); + $this->db->query("UPDATE `dxcc_master` SET TimeZone = 5, ITUZone = 12, PrefixList = 'PT8, PU8[J-L], Z[V-Z]8J, Z[V-Z]8K, Z[V-Z]8L', location = 'Acre ' WHERE CountryCode = 108 AND DXCCSort = 86;"); + $this->db->query("UPDATE `dxcc_master` SET TimeZone = 4, ITUZone = 12, PrefixList = 'PV8, PU8[T-V], Z[V-Z]8T, Z[V-Z]8U, Z[V-Z]8V', location = 'Roraima ' WHERE CountryCode = 108 AND DXCCSort = 87;"); + $this->db->query("UPDATE `dxcc_master` SET TimeZone = 4, ITUZone = 12, PrefixList = 'PW8, PU8[D-F], Z[V-Z]8D, Z[V-Z]8E, Z[V-Z]8F', location = 'Rondonia ' WHERE CountryCode = 108 AND DXCCSort = 88;"); + $this->db->query("UPDATE `dxcc_master` SET TimeZone = 4, ITUZone = 13, PrefixList = 'PT9, PU9[A-N], Z[V-Z]9', location = 'Mato Grosso do Sul ' WHERE CountryCode = 108 AND DXCCSort = 92;"); + $this->db->query("UPDATE `dxcc_master` SET TimeZone = 3, ITUZone = 15, PrefixList = 'PY1, PU1[J-Y], Z[V-Z]1', location = 'Rio de Janeiro ' WHERE CountryCode = 108 AND DXCCSort = 11;"); + $this->db->query("UPDATE `dxcc_master` SET TimeZone = 3, ITUZone = 15, PrefixList = 'PY2, PU2[K-Y], Z[V-Z]2', location = 'Sao Paulo ' WHERE CountryCode = 108 AND DXCCSort = 21;"); + $this->db->query("UPDATE `dxcc_master` SET TimeZone = 3, ITUZone = 15, PrefixList = 'P[P-Y]3, Z[V-Z]3', location = 'Rio Grande do Sul ' WHERE CountryCode = 108 AND DXCCSort = 31;"); + $this->db->query("UPDATE `dxcc_master` SET TimeZone = 3, ITUZone = 15, PrefixList = 'P[P-Y]4, Z[V-Z]4', location = 'Minas Gerais ' WHERE CountryCode = 108 AND DXCCSort = 41;"); + $this->db->query("UPDATE `dxcc_master` SET TimeZone = 3, ITUZone = 15, PrefixList = 'PY5, PU5[M-Y], Z[V-Z]5', location = 'Parana ' WHERE CountryCode = 108 AND DXCCSort = 51;"); + $this->db->query("UPDATE `dxcc_master` SET TimeZone = 3, ITUZone = 13, PrefixList = 'PY6, PU6[J-Y], Z[V-Z]6', location = 'Bahia ' WHERE CountryCode = 108 AND DXCCSort = 61;"); + $this->db->query("UPDATE `dxcc_master` SET TimeZone = 3, ITUZone = 13, PrefixList = 'PY7, PU7[R-Y], Z[V-Z]7', location = 'Pernambuco ' WHERE CountryCode = 108 AND DXCCSort = 71;"); + $this->db->query("UPDATE `dxcc_master` SET TimeZone = 3, ITUZone = 13, PrefixList = 'PY8, PU8[W-Y], Z[V-Z]8', location = 'Para ' WHERE CountryCode = 108 AND DXCCSort = 81;"); + $this->db->query("UPDATE `dxcc_master` SET TimeZone = 4, ITUZone = 13, PrefixList = 'PY9, PU9[O-Y], ZV9[O-Z], ZW9[O-Z], ZX9[O-Z], ZY9[O-Z], ZZ9[O-Z]', location = 'Mato Grosso ' WHERE CountryCode = 108 AND DXCCSort = 91;"); + } + + public function down(){ + $this->db->query("DELETE FROM `dxcc_master` WHERE CountryCode = 108;"); + $this->db->query("INSERT INTO `dxcc_master` (DXCCPrefix,DXCCSearch,DXCCMap,DXCCSort,CountryCode,PrefixList,DXCCName,Location,Continent,CQZone,ITUZone,IOTA,TimeZone,Latitude,Longitude,StartDate,EndDate) VALUES ('PY','PY','PY',1,108,'P[P-Y], Z[V-Z]','Brazil','Brazil','SA','11',NULL,NULL,4.0,-15.8,-47.9167,NULL,NULL);"); + $this->db->query("INSERT INTO `dxcc_master` (DXCCPrefix,DXCCSearch,DXCCMap,DXCCSort,CountryCode,PrefixList,DXCCName,Location,Continent,CQZone,ITUZone,IOTA,TimeZone,Latitude,Longitude,StartDate,EndDate) VALUES ('PY','PY','PY',22,108,'PP2, PU2[F-H], Z[V-Z]2F, Z[V-Z]2G, Z[V-Z]2H','Brazil','Goias ','SA','11','',NULL,5.0,-15.8,-50.0,NULL,NULL);"); + $this->db->query("INSERT INTO `dxcc_master` (DXCCPrefix,DXCCSearch,DXCCMap,DXCCSort,CountryCode,PrefixList,DXCCName,Location,Continent,CQZone,ITUZone,IOTA,TimeZone,Latitude,Longitude,StartDate,EndDate) VALUES ('PY','PY','PY',12,108,'PP1, PU1[A-I], ZV1[A-I], ZW1[A-I], ZX1[A-I], ZY1[A-I], ZZ1[A-I]','Brazil','Esprito Santo ','SA','11','15',NULL,4.0,-20.0,-40.6,NULL,NULL);"); + $this->db->query("INSERT INTO `dxcc_master` (DXCCPrefix,DXCCSearch,DXCCMap,DXCCSort,CountryCode,PrefixList,DXCCName,Location,Continent,CQZone,ITUZone,IOTA,TimeZone,Latitude,Longitude,StartDate,EndDate) VALUES ('PY','PY','PY',75,108,'PT7, PU7[M-P], Z[V-Z]7M, Z[V-Z]7N, Z[V-Z]7O, Z[V-Z]7P','Brazil','Ceara ','SA','11','15',NULL,4.0,-5.6,-37.0,NULL,NULL);"); + $this->db->query("INSERT INTO `dxcc_master` (DXCCPrefix,DXCCSearch,DXCCMap,DXCCSort,CountryCode,PrefixList,DXCCName,Location,Continent,CQZone,ITUZone,IOTA,TimeZone,Latitude,Longitude,StartDate,EndDate) VALUES ('PY','PY','PY',52,108,'PP5, PU5[A-L], ZV5[A-L], ZW5[A-L], ZX5[A-L], ZY5[A-L], ZZ5[A-L]','Brazil','Santa Catarina ','SA','11','15',NULL,4.0,-27.0,-50.6,NULL,NULL);"); + $this->db->query("INSERT INTO `dxcc_master` (DXCCPrefix,DXCCSearch,DXCCMap,DXCCSort,CountryCode,PrefixList,DXCCName,Location,Continent,CQZone,ITUZone,IOTA,TimeZone,Latitude,Longitude,StartDate,EndDate) VALUES ('PY','PY','PY',62,108,'PP6, PU6[A-I], ,ZV6[A-I], ZW6[A-I], ZX6[A-I], ZY6[A-I], ZZ6[A-I]','Brazil','Sergipe ','SA','11','13',NULL,4.0,-10.7,-37.3,NULL,NULL);"); + $this->db->query("INSERT INTO `dxcc_master` (DXCCPrefix,DXCCSearch,DXCCMap,DXCCSort,CountryCode,PrefixList,DXCCName,Location,Continent,CQZone,ITUZone,IOTA,TimeZone,Latitude,Longitude,StartDate,EndDate) VALUES ('PY','PY','PY',72,108,'PP7, PU7[A-D], Z[V-Z]7A, Z[V-Z]7B, Z[V-Z]7C, Z[V-Z]7D','Brazil','Algonas ','SA','11','13',NULL,4.0,-9.8,-36.6,NULL,NULL);"); + $this->db->query("INSERT INTO `dxcc_master` (DXCCPrefix,DXCCSearch,DXCCMap,DXCCSort,CountryCode,PrefixList,DXCCName,Location,Continent,CQZone,ITUZone,IOTA,TimeZone,Latitude,Longitude,StartDate,EndDate) VALUES ('PY','PY','PY',82,108,'PP8, PU8[A-C], Z[V-Z]8A, Z[V-Z]8B, Z[V-Z]8C','Brazil','Amazonas ','SA','11','',NULL,4.0,-3.9,-65.0,NULL,NULL);"); + $this->db->query("INSERT INTO `dxcc_master` (DXCCPrefix,DXCCSearch,DXCCMap,DXCCSort,CountryCode,PrefixList,DXCCName,Location,Continent,CQZone,ITUZone,IOTA,TimeZone,Latitude,Longitude,StartDate,EndDate) VALUES ('PY','PY','PY',86,108,'PT8, PU8[J-L], Z[V-Z]8J, Z[V-Z]8K, Z[V-Z]8L','Brazil','Acre ','SA','11','12',NULL,4.0,-9.0,-70.3,NULL,NULL);"); + $this->db->query("INSERT INTO `dxcc_master` (DXCCPrefix,DXCCSearch,DXCCMap,DXCCSort,CountryCode,PrefixList,DXCCName,Location,Continent,CQZone,ITUZone,IOTA,TimeZone,Latitude,Longitude,StartDate,EndDate) VALUES ('PY','PY','PY',11,108,'P[Q-Y]1, Z[V-Z]1','Brazil','Rio de Janeiro ','SA','11','15',NULL,4.0,-22.75,-43.0,NULL,NULL);"); + $this->db->query("INSERT INTO `dxcc_master` (DXCCPrefix,DXCCSearch,DXCCMap,DXCCSort,CountryCode,PrefixList,DXCCName,Location,Continent,CQZone,ITUZone,IOTA,TimeZone,Latitude,Longitude,StartDate,EndDate) VALUES ('PY','PY','PY',21,108,'PR2,PS2,P[U-Y]2, Z[V-Z]2','Brazil','Sao Paulo ','SA','11','15',NULL,4.0,-22.6,-48.3,NULL,NULL);"); + $this->db->query("INSERT INTO `dxcc_master` (DXCCPrefix,DXCCSearch,DXCCMap,DXCCSort,CountryCode,PrefixList,DXCCName,Location,Continent,CQZone,ITUZone,IOTA,TimeZone,Latitude,Longitude,StartDate,EndDate) VALUES ('PY','PY','PY',31,108,'P[P-Y]3, Z[V-Z]3','Brazil','Rio Grande do Sul ','SA','11','15',NULL,4.0,-29.8,-53.5,NULL,NULL);"); + $this->db->query("INSERT INTO `dxcc_master` (DXCCPrefix,DXCCSearch,DXCCMap,DXCCSort,CountryCode,PrefixList,DXCCName,Location,Continent,CQZone,ITUZone,IOTA,TimeZone,Latitude,Longitude,StartDate,EndDate) VALUES ('PY','PY','PY',41,108,'P[P-Y]4, Z[V-Z]4','Brazil','Minas Gerias ','SA','11','',NULL,4.0,-18.8,-45.2,NULL,NULL);"); + $this->db->query("INSERT INTO `dxcc_master` (DXCCPrefix,DXCCSearch,DXCCMap,DXCCSort,CountryCode,PrefixList,DXCCName,Location,Continent,CQZone,ITUZone,IOTA,TimeZone,Latitude,Longitude,StartDate,EndDate) VALUES ('PY','PY','PY',51,108,'P[Q-Y]5, Z[V-Z]5','Brazil','Parana ','SA','11','15',NULL,4.0,-24.8,-52.2,NULL,NULL);"); + $this->db->query("INSERT INTO `dxcc_master` (DXCCPrefix,DXCCSearch,DXCCMap,DXCCSort,CountryCode,PrefixList,DXCCName,Location,Continent,CQZone,ITUZone,IOTA,TimeZone,Latitude,Longitude,StartDate,EndDate) VALUES ('PY','PY','PY',61,108,'P[Q-Y]6, Z[V-Z]6','Brazil','Bahia ','SA','11','',NULL,4.0,-12.2,-42.1,NULL,NULL);"); + $this->db->query("INSERT INTO `dxcc_master` (DXCCPrefix,DXCCSearch,DXCCMap,DXCCSort,CountryCode,PrefixList,DXCCName,Location,Continent,CQZone,ITUZone,IOTA,TimeZone,Latitude,Longitude,StartDate,EndDate) VALUES ('PY','PY','PY',71,108,'PQ7, P[U-Y]7, Z[V-Z]7','Brazil','Pernambuco ','SA','11','13',NULL,4.0,-8.5,-37.7,NULL,NULL);"); + $this->db->query("INSERT INTO `dxcc_master` (DXCCPrefix,DXCCSearch,DXCCMap,DXCCSort,CountryCode,PrefixList,DXCCName,Location,Continent,CQZone,ITUZone,IOTA,TimeZone,Latitude,Longitude,StartDate,EndDate) VALUES ('PY','PY','PY',81,108,'P[X-Y]8, PU8[W-Y], Z[V-Z]8','Brazil','Para ','SA','11','13',NULL,4.0,-3.3,-52.7,NULL,NULL);"); + $this->db->query("INSERT INTO `dxcc_master` (DXCCPrefix,DXCCSearch,DXCCMap,DXCCSort,CountryCode,PrefixList,DXCCName,Location,Continent,CQZone,ITUZone,IOTA,TimeZone,Latitude,Longitude,StartDate,EndDate) VALUES ('PY','PY','PY',91,108,'P[P-S]9, P[U-Y]9, ZV9[O-Z], ZW9[O-Z], ZX9[O-Z], ZY9[O-Z], ZZ9[O-Z]','Brazil','Mato Grosso ','SA','11','',NULL,4.0,-13.3,-56.0,NULL,NULL);"); + $this->db->query("INSERT INTO `dxcc_master` (DXCCPrefix,DXCCSearch,DXCCMap,DXCCSort,CountryCode,PrefixList,DXCCName,Location,Continent,CQZone,ITUZone,IOTA,TimeZone,Latitude,Longitude,StartDate,EndDate) VALUES ('PY','PY','PY',23,108,'PQ2, PU2[I-J], Z[V-Z]2I, Z[V-Z]2J','Brazil','Tocantins ','SA','11','13',NULL,4.0,-10.4,-48.4,NULL,NULL);"); + $this->db->query("INSERT INTO `dxcc_master` (DXCCPrefix,DXCCSearch,DXCCMap,DXCCSort,CountryCode,PrefixList,DXCCName,Location,Continent,CQZone,ITUZone,IOTA,TimeZone,Latitude,Longitude,StartDate,EndDate) VALUES ('PY','PY','PY',84,108,'PR8, PU8[M-O], Z[V-Z]8M, Z[V-Z]8N ,Z[V-Z]8O','Brazil','Maranhao ','SA','11','15',NULL,4.0,-4.9,-45.2,NULL,NULL);"); + $this->db->query("INSERT INTO `dxcc_master` (DXCCPrefix,DXCCSearch,DXCCMap,DXCCSort,CountryCode,PrefixList,DXCCName,Location,Continent,CQZone,ITUZone,IOTA,TimeZone,Latitude,Longitude,StartDate,EndDate) VALUES ('PY','PY','PY',24,108,'PT2, PU2[A-E], Z[V-Z]2A, Z[V-Z]2B, Z[V-Z]2C, Z[V-Z]2D, Z[V-Z]2E','Brazil','Brasilia ','SA','11','15',NULL,4.0,-15.9,-47.9,NULL,NULL);"); + $this->db->query("INSERT INTO `dxcc_master` (DXCCPrefix,DXCCSearch,DXCCMap,DXCCSort,CountryCode,PrefixList,DXCCName,Location,Continent,CQZone,ITUZone,IOTA,TimeZone,Latitude,Longitude,StartDate,EndDate) VALUES ('PY','PY','PY',83,108,'PQ8, PU8[G-I], Z[V-Z]G ,Z[V-Z]8H, Z[V-Z]8I','Brazil','Amapa ','SA','11','13',NULL,4.0,1.62,-52.1,NULL,NULL);"); + $this->db->query("INSERT INTO `dxcc_master` (DXCCPrefix,DXCCSearch,DXCCMap,DXCCSort,CountryCode,PrefixList,DXCCName,Location,Continent,CQZone,ITUZone,IOTA,TimeZone,Latitude,Longitude,StartDate,EndDate) VALUES ('PY','PY','PY',73,108,'PR7, PU7[E-H], Z[V-Z]7E, Z[V-Z]7F, Z[V-Z]7G, Z[V-Z]7H','Brazil','Paraiba ','SA','11','13',NULL,4.0,-7.1,-36.3,NULL,NULL);"); + $this->db->query("INSERT INTO `dxcc_master` (DXCCPrefix,DXCCSearch,DXCCMap,DXCCSort,CountryCode,PrefixList,DXCCName,Location,Continent,CQZone,ITUZone,IOTA,TimeZone,Latitude,Longitude,StartDate,EndDate) VALUES ('PY','PY','PY',85,108,'PS8, PU8[P-S], Z[V-Z]8P, Z[V-Z]8Q, Z[V-Z]8R, Z[V-Z]8S','Brazil','Piaui ','SA','11','13',NULL,4.0,-7.4,-42.4,NULL,NULL);"); + $this->db->query("INSERT INTO `dxcc_master` (DXCCPrefix,DXCCSearch,DXCCMap,DXCCSort,CountryCode,PrefixList,DXCCName,Location,Continent,CQZone,ITUZone,IOTA,TimeZone,Latitude,Longitude,StartDate,EndDate) VALUES ('PY','PY','PY',74,108,'PS7, PU7[I-L], Z[V-Z]7I, Z[V-Z]7J, Z[V-Z]7K, Z[V-Z]7L','Brazil','Rio Grande del Norte ','SA','11','12',NULL,4.0,-5.8,-36.7,NULL,NULL);"); + $this->db->query("INSERT INTO `dxcc_master` (DXCCPrefix,DXCCSearch,DXCCMap,DXCCSort,CountryCode,PrefixList,DXCCName,Location,Continent,CQZone,ITUZone,IOTA,TimeZone,Latitude,Longitude,StartDate,EndDate) VALUES ('PY','PY','PY',87,108,'PV8, PU8[T-V], Z[V-Z]8T, Z[V-Z]8U, Z[V-Z]8]V','Brazil','Roraima ','SA','11','',NULL,4.0,2.0,-62.0,NULL,NULL);"); + $this->db->query("INSERT INTO `dxcc_master` (DXCCPrefix,DXCCSearch,DXCCMap,DXCCSort,CountryCode,PrefixList,DXCCName,Location,Continent,CQZone,ITUZone,IOTA,TimeZone,Latitude,Longitude,StartDate,EndDate) VALUES ('PY','PY','PY',88,108,'PW8, PU8[D-F], Z[V-Z]8D, Z[V-Z]8E, Z[V-Z]8F','Brazil','Rondonia ','SA','11','12',NULL,4.0,-10.8,-63.0,NULL,NULL);"); + $this->db->query("INSERT INTO `dxcc_master` (DXCCPrefix,DXCCSearch,DXCCMap,DXCCSort,CountryCode,PrefixList,DXCCName,Location,Continent,CQZone,ITUZone,IOTA,TimeZone,Latitude,Longitude,StartDate,EndDate) VALUES ('PY','PY','PY',92,108,'PT9, PU9[A-N], Z[V-Z]9','Brazil','Mato Grosso do Sul ','SA','11','15',NULL,4.0,-20.7,-55.0,NULL,NULL);"); + } +} From c7a21a355c1ae1c9c17a57f0373cf2cb745511a9 Mon Sep 17 00:00:00 2001 From: Rodrigo Freire Date: Thu, 10 Jul 2025 23:41:39 -0300 Subject: [PATCH 03/15] Brazilian DXCC fix: Fixes the class name --- application/migrations/200_fix_brazil_dxcc_data.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/migrations/200_fix_brazil_dxcc_data.php b/application/migrations/200_fix_brazil_dxcc_data.php index c8b25e77..54aef3f2 100644 --- a/application/migrations/200_fix_brazil_dxcc_data.php +++ b/application/migrations/200_fix_brazil_dxcc_data.php @@ -1,6 +1,6 @@ Date: Thu, 10 Jul 2025 23:47:55 -0300 Subject: [PATCH 04/15] Brazilian DXCC data: Minor adjustements - Fixes a cosmethic ordering entry - Also adds comments giving references --- application/migrations/200_fix_brazil_dxcc_data.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/application/migrations/200_fix_brazil_dxcc_data.php b/application/migrations/200_fix_brazil_dxcc_data.php index 54aef3f2..d615914d 100644 --- a/application/migrations/200_fix_brazil_dxcc_data.php +++ b/application/migrations/200_fix_brazil_dxcc_data.php @@ -4,6 +4,8 @@ class Migration_fix_brazil_dxcc_data extends CI_Migration { public function up() { + // Fixes Brazilian DXCC data: Typos, ITU zone, + // Callsign assignment plan, time zone $this->db->query("UPDATE `dxcc_master` SET TimeZone = 3 WHERE CountryCode = 108 AND DXCCSort = 1;"); $this->db->query("UPDATE `dxcc_master` SET TimeZone = 3, ITUZone = 15, PrefixList = 'PP1, PU1[A-I], ZV1[A-I], ZW1[A-I], ZX1[A-I], ZY1[A-I], ZZ1[A-I]', location = 'Espirito Santo ' WHERE CountryCode = 108 AND DXCCSort = 12;"); $this->db->query("UPDATE `dxcc_master` SET TimeZone = 3, ITUZone = 13, PrefixList = 'PP2, PU2[F-H], Z[V-Z]2F, Z[V-Z]2G, Z[V-Z]2H', location = 'Goias ' WHERE CountryCode = 108 AND DXCCSort = 22;"); @@ -20,9 +22,9 @@ class Migration_fix_brazil_dxcc_data extends CI_Migration { $this->db->query("UPDATE `dxcc_master` SET TimeZone = 3, ITUZone = 13, PrefixList = 'PT2, PU2[A-E], Z[V-Z]2A, Z[V-Z]2B, Z[V-Z]2C, Z[V-Z]2D, Z[V-Z]2E', location = 'Brasilia ' WHERE CountryCode = 108 AND DXCCSort = 24;"); $this->db->query("UPDATE `dxcc_master` SET TimeZone = 3, ITUZone = 13, PrefixList = 'PT7, PU7[M-P], Z[V-Z]7M, Z[V-Z]7N, Z[V-Z]7O, Z[V-Z]7P', location = 'Ceara ' WHERE CountryCode = 108 AND DXCCSort = 75;"); $this->db->query("UPDATE `dxcc_master` SET TimeZone = 5, ITUZone = 12, PrefixList = 'PT8, PU8[J-L], Z[V-Z]8J, Z[V-Z]8K, Z[V-Z]8L', location = 'Acre ' WHERE CountryCode = 108 AND DXCCSort = 86;"); + $this->db->query("UPDATE `dxcc_master` SET TimeZone = 4, ITUZone = 13, PrefixList = 'PT9, PU9[A-N], Z[V-Z]9', location = 'Mato Grosso do Sul ' WHERE CountryCode = 108 AND DXCCSort = 92;"); $this->db->query("UPDATE `dxcc_master` SET TimeZone = 4, ITUZone = 12, PrefixList = 'PV8, PU8[T-V], Z[V-Z]8T, Z[V-Z]8U, Z[V-Z]8V', location = 'Roraima ' WHERE CountryCode = 108 AND DXCCSort = 87;"); $this->db->query("UPDATE `dxcc_master` SET TimeZone = 4, ITUZone = 12, PrefixList = 'PW8, PU8[D-F], Z[V-Z]8D, Z[V-Z]8E, Z[V-Z]8F', location = 'Rondonia ' WHERE CountryCode = 108 AND DXCCSort = 88;"); - $this->db->query("UPDATE `dxcc_master` SET TimeZone = 4, ITUZone = 13, PrefixList = 'PT9, PU9[A-N], Z[V-Z]9', location = 'Mato Grosso do Sul ' WHERE CountryCode = 108 AND DXCCSort = 92;"); $this->db->query("UPDATE `dxcc_master` SET TimeZone = 3, ITUZone = 15, PrefixList = 'PY1, PU1[J-Y], Z[V-Z]1', location = 'Rio de Janeiro ' WHERE CountryCode = 108 AND DXCCSort = 11;"); $this->db->query("UPDATE `dxcc_master` SET TimeZone = 3, ITUZone = 15, PrefixList = 'PY2, PU2[K-Y], Z[V-Z]2', location = 'Sao Paulo ' WHERE CountryCode = 108 AND DXCCSort = 21;"); $this->db->query("UPDATE `dxcc_master` SET TimeZone = 3, ITUZone = 15, PrefixList = 'P[P-Y]3, Z[V-Z]3', location = 'Rio Grande do Sul ' WHERE CountryCode = 108 AND DXCCSort = 31;"); @@ -34,7 +36,10 @@ class Migration_fix_brazil_dxcc_data extends CI_Migration { $this->db->query("UPDATE `dxcc_master` SET TimeZone = 4, ITUZone = 13, PrefixList = 'PY9, PU9[O-Y], ZV9[O-Z], ZW9[O-Z], ZX9[O-Z], ZY9[O-Z], ZZ9[O-Z]', location = 'Mato Grosso ' WHERE CountryCode = 108 AND DXCCSort = 91;"); } - public function down(){ + public function down() + { + // Reverts to the original content + // (from 105_create_dxcc_master_tables.php) $this->db->query("DELETE FROM `dxcc_master` WHERE CountryCode = 108;"); $this->db->query("INSERT INTO `dxcc_master` (DXCCPrefix,DXCCSearch,DXCCMap,DXCCSort,CountryCode,PrefixList,DXCCName,Location,Continent,CQZone,ITUZone,IOTA,TimeZone,Latitude,Longitude,StartDate,EndDate) VALUES ('PY','PY','PY',1,108,'P[P-Y], Z[V-Z]','Brazil','Brazil','SA','11',NULL,NULL,4.0,-15.8,-47.9167,NULL,NULL);"); $this->db->query("INSERT INTO `dxcc_master` (DXCCPrefix,DXCCSearch,DXCCMap,DXCCSort,CountryCode,PrefixList,DXCCName,Location,Continent,CQZone,ITUZone,IOTA,TimeZone,Latitude,Longitude,StartDate,EndDate) VALUES ('PY','PY','PY',22,108,'PP2, PU2[F-H], Z[V-Z]2F, Z[V-Z]2G, Z[V-Z]2H','Brazil','Goias ','SA','11','',NULL,5.0,-15.8,-50.0,NULL,NULL);"); From d80acebb432b8c216fe4afd6bc70db5674a6f5cc Mon Sep 17 00:00:00 2001 From: Rodrigo Freire Date: Thu, 10 Jul 2025 23:50:00 -0300 Subject: [PATCH 05/15] Brazilian DXCC fix: Fixes indentation --- application/migrations/200_fix_brazil_dxcc_data.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/migrations/200_fix_brazil_dxcc_data.php b/application/migrations/200_fix_brazil_dxcc_data.php index d615914d..5241961c 100644 --- a/application/migrations/200_fix_brazil_dxcc_data.php +++ b/application/migrations/200_fix_brazil_dxcc_data.php @@ -40,7 +40,7 @@ class Migration_fix_brazil_dxcc_data extends CI_Migration { { // Reverts to the original content // (from 105_create_dxcc_master_tables.php) - $this->db->query("DELETE FROM `dxcc_master` WHERE CountryCode = 108;"); + $this->db->query("DELETE FROM `dxcc_master` WHERE CountryCode = 108;"); $this->db->query("INSERT INTO `dxcc_master` (DXCCPrefix,DXCCSearch,DXCCMap,DXCCSort,CountryCode,PrefixList,DXCCName,Location,Continent,CQZone,ITUZone,IOTA,TimeZone,Latitude,Longitude,StartDate,EndDate) VALUES ('PY','PY','PY',1,108,'P[P-Y], Z[V-Z]','Brazil','Brazil','SA','11',NULL,NULL,4.0,-15.8,-47.9167,NULL,NULL);"); $this->db->query("INSERT INTO `dxcc_master` (DXCCPrefix,DXCCSearch,DXCCMap,DXCCSort,CountryCode,PrefixList,DXCCName,Location,Continent,CQZone,ITUZone,IOTA,TimeZone,Latitude,Longitude,StartDate,EndDate) VALUES ('PY','PY','PY',22,108,'PP2, PU2[F-H], Z[V-Z]2F, Z[V-Z]2G, Z[V-Z]2H','Brazil','Goias ','SA','11','',NULL,5.0,-15.8,-50.0,NULL,NULL);"); $this->db->query("INSERT INTO `dxcc_master` (DXCCPrefix,DXCCSearch,DXCCMap,DXCCSort,CountryCode,PrefixList,DXCCName,Location,Continent,CQZone,ITUZone,IOTA,TimeZone,Latitude,Longitude,StartDate,EndDate) VALUES ('PY','PY','PY',12,108,'PP1, PU1[A-I], ZV1[A-I], ZW1[A-I], ZX1[A-I], ZY1[A-I], ZZ1[A-I]','Brazil','Esprito Santo ','SA','11','15',NULL,4.0,-20.0,-40.6,NULL,NULL);"); From 4d10db1fc0d99847c454082f5cd9fca2752d37d3 Mon Sep 17 00:00:00 2001 From: Peter Goodhall Date: Tue, 15 Jul 2025 14:23:53 +0100 Subject: [PATCH 06/15] Fixed winkey state errors --- application/controllers/User.php | 3 +++ application/models/User_model.php | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/application/controllers/User.php b/application/controllers/User.php index 42c6808b..46dfc375 100644 --- a/application/controllers/User.php +++ b/application/controllers/User.php @@ -739,6 +739,9 @@ class User extends CI_Controller $post_data = $this->input->post(); + if (!isset($post_data['user_winkey'])) { + $post_data['user_winkey'] = '0'; + } if (!isset($post_data['user_winkey_websocket'])) { $post_data['user_winkey_websocket'] = '0'; } diff --git a/application/models/User_model.php b/application/models/User_model.php index ea93efdf..731f26c9 100644 --- a/application/models/User_model.php +++ b/application/models/User_model.php @@ -266,8 +266,8 @@ class User_Model extends CI_Model { 'user_quicklog' => xss_clean($fields['user_quicklog']), 'user_quicklog_enter' => xss_clean($fields['user_quicklog_enter']), 'language' => xss_clean($fields['language']), - 'winkey' => xss_clean($fields['user_winkey']), - 'winkey_websocket' => xss_clean($fields['user_winkey_websocket']), + 'winkey' => isset($fields['user_winkey']) ? xss_clean($fields['user_winkey']) : 0, + 'winkey_websocket' => isset($fields['user_winkey_websocket']) ? xss_clean($fields['user_winkey_websocket']) : 0, ); $this->db->query("replace into user_options (user_id, option_type, option_name, option_key, option_value) values (" . $fields['id'] . ", 'hamsat','hamsat_key','api','".xss_clean($fields['user_hamsat_key'])."');"); From a783f7d8a4004be495a30cc5039f6f4618f7794b Mon Sep 17 00:00:00 2001 From: Peter Goodhall Date: Tue, 15 Jul 2025 14:31:53 +0100 Subject: [PATCH 07/15] Security bug fixes --- application/models/Eqsl_images.php | 7 ++++++- application/models/Eqslmethods_model.php | 14 ++++++++++++-- application/models/User_model.php | 2 +- application/views/logbookadvanced/index.php | 4 ++++ assets/js/sections/logbookadvanced.js | 15 +++++++++++++++ 5 files changed, 38 insertions(+), 4 deletions(-) diff --git a/application/models/Eqsl_images.php b/application/models/Eqsl_images.php index dcd16092..dc5c9c6b 100644 --- a/application/models/Eqsl_images.php +++ b/application/models/Eqsl_images.php @@ -30,7 +30,12 @@ class Eqsl_images extends CI_Model { $this->db->select('COL_PRIMARY_KEY, qso_id, COL_CALL, COL_MODE, , COL_SUBMODE, COL_TIME_ON, COL_BAND, COL_SAT_NAME, image_file'); $this->db->join($this->config->item('table_name'), 'qso_id = COL_PRIMARY_KEY', 'left outer'); $this->db->join('station_profile', $this->config->item('table_name').'.station_id = station_profile.station_id', 'left outer'); - $this->db->where_in('station_profile.station_id', $logbooks_locations_array); + if (!empty($logbooks_locations_array)) { + $this->db->where_in('station_profile.station_id', $logbooks_locations_array); + } else { + // Option 1: Prevent query and return empty result + return []; + } $this->db->order_by('COL_TIME_ON', 'DESC'); return $this->db->get('eQSL_images'); } diff --git a/application/models/Eqslmethods_model.php b/application/models/Eqslmethods_model.php index 4d782f5b..3f410fc1 100644 --- a/application/models/Eqslmethods_model.php +++ b/application/models/Eqslmethods_model.php @@ -63,7 +63,12 @@ class Eqslmethods_model extends CI_Model { $this->db->or_where($this->config->item('table_name').'.COL_EQSL_QSL_SENT', 'Q'); $this->db->or_where($this->config->item('table_name').'.COL_EQSL_QSL_SENT', 'N'); $this->db->group_end(); - $this->db->where_in('station_profile.station_id', $logbooks_locations_array); + if (!empty($logbooks_locations_array)) { + $this->db->where_in('station_profile.station_id', $logbooks_locations_array); + } else { + // Option 1: Skip the query altogether (return no results) + return []; + } return $this->db->get(); } @@ -91,7 +96,12 @@ class Eqslmethods_model extends CI_Model { $this->db->where($this->config->item('table_name').'.COL_CALL !=', ''); $this->db->where($this->config->item('table_name').'.COL_EQSL_QSL_RCVD', 'Y'); $this->db->where('qso_id', NULL); - $this->db->where_in('station_profile.station_id', $logbooks_locations_array); + if (!empty($logbooks_locations_array)) { + $this->db->where_in('station_profile.station_id', $logbooks_locations_array); + } else { + // Option 1: Skip the query altogether (return no results) + return []; + } $this->db->order_by("COL_TIME_ON", "desc"); return $this->db->get(); diff --git a/application/models/User_model.php b/application/models/User_model.php index 731f26c9..528b15ea 100644 --- a/application/models/User_model.php +++ b/application/models/User_model.php @@ -266,7 +266,7 @@ class User_Model extends CI_Model { 'user_quicklog' => xss_clean($fields['user_quicklog']), 'user_quicklog_enter' => xss_clean($fields['user_quicklog_enter']), 'language' => xss_clean($fields['language']), - 'winkey' => isset($fields['user_winkey']) ? xss_clean($fields['user_winkey']) : 0, + 'winkey' => (isset($fields['user_winkey']) && is_numeric($clean = xss_clean($fields['user_winkey'])) && $clean !== '') ? intval($clean) : 0, 'winkey_websocket' => isset($fields['user_winkey_websocket']) ? xss_clean($fields['user_winkey_websocket']) : 0, ); diff --git a/application/views/logbookadvanced/index.php b/application/views/logbookadvanced/index.php index c2a3bd0b..35d5e367 100644 --- a/application/views/logbookadvanced/index.php +++ b/application/views/logbookadvanced/index.php @@ -20,6 +20,10 @@ if (!isset($options->operator)) { } ?> +