[Station Location] Import / export

This commit is contained in:
Andreas Kristiansen
2025-11-04 10:13:41 +01:00
parent 3c087176a2
commit a96bbab727
3 changed files with 256 additions and 24 deletions

View File

@@ -528,4 +528,86 @@ class Stationsetup extends CI_Controller {
$this->load->view('stationsetup/locationlist');
$this->load->view('interface_assets/footer');
}
public function export_locations() {
$this->load->model('stationsetup_model');
$locations = $this->stationsetup_model->list_all_locations();
// Output as JSON
$this->output
->set_content_type('application/json')
->set_output(json_encode($locations));
}
public function import_locations(){
if (empty($_FILES['file']['tmp_name'])) {
$this->output
->set_content_type('application/json')
->set_output(json_encode(['status' => 'error', 'message' => 'No file uploaded']));
return;
}
$fileContent = file_get_contents($_FILES['file']['tmp_name']);
$locations = json_decode($fileContent, true);
if ($locations === null) {
$this->output
->set_content_type('application/json')
->set_output(json_encode(['status' => 'error', 'message' => 'Invalid JSON file']));
return;
}
// Load your model
$this->load->model('stationsetup_model');
$imported = 0;
foreach ($locations as $loc) {
// Data for station_profile
$dbdata = [
'station_active' => 0,
'station_profile_name' => $loc['station_profile_name'] ?? null,
'station_gridsquare' => $loc['station_gridsquare'] ?? null,
'station_city' => $loc['station_city'] ?? null,
'station_iota' => $loc['station_iota'] ?? null,
'station_sota' => $loc['station_sota'] ?? null,
'station_callsign' => $loc['station_callsign'] ?? null,
'station_power' => $loc['station_power'] ?? null,
'station_dxcc' => $loc['station_dxcc'] ?? null,
'station_cq' => $loc['station_cq'] ?? null,
'station_itu' => $loc['station_itu'] ?? null,
'station_sig' => $loc['station_sig'] ?? null,
'station_sig_info' => $loc['station_sig_info'] ?? null,
'station_wwff' => $loc['station_wwff'] ?? null,
'station_pota' => $loc['station_pota'] ?? null,
'state' => $loc['state'] ?? null,
'station_cnty' => $loc['station_cnty'] ?? null,
'qrzrealtime' => $loc['qrzrealtime'] ?? 0,
'oqrs' => $loc['oqrs'] ?? 0,
'oqrs_text' => $loc['oqrs_text'] ?? null,
'oqrs_email' => $loc['oqrs_email'] ?? null,
'webadifrealtime' => $loc['webadifrealtime'] ?? null,
'clublogignore' => $loc['clublogignore'] ?? 1,
'clublogrealtime' => $loc['clublogrealtime'] ?? 0,
'hrdlogrealtime' => $loc['hrdlogrealtime'] ?? 0,
'hrdlog_username' => $loc['hrdlog_username'] ?? null,
'eqslqthnickname' => $loc['eqslqthnickname'] ?? null,
'webadifapiurl' => 'https://qo100dx.club/api',
'user_id' => $this->session->userdata('user_id'),
];
// Data for user_options
$optiondata = [
'eqsl_default_qslmsg' => $loc['eqsl_default_qslmsg'] ?? null,
];
// Insert or update location in DB
$imported += $this->stationsetup_model->save_location($dbdata, $optiondata);
}
$this->output
->set_content_type('application/json')
->set_output(json_encode(['status' => 'success', 'message' => "$imported locations imported."]));
}
}

View File

@@ -234,7 +234,7 @@ class Stationsetup_model extends CI_Model {
}
function list_all_locations() {
$sql = "select dxcc_entities.end, station_profile.station_id, station_profile_name, station_gridsquare, station_city, station_iota, station_sota, station_callsign, station_power, station_dxcc, dxcc_entities.name as dxccname, dxcc_entities.prefix as dxccprefix, station_cnty, station_cq, station_itu, station_active, eqslqthnickname, state, county, station_sig, station_sig_info, qrzrealtime, station_wwff, station_pota, oqrs, oqrs_text, oqrs_email, webadifrealtime, clublogrealtime, clublogignore, hrdlogrealtime, creation_date, last_modified
$sql = "select dxcc_entities.end, station_profile.station_id, station_profile_name, station_profile.hrdlog_username, station_gridsquare, station_city, station_iota, station_sota, station_callsign, station_power, station_dxcc, dxcc_entities.name as dxccname, dxcc_entities.prefix as dxccprefix, station_cnty, station_cq, station_itu, station_active, eqslqthnickname, state, county, station_sig, station_sig_info, qrzrealtime, station_wwff, station_pota, oqrs, oqrs_text, oqrs_email, webadifrealtime, clublogrealtime, clublogignore, hrdlogrealtime, creation_date, last_modified
from station_profile
join dxcc_entities on station_profile.station_dxcc = dxcc_entities.adif
where user_id = ?";
@@ -254,6 +254,66 @@ class Stationsetup_model extends CI_Model {
return $result;
}
public function save_location($dbdata, $optiondata) {
// Make sure we have the needed fields
if (empty($dbdata['station_profile_name']) || empty($dbdata['station_callsign'])) {
return false;
}
// Check if a location exists with same parameters
$sql = "
SELECT *
FROM station_profile
WHERE station_profile_name = ?
AND station_callsign = ?
AND station_gridsquare = ?
AND station_city = ?
AND station_iota = ?
AND station_sota = ?
AND state = ?
AND station_cnty = ?
AND station_dxcc = ?
AND station_wwff = ?
AND station_pota = ?
AND station_sig = ?
AND station_sig_info = ?
AND user_id = ?;
";
$query = $this->db->query($sql, [
$dbdata['station_profile_name'],
$dbdata['station_callsign'],
$dbdata['station_gridsquare'],
$dbdata['station_city'],
$dbdata['station_iota'],
$dbdata['station_sota'],
$dbdata['state'],
$dbdata['station_cnty'],
$dbdata['station_dxcc'],
$dbdata['station_wwff'],
$dbdata['station_pota'],
$dbdata['station_sig'],
$dbdata['station_sig_info'],
$this->session->userdata('user_id')
]);
if ($query->num_rows() > 0) {
// Location already exists
return 0;
} else {
// Insert new location
$this->db->insert('station_profile', $dbdata);
$location_id = $this->db->insert_id();
if (!empty(trim($optiondata['eqsl_default_qslmsg']))) {
$this->user_options_model->set_option('eqsl_default_qslmsg', 'key_station_id', array($location_id => $optiondata['eqsl_default_qslmsg']));
}
}
return 1;
}
}
?>

View File

@@ -1,3 +1,4 @@
<div class="container-fluid pt-3 ps-4 pe-4">
<h2><?= $page_title ?></h2>
<?php if (!empty($locations)): ?>
@@ -33,6 +34,7 @@
<th>ClubLog realtime upload</th>
<th>ClubLog Ignore</th>
<th>HRDLog realtime upload</th>
<th>HRDLog username</th>
<th>Created</th>
<th>Last Modified</th>
</tr>
@@ -72,6 +74,7 @@
<td><?php echo $loc->clublogrealtime ? 'Yes' : 'No' ?></td>
<td><?php echo $loc->clublogignore ? 'Yes' : 'No' ?></td>
<td><?php echo $loc->hrdlogrealtime ? 'Yes' : 'No' ?></td>
<td><?php echo $loc->hrdlog_username; ?></td>
<td><?php echo $loc->creation_date; ?></td>
<td><?php echo $loc->last_modified; ?></td>
</tr>
@@ -85,27 +88,114 @@
</div>
<script>
document.addEventListener("DOMContentLoaded", function() {
$('.table').DataTable({
"pageLength": 25,
responsive: false,
ordering: true,
"scrollY": window.innerHeight - 250,
"scrollCollapse": true,
"paging": false,
"scrollX": true,
"language": {
url: getDataTablesLanguageUrl(),
},
dom: 'Bfrtip',
buttons: [
{
extend: 'csv',
className: 'mb-1 btn btn-sm btn-primary', // Bootstrap classes
init: function(api, node, config) {
$(node).removeClass('dt-button').addClass('btn btn-primary'); // Ensure Bootstrap class applies
},
}
]
});
});
$('.table').DataTable({
"pageLength": 25,
responsive: false,
ordering: true,
"scrollY": window.innerHeight - 250,
"scrollCollapse": true,
"paging": false,
"scrollX": true,
"language": {
url: getDataTablesLanguageUrl(),
},
dom: 'Bfrtip',
buttons: [
{
extend: 'csv',
className: 'mb-1 btn btn-sm btn-primary',
init: function(api, node, config) {
$(node).removeClass('dt-button').addClass('btn btn-primary');
},
},
{
text: 'Export All Locations',
className: 'mb-1 btn btn-sm btn-primary', // same Bootstrap style
action: function(e, dt, node, config) {
exportAllLocations();
},
init: function(api, node, config) {
$(node).removeClass('dt-button').addClass('btn btn-primary');
}
},
{
text: 'Import Locations',
className: 'mb-1 btn btn-sm btn-primary',
action: function(e, dt, node, config) {
// Create a hidden file input (accept JSON)
const input = document.createElement('input');
input.type = 'file';
input.accept = 'application/json';
input.style.display = 'none';
input.addEventListener('change', function(event) {
const file = event.target.files[0];
if (!file) return;
const formData = new FormData();
formData.append('file', file);
const url = base_url + 'index.php/stationsetup/import_locations';
fetch(url, {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(result => {
console.log("Import result:", result);
showToast('Info', result.message || "Import completed successfully!", 'bg-info text-dark', 4000);
})
.catch(error => {
console.error("Import failed:", error);
showToast('Error', 'Import failed. Check console for details.', 'bg-danger text-white', 5000);
});
});
document.body.appendChild(input);
input.click(); // Trigger file chooser
document.body.removeChild(input);
},
init: function(api, node, config) {
$(node).removeClass('dt-button').addClass('btn btn-primary');
}
}
]
});
});
function exportAllLocations() {
const url = base_url + 'index.php/stationsetup/export_locations';
fetch(url)
.then(response => {
if (!response.ok) {
showToast('Error', 'Network response was not ok (${response.status})', 'bg-danger text-white', 5000);
}
return response.json();
})
.then(data => {
// Convert JSON to string
const jsonStr = JSON.stringify(data, null, 2);
// Create a downloadable blob
const blob = new Blob([jsonStr], { type: "application/json" });
const link = document.createElement("a");
link.href = URL.createObjectURL(blob);
link.download = "locations.json";
// Trigger download
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
})
.catch(error => {
showToast('Error', 'Failed to export locations. Check console for details.', 'bg-danger text-white', 5000);
});
}
</script>
</div>