Merge pull request #3061 from wavelog/dev

Release 2.3.1
This commit is contained in:
Florian (DF2ET)
2026-03-13 17:31:17 +01:00
committed by GitHub
406 changed files with 69832 additions and 64994 deletions

View File

@@ -1,7 +1,7 @@
name: Report a bug ❌
description: Report a bug in Wavelog
title: "Choose a descriptive title......"
labels: ["bug"]
labels: ["needs triage"]
body:
- type: markdown
attributes:

View File

@@ -10,33 +10,141 @@ env:
IMAGE_NAME: ${{ github.repository }}
jobs:
build:
prepare:
runs-on: ubuntu-latest
outputs:
image_name: ${{ steps.lowercase.outputs.image_name }}
steps:
- name: Set lowercase image name
id: lowercase
run: echo "image_name=$(echo '${{ env.IMAGE_NAME }}' | tr '[:upper:]' '[:lower:]')" >> $GITHUB_OUTPUT
build-amd64:
runs-on: ubuntu-latest
needs: prepare
permissions:
contents: read
packages: write
outputs:
digest: ${{ steps.build.outputs.digest }}
steps:
- uses: actions/checkout@v4
- name: 'Login to GitHub Container Registry'
uses: docker/login-action@v1
- uses: actions/checkout@v6
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{github.actor}}
password: ${{secrets.GITHUB_TOKEN}}
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
images: ${{ env.REGISTRY }}/${{ needs.prepare.outputs.image_name }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and push (amd64)
id: build
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64
outputs: type=image,name=${{ env.REGISTRY }}/${{ needs.prepare.outputs.image_name }},push-by-digest=true,name-canonical=true,push=true
labels: ${{ steps.meta.outputs.labels }}
build-arm64:
runs-on: ubuntu-24.04-arm
needs: prepare
permissions:
contents: read
packages: write
outputs:
digest: ${{ steps.build.outputs.digest }}
steps:
- uses: actions/checkout@v6
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ needs.prepare.outputs.image_name }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and push (arm64)
id: build
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/arm64
outputs: type=image,name=${{ env.REGISTRY }}/${{ needs.prepare.outputs.image_name }},push-by-digest=true,name-canonical=true,push=true
labels: ${{ steps.meta.outputs.labels }}
build-armv7:
runs-on: ubuntu-24.04-arm
needs: prepare
permissions:
contents: read
packages: write
outputs:
digest: ${{ steps.build.outputs.digest }}
steps:
- uses: actions/checkout@v6
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ needs.prepare.outputs.image_name }}
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and push
uses: docker/build-push-action@v5
- name: Build and push (arm/v7)
id: build
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm64,linux/arm/v7
push: true
tags: ${{ steps.meta.outputs.tags }}
platforms: linux/arm/v7
outputs: type=image,name=${{ env.REGISTRY }}/${{ needs.prepare.outputs.image_name }},push-by-digest=true,name-canonical=true,push=true
labels: ${{ steps.meta.outputs.labels }}
merge:
runs-on: ubuntu-latest
needs:
- prepare
- build-amd64
- build-arm64
- build-armv7
permissions:
contents: read
packages: write
steps:
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ needs.prepare.outputs.image_name }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Create and push multi-arch manifest
run: |
docker buildx imagetools create \
$(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
${{ env.REGISTRY }}/${{ needs.prepare.outputs.image_name }}@${{ needs.build-amd64.outputs.digest }} \
${{ env.REGISTRY }}/${{ needs.prepare.outputs.image_name }}@${{ needs.build-arm64.outputs.digest }} \
${{ env.REGISTRY }}/${{ needs.prepare.outputs.image_name }}@${{ needs.build-armv7.outputs.digest }}

View File

@@ -1,4 +1,4 @@
FROM php:8.3-apache
FROM php:8.4-apache
ENV CI_ENV=docker
COPY --from=ghcr.io/mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/
@@ -27,7 +27,7 @@ max_execution_time = 600\n" > $PHP_INI_DIR/conf.d/wavelog.ini
COPY ./ /var/www/html/
WORKDIR /var/www/html
# Setting permissions as: https://github.com/wavelog/Wavelog/wiki/Installation
# Setting permissions as: https://docs.wavelog.org/getting-started/installation/linux/#3-set-directory-ownership-and-permissions
RUN mkdir ./application/config/docker; \
mv ./htaccess.sample ./.htaccess; \
sed -i "s/\$config\['index_page'\] = 'index.php';/\$config\['index_page'\] = '';/g" ./install/config/config.php; \

File diff suppressed because one or more lines are too long

View File

@@ -433,7 +433,7 @@ $config['error_views_path'] = '';
|
*/
$config['cache_path'] = '';
$config['cache_adapter'] = 'file';
$config['cache_adapter'] = 'apcu';
$config['cache_backup'] = 'file';
$config['cache_key_prefix'] = '';
@@ -736,7 +736,7 @@ $config['disable_oqrs'] = false;
| This config switch is meant for Special Callsign operations or Clubstations.
| If this switch is set to true it enables a whole bunch of features to handle Special Callsigns and Club Callsigns.
| For more Information please visit the Wiki:
| https://github.com/wavelog/wavelog/wiki/Clubstations
| https://docs.wavelog.org/admin-guide/administration/clubstations/
|
| !!! Important !!!
| $config['disable_impersonate'] has to be set to false to use this feature.
@@ -892,6 +892,19 @@ $config['max_login_attempts'] = 3;
$config['enable_dxcluster_file_cache_band'] = false;
$config['enable_dxcluster_file_cache_worked'] = false;
/*
|--------------------------------------------------------------------------
| DXCluster Refresh Time
|--------------------------------------------------------------------------
| This defines the how often the DXCluster spots are refreshed in seconds. Default is 30 seconds.
| Be careful with this and do not set it too low because depending on how many QSOs a user has it
| can cause a lot of load on the server. Also consider enabling a proper caching (file caches are
| not recommended for very large installations) to reduce the load on the server.
|--------------------------------------------------------------------------
*/
$config['dxcluster_refresh_time'] = 30;
/*
|--------------------------------------------------------------------------
| Internal tools

View File

@@ -22,7 +22,7 @@ $config['migration_enabled'] = TRUE;
|
*/
$config['migration_version'] = 271;
$config['migration_version'] = 272;
/*
|--------------------------------------------------------------------------

View File

@@ -44,8 +44,8 @@ class Activated_gridmap extends CI_Controller {
$footerData['scripts'] = [
'assets/js/leaflet/geocoding.js',
'assets/js/leaflet/L.MaidenheadColouredGridMap.js',
'assets/js/sections/gridmap.js?',
'assets/js/bootstrap-multiselect.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/bootstrap-multiselect.js")),
'assets/js/sections/gridmap.js',
'assets/js/bootstrap-multiselect.js',
];
$this->load->view('interface_assets/header', $data);

View File

@@ -50,7 +50,7 @@ class Activators extends CI_Controller
$footerData = [];
$footerData['scripts'] = [
'assets/js/sections/activators.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/activators.js")),
'assets/js/sections/activators.js',
];
$this->load->view('interface_assets/header', $data);

View File

@@ -728,6 +728,80 @@ class API extends CI_Controller {
}
// API function to check if a grid is in the logbook already
function logbook_get_worked_grids() {
$arr = array();
header('Content-type: application/json');
$this->load->model('api_model');
$obj = json_decode(file_get_contents("php://input"), true);
if ($obj === NULL) {
echo json_encode(['status' => 'failed', 'reason' => "wrong JSON"]);
die();
}
// Check rate limit
$identifier = isset($obj['key']) ? $obj['key'] : null;
$this->check_rate_limit('logbook_get_worked_grids', $identifier);
if(!isset($obj['key']) || $this->api_model->authorize($obj['key']) == 0) {
http_response_code(401);
echo json_encode(['status' => 'failed', 'reason' => "missing api key"]);
die();
}
$api_user_id = $this->api_model->key_userid($obj['key']);
if(!isset($obj['logbook_public_slug'])) {
http_response_code(400);
echo json_encode(['status' => 'failed', 'reason' => "missing fields"]);
return;
}
if($obj['logbook_public_slug'] != "") {
$logbook_slug = $obj['logbook_public_slug'];
if(isset($obj['band'])) {
$band = $obj['band'];
} else {
$band = null;
}
if(isset($obj['cnfm'])) {
$cnfm = $obj['cnfm'];
} else {
$cnfm = null;
}
$this->load->model('logbooks_model');
if(!$this->logbooks_model->public_slug_belongs_to_user($logbook_slug, $api_user_id)) {
http_response_code(403);
echo json_encode(['status' => 'failed', 'reason' => "logbook does not belong to this api key"]);
die();
}
if($this->logbooks_model->public_slug_exists($logbook_slug)) {
$logbook_id = $this->logbooks_model->public_slug_exists_logbook_id($logbook_slug);
if($logbook_id != false)
{
$logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($logbook_id);
if (!$logbooks_locations_array) {
http_response_code(404);
echo json_encode(['status' => 'failed', 'reason' => "Empty Logbook"]);
die();
}
} else {
http_response_code(404);
echo json_encode(['status' => 'failed', 'reason' => $logbook_slug." has no associated station locations"]);
die();
}
$this->load->model('logbook_model');
$arr = $this->api_model->get_grids_worked_in_logbook($logbooks_locations_array, $band, $cnfm);
http_response_code(201);
echo json_encode($arr);
} else {
http_response_code(404);
echo json_encode(['status' => 'failed', 'reason' => "logbook not found"]);
die();
}
}
}
/* ENDPOINT for Rig Control */
function radio() {
@@ -962,7 +1036,7 @@ class API extends CI_Controller {
];
$return['callsign'] = $lookup_callsign;
$dxccobj = new Dxcc(null);
$dxccobj = new Dxcc();
$callsign_dxcc_lookup = $dxccobj->dxcc_lookup($lookup_callsign, $date);
$last_slash_pos = strrpos($lookup_callsign, '/');
@@ -1122,7 +1196,7 @@ class API extends CI_Controller {
$return['callsign'] = $lookup_callsign;
// Use Wavelog\Dxcc\Dxcc for faster in-memory lookup
$dxccobj = new Dxcc($date);
$dxccobj = new Dxcc();
$callsign_dxcc_lookup = $dxccobj->dxcc_lookup($lookup_callsign, $date);
$return['dxcc_id'] = $callsign_dxcc_lookup['adif'] ?? '';
@@ -1146,8 +1220,6 @@ class API extends CI_Controller {
$return['qsl_manager'] = $call_lookup_results->COL_QSL_VIA;
$return['state'] = $call_lookup_results->COL_STATE;
$return['us_county'] = $call_lookup_results->COL_CNTY;
$return['dxcc_id'] = $call_lookup_results->COL_DXCC;
$return['cont'] = $call_lookup_results->COL_CONT;
$return['workedBefore'] = true;
if ($return['gridsquare'] != "") {
@@ -1309,4 +1381,55 @@ class API extends CI_Controller {
return $url;
}
/* **
* List members of a clubstation
* API key needs to be of a club officer (permission level 9)
* returns array of club member details
*/
function list_clubmembers() {
header('Content-type: application/json');
$this->load->model('api_model');
// Decode JSON and store
$obj = json_decode(file_get_contents("php://input"), true);
if ($obj === NULL) {
http_response_code(400);
echo json_encode(['status' => 'failed', 'reason' => "wrong JSON"]);
return;
}
if ($this->api_model->access($obj['key']) == "No Key Found" || $this->api_model->access($obj['key']) == "Key Disabled") {
http_response_code(401);
echo json_encode(['status' => 'error', 'message' => 'Auth Error, invalid key']);
return;
}
$this->load->model('club_model');
$userid = $this->api_model->key_userid($obj['key']);
$created_by = $this->api_model->key_created_by($obj['key']);
$club_perm = $this->club_model->get_permission_noui($userid,$created_by);
if (($userid == $created_by) || (($club_perm ?? 0) != 9)) { // not club officer
http_response_code(401);
echo json_encode(['status' => 'error', 'message' => 'Auth Error, not enough permissions for this operation']);
return;
}
$memberlist = $this->club_model->get_club_members($userid);
if (!empty($memberlist)) {
foreach($memberlist as $member) {
$members[] = [
'callsign' => $member->user_callsign,
'user_name' => $member->user_name,
'p_level' => $member->p_level
];
}
http_response_code(200);
echo json_encode(['status' => 'successful', 'members' => $members]);
} else {
http_response_code(204);
echo json_encode(['status' => 'failed', 'reason' => "No club members found", 'members' => '']);
return;
}
}
}

View File

@@ -36,7 +36,6 @@ class Awards extends CI_Controller {
public function dok ()
{
$this->load->model('logbooks_model');
$logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($this->session->userdata('active_station_logbook'));
$data['user_map_custom'] = $this->optionslib->get_map_custom();
@@ -110,6 +109,9 @@ class Awards extends CI_Controller {
$this->load->model('dxcc');
$this->load->model('modes');
$this->load->model('bands');
$this->load->model('logbooks_model');
$logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($this->session->userdata('active_station_logbook'));
$data['orbits'] = $this->bands->get_worked_orbits();
$data['sats_available'] = $this->bands->get_worked_sats();
@@ -183,16 +185,25 @@ class Awards extends CI_Controller {
$postdata['dateTo'] = null;
}
$dxcclist = $this->dxcc->fetchdxcc($postdata);
if ($dxcclist && $dxcclist[0]->adif == "0") {
unset($dxcclist[0]);
}
$data['dxcc_array'] = $this->dxcc->get_dxcc_array($dxcclist, $bands, $postdata);
$data['dxcc_summary'] = $this->dxcc->get_dxcc_summary($bands, $postdata);
if ($logbooks_locations_array) {
$location_list = "'".implode("','",$logbooks_locations_array)."'";
$dxcclist = $this->dxcc->fetchdxcc($postdata, $location_list);
if ($dxcclist && $dxcclist[0]->adif == "0") {
unset($dxcclist[0]);
}
$dxcc_result = $this->dxcc->get_dxcc_array($dxcclist, $bands, $postdata, $location_list);
// Extract bands data and summary from the result
$data['dxcc_array'] = ($dxcc_result && isset($dxcc_result['matrix'])) ? $dxcc_result['matrix'] : null;
$data['dxcc_summary'] = ($dxcc_result && isset($dxcc_result['summary'])) ? $dxcc_result['summary'] : null;
} else {
$location_list = null;
$data['dxcc_array'] = null;
$data['dxcc_summary'] = null;
}
// Render Page
$data['page_title'] = sprintf(__("Awards - %s"), __("DXCC"));
$data['posted_band']=$postdata['band'];
$data['posted_band'] = $postdata['band'];
$this->load->view('interface_assets/header', $data);
$this->load->view('awards/dxcc/index');
$this->load->view('interface_assets/footer');
@@ -200,6 +211,10 @@ class Awards extends CI_Controller {
public function wapc () {
$footerData = [];
$footerData['scripts'] = [
'assets/js/sections/wapcmap.js',
'assets/js/leaflet/L.Maidenhead.js',
];
$this->load->model('wapc');
$this->load->model('modes');
@@ -277,7 +292,7 @@ class Awards extends CI_Controller {
public function waja () {
$footerData = [];
$footerData['scripts'] = [
'assets/js/sections/wajamap.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/wajamap.js")),
'assets/js/sections/wajamap.js',
'assets/js/leaflet/L.Maidenhead.js',
];
@@ -357,8 +372,8 @@ class Awards extends CI_Controller {
public function jcc () {
$footerData = [];
$footerData['scripts'] = [
'assets/js/sections/jcc.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/jcc.js")),
'assets/js/sections/jccmap.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/jccmap.js"))
'assets/js/sections/jcc.js',
'assets/js/sections/jccmap.js'
];
$this->load->model('jcc_model');
@@ -483,7 +498,6 @@ class Awards extends CI_Controller {
public function vucc_band(){
$this->load->model('vucc');
$data['user_map_custom'] = $this->optionslib->get_map_custom();
$band = str_replace('"', "", $this->security->xss_clean($this->input->get("Band")));
$type = str_replace('"', "", $this->security->xss_clean($this->input->get("Type")));
$data['vucc_array'] = $this->vucc->vucc_details($band, $type);
@@ -558,7 +572,8 @@ class Awards extends CI_Controller {
// Render Page
$data['page_title'] = __("Log View")." - " . $type;
$data['filter'] = (($type != $band) ? $type : '')." ".$searchphrase.__(" and band ").$band;
$data['filter'] = (($type != $band) ? $type : '')." ".$searchphrase." ".__("and")." ";
$data['filter'] .= ($band == 'All' ? lcfirst(__("Every band (w/o SAT)")) : __("band")." ".$band);
if ($band == 'SAT') {
if ($sat != 'All' && $sat != null) {
$data['filter'] .= __(" and satellite ").$sat;
@@ -637,8 +652,8 @@ class Awards extends CI_Controller {
public function cq() {
$footerData = [];
$footerData['scripts'] = [
'assets/js/sections/cqmap_geojson.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/cqmap_geojson.js")),
'assets/js/sections/cqmap.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/cqmap.js"))
'assets/js/sections/cqmap_geojson.js',
'assets/js/sections/cqmap.js'
];
$this->load->model('logbooks_model');
@@ -666,37 +681,43 @@ class Awards extends CI_Controller {
$data['bands'] = $bands; // Used for displaying selected band(s) in the table in the view
if($this->input->method() === 'post') {
$postdata['qsl'] = $this->security->xss_clean($this->input->post('qsl'));
$postdata['lotw'] = $this->security->xss_clean($this->input->post('lotw'));
$postdata['eqsl'] = $this->security->xss_clean($this->input->post('eqsl'));
$postdata['qrz'] = $this->security->xss_clean($this->input->post('qrz'));
$postdata['worked'] = $this->security->xss_clean($this->input->post('worked'));
$postdata['confirmed'] = $this->security->xss_clean($this->input->post('confirmed'));
$postdata['notworked'] = $this->security->xss_clean($this->input->post('notworked'));
$postdata['band'] = $this->security->xss_clean($this->input->post('band'));
if($this->input->method() === 'post') {
$postdata['qsl'] = ($this->input->post('qsl',true) ?? 0) == 0 ? NULL: 1;
$postdata['lotw'] = ($this->input->post('lotw',true) ?? 0) == 0 ? NULL: 1;
$postdata['eqsl'] = ($this->input->post('eqsl',true) ?? 0) == 0 ? NULL: 1;
$postdata['qrz'] = ($this->input->post('qrz',true) ?? 0) == 0 ? NULL: 1;
$postdata['clublog'] = ($this->input->post('clublog',true) ?? 0) == 0 ? NULL: 1;
$postdata['worked'] = ($this->input->post('worked',true) ?? 0) == 0 ? NULL: 1;
$postdata['confirmed'] = ($this->input->post('confirmed',true) ?? 0) == 0 ? NULL: 1;
$postdata['notworked'] = ($this->input->post('notworked',true) ?? 0) == 0 ? NULL: 1;
$postdata['band'] = $this->security->xss_clean($this->input->post('band'));
$postdata['mode'] = $this->security->xss_clean($this->input->post('mode'));
$postdata['datefrom'] = $this->security->xss_clean($this->input->post('dateFrom'));
$postdata['dateto'] = $this->security->xss_clean($this->input->post('dateTo'));
}
else { // Setting default values at first load of page
$postdata['qsl'] = 1;
$postdata['lotw'] = 1;
$postdata['eqsl'] = 0;
$postdata['qrz'] = 0;
$postdata['worked'] = 1;
$postdata['confirmed'] = 1;
$postdata['notworked'] = 1;
$postdata['band'] = 'All';
}
else { // Setting default values at first load of page
$postdata['qsl'] = 1;
$postdata['lotw'] = 1;
$postdata['eqsl'] = NULL;
$postdata['qrz'] = NULL;
$postdata['clublog'] = NULL;
$postdata['worked'] = 1;
$postdata['confirmed'] = 1;
$postdata['notworked'] = 1;
$postdata['band'] = 'All';
$postdata['mode'] = 'All';
$postdata['datefrom'] = null;
$postdata['dateto'] = null;
}
}
$data['posted_band'] = $postdata['band'];
if ($logbooks_locations_array) {
$location_list = "'".implode("','",$logbooks_locations_array)."'";
$data['cq_array'] = $this->cq->get_cq_array($bands, $postdata, $location_list);
$data['cq_summary'] = $this->cq->get_cq_summary($bands, $postdata, $location_list);
$cq_result = $this->cq->get_cq_array($bands, $postdata, $location_list);
// Extract bands data and summary from the result
$data['cq_array'] = ($cq_result && isset($cq_result['bands'])) ? $cq_result['bands'] : null;
$data['cq_summary'] = ($cq_result && isset($cq_result['summary'])) ? $cq_result['summary'] : null;
} else {
$location_list = null;
$data['cq_array'] = null;
@@ -713,7 +734,7 @@ class Awards extends CI_Controller {
public function was() {
$footerData = [];
$footerData['scripts'] = [
'assets/js/sections/wasmap.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/wasmap.js")),
'assets/js/sections/wasmap.js',
'assets/js/leaflet/L.Maidenhead.js',
];
@@ -775,7 +796,7 @@ class Awards extends CI_Controller {
public function rac() {
$footerData = [];
$footerData['scripts'] = [
'assets/js/sections/racmap.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/racmap.js")),
'assets/js/sections/racmap.js',
'assets/js/leaflet/L.Maidenhead.js',
];
@@ -837,7 +858,7 @@ class Awards extends CI_Controller {
public function helvetia() {
$footerData = [];
$footerData['scripts'] = [
'assets/js/sections/helvetiamap.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/helvetiamap.js")),
'assets/js/sections/helvetiamap.js',
'assets/js/leaflet/L.Maidenhead.js',
];
@@ -1367,7 +1388,7 @@ class Awards extends CI_Controller {
public function wap() {
$footerData = [];
$footerData['scripts'] = [
'assets/js/sections/wapmap.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/wapmap.js")),
'assets/js/sections/wapmap.js',
'assets/js/leaflet/L.Maidenhead.js',
];
@@ -1600,8 +1621,16 @@ class Awards extends CI_Controller {
$logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($this->session->userdata('active_station_logbook'));
$this->load->model('cq');
$this->load->model('bands');
$bands[] = $this->input->post('band');
$data['worked_bands'] = $this->bands->get_worked_bands('cq');
if ($this->input->post('band') == 'All') {
$bands = $data['worked_bands'];
}
else {
$bands[] = $this->input->post('band');
}
$postdata['qsl'] = $this->input->post('qsl') == 0 ? NULL: 1;
$postdata['lotw'] = $this->input->post('lotw') == 0 ? NULL: 1;
@@ -1613,36 +1642,15 @@ class Awards extends CI_Controller {
$postdata['notworked'] = $this->input->post('notworked') == 0 ? NULL: 1;
$postdata['band'] = $this->security->xss_clean($this->input->post('band'));
$postdata['mode'] = $this->security->xss_clean($this->input->post('mode'));
$postdata['datefrom'] = $this->security->xss_clean($this->input->post('datefrom'));
$postdata['dateto'] = $this->security->xss_clean($this->input->post('dateto'));
$postdata['datefrom'] = $this->security->xss_clean($this->input->post('dateFrom'));
$postdata['dateto'] = $this->security->xss_clean($this->input->post('dateTo'));
if ($logbooks_locations_array) {
$location_list = "'".implode("','",$logbooks_locations_array)."'";
$cq_array = $this->cq->get_cq_array($bands, $postdata, $location_list, $this->user_map_color_qso, $this->user_map_color_qsoconfirm);
$zones = $this->cq->get_cq_array($bands, $postdata, $location_list, true);
} else {
$location_list = null;
$cq_array = null;
}
$zones = array();
foreach ($cq_array as $cq => $value) {
foreach ($value as $key) {
if($key != "") {
if (strpos($key, '>W<') !== false) {
$zones[] = 'W';
break;
}
if (strpos($key, '>C<') !== false) {
$zones[] = 'C';
break;
}
if (strpos($key, '-') !== false) {
$zones[] = '-';
break;
}
}
}
$zones = array();
}
header('Content-Type: application/json');
@@ -1705,64 +1713,134 @@ class Awards extends CI_Controller {
echo json_encode($prefectures);
}
/*
function wapc_map
*/
public function wapc_map() {
$this->load->model('wapc');
$this->load->model('bands');
$bands[] = $this->security->xss_clean($this->input->post('band'));
$postdata['qsl'] = $this->input->post('qsl') == 0 ? NULL: 1;
$postdata['lotw'] = $this->input->post('lotw') == 0 ? NULL: 1;
$postdata['eqsl'] = $this->input->post('eqsl') == 0 ? NULL: 1;
$postdata['qrz'] = $this->input->post('qrz') == 0 ? NULL: 1;
$postdata['worked'] = $this->input->post('worked') == 0 ? NULL: 1;
$postdata['clublog'] = $this->input->post('clublog') == 0 ? NULL: 1;
$postdata['confirmed'] = $this->input->post('confirmed') == 0 ? NULL: 1;
$postdata['notworked'] = $this->input->post('notworked') == 0 ? NULL: 1;
$postdata['band'] = $this->input->post('band', TRUE);
$postdata['mode'] = $this->input->post('mode', TRUE);
$wapc_array = $this->wapc->get_wapc_array($bands, $postdata);
$provinces = array();
$wapcArray = array_keys($this->wapc->cnProvinces);
foreach ($wapcArray as $state) {
$provinces[$state] = '-';
}
foreach ($wapc_array as $wapc => $value) {
foreach ($value as $key) {
if($key != "") {
if (strpos($key, '>W<') !== false) {
$provinces[$wapc] = 'W';
break;
}
if (strpos($key, '>C<') !== false) {
$provinces[$wapc] = 'C';
break;
}
if (strpos($key, '-') !== false) {
$provinces[$wapc] = '-';
break;
}
}
}
}
header('Content-Type: application/json');
echo json_encode($provinces);
}
/*
function dxcc_map
This displays the DXCC map
*/
public function dxcc_map() {
$this->load->model('dxcc');
$this->load->model('bands');
$this->load->model('dxcc');
$this->load->model('bands');
$bands[] = $this->security->xss_clean($this->input->post('band'));
$data['worked_bands'] = $this->bands->get_worked_bands('dxcc');
$postdata['qsl'] = ($this->input->post('qsl',true) ?? 0) == 0 ? NULL: 1;
$postdata['lotw'] = ($this->input->post('lotw',true) ?? 0) == 0 ? NULL: 1;
$postdata['eqsl'] = ($this->input->post('eqsl',true) ?? 0) == 0 ? NULL: 1;
$postdata['qrz'] = ($this->input->post('qrz',true) ?? 0) == 0 ? NULL: 1;
$postdata['clublog'] = ($this->input->post('clublog',true) ?? 0) == 0 ? NULL: 1;
$postdata['worked'] = ($this->input->post('worked',true) ?? 0) == 0 ? NULL: 1;
$postdata['confirmed'] = ($this->input->post('confirmed',true) ?? 0) == 0 ? NULL: 1;
$postdata['notworked'] = ($this->input->post('notworked',true) ?? 0) == 0 ? NULL: 1;
if ($this->input->post('band') == 'All') {
$bands = $data['worked_bands'];
}
else {
$bands[] = $this->input->post('band');
}
$postdata['includedeleted'] = ($this->input->post('includedeleted',true) ?? 0) == 0 ? NULL: 1;
$postdata['Africa'] = ($this->input->post('Africa',true) ?? 0) == 0 ? NULL: 1;
$postdata['Asia'] = ($this->input->post('Asia',true) ?? 0) == 0 ? NULL: 1;
$postdata['Europe'] = ($this->input->post('Europe',true) ?? 0) == 0 ? NULL: 1;
$postdata['NorthAmerica'] = ($this->input->post('NorthAmerica',true) ?? 0) == 0 ? NULL: 1;
$postdata['SouthAmerica'] = ($this->input->post('SouthAmerica',true) ?? 0) == 0 ? NULL: 1;
$postdata['Oceania'] = ($this->input->post('Oceania',true) ?? 0) == 0 ? NULL: 1;
$postdata['Antarctica'] = ($this->input->post('Antarctica',true) ?? 0) == 0 ? NULL: 1;
$postdata['band'] = $this->security->xss_clean($this->input->post('band'));
$postdata['mode'] = $this->security->xss_clean($this->input->post('mode'));
$postdata['sat'] = $this->security->xss_clean($this->input->post('sat'));
$postdata['orbit'] = $this->security->xss_clean($this->input->post('orbit'));
$bands[] = $this->security->xss_clean($this->input->post('band'));
$postdata['qsl'] = ($this->input->post('qsl',true) ?? 0) == 0 ? NULL: 1;
$postdata['lotw'] = ($this->input->post('lotw',true) ?? 0) == 0 ? NULL: 1;
$postdata['eqsl'] = ($this->input->post('eqsl',true) ?? 0) == 0 ? NULL: 1;
$postdata['qrz'] = ($this->input->post('qrz',true) ?? 0) == 0 ? NULL: 1;
$postdata['clublog'] = ($this->input->post('clublog',true) ?? 0) == 0 ? NULL: 1;
$postdata['worked'] = ($this->input->post('worked',true) ?? 0) == 0 ? NULL: 1;
$postdata['confirmed'] = ($this->input->post('confirmed',true) ?? 0) == 0 ? NULL: 1;
$postdata['notworked'] = ($this->input->post('notworked',true) ?? 0) == 0 ? NULL: 1;
$postdata['includedeleted'] = ($this->input->post('includedeleted',true) ?? 0) == 0 ? NULL: 1;
$postdata['Africa'] = ($this->input->post('Africa',true) ?? 0) == 0 ? NULL: 1;
$postdata['Asia'] = ($this->input->post('Asia',true) ?? 0) == 0 ? NULL: 1;
$postdata['Europe'] = ($this->input->post('Europe',true) ?? 0) == 0 ? NULL: 1;
$postdata['NorthAmerica'] = ($this->input->post('NorthAmerica',true) ?? 0) == 0 ? NULL: 1;
$postdata['SouthAmerica'] = ($this->input->post('SouthAmerica',true) ?? 0) == 0 ? NULL: 1;
$postdata['Oceania'] = ($this->input->post('Oceania',true) ?? 0) == 0 ? NULL: 1;
$postdata['Antarctica'] = ($this->input->post('Antarctica',true) ?? 0) == 0 ? NULL: 1;
$postdata['band'] = $this->security->xss_clean($this->input->post('band'));
$postdata['mode'] = $this->security->xss_clean($this->input->post('mode'));
$postdata['sat'] = $this->security->xss_clean($this->input->post('sat'));
$postdata['orbit'] = $this->security->xss_clean($this->input->post('orbit'));
$postdata['dateFrom'] = $this->security->xss_clean($this->input->post('dateFrom'));
$postdata['dateTo'] = $this->security->xss_clean($this->input->post('dateTo'));
$dxcclist = $this->dxcc->fetchdxcc($postdata);
if ($dxcclist[0]->adif == "0") {
unset($dxcclist[0]);
}
$this->load->model('logbooks_model');
$logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($this->session->userdata('active_station_logbook'));
$dxcc_array = $this->dxcc->get_dxcc_array($dxcclist, $bands, $postdata);
if ($logbooks_locations_array) {
$location_list = "'".implode("','",$logbooks_locations_array)."'";
$dxcclist = $this->dxcc->fetchdxcc($postdata, $location_list);
if ($dxcclist[0]->adif == "0") {
unset($dxcclist[0]);
}
$dxcc_array = $this->dxcc->get_dxcc_array($dxcclist, $bands, $postdata, $location_list, true);
} else {
$location_list = null;
$dxcc_array = array();
}
$i = 0;
$i = 0;
foreach ($dxcclist as $dxcc) {
$newdxcc[$i]['adif'] = $dxcc->adif;
$newdxcc[$i]['prefix'] = $dxcc->prefix;
$newdxcc[$i]['name'] = ucwords(strtolower($dxcc->name), "- (/");
if ($dxcc->Enddate!=null) {
$newdxcc[$i]['name'] .= ' (deleted)';
}
$newdxcc[$i]['lat'] = $dxcc->lat;
$newdxcc[$i]['long'] = $dxcc->long;
$newdxcc[$i++]['status'] = isset($dxcc_array[$dxcc->adif]) ? $this->returnStatus($dxcc_array[$dxcc->adif]) : 'x';
}
foreach ($dxcclist as $dxcc) {
$newdxcc[$i]['adif'] = $dxcc->adif;
$newdxcc[$i]['prefix'] = $dxcc->prefix;
$newdxcc[$i]['name'] = ucwords(strtolower($dxcc->name), "- (/");
if ($dxcc->Enddate!=null) {
$newdxcc[$i]['name'] .= ' (deleted)';
}
$newdxcc[$i]['lat'] = $dxcc->lat;
$newdxcc[$i]['long'] = $dxcc->long;
$newdxcc[$i++]['status'] = isset($dxcc_array[$dxcc->adif]) ? $dxcc_array[$dxcc->adif] : 'x';
}
header('Content-Type: application/json');
echo json_encode($newdxcc);
header('Content-Type: application/json');
echo json_encode($newdxcc);
}
/*
@@ -1895,7 +1973,7 @@ class Awards extends CI_Controller {
$footerData = [];
$footerData['scripts'] = [
'assets/js/sections/wab.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/wab.js"))
'assets/js/sections/wab.js'
];
// Render page
@@ -1975,8 +2053,8 @@ class Awards extends CI_Controller {
public function itu() {
$footerData = [];
$footerData['scripts'] = [
'assets/js/sections/itumap_geojson.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/itumap_geojson.js")),
'assets/js/sections/itumap.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/itumap.js"))
'assets/js/sections/itumap_geojson.js',
'assets/js/sections/itumap.js'
];
$this->load->model('logbooks_model');
@@ -1985,9 +2063,9 @@ class Awards extends CI_Controller {
$this->load->model('itu');
$this->load->model('modes');
$this->load->model('bands');
$data['user_map_custom'] = $this->optionslib->get_map_custom();
$data['worked_bands'] = $this->bands->get_worked_bands('cq');
$data['user_map_custom'] = $this->optionslib->get_map_custom();
$data['modes'] = $this->modes->active(); // Used in the view for mode select
if ($this->input->post('band') != NULL) { // Band is not set when page first loads.
@@ -2004,35 +2082,43 @@ class Awards extends CI_Controller {
$data['bands'] = $bands; // Used for displaying selected band(s) in the table in the view
if($this->input->method() === 'post') {
$postdata['qsl'] = $this->security->xss_clean($this->input->post('qsl'));
$postdata['lotw'] = $this->security->xss_clean($this->input->post('lotw'));
$postdata['eqsl'] = $this->security->xss_clean($this->input->post('eqsl'));
$postdata['qrz'] = $this->security->xss_clean($this->input->post('qrz'));
$postdata['clublog'] = $this->security->xss_clean($this->input->post('clublog'));
$postdata['worked'] = $this->security->xss_clean($this->input->post('worked'));
$postdata['confirmed'] = $this->security->xss_clean($this->input->post('confirmed'));
$postdata['notworked'] = $this->security->xss_clean($this->input->post('notworked'));
$postdata['band'] = $this->security->xss_clean($this->input->post('band'));
$postdata['mode'] = $this->security->xss_clean($this->input->post('mode'));
}
else { // Setting default values at first load of page
$postdata['qsl'] = 1;
$postdata['lotw'] = 1;
$postdata['eqsl'] = 0;
$postdata['qrz'] = 0;
$postdata['clublog'] = 0;
$postdata['worked'] = 1;
$postdata['confirmed'] = 1;
$postdata['notworked'] = 1;
$postdata['band'] = 'All';
if($this->input->method() === 'post') {
$postdata['qsl'] = ($this->input->post('qsl',true) ?? 0) == 0 ? NULL: 1;
$postdata['lotw'] = ($this->input->post('lotw',true) ?? 0) == 0 ? NULL: 1;
$postdata['eqsl'] = ($this->input->post('eqsl',true) ?? 0) == 0 ? NULL: 1;
$postdata['qrz'] = ($this->input->post('qrz',true) ?? 0) == 0 ? NULL: 1;
$postdata['clublog'] = ($this->input->post('clublog',true) ?? 0) == 0 ? NULL: 1;
$postdata['worked'] = ($this->input->post('worked',true) ?? 0) == 0 ? NULL: 1;
$postdata['confirmed'] = ($this->input->post('confirmed',true) ?? 0) == 0 ? NULL: 1;
$postdata['notworked'] = ($this->input->post('notworked',true) ?? 0) == 0 ? NULL: 1;
$postdata['band'] = $this->security->xss_clean($this->input->post('band'));
$postdata['mode'] = $this->security->xss_clean($this->input->post('mode'));
$postdata['datefrom'] = $this->security->xss_clean($this->input->post('dateFrom'));
$postdata['dateto'] = $this->security->xss_clean($this->input->post('dateTo'));
}
else { // Setting default values at first load of page
$postdata['qsl'] = 1;
$postdata['lotw'] = 1;
$postdata['eqsl'] = NULL;
$postdata['qrz'] = NULL;
$postdata['clublog'] = NULL;
$postdata['worked'] = 1;
$postdata['confirmed'] = 1;
$postdata['notworked'] = 1;
$postdata['band'] = 'All';
$postdata['mode'] = 'All';
}
$postdata['datefrom'] = null;
$postdata['dateto'] = null;
}
$data['posted_band'] = $postdata['band'];
if ($logbooks_locations_array) {
$location_list = "'".implode("','",$logbooks_locations_array)."'";
$data['itu_array'] = $this->itu->get_itu_array($bands, $postdata, $location_list);
$data['itu_summary'] = $this->itu->get_itu_summary($bands, $postdata, $location_list);
$itu_result = $this->itu->get_itu_array($bands, $postdata, $location_list);
// Extract bands data and summary from the result
$data['itu_array'] = ($itu_result && isset($itu_result['bands'])) ? $itu_result['bands'] : null;
$data['itu_summary'] = ($itu_result && isset($itu_result['summary'])) ? $itu_result['summary'] : null;
} else {
$location_list = null;
$data['itu_array'] = null;
@@ -2055,8 +2141,16 @@ class Awards extends CI_Controller {
$logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($this->session->userdata('active_station_logbook'));
$this->load->model('itu');
$this->load->model('bands');
$bands[] = $this->input->post('band');
$data['worked_bands'] = $this->bands->get_worked_bands('cq');
if ($this->input->post('band') == 'All') {
$bands = $data['worked_bands'];
}
else {
$bands[] = $this->input->post('band');
}
$postdata['qsl'] = $this->input->post('qsl') == 0 ? NULL: 1;
$postdata['lotw'] = $this->input->post('lotw') == 0 ? NULL: 1;
@@ -2068,34 +2162,15 @@ class Awards extends CI_Controller {
$postdata['notworked'] = $this->input->post('notworked') == 0 ? NULL: 1;
$postdata['band'] = $this->security->xss_clean($this->input->post('band'));
$postdata['mode'] = $this->security->xss_clean($this->input->post('mode'));
$postdata['datefrom'] = $this->security->xss_clean($this->input->post('dateFrom'));
$postdata['dateto'] = $this->security->xss_clean($this->input->post('dateTo'));
if ($logbooks_locations_array) {
$location_list = "'".implode("','",$logbooks_locations_array)."'";
$itu_array = $this->itu->get_itu_array($bands, $postdata, $location_list);
$zones = $this->itu->get_itu_array($bands, $postdata, $location_list, true);
} else {
$location_list = null;
$itu_array = null;
}
$zones = array();
foreach ($itu_array as $itu => $value) {
foreach ($value as $key) {
if($key != "") {
if (strpos($key, '>W<') !== false) {
$zones[] = 'W';
break;
}
if (strpos($key, '>C<') !== false) {
$zones[] = 'C';
break;
}
if (strpos($key, '-') !== false) {
$zones[] = '-';
break;
}
}
}
$zones = array();
}
header('Content-Type: application/json');
@@ -2133,30 +2208,34 @@ class Awards extends CI_Controller {
$data['bands'] = $bands; // Used for displaying selected band(s) in the table in the view
if($this->input->method() === 'post') {
$postdata['qsl'] = $this->security->xss_clean($this->input->post('qsl'));
$postdata['lotw'] = $this->security->xss_clean($this->input->post('lotw'));
$postdata['eqsl'] = $this->security->xss_clean($this->input->post('eqsl'));
$postdata['qrz'] = $this->security->xss_clean($this->input->post('qrz'));
$postdata['worked'] = $this->security->xss_clean($this->input->post('worked'));
$postdata['confirmed'] = $this->security->xss_clean($this->input->post('confirmed'));
$postdata['notworked'] = $this->security->xss_clean($this->input->post('notworked'));
$postdata['qsl'] = ($this->input->post('qsl',true) ?? 0) == 0 ? NULL: 1;
$postdata['lotw'] = ($this->input->post('lotw',true) ?? 0) == 0 ? NULL: 1;
$postdata['eqsl'] = ($this->input->post('eqsl',true) ?? 0) == 0 ? NULL: 1;
$postdata['qrz'] = ($this->input->post('qrz',true) ?? 0) == 0 ? NULL: 1;
$postdata['clublog'] = ($this->input->post('clublog',true) ?? 0) == 0 ? NULL: 1;
$postdata['band'] = $this->security->xss_clean($this->input->post('band'));
$postdata['mode'] = $this->security->xss_clean($this->input->post('mode'));
$postdata['sat'] = $this->security->xss_clean($this->input->post('sats'));
$postdata['orbit'] = $this->security->xss_clean($this->input->post('orbits'));
$postdata['worked'] = ($this->input->post('worked',true) ?? 0) == 0 ? NULL: 1;
$postdata['confirmed'] = ($this->input->post('confirmed',true) ?? 0) == 0 ? NULL: 1;
$postdata['notworked'] = ($this->input->post('notworked',true) ?? 0) == 0 ? NULL: 1;
$postdata['band'] = $this->security->xss_clean($this->input->post('band'));
}
else { // Setting default values at first load of page
$postdata['qsl'] = 1;
$postdata['lotw'] = 1;
$postdata['eqsl'] = 0;
$postdata['qrz'] = 0;
$postdata['worked'] = 1;
$postdata['confirmed'] = 1;
$postdata['notworked'] = 1;
$postdata['eqsl'] = null;
$postdata['qrz'] = null;
$postdata['clublog'] = null;
$postdata['band'] = 'All';
$postdata['mode'] = 'All';
$postdata['sat'] = 'All';
$postdata['orbit'] = 'All';
$postdata['worked'] = 1;
$postdata['confirmed'] = 1;
$postdata['notworked'] = 1;
$postdata['band'] = 'All';
}
if ($logbooks_locations_array) {
@@ -2169,11 +2248,18 @@ class Awards extends CI_Controller {
$data['wac_summary'] = null;
}
$data['posted_band'] = $postdata['band'];
$footerData = [];
$footerData['scripts'] = [
'assets/js/sections/wac.js',
];
// Render page
$data['page_title'] = sprintf(__("Awards - %s"), __("Worked All Continents (WAC)"));
$this->load->view('interface_assets/header', $data);
$this->load->view('awards/wac/index');
$this->load->view('interface_assets/footer');
$this->load->view('interface_assets/footer', $footerData);
}
public function wae () {
@@ -2212,17 +2298,14 @@ class Awards extends CI_Controller {
$postdata['notworked'] = $this->input->post('notworked') == 0 ? NULL: 1;
$postdata['includedeleted'] = $this->security->xss_clean($this->input->post('includedeleted'));
$postdata['Africa'] = $this->security->xss_clean($this->input->post('Africa'));
$postdata['Asia'] = $this->security->xss_clean($this->input->post('Asia'));
$postdata['Europe'] = $this->security->xss_clean($this->input->post('Europe'));
$postdata['NorthAmerica'] = $this->security->xss_clean($this->input->post('NorthAmerica'));
$postdata['SouthAmerica'] = $this->security->xss_clean($this->input->post('SouthAmerica'));
$postdata['Oceania'] = $this->security->xss_clean($this->input->post('Oceania'));
$postdata['Antarctica'] = $this->security->xss_clean($this->input->post('Antarctica'));
$postdata['band'] = $this->security->xss_clean($this->input->post('band'));
$postdata['mode'] = $this->security->xss_clean($this->input->post('mode'));
$postdata['sat'] = $this->security->xss_clean($this->input->post('sats'));
$postdata['orbit'] = $this->security->xss_clean($this->input->post('orbits'));
$postdata['dateFrom'] = $this->security->xss_clean($this->input->post('dateFrom'));
$postdata['dateTo'] = $this->security->xss_clean($this->input->post('dateTo'));
} else { // Setting default values at first load of page
$postdata['qsl'] = 1;
$postdata['lotw'] = 1;
@@ -2232,21 +2315,19 @@ class Awards extends CI_Controller {
$postdata['confirmed'] = 1;
$postdata['notworked'] = 1;
$postdata['includedeleted'] = 0;
$postdata['Africa'] = 1;
$postdata['Asia'] = 1;
$postdata['Europe'] = 1;
$postdata['NorthAmerica'] = 1;
$postdata['SouthAmerica'] = 1;
$postdata['Oceania'] = 1;
$postdata['Antarctica'] = 1;
$postdata['band'] = 'All';
$postdata['mode'] = 'All';
$postdata['sat'] = 'All';
$postdata['orbit'] = 'All';
$postdata['dateFrom'] = null;
$postdata['dateTo'] = null;
}
$data['wae_array'] = $this->wae->get_wae_array($bands, $postdata);
$data['wae_summary'] = $this->wae->get_wae_summary($bands, $postdata);
$result = $this->wae->get_wae_array($bands, $postdata);
$data['wae_array'] = $result['matrix'] ?? null;
$data['wae_summary'] = $result['summary'] ?? null;
$data['posted_band'] = $postdata['band'];
// Render Page
$data['page_title'] = sprintf(__("Awards - %s"), __("WAE"));
@@ -2271,7 +2352,7 @@ class Awards extends CI_Controller {
public function wpx () {
$footerData = [];
$footerData['scripts'] = [
'assets/js/sections/wpx.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/wpx.js")),
'assets/js/sections/wpx.js',
];
$this->load->model('wpx');
@@ -2385,7 +2466,7 @@ class Awards extends CI_Controller {
public function pl_polska() {
$footerData = [];
$footerData['scripts'] = [
'assets/js/sections/award_pl_polska.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/award_pl_polska.js")),
'assets/js/sections/award_pl_polska.js',
'assets/js/leaflet/L.Maidenhead.js',
];

View File

@@ -36,7 +36,7 @@ class Band extends CI_Controller {
$footerData = [];
$footerData['scripts'] = [
'assets/js/sections/bandedges.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/bandedges.js")),
'assets/js/sections/bandedges.js',
];
// Render Page

View File

@@ -10,27 +10,6 @@ class Bandmap extends CI_Controller {
$this->load->model('bands');
}
function index() {
$this->load->model('cat');
$this->load->model('bands');
$data['radios'] = $this->cat->radios(true);
$data['bands'] = $this->bands->get_user_bands_for_qso_entry();
$footerData = [];
$footerData['scripts'] = [
'assets/js/highcharts/highcharts.js',
'assets/js/highcharts/timeline.js',
'assets/js/highcharts/exporting.js',
'assets/js/highcharts/accessibility.js',
'assets/js/sections/bandmap.js',
];
$data['page_title'] = __("DXCluster");
$this->load->view('interface_assets/header', $data);
$this->load->view('bandmap/index');
$this->load->view('interface_assets/footer', $footerData);
}
function list() {
$this->load->model('cat');
$this->load->model('bands');
@@ -41,13 +20,13 @@ class Bandmap extends CI_Controller {
$footerData = [];
$footerData['scripts'] = [
'assets/js/moment.min.js',
'assets/js/datetime-moment.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/datetime-moment.js")),
'assets/js/cat.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/cat.js")),
'assets/js/leaflet/leaflet.geodesic.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/leaflet/leaflet.geodesic.js")),
'assets/js/leaflet.polylineDecorator.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/leaflet.polylineDecorator.js")),
'assets/js/leaflet/L.Terminator.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/leaflet/L.Terminator.js")),
'assets/js/sections/callstats.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/callstats.js")),
'assets/js/sections/bandmap_list.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/bandmap_list.js")),
'assets/js/datetime-moment.js',
'assets/js/cat.js',
'assets/js/leaflet/leaflet.geodesic.js',
'assets/js/leaflet.polylineDecorator.js',
'assets/js/leaflet/L.Terminator.js',
'assets/js/sections/callstats.js',
'assets/js/sections/bandmap_list.js',
];
// Get Date format
@@ -60,18 +39,20 @@ class Bandmap extends CI_Controller {
}
switch ($pageData['custom_date_format']) {
case "d/m/y": $pageData['custom_date_format'] = 'DD/MM/YY'; break;
case "d/m/Y": $pageData['custom_date_format'] = 'DD/MM/YYYY'; break;
case "m/d/y": $pageData['custom_date_format'] = 'MM/DD/YY'; break;
case "m/d/Y": $pageData['custom_date_format'] = 'MM/DD/YYYY'; break;
case "d.m.Y": $pageData['custom_date_format'] = 'DD.MM.YYYY'; break;
case "y/m/d": $pageData['custom_date_format'] = 'YY/MM/DD'; break;
case "Y-m-d": $pageData['custom_date_format'] = 'YYYY-MM-DD'; break;
case "M d, Y": $pageData['custom_date_format'] = 'MMM DD, YYYY'; break;
case "M d, y": $pageData['custom_date_format'] = 'MMM DD, YY'; break;
default: $pageData['custom_date_format'] = 'DD/MM/YYYY';
case "d/m/y": $pageData['custom_date_format'] = 'DD/MM/YY'; break;
case "d/m/Y": $pageData['custom_date_format'] = 'DD/MM/YYYY'; break;
case "m/d/y": $pageData['custom_date_format'] = 'MM/DD/YY'; break;
case "m/d/Y": $pageData['custom_date_format'] = 'MM/DD/YYYY'; break;
case "d.m.Y": $pageData['custom_date_format'] = 'DD.MM.YYYY'; break;
case "y/m/d": $pageData['custom_date_format'] = 'YY/MM/DD'; break;
case "Y-m-d": $pageData['custom_date_format'] = 'YYYY-MM-DD'; break;
case "M d, Y": $pageData['custom_date_format'] = 'MMM DD, YYYY'; break;
case "M d, y": $pageData['custom_date_format'] = 'MMM DD, YY'; break;
default: $pageData['custom_date_format'] = 'DD/MM/YYYY';
}
$data['dxcluster_refresh_time'] = $this->config->item('dxcluster_refresh_time') ?? 30;
$data['page_title'] = __("DXCluster");
$this->load->view('interface_assets/header', $data);
$this->load->view('bandmap/list',$pageData);

View File

@@ -74,7 +74,7 @@ class Callstats extends CI_Controller
$footerData = [];
$footerData['scripts'] = [
'assets/js/sections/callstats.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/callstats.js")),
'assets/js/sections/callstats.js',
];
$this->load->view('interface_assets/header', $data);

File diff suppressed because it is too large Load Diff

View File

@@ -8,7 +8,7 @@ class Club extends CI_Controller
* 3 - Member
*
* These permission levels are independent of the codeigniter permission levels and managed in the club_permissions table!
* https://github.com/wavelog/wavelog/wiki/Clubstations
* https://docs.wavelog.org/admin-guide/administration/clubstations/
*/
/**
@@ -61,7 +61,7 @@ class Club extends CI_Controller
$footerData = [];
$footerData['scripts'] = [
'assets/js/sections/club_permissions.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/club_permissions.js")),
'assets/js/sections/club_permissions.js',
];
$this->load->view('interface_assets/header', $data);

View File

@@ -96,7 +96,7 @@ class Clublog extends CI_Controller
$footerData = [];
$footerData['scripts'] = [
'assets/js/sections/clublog.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/clublog.js")),
'assets/js/sections/clublog.js',
];
$this->load->view('interface_assets/header', $data);

View File

@@ -36,7 +36,7 @@ class Contestcalendar extends CI_Controller {
}
$footerData['scripts'] = [
'assets/js/sections/dxcalendar.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/dxcalendar.js"))
'assets/js/sections/dxcalendar.js'
];
} else {
$data['contestsToday']='';

View File

@@ -45,7 +45,7 @@ class Contesting extends CI_Controller {
$footerData = [];
$footerData['scripts'] = [
'assets/js/sections/contesting.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/contesting.js")),
'assets/js/sections/contesting.js',
];
$this->load->library('form_validation');
@@ -121,7 +121,7 @@ class Contesting extends CI_Controller {
$footerData = [];
$footerData['scripts'] = [
'assets/js/sections/contesting.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/contesting.js")),
'assets/js/sections/contesting.js',
];
// Render Page
@@ -143,7 +143,7 @@ class Contesting extends CI_Controller {
$footerData = [];
$footerData['scripts'] = [
'assets/js/sections/contesting.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/contesting.js")),
'assets/js/sections/contesting.js',
];
$this->form_validation->set_rules('name', 'Contest Name', 'required');

View File

@@ -31,8 +31,8 @@ class cron extends CI_Controller {
$footerData = [];
$footerData['scripts'] = [
'assets/js/cronstrue.min.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/cronstrue.min.js")),
'assets/js/sections/cron.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/cron.js"))
'assets/js/cronstrue.min.js',
'assets/js/sections/cron.js'
];
$data['page_title'] = __("Cron Manager");

View File

@@ -160,7 +160,7 @@ class Dashboard extends CI_Controller {
$dxcc = $this->dxcc->list_current();
$footerData['scripts'] = [
'assets/js/sections/dashboard.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/dashboard.js")),
'assets/js/sections/dashboard.js',
];
// First Login Wizard
@@ -189,7 +189,7 @@ class Dashboard extends CI_Controller {
$this->load->model('dxcc');
$viewdata['dxcc_list'] = $this->dxcc->list();
$footerData['scripts'][] = 'assets/js/bootstrap-multiselect.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/bootstrap-multiselect.js"));
$footerData['scripts'][] = 'assets/js/bootstrap-multiselect.js';
$this->load->library('form_validation');

View File

@@ -109,10 +109,10 @@ class Debug extends CI_Controller
$cache_info = $this->Debug_model->get_cache_info();
$data['cache_available_adapters'] = $cache_info['adapters'];
$data['cache_path'] = $cache_info['config']['cache_path'] ?: 'application/cache';
$data['cache_adapter'] = ucfirst($cache_info['config']['cache_adapter'] ?? 'file');
$data['cache_backup'] = ucfirst($cache_info['config']['cache_backup'] ?? 'file');
$data['cache_adapter'] = strtolower($cache_info['config']['cache_adapter'] ?? 'file');
$data['cache_backup'] = strtolower($cache_info['config']['cache_backup'] ?? 'file');
$data['cache_key_prefix'] = $cache_info['config']['cache_key_prefix'] ?: __("(empty)");
$data['active_adapter'] = ucfirst($cache_info['active']['adapter'] ?? ($cache_info['config']['cache_adapter'] ?? 'file'));
$data['active_adapter'] = strtolower($cache_info['active']['adapter'] ?? ($cache_info['config']['cache_adapter'] ?? 'file'));
$data['using_backup'] = !empty($cache_info['active']['using_backup']);
$data['details_cache_size'] = $cache_info['details']['size'] ?? '0 B';
$data['details_cache_keys_count'] = $cache_info['details']['keys_count'] ?? 0;

View File

@@ -80,7 +80,7 @@ class Distances extends CI_Controller {
// Render Page
$data['page_title'] = "Log View - " . $distance;
$data['filter'] = __("QSOs with") . " " . $distance . " " . __("and band"). " " . $band. __("and propagation"). " " . $propagation;
$data['filter'] = __("QSOs with") . " " . $distance . " " . __("and band"). " " . $band. " " . __("and propagation"). " " . $propagation;
$this->load->view('awards/details', $data);
}
}

View File

@@ -18,7 +18,7 @@ class Dxcalendar extends CI_Controller {
'backup' => $this->config->item('cache_backup') ?? 'file',
'key_prefix' => $this->config->item('cache_key_prefix') ?? ''
]);
$rssUrl = 'http://www.ng3k.com/adxo.xml';
$rssUrl = 'https://www.ng3k.com/adxo.xml';
if (!$rssRawData = $this->cache->get('RssRawDxCal')) {
$rssRawData = file_get_contents($rssUrl, true);
$this->cache->save('RssRawDxCal', $rssRawData, (60*60*12));
@@ -39,7 +39,7 @@ class Dxcalendar extends CI_Controller {
$custom_date_format = $this->config->item('qso_date_format');
}
$dxccobj = new Dxcc(null);
$dxccobj = new Dxcc();
foreach ($rssdata->channel->item as $item) {
$dxped=(object)[];
$title = explode('--', $item->title);
@@ -85,7 +85,7 @@ class Dxcalendar extends CI_Controller {
$footerData['scripts'] = [
'assets/js/sections/dxcalendar.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/dxcalendar.js"))
'assets/js/sections/dxcalendar.js'
];
$this->load->view('interface_assets/header', $data);

View File

@@ -66,7 +66,7 @@ class Dxcluster extends CI_Controller {
// TODO: Is this used anywhere? If not, remove it!
public function call($call) {
$date = date('Y-m-d', time());
$dxccobj = new Dxcc($date);
$dxccobj = new Dxcc();
$dxcc = $dxccobj->dxcc_lookup($call, $date);

View File

@@ -21,8 +21,8 @@ class Generic_qsl extends CI_Controller {
$footerData = [];
$footerData['scripts'] = [
'assets/js/bootstrap-multiselect.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/bootstrap-multiselect.js")),
'assets/js/sections/qsl.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/qsl.js")),
'assets/js/bootstrap-multiselect.js',
'assets/js/sections/qsl.js',
];
$this->load->view('interface_assets/header', $data);

View File

@@ -44,11 +44,11 @@ class Gridmap extends CI_Controller {
$footerData = [];
$footerData['scripts'] = [
'assets/js/leaflet/geocoding.js',
'assets/js/sections/gridmap.js?',
'assets/js/sections/gridmap.js',
'assets/js/leaflet/L.MaidenheadColouredGridMap.js',
'assets/js/sections/itumap_geojson.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/itumap_geojson.js")),
'assets/js/sections/cqmap_geojson.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/cqmap_geojson.js")),
'assets/js/bootstrap-multiselect.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/bootstrap-multiselect.js")),
'assets/js/sections/itumap_geojson.js',
'assets/js/sections/cqmap_geojson.js',
'assets/js/bootstrap-multiselect.js',
];
$this->load->view('interface_assets/header', $data);

View File

@@ -15,7 +15,7 @@ class Hamsat extends CI_Controller {
public function index() {
$data['scripts'] = [
'assets/js/sections/hamsat.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/hamsat.js")),
'assets/js/sections/hamsat.js',
'assets/js/moment.min.js',
'assets/js/datetime-moment.js'
];

View File

@@ -146,10 +146,11 @@ class Labels extends CI_Controller {
$qslmsg = $this->input->post('qslmsg') === "true" ? 1 : 0;
$tnxmsg = $this->input->post('tnxmsg') === "true" ? 1 : 0;
$reference = $this->input->post('reference') == "true" ? 1 : 0;
$mycall = $this->input->post('mycall') == "true" ? 1 : 0;
$this->load->model('labels_model');
$result = $this->labels_model->export_printrequestedids($ids);
$this->prepareLabel($result, true, $offset, $grid, $via, $reference, $qslmsg, $tnxmsg);
$this->prepareLabel($result, true, $offset, $grid, $via, $reference, $qslmsg, $tnxmsg, $mycall);
}
public function print($station_id) {
@@ -160,22 +161,22 @@ class Labels extends CI_Controller {
$qslmsg = xss_clean($this->input->post('qslmsg') ?? 0);
$tnxmsg = xss_clean($this->input->post('tnxmsg') ?? 0);
$reference = xss_clean($this->input->post('reference') ?? 0);
$mycall = $this->input->post('mycall') ?? 0;
$this->load->model('stations');
if ($this->stations->check_station_is_accessible($station_id)) {
$this->load->model('labels_model');
$result = $this->labels_model->export_printrequested($clean_id);
$this->prepareLabel($result, false, $offset, $grid, $via, $reference, $qslmsg, $tnxmsg);
$this->prepareLabel($result, false, $offset, $grid, $via, $reference, $qslmsg, $tnxmsg, $mycall);
} else {
redirect('labels');
}
}
function prepareLabel($qsos, $jscall = false, $offset = 1, $grid = false, $via = false, $reference = false, $qslmsg = false, $tnxmsg = true) {
function prepareLabel($qsos, $jscall = false, $offset = 1, $grid = false, $via = false, $reference = false, $qslmsg = false, $tnxmsg = true, $mycall = false) {
$this->load->model('labels_model');
$label = $this->labels_model->getDefaultLabel();
try {
if ($label) {
$label->font='DejaVuSans'; // Fix font to DejaVuSans
@@ -247,9 +248,9 @@ class Labels extends CI_Controller {
if ($qsos->num_rows() > 0) {
if ($label->qsos == 1) {
$this->makeMultiQsoLabel($qsos->result(), $pdf, 1, $offset, $ptype->orientation, $grid, $via, $reference, $qslmsg, $tnxmsg);
$this->makeMultiQsoLabel($qsos->result(), $pdf, 1, $offset, $ptype->orientation, $grid, $via, $reference, $qslmsg, $tnxmsg, $mycall);
} else {
$this->makeMultiQsoLabel($qsos->result(), $pdf, $label->qsos, $offset, $ptype->orientation, $grid, $via, $reference, $qslmsg, $tnxmsg);
$this->makeMultiQsoLabel($qsos->result(), $pdf, $label->qsos, $offset, $ptype->orientation, $grid, $via, $reference, $qslmsg, $tnxmsg, $mycall);
}
} else {
$this->session->set_flashdata('message', __('0 QSOs found for print!'));
@@ -258,7 +259,7 @@ class Labels extends CI_Controller {
$pdf->Output();
}
function makeMultiQsoLabel($qsos, $pdf, $numberofqsos, $offset, $orientation, $grid, $via, $reference, $qslmsg, $tnxmsg) {
function makeMultiQsoLabel($qsos, $pdf, $numberofqsos, $offset, $orientation, $grid, $via, $reference, $qslmsg, $tnxmsg, $mycall) {
$text = '';
$current_callsign = '';
$current_sat = '';
@@ -275,7 +276,7 @@ class Labels extends CI_Controller {
( ($qso->COL_BAND_RX !== $current_sat_bandrx) && ($this->pretty_sat_mode($qso->COL_SAT_MODE) !== '')) ) {
// ((($qso->COL_SAT_NAME ?? '' !== $current_sat) || ($qso->COL_CALL !== $current_callsign)) && ($qso->COL_SAT_NAME ?? '' !== '') && ($col->COL_BAND_RX ?? '' !== $current_sat_bandrx))) {
if (!empty($qso_data)) {
$this->finalizeData($pdf, $current_callsign, $qso_data, $numberofqsos, $orientation, $grid, $via, $reference, $qslmsg, $tnxmsg);
$this->finalizeData($pdf, $current_callsign, $qso_data, $numberofqsos, $orientation, $grid, $via, $reference, $qslmsg, $tnxmsg, $mycall);
$qso_data = [];
}
$current_callsign = $qso->COL_CALL;
@@ -307,7 +308,7 @@ class Labels extends CI_Controller {
];
}
if (!empty($qso_data)) {
$this->finalizeData($pdf, $current_callsign, $qso_data, $numberofqsos, $orientation, $grid, $via, $reference, $qslmsg, $tnxmsg);
$this->finalizeData($pdf, $current_callsign, $qso_data, $numberofqsos, $orientation, $grid, $via, $reference, $qslmsg, $tnxmsg, $mycall);
}
}
// New begin
@@ -315,7 +316,7 @@ class Labels extends CI_Controller {
return(strlen($sat_mode ?? '') == 2 ? (strtoupper($sat_mode[0]).'/'.strtoupper($sat_mode[1])) : strtoupper($sat_mode ?? ''));
}
function finalizeData($pdf, $current_callsign, &$preliminaryData, $qso_per_label,$orientation, $grid, $via, $reference, $qslmsg, $tnxmsg) {
function finalizeData($pdf, $current_callsign, &$preliminaryData, $qso_per_label,$orientation, $grid, $via, $reference, $qslmsg, $tnxmsg, $mycall) {
$tableData = [];
$count_qso = 0;
@@ -333,9 +334,8 @@ class Labels extends CI_Controller {
$tableData[] = $rowData;
$count_qso++;
if($count_qso == $qso_per_label){
$this->generateLabel($pdf, $current_callsign, $tableData,$count_qso,$qso,$orientation, $grid, $via, $reference, $qslmsg, $tnxmsg);
$this->generateLabel($pdf, $current_callsign, $tableData,$count_qso,$qso,$orientation, $grid, $via, $reference, $qslmsg, $tnxmsg, $mycall);
$tableData = []; // reset the data
$count_qso = 0; // reset the counter
}
@@ -343,12 +343,12 @@ class Labels extends CI_Controller {
}
// generate label for remaining QSOs
if($count_qso > 0){
$this->generateLabel($pdf, $current_callsign, $tableData,$count_qso,$qso,$orientation, $grid, $via, $reference, $qslmsg, $tnxmsg);
$this->generateLabel($pdf, $current_callsign, $tableData,$count_qso,$qso,$orientation, $grid, $via, $reference, $qslmsg, $tnxmsg, $mycall);
$preliminaryData = []; // reset the data
}
}
function generateLabel($pdf, $current_callsign, $tableData,$numofqsos,$qso,$orientation,$grid=true, $via=false, $reference = false, $qslmsg = false, $tnxmsg = true){
function generateLabel($pdf, $current_callsign, $tableData,$numofqsos,$qso,$orientation,$grid=true, $via=false, $reference = false, $qslmsg = false, $tnxmsg = true, $mycall = false){
$builder = new \AsciiTable\Builder();
$builder->addRows($tableData);
$toradio = "To Radio: ";
@@ -372,7 +372,11 @@ class Labels extends CI_Controller {
}
}
$text.="\n";
if ($grid) { $text .= "My call: ".$qso['mycall']." Grid: ".$qso['mygrid']."\n"; }
if ($mycall) { $text .= "My call: ".$qso['mycall'] . ' '; }
if ($mycall && !$grid) {
$text .= "\n";
}
if ($grid) { $text .= "Grid: ".$qso['mygrid']."\n"; }
if ($reference) {
$ref_text = "";
$ref_avail = false;

View File

@@ -166,18 +166,22 @@ class Logbook extends CI_Controller {
// Get user's lookup priority preference
$lookup_priority = $this->get_lookup_priority();
$return['callsign_name'] = $this->nval($this->logbook_model->call_name($callsign), $callbook['name'] ?? '', $lookup_priority);
$return['callsign_qra'] = $this->nval($this->logbook_model->call_qra($callsign), $callbook['gridsquare'] ?? '', $lookup_priority);
// Consolidated callsign lookup - reduces queries from 11 to 2
$callsign_info = $this->logbook_model->get_callsign_all_info($callsign);
$return['callsign_name'] = $this->nval($callsign_info['name'], $callbook['name'] ?? '', $lookup_priority);
$return['callsign_qra'] = $this->nval($callsign_info['qra'], $callbook['gridsquare'] ?? '', $lookup_priority);
$return['callsign_geoloc'] = $callbook['geoloc'] ?? '';
$return['callsign_distance'] = $this->distance($return['callsign_qra'], $station_id);
$return['callsign_qth'] = $this->nval($this->logbook_model->call_qth($callsign), $callbook['city'] ?? '', $lookup_priority);
$return['callsign_iota'] = $this->nval($this->logbook_model->call_iota($callsign), $callbook['iota'] ?? '', $lookup_priority);
$return['callsign_email'] = $this->nval($this->logbook_model->call_email($callsign), $callbook['email'] ?? '', $lookup_priority);
$return['qsl_manager'] = $this->nval($this->logbook_model->call_qslvia($callsign), $callbook['qslmgr'] ?? '', $lookup_priority);
$return['callsign_state'] = $this->nval($this->logbook_model->call_state($callsign), $callbook['state'] ?? '', $lookup_priority);
$return['callsign_us_county'] = $this->nval($this->logbook_model->call_us_county($callsign), $callbook['us_county'] ?? '', $lookup_priority);
$return['callsign_ituz'] = $this->nval($this->logbook_model->call_ituzone($callsign), $callbook['ituz'] ?? '', $lookup_priority);
$return['callsign_cqz'] = $this->nval($this->logbook_model->call_cqzone($callsign), $callbook['cqz'] ?? '', $lookup_priority);
$return['callsign_qth'] = $this->nval($callsign_info['qth'], $callbook['city'] ?? '', $lookup_priority);
$return['callsign_iota'] = $this->nval($callsign_info['iota'], $callbook['iota'] ?? '', $lookup_priority);
$return['callsign_email'] = $this->nval($callsign_info['email'], $callbook['email'] ?? '', $lookup_priority);
$return['qsl_manager'] = $this->nval($callsign_info['qslvia'], $callbook['qslmgr'] ?? '', $lookup_priority);
$return['callsign_state'] = $this->nval($callsign_info['state'], $callbook['state'] ?? '', $lookup_priority);
$return['callsign_us_county'] = $this->nval($callsign_info['us_county'], $callbook['us_county'] ?? '', $lookup_priority);
$return['callsign_ituz'] = $this->nval($callsign_info['ituz'], $callbook['ituz'] ?? '', $lookup_priority);
$return['callsign_cqz'] = $this->nval($callsign_info['cqz'], $callbook['cqz'] ?? '', $lookup_priority);
// call_darc_dok remains separate due to different query pattern (uses logbooks_relationships)
$return['callsign_darc_dok'] = $this->nval($this->logbook_model->call_darc_dok($callsign), $callbook['darc_dok'] ?? '', $lookup_priority);
$return['workedBefore'] = $this->worked_grid_before($return['callsign_qra'], $band, $mode);
$return['confirmed'] = $this->confirmed_grid_before($return['callsign_qra'], $band, $mode);
$return['timesWorked'] = $this->logbook_model->times_worked($lookupcall);
@@ -1256,7 +1260,7 @@ class Logbook extends CI_Controller {
if ($date == ''){
$date = date("Y-m-d");
}
$dxccobj = new Dxcc($date);
$dxccobj = new Dxcc();
$ans = $dxccobj->dxcc_lookup($call, $date);
return $ans;

View File

@@ -91,15 +91,15 @@ class Logbookadvanced extends CI_Controller {
$footerData['scripts'] = [
'assets/js/moment.min.js',
'assets/js/datetime-moment.js',
'assets/js/sections/logbookadvanced.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/logbookadvanced.js")),
'assets/js/sections/logbookadvanced_edit.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/logbookadvanced_edit.js")),
'assets/js/sections/logbookadvanced_map.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/logbookadvanced_map.js")),
'assets/js/sections/cqmap_geojson.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/cqmap_geojson.js")),
'assets/js/sections/itumap_geojson.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/itumap_geojson.js")),
'assets/js/leaflet/L.Terminator.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/leaflet/L.Terminator.js")),
'assets/js/sections/logbookadvanced.js',
'assets/js/sections/logbookadvanced_edit.js',
'assets/js/sections/logbookadvanced_map.js',
'assets/js/sections/cqmap_geojson.js',
'assets/js/sections/itumap_geojson.js',
'assets/js/leaflet/L.Terminator.js',
'assets/js/leaflet/geocoding.js',
'assets/js/globe/globe.gl.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/globe/globe.gl.js")),
'assets/js/bootstrap-multiselect.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/bootstrap-multiselect.js")),
'assets/js/globe/globe.gl.js',
'assets/js/bootstrap-multiselect.js',
'assets/js/leaflet/L.MaidenheadColouredGridMap.js',
];
@@ -161,7 +161,8 @@ class Logbookadvanced extends CI_Controller {
'qrzReceived' => xss_clean($this->input->post('qrzReceived')),
'distance' => xss_clean($this->input->post('distance')),
'sortcolumn' => xss_clean($this->input->post('sortcolumn')),
'sortdirection' => xss_clean($this->input->post('sortdirection'))
'sortdirection' => xss_clean($this->input->post('sortdirection')),
'duration' => xss_clean($this->input->post('duration'))
);
}
@@ -394,7 +395,8 @@ class Logbookadvanced extends CI_Controller {
'ids' => json_decode(xss_clean($this->input->post('ids'))),
'qsoids' => xss_clean($this->input->post('qsoids')),
'sortcolumn' => 'qsotime',
'sortdirection' => 'desc'
'sortdirection' => 'desc',
'duration' => '*'
);
$result = $this->logbookadvanced_model->getSearchResultArray($searchCriteria);
@@ -622,6 +624,7 @@ class Logbookadvanced extends CI_Controller {
$json_string['frequency']['show'] = $this->def_boolean($this->input->post('frequency'));
$json_string['dcl']['show'] = $this->def_boolean($this->input->post('dcl'));
$json_string['last_modification']['show'] = $this->def_boolean($this->input->post('last_modification'));
$json_string['duration']['show'] = $this->def_boolean($this->input->post('duration'));
$obj['column_settings']= json_encode($json_string);
@@ -653,7 +656,7 @@ class Logbookadvanced extends CI_Controller {
$data['stateDxcc'] = $this->logbookadvanced_model->getPrimarySubdivisonsDxccs();
$data['modes'] = $this->modes->active();
$data['modes'] = $this->modes->all();
$data['bands'] = $this->bands->get_user_bands_for_qso_entry();
$data['contests'] = $this->contesting_model->getActivecontests();
$this->load->view('logbookadvanced/edit', $data);
@@ -729,10 +732,6 @@ class Logbookadvanced extends CI_Controller {
$this->load->view('logbookadvanced/help');
}
public function continentDialog() {
$this->load->view('logbookadvanced/continentdialog');
}
public function stateDialog() {
$this->load->library('Geojson');
@@ -782,7 +781,9 @@ class Logbookadvanced extends CI_Controller {
public function fixContinent() {
$this->load->model('logbookadvanced_model');
$result = $this->logbookadvanced_model->check_missing_continent();
$stationid = $this->input->post('stationid', true);
$result = $this->logbookadvanced_model->check_missing_continent($stationid);
$data['result'] = $result;
@@ -829,8 +830,10 @@ class Logbookadvanced extends CI_Controller {
public function updateDistances() {
if(!clubaccess_check(9)) return;
$stationid = $this->input->post('stationid', true);
$this->load->model('logbookadvanced_model');
$result = $this->logbookadvanced_model->update_distances_batch();
$result = $this->logbookadvanced_model->update_distances_batch($stationid);
$data['result'] = $result;
@@ -844,16 +847,20 @@ class Logbookadvanced extends CI_Controller {
}
public function dbtoolsDialog() {
$this->load->view('logbookadvanced/dbtoolsdialog');
$this->load->model('stations');
$data['station_profile'] = $this->stations->all_of_user();
$this->load->view('logbookadvanced/dbtoolsdialog', $data);
}
public function checkDb() {
if(!clubaccess_check(9)) return;
$type = $this->input->post('type', true);
$stationid = $this->input->post('stationid', true);
$this->load->model('logbookadvanced_model');
$data['result'] = $this->logbookadvanced_model->runCheckDb($type);
$data['result'] = $this->logbookadvanced_model->runCheckDb($type, $stationid);
if ($type == 'checkstate') {
$this->load->view('logbookadvanced/statecheckresult', $data);
} else {
@@ -870,10 +877,11 @@ class Logbookadvanced extends CI_Controller {
$this->load->model('logbookadvanced_model');
$dxcc = $this->input->post('dxcc', true);
$stationid = $this->input->post('stationid', true);
$data['country'] = $this->input->post('country', true);
// Process for batch QSO state fix
$result = $this->logbookadvanced_model->fixStateBatch($dxcc);
$result = $this->logbookadvanced_model->fixStateBatch($dxcc, $stationid);
$data['result'] = $result;
@@ -889,19 +897,21 @@ class Logbookadvanced extends CI_Controller {
$data['dxcc'] = $this->input->post('dxcc', true);
$data['country'] = $this->input->post('country', true);
$data['stationid'] = $this->input->post('stationid', true);
// Process for batch QSO state fix
$data['qsos'] = $this->logbookadvanced_model->getStateListQsos($data['dxcc']);
$data['qsos'] = $this->logbookadvanced_model->getStateListQsos($data['dxcc'], $data['stationid']);
$this->load->view('logbookadvanced/showStateQsos', $data);
}
public function batchFix() {
public function fixMissingGrids() {
if(!clubaccess_check(9)) return;
$type = $this->input->post('type', true);
$stationid = $this->input->post('stationid', true);
$this->load->model('logbookadvanced_model');
$result = $this->logbookadvanced_model->batchFix($type);
$result = $this->logbookadvanced_model->check_missing_grid($stationid);
$data['result'] = $result;
$data['type'] = $type;

View File

@@ -158,24 +158,6 @@ class Lookup extends CI_Controller {
}
}
public function dok($call) {
session_write_close();
if($call) {
$call = str_replace("-","/",$call);
$uppercase_callsign = strtoupper($call);
}
// DOK results from logbook
$this->load->model('logbook_model');
$query = $this->logbook_model->get_dok($uppercase_callsign);
if ($query->row()) {
echo $query->row()->COL_DARC_DOK;
}
}
public function ham_of_note($call = '') {
session_write_close();
@@ -184,9 +166,9 @@ class Lookup extends CI_Controller {
$uppercase_callsign = strtoupper($call);
$this->load->model('Pota');
$query = $this->Pota->ham_of_note($uppercase_callsign);
if ($query->row()) {
if ($query->num_rows() > 0) {
header('Content-Type: application/json');
echo json_encode($query->row());
echo json_encode($query->result());
} else {
return null;
}

View File

@@ -257,10 +257,6 @@ class Lotw extends CI_Controller {
echo $data['lotw_cert_info']->callsign.": QSO start date of LoTW certificate not reached yet!<br>";
continue;
}
if ($current_date > $data['lotw_cert_info']->qso_end_date) {
echo $data['lotw_cert_info']->callsign.": QSO end date of LoTW certificate exceeded!<br>";
continue;
}
if ($current_date < $data['lotw_cert_info']->date_created) {
echo $data['lotw_cert_info']->callsign.": LoTW certificate not valid yet!<br>";
continue;
@@ -445,7 +441,7 @@ class Lotw extends CI_Controller {
unlink($file);
// OpenSSL error:11800071:PKCS12 routines::mac verify failure is most likely an (unknown) password set on the exported certificate
if (str_contains($openssl_error_pkcs12_read, 'mac verify failure')) {
$this->session->set_flashdata('warning', sprintf(__("The certificate found in file %s contains a password and cannot be processed. %sPlease make sure you export the LoTW certificate from tqsl application without password!%s For further information please visit the %sLoTW FAQ page%s in the Wavelog Wiki."), basename($file), '<b>', '</b>', '<a target="_blank" href="https://github.com/wavelog/wavelog/wiki/Logbook-of-The-World-(LoTW)">', '</a>'));
$this->session->set_flashdata('warning', sprintf(__("The certificate found in file %s contains a password and cannot be processed. %sPlease make sure you export the LoTW certificate from tqsl application without password!%s For further information please visit the %sLoTW FAQ page%s in the Wavelog Wiki."), basename($file), '<b>', '</b>', '<a target="_blank" href="https://docs.wavelog.org/user-guide/qsl/lotw/">', '</a>'));
} else {
$this->session->set_flashdata('warning', sprintf(__("Generic error extracting the certificate from file %s. If the filename contains 'key-only' this is typically a certificate request which has not been processed by LoTW yet."), basename($file)));
}
@@ -719,77 +715,200 @@ class Lotw extends CI_Controller {
$q = $url_query->row();
$lotw_base_url = $q->lotw_download_url;
foreach ($query->result() as $user) {
if ( ($sync_user_id != null) && ($sync_user_id != $user->user_id) ) { continue; }
$station_ids=$this->Stations->all_station_ids_of_user($user->user_id);
if ($station_ids == '') { continue; } // User has no Station-ID! next one
// Single-user mode: fall back to sequential download
if ($sync_user_id != null) {
foreach ($query->result() as $user) {
if ($sync_user_id != $user->user_id) { continue; }
$station_ids=$this->Stations->all_station_ids_of_user($user->user_id);
if ($station_ids == '') { continue; }
if ($user->user_lotw_password == '') {
$result = "You have not defined your ARRL LoTW credentials!";
continue;
}
$config['upload_path'] = './uploads/';
$file = $config['upload_path'] . 'lotwreport_download_'.$user->user_id.'_auto.adi';
if (file_exists($file) && ! is_writable($file)) {
$result = "Temporary download file ".$file." is not writable. Aborting!";
continue;
}
$lotw_last_qsl_date = date('Y-m-d', strtotime($this->logbook_model->lotw_last_qsl_date($user->user_id)));
$lotw_url = $lotw_base_url."?";
$lotw_url .= "login=" . urlencode($user->user_lotw_name);
$lotw_url .= "&password=" . urlencode($user->user_lotw_password);
$lotw_url .= "&qso_query=1&qso_qsl='yes'&qso_qsldetail='yes'&qso_mydetail='yes'";
$lotw_url .= "&qso_qslsince=";
$lotw_url .= "$lotw_last_qsl_date";
if (! is_writable(dirname($file))) {
$result = "Temporary download directory ".dirname($file)." is not writable. Aborting!";
continue;
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $lotw_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
$content = curl_exec($ch);
if(curl_errno($ch)) {
$result = "LoTW download failed for user ".$user->user_lotw_name.": ".curl_strerror(curl_errno($ch))." (".curl_errno($ch).").";
continue;
} else if(str_contains(substr($content,0 , 2000),"Username/password incorrect</I>")) {
$result = "LoTW download failed for user ".$user->user_lotw_name.": Username/password incorrect";
log_message('error', 'LoTW download failed for user '.$user->user_name.': Username/password incorrect');
if ($this->Lotw_model->remove_lotw_credentials($user->user_id)) {
log_message('error', 'LoTW credentials deleted for user '.$user->user_name);
} else {
log_message('error', 'Deleting LoTW credentials for user '.$user->user_name.' failed');
}
continue;
} else if (str_contains(substr($content, 0, 2000),"Page Request Limit!</B>")) {
$result = "LoTW download hit a rate limit for user ".$user->user_lotw_name;
log_message('error', 'LoTW download hit a rate limit for user '.$user->user_name);
continue;
}
file_put_contents($file, $content);
if (file_get_contents($file, false, null, 0, 39) != "ARRL Logbook of the World Status Report") {
$result = "Downloaded LoTW report for user ".$user->user_lotw_name." is invalid. Check your credentials.";
log_message('error', 'Downloaded LoTW report is invalid for user '.$user->user_name);
continue;
}
ini_set('memory_limit', '-1');
$result = $this->loadFromFile($file, $station_ids, false);
}
return $result;
} else {
// Multi-user mode (sync_user_id == null): parallel download via curl_multi only triggered by cron - so message-return is omitted
// Pass 1: collect eligible users and prepare download queue
$max_parallel = 5;
$queue = array();
foreach ($query->result() as $user) {
$station_ids = $this->Stations->all_station_ids_of_user($user->user_id);
if ($station_ids == '') { continue; }
// Validate that LoTW credentials are not empty
// TODO: We don't actually see the error message
if ($user->user_lotw_password == '') {
$result = "You have not defined your ARRL LoTW credentials!";
continue;
}
$config['upload_path'] = './uploads/';
$file = $config['upload_path'] . 'lotwreport_download_'.$user->user_id.'_auto.adi';
if (file_exists($file) && ! is_writable($file)) {
$result = "Temporary download file ".$file." is not writable. Aborting!";
log_message("Error","LoTW Multidownload: UID: ".$user->user_id." - Temporary download file ".$file." is not writable. Aborting!");
continue;
}
if (! is_writable(dirname($file))) {
log_message("Error","LoTW Multidownload: UID: ".$user->user_id." - Temporary download directory ".dirname($file)." is not writable. Aborting!");
continue;
}
$lotw_last_qsl_date = date('Y-m-d', strtotime($this->logbook_model->lotw_last_qsl_date($user->user_id)));
// Build URL for LoTW report file
$lotw_url = $lotw_base_url."?";
$lotw_url .= "login=" . urlencode($user->user_lotw_name);
$lotw_url .= "&password=" . urlencode($user->user_lotw_password);
$lotw_url .= "&qso_query=1&qso_qsl='yes'&qso_qsldetail='yes'&qso_mydetail='yes'";
$lotw_url .= "&qso_qslsince=";
$lotw_url .= "$lotw_last_qsl_date";
if (! is_writable(dirname($file))) {
$result = "Temporary download directory ".dirname($file)." is not writable. Aborting!";
continue;
}
$queue[] = array(
'url' => $lotw_url,
'user' => $user,
'file' => $file,
'station_ids' => $station_ids,
);
}
// Download in batches of $max_parallel, process completed ones before next batch
$mh = curl_multi_init();
$active_handles = array(); // maps curl resource id => queue entry + handle
$queue_index = 0;
// Seed initial batch
while ($queue_index < count($queue) && count($active_handles) < $max_parallel) {
$entry = $queue[$queue_index];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $lotw_url);
curl_setopt($ch, CURLOPT_URL, $entry['url']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
$content = curl_exec($ch);
if(curl_errno($ch)) {
$result = "LoTW download failed for user ".$user->user_lotw_name.": ".curl_strerror(curl_errno($ch))." (".curl_errno($ch).").";
if (curl_errno($ch) == 28) { // break on timeout
$result .= "<br>Timeout reached. Stopping subsequent downloads.";
break;
}
continue;
} else if(str_contains(substr($content,0 , 2000),"Username/password incorrect</I>")) {
$result = "LoTW download failed for user ".$user->user_lotw_name.": Username/password incorrect";
log_message('error', 'LoTW download failed for user '.$user->user_name.': Username/password incorrect');
if ($this->Lotw_model->remove_lotw_credentials($user->user_id)) {
log_message('error', 'LoTW credentials deleted for user '.$user->user_name);
curl_multi_add_handle($mh, $ch);
$active_handles[(int)$ch] = array_merge($entry, array('ch' => $ch));
log_message('debug', 'LoTW parallel download started for UID '.$entry['user']->user_id.' ('.$entry['user']->user_lotw_name.')');
$queue_index++;
}
// Process downloads as they complete, refill slots from queue
while (count($active_handles) > 0) {
curl_multi_exec($mh, $running);
// Check for completed handles
while ($info = curl_multi_info_read($mh)) {
$ch = $info['handle'];
$dl = $active_handles[(int)$ch];
unset($active_handles[(int)$ch]);
$user = $dl['user'];
$file = $dl['file'];
$station_ids = $dl['station_ids'];
$errno = curl_errno($ch);
log_message('debug', 'LoTW parallel download finished for UID '.$user->user_id.' ('.$user->user_lotw_name.')'.($errno ? ' with error: '.curl_strerror($errno) : ''));
if ($errno) {
log_message('error', 'LoTW download failed for user '.$user->user_name.': '.curl_strerror($errno));
curl_multi_remove_handle($mh, $ch);
curl_close($ch);
} else {
log_message('error', 'Deleting LoTW credentials for user '.$user->user_name.' failed');
$content = curl_multi_getcontent($ch);
curl_multi_remove_handle($mh, $ch);
curl_close($ch);
if (str_contains(substr($content, 0, 2000), "Username/password incorrect</I>")) {
log_message('error', 'LoTW download failed for user '.$user->user_name.': Username/password incorrect');
if ($this->Lotw_model->remove_lotw_credentials($user->user_id)) {
log_message('error', 'LoTW credentials deleted for user '.$user->user_name);
} else {
log_message('error', 'Deleting LoTW credentials for user '.$user->user_name.' failed');
}
} else if (str_contains(substr($content, 0, 2000), "Page Request Limit!</B>")) {
log_message('error', 'LoTW download hit a rate limit for user '.$user->user_name);
} else {
file_put_contents($file, $content);
if (file_get_contents($file, false, null, 0, 39) != "ARRL Logbook of the World Status Report") {
log_message('error', 'Downloaded LoTW report is invalid for user '.$user->user_name);
} else {
ini_set('memory_limit', '-1');
log_message('debug', 'LoTW parallel download passing to loadFromFile for UID '.$user->user_id.' ('.$user->user_lotw_name.')');
$this->loadFromFile($file, $station_ids, false);
}
}
}
// Refill slot from queue
if ($queue_index < count($queue)) {
$entry = $queue[$queue_index];
$new_ch = curl_init();
curl_setopt($new_ch, CURLOPT_URL, $entry['url']);
curl_setopt($new_ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($new_ch, CURLOPT_CONNECTTIMEOUT, 30);
curl_multi_add_handle($mh, $new_ch);
$active_handles[(int)$new_ch] = array_merge($entry, array('ch' => $new_ch));
log_message('debug', 'LoTW parallel download started for UID '.$entry['user']->user_id.' ('.$entry['user']->user_lotw_name.')');
$queue_index++;
}
continue;
} else if (str_contains(substr($content, 0, 2000),"Page Request Limit!</B>")) {
$result = "LoTW download hit a rate limit for user ".$user->user_lotw_name;
log_message('error', 'LoTW download hit a rate limit for user '.$user->user_name);
continue;
}
file_put_contents($file, $content);
if (file_get_contents($file, false, null, 0, 39) != "ARRL Logbook of the World Status Report") {
$result = "Downloaded LoTW report for user ".$user->user_lotw_name." is invalid. Check your credentials.";
log_message('error', 'Downloaded LoTW report is invalid for user '.$user->user_name);
continue;
}
ini_set('memory_limit', '-1');
$result = $this->loadFromFile($file, $station_ids, false);
if (count($active_handles) > 0) {
curl_multi_select($mh, 1.0);
}
}
curl_multi_close($mh);
return $result;
} // end else (multi-user parallel mode)
} else {
return "No LoTW User details found to carry out matches.";
}

View File

@@ -51,9 +51,9 @@ class Map extends CI_Controller {
$footerData['scripts'] = [
'assets/js/leaflet/geocoding.js',
'assets/js/leaflet/L.Maidenhead.js',
'assets/js/sections/qso_map.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/qso_map.js")),
'assets/js/sections/itumap_geojson.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/itumap_geojson.js")),
'assets/js/sections/cqmap_geojson.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/cqmap_geojson.js")),
'assets/js/sections/qso_map.js',
'assets/js/sections/itumap_geojson.js',
'assets/js/sections/cqmap_geojson.js',
];
$this->load->view('interface_assets/header', $data);

View File

@@ -27,7 +27,7 @@ class Qrz extends CI_Controller {
public function qrz_apitest() {
$apikey = xss_clean($this->input->post('APIKEY'));
$url = 'http://logbook.qrz.com/api'; // TODO: Move this to database
$url = 'https://logbook.qrz.com/api'; // TODO: Move this to database
$post_data['KEY'] = $apikey;
$post_data['ACTION'] = 'STATUS';
@@ -362,7 +362,7 @@ class Qrz extends CI_Controller {
$result = "Temporary download file ".$file." is not writable. Aborting!";
return false;
}
$url = 'http://logbook.qrz.com/api';
$url = 'https://logbook.qrz.com/api';
$post_data['KEY'] = $qrz_api_key;
$post_data['ACTION'] = 'FETCH';

View File

@@ -27,7 +27,7 @@ class Qsl extends CI_Controller {
$footerData = [];
$footerData['scripts'] = [
'assets/js/sections/qsl.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/qsl.js")),
'assets/js/sections/qsl.js',
];
$this->load->view('interface_assets/header', $data);

View File

@@ -99,6 +99,13 @@ class QSO extends CI_Controller {
$data['user_station_to_qso_tab'] = 0;
}
$qkey_opt = $this->user_options_model->get_options('qso_tab', array('option_name' => 'map', 'option_key' => 'show'))->result();
if (count($qkey_opt) > 0) {
$data['user_qso_show_map'] = $qkey_opt[0]->option_value;
} else {
$data['user_qso_show_map'] = 1; // default: show map
}
// Get status of DX Waterfall enable option
$qkey_opt=$this->user_options_model->get_options('dxwaterfall',array('option_name'=>'enable','option_key'=>'boolean'))->result();
if (count($qkey_opt)>0) {

View File

@@ -18,7 +18,7 @@ class Radio extends CI_Controller {
$footerData = [];
$footerData['scripts'] = [
'assets/js/sections/radio.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/radio.js")),
'assets/js/sections/radio.js',
];
$this->load->view('interface_assets/header', $data);
@@ -36,6 +36,9 @@ class Radio extends CI_Controller {
$this->load->model('cat');
$query = $this->cat->status();
// Get the default radio
$default_user_radio = $this->user_options_model->get_options('cat', array('option_name' => $this->_get_optionname()), $this->_get_correct_uid())->row()->option_value ?? NULL;
if ($query->num_rows() > 0) {
echo "<thead><tr>";
echo "<th>" . __("Radio") . "</th>";
@@ -50,6 +53,23 @@ class Radio extends CI_Controller {
echo "<th>" . __("Settings") . "</th>";
echo "<th></th>";
echo "</tr></thead><tbody>";
// WebSocket as first row
echo "<tr>";
echo "<td>" . __("WebSocket") . "</td>";
echo "<td>-</td>"; // Frequency
echo "<td>-</td>"; // Mode
echo "<td>-</td>"; // Timestamp
echo '<td></td>'; // Last updated
if ($default_user_radio === 'ws') {
echo '<td><button id="default_radio_btn_ws" class="btn btn-sm btn-primary ld-ext-right" onclick="release_default_radio(\'ws\')">' . __("Default (click to release)") . '<div class="ld ld-ring ld-spin"></div></button></td>';
} else {
echo '<td><button id="default_radio_btn_ws" class="btn btn-sm btn-outline-primary ld-ext-right" onclick="set_default_radio(\'ws\')">' . __("Set as default radio") . '<div class="ld ld-ring ld-spin"></div></button></td>';
}
echo '<td></td>'; // Settings (no edit for WebSocket)
echo '<td></td>'; // Delete (no delete for WebSocket)
echo "</tr>";
foreach ($query->result() as $row) {
echo "<tr>";
echo "<td>" . $row->radio . "</td>";
@@ -68,6 +88,8 @@ class Radio extends CI_Controller {
echo "<td>- / -</td>";
} elseif (empty($row->frequency_rx) || $row->frequency_rx == "0") {
echo "<td>" . $this->frequency->qrg_conversion($row->frequency) . "</td>";
} elseif ($this->frequency->frequencies_are_equal($row->frequency, $row->frequency_rx)) {
echo "<td>" . $this->frequency->qrg_conversion($row->frequency) . "</td>";
} else {
echo "<td>" . $this->frequency->qrg_conversion($row->frequency_rx) . " / " . $this->frequency->qrg_conversion($row->frequency) . "</td>";
}
@@ -100,17 +122,10 @@ class Radio extends CI_Controller {
echo '<td></td>';
}
if ($this->session->userdata('clubstation') != 1) {
$defaul_user_radio = $this->user_options_model->get_options('cat', array('option_name' => 'default_radio'))->row()->option_value ?? NULL;
if (!$defaul_user_radio) {
echo '<td><button id="default_radio_btn_' . $row->id . '" class="btn btn-sm btn-outline-primary ld-ext-right" onclick="set_default_radio(' . $row->id . ')">' . __("Set as default radio") . '<div class="ld ld-ring ld-spin"></div></button</td>';
} else {
if ($defaul_user_radio !== $row->id) {
echo '<td><button id="default_radio_btn_' . $row->id . '" class="btn btn-sm btn-outline-primary ld-ext-right" onclick="set_default_radio(' . $row->id . ')">' . __("Set as default radio") . '<div class="ld ld-ring ld-spin"></div></button</td>';
} else {
echo '<td><button id="default_radio_btn_' . $row->id . '" class="btn btn-sm btn-primary ld-ext-right" onclick="release_default_radio(' . $row->id . ')">' . __("Default (click to release)") . '<div class="ld ld-ring ld-spin"></div></button</td>';
}
}
if ($default_user_radio == $row->id) {
echo '<td><button id="default_radio_btn_' . $row->id . '" class="btn btn-sm btn-primary ld-ext-right" onclick="release_default_radio(' . $row->id . ')">' . __("Default (click to release)") . '<div class="ld ld-ring ld-spin"></div></button</td>';
} else {
echo '<td><button id="default_radio_btn_' . $row->id . '" class="btn btn-sm btn-outline-primary ld-ext-right" onclick="set_default_radio(' . $row->id . ')">' . __("Set as default radio") . '<div class="ld ld-ring ld-spin"></div></button</td>';
}
echo "<td><button id='edit_cat_settings_".$row->id."' \" class=\"editCatSettings btn btn-sm btn-primary\"> " . __("Edit") . "</button></td>";
echo "<td><a href=\"" . site_url('radio/delete') . "/" . $row->id . "\" class=\"btn btn-sm btn-danger\"> <i class=\"fas fa-trash-alt\"></i> " . __("Delete") . "</a></td>";
@@ -118,8 +133,18 @@ class Radio extends CI_Controller {
}
echo "</tbody>";
} else {
// No radios found - show WebSocket button
if ($default_user_radio === 'ws') {
$websocket_button = '<button id="default_radio_btn_ws" type="button" class="btn btn-sm btn-primary mt-2 ld-ext-right d-block mx-auto" onclick="release_default_radio(\'ws\')">' . __("WebSocket is currently default (click to release)") . '<div class="ld ld-ring ld-spin"></div></button>';
} else {
$websocket_button = '<button id="default_radio_btn_ws" type="button" class="btn btn-sm btn-primary mt-2 ld-ext-right d-block mx-auto" onclick="set_default_radio(\'ws\')">' . __("Set WebSocket as default radio") . '<div class="ld ld-ring ld-spin"></div></button>';
}
echo "<thead><tr>";
echo "<td colspan=\"6\"><div class=\"alert alert-info text-center\">" . __("No CAT interfaced radios found.") . "</div></td>";
echo "<td colspan=\"6\"><div class=\"alert alert-info text-center\">";
echo __("No CAT interfaced radios found.");
echo "<p>" . __("You can still set the WebSocket option as your default radio.") . "</p>";
echo $websocket_button;
echo "</div></td>";
echo "</tr></thead>";
}
}
@@ -302,11 +327,11 @@ class Radio extends CI_Controller {
$this->cat->delete($clean_id);
if ($clean_id == $this->user_options_model->get_options('cat', array('option_name' => 'default_radio'))->row()->option_value ?? '') {
if ($clean_id == $this->user_options_model->get_options('cat', array('option_name' => $this->_get_optionname()), $this->_get_correct_uid())->row()->option_value ?? '') {
$this->release_default_radio();
}
$this->session->set_flashdata('message', 'Radio Profile Deleted');
$this->session->set_flashdata('message', __("Radio removed successfully"));
session_write_close();
redirect('radio');
@@ -315,8 +340,8 @@ class Radio extends CI_Controller {
function set_default_radio() {
// get the radio_id from POST
$clean_radio_id = $this->security->xss_clean($this->input->post('radio_id'));
$clean_radio_id = $this->input->post('radio_id', TRUE);
// Check Auth
$this->load->model('user_model');
if (!$this->user_model->authorize(3)) {
@@ -328,7 +353,7 @@ class Radio extends CI_Controller {
$this->release_default_radio();
// Set the user_option and session data
$this->user_options_model->set_option('cat', 'default_radio', array('radio_id' => $clean_radio_id));
$this->user_options_model->set_option('cat', $this->_get_optionname(), array('radio_id' => $clean_radio_id), $this->_get_correct_uid());
$this->session->set_userdata('radio', $clean_radio_id);
}
@@ -341,7 +366,27 @@ class Radio extends CI_Controller {
}
// Unset the user_option and session data
$this->user_options_model->del_option('cat', 'default_radio');
$this->user_options_model->del_option('cat', $this->_get_optionname(), NULL, $this->_get_correct_uid());
$this->session->unset_userdata('radio');
}
private function _get_correct_uid() {
if ($this->_is_clubstation()) {
return $this->session->userdata('source_uid');
} else {
return $this->session->userdata('user_id');
}
}
private function _is_clubstation() {
return $this->session->userdata('clubstation') == 1;
}
private function _get_optionname() {
if ($this->_is_clubstation() && ($this->session->userdata('source_uid') ?? '') != '') {
return 'default_clubradio_' . $this->session->userdata('user_id');
} else {
return 'default_radio';
}
}
}

View File

@@ -34,7 +34,7 @@ class Satellite extends CI_Controller {
$footerData = [];
$footerData['scripts'] = [
'assets/js/sections/satellite.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/satellite.js")),
'assets/js/sections/satellite.js',
];
// Render Page
@@ -184,10 +184,10 @@ class Satellite extends CI_Controller {
$footerData = [];
$footerData['scripts'] = [
'assets/js/sections/satellite.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/satellite.js")),
'assets/js/sections/three-orbit-controls.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/three-orbit-controls.js")),
'assets/js/sections/satellite_functions.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/satellite_functions.js")),
'assets/js/sections/flightpath.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/flightpath.js")),
'assets/js/sections/satellite.js',
'assets/js/sections/three-orbit-controls.js',
'assets/js/sections/satellite_functions.js',
'assets/js/sections/flightpath.js',
'assets/js/leaflet/L.Maidenhead.js',
'assets/js/leaflet/geocoding.js',
];
@@ -245,8 +245,8 @@ class Satellite extends CI_Controller {
$footerData = [];
$footerData['scripts'] = [
'assets/js/bootstrap-multiselect.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/bootstrap-multiselect.js")),
'assets/js/sections/satpasses.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/satpasses.js")),
'assets/js/bootstrap-multiselect.js',
'assets/js/sections/satpasses.js',
];
// Render Page

View File

@@ -13,7 +13,7 @@ class Sattimers extends CI_Controller {
$this->load->model('stations');
$footerData = [];
$footerData['scripts'] = [
'assets/js/sections/sattimers.js?'
'assets/js/sections/sattimers.js'
];
$url = 'https://www.df2et.de/tevel/api2.php?grid='.strtoupper($this->stations->find_gridsquare());

View File

@@ -27,7 +27,7 @@ class SimpleFLE extends CI_Controller {
$footerData['scripts'] = [
'assets/js/moment.min.js',
'assets/js/datetime-moment.js',
'assets/js/sections/simplefle.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/simplefle.js"))
'assets/js/sections/simplefle.js'
];
$this->load->view('interface_assets/header', $data);

View File

@@ -32,7 +32,7 @@ class Stationsetup extends CI_Controller {
$footerData['scripts'] = [
'assets/js/moment.min.js',
'assets/js/datetime-moment.js',
'assets/js/sections/stationsetup.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/stationsetup.js")),
'assets/js/sections/stationsetup.js',
];
// Get Date format
@@ -259,7 +259,7 @@ class Stationsetup extends CI_Controller {
$result = $this->logbooks_model->show_all()->result();
foreach ($result as $entry) {
$single=(Object)[];
$single->logbook_id = $entry->logbook_id;
$single->logbook_id = '<span class="badge bg-info">'.$entry->logbook_id.'</span>';
$single->logbook_name = $this->lbname2html($entry->logbook_id, $entry->logbook_name);
$single->logbook_state = $this->lbstate2html($entry->logbook_id);
$single->logbook_edit = $this->lbedit2html($entry->logbook_id);

View File

@@ -321,9 +321,9 @@ class Statistics extends CI_Controller {
$footerData = [];
$footerData['scripts'] = [
'assets/js/chart.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/chart.js")),
'assets/js/sections/antennastats.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/antennastats.js")),
'assets/js/bootstrap-multiselect.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/bootstrap-multiselect.js")),
'assets/js/chart.js',
'assets/js/sections/antennastats.js',
'assets/js/bootstrap-multiselect.js',
];
// Load Views
@@ -389,7 +389,7 @@ class Statistics extends CI_Controller {
$footerData = [];
$footerData['scripts'] = [
'assets/js/sections/initials.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/initials.js")),
'assets/js/sections/initials.js',
];
// Load Views

View File

@@ -101,7 +101,7 @@ class Timeline extends CI_Controller {
$data['onlynew'] = $onlynew;
$data['selectedyear'] = $year;
$footerData['scripts'] = [ 'assets/js/sections/timeline.js?' ];
$footerData['scripts'] = [ 'assets/js/sections/timeline.js' ];
$this->load->view('interface_assets/header', $data);
$this->load->view('timeline/index');
$this->load->view('interface_assets/footer', $footerData);

View File

@@ -272,6 +272,8 @@ class Update extends CI_Controller {
$this->db->query($sql);
$this->db->trans_complete();
$this->_invalidate_dxcc_cache();
$this->update_status(__("DONE"));
echo 'success';
@@ -292,6 +294,26 @@ class Update extends CI_Controller {
}
private function _invalidate_dxcc_cache() {
$this->load->is_loaded('cache') ?: $this->load->driver('cache', [
'adapter' => $this->config->item('cache_adapter') ?? 'file',
'backup' => $this->config->item('cache_backup') ?? 'file',
'key_prefix' => $this->config->item('cache_key_prefix') ?? ''
]);
$possible_cachekeys = [
'dxcc_exceptions',
'dxcc_prefixes',
];
foreach ($possible_cachekeys as $cache_key) {
if ($this->cache->get($cache_key) !== false) {
$this->cache->delete($cache_key);
log_message('info', "Deleted cache for key: " . $cache_key);
}
}
}
public function update_status($done=""){
if(!$this->load->is_loaded('Paths')) {

View File

@@ -44,7 +44,7 @@ class User extends CI_Controller {
$footerData = [];
$footerData['scripts'] = [
'assets/js/sections/user.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/user.js")),
'assets/js/sections/user.js',
];
$data['page_title'] = __("User Accounts");
@@ -174,7 +174,7 @@ class User extends CI_Controller {
$footerData = [];
$footerData['scripts'] = [
'assets/js/sections/user.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/user.js")),
'assets/js/sections/user.js',
];
// Get timezones
@@ -239,6 +239,7 @@ class User extends CI_Controller {
$data['user_sig_to_qso_tab'] = $this->input->post('user_sig_to_qso_tab');
$data['user_dok_to_qso_tab'] = $this->input->post('user_dok_to_qso_tab');
$data['user_station_to_qso_tab'] = $this->input->post('user_station_to_qso_tab');
$data['user_qso_show_map'] = $this->input->post('user_qso_show_map') ?? 1;
$data['user_language'] = $this->input->post('user_language');
$data['global_oqrs_text'] = $this->input->post('global_oqrs_text') ?? '';
$data['oqrs_grouped_search'] = $this->input->post('oqrs_grouped_search') ?? 'off';
@@ -312,7 +313,8 @@ class User extends CI_Controller {
$this->input->post('oqrs_grouped_search_show_station_name') ?? 'off',
$this->input->post('oqrs_auto_matching') ?? 'on',
$this->input->post('oqrs_direct_auto_matching') ?? 'on',
$this->input->post('user_dxwaterfall_enable') ?? 'N',
$this->input->post('user_dxwaterfall_enable') ?? 'N',
$this->input->post('user_qso_show_map') ?? 1,
$this->input->post('clubstation') == '1' ? true : false)
) {
// Check for errors
@@ -418,7 +420,7 @@ class User extends CI_Controller {
$footerData = [];
$footerData['scripts'] = [
'assets/js/sections/user.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/user.js")),
'assets/js/sections/user.js',
];
// Get timezones
@@ -714,7 +716,7 @@ class User extends CI_Controller {
}
if($this->input->post('user_dashboard_map')) {
$data['user_dashboard_map'] = $this->input->post('user_dashboard_map', false);
$data['user_dashboard_map'] = $this->input->post('user_dashboard_map', true);
} else {
$dkey_opt=$this->user_options_model->get_options('dashboard',array('option_name'=>'show_map','option_key'=>'boolean'), $this->uri->segment(3))->result();
if (count($dkey_opt)>0) {
@@ -822,6 +824,17 @@ class User extends CI_Controller {
}
}
if ($this->input->post('user_qso_show_map')) {
$data['user_qso_show_map'] = $this->input->post('user_qso_show_map', true);
} else {
$qkey_opt = $this->user_options_model->get_options('qso_tab', array('option_name' => 'map', 'option_key' => 'show'), $this->uri->segment(3))->result();
if (count($qkey_opt) > 0) {
$data['user_qso_show_map'] = $qkey_opt[0]->option_value;
} else {
$data['user_qso_show_map'] = 1; // default: show
}
}
if($this->input->post('global_oqrs_text')) {
$data['global_oqrs_text'] = $this->input->post('global_oqrs_text', false);
} else {

View File

@@ -501,6 +501,14 @@ class Widgets extends CI_Controller {
);
$mode_string = empty($cat_data->mode) ? "" : $cat_data->mode;
return trim(sprintf("%s %s", $tx_frequency, $mode_string));
} elseif ($this->frequency->frequencies_are_equal($cat_data->frequency, $cat_data->frequency_rx)) {
// Frequencies are equal, show only one
$tx_frequency = $this->frequency->qrg_conversion(
$cat_data->frequency, $r_option, $source_unit, $target_unit
);
$mode_string = empty($cat_data->mode) ? "" : $cat_data->mode;
return trim(sprintf("%s %s", $tx_frequency, $mode_string));
} else {
$rx_frequency = $this->frequency->qrg_conversion(

View File

@@ -10,8 +10,55 @@ class Callbook {
private $ci;
// Duration of session keys
// QRZ.com
// They write that session keys have no guaranteed lifetime. We should cache it to reuse it, but also be prepared
// to get a new one if the session key is invalid.
// Older documents showed that the duration was between 12-24 hours. So we set it to 4 hours to be on the safe side.
// Ref.: https://www.qrz.com/docs/xml/current_spec.html
const QRZ_SESSION_DURATION = 14400; // 4 hours
private $qrz_session_cachekey = null;
// QRZCQ.com
// I could not find any information about session key duration on their website. Let's cache it for at least 55 minutes.
// In code we are prepared for an invalid session key, so if the session key is invalid we will get a new one and retry the search.
// Ref.: https://www.qrzcq.com/docs/api/xml/
const QRZCQ_SESSION_DURATION = 3300; // 55 minutes
private $qrzcq_session_cachekey = null;
// HamQTH.com
// Session Key is valid for 1 hour according to their documentation. We set it just a few moments below that to 55 Minutes.
// Ref.: https://www.hamqth.com/developers.php
const HAMQTH_SESSION_DURATION = 3300; // 55 minutes
private $hamqth_session_cachekey = null;
// QRZRU.com
// Session Key is valid for 1 hour according to their documentation. We set it just a few moments below that to 55 Minutes.
// Ref.: https://www.qrz.ru/help/api/xml
const QRZRU_SESSION_DURATION = 3300; // 55 minutes
private $qrzru_session_cachekey = null;
// Some generic stuff
private $logbook_not_configured;
private $error_obtaining_sessionkey;
public function __construct() {
$this->ci = & get_instance();
$this->ci->load->is_loaded('cache') ?: $this->ci->load->driver('cache', [
'adapter' => $this->ci->config->item('cache_adapter') ?? 'file',
'backup' => $this->ci->config->item('cache_backup') ?? 'file',
'key_prefix' => $this->ci->config->item('cache_key_prefix') ?? ''
]);
$this->qrz_session_cachekey = 'qrz_session_key_'.$this->ci->config->item('qrz_username');
$this->qrzcq_session_cachekey = 'qrzcq_session_key_'.$this->ci->config->item('qrzcq_username');
$this->hamqth_session_cachekey = 'hamqth_session_key_'.$this->ci->config->item('hamqth_username');
$this->qrzru_session_cachekey = 'qrzru_session_key_'.$this->ci->config->item('qrzru_username');
$this->logbook_not_configured = __("Lookup not configured. Please review configuration.");
$this->error_obtaining_sessionkey = __("Error obtaining a session key for callbook. Error: %s");
}
// TODO:
@@ -31,7 +78,7 @@ class Callbook {
break;
} else {
$callbook_errors['error_'.$source] = $callbook['error'];
$callbook_errors['error_'.$source.'_name'] = $callbook['source'];
$callbook_errors['error_'.$source.'_name'] = $callbook['source'] ?? '';
}
}
} else {
@@ -66,179 +113,225 @@ class Callbook {
function queryCallbook($callsign, $source) {
switch ($source) {
case 'qrz':
$callbook = $this->qrz($callsign, $this->ci->config->item('use_fullname'));
$callbook = $this->_qrz($callsign, $this->ci->config->item('use_fullname'));
break;
case 'qrzcq':
$callbook = $this->qrzcq($callsign);
$callbook = $this->_qrzcq($callsign);
break;
case 'hamqth':
$callbook = $this->hamqth($callsign);
$callbook = $this->_hamqth($callsign);
break;
case 'qrzru':
$callbook = $this->qrzru($callsign);
$callbook = $this->_qrzru($callsign);
break;
default:
$callbook['error'] = 'No callbook defined. Please review configuration.';
$callbook['error'] = $this->logbook_not_configured;
}
log_message('debug', 'Callbook lookup for '.$callsign.' using '.$source.': '.((($callbook['error'] ?? '' ) != '') ? $callbook['error'] : 'Success'));
return $callbook;
}
function qrz($callsign, $fullname) {
if (!$this->ci->load->is_loaded('qrz')) {
$this->ci->load->library('qrz');
}
if ($this->ci->config->item('qrz_username') == null || $this->ci->config->item('qrz_password') == null) {
$callbook['error'] = 'Lookup not configured. Please review configuration.';
$callbook['source'] = $this->ci->qrz->sourcename();
} else {
$username = $this->ci->config->item('qrz_username');
$password = $this->ci->config->item('qrz_password');
private function _qrz($callsign, $fullname) {
$this->ci->load->is_loaded('qrz') ?: $this->ci->load->library('qrz');
if (!$this->ci->session->userdata('qrz_session_key')) {
$callbook['source'] = $this->ci->qrz->sourcename();
$username = trim($this->ci->config->item('qrz_username') ?? '');
$password = trim($this->ci->config->item('qrz_password') ?? '');
if ($username == '' || $password == '') {
$callbook['error'] = $this->logbook_not_configured;
} else {
if (!$this->ci->cache->get($this->qrz_session_cachekey)) {
$qrz_session_key = $this->ci->qrz->session($username, $password);
$this->ci->session->set_userdata('qrz_session_key', $qrz_session_key);
if (!$this->_validate_sessionkey($qrz_session_key)) {
$callbook['error'] = sprintf($this->error_obtaining_sessionkey, $qrz_session_key);
$this->ci->cache->delete($this->qrz_session_cachekey);
return $callbook;
}
$this->ci->cache->save($this->qrz_session_cachekey, $qrz_session_key, self::QRZ_SESSION_DURATION);
}
$callbook = $this->ci->qrz->search($callsign, $this->ci->session->userdata('qrz_session_key'), $fullname);
$callbook = $this->ci->qrz->search($callsign, $this->ci->cache->get($this->qrz_session_cachekey), $fullname);
if ($callbook['error'] ?? '' == 'Invalid session key') {
$qrz_session_key = $this->ci->qrz->session($username, $password);
$this->ci->session->set_userdata('qrz_session_key', $qrz_session_key);
$callbook = $this->ci->qrz->search($callsign, $this->ci->session->userdata('qrz_session_key'), $fullname);
if (!$this->_validate_sessionkey($qrz_session_key)) {
$callbook['error'] = sprintf($this->error_obtaining_sessionkey, $qrz_session_key);
$this->ci->cache->delete($this->qrz_session_cachekey);
return $callbook;
}
$this->ci->cache->save($this->qrz_session_cachekey, $qrz_session_key, self::QRZ_SESSION_DURATION);
$callbook = $this->ci->qrz->search($callsign, $this->ci->cache->get($this->qrz_session_cachekey), $fullname);
}
if (strpos($callbook['error'] ?? '', 'Not found') !== false && strpos($callsign, "/") !== false) {
$plaincall = $this->get_plaincall($callsign);
// Now try again but give back reduced data, as we can't validate location and stuff (true at the end)
$callbook = $this->ci->qrz->search($plaincall, $this->ci->session->userdata('qrz_session_key'), $fullname, true);
$callbook = $this->ci->qrz->search($plaincall, $this->ci->cache->get($this->qrz_session_cachekey), $fullname, true);
}
}
$callbook['source'] = $this->ci->qrz->sourcename();
return $callbook;
}
function qrzcq($callsign) {
if (!$this->ci->load->is_loaded('qrzcq')) {
$this->ci->load->library('qrzcq');
}
if ($this->ci->config->item('qrzcq_username') == null || $this->ci->config->item('qrzcq_password') == null) {
$callbook['error'] = 'Lookup not configured. Please review configuration.';
$callbook['source'] = $this->ci->qrzcq->sourcename();
} else {
$username = $this->ci->config->item('qrzcq_username');
$password = $this->ci->config->item('qrzcq_password');
private function _qrzcq($callsign) {
$this->ci->load->is_loaded('qrzcq') ?: $this->ci->load->library('qrzcq');
if (!$this->ci->session->userdata('qrzcq_session_key')) {
$callbook['source'] = $this->ci->qrzcq->sourcename();
$username = trim($this->ci->config->item('qrzcq_username') ?? '');
$password = trim($this->ci->config->item('qrzcq_password') ?? '');
if ($username == '' || $password == '') {
$callbook['error'] = $this->logbook_not_configured;
} else {
if (!$this->ci->cache->get($this->qrzcq_session_cachekey)) {
$result = $this->ci->qrzcq->session($username, $password);
if (!$this->_validate_sessionkey($result[1])) {
$callbook['error'] = sprintf($this->error_obtaining_sessionkey, $result[1]);
$this->ci->cache->delete($this->qrzcq_session_cachekey);
return $callbook;
}
if ($result[0] == 0) {
$this->ci->session->set_userdata('qrzcq_session_key', $result[1]);
$this->ci->cache->save($this->qrzcq_session_cachekey, $result[1], self::QRZCQ_SESSION_DURATION);
} else {
$data['error'] = __("QRZCQ Error").": ".$result[1];
$data['source'] = $this->ci->qrzcq->sourcename();
return $data;
$callbook['error'] = __("QRZCQ Error").": ".$result[1];
return $callbook;
}
}
$callbook = $this->ci->qrzcq->search($callsign, $this->ci->session->userdata('qrzcq_session_key'));
$callbook = $this->ci->qrzcq->search($callsign, $this->ci->cache->get($this->qrzcq_session_cachekey));
if ($callbook['error'] ?? '' == 'Invalid session key') {
$qrzcq_session_key = $this->ci->qrzcq->session($username, $password);
$this->ci->session->set_userdata('qrzcq_session_key', $qrzcq_session_key);
$callbook = $this->ci->qrzcq->search($callsign, $this->ci->session->userdata('qrzcq_session_key'));
if (!$this->_validate_sessionkey($qrzcq_session_key[1])) {
$callbook['error'] = sprintf($this->error_obtaining_sessionkey, $qrzcq_session_key[1]);
$this->ci->cache->delete($this->qrzcq_session_cachekey);
return $callbook;
}
$this->ci->cache->save($this->qrzcq_session_cachekey, $qrzcq_session_key[1], self::QRZCQ_SESSION_DURATION);
$callbook = $this->ci->qrzcq->search($callsign, $this->ci->cache->get($this->qrzcq_session_cachekey));
}
if (strpos($callbook['error'] ?? '', 'Not found') !== false && strpos($callsign, "/") !== false) {
$plaincall = $this->get_plaincall($callsign);
// Now try again but give back reduced data, as we can't validate location and stuff (true at the end)
$callbook = $this->ci->qrzcq->search($plaincall, $this->ci->session->userdata('qrzcq_session_key'), true);
$callbook = $this->ci->qrzcq->search($plaincall, $this->ci->cache->get($this->qrzcq_session_cachekey), true);
}
}
$callbook['source'] = $this->ci->qrzcq->sourcename();
return $callbook;
}
function hamqth($callsign) {
// Load the HamQTH library
if (!$this->ci->load->is_loaded('hamqth')) {
$this->ci->load->library('hamqth');
}
if ($this->ci->config->item('hamqth_username') == null || $this->ci->config->item('hamqth_password') == null) {
$callbook['error'] = 'Lookup not configured. Please review configuration.';
$callbook['source'] = $this->ci->hamqth->sourcename();
} else {
$username = $this->ci->config->item('hamqth_username');
$password = $this->ci->config->item('hamqth_password');
private function _hamqth($callsign) {
$this->ci->load->is_loaded('hamqth') ?: $this->ci->load->library('hamqth');
if (!$this->ci->session->userdata('hamqth_session_key')) {
$callbook['source'] = $this->ci->hamqth->sourcename();
$username = trim($this->ci->config->item('hamqth_username') ?? '');
$password = trim($this->ci->config->item('hamqth_password') ?? '');
if ($username == '' || $password == '') {
$callbook['error'] = $this->logbook_not_configured;
} else {
if (!$this->ci->cache->get($this->hamqth_session_cachekey)) {
$hamqth_session_key = $this->ci->hamqth->session($username, $password);
if ($hamqth_session_key == false) {
$callbook['error'] = __("Error obtaining a session key for HamQTH query");
$callbook['source'] = $this->ci->hamqth->sourcename();
if (!$this->_validate_sessionkey($hamqth_session_key)) {
$callbook['error'] = sprintf($this->error_obtaining_sessionkey, $hamqth_session_key);
$this->ci->cache->delete($this->hamqth_session_cachekey);
return $callbook;
} else {
$this->ci->session->set_userdata('hamqth_session_key', $hamqth_session_key);
$this->ci->cache->save($this->hamqth_session_cachekey, $hamqth_session_key, self::HAMQTH_SESSION_DURATION);
}
}
$callbook = $this->ci->hamqth->search($callsign, $this->ci->session->userdata('hamqth_session_key'));
$callbook = $this->ci->hamqth->search($callsign, $this->ci->cache->get($this->hamqth_session_cachekey));
// If HamQTH session has expired, start a new session and retry the search.
if ($callbook['error'] == "Session does not exist or expired") {
$hamqth_session_key = $this->ci->hamqth->session($username, $password);
$this->ci->session->set_userdata('hamqth_session_key', $hamqth_session_key);
$callbook = $this->ci->hamqth->search($callsign, $this->ci->session->userdata('hamqth_session_key'));
if (!$this->_validate_sessionkey($hamqth_session_key)) {
$callbook['error'] = sprintf($this->error_obtaining_sessionkey, $hamqth_session_key);
$this->ci->cache->delete($this->hamqth_session_cachekey);
return $callbook;
}
$this->ci->cache->save($this->hamqth_session_cachekey, $hamqth_session_key, self::HAMQTH_SESSION_DURATION);
$callbook = $this->ci->hamqth->search($callsign, $this->ci->cache->get($this->hamqth_session_cachekey));
}
if (strpos($callbook['error'] ?? '', 'Not found') !== false && strpos($callsign, "/") !== false) {
$plaincall = $this->get_plaincall($callsign);
// Now try again but give back reduced data, as we can't validate location and stuff (true at the end)
$callbook = $this->ci->hamqth->search($plaincall, $this->ci->session->userdata('hamqth_session_key'), true);
$callbook = $this->ci->hamqth->search($plaincall, $this->ci->cache->get($this->hamqth_session_cachekey), true);
}
}
$callbook['source'] = $this->ci->hamqth->sourcename();
return $callbook;
}
function qrzru($callsign) {
if (!$this->ci->load->is_loaded('qrzru')) {
$this->ci->load->library('qrzru');
}
if ($this->ci->config->item('qrzru_username') == null || $this->ci->config->item('qrzru_password') == null) {
$callbook['error'] = 'Lookup not configured. Please review configuration.';
$callbook['source'] = $this->ci->qrzru->sourcename();
} else {
$username = $this->ci->config->item('qrzru_username');
$password = $this->ci->config->item('qrzru_password');
private function _qrzru($callsign) {
$this->ci->load->is_loaded('qrzru') ?: $this->ci->load->library('qrzru');
if (!$this->ci->session->userdata('qrzru_session_key')) {
$callbook['source'] = $this->ci->qrzru->sourcename();
$username = trim($this->ci->config->item('qrzru_username') ?? '');
$password = trim($this->ci->config->item('qrzru_password') ?? '');
if ($username == '' || $password == '') {
$callbook['error'] = $this->logbook_not_configured;
} else {
if (!$this->ci->cache->get($this->qrzru_session_cachekey)) {
$result = $this->ci->qrzru->session($username, $password);
$this->ci->session->set_userdata('qrzru_session_key', $result);
if (!$this->_validate_sessionkey($result)) {
$callbook['error'] = sprintf($this->error_obtaining_sessionkey, $result);
$this->ci->cache->delete($this->qrzru_session_cachekey);
return $callbook;
}
$this->ci->cache->save($this->qrzru_session_cachekey, $result, self::QRZRU_SESSION_DURATION);
}
$callbook = $this->ci->qrzru->search($callsign, $this->ci->session->userdata('qrzru_session_key'));
$callbook = $this->ci->qrzru->search($callsign, $this->ci->cache->get($this->qrzru_session_cachekey));
if ($callbook['error'] ?? '' == 'Session does not exist or expired') {
$qrzru_session_key = $this->ci->qrzru->session($username, $password);
$this->ci->session->set_userdata('qrzru_session_key', $qrzru_session_key);
$callbook = $this->ci->qrzru->search($callsign, $this->ci->session->userdata('qrzru_session_key'));
if (!$this->_validate_sessionkey($qrzru_session_key)) {
$callbook['error'] = sprintf($this->error_obtaining_sessionkey, $qrzru_session_key);
$this->ci->cache->delete($this->qrzru_session_cachekey);
return $callbook;
}
$this->ci->cache->save($this->qrzru_session_cachekey, $qrzru_session_key, self::QRZRU_SESSION_DURATION);
$callbook = $this->ci->qrzru->search($callsign, $this->ci->cache->get($this->qrzru_session_cachekey));
}
if (strpos($callbook['error'] ?? '', 'Callsign not found') !== false && strpos($callsign, "/") !== false) {
$plaincall = $this->get_plaincall($callsign);
// Now try again but give back reduced data, as we can't validate location and stuff (true at the end)
$callbook = $this->ci->qrzru->search($plaincall, $this->ci->session->userdata('qrzru_session_key'), true);
$callbook = $this->ci->qrzru->search($plaincall, $this->ci->cache->get($this->qrzru_session_cachekey), true);
}
}
$callbook['source'] = $this->ci->qrzru->sourcename();
return $callbook;
}
private function _validate_sessionkey($key) {
// Session key must be a non-empty string
if ($key == false || $key == '' || !is_string($key)) {
return false;
}
// All session keys should be at least 10 characters. Regarding to their documentation all keys have aprox. the same format
// "2331uf894c4bd29f3923f3bacf02c532d7bd9"
// Since it can differ and we want to don't overcomplicate things we simply check if the key is at least 10 characters long.
// If not, we consider it as invalid.
if (strlen($key) < 10) {
return false;
}
return true;
}
function get_plaincall($callsign) {
$split_callsign = explode('/', $callsign);
if (count($split_callsign) == 1) { // case of plain callsign --> return callsign

View File

@@ -80,7 +80,7 @@ class DxclusterCache {
$this->_delete_from_cache($this->get_worked_call_key($logbook_key, $callsign));
// Look up DXCC and continent from callsign
$dxccobj = new Dxcc(null);
$dxccobj = new Dxcc();
$dxcc_info = $dxccobj->dxcc_lookup($callsign, date('Y-m-d'));
if (!empty($dxcc_info['adif'])) {

View File

@@ -153,11 +153,6 @@ class EqslImporter
// The report from eQSL should only contain entries that have been confirmed via eQSL
// If there's a match for the QSO from the report in our log, it's confirmed via eQSL.
// If we have a positive match from eQSL, record it in the DB according to the user's preferences
if ( (array_key_exists('qsl_sent',$record)) && ($record['qsl_sent'] == "Y")) {
$record['qsl_sent'] = $config['eqsl_rcvd_mark'];
}
// SAT-Name not given? Create array-key and fill with null
if (!(array_key_exists('sat_name', $record))) {
$record['sat_name']=null;

View File

@@ -337,5 +337,25 @@ class Frequency {
}
return $unit;
}
/**
* Check if two frequencies are equal (handles different formats and empty values)
*
* @param mixed $freq1 First frequency (TX)
* @param mixed $freq2 Second frequency (RX)
* @return bool True if frequencies are equal or if one is empty/zero
*/
function frequencies_are_equal($freq1, $freq2) {
// Treat empty, null, or zero as "not set"
if (empty($freq1) || $freq1 === '0' || $freq1 === 0) {
return true;
}
if (empty($freq2) || $freq2 === '0' || $freq2 === 0) {
return true;
}
// Compare as floats to handle different string representations
return (float)$freq1 === (float)$freq2;
}
}
/* End of file Frequency.php */

View File

@@ -100,6 +100,7 @@ class Hamqth {
$data['error'] = (string)$xml->session->error;
$data['ituz'] = (string)$xml->search->itu;
$data['cqz'] = (string)$xml->search->cq;
$data['darc_dok'] = (string)$xml->search->dok;
if ($xml->search->country == "United States") {
$data['us_county'] = (string)$xml->search->us_county;
@@ -120,11 +121,13 @@ class Hamqth {
$data['error'] = (string)$xml->session->error;
$data['ituz'] = '';
$data['cqz'] = '';
$data['darc_dok'] = '';
$data['us_county'] = '';
}
} finally {
$data['source'] = $this->sourcename();
return $data;
}
}

View File

@@ -32,4 +32,30 @@ class Paths
}
return $datadir . "/" . $path;
}
function cache_buster($filepath) {
// make sure $filepath starts with a slash
if (substr($filepath, 0, 1) !== '/') $filepath = '/' . $filepath;
// These files are not existent on purpose and should not trigger error logs
$err_exceptions = [
'/assets/json/datatables_languages/en-US.json',
];
$CI = & get_instance();
$fullpath = empty($CI->config->item('directory')) ? $_SERVER['DOCUMENT_ROOT'] . $filepath : $_SERVER['DOCUMENT_ROOT'] . '/' . $CI->config->item('directory') . $filepath;
// We comment out this line because latest teste at LA8AJA's XAMPP setup showed that it works even without it
// So we will keep it simple and just use the $filepath as is, since it seems to work fine on both Linux and Windows setups
// $fullpath = rtrim($_SERVER['DOCUMENT_ROOT'], '/\\') . str_replace('/', DIRECTORY_SEPARATOR, $filepath);
if (file_exists($fullpath)) {
return base_url($filepath) . '?v=' . filemtime($fullpath);
} else {
if (!in_array($filepath, $err_exceptions)) {
log_message('error', 'CACHE BUSTER: File does not exist: ' . $fullpath);
}
}
return base_url($filepath);
}
}

View File

@@ -182,6 +182,7 @@ class Qrz {
$data['cqzone'] = '';
}
} finally {
$data['source'] = $this->sourcename();
return $data;
}
}

View File

@@ -143,6 +143,7 @@ class Qrzcq {
}
} finally {
$data['source'] = $this->sourcename();
return $data;
}
}

View File

@@ -114,6 +114,7 @@ class Qrzru {
$data['cqz'] = '';
}
} finally {
$data['source'] = $this->sourcename();
return $data;
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,21 +0,0 @@
<?php defined('BASEPATH') OR exit('No direct script access allowed');
class Migration_add_lotw_credentials extends CI_Migration {
public function up()
{
$fields = array(
'user_lotw_name VARCHAR(32) DEFAULT NULL',
'user_lotw_password VARCHAR(64) DEFAULT NULL'
);
$this->dbforge->add_column('users', $fields);
}
public function down()
{
$this->dbforge->drop_column('users', 'user_lotw_name');
$this->dbforge->drop_column('users', 'user_lotw_password');
}
}
?>

View File

@@ -1,41 +0,0 @@
<?php defined('BASEPATH') OR exit('No direct script access allowed');
class Migration_add_config_table extends CI_Migration {
public function up()
{
$this->dbforge->add_field('id');
$this->dbforge->add_field(array(
'lotw_download_url' => array(
'type' => 'VARCHAR',
'constraint' => 255,
),
'lotw_upload_url' => array(
'type' => 'VARCHAR',
'constraint' => 255,
),
'lotw_rcvd_mark' => array(
'type' => 'VARCHAR',
'constraint' => 1,
),
));
$this->dbforge->create_table('config');
$data = array(
'lotw_download_url' => 'https://p1k.arrl.org/lotwuser/lotwreport.adi',
'lotw_upload_url' => 'https://p1k.arrl.org/lotwuser/upload',
'lotw_rcvd_mark' => 'Y'
);
$this->db->insert('config', $data);
}
public function down()
{
$this->dbforge->drop_table('config');
}
}
?>

Some files were not shown because too many files have changed in this diff Show More