From 3e24905520c806c9aca85b423969a8fa41256c24 Mon Sep 17 00:00:00 2001 From: Peter Goodhall Date: Wed, 21 May 2025 16:47:57 +0100 Subject: [PATCH 01/17] If Clublog returns 403 disable upload --- application/controllers/Clublog.php | 8 ++++++++ application/models/Clublog_model.php | 11 +++++++++++ 2 files changed, 19 insertions(+) diff --git a/application/controllers/Clublog.php b/application/controllers/Clublog.php index 8472b5da..74801237 100644 --- a/application/controllers/Clublog.php +++ b/application/controllers/Clublog.php @@ -107,6 +107,14 @@ class Clublog extends CI_Controller { } else { echo "Error ".$response; log_message('error', 'Clublog upload for '.$station_row->station_callsign.' failed reason '.$response); + + // If Clublog responds with a 403 + if ($info['http_code'] == 403) { + $this->load->model('clublog_model'); + echo "Clublog API access denied for ".$station_row->station_callsign."
"; + log_message('error', 'Clublog API access denied for '.$station_row->station_callsign); + $this->clublog_model->reset_clublog_user_fields($station_row->user_id); + } } // Delete the ADIF file used for clublog diff --git a/application/models/Clublog_model.php b/application/models/Clublog_model.php index 009b5412..8aa157fe 100644 --- a/application/models/Clublog_model.php +++ b/application/models/Clublog_model.php @@ -17,6 +17,17 @@ class Clublog_model extends CI_Model { return $row = $query->row_array(); } + // function to reset clublog fields for the user in the auth table + function reset_clublog_user_fields($user_id) { + $data = array( + 'user_clublog_name' => null, + 'user_clublog_password' => null, + ); + + $this->db->where('user_id', $user_id); + $this->db->update($this->config->item('auth_table'), $data); + } + function mark_qsos_sent($station_id) { $data = array( 'COL_CLUBLOG_QSO_UPLOAD_DATE' => date('Y-m-d'), From 28f73d597018fb12a31d20adf88ceea81c865b45 Mon Sep 17 00:00:00 2001 From: Peter Goodhall Date: Wed, 21 May 2025 17:12:22 +0100 Subject: [PATCH 02/17] Improved commenting --- application/controllers/Clublog.php | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/application/controllers/Clublog.php b/application/controllers/Clublog.php index 74801237..f8c7b5bd 100644 --- a/application/controllers/Clublog.php +++ b/application/controllers/Clublog.php @@ -37,27 +37,33 @@ class Clublog extends CI_Controller { $this->load->model('clublog_model'); + // Retrieve all station profiles for the user with their QSO counts $station_profiles = $this->clublog_model->all_with_count($clean_userid); if($station_profiles->num_rows()){ foreach ($station_profiles->result() as $station_row) { + // Only process stations that have QSOs to upload if($station_row->qso_total > 0) { + // Get QSOs for this station that haven't been uploaded to Clublog yet $data['qsos'] = $this->clublog_model->get_clublog_qsos($station_row->station_id); if($data['qsos']->num_rows()){ + // Generate ADIF file content from the view template $string = $this->load->view('adif/data/clublog', $data, TRUE); + // Generate a unique ID for the temporary file $ranid = uniqid(); + // Write the ADIF data to a temporary file if ( ! write_file('uploads/clublog'.$ranid.$station_row->station_id.'.adi', $string)) { echo 'Unable to write the file - Make the folder Upload folder has write permissions.'; } else { - + // Get details of the created ADIF file $file_info = get_file_info('uploads/clublog'.$ranid.$station_row->station_id.'.adi'); - // initialise the curl request + // Initialize the CURL request to Clublog's API endpoint $request = curl_init('https://clublog.org/putlogs.php'); if($this->config->item('directory') != "") { @@ -138,13 +144,12 @@ class Clublog extends CI_Controller { $this->clublog_model->mark_qsos_sent($clean_station_id); } - function markallnotsent() { + function markallnotsent($station_id) { $clean_station_id = $this->security->xss_clean($station_id); $this->load->model('clublog_model'); $this->clublog_model->mark_all_qsos_notsent($clean_station_id); } - // Find DXCC function find_dxcc($callsign) { $clean_callsign = $this->security->xss_clean($callsign); From 34c240d43a208ef9f3b6f118a536c24d54b3de8d Mon Sep 17 00:00:00 2001 From: Peter Goodhall Date: Wed, 21 May 2025 23:06:59 +0100 Subject: [PATCH 03/17] Improve station profile page layout and fix HTML issues This commit makes two main improvements to the station profile page: 1. UI/Layout improvements: - Move the "Create Station Location" button next to the page title - Create a flex container for better alignment of title and button - Remove unnecessary paragraph tags around the button 2. HTML validation fixes: - Add missing quotes around title attributes in buttons - Replace incorrect
tag with proper
tag - Fix duplicate closing tag in empty log section - Clean up extra whitespace These changes improve both the visual appearance and HTML validity of the station profile page. --- application/views/station_profile/index.php | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/application/views/station_profile/index.php b/application/views/station_profile/index.php index c45df598..83899cb7 100644 --- a/application/views/station_profile/index.php +++ b/application/views/station_profile/index.php @@ -8,7 +8,10 @@ -

+
+

+ +
@@ -16,8 +19,6 @@

-

- num_rows() > 0) { ?> @@ -28,8 +29,7 @@ = 1) && ($is_admin)) { ?> @@ -73,17 +73,16 @@ user_id == "") { ?> station_id; ?>" class="btn btn-outline-primary btn-sm"> - station_id; ?>" title= class="btn btn-outline-primary btn-sm"> + station_id; ?>" title="" class="btn btn-outline-primary btn-sm"> - station_id; ?>" title= class="btn btn-outline-primary btn-sm"> + station_id; ?>" title="" class="btn btn-outline-primary btn-sm"> - - station_id; ?>" class="btn btn-danger btn-sm" title= onclick="return confirm('');"> + station_id; ?>" class="btn btn-danger btn-sm" title="" onclick="return confirm('');"> station_active != 1) { ?> - station_id; ?>" class="btn btn-danger btn-sm" title= onclick="return confirm(' station_profile_name; ?> ');"> + station_id; ?>" class="btn btn-danger btn-sm" title="" onclick="return confirm(' station_profile_name; ?> ');"> From a5cf402827688536079d56bee30769303665fd05 Mon Sep 17 00:00:00 2001 From: Peter Goodhall Date: Thu, 22 May 2025 22:54:18 +0100 Subject: [PATCH 04/17] Starting to add Winkey web socket features --- application/views/user/edit.php | 98 ++++++++++++++++++++------------- 1 file changed, 59 insertions(+), 39 deletions(-) diff --git a/application/views/user/edit.php b/application/views/user/edit.php index 1e20e791..d1c1e5e6 100644 --- a/application/views/user/edit.php +++ b/application/views/user/edit.php @@ -46,56 +46,71 @@
-
+
+ +
- - +
+ + +
" . $username_error . ""; + echo " " . $username_error . ""; } ?>
- - +
+ + +
" . $email_error . ""; + echo " " . $email_error . ""; } ?>
- +
+ - +
" . $password_error . ""; + echo " " . $password_error . ""; } else { ?> - +
-
+
- + session->userdata('user_type') == 99) { ?> - +
+ + +
config->item('auth_level'); - echo $l[$user_type]; + echo '
+ + +
'; } ?>
@@ -1162,24 +1177,29 @@
-
-
-
-
- - - - +
+
+
+ + > + +
+ +
+
+
+ + > + +
+
+ +
From d853963384d1b260eb3c0be157626838034ea118 Mon Sep 17 00:00:00 2001 From: Peter Goodhall Date: Fri, 23 May 2025 11:55:35 +0100 Subject: [PATCH 05/17] Cleaned up code formatting --- application/views/timeplotter/index.php | 26 ++--- application/views/update/index.php | 26 +++-- application/views/user/delete.php | 24 ++--- application/views/user/edit.php | 62 +++++++----- application/views/user/forgot_password.php | 56 +++++------ application/views/user/login.php | 66 ++++++------- application/views/user/main.php | 6 +- application/views/user/profile.php | 109 ++++++++++++--------- application/views/user/reset_password.php | 76 +++++++------- 9 files changed, 239 insertions(+), 212 deletions(-) diff --git a/application/views/timeplotter/index.php b/application/views/timeplotter/index.php index 680e441a..d47ea941 100644 --- a/application/views/timeplotter/index.php +++ b/application/views/timeplotter/index.php @@ -8,8 +8,8 @@
@@ -17,16 +17,16 @@
@@ -37,10 +37,10 @@
@@ -57,4 +57,4 @@
-
+
\ No newline at end of file diff --git a/application/views/update/index.php b/application/views/update/index.php index e2e75c82..cf05c2ab 100644 --- a/application/views/update/index.php +++ b/application/views/update/index.php @@ -3,7 +3,7 @@
-

Here you can update QSOs with missing distance information.

-

Update distance data

+

Update distance data

-
- - +
\ No newline at end of file diff --git a/application/views/user/delete.php b/application/views/user/delete.php index 91587efe..a35c462e 100644 --- a/application/views/user/delete.php +++ b/application/views/user/delete.php @@ -1,18 +1,18 @@
-
+
-
- -
-
-
+
+ +
+
+
-

?

+

?

-
uri->segment(3); ?>" name="users"> - - + uri->segment(3); ?>" name="users"> + +
-
+
-
+
\ No newline at end of file diff --git a/application/views/user/edit.php b/application/views/user/edit.php index d1c1e5e6..5d5f032d 100644 --- a/application/views/user/edit.php +++ b/application/views/user/edit.php @@ -55,8 +55,8 @@
+ echo $user_name; + } ?>" />
" . $username_error . ""; @@ -68,8 +68,8 @@
+ echo $user_email; + } ?>" />
" . $email_error . ""; @@ -296,28 +296,38 @@
- > - + > +
- > - + > +
- > - + > +
- > - + > +
- > - + > +
@@ -440,7 +450,7 @@ } ?>> + } ?>>
@@ -1036,8 +1046,8 @@
+ echo $user_callbook_username; + } ?>" /> " . $callbook_username_error . ""; } ?> @@ -1177,28 +1187,34 @@
-
-
+
+
+
+
- > + >

-
+
- > + >
- +
diff --git a/application/views/user/forgot_password.php b/application/views/user/forgot_password.php index 910875ac..89b756e1 100644 --- a/application/views/user/forgot_password.php +++ b/application/views/user/forgot_password.php @@ -1,43 +1,43 @@
- +
-

-

+

+

- - + +
diff --git a/application/views/user/login.php b/application/views/user/login.php index bdb90842..8396487a 100644 --- a/application/views/user/login.php +++ b/application/views/user/login.php @@ -1,44 +1,44 @@
- +

- + load->view('layout/messages'); ?> - + - form_validation->set_error_delimiters('', ''); ?> + form_validation->set_error_delimiters('', ''); ?>
@@ -57,10 +57,10 @@ body { -
-

-
- +
+

+
+
diff --git a/application/views/user/main.php b/application/views/user/main.php index a8ff0851..18b8ff9a 100644 --- a/application/views/user/main.php +++ b/application/views/user/main.php @@ -65,12 +65,12 @@ user_email; ?> config->item('auth_level'); echo $l[$row->user_type]; ?> - last_login_date != null) { // if the user never logged in before the value is null. We can show "never" then. echo $row->last_login_date; } else { echo lang('general_word_never'); - }?> + } ?> user_id; ?>" class="btn btn-outline-primary btn-sm"> @@ -81,7 +81,7 @@ ?> user_id) { ?> - + diff --git a/application/views/user/profile.php b/application/views/user/profile.php index 54eacf28..013f758d 100644 --- a/application/views/user/profile.php +++ b/application/views/user/profile.php @@ -1,55 +1,68 @@
-
+
-
-
- session->userdata('user_name')."'s profile"; ?> -
-
-
-

- - - - - - - - - - +
+
+ session->userdata('user_name') . "'s profile"; ?> +
+
+
+

+
Username
Levelconfig->item('auth_level'); echo $l[$user_type]; ?>
+ + + + - - - - - - - - - - - - - - - - - - - - - - - - - -
Username
E-mail
Callsign
Gridsquare
First name
Last name
+ + Level + config->item('auth_level'); + echo $l[$user_type]; ?> + -session->userdata('user_id'); ?>">Edit profile -
-
+ + E-mail + + + + + Callsign + + + + + Gridsquare + + + + + First name + + + + + Last name + + + + + + session->userdata('user_id'); ?>">Edit profile +
+
-
+
\ No newline at end of file diff --git a/application/views/user/reset_password.php b/application/views/user/reset_password.php index e83184c2..e3f14338 100644 --- a/application/views/user/reset_password.php +++ b/application/views/user/reset_password.php @@ -1,47 +1,47 @@
-
-
-
-
-
-

-

?

-

-
- - - - +
+
+
+
+
+

+

?

+

+
-
+ + + -
- -
- -
-
+ -
- -
- -
-
- -
- -
- - -
- +
+ +
+
-
+ +
+ +
+ +
+
+ +
+ +
+ + + +
-
+
+
+
+
\ No newline at end of file From e3ca732c0db6a955c0884bb164337e45cb139b9e Mon Sep 17 00:00:00 2001 From: Peter Goodhall Date: Fri, 23 May 2025 13:17:48 +0100 Subject: [PATCH 06/17] Adds HADES-ICM to the sat file --- assets/json/satellite_data.json | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/assets/json/satellite_data.json b/assets/json/satellite_data.json index 978465ac..5a63b03b 100644 --- a/assets/json/satellite_data.json +++ b/assets/json/satellite_data.json @@ -499,6 +499,18 @@ ] } }, + "HADES-ICM":{ + "Modes":{ + "V/U":[ + { + "Uplink_Mode":"FM", + "Uplink_Freq":"145875000", + "Downlink_Mode":"FM", + "Downlink_Freq":"436888000" + } + ] + } + }, "SONATE-2":{ "Modes":{ "V":[ From b894a5d3c69adff65aee70412ba41ff2eacf8007 Mon Sep 17 00:00:00 2001 From: Peter Goodhall Date: Fri, 23 May 2025 13:18:25 +0100 Subject: [PATCH 07/17] got the freq wrong --- assets/json/satellite_data.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/json/satellite_data.json b/assets/json/satellite_data.json index 5a63b03b..2e7e9b6f 100644 --- a/assets/json/satellite_data.json +++ b/assets/json/satellite_data.json @@ -506,7 +506,7 @@ "Uplink_Mode":"FM", "Uplink_Freq":"145875000", "Downlink_Mode":"FM", - "Downlink_Freq":"436888000" + "Downlink_Freq":"436666000" } ] } From e2006a936f9cd4de73efc31e4df322b85df21112 Mon Sep 17 00:00:00 2001 From: Peter Goodhall Date: Fri, 23 May 2025 15:03:32 +0100 Subject: [PATCH 08/17] Cleaned up code formatting --- application/controllers/Activated_gridmap.php | 112 +++++++++--------- 1 file changed, 58 insertions(+), 54 deletions(-) diff --git a/application/controllers/Activated_gridmap.php b/application/controllers/Activated_gridmap.php index ba41858f..2a498f6e 100644 --- a/application/controllers/Activated_gridmap.php +++ b/application/controllers/Activated_gridmap.php @@ -1,16 +1,19 @@ -load->model('bands'); - $this->load->model('activated_gridmap_model'); + $this->load->model('bands'); + $this->load->model('activated_gridmap_model'); $this->load->model('stations'); $data['visitor'] = false; @@ -32,25 +35,26 @@ class Activated_gridmap extends CI_Controller { $data['gridsquares_gridsquares_not_confirmed'] = lang('gridsquares_gridsquares_not_confirmed'); $data['gridsquares_gridsquares_total_activated'] = lang('gridsquares_gridsquares_total_activated'); - $footerData = []; + $footerData = []; $footerData['scripts'] = [ 'assets/js/leaflet/geocoding.js', 'assets/js/leaflet/L.MaidenheadColouredGridMap.js', 'assets/js/sections/gridmap.js?' ]; - + $this->load->view('interface_assets/header', $data); $this->load->view('activated_gridmap/index'); $this->load->view('interface_assets/footer', $footerData); - } + } - public function getGridsjs() { - $band = $this->security->xss_clean($this->input->post('band')); - $mode = $this->security->xss_clean($this->input->post('mode')); - $qsl = $this->security->xss_clean($this->input->post('qsl')); - $lotw = $this->security->xss_clean($this->input->post('lotw')); - $eqsl = $this->security->xss_clean($this->input->post('eqsl')); - $qrz = $this->security->xss_clean($this->input->post('qrz')); + public function getGridsjs() + { + $band = $this->security->xss_clean($this->input->post('band')); + $mode = $this->security->xss_clean($this->input->post('mode')); + $qsl = $this->security->xss_clean($this->input->post('qsl')); + $lotw = $this->security->xss_clean($this->input->post('lotw')); + $eqsl = $this->security->xss_clean($this->input->post('eqsl')); + $qrz = $this->security->xss_clean($this->input->post('qrz')); $sat = $this->security->xss_clean($this->input->post('sat')); $this->load->model('activated_gridmap_model'); @@ -73,27 +77,27 @@ class Activated_gridmap extends CI_Controller { $query = $this->activated_gridmap_model->get_band_confirmed($band, $mode, $qsl, $lotw, $eqsl, $qrz, $sat); if ($query && $query->num_rows() > 0) { - foreach ($query->result() as $row) { + foreach ($query->result() as $row) { $gridlist = explode(',', $row->GRID_SQUARES); foreach ($gridlist as $grid) { - $grid_2char_confirmed = strtoupper(substr($grid,0,2)); - $grid_4char_confirmed = strtoupper(substr($grid,0,4)); + $grid_2char_confirmed = strtoupper(substr($grid, 0, 2)); + $grid_4char_confirmed = strtoupper(substr($grid, 0, 4)); if ($this->config->item('map_6digit_grids')) { - $grid_6char_confirmed = strtoupper(substr($grid,0,6)); + $grid_6char_confirmed = strtoupper(substr($grid, 0, 6)); } // Check if 2 Char is in array - if(!in_array($grid_2char_confirmed, $array_grid_2char_confirmed)){ - array_push($array_grid_2char_confirmed, $grid_2char_confirmed); + if (!in_array($grid_2char_confirmed, $array_grid_2char_confirmed)) { + array_push($array_grid_2char_confirmed, $grid_2char_confirmed); } - if(!in_array($grid_4char_confirmed, $array_grid_4char_confirmed)){ - array_push($array_grid_4char_confirmed, $grid_4char_confirmed); + if (!in_array($grid_4char_confirmed, $array_grid_4char_confirmed)) { + array_push($array_grid_4char_confirmed, $grid_4char_confirmed); } if ($this->config->item('map_6digit_grids')) { - if(!in_array($grid_6char_confirmed, $array_grid_6char_confirmed)){ - array_push($array_grid_6char_confirmed, $grid_6char_confirmed); + if (!in_array($grid_6char_confirmed, $array_grid_6char_confirmed)) { + array_push($array_grid_6char_confirmed, $grid_6char_confirmed); } } } @@ -107,24 +111,24 @@ class Activated_gridmap extends CI_Controller { $gridlist = explode(',', $row->GRID_SQUARES); foreach ($gridlist as $grid) { - $grid_two = strtoupper(substr($grid,0,2)); - $grid_four = strtoupper(substr($grid,0,4)); + $grid_two = strtoupper(substr($grid, 0, 2)); + $grid_four = strtoupper(substr($grid, 0, 4)); if ($this->config->item('map_6digit_grids')) { - $grid_six = strtoupper(substr($grid,0,6)); + $grid_six = strtoupper(substr($grid, 0, 6)); } // Check if 2 Char is in array - if(!in_array($grid_two, $array_grid_2char)){ - array_push($array_grid_2char, $grid_two); + if (!in_array($grid_two, $array_grid_2char)) { + array_push($array_grid_2char, $grid_two); } - if(!in_array($grid_four, $array_grid_4char)){ - array_push($array_grid_4char, $grid_four); + if (!in_array($grid_four, $array_grid_4char)) { + array_push($array_grid_4char, $grid_four); } if ($this->config->item('map_6digit_grids')) { - if(!in_array($grid_six, $array_grid_6char)){ - array_push($array_grid_6char, $grid_six); + if (!in_array($grid_six, $array_grid_6char)) { + array_push($array_grid_6char, $grid_six); } } } @@ -137,18 +141,18 @@ class Activated_gridmap extends CI_Controller { $grids = explode(",", $row->COL_VUCC_GRIDS); - foreach($grids as $key) { - $grid_two = strtoupper(substr($key,0,2)); - $grid_four = strtoupper(substr($key,0,4)); + foreach ($grids as $key) { + $grid_two = strtoupper(substr($key, 0, 2)); + $grid_four = strtoupper(substr($key, 0, 4)); // Check if 2 Char is in array - if(!in_array($grid_two, $array_grid_2char)){ - array_push($array_grid_2char, $grid_two); + if (!in_array($grid_two, $array_grid_2char)) { + array_push($array_grid_2char, $grid_two); } - if(!in_array($grid_four, $array_grid_4char)){ - array_push($array_grid_4char, $grid_four); + if (!in_array($grid_four, $array_grid_4char)) { + array_push($array_grid_4char, $grid_four); } } } @@ -158,28 +162,28 @@ class Activated_gridmap extends CI_Controller { $query_vucc = $this->activated_gridmap_model->get_band_confirmed_vucc_squares($band, $mode, $qsl, $lotw, $eqsl, $qrz, $sat); if ($query_vucc && $query_vucc->num_rows() > 0) { - foreach ($query_vucc->result() as $row) { + foreach ($query_vucc->result() as $row) { $grids = explode(",", $row->COL_VUCC_GRIDS); - foreach($grids as $key) { - $grid_2char_confirmed = strtoupper(substr($key,0,2)); - $grid_4char_confirmed = strtoupper(substr($key,0,4)); + foreach ($grids as $key) { + $grid_2char_confirmed = strtoupper(substr($key, 0, 2)); + $grid_4char_confirmed = strtoupper(substr($key, 0, 4)); // Check if 2 Char is in array - if(!in_array($grid_2char_confirmed, $array_grid_2char_confirmed)){ - array_push($array_grid_2char_confirmed, $grid_2char_confirmed); + if (!in_array($grid_2char_confirmed, $array_grid_2char_confirmed)) { + array_push($array_grid_2char_confirmed, $grid_2char_confirmed); } - if(!in_array($grid_4char_confirmed, $array_grid_4char_confirmed)){ - array_push($array_grid_4char_confirmed, $grid_4char_confirmed); + if (!in_array($grid_4char_confirmed, $array_grid_4char_confirmed)) { + array_push($array_grid_4char_confirmed, $grid_4char_confirmed); } } } } - $data['grid_2char_confirmed'] = ($array_grid_2char_confirmed); + $data['grid_2char_confirmed'] = ($array_grid_2char_confirmed); $data['grid_4char_confirmed'] = ($array_grid_4char_confirmed); $data['grid_6char_confirmed'] = ($array_grid_6char_confirmed); @@ -187,7 +191,7 @@ class Activated_gridmap extends CI_Controller { $data['grid_4char'] = ($array_grid_4char); $data['grid_6char'] = ($array_grid_6char); - header('Content-Type: application/json'); - echo json_encode($data); - } + header('Content-Type: application/json'); + echo json_encode($data); + } } From 7156b185e1b192e66c87b94a85b25231fb8175e7 Mon Sep 17 00:00:00 2001 From: Peter Goodhall Date: Wed, 28 May 2025 13:38:25 +0100 Subject: [PATCH 09/17] add option to turn on websockets for winkey --- application/config/migration.php | 2 +- application/controllers/User.php | 33 +++++++++++++------ .../migrations/197_add_winkey_websocket.php | 30 +++++++++++++++++ application/models/User_model.php | 1 + application/views/user/edit.php | 5 +-- 5 files changed, 56 insertions(+), 15 deletions(-) create mode 100644 application/migrations/197_add_winkey_websocket.php diff --git a/application/config/migration.php b/application/config/migration.php index ce5a1727..90c77c9d 100644 --- a/application/config/migration.php +++ b/application/config/migration.php @@ -22,7 +22,7 @@ $config['migration_enabled'] = TRUE; | */ -$config['migration_version'] = 196; +$config['migration_version'] = 197; /* |-------------------------------------------------------------------------- diff --git a/application/controllers/User.php b/application/controllers/User.php index d3b91646..42c6808b 100644 --- a/application/controllers/User.php +++ b/application/controllers/User.php @@ -22,7 +22,7 @@ class User extends CI_Controller public function index() { $this->load->model('user_model'); - + // Check if the user is authorized if (!$this->user_model->authorize(99)) { $this->session->set_flashdata('notice', 'You\'re not allowed to do that!'); @@ -215,7 +215,7 @@ class User extends CI_Controller $this->input->post('user_callbook_username'), $this->input->post('user_callbook_password') )) { - // Check for errors + // Check for errors case EUSERNAMEEXISTS: $data['username_error'] = 'Username ' . $this->input->post('user_name') . ' already in use!'; break; @@ -225,7 +225,7 @@ class User extends CI_Controller case EPASSWORDINVALID: $data['password_error'] = 'Invalid password!'; break; - // All okay, return to user screen + // All okay, return to user screen case OK: $this->session->set_flashdata('notice', 'User ' . $this->input->post('user_name') . ' added'); redirect('user'); @@ -576,6 +576,12 @@ class User extends CI_Controller $data['user_winkey'] = $q->winkey; } + if ($this->input->post('user_winkey_websocket')) { + $data['user_winkey_websocket'] = $this->input->post('user_winkey_websocket', true); + } else { + $data['user_winkey_websocket'] = $q->winkey_websocket; + } + $this->load->model('user_options_model'); $callbook_type_object = $this->user_options_model->get_options('callbook')->result(); @@ -730,8 +736,14 @@ class User extends CI_Controller $this->load->view('interface_assets/footer'); } else { unset($data); - switch ($this->user_model->edit($this->input->post())) { - // Check for errors + + + $post_data = $this->input->post(); + if (!isset($post_data['user_winkey_websocket'])) { + $post_data['user_winkey_websocket'] = '0'; + } + switch ($this->user_model->edit($post_data)) { + // Check for errors case EUSERNAMEEXISTS: $data['username_error'] = 'Username ' . $this->input->post('user_name', true) . ' already in use!'; break; @@ -741,7 +753,7 @@ class User extends CI_Controller case EPASSWORDINVALID: $data['password_error'] = 'Invalid password!'; break; - // All okay, return to user screen + // All okay, return to user screen case OK: if ($this->session->userdata('user_id') == $this->uri->segment(3)) { // Editing own User? Set cookie! $cookie = array( @@ -755,25 +767,25 @@ class User extends CI_Controller $this->input->set_cookie($cookie); } if ($this->session->userdata('user_id') == $this->input->post('id', true)) { - + // Handle user_callbook_password if (isset($_POST['user_callbook_password']) && !empty($_POST['user_callbook_password'])) { - + // Handle user_callbook_type if (isset($_POST['user_callbook_type'])) { $this->user_options_model->set_option('callbook', 'callbook_type', array('value' => $_POST['user_callbook_type'])); } else { $this->user_options_model->set_option('callbook', 'callbook_type', array('value' => '')); } - + // Handle user_callbook_username if (isset($_POST['user_callbook_username'])) { $this->user_options_model->set_option('callbook', 'callbook_username', array('value' => $_POST['user_callbook_username'])); } else { $this->user_options_model->set_option('callbook', 'callbook_username', array('value' => '')); } - + // Load the encryption library $this->load->library('encryption'); @@ -892,6 +904,7 @@ class User extends CI_Controller $data['user_quicklog_enter'] = $this->input->post('user_quicklog_enter'); $data['language'] = $this->input->post('language'); $data['user_winkey'] = $this->input->post('user_winkey'); + $data['user_winkey_websocket'] = $this->input->post('user_winkey_websocket'); $data['user_hamsat_key'] = $this->input->post('user_hamsat_key'); $data['user_hamsat_workable_only'] = $this->input->post('user_hamsat_workable_only'); diff --git a/application/migrations/197_add_winkey_websocket.php b/application/migrations/197_add_winkey_websocket.php new file mode 100644 index 00000000..a38b9a75 --- /dev/null +++ b/application/migrations/197_add_winkey_websocket.php @@ -0,0 +1,30 @@ +db->field_exists('winkey_websocket', 'users')) { + $fields = array( + 'winkey_websocket boolean default 0', + ); + + $this->dbforge->add_column('users', $fields); + } + } + + public function down() + { + if ($this->db->field_exists('winkey_websocket', 'users')) { + $this->dbforge->drop_column('users', 'winkey_websocket'); + } + } +} diff --git a/application/models/User_model.php b/application/models/User_model.php index 3a12405b..aeb20967 100644 --- a/application/models/User_model.php +++ b/application/models/User_model.php @@ -267,6 +267,7 @@ class User_Model extends CI_Model { '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']), ); $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'])."');"); diff --git a/application/views/user/edit.php b/application/views/user/edit.php index 5d5f032d..33b2b4e1 100644 --- a/application/views/user/edit.php +++ b/application/views/user/edit.php @@ -1205,10 +1205,7 @@
- - > From 978bdbf76b7f1ba1e0f82f3c50a4f3e3e2efd6c5 Mon Sep 17 00:00:00 2001 From: Peter Goodhall Date: Wed, 28 May 2025 14:24:03 +0100 Subject: [PATCH 10/17] Wiring for Cloudlog Aurora Winkey Websocket Support --- application/models/User_model.php | 1 + application/views/interface_assets/footer.php | 234 +++++++++++++++++- application/views/qso/index.php | 44 +++- 3 files changed, 266 insertions(+), 13 deletions(-) diff --git a/application/models/User_model.php b/application/models/User_model.php index aeb20967..ea93efdf 100644 --- a/application/models/User_model.php +++ b/application/models/User_model.php @@ -427,6 +427,7 @@ class User_Model extends CI_Model { 'active_station_logbook' => $u->row()->active_station_logbook, 'language' => isset($u->row()->language) ? $u->row()->language: 'english', 'isWinkeyEnabled' => $u->row()->winkey, + 'isWinkeyWebsocketEnabled' => (bool)$u->row()->winkey_websocket, 'hasQrzKey' => $this->hasQrzKey($u->row()->user_id), 'callbook_type' => $callbook_type, 'callbook_username' => $callbook_username, diff --git a/application/views/interface_assets/footer.php b/application/views/interface_assets/footer.php index d7152fc2..038dc04b 100644 --- a/application/views/interface_assets/footer.php +++ b/application/views/interface_assets/footer.php @@ -1125,11 +1125,223 @@ if ($this->session->userdata('user_id') != null) { uri->segment(1) == "qso") { ?> - session->userdata('isWinkeyEnabled')) { ?> + session->userdata('isWinkeyEnabled') && !$this->session->userdata('isWinkeyWebsocketEnabled')) { ?> - session->userdata('isWinkeyEnabled') && $this->session->userdata('isWinkeyWebsocketEnabled')) { ?> + - if ($this->optionslib->get_option('dxcache_url') != '') { ?> + + + + + optionslib->get_option('dxcache_url') != '') { ?> - + diff --git a/application/views/qso/index.php b/application/views/qso/index.php index 56b1700c..5993a1a3 100755 --- a/application/views/qso/index.php +++ b/application/views/qso/index.php @@ -673,9 +673,49 @@ + session->userdata('isWinkeyEnabled') && $this->session->userdata('isWinkeyWebsocketEnabled')) { ?> +
+
+

Winkey Web Sockets + +
+ Status: Disconnected +
+ + +

+
+ +
+ +
+ + + + + +

+ + +
+ Message Log: + +
+ +
+
+ + + session->userdata('isWinkeyEnabled')) { ?> + // if isWinkeyEnabled in session data is true and isWinkeyWebsocketEnabled is false + + if ($this->session->userdata('isWinkeyEnabled') && !$this->session->userdata('isWinkeyWebsocketEnabled')) { ?>
From 34510470cecb92ce073100e283b98d0fe8648848 Mon Sep 17 00:00:00 2001 From: Peter Goodhall Date: Wed, 28 May 2025 14:31:22 +0100 Subject: [PATCH 11/17] feat: Add auto-reconnect functionality for Web Serial API - Implement autoReconnect() function to automatically reconnect to previously authorized serial devices on page load - Use navigator.serial.getPorts() to retrieve previously connected ports - Add graceful error handling for auto-reconnect failures - Improve disconnect() function with null check for port - Eliminates need for manual reconnection after page refresh - Maintains backward compatibility with existing functionality Fixes issue where Web Serial connection was lost on page refresh, requiring users to manually reconnect their devices each time. --- assets/js/winkey.js | 45 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/assets/js/winkey.js b/assets/js/winkey.js index c6195fe9..89b02e4a 100644 --- a/assets/js/winkey.js +++ b/assets/js/winkey.js @@ -88,6 +88,45 @@ async function clickConnect() { //Define outputstream, inputstream and port so they can be used throughout the sketch var outputStream, inputStream, port; + +// Auto-reconnect functionality +async function autoReconnect() { + try { + // Get previously connected ports + const ports = await navigator.serial.getPorts(); + if (ports.length > 0) { + // Try to reconnect to the first available port + port = ports[0]; + await port.open({ baudRate: 1200 }); + await port.setSignals({ dataTerminalReady: true }); + + statusBar.innerText = "Auto-reconnected"; + connectButton.innerText = "Disconnect"; + + let decoder = new TextDecoderStream(); + inputDone = port.readable.pipeTo(decoder.writable); + inputStream = decoder.readable; + + const encoder = new TextEncoderStream(); + outputDone = encoder.readable.pipeTo(port.writable); + outputStream = encoder.writable; + + writeToByte("0x00, 0x02"); + writeToByte("0x02, 0x00"); + + $('#winkey_buttons').show(); + + reader = inputStream.getReader(); + readLoop(); + } + } catch (e) { + console.log("Auto-reconnect failed:", e); + // If auto-reconnect fails, just continue with normal flow + } +} + +// Call auto-reconnect when page loads +window.addEventListener('load', autoReconnect); navigator.serial.addEventListener('connect', e => { statusBar.innerText = `Connected to ${e.port}`; connectButton.innerText = "Disconnect" @@ -182,8 +221,10 @@ async function disconnect() { statusBar.innerText = "Disconnected"; connectButton.innerText = "Connect" //Close the port. - await port.close(); - port = null; + if (port) { + await port.close(); + port = null; + } } //When the send button is pressed From 85ffd419abe728bafa65c91124ab47343a0f889a Mon Sep 17 00:00:00 2001 From: Peter Goodhall Date: Wed, 28 May 2025 16:56:03 +0100 Subject: [PATCH 12/17] Prevent duplicate QSO form submissions Prevent duplicate QSO form submissions - Add isSubmitting flag to track form submission state - Implement event listener on qso_input form to prevent multiple submissions - Block subsequent submit attempts while form is processing - Add comprehensive JSDoc documentation for the feature - Prevents duplicate QSO contacts from being created accidentally Fixes #3181 --- application/views/interface_assets/footer.php | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/application/views/interface_assets/footer.php b/application/views/interface_assets/footer.php index 038dc04b..b3aa66eb 100644 --- a/application/views/interface_assets/footer.php +++ b/application/views/interface_assets/footer.php @@ -1323,7 +1323,7 @@ if ($this->session->userdata('user_id') != null) { }); } - + function sendMyMessage() { const message = document.getElementById('sendText').value; if (message.trim() === '') { @@ -1338,7 +1338,6 @@ if ($this->session->userdata('user_id') != null) { // Clear the input field document.getElementById('sendText').value = ''; } - optionslib->get_option('dxcache_url') != '') { ?> @@ -1834,6 +1833,28 @@ if ($this->session->userdata('user_id') != null) { // Event listeners $(document).ready(() => { + + /** + * Prevents multiple form submissions by tracking submission state + * + * This script prevents duplicate QSO (contact) submissions by: + * - Maintaining an isSubmitting flag to track form submission state + * - Adding an event listener to the 'qso_input' form + * - Preventing form submission if a submission is already in progress + * - Setting the flag to true when a valid submission begins + * + * @since Unknown + * @global boolean isSubmitting Flag to track if form is currently being submitted + */ + let isSubmitting = false; + document.getElementById('qso_input').addEventListener('submit', function(e) { + if (isSubmitting) { + e.preventDefault(); + return false; + } + isSubmitting = true; + }); + // Update frequency every three seconds for the selected radio setInterval(() => { const selectedRadioID = $('select.radios option:selected').val(); From 72d2d84332ddd43c2b187a19df71de59ff7a7711 Mon Sep 17 00:00:00 2001 From: Peter Goodhall Date: Wed, 28 May 2025 17:08:54 +0100 Subject: [PATCH 13/17] Add dB signal report support for Q65, FST4, and FST4W digital modes - Updated setRst() function in footer.php to include Q65, FST4, FST4W modes - Extended getReportByMode() function in simplefle.js to handle dB reports for all digital modes - Ensures consistent signal report handling (-5 dB default) across all WSJT-X compatible modes - Fixes issue where Q65, FST4, FST4W used traditional RST instead of dB reports --- application/views/interface_assets/footer.php | 2 +- assets/js/sections/simplefle.js | 14 +++++++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/application/views/interface_assets/footer.php b/application/views/interface_assets/footer.php index b3aa66eb..17d81303 100644 --- a/application/views/interface_assets/footer.php +++ b/application/views/interface_assets/footer.php @@ -1681,7 +1681,7 @@ if ($this->session->userdata('user_id') != null) { $('#notice-alerts').delay(1000).fadeOut(5000); function setRst(mode) { - if (mode == 'JT65' || mode == 'JT65B' || mode == 'JT6C' || mode == 'JTMS' || mode == 'ISCAT' || mode == 'MSK144' || mode == 'JTMSK' || mode == 'QRA64' || mode == 'FT8' || mode == 'FT4' || mode == 'JS8' || mode == 'JT9' || mode == 'JT9-1' || mode == 'ROS') { + if (mode == 'JT65' || mode == 'JT65B' || mode == 'JT6C' || mode == 'JTMS' || mode == 'ISCAT' || mode == 'MSK144' || mode == 'JTMSK' || mode == 'QRA64' || mode == 'FT8' || mode == 'FT4' || mode == 'JS8' || mode == 'JT9' || mode == 'JT9-1' || mode == 'ROS' || mode == 'Q65' || mode == 'FST4' || mode == 'FST4W') { $('#rst_sent').val('-5'); $('#rst_rcvd').val('-5'); } else if (mode == 'FSK441' || mode == 'JT6M') { diff --git a/assets/js/sections/simplefle.js b/assets/js/sections/simplefle.js index ad7c8de5..4bbb259e 100644 --- a/assets/js/sections/simplefle.js +++ b/assets/js/sections/simplefle.js @@ -174,14 +174,13 @@ function handleInput() { /^[A-Z0-9]{1,3}\/[A-Z]{2}-\d{3}|[AENOS]*[FNSUACA]-\d{3}|(?!.*FF)[A-Z0-9]{1,3}-\d{4,5}|[A-Z0-9]{1,3}[F]{2}-\d{4}$/i ) ) { - sotaWwff = item.toUpperCase(); - } else if ( + sotaWwff = item.toUpperCase(); } else if ( item.match( /([a-zA-Z0-9]{1,3}[0-9][a-zA-Z0-9]{0,3}[a-zA-Z])|.*\/([a-zA-Z0-9]{1,3}[0-9][a-zA-Z0-9]{0,3}[a-zA-Z])|([a-zA-Z0-9]{1,3}[0-9][a-zA-Z0-9]{0,3}[a-zA-Z])\/.*/ ) ) { callsign = item.toUpperCase(); - } else if (itemNumber > 0 && item.match(/^\d{1,3}$/)) { + } else if (itemNumber > 0 && (item.match(/^\d{1,3}$/) || item.match(/^[+-]\d{1,2}$/))) { if (rst_s === null) { rst_s = item; } else { @@ -566,6 +565,15 @@ function getReportByMode(rst, mode) { return "599"; } + // Handle digital modes with dB signal reports (e.g., -09, +00) + if ((mode.toUpperCase() === "FT8" || mode.toUpperCase() === "FT4" || mode.toUpperCase() === "JS8" || + mode.toUpperCase() === "JT65" || mode.toUpperCase() === "JT65B" || mode.toUpperCase() === "JT6C" || + mode.toUpperCase() === "JTMS" || mode.toUpperCase() === "ISCAT" || mode.toUpperCase() === "MSK144" || + mode.toUpperCase() === "JTMSK" || mode.toUpperCase() === "QRA64" || mode.toUpperCase() === "JT9" || + mode.toUpperCase() === "JT9-1" || mode.toUpperCase() === "ROS" || mode.toUpperCase() === "Q65" || + mode.toUpperCase() === "FST4" || mode.toUpperCase() === "FST4W") && rst.match(/^[+-]\d{1,2}$/)) { + return rst; + } if (settingsMode === "SSB") { if (rst.length === 1) { From ff134c067e50e361a45d02a6b03916ef61fee997 Mon Sep 17 00:00:00 2001 From: Peter Goodhall Date: Tue, 10 Jun 2025 14:19:55 +0100 Subject: [PATCH 14/17] [Sats] Cbanged HADES-ICM to SO-125 --- application/config/migration.php | 2 +- .../198_sat_name_change_hadesicm_so125.php | 37 +++++++++++++++++++ assets/json/satellite_data.json | 2 +- 3 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 application/migrations/198_sat_name_change_hadesicm_so125.php diff --git a/application/config/migration.php b/application/config/migration.php index 90c77c9d..9399b8d8 100644 --- a/application/config/migration.php +++ b/application/config/migration.php @@ -22,7 +22,7 @@ $config['migration_enabled'] = TRUE; | */ -$config['migration_version'] = 197; +$config['migration_version'] = 198; /* |-------------------------------------------------------------------------- diff --git a/application/migrations/198_sat_name_change_hadesicm_so125.php b/application/migrations/198_sat_name_change_hadesicm_so125.php new file mode 100644 index 00000000..45eb207e --- /dev/null +++ b/application/migrations/198_sat_name_change_hadesicm_so125.php @@ -0,0 +1,37 @@ +db->set('COL_SAT_NAME', 'SO-125'); + $this->db->where('COL_SAT_NAME', 'HADES-ICM'); + $this->db->update($this->config->item('table_name')); + log_message('info', 'Migration: Updated COL_SAT_NAME to SO-125 for HADES-ICM'); + + // update column COL_LOTW_QSL_SENT to N if its SO-125 + $this->db->set('COL_LOTW_QSL_SENT', 'N'); + $this->db->where('COL_SAT_NAME', 'SO-125'); + $this->db->update($this->config->item('table_name')); + log_message('info', 'Migration: Set COL_LOTW_QSL_SENT to N for SO-125'); + + } + + public function down() + { + //Change back to HADES-ICM + $this->db->set('COL_SAT_NAME', 'HADES-ICM'); + $this->db->where('COL_SAT_NAME', 'SO-125'); + $this->db->update($this->config->item('table_name')); + log_message('info', 'Migration: Reverted COL_SAT_NAME back to HADES-ICM'); + + // Set COL_LOTW_QSL_SENT back to N for HADES-ICM + $this->db->set('COL_LOTW_QSL_SENT', 'N'); + $this->db->where('COL_SAT_NAME', 'HADES-ICM'); + $this->db->update($this->config->item('table_name')); + log_message('info', 'Migration: Reverted COL_LOTW_QSL_SENT back to N for HADES-ICM'); + } +} diff --git a/assets/json/satellite_data.json b/assets/json/satellite_data.json index 2e7e9b6f..6ad5964a 100644 --- a/assets/json/satellite_data.json +++ b/assets/json/satellite_data.json @@ -499,7 +499,7 @@ ] } }, - "HADES-ICM":{ + "SO-125":{ "Modes":{ "V/U":[ { From ff8bbcf216fa994c542fa83466b46e94a53899d8 Mon Sep 17 00:00:00 2001 From: Peter Goodhall Date: Tue, 10 Jun 2025 14:45:41 +0100 Subject: [PATCH 15/17] Update 198_sat_name_change_hadesicm_so125.php --- application/migrations/198_sat_name_change_hadesicm_so125.php | 1 - 1 file changed, 1 deletion(-) diff --git a/application/migrations/198_sat_name_change_hadesicm_so125.php b/application/migrations/198_sat_name_change_hadesicm_so125.php index 45eb207e..28c7f6bc 100644 --- a/application/migrations/198_sat_name_change_hadesicm_so125.php +++ b/application/migrations/198_sat_name_change_hadesicm_so125.php @@ -5,7 +5,6 @@ class Migration_198_sat_name_change_hadesicm_so125 extends CI_Migration { public function up() { - // update column COL_SAT_NAME to SO-125 if its HADES-ICM $this->db->set('COL_SAT_NAME', 'SO-125'); $this->db->where('COL_SAT_NAME', 'HADES-ICM'); From 17bf359515b2169da27923c52aa9827386748c4d Mon Sep 17 00:00:00 2001 From: Peter Goodhall Date: Tue, 10 Jun 2025 15:05:50 +0100 Subject: [PATCH 16/17] typo --- application/migrations/198_sat_name_change_hadesicm_so125.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/migrations/198_sat_name_change_hadesicm_so125.php b/application/migrations/198_sat_name_change_hadesicm_so125.php index 28c7f6bc..e5b42e71 100644 --- a/application/migrations/198_sat_name_change_hadesicm_so125.php +++ b/application/migrations/198_sat_name_change_hadesicm_so125.php @@ -1,7 +1,7 @@ Date: Wed, 11 Jun 2025 15:25:08 +0100 Subject: [PATCH 17/17] tag 2..6.19 --- application/config/migration.php | 2 +- application/migrations/199_tag_2_6_19.php | 30 +++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 application/migrations/199_tag_2_6_19.php diff --git a/application/config/migration.php b/application/config/migration.php index 9399b8d8..2eb36735 100644 --- a/application/config/migration.php +++ b/application/config/migration.php @@ -22,7 +22,7 @@ $config['migration_enabled'] = TRUE; | */ -$config['migration_version'] = 198; +$config['migration_version'] = 199; /* |-------------------------------------------------------------------------- diff --git a/application/migrations/199_tag_2_6_19.php b/application/migrations/199_tag_2_6_19.php new file mode 100644 index 00000000..2f8c2c45 --- /dev/null +++ b/application/migrations/199_tag_2_6_19.php @@ -0,0 +1,30 @@ +db->where('option_name', 'version'); + $this->db->update('options', array('option_value' => '2.6.19')); + + // Trigger Version Info Dialog + $this->db->where('option_type', 'version_dialog'); + $this->db->where('option_name', 'confirmed'); + $this->db->update('user_options', array('option_value' => 'false')); + + } + + public function down() + { + $this->db->where('option_name', 'version'); + $this->db->update('options', array('option_value' => '2.6.18')); + } +} \ No newline at end of file