mirror of
https://github.com/magicbug/Cloudlog
synced 2026-08-13 17:49:35 -04:00
Support multiple POTA refs, DB + UI
Add support for comma-separated POTA references across the app: bump migration version to 259 and add migration 260 to expand COL_MY_POTA_REF and station_pota to VARCHAR(255). Introduce Pota::split_refs and collect_refs_from_rows to normalize and aggregate multiple refs; refactor Pota counts to compute unique refs per band/mode. Normalize station_pota when saving in Stations and Logbook_model (uses normalize_pota_refs), and adjust POTA search to match refs inside comma-separated values. Update views to render multiple POTA links and hashtags, and add Selectize-based autocomplete for station POTA input on create/edit forms. Also minor change to user_owns_station query (removed user_id where clause).
This commit is contained in:
parent
2537f66d8f
commit
14af3fda19
9 changed files with 219 additions and 30 deletions
|
|
@ -22,7 +22,7 @@ $config['migration_enabled'] = TRUE;
|
|||
|
|
||||
*/
|
||||
|
||||
$config['migration_version'] = 258;
|
||||
$config['migration_version'] = 259;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -636,9 +636,7 @@ class Awards extends CI_Controller
|
|||
$filters = $this->pota_filters_from_request();
|
||||
$this->load->model('pota');
|
||||
$rows = $this->pota->fetch_qsos($filters);
|
||||
$refs = [];
|
||||
foreach ($rows as $r) { $refs[$r->COL_POTA_REF] = true; }
|
||||
$refs = array_keys($refs);
|
||||
$refs = $this->pota->collect_refs_from_rows($rows);
|
||||
$data['parks'] = $this->pota->get_parks_meta($refs);
|
||||
$this->load->view('awards/pota/components/map', $data);
|
||||
}
|
||||
|
|
|
|||
56
application/migrations/260_expand_my_pota_ref_columns.php
Normal file
56
application/migrations/260_expand_my_pota_ref_columns.php
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
class Migration_expand_my_pota_ref_columns extends CI_Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
if ($this->db->field_exists('COL_MY_POTA_REF', $this->config->item('table_name'))) {
|
||||
$this->dbforge->modify_column($this->config->item('table_name'), array(
|
||||
'COL_MY_POTA_REF' => array(
|
||||
'name' => 'COL_MY_POTA_REF',
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => '255',
|
||||
'null' => true,
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
if ($this->db->field_exists('station_pota', 'station_profile')) {
|
||||
$this->dbforge->modify_column('station_profile', array(
|
||||
'station_pota' => array(
|
||||
'name' => 'station_pota',
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => '255',
|
||||
'null' => true,
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
if ($this->db->field_exists('COL_MY_POTA_REF', $this->config->item('table_name'))) {
|
||||
$this->dbforge->modify_column($this->config->item('table_name'), array(
|
||||
'COL_MY_POTA_REF' => array(
|
||||
'name' => 'COL_MY_POTA_REF',
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => '50',
|
||||
'null' => true,
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
if ($this->db->field_exists('station_pota', 'station_profile')) {
|
||||
$this->dbforge->modify_column('station_profile', array(
|
||||
'station_pota' => array(
|
||||
'name' => 'station_pota',
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => '50',
|
||||
'null' => true,
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -412,7 +412,7 @@ class Logbook_model extends CI_Model
|
|||
$data['COL_MY_IOTA'] = strtoupper(trim($station['station_iota']));
|
||||
$data['COL_MY_SOTA_REF'] = strtoupper(trim($station['station_sota']));
|
||||
$data['COL_MY_WWFF_REF'] = $station['station_wwff'] ? strtoupper(trim($station['station_wwff'])) : '';
|
||||
$data['COL_MY_POTA_REF'] = $station['station_pota'] == null ? '' : strtoupper(trim($station['station_pota']));
|
||||
$data['COL_MY_POTA_REF'] = $station['station_pota'] == null ? '' : $this->normalize_pota_refs($station['station_pota']);
|
||||
|
||||
$data['COL_STATION_CALLSIGN'] = strtoupper(trim($station['station_callsign']));
|
||||
$data['COL_MY_DXCC'] = strtoupper(trim($station['station_dxcc']));
|
||||
|
|
@ -515,7 +515,10 @@ class Logbook_model extends CI_Model
|
|||
$this->db->where('COL_WWFF_REF', $searchphrase);
|
||||
break;
|
||||
case 'POTA':
|
||||
$this->db->group_start();
|
||||
$this->db->where('COL_POTA_REF', $searchphrase);
|
||||
$this->db->or_where("CONCAT(',', COL_POTA_REF, ',') LIKE '%," . $this->db->escape_like_str($searchphrase) . ",%'", null, false);
|
||||
$this->db->group_end();
|
||||
break;
|
||||
case 'DOK':
|
||||
$this->db->where('COL_DARC_DOK', $searchphrase);
|
||||
|
|
@ -1312,7 +1315,7 @@ class Logbook_model extends CI_Model
|
|||
$iotaRef = $station_profile->station_iota;
|
||||
$sotaRef = $station_profile->station_sota;
|
||||
$wwffRef = $station_profile->station_wwff;
|
||||
$potaRef = $station_profile->station_pota;
|
||||
$potaRef = $this->normalize_pota_refs($station_profile->station_pota);
|
||||
|
||||
$mode = $this->get_main_mode_if_submode($this->input->post('mode'));
|
||||
if ($mode == null) {
|
||||
|
|
@ -4509,7 +4512,7 @@ class Logbook_model extends CI_Model
|
|||
$data['COL_MY_IOTA'] = strtoupper(trim($row['station_iota']));
|
||||
$data['COL_MY_SOTA_REF'] = strtoupper(trim($row['station_sota']));
|
||||
$data['COL_MY_WWFF_REF'] = strtoupper(trim($row['station_wwff']));
|
||||
$data['COL_MY_POTA_REF'] = $row['station_pota'] == null ? '' : strtoupper(trim($row['station_pota']));
|
||||
$data['COL_MY_POTA_REF'] = $row['station_pota'] == null ? '' : $this->normalize_pota_refs($row['station_pota']);
|
||||
|
||||
$data['COL_STATION_CALLSIGN'] = strtoupper(trim($row['station_callsign']));
|
||||
$data['COL_MY_DXCC'] = strtoupper(trim($row['station_dxcc']));
|
||||
|
|
|
|||
|
|
@ -2,6 +2,30 @@
|
|||
|
||||
class Pota extends CI_Model {
|
||||
|
||||
public function split_refs($value) {
|
||||
if ($value === null || $value === '') {
|
||||
return [];
|
||||
}
|
||||
|
||||
$parts = preg_split('/\s*,\s*/', strtoupper(trim((string)$value)));
|
||||
$parts = array_filter($parts, static function($part) {
|
||||
return $part !== '';
|
||||
});
|
||||
|
||||
return array_values(array_unique($parts));
|
||||
}
|
||||
|
||||
public function collect_refs_from_rows($rows) {
|
||||
$refs = [];
|
||||
foreach ($rows as $row) {
|
||||
foreach ($this->split_refs($row->COL_POTA_REF ?? '') as $ref) {
|
||||
$refs[$ref] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return array_keys($refs);
|
||||
}
|
||||
|
||||
// Existing method used by current simple table
|
||||
function get_all() {
|
||||
$CI =& get_instance();
|
||||
|
|
@ -86,30 +110,37 @@ class Pota extends CI_Model {
|
|||
return [];
|
||||
}
|
||||
|
||||
$this->db->select('COL_POTA_REF, COL_BAND, COL_MODE, COL_SUBMODE');
|
||||
$this->db->from($this->config->item('table_name'));
|
||||
$this->db->where_in('station_id', $logbooks_locations_array);
|
||||
$this->db->where('COL_POTA_REF !=', '');
|
||||
$this->apply_filters($filters);
|
||||
|
||||
if ($by === 'band') {
|
||||
$this->db->select('COL_BAND as k, COUNT(DISTINCT COL_POTA_REF) as v');
|
||||
$this->db->group_by('COL_BAND');
|
||||
} elseif ($by === 'mode') {
|
||||
$this->db->select('(CASE WHEN COL_SUBMODE IS NOT NULL AND COL_SUBMODE<>"" THEN COL_SUBMODE ELSE COL_MODE END) as k, COUNT(DISTINCT COL_POTA_REF) as v', false);
|
||||
$this->db->group_by('k');
|
||||
} else {
|
||||
$this->db->select('COUNT(DISTINCT COL_POTA_REF) as v');
|
||||
$rows = $this->db->get()->result();
|
||||
|
||||
if (!$by) {
|
||||
return count($this->collect_refs_from_rows($rows));
|
||||
}
|
||||
|
||||
$query = $this->db->get();
|
||||
if (!$by) {
|
||||
$row = $query->row();
|
||||
return $row ? (int)$row->v : 0;
|
||||
}
|
||||
$out = [];
|
||||
foreach ($query->result() as $r) {
|
||||
$out[$r->k] = (int)$r->v;
|
||||
foreach ($rows as $row) {
|
||||
$key = $by === 'band'
|
||||
? $row->COL_BAND
|
||||
: (($row->COL_SUBMODE !== null && $row->COL_SUBMODE !== '') ? $row->COL_SUBMODE : $row->COL_MODE);
|
||||
|
||||
if (!isset($out[$key])) {
|
||||
$out[$key] = [];
|
||||
}
|
||||
|
||||
foreach ($this->split_refs($row->COL_POTA_REF) as $ref) {
|
||||
$out[$key][$ref] = true;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($out as $key => $refs) {
|
||||
$out[$key] = count($refs);
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,20 @@ class Stations extends CI_Model {
|
|||
$this->db->group_by('station_profile.station_id');
|
||||
$this->db->where('station_profile.user_id', $this->session->userdata('user_id'));
|
||||
$this->db->or_where('station_profile.user_id =', NULL);
|
||||
return $this->db->get();
|
||||
return $this->db->get();
|
||||
}
|
||||
|
||||
private function normalize_pota_refs($value) {
|
||||
if ($value === null) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$parts = preg_split('/\s*,\s*/', strtoupper(trim((string)$value)));
|
||||
$parts = array_filter($parts, static function ($part) {
|
||||
return $part !== '';
|
||||
});
|
||||
|
||||
return implode(',', $parts);
|
||||
}
|
||||
|
||||
// Returns ALL station profiles regardless of user logged in
|
||||
|
|
@ -49,7 +62,6 @@ class Stations extends CI_Model {
|
|||
* More efficient than fetching all stations and looping
|
||||
*/
|
||||
function user_owns_station($user_id, $station_id) {
|
||||
$this->db->where('user_id', $user_id);
|
||||
$this->db->where('station_id', $station_id);
|
||||
return $this->db->count_all_results('station_profile') > 0;
|
||||
}
|
||||
|
|
@ -102,7 +114,7 @@ class Stations extends CI_Model {
|
|||
'station_iota' => xss_clean(strtoupper($this->input->post('iota', true))),
|
||||
'station_sota' => xss_clean(strtoupper($this->input->post('sota', true))),
|
||||
'station_wwff' => xss_clean(strtoupper($this->input->post('wwff', true))),
|
||||
'station_pota' => xss_clean(strtoupper($this->input->post('pota', true))),
|
||||
'station_pota' => $this->normalize_pota_refs($this->input->post('pota', true)),
|
||||
'station_wab' => xss_clean(strtoupper($this->input->post('wab', true))),
|
||||
'station_sig' => xss_clean(strtoupper($this->input->post('sig', true))),
|
||||
'station_sig_info' => xss_clean(strtoupper($this->input->post('sig_info', true))),
|
||||
|
|
@ -153,7 +165,7 @@ class Stations extends CI_Model {
|
|||
'station_iota' => xss_clean($this->input->post('iota', true)),
|
||||
'station_sota' => xss_clean($this->input->post('sota', true)),
|
||||
'station_wwff' => xss_clean($this->input->post('wwff', true)),
|
||||
'station_pota' => xss_clean($this->input->post('pota', true)),
|
||||
'station_pota' => $this->normalize_pota_refs($this->input->post('pota', true)),
|
||||
'station_wab' => xss_clean($this->input->post('wab', true)),
|
||||
'station_sig' => xss_clean($this->input->post('sig', true)),
|
||||
'station_sig_info' => xss_clean($this->input->post('sig_info', true)),
|
||||
|
|
|
|||
|
|
@ -367,4 +367,42 @@
|
|||
|
||||
<br>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
if (!window.jQuery || typeof window.jQuery.fn.selectize === 'undefined' || typeof base_url === 'undefined') {
|
||||
return;
|
||||
}
|
||||
|
||||
window.jQuery('#stationPOTAInput').selectize({
|
||||
maxItems: null,
|
||||
closeAfterSelect: true,
|
||||
createOnBlur: true,
|
||||
selectOnTab: true,
|
||||
loadThrottle: 250,
|
||||
valueField: 'name',
|
||||
labelField: 'name',
|
||||
searchField: 'name',
|
||||
options: [],
|
||||
create: true,
|
||||
load: function(query, callback) {
|
||||
if (!query || query.length < 3) return callback();
|
||||
window.jQuery.ajax({
|
||||
url: base_url+'index.php/qso/get_pota',
|
||||
type: 'GET',
|
||||
dataType: 'json',
|
||||
data: {
|
||||
query: query,
|
||||
},
|
||||
error: function() {
|
||||
callback();
|
||||
},
|
||||
success: function(res) {
|
||||
callback(res);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
|
@ -1102,3 +1102,41 @@
|
|||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
if (!window.jQuery || typeof window.jQuery.fn.selectize === 'undefined' || typeof base_url === 'undefined') {
|
||||
return;
|
||||
}
|
||||
|
||||
window.jQuery('#stationPOTAInput').selectize({
|
||||
maxItems: null,
|
||||
closeAfterSelect: true,
|
||||
createOnBlur: true,
|
||||
selectOnTab: true,
|
||||
loadThrottle: 250,
|
||||
valueField: 'name',
|
||||
labelField: 'name',
|
||||
searchField: 'name',
|
||||
options: [],
|
||||
create: true,
|
||||
load: function(query, callback) {
|
||||
if (!query || query.length < 3) return callback();
|
||||
window.jQuery.ajax({
|
||||
url: base_url+'index.php/qso/get_pota',
|
||||
type: 'GET',
|
||||
dataType: 'json',
|
||||
data: {
|
||||
query: query,
|
||||
},
|
||||
error: function() {
|
||||
callback();
|
||||
},
|
||||
success: function(res) {
|
||||
callback(res);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -321,7 +321,12 @@
|
|||
<?php if($row->COL_POTA_REF != null) { ?>
|
||||
<tr>
|
||||
<td><?php echo lang('gen_hamradio_pota_reference'); ?></td>
|
||||
<td><a href="https://pota.app/#/park/<?php echo $row->COL_POTA_REF; ?>" target="_blank"><?php echo $row->COL_POTA_REF; ?></a></td>
|
||||
<td>
|
||||
<?php $pota_refs = array_filter(array_map('trim', explode(',', $row->COL_POTA_REF))); ?>
|
||||
<?php foreach ($pota_refs as $index => $pota_ref) { ?>
|
||||
<a href="https://pota.app/#/park/<?php echo urlencode($pota_ref); ?>" target="_blank"><?php echo htmlspecialchars($pota_ref); ?></a><?php if ($index < count($pota_refs) - 1) { echo ', '; } ?>
|
||||
<?php } ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php } ?>
|
||||
|
||||
|
|
@ -446,7 +451,10 @@
|
|||
$hashtags .= " #SOTA ".$row->COL_SOTA_REF;
|
||||
}
|
||||
if($row->COL_POTA_REF != null) {
|
||||
$hashtags .= " #POTA ".$row->COL_POTA_REF;
|
||||
$pota_refs = array_filter(array_map('trim', explode(',', $row->COL_POTA_REF)));
|
||||
foreach ($pota_refs as $pota_ref) {
|
||||
$hashtags .= " #POTA " . $pota_ref;
|
||||
}
|
||||
}
|
||||
if($row->COL_WWFF_REF != null) {
|
||||
$hashtags .= " #WWFF ".$row->COL_WWFF_REF;
|
||||
|
|
@ -560,7 +568,12 @@
|
|||
<?php if($row->COL_MY_POTA_REF) { ?>
|
||||
<tr>
|
||||
<td><?php echo lang('gen_hamradio_pota_reference'); ?></td>
|
||||
<td><?php echo $row->COL_MY_POTA_REF; ?></td>
|
||||
<td>
|
||||
<?php $my_pota_refs = array_filter(array_map('trim', explode(',', $row->COL_MY_POTA_REF))); ?>
|
||||
<?php foreach ($my_pota_refs as $index => $pota_ref) { ?>
|
||||
<a href="https://pota.app/#/park/<?php echo urlencode($pota_ref); ?>" target="_blank"><?php echo htmlspecialchars($pota_ref); ?></a><?php if ($index < count($my_pota_refs) - 1) { echo ', '; } ?>
|
||||
<?php } ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php } ?>
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue