From b9f0b616541f2236ee108e979430e8be77caae5a Mon Sep 17 00:00:00 2001 From: phl0 Date: Thu, 5 Jun 2025 12:26:03 +0200 Subject: [PATCH 1/5] Add option to push logged QSOs to another WL instance --- application/config/migration.php | 2 +- application/controllers/Station.php | 3 + application/models/Logbook_model.php | 67 ++++++++++++++++++++ application/models/Stations.php | 6 ++ application/models/User_model.php | 5 +- application/views/station_profile/create.php | 19 ++++++ application/views/station_profile/edit.php | 27 ++++++++ 7 files changed, 126 insertions(+), 3 deletions(-) diff --git a/application/config/migration.php b/application/config/migration.php index 3186cc6494..6d3d840bb7 100644 --- a/application/config/migration.php +++ b/application/config/migration.php @@ -22,7 +22,7 @@ | */ -$config['migration_version'] = 245; +$config['migration_version'] = 246; /* |-------------------------------------------------------------------------- diff --git a/application/controllers/Station.php b/application/controllers/Station.php index 75b68c1c90..60d7c8359e 100644 --- a/application/controllers/Station.php +++ b/application/controllers/Station.php @@ -63,6 +63,9 @@ public function create() $data['qrzrealtime'] = $this->input->post('qrzrealtime'); $data['webadifapikey'] = $this->input->post('webadifapikey'); $data['webadifrealtime'] = $this->input->post('webadifrealtime'); + $data['wavelog_apiurl'] = $this->input->post('wavelog_apiurl'); + $data['wavelog_apikey'] = $this->input->post('wavelog_apikey'); + $data['wavelog_profileid'] = $this->input->post('wavelog_profileid'); $data['oqrs'] = $this->input->post('oqrs'); $data['oqrsemail'] = $this->input->post('oqrsemail'); $data['oqrstext'] = $this->input->post('oqrstext'); diff --git a/application/models/Logbook_model.php b/application/models/Logbook_model.php index f3d9a82bb8..65afe528db 100644 --- a/application/models/Logbook_model.php +++ b/application/models/Logbook_model.php @@ -885,6 +885,23 @@ function add_qso($data, $skipexport = false, $batchmode = false) { $this->mark_webadif_qsos_sent([$last_id]); } } + + $result = $this->exists_wavelog_api_key($data['station_id']); + // Push qso to upstream Wavelog instance + if (isset($result->wavelog_apikey)) { + if (!$this->load->is_loaded('AdifHelper')) { + $this->load->library('AdifHelper'); + } + $qso = $this->get_qso($last_id, true)->result(); + + $adif = $this->adifhelper->getAdifLine($qso[0]); + $result = $this->push_qso_to_wavelog( + $result->wavelog_apiurl, + $result->wavelog_apikey, + $result->wavelog_profileid, + $adif + ); + } } } } @@ -961,6 +978,24 @@ function exists_webadif_api_key($station_id) { } } + /* + * Function checks if a Wavelog API Key exists in the table with the given station id + */ + function exists_wavelog_api_key($station_id) { + $sql = 'select wavelog_apiurl, wavelog_apikey, wavelog_profileid from station_profile + where station_id = ?'; + + $query = $this->db->query($sql, $station_id); + + $result = $query->row(); + + if ($result) { + return $result; + } else { + return false; + } + } + /* * Function uploads a QSO to HRDLog with the API given. * $adif contains a line with the QSO in the ADIF format. QSO ends with an @@ -1091,6 +1126,38 @@ function push_qso_to_webadif($url, $apikey, $adif): bool { return $response === 200; } + /* + * Function uploads a QSO to an upstream Wavelog instance + * using URL, api key and profile id + * $adif contains a line with the QSO in the ADIF format. + */ + function push_qso_to_wavelog($url, $apikey, $profileid, $adif): bool { + + $headers = array( + 'Content-Type: application/json', + ); + + if (substr($url, -17) !== "index.php/api/qso") { + $url .= 'index.php/api/qso'; + } + + $arr = array('key' => $apikey, 'station_profile_id' => $profileid, 'type' => 'adif', 'string' => trim(preg_replace('/[\r\n]/', '', $adif))); + + $ch = curl_init($url); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($arr)); + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); + curl_setopt($ch, CURLOPT_HEADER, 0); + curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + + $content = curl_exec($ch); + $errors = curl_error($ch); + $response = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + return $response === 200; + } + /* * Function marks QSOs as uploaded to Clublog * $primarykey is the unique id for that QSO in the logbook diff --git a/application/models/Stations.php b/application/models/Stations.php index 51ad587753..84dc5f8aa7 100644 --- a/application/models/Stations.php +++ b/application/models/Stations.php @@ -172,6 +172,9 @@ function add() { 'webadifapikey' => xss_clean($this->input->post('webadifapikey', true)), 'webadifapiurl' => 'https://qo100dx.club/api', 'webadifrealtime' => xss_clean($this->input->post('webadifrealtime', true)), + 'wavelog_apiurl' => xss_clean($this->input->post('wavelog_apiurl', true)), + 'wavelog_apikey' => xss_clean($this->input->post('wavelog_apikey', true)), + 'wavelog_profileid' => xss_clean($this->input->post('wavelog_profileid', true)), ); // Insert Records & return insert id // @@ -251,6 +254,9 @@ function edit() { 'webadifapikey' => xss_clean($this->input->post('webadifapikey', true)), 'webadifapiurl' => 'https://qo100dx.club/api', 'webadifrealtime' => xss_clean($this->input->post('webadifrealtime', true)), + 'wavelog_apiurl' => xss_clean($this->input->post('wavelog_apiurl', true)), + 'wavelog_apikey' => xss_clean($this->input->post('wavelog_apikey', true)), + 'wavelog_profileid' => xss_clean($this->input->post('wavelog_profileid', true)), ); $this->db->where('user_id', $this->session->userdata('user_id')); diff --git a/application/models/User_model.php b/application/models/User_model.php index 27a27159ea..e8eb2412dd 100644 --- a/application/models/User_model.php +++ b/application/models/User_model.php @@ -991,10 +991,11 @@ function firstlogin_wizard($stationdata) { station_profile_name, station_gridsquare, station_city, station_iota, station_sota, station_callsign, station_power, station_dxcc, station_cnty, station_cq, station_itu, station_active, eqslqthnickname, state, qrzapikey, county, station_sig, station_sig_info, qrzrealtime, user_id, station_wwff, station_pota, oqrs, oqrs_text, oqrs_email, - webadifapikey, webadifapiurl, webadifrealtime, clublogignore, clublogrealtime, hrdlogrealtime, hrdlog_code, hrdlog_username + webadifapikey, webadifapiurl, webadifrealtime, clublogignore, clublogrealtime, hrdlogrealtime, hrdlog_code, hrdlog_username, + wavelog_apiurl, wavelog_apikey, wavelog_profileid ) VALUES ( ?, ?, '', '', '', ?, NULL, ?, '', ?, ?, 1, '', '', '', '', '', '', 0, ?, '', '', 0, '', 0, '', - 'https://qo100dx.club/api', 0, 0, 0, 0, '', '' + 'https://qo100dx.club/api', 0, 0, 0, 0, '', '', '', '', '' )", [ $stationdata['station_name'], strtoupper($stationdata['station_locator']), diff --git a/application/views/station_profile/create.php b/application/views/station_profile/create.php index 8837fcb8a4..722c14d5c1 100644 --- a/application/views/station_profile/create.php +++ b/application/views/station_profile/create.php @@ -209,6 +209,25 @@ + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+
wavelog_apiurl; } ?>"> + +
+
+ +
+ wavelog_apikey; } ?>"> + +
+ +
+
+ + wavelog_profileid; } ?>"> + +
+ + + +
From e27bebdbed69d87eccd29c1328234338ecbd9065 Mon Sep 17 00:00:00 2001 From: phl0 Date: Thu, 5 Jun 2025 12:32:10 +0200 Subject: [PATCH 2/5] Add migration script --- .../migrations/246_add_wavelog_api_export.php | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 application/migrations/246_add_wavelog_api_export.php diff --git a/application/migrations/246_add_wavelog_api_export.php b/application/migrations/246_add_wavelog_api_export.php new file mode 100644 index 0000000000..62e4a5ce86 --- /dev/null +++ b/application/migrations/246_add_wavelog_api_export.php @@ -0,0 +1,33 @@ +db->field_exists('wavelog_apiurl', 'station_profile')) { + $fields = array( + 'wavelog_apiurl varchar(100) DEFAULT NULL' + ); + $this->dbforge->add_column('station_profile', $fields); + } + if (!$this->db->field_exists('wavelog_apikey', 'station_profile')) { + $fields = array( + 'wavelog_apikey varchar(25) DEFAULT NULL' + ); + $this->dbforge->add_column('station_profile', $fields); + } + if (!$this->db->field_exists('wavelog_profileid', 'station_profile')) { + $fields = array( + 'wavelog_profileid int DEFAULT NULL' + ); + $this->dbforge->add_column('station_profile', $fields); + } + } + + public function down() { + $this->dbforge->drop_column('station_profile', 'wavelog_apiurl'); + $this->dbforge->drop_column('station_profile', 'wavelog_apikey'); + $this->dbforge->drop_column('station_profile', 'wavelog_profileid'); + } +} From 71c66b3ce514d649e1e25812047c6b78a5d2699d Mon Sep 17 00:00:00 2001 From: phl0 Date: Thu, 5 Jun 2025 15:01:48 +0200 Subject: [PATCH 3/5] Add table to keep track of uploaded QSOs --- .../migrations/246_add_wavelog_api_export.php | 21 ++++ application/models/Logbook_model.php | 62 ++++++++- application/models/Stations.php | 32 +++++ application/views/interface_assets/footer.php | 3 + application/views/interface_assets/header.php | 1 + application/views/wavelog/export.php | 119 ++++++++++++++++++ application/views/wavelog/mark_wavelog.php | 22 ++++ assets/js/sections/wavelog.js | 60 +++++++++ 8 files changed, 318 insertions(+), 2 deletions(-) create mode 100644 application/views/wavelog/export.php create mode 100644 application/views/wavelog/mark_wavelog.php create mode 100644 assets/js/sections/wavelog.js diff --git a/application/migrations/246_add_wavelog_api_export.php b/application/migrations/246_add_wavelog_api_export.php index 62e4a5ce86..7bb2873d63 100644 --- a/application/migrations/246_add_wavelog_api_export.php +++ b/application/migrations/246_add_wavelog_api_export.php @@ -23,11 +23,32 @@ public function up() { ); $this->dbforge->add_column('station_profile', $fields); } + + if (!$this->db->table_exists('wavelog')) { + $this->dbforge->add_field(array( + 'id' => array( + 'type' => 'INT', + 'auto_increment' => TRUE + ), + 'qso_id' => array( + 'type' => 'int', + ), + 'upload_date' => array( + 'type' => 'datetime', + ), + )); + + $this->dbforge->add_key('id', TRUE); + $this->dbforge->add_key(array('qso_id','upload_date'), FALSE); + + $this->dbforge->create_table('wavelog'); + } } public function down() { $this->dbforge->drop_column('station_profile', 'wavelog_apiurl'); $this->dbforge->drop_column('station_profile', 'wavelog_apikey'); $this->dbforge->drop_column('station_profile', 'wavelog_profileid'); + $this->dbforge->drop_table('wavelog'); } } diff --git a/application/models/Logbook_model.php b/application/models/Logbook_model.php index 65afe528db..70aa7e89ea 100644 --- a/application/models/Logbook_model.php +++ b/application/models/Logbook_model.php @@ -901,6 +901,9 @@ function add_qso($data, $skipexport = false, $batchmode = false) { $result->wavelog_profileid, $adif ); + if ($result) { + $this->mark_wavelog_qsos_sent([$last_id]); + } } } } @@ -1155,7 +1158,7 @@ function push_qso_to_wavelog($url, $apikey, $profileid, $adif): bool { $errors = curl_error($ch); $response = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); - return $response === 200; + return $response === 201; } /* @@ -1212,7 +1215,7 @@ function mark_qrz_qsos_sent($primarykey, $state = 'Y') { /* * Function marks QSOs as uploaded to WebADIF. - * $qsoIDs is an arroy of unique id for the QSOs in the logbook + * $qsoIDs is an array of unique id for the QSOs in the logbook */ function mark_webadif_qsos_sent(array $qsoIDs) { $data = []; @@ -1227,6 +1230,23 @@ function mark_webadif_qsos_sent(array $qsoIDs) { return true; } + /* + * Function marks QSOs as uploaded to upstream Wavelog. + * $qsoIDs is an array of unique id for the QSOs in the logbook + */ + function mark_wavelog_qsos_sent(array $qsoIDs) { + $data = []; + $now = date("Y-m-d H:i:s", strtotime("now")); + foreach ($qsoIDs as $qsoID) { + $data[] = [ + 'upload_date' => $now, + 'qso_id' => $qsoID, + ]; + } + $this->db->insert_batch('wavelog', $data); + return true; + } + function upload_amsat_status($data) { $sat_name = ''; if ($data['COL_SAT_NAME'] == 'AO-7') { @@ -2291,6 +2311,44 @@ function get_webadif_qsos($station_id, $from = null, $to = null, $trusted = fals return $this->db->query($sql, $binding); } + /* + * Function returns the QSOs from the logbook, which have not been either marked as uploaded to upstream Wavelog + */ + function get_wavelog_qsos($station_id, $from = null, $to = null, $trusted = false) { + $binding = []; + $this->load->model('stations'); + if ((!$trusted) && (!$this->stations->check_station_is_accessible($station_id))) { + return; + } + $sql = " + SELECT qsos.*, station_profile.*, dxcc_entities.name as station_country + FROM " . $this->config->item('table_name') . " qsos + INNER JOIN station_profile ON qsos.station_id = station_profile.station_id + LEFT JOIN dxcc_entities on qsos.col_my_dxcc = dxcc_entities.adif + LEFT OUTER JOIN wavelog ON qsos.COL_PRIMARY_KEY = wavelog.qso_id + WHERE qsos.station_id = ? + AND wavelog.upload_date IS NULL + "; + $binding[] = $station_id; + + if ($from) { + $from = DateTime::createFromFormat('d/m/Y', $from); + $from = $from->format('Y-m-d'); + + $sql .= " AND qsos.COL_TIME_ON >= ?"; + $binding[] = $from; + } + if ($to) { + $to = DateTime::createFromFormat('d/m/Y', $to); + $to = $to->format('Y-m-d'); + + $sql .= " AND qsos.COL_TIME_ON <= ?"; + $binding[] = $to; + } + + return $this->db->query($sql, $binding); + } + /* * Function returns all the station_id's with QRZ API Key's */ diff --git a/application/models/Stations.php b/application/models/Stations.php index 84dc5f8aa7..61b700663e 100644 --- a/application/models/Stations.php +++ b/application/models/Stations.php @@ -569,6 +569,38 @@ function stations_with_webadif_api_key() { return $this->db->query($sql,$bindings); } + function stations_with_wavelog_api_key() { + $bindings=[]; + $sql=" + SELECT station_profile.station_id, station_profile.station_profile_name, station_profile.station_callsign, notc.c notcount, totc.c totcount + FROM station_profile + LEFT OUTER JOIN ( + SELECT qsos.station_id, COUNT(qsos.COL_PRIMARY_KEY) c + FROM %s qsos + LEFT JOIN wavelog ON qsos.COL_PRIMARY_KEY = wavelog.qso_id + WHERE wavelog.qso_id IS NULL + GROUP BY qsos.station_id + ) notc ON station_profile.station_id = notc.station_id + LEFT JOIN ( + SELECT qsos.station_id, COUNT(qsos.COL_PRIMARY_KEY) c + FROM %s qsos + WHERE 1 + GROUP BY qsos.station_id + ) totc ON station_profile.station_id = totc.station_id + WHERE COALESCE(station_profile.wavelog_apikey, '') <> '' + AND COALESCE(station_profile.wavelog_apiurl, '') <> '' + AND COALESCE(station_profile.wavelog_profileid, '') <> 0 + AND station_profile.user_id = ? + "; + $bindings[]=$this->session->userdata('user_id'); + $sql=sprintf( + $sql, + $this->config->item('table_name'), + $this->config->item('table_name') + ); + return $this->db->query($sql,$bindings); + } + /* * Function: are_eqsl_nicks_defined * Description: Returns number of station profiles with eqslnicknames diff --git a/application/views/interface_assets/footer.php b/application/views/interface_assets/footer.php index c579a0be26..2ea817510e 100644 --- a/application/views/interface_assets/footer.php +++ b/application/views/interface_assets/footer.php @@ -1846,6 +1846,9 @@ function onMapClick(event) { uri->segment(1) == "webadif") { ?> + uri->segment(1) == "wavelog") { ?> + + uri->segment(2) == "dxcc" || $this->uri->segment(2) == "wae") { ?>