Skip to content

Commit 32505c1

Browse files
authored
2.7.6
2.7.6
2 parents 97e5ac1 + 1f7d17e commit 32505c1

11 files changed

Lines changed: 250 additions & 44 deletions

File tree

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
66
Cloudlog is a self-hosted PHP application that allows you to log your amateur radio contacts anywhere. All you need is a web browser and active internet connection.
77

8-
While Cloudlog as started by Peter Goodhall, 2M0SQL, although since has received a lot of community code contributions. If you would like to contribute to Cloudlog please see the [Contributing](#contributing) section below.
8+
While Cloudlog as started by Peter Goodhall, MM9SQL, although since has received a lot of community code contributions. If you would like to contribute to Cloudlog please see the [Contributing](#contributing) section below.
99

1010
Website: [http://www.cloudlog.co.uk](http://www.cloudlog.co.uk)
1111

@@ -103,7 +103,7 @@ Cloudlog has two support systems for code issues use Github issues, however if y
103103

104104
## Security Vulnerabilities
105105

106-
If you discover a security vulnerability within Cloudlog, please send an e-mail to Peter Goodhall, 2M0SQL via [peter@magicbug.co.uk](mailto:peter@magicbug.co.uk). All security vulnerabilities will be promptly addressed.
106+
If you discover a security vulnerability within Cloudlog, please send an e-mail to Peter Goodhall, MM9SQL via [peter@magicbug.co.uk](mailto:peter@magicbug.co.uk). All security vulnerabilities will be promptly addressed.
107107

108108
## Want Cloudlog Hosting?
109109

@@ -131,4 +131,4 @@ Cloudlog is supported by Patreon and donations via PayPal, thanks to the followi
131131

132132
Paul (M0TZO), Tim (G4VXE), Paul (N8HM), Michelle (W5NYV), Mitchell (AD0HJ), Dan (M0TCB), Martin (DK3ML), Juan Carlos (EA5WA), Iain (M0PCB), Charlie (GM1TGY), Ondrej (OK1CDJ), Trystan (G0KAY), Oliver (DL6KBG), Volkmar Schirmer, Jordan (M0PIR), Thomas Ziegler, Mathis (DB9MAT), Ken (VE3HLS), Tyler (WL7T), Jeremy Taylor, Ben Kuhn, Eric Thresher, Michael Cullen, Juuso (OH1JW), Anthony Castiglia, Fernando Ramirez-Ferrer, Robert Dixon, Mark Percival, Julia (KV1V), Timo Tomasini, Ant (NU1U), Christopher Williams, Danny Barnes, Vic, Tom (M0LTE), smurphboy, Lars (SM0TGU), Theo (PD9DP), Stefan (SM0RGM). Peter (G0ABI), Lou (KI5FTY), Michael (DG3NAB), Dragan (4O4A), minorsecond, Emily (W7AYQ), Steve (M0SKM), Rob (M0VFC), Doug (WA6L), Petr (OK1PKR), Fabian (HB9HIL), Daniel (OK2VLK), John (M5JFS), Johnathan (2E0DEF), Peter (M0LNB)
133133

134-
If you'd like to donate to Cloudlog to help allow @magicbug spend less time doing commercial work and more time coding Cloudlog then you can donate via [PayPal](https://paypal.me/PGoodhall), [Github Sponsor](https://github.com/sponsors/magicbug) or become a [Patreon](https://www.patreon.com/2m0sql)
134+
If you'd like to donate to Cloudlog to help allow @magicbug spend less time doing commercial work and more time coding Cloudlog then you can donate via [PayPal](https://paypal.me/PGoodhall), [Github Sponsor](https://github.com/sponsors/magicbug) or become a [Patreon](https://www.patreon.com/MM9SQL)

application/config/migration.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
|
2323
*/
2424

25-
$config['migration_version'] = 230;
25+
$config['migration_version'] = 231;
2626

2727
/*
2828
|--------------------------------------------------------------------------

application/controllers/Awards.php

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -276,8 +276,39 @@ public function vucc_details_ajax()
276276
{
277277
$this->load->model('logbook_model');
278278

279-
$gridsquare = str_replace('"', "", $this->security->xss_clean($this->input->post("Gridsquare")));
280-
$band = str_replace('"', "", $this->security->xss_clean($this->input->post("Band")));
279+
// Validate and sanitize gridsquare input - should be alphanumeric only, max 6 characters
280+
$gridsquare_raw = $this->input->post("Gridsquare");
281+
$band_raw = $this->input->post("Band");
282+
283+
// Validate gridsquare format - VUCC allows multiple gridsquares separated by commas
284+
if (!$gridsquare_raw) {
285+
show_error('Gridsquare parameter is required', 400);
286+
return;
287+
}
288+
289+
// Split by comma and validate each gridsquare
290+
$gridsquares = explode(',', $gridsquare_raw);
291+
foreach ($gridsquares as $grid) {
292+
$grid = trim($grid);
293+
// Each grid should be 4 or 6 characters: AA00 or AA00aa format
294+
if (!preg_match('/^[A-Ra-r]{2}[0-9]{2}[A-Xa-x]{0,2}$/', $grid)) {
295+
show_error('Invalid gridsquare format: ' . htmlspecialchars($grid), 400);
296+
return;
297+
}
298+
}
299+
300+
// Validate band - use Cloudlog's band system for validation
301+
$this->load->model('bands');
302+
$valid_bands = array_keys($this->bands->bandslots);
303+
$valid_bands[] = 'All'; // Add 'All' as a valid option
304+
305+
if (!$band_raw || !in_array($band_raw, $valid_bands)) {
306+
show_error('Invalid band specified', 400);
307+
return;
308+
}
309+
310+
$gridsquare = strtoupper($gridsquare_raw);
311+
$band = $band_raw;
281312
$data['results'] = $this->logbook_model->vucc_qso_details($gridsquare, $band);
282313

283314
// Render Page

application/controllers/Eqsl.php

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -168,10 +168,8 @@ public function export()
168168

169169
foreach ($qslsnotsent->result_array() as $qsl) {
170170
$rows .= "<tr>";
171-
// eQSL username changes for linked account.
172-
// i.e. when operating /P it must be callsign/p
173-
// the password, however, is always the same as the main account
174-
$data['user_eqsl_name'] = $qsl['station_callsign'];
171+
// Note: eQSL authentication uses the user's actual eQSL credentials
172+
// The station callsign is handled in the ADIF data via eqslqthnickname
175173
$adif = $this->generateAdif($qsl, $data);
176174

177175
$status = $this->uploadQso($adif, $qsl);

application/controllers/Lotw.php

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -724,15 +724,37 @@ function lotw_download($sync_user_id = null) {
724724
'Accept-Language: en-US,en;q=0.9'
725725
));
726726

727-
$response = curl_exec($ch);
728-
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
729-
$curl_error = curl_error($ch);
727+
$max_retries = 3;
728+
$retry_delay = 2; // seconds
729+
$response = false;
730+
$curl_error = '';
731+
$http_code = 0;
732+
733+
for ($attempt = 1; $attempt <= $max_retries; $attempt++) {
734+
$response = curl_exec($ch);
735+
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
736+
$curl_error = curl_error($ch);
737+
738+
// If successful or non-network error, break out of retry loop
739+
if ($response !== false && empty($curl_error)) {
740+
break;
741+
}
742+
743+
// Log retry attempt
744+
if ($attempt < $max_retries) {
745+
log_message('debug', "LoTW download attempt {$attempt} failed for user ".$data['user_lotw_name'].": " . $curl_error . " - retrying in {$retry_delay} seconds");
746+
sleep($retry_delay);
747+
// Exponential backoff - increase delay for next retry
748+
$retry_delay *= 2;
749+
}
750+
}
751+
730752
curl_close($ch);
731753

732-
// Check for cURL errors
754+
// Check for cURL errors after all retries
733755
if ($response === false || !empty($curl_error)) {
734-
$result = "LoTW download failed for user ".$data['user_lotw_name'].": " . $curl_error;
735-
log_message('error', 'LoTW cURL error: ' . $curl_error);
756+
$result = "LoTW download failed for user ".$data['user_lotw_name']." after {$max_retries} attempts: " . $curl_error;
757+
log_message('error', 'LoTW cURL error after retries: ' . $curl_error);
736758
continue;
737759
}
738760

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
defined('BASEPATH') OR exit('No direct script access allowed');
4+
5+
/*
6+
* Tag Cloudlog as 2.7.6
7+
*/
8+
9+
class Migration_tag_2_7_6 extends CI_Migration {
10+
11+
public function up()
12+
{
13+
14+
// Tag Cloudlog 2.7.6
15+
$this->db->where('option_name', 'version');
16+
$this->db->update('options', array('option_value' => '2.7.6'));
17+
18+
// Trigger Version Info Dialog
19+
$this->db->where('option_type', 'version_dialog');
20+
$this->db->where('option_name', 'confirmed');
21+
$this->db->update('user_options', array('option_value' => 'false'));
22+
23+
}
24+
25+
public function down()
26+
{
27+
$this->db->where('option_name', 'version');
28+
$this->db->update('options', array('option_value' => '2.7.5'));
29+
}
30+
}

application/models/Logbook_model.php

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -417,9 +417,12 @@ public function qso_details($searchphrase, $band, $mode, $type, $qsl, $searchmod
417417
break;
418418
case 'VUCC':
419419
if ($searchmode == 'activated') {
420-
$this->db->where("station_gridsquare like '%" . $searchphrase . "%'");
420+
$this->db->like('station_gridsquare', $searchphrase);
421421
} else {
422-
$this->db->where("(COL_GRIDSQUARE like '" . $searchphrase . "%' OR COL_VUCC_GRIDS like '%" . $searchphrase . "%')");
422+
$this->db->group_start();
423+
$this->db->like('COL_GRIDSQUARE', $searchphrase, 'after');
424+
$this->db->or_like('COL_VUCC_GRIDS', $searchphrase);
425+
$this->db->group_end();
423426
}
424427
break;
425428
case 'CQZone':
@@ -556,23 +559,34 @@ public function vucc_qso_details($gridsquare, $band)
556559
$CI->load->model('logbooks_model');
557560
$logbooks_locations_array = $CI->logbooks_model->list_logbook_relationships($this->session->userdata('active_station_logbook'));
558561

559-
$location_list = "'" . implode("','", $logbooks_locations_array) . "'";
562+
if (empty($logbooks_locations_array)) {
563+
return $this->db->query("SELECT * FROM " . $this->config->item('table_name') . " WHERE 1=0"); // Return empty result
564+
}
560565

561-
$sql = "select * from " . $this->config->item('table_name') .
562-
" where station_id in (" . $location_list . ")" .
563-
" and (col_gridsquare like '" . $gridsquare . "%'
564-
or col_vucc_grids like '%" . $gridsquare . "%')";
566+
// Use parameterized query to prevent SQL injection
567+
$this->db->select('*');
568+
$this->db->from($this->config->item('table_name'));
569+
$this->db->where_in('station_id', $logbooks_locations_array);
570+
571+
// Use parameterized LIKE queries for gridsquare matching
572+
$gridsquare_like = $gridsquare . '%';
573+
$gridsquare_contains = '%' . $gridsquare . '%';
574+
575+
$this->db->group_start();
576+
$this->db->like('col_gridsquare', $gridsquare_like, 'after');
577+
$this->db->or_like('col_vucc_grids', $gridsquare_contains);
578+
$this->db->group_end();
565579

566580
if ($band != 'All') {
567581
if ($band == 'SAT') {
568-
$sql .= " and col_prop_mode ='" . $band . "'";
582+
$this->db->where('col_prop_mode', $band);
569583
} else {
570-
$sql .= " and col_prop_mode !='SAT'";
571-
$sql .= " and col_band ='" . $band . "'";
584+
$this->db->where('col_prop_mode !=', 'SAT');
585+
$this->db->where('col_band', $band);
572586
}
573587
}
574588

575-
return $this->db->query($sql);
589+
return $this->db->get();
576590
}
577591

578592
public function activator_details($call, $band, $leogeo)
@@ -1374,6 +1388,22 @@ function edit()
13741388
$data['COL_QRZCOM_QSO_UPLOAD_STATUS'] = 'M';
13751389
}
13761390

1391+
if ($this->exists_clublog_credentials($data['station_id'])) {
1392+
$data['COL_CLUBLOG_QSO_UPLOAD_STATUS'] = 'M';
1393+
}
1394+
1395+
// Reset LoTW and eQSL sent status to 'N' if they were previously sent
1396+
// This ensures edited QSOs get re-uploaded to these services
1397+
if ($qso->COL_LOTW_QSL_SENT == 'Y' && $data['COL_LOTW_QSL_SENT'] == 'Y') {
1398+
$data['COL_LOTW_QSL_SENT'] = 'N';
1399+
$data['COL_LOTW_QSLSDATE'] = null;
1400+
}
1401+
1402+
if ($qso->COL_EQSL_QSL_SENT == 'Y' && $data['COL_EQSL_QSL_SENT'] == 'Y') {
1403+
$data['COL_EQSL_QSL_SENT'] = 'N';
1404+
$data['COL_EQSL_QSLSDATE'] = null;
1405+
}
1406+
13771407
$this->db->where('COL_PRIMARY_KEY', $this->input->post('id'));
13781408
$this->db->update($this->config->item('table_name'), $data);
13791409
}

application/views/interface_assets/footer.php

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1885,7 +1885,59 @@ function getUTCDateStamp(el) {
18851885
var now = new Date();
18861886
var localTime = now.getTime();
18871887
var utc = localTime + (now.getTimezoneOffset() * 60000);
1888-
$(el).attr('value', ("0" + now.getUTCDate()).slice(-2) + '-' + ("0" + (now.getUTCMonth() + 1)).slice(-2) + '-' + now.getUTCFullYear());
1888+
1889+
// Get user's date format preference
1890+
var userDateFormat = '<?php
1891+
if ($this->session->userdata('user_date_format')) {
1892+
echo $this->session->userdata('user_date_format');
1893+
} else {
1894+
echo $this->config->item('qso_date_format');
1895+
}
1896+
?>';
1897+
1898+
// Format date according to user preference
1899+
var day = ("0" + now.getUTCDate()).slice(-2);
1900+
var month = ("0" + (now.getUTCMonth() + 1)).slice(-2);
1901+
var year2 = now.getUTCFullYear().toString().slice(-2);
1902+
var year4 = now.getUTCFullYear();
1903+
1904+
var formattedDate;
1905+
switch(userDateFormat) {
1906+
case 'd/m/y':
1907+
formattedDate = day + '/' + month + '/' + year2;
1908+
break;
1909+
case 'd/m/Y':
1910+
formattedDate = day + '/' + month + '/' + year4;
1911+
break;
1912+
case 'm/d/y':
1913+
formattedDate = month + '/' + day + '/' + year2;
1914+
break;
1915+
case 'm/d/Y':
1916+
formattedDate = month + '/' + day + '/' + year4;
1917+
break;
1918+
case 'd.m.Y':
1919+
formattedDate = day + '.' + month + '.' + year4;
1920+
break;
1921+
case 'y/m/d':
1922+
formattedDate = year2 + '/' + month + '/' + day;
1923+
break;
1924+
case 'Y-m-d':
1925+
formattedDate = year4 + '-' + month + '-' + day;
1926+
break;
1927+
case 'M d, Y':
1928+
var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
1929+
formattedDate = months[now.getUTCMonth()] + ' ' + now.getUTCDate() + ', ' + year4;
1930+
break;
1931+
case 'M d, y':
1932+
var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
1933+
formattedDate = months[now.getUTCMonth()] + ' ' + now.getUTCDate() + ', ' + year2;
1934+
break;
1935+
default:
1936+
// Fallback to original format if no match
1937+
formattedDate = day + '-' + month + '-' + year4;
1938+
}
1939+
1940+
$(el).attr('value', formattedDate);
18891941
}
18901942
</script>
18911943

application/views/mostworked/index.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
<div class="col-md-2">
5050
<label for="min_qsos" class="form-label">Min QSOs:</label>
5151
<select class="form-select form-select-sm" name="min_qsos" id="min_qsos">
52+
<option value="1" <?php echo ($filters['min_qsos'] == 1) ? 'selected' : ''; ?>>1+</option>
5253
<option value="2" <?php echo ($filters['min_qsos'] == 2) ? 'selected' : ''; ?>>2+</option>
5354
<option value="3" <?php echo ($filters['min_qsos'] == 3) ? 'selected' : ''; ?>>3+</option>
5455
<option value="5" <?php echo ($filters['min_qsos'] == 5) ? 'selected' : ''; ?>>5+</option>

assets/js/sections/common.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,48 @@ function qso_edit(id) {
153153
}
154154
});
155155

156+
// Add callsign change handler to update DXCC/location info
157+
$('.modal-content #callsign').on('change blur', function() {
158+
var callsignValue = $(this).val();
159+
if (callsignValue.length >= 3) {
160+
var find_callsign = callsignValue.toUpperCase();
161+
find_callsign = find_callsign.replace(/\//g, "-");
162+
find_callsign = find_callsign.replace('Ø', '0');
163+
164+
$.getJSON(base_url + 'index.php/logbook/json/' + find_callsign + '/0/0/0/' + $('.modal-content #stationProfile').val(), function(result) {
165+
if (result.dxcc && result.dxcc.entity !== undefined && result.dxcc.entity !== 'Not Found') {
166+
// Update country field
167+
$('.modal-content #country').val(result.dxcc.entity);
168+
169+
// Update DXCC ID
170+
if (result.dxcc.adif !== undefined) {
171+
$('.modal-content #dxcc_id').val(result.dxcc.adif);
172+
}
173+
174+
// Update CQ Zone
175+
if (result.dxcc.cqz !== undefined) {
176+
$('.modal-content #cqz').val(result.dxcc.cqz);
177+
}
178+
179+
// Update ITU Zone
180+
if (result.dxcc.ituz !== undefined) {
181+
$('.modal-content #ituz').val(result.dxcc.ituz);
182+
}
183+
184+
// Update continent
185+
if (result.dxcc.cont !== undefined) {
186+
$('.modal-content #continent').val(result.dxcc.cont);
187+
}
188+
189+
// Update state if available
190+
if (result.callsign_state && $('.modal-content #input_usa_state_edit').val() == "") {
191+
$('.modal-content #input_usa_state_edit').val(result.callsign_state).trigger('change');
192+
}
193+
}
194+
});
195+
}
196+
});
197+
156198
$('#locator').change(function(){
157199
if ($(this).val().length >= 4) {
158200
$.ajax({

0 commit comments

Comments
 (0)