diff --git a/README.md b/README.md index 0ca7a08b3..fe398b107 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Translation Status - Commit Activity + Commit Activity @@ -68,11 +68,11 @@ Wavelog-support can be reached by creating an issue here at github. If you've an Special thanks to our contributors, who are part of Wavelog by improving code! -[F4ANS](https://github.com/abarrau), [DG0TM](https://github.com/dg0tm), [DG9VH](https://github.com/dg9vh), [DJ3CE](https://github.com/dj3ce), [R1BLH](https://github.com/r1blh), [BG2ELG](https://github.com/violarulan), [DF1ASH](https://github.com/derFogel), [DB4SCW](https://github.com/DB4SCW), [VE2HEW](https://github.com/anthonydiiorio), [OK1GOD](https://github.com/filipmelik), [DJ1PW](https://github.com/winnieXY), [toseppo](https://github.com/toseppo), [N7DSB](https://github.com/desertblade), [BA7LAC](https://github.com/imlonghao) +[F4ANS](https://github.com/abarrau), [DG0TM](https://github.com/dg0tm), [DG9VH](https://github.com/dg9vh), [DJ3CE](https://github.com/dj3ce), [R1BLH](https://github.com/r1blh), [BG2ELG](https://github.com/violarulan), [DF1ASH](https://github.com/derFogel), [DB4SCW](https://github.com/DB4SCW), [VE2HEW](https://github.com/anthonydiiorio), [OK1GOD](https://github.com/filipmelik), [DJ1PW](https://github.com/winnieXY), [toseppo](https://github.com/toseppo), [N7DSB](https://github.com/desertblade), [BA7LAC](https://github.com/imlonghao), [Ethan C. Edwards](https://github.com/ethancedwards8) Translators: -[Ondřej Koloničný (OK1CDJ)](https://translate.wavelog.org/user/ok1cdj/), [Michael Skolsky (R1BLH)](https://translate.wavelog.org/user/R1BLH/), [Karuru (BG2ELG)](https://translate.wavelog.org/user/viola/), [Byt3](https://translate.wavelog.org/user/205er/), [BG6HJE](https://translate.wavelog.org/user/BG6HJE/), [Francisco (F4VSE)](https://translate.wavelog.org/user/kikosgc/), [Kim (DG9VH)](https://translate.wavelog.org/user/dg9vh/), [Casper van Lieburg (PA7DX)](https://translate.wavelog.org/user/pa7dx/), [Halil AYYILDIZ (TA2LG)](https://translate.wavelog.org/user/TA2LG/), [Michal Šiman](https://translate.wavelog.org/user/michalsiman/), [DN4BS](https://github.com/dn4bs), [Luca (IU2FRL)](https://translate.wavelog.org/user/iu2frl/), [Dragan Đorđević (4O4A)](https://translate.wavelog.org/user/4o4a/), [Dren Imeraj (Z63DRI)](https://translate.wavelog.org/user/Dren/), [Filip Melik (OK1GOD)](https://translate.wavelog.org/user/filipmelik/), [Petr (OK1PTR)](https://translate.wavelog.org/user/OK1PTR/), [Stefan (DB4SCW)](https://translate.wavelog.org/user/DB4SCW/), [F4JSU](https://translate.wavelog.org/user/F4JSU/), [Maciej](https://translate.wavelog.org/user/maciejla/), [imlonghao](https://translate.wavelog.org/user/imlonghao/), [Reiner Herrmann](https://translate.wavelog.org/user/reinerh/), [Jian ke (BG8IXZ)](https://translate.wavelog.org/user/bg8ixz/), [Fabian Franz](https://translate.wavelog.org/user/fabianfrz/), [Fatih Önder](https://translate.wavelog.org/user/cektor/), [Qing He(BD8DHF)](https://translate.wavelog.org/user/BD8DHF), [hellofinch](https://translate.wavelog.org/user/hellofinch/), [tviitkar (ES5TVI )](https://translate.wavelog.org/user/tviitkar/), [utkuyalcin](https://translate.wavelog.org/user/utkuyalcin/), [Plamen Panteleev (LZ1PPL)](https://translate.wavelog.org/user/lz1ppl/), [Bartek](https://translate.wavelog.org/user/atimias/), [Samir (DL4DCO)](https://translate.wavelog.org/user/DL4DCO/) +[Ondřej Koloničný (OK1CDJ)](https://translate.wavelog.org/user/ok1cdj/), [Michael Skolsky (R1BLH)](https://translate.wavelog.org/user/R1BLH/), [Karuru (BG2ELG)](https://translate.wavelog.org/user/viola/), [Byt3](https://translate.wavelog.org/user/205er/), [BG6HJE](https://translate.wavelog.org/user/BG6HJE/), [Francisco (F4VSE)](https://translate.wavelog.org/user/kikosgc/), [Kim (DG9VH)](https://translate.wavelog.org/user/dg9vh/), [Casper van Lieburg (PA7DX)](https://translate.wavelog.org/user/pa7dx/), [Halil AYYILDIZ (TA2LG)](https://translate.wavelog.org/user/TA2LG/), [Michal Šiman](https://translate.wavelog.org/user/michalsiman/), [DN4BS](https://github.com/dn4bs), [Luca (IU2FRL)](https://translate.wavelog.org/user/iu2frl/), [Dragan Đorđević (4O4A)](https://translate.wavelog.org/user/4o4a/), [Dren Imeraj (Z63DRI)](https://translate.wavelog.org/user/Dren/), [Filip Melik (OK1GOD)](https://translate.wavelog.org/user/filipmelik/), [Petr (OK1PTR)](https://translate.wavelog.org/user/OK1PTR/), [Stefan (DB4SCW)](https://translate.wavelog.org/user/DB4SCW/), [F4JSU](https://translate.wavelog.org/user/F4JSU/), [Maciej](https://translate.wavelog.org/user/maciejla/), [imlonghao](https://translate.wavelog.org/user/imlonghao/), [Reiner Herrmann](https://translate.wavelog.org/user/reinerh/), [Jian ke (BG8IXZ)](https://translate.wavelog.org/user/bg8ixz/), [Fabian Franz](https://translate.wavelog.org/user/fabianfrz/), [Fatih Önder](https://translate.wavelog.org/user/cektor/), [Qing He(BD8DHF)](https://translate.wavelog.org/user/BD8DHF), [hellofinch](https://translate.wavelog.org/user/hellofinch/), [tviitkar (ES5TVI )](https://translate.wavelog.org/user/tviitkar/), [utkuyalcin](https://translate.wavelog.org/user/utkuyalcin/), [Plamen Panteleev (LZ1PPL)](https://translate.wavelog.org/user/lz1ppl/), [Bartek](https://translate.wavelog.org/user/atimias/), [Samir (DL4DCO)](https://translate.wavelog.org/user/DL4DCO/), [Stanisław Korzeń (SP5CRO)](https://translate.wavelog.org/user/sp5cro/), [wxy (BA7NID)](https://translate.wavelog.org/user/ba7nid/), [David Quental (CT1DRB)](https://translate.wavelog.org/user/ct1drb/), [Sebastian K.](https://translate.wavelog.org/user/sebket/), [Limes](https://translate.wavelog.org/user/limes-github/), [Ethan C. Edwards](https://translate.wavelog.org/user/ethancedwards8/) If you would like to contribute in any way to Wavelog, it is most appreciated. This has been developed in free time, help coding new features or writing documentation is always useful. diff --git a/application/config/autoload.php b/application/config/autoload.php index 7eb077e1c..6b290c493 100644 --- a/application/config/autoload.php +++ b/application/config/autoload.php @@ -64,7 +64,7 @@ $autoload['libraries'] = array('database', 'session', 'curl', 'OptionsLib', 'Pat | $autoload['helper'] = array('url', 'file'); */ -$autoload['helper'] = array('url', 'security', 'language'); +$autoload['helper'] = array('url', 'security', 'language', 'club'); /* diff --git a/application/config/config.sample.php b/application/config/config.sample.php index 463551db3..6c871f3d0 100644 --- a/application/config/config.sample.php +++ b/application/config/config.sample.php @@ -14,7 +14,7 @@ defined('BASEPATH') OR exit('No direct script access allowed'); $config['app_name'] = 'Wavelog'; $config['directory'] = 'logbook'; -$config['callbook'] = 'hamqth'; // Options are hamqth or qrz +$config['callbook'] = 'hamqth'; // Options are hamqth, qrz or qrzcq $config['datadir'] = null; // default to install directory @@ -57,6 +57,17 @@ $config['use_fullname'] = false; $config['hamqth_username'] = ''; $config['hamqth_password'] = ''; +/* +|-------------------------------------------------------------------------- +| QRZcq Login Options +|-------------------------------------------------------------------------- +| +| 'qrzcq_username' QRZcq.com user login +| 'qrzcq_password' QRZcq.com user password +*/ +$config['qrzcq_username'] = ''; +$config['qrzcq_password'] = ''; + /* |-------------------------------------------------------------------------- | Authentication @@ -460,7 +471,7 @@ $config['sess_match_ip'] = FALSE; $config['sess_time_to_update'] = 300; $config['sess_regenerate_destroy'] = FALSE; -/* +/* * To make sure we do not collect infinite session we set some garbage collection settings * see https://www.php.net/manual/en/session.configuration.php#ini.session.gc-probability * and https://www.php.net/manual/en/session.configuration.php#ini.session.gc-divisor @@ -642,7 +653,7 @@ $config['disable_manual_qrz'] = false; | Disables QSL-Image-Feature |-------------------------------------------------------------------------- | -| This disabled the whole QSL image feature if you don't need it and want to hide it. +| This disabled the whole QSL image feature if you don't need it and want to hide it. | Set to true will hide all QSL image related stuff in Wavelog | */ @@ -654,7 +665,7 @@ $config['disable_qsl'] = false; | Disables OQRS-Feature |-------------------------------------------------------------------------- | -| This disabled the whole OQRS feature if you don't need it and want to hide it. +| This disabled the whole OQRS feature if you don't need it and want to hide it. | Set to true will hide all OQRS related stuff in Wavelog | */ @@ -663,25 +674,21 @@ $config['disable_oqrs'] = false; /* |-------------------------------------------------------------------------- -| Special Callsign Feature +| Special Callsign Feature aka. Clubstations Support |-------------------------------------------------------------------------- | -| This config switch is meant to use for Special Callsign operations in a dedicated Wavelog Installation -| If this switch is set to true it will enable a dialog which pops up for each operator after login -| to ask for his personal callsign. This causes the QSOs to get saved with the correct operator data. -| Example: Special Callsign: DL250CDF -| Operator: DF2TG -| -| It is recommend to enable also "Disable Syncing to 3rd party-Services at UI" -| More Information about this feature and how to use it, you can find here: -| https://github.com/wavelog/wavelog/wiki/Recommended-Setup-for-Special-Callsigns-and-Clubs +| This config switch is meant to use 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 +| +| !!! Important !!! +| $config['disable_impersonate'] has to be set to false to use this feature. +| */ $config['special_callsign'] = false; -// hides the usermenu; takes action only if "special_callsign" is true -$config['sc_hide_usermenu'] = true; - /* |-------------------------------------------------------------------------- @@ -689,11 +696,11 @@ $config['sc_hide_usermenu'] = true; |-------------------------------------------------------------------------- | | This config switch disables the impersonate feature. This feauture is used to impersonate another user. -| Impersonate is enabled by default. To disable it, set the value to false. -| +| Impersonate is enabled by default. To disable it, set the value to false. Also the special_callsign feature needs this to be false. +| */ -$config['disable_impersonate'] = false; +$config['disable_impersonate'] = false; /* @@ -703,7 +710,7 @@ $config['disable_impersonate'] = false; | | The cronmanager needs http or https with a valid certificate to work. | If you want to use it with https and a self-signed certificate, you need to set this to true. -| +| */ $config['cron_allow_insecure'] = false; @@ -725,6 +732,10 @@ $config['disable_version_check'] = false; | trx-control Configuration |-------------------------------------------------------------------------- | +| *** +| No Features implemented yet, Nothing is going to happen if you set this. +| *** +| | This defines server and port of your personal trx-control server. | If you don't have a trx-control server, you can ignore this. | @@ -746,4 +757,15 @@ $config['disable_version_check'] = false; // $config['trxd_server_port'] = '14290'; // $config['trxd_connection_type'] = 'ws'; // $config['trxd_ws_path'] = '/trx-control'; -// $config['trxd_timeout'] = 5; \ No newline at end of file +// $config['trxd_timeout'] = 5; + +/* +|-------------------------------------------------------------------------- +| eqsl.cc Massdownloa +|-------------------------------------------------------------------------- +| +| The eqsl.cc mass download function is not threadsafe. So it is disabled by default. +| Please consider enabling this carefully. Not recommended for multi-user environments. + */ + +$config['enable_eqsl_massdownload'] = false; diff --git a/application/config/gettext.php b/application/config/gettext.php index 651f02e5e..8e645fbd2 100644 --- a/application/config/gettext.php +++ b/application/config/gettext.php @@ -300,6 +300,16 @@ $config['languages'] = array( 'direction' => 'ltr', 'code' => 'tr', 'flag' => 'tr', + ), + 'armenian' => array( + 'name' => 'Հայերեն', + 'name_en' => 'Armenian', + 'folder' => 'armenian', + 'locale' => 'hy', + 'gettext' => 'hy', + 'direction' => 'ltr', + 'code' => 'hy', + 'flag' => 'am', ) ); diff --git a/application/config/migration.php b/application/config/migration.php index 42282860f..5108d575b 100644 --- a/application/config/migration.php +++ b/application/config/migration.php @@ -22,7 +22,7 @@ $config['migration_enabled'] = TRUE; | */ -$config['migration_version'] = 227; +$config['migration_version'] = 233; /* |-------------------------------------------------------------------------- diff --git a/application/controllers/Activated_gridmap.php b/application/controllers/Activated_gridmap.php index f3d93c5bc..8c59248ac 100644 --- a/application/controllers/Activated_gridmap.php +++ b/application/controllers/Activated_gridmap.php @@ -33,13 +33,18 @@ class Activated_gridmap extends CI_Controller { $data['gridsquares_gridsquares_not_confirmed'] = __("Gridsquares not confirmed"); $data['gridsquares_gridsquares_total_activated'] = __("Total gridsquares activated"); + $data['gridsquares_fields'] = __("Fields"); + $data['gridsquares_fields_confirmed'] = __("Fields confirmed"); + $data['gridsquares_fields_not_confirmed'] = __("Fields not confirmed"); + $data['gridsquares_fields_total_worked'] = __("Total fields worked"); + $footerData = []; $footerData['scripts'] = [ 'assets/js/leaflet/geocoding.js', 'assets/js/leaflet/L.MaidenheadColouredGridMap.js', 'assets/js/sections/gridmap.js?' ]; - + $this->load->view('interface_assets/header', $data); $this->load->view('activated_gridmap/index'); $this->load->view('interface_assets/footer', $footerData); @@ -87,16 +92,16 @@ class Activated_gridmap extends CI_Controller { // Check if 2 Char is in array if(!in_array($grid_2char_confirmed, $array_grid_2char_confirmed)){ - array_push($array_grid_2char_confirmed, $grid_2char_confirmed); + array_push($array_grid_2char_confirmed, $grid_2char_confirmed); } if(!in_array($grid_4char_confirmed, $array_grid_4char_confirmed)){ - array_push($array_grid_4char_confirmed, $grid_4char_confirmed); + array_push($array_grid_4char_confirmed, $grid_4char_confirmed); } if ($this->config->item('map_6digit_grids')) { if(!in_array($grid_6char_confirmed, $array_grid_6char_confirmed)){ - array_push($array_grid_6char_confirmed, $grid_6char_confirmed); + array_push($array_grid_6char_confirmed, $grid_6char_confirmed); } } } @@ -118,16 +123,16 @@ class Activated_gridmap extends CI_Controller { // Check if 2 Char is in array if(!in_array($grid_two, $array_grid_2char)){ - array_push($array_grid_2char, $grid_two); + array_push($array_grid_2char, $grid_two); } if(!in_array($grid_four, $array_grid_4char)){ - array_push($array_grid_4char, $grid_four); + array_push($array_grid_4char, $grid_four); } if ($this->config->item('map_6digit_grids')) { if(!in_array($grid_six, $array_grid_6char)){ - array_push($array_grid_6char, $grid_six); + array_push($array_grid_6char, $grid_six); } } } @@ -140,18 +145,18 @@ class Activated_gridmap extends CI_Controller { $grids = explode(",", $row->COL_VUCC_GRIDS); - foreach($grids as $key) { + foreach($grids as $key) { $grid_two = strtoupper(substr($key,0,2)); $grid_four = strtoupper(substr($key,0,4)); // Check if 2 Char is in array if(!in_array($grid_two, $array_grid_2char)){ - array_push($array_grid_2char, $grid_two); + array_push($array_grid_2char, $grid_two); } if(!in_array($grid_four, $array_grid_4char)){ - array_push($array_grid_4char, $grid_four); + array_push($array_grid_4char, $grid_four); } } } @@ -165,18 +170,18 @@ class Activated_gridmap extends CI_Controller { $grids = explode(",", $row->COL_VUCC_GRIDS); - foreach($grids as $key) { + foreach($grids as $key) { $grid_2char_confirmed = strtoupper(substr($key,0,2)); $grid_4char_confirmed = strtoupper(substr($key,0,4)); // Check if 2 Char is in array if(!in_array($grid_2char_confirmed, $array_grid_2char_confirmed)){ - array_push($array_grid_2char_confirmed, $grid_2char_confirmed); + array_push($array_grid_2char_confirmed, $grid_2char_confirmed); } if(!in_array($grid_4char_confirmed, $array_grid_4char_confirmed)){ - array_push($array_grid_4char_confirmed, $grid_4char_confirmed); + array_push($array_grid_4char_confirmed, $grid_4char_confirmed); } } } diff --git a/application/controllers/Adif.php b/application/controllers/Adif.php index fd2929aa3..932ad83b6 100644 --- a/application/controllers/Adif.php +++ b/application/controllers/Adif.php @@ -10,7 +10,7 @@ class adif extends CI_Controller { $this->load->helper(array('form', 'url')); $this->load->model('user_model'); - if(!$this->user_model->authorize(2)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } + if(!$this->user_model->authorize(2) || !clubaccess_check(9)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } } public function test() { @@ -145,6 +145,13 @@ class adif extends CI_Controller { $data['page_title'] = __("ADIF Import / Export"); $data['max_upload'] = ini_get('upload_max_filesize'); + if ($this->config->item('special_callsign') && clubaccess_check(9) && $this->session->userdata('clubstation') == 1) { + $this->load->model('club_model'); + $data['club_operators'] = $this->club_model->get_club_members($this->session->userdata('user_id')); + } else { + $data['club_operators'] = false; + } + $data['station_profile'] = $this->stations->all_of_user(); $active_station_id = $this->stations->find_active(); $station_profile = $this->stations->profile($active_station_id); @@ -185,7 +192,8 @@ class adif extends CI_Controller { $this->load->view('interface_assets/footer'); } else { if ($this->stations->check_station_is_accessible($this->input->post('station_profile', TRUE))) { - $contest=$this->security->xss_clean($this->input->post('contest')) ?? ''; + $contest=$this->input->post('contest', true) ?? ''; + $club_operator=$this->input->post('club_operator', true) ?? ''; $stopnow=false; $fdata = array('upload_data' => $this->upload->data()); ini_set('memory_limit', '-1'); @@ -232,6 +240,7 @@ class adif extends CI_Controller { if ($contest != '') { $record['contest_id'] = $contest; } +<<<<<<< HEAD //check if contest_id exists in record and extract all found contest_ids if(array_key_exists('contest_id', $record)){ @@ -245,6 +254,11 @@ class adif extends CI_Controller { } } +======= + if ($club_operator != '') { + $record['operator']=strtoupper($club_operator); + } +>>>>>>> dev if(count($record) == 0) { break; }; @@ -252,7 +266,7 @@ class adif extends CI_Controller { }; $record=''; // free memory try { - $custom_errors = $this->logbook_model->import_bulk($alladif, $this->input->post('station_profile', TRUE), $this->input->post('skipDuplicate'), $this->input->post('markClublog'),$this->input->post('markLotw'), $this->input->post('dxccAdif'), $this->input->post('markQrz'), $this->input->post('markEqsl'), $this->input->post('markHrd'), true, $this->input->post('operatorName'), false, $this->input->post('skipStationCheck')); + $custom_errors = $this->logbook_model->import_bulk($alladif, $this->input->post('station_profile', TRUE), $this->input->post('skipDuplicate'), $this->input->post('markClublog'),$this->input->post('markLotw'), $this->input->post('dxccAdif'), $this->input->post('markQrz'), $this->input->post('markEqsl'), $this->input->post('markHrd'), $this->input->post('markDcl'), true, $this->input->post('operatorName') ?? false, false, $this->input->post('skipStationCheck')); } catch (Exception $e) { log_message('error', 'Import error: '.$e->getMessage()); $data['page_title'] = __("ADIF Import failed!"); @@ -272,12 +286,6 @@ class adif extends CI_Controller { $custom_errors=__("Station Profile not valid for User"); } - // Lets clean up static maps cache for this station - if (!$this->load->is_loaded('staticmap_model')) { - $this->load->model('staticmap_model'); - } - $this->staticmap_model->remove_static_map_image($this->input->post('station_profile', TRUE)); - log_message("Error","ADIF End"); $data['adif_errors'] = $custom_errors; $data['skip_dupes'] = $this->input->post('skipDuplicate'); diff --git a/application/controllers/Api.php b/application/controllers/Api.php index 422dfc55c..5b0692345 100644 --- a/application/controllers/Api.php +++ b/application/controllers/Api.php @@ -2,44 +2,31 @@ class API extends CI_Controller { - // Do absolutely nothing - function index() - { - echo "nothing to see"; - } - - function help() - { + function index() { $this->load->model('user_model'); - - // Check if users logged in - - if($this->user_model->validate_session() == 0) { - // user is not logged in - redirect('user/login'); - } + if(!$this->user_model->authorize(3)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } $this->load->model('api_model'); + $this->load->library('form_validation'); $data['api_keys'] = $this->api_model->keys(); - + $data['clubmode'] = $this->session->userdata('clubstation') == 1 ? true : false; $data['page_title'] = __("API"); $this->load->view('interface_assets/header', $data); - $this->load->view('api/help'); + $this->load->view('api/index'); $this->load->view('interface_assets/footer'); } + // legacy + function help() { + redirect('api'); + } + function edit($key) { $this->load->model('user_model'); - - // Check if users logged in - - if($this->user_model->validate_session() == 0) { - // user is not logged in - redirect('user/login'); - } + if(!$this->user_model->authorize(3)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } $this->load->model('api_model'); @@ -68,38 +55,40 @@ class API extends CI_Controller { $this->session->set_flashdata('notice', sprintf(__("API Key %s description has been updated."), "".$this->input->post('api_key')."")); - redirect('api/help'); + redirect('api'); } } function generate($rights) { $this->load->model('user_model'); + if(!$this->user_model->authorize(3)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } - // Check if users logged in - - if($this->user_model->validate_session() == 0) { - // user is not logged in - redirect('user/login'); + if ($rights !== "r" && $rights !== "rw") { + $this->session->set_flashdata('error', __("Invalid API rights")); + redirect('api'); + exit; } - $this->load->model('api_model'); - $data['api_keys'] = $this->api_model->generate_key($rights); + if ($this->session->userdata('clubstation') == 1 && $this->session->userdata('impersonate') == 1) { + $creator = $this->session->userdata('source_uid'); + } else { + $creator = $this->session->userdata('user_id'); + } - redirect('api/help'); + if ($this->api_model->generate_key($rights, $creator)) { + $this->session->set_flashdata('success', __("API Key generated")); + } else { + $this->session->set_flashdata('error', __("API Key could not be generated")); + } + redirect('api'); } function delete($key) { $this->load->model('user_model'); - - // Check if users logged in - - if($this->user_model->validate_session() == 0) { - // user is not logged in - redirect('user/login'); - } + if(!$this->user_model->authorize(3)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } $this->load->model('api_model'); @@ -108,11 +97,11 @@ class API extends CI_Controller { $this->session->set_flashdata('notice', sprintf(__("API Key %s has been deleted"), "".$key."" )); - redirect('api/help'); + redirect('api'); } // Example of authing - function auth($key) { + function auth($key = '') { $this->load->model('api_model'); header("Content-type: text/xml"); if($this->api_model->access($key) == "No Key Found" || $this->api_model->access($key) == "Key Disabled") { @@ -128,7 +117,7 @@ class API extends CI_Controller { } } - function station_info($key) { + function station_info($key = '') { $this->load->model('api_model'); $this->load->model('stations'); header("Content-type: application/json"); @@ -168,6 +157,10 @@ class API extends CI_Controller { $this->load->model('stations'); + if (!$this->load->is_loaded('Qra')) { + $this->load->library('Qra'); + } + $return_msg = array(); $return_count = 0; @@ -187,6 +180,25 @@ class API extends CI_Controller { } $userid = $this->api_model->key_userid($obj['key']); + $created_by = $this->api_model->key_created_by($obj['key']); + + /** + * As the API key user could use it also for clubstations we need to do an additional check here. Only if clubstations are enabled + * + * In Detail: + * If the user is not the creator of the API key, it's likely a clubstation. In this case the callsign of the clubstation + * can not be the same as the callsign of the user (operator call provided by the user). If this is the case, we need to use the callsign of the creator of the API key + */ + if ($this->config->item('special_callsign')) { + if ($userid != $created_by) { + $this->load->model('user_model'); + $real_operator = $this->user_model->get_by_id($created_by)->row()->user_callsign; + // TODO: It would be possible to check here if operator is allowed to use the clubstation, but this can be added later if needed + } else { + $real_operator = null; + } + } + $this->api_model->update_last_used(($obj['key'])); if(!isset($obj['station_profile_id']) || $this->stations->check_station_against_user($obj['station_profile_id'], $userid) == false) { @@ -194,6 +206,8 @@ class API extends CI_Controller { echo json_encode(['status' => 'failed', 'reason' => "station id does not belong to the API key owner."]); die(); } + $mystation=$this->stations->profile_clean($obj['station_profile_id']); + $mygrid=($mystation->station_gridsquare ?? ''); if($obj['type'] == "adif" && $obj['string'] != "") { // Load the logbook model for adding QSO records @@ -220,13 +234,22 @@ class API extends CI_Controller { } if(count($record) == 0) { break; - }; + } + // in case the provided op call is the same as the clubstation callsign, we need to use the creator of the API key as the operator + $recorded_operator = $record['operator'] ?? ''; + if ($real_operator != null && ($record['operator'] == $record['station_callsign']) || ($recorded_operator == '')) { + $record['operator'] = $real_operator; + } + + if ((key_exists('gridsquare',$record)) && (($mygrid ?? '') != '') && (($record['gridsquare'] ?? '') != '') && (!(key_exists('distance',$record)))) { + $record['distance'] = $this->qra->distance($mygrid, $record['gridsquare'], 'K'); + } array_push($alladif,$record); $adif_count++; }; $record=''; // free memory gc_collect_cycles(); - $custom_errors = $this->logbook_model->import_bulk($alladif, $obj['station_profile_id'], false, false, false, false, false, false, false, true, false, true, false); + $custom_errors = $this->logbook_model->import_bulk($alladif, $obj['station_profile_id'], false, false, false, false, false, false, false, false, true, false, true, false); if ($custom_errors) { $adif_errors++; } @@ -236,8 +259,15 @@ class API extends CI_Controller { $return_msg[]='Dryrun works'; } - http_response_code(201); - echo json_encode(['status' => 'created', 'type' => $obj['type'], 'string' => $obj['string'], 'adif_count' => $adif_count, 'adif_errors' => $adif_errors, 'messages' => $return_msg ]); + if ($adif_errors == 0) { + http_response_code(201); + echo json_encode(['status' => 'created', 'type' => $obj['type'], 'string' => $obj['string'], 'adif_count' => $adif_count, 'adif_errors' => $adif_errors, 'messages' => $return_msg ]); + } else { + $return_msg[]=$custom_errors; + http_response_code(400); + echo json_encode(['status' => 'abort', 'type' => $obj['type'], 'string' => $obj['string'], 'adif_count' => $adif_count, 'adif_errors' => $adif_errors, 'messages' => $return_msg ]); + } + } @@ -559,6 +589,14 @@ class API extends CI_Controller { $this->api_model->update_last_used($obj['key']); $user_id = $this->api_model->key_userid($obj['key']); + $created_by = $this->api_model->key_created_by($obj['key']); + + // Clubmode needs an additional check for the operator + if ($user_id != $created_by) { + $operator = $created_by; + } else { + $operator = $user_id; + } // Special Case: Yaesu Radio's use CW-U and CW-L which aren't official ADIF Modes. We override this here to CW if (isset($obj['mode']) && (strtoupper($obj['mode']) == 'CW-U' || strtoupper($obj['mode']) == 'CW-L')) { @@ -566,7 +604,7 @@ class API extends CI_Controller { } // Store Result to Database - $this->cat->update($obj, $user_id); + $this->cat->update($obj, $user_id, $operator); // Return Message diff --git a/application/controllers/Awards.php b/application/controllers/Awards.php index 71974e94f..ba399b851 100644 --- a/application/controllers/Awards.php +++ b/application/controllers/Awards.php @@ -1917,4 +1917,82 @@ class Awards extends CI_Controller { $this->load->view('interface_assets/footer'); } + public function wae () { + $this->load->model('wae'); + $this->load->model('modes'); + $this->load->model('bands'); + + $data['orbits'] = $this->bands->get_worked_orbits(); + $data['sats_available'] = $this->bands->get_worked_sats(); + $data['user_default_band'] = $this->session->userdata('user_default_band'); + + $data['worked_bands'] = $this->bands->get_worked_bands('dxcc'); // Used in the view for band select + $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. + if ($this->input->post('band') == 'All') { // Did the user specify a band? If not, use all bands + $bands = $data['worked_bands']; + } else { + $bands[] = $this->security->xss_clean($this->input->post('band')); + } + } else { + $bands = $data['worked_bands']; + } + + $data['bands'] = $bands; // Used for displaying selected band(s) in the table in the view + + if($this->input->method() === 'post') { + $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['clublog'] = $this->input->post('clublog') == 0 ? NULL: 1; + $postdata['worked'] = $this->input->post('worked') == 0 ? NULL: 1; + $postdata['confirmed'] = $this->input->post('confirmed') == 0 ? NULL: 1; + $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')); + } 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['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'; + } + + $data['wae_array'] = $this->wae->get_wae_array($bands, $postdata); + $data['wae_summary'] = $this->wae->get_wae_summary($bands, $postdata); + + // Render Page + $data['page_title'] = sprintf(__("Awards - %s"), __("WAE")); + $this->load->view('interface_assets/header', $data); + $this->load->view('awards/wae/index'); + $this->load->view('interface_assets/footer'); + } + } diff --git a/application/controllers/Band.php b/application/controllers/Band.php index ca5f0e9a3..e37055e4f 100644 --- a/application/controllers/Band.php +++ b/application/controllers/Band.php @@ -12,7 +12,7 @@ class Band extends CI_Controller { $this->load->helper(array('form', 'url')); $this->load->model('user_model'); - if(!$this->user_model->authorize(2)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } + if(!$this->user_model->authorize(2) || !clubaccess_check(9)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } } public function index() diff --git a/application/controllers/Cabrillo.php b/application/controllers/Cabrillo.php index fb3368bb4..faa733964 100644 --- a/application/controllers/Cabrillo.php +++ b/application/controllers/Cabrillo.php @@ -13,7 +13,7 @@ class Cabrillo extends CI_Controller { parent::__construct(); $this->load->model('user_model'); - if(!$this->user_model->authorize(2)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } + if(!$this->user_model->authorize(2) || !clubaccess_check(9)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } } public function index() { diff --git a/application/controllers/Cfdexport.php b/application/controllers/Cfdexport.php index 783bb4f7c..517dcc1b6 100644 --- a/application/controllers/Cfdexport.php +++ b/application/controllers/Cfdexport.php @@ -15,7 +15,7 @@ class Cfdexport extends CI_Controller { $this->load->model('logbook_model'); $this->load->model('bands'); - if(!$this->user_model->authorize(2)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } + if(!$this->user_model->authorize(2) || !clubaccess_check(9)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } $data['page_title'] = __("CFD Export"); diff --git a/application/controllers/Club.php b/application/controllers/Club.php new file mode 100644 index 000000000..99a27960a --- /dev/null +++ b/application/controllers/Club.php @@ -0,0 +1,243 @@ +permissions = [ + 9 => __("Club Officer"), + 3 => __("Club Member"), + ]; + } + + public function index() + { + // nothing to display + redirect('dashboard'); + } + + public function permissions($club_id) { + + $this->load->model('user_model'); + $this->load->model('club_model'); + $this->load->library('form_validation'); + + $cid = $this->security->xss_clean($club_id); + $club = $this->user_model->get_by_id($cid)->row(); + + if (!is_numeric($cid)) { + $this->session->set_flashdata('error', __("Invalid User ID!")); + redirect('user'); + } + if(!$this->user_model->authorize(99) && !$this->club_model->club_authorize(9, $cid)) { + $this->session->set_flashdata('error', __("You're not allowed to do that!")); + redirect('dashboard'); + } + if ($club->clubstation != 1) { + $this->session->set_flashdata('error', __("This user is not a club station.")); + redirect('user'); + } + + $data['page_title'] = __("Club Permissions"); + $data['club'] = $club; + $data['club_members'] = $this->club_model->get_club_members($cid); + $data['users'] = $this->user_model->users(); + $data['permissions'] = $this->permissions; + + $footerData = []; + $footerData['scripts'] = [ + 'assets/js/sections/club_permissions.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/club_permissions.js")), + ]; + + $this->load->view('interface_assets/header', $data); + $this->load->view('club/permissions'); + $this->load->view('interface_assets/footer', $footerData); + } + + public function get_users() { + + if(!clubaccess_check(9)) { + $this->session->set_flashdata('error', __("You're not allowed to do that!")); + redirect('dashboard'); + } + if (!$this->load->is_loaded('user_model')) { + $this->load->model('user_model'); + } + + $query = (string) $this->input->post('query', true) ?? ''; + if (empty($query)) { + header('Content-Type: application/json'); + echo json_encode([]); + return; + } + + $users = $this->user_model->search_users($query); + + $result = []; + + if ($users != false) { + foreach ($users->result() as $user) { + $result[] = [ + 'user_id' => $user->user_id, + 'user_callsign' => $user->user_callsign, + 'user_firstname' => $user->user_firstname, + 'user_lastname' => $user->user_lastname + ]; + } + } + + header('Content-Type: application/json'); + echo json_encode($result); + } + + public function alter_member() { + + $this->load->model('user_model'); + $this->load->model('club_model'); + + $club_id = $this->input->post('club_id', true); + $user_id = $this->input->post('user_id', true); + $p_level = $this->input->post('permission', true); + + if (!is_numeric($club_id)) { + $this->session->set_flashdata('error', __("Invalid Club ID!")); + redirect('dashboard'); + } + if(!$this->user_model->authorize(99) && !$this->club_model->club_authorize(9, $club_id)) { + $this->session->set_flashdata('error', __("You're not allowed to do that!")); + redirect('dashboard'); + } + + $this->club_model->alter_member($club_id, $user_id, $p_level); + + if ($this->input->post('notify_user', true) == 'on') { + if (!$this->notification($user_id, $club_id, $this->input->post('notify_message', true))) { + $this->session->set_flashdata('error', __("User could not be notified. Please check your email settings.")); + } + } + + $this->session->set_flashdata('success', __("Club member permissions have been updated.")); + redirect('club/permissions/'.$club_id); + } + + public function delete_member() { + + $this->load->model('user_model'); + $this->load->model('club_model'); + + $club_id = $this->input->post('club_id', true); + $user_id = $this->input->post('user_id', true); + + if (!is_numeric($club_id)) { + $this->session->set_flashdata('error', __("Invalid Club ID!")); + redirect('dashboard'); + } + if(!$this->user_model->authorize(99) && !$this->club_model->club_authorize(9, $club_id)) { + $this->session->set_flashdata('error', __("You're not allowed to do that!")); + redirect('dashboard'); + } + + if ($this->club_model->delete_member($club_id, $user_id)) { + $this->session->set_flashdata('success', __("User removed from club.")); + } else { + $this->session->set_flashdata('error', __("User could not be removed from club.")); + } + redirect('club/permissions/'.$club_id); + } + + public function switch_modal() { + + $this->load->model('user_model'); + $this->load->model('club_model'); + $this->load->library('encryption'); + + $cid = $this->input->post('club_id', true); + $data['club_callsign'] = $this->input->post('club_callsign', true); + $user_id = $this->session->userdata('user_id'); + + if (!is_numeric($cid)) { + $this->session->set_flashdata('error', __("Invalid Club ID!")); + redirect('dashboard'); + } + if(!$this->club_model->club_authorize(3, $cid)) { + $this->session->set_flashdata('error', __("You're not allowed to do that!")); + redirect('dashboard'); + } + + $data['impersonate_hash'] = $this->encryption->encrypt($user_id . '/' . $cid . '/' . time()); + + $this->load->view('club/clubswitch_modal', $data); + } + + private function notification($user_id, $club_id, $message) { + + $this->load->library('email'); + $this->load->model('club_model'); + + switch ($message) { + case 'new_member': + $view = 'email/club/new_member'; + break; + case 'modified_member': + $view = 'email/club/modified_member'; + break; + default: + log_message('error', "Club Notification; Can't notify user - Invalid message type."); + $this->session->set_flashdata('error', __("Invalid message type.")); + redirect('club/permissions/'.$club_id); + } + + if($this->optionslib->get_option('emailProtocol') == "smtp") { + $config = [ + 'protocol' => $this->optionslib->get_option('emailProtocol'), + 'smtp_crypto' => $this->optionslib->get_option('smtpEncryption'), + 'smtp_host' => $this->optionslib->get_option('smtpHost'), + 'smtp_port' => $this->optionslib->get_option('smtpPort'), + 'smtp_user' => $this->optionslib->get_option('smtpUsername'), + 'smtp_pass' => $this->optionslib->get_option('smtpPassword'), + 'crlf' => "\r\n", + 'newline' => "\r\n" + ]; + $this->email->initialize($config); + + } else { + log_message('error', "Club Notification; Can't notify user - Email settings not configured."); + $this->session->set_flashdata('error', __("Email settings not configured.")); + redirect('club/permissions/'.$club_id); + } + + $user = $this->user_model->get_by_id($user_id)->row(); + $club = $this->user_model->get_by_id($club_id)->row(); + $permission = $this->club_model->get_permission($club_id, $user_id); + $permission_level = $this->permissions[$permission] ?? __("Unknown"); + + $mail_data['user_callsign'] = $user->user_callsign; + $mail_data['club_callsign'] = $club->user_callsign; + $mail_data['permission_level'] = $permission_level; + + $message = $this->email->load($view, $mail_data, $user->user_language); + + $this->email->from($this->optionslib->get_option('emailAddress'), $this->optionslib->get_option('emailSenderName')); + $this->email->to($user->user_email); + $this->email->subject($message['subject']); + $this->email->message($message['body']); + + return $this->email->send(); + } + +} \ No newline at end of file diff --git a/application/controllers/Contesting.php b/application/controllers/Contesting.php index 501d8aacf..f50b29328 100644 --- a/application/controllers/Contesting.php +++ b/application/controllers/Contesting.php @@ -11,7 +11,7 @@ class Contesting extends CI_Controller { parent::__construct(); $this->load->model('user_model'); - if(!$this->user_model->authorize(2)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } + if(!$this->user_model->authorize(2) || !clubaccess_check(99)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } } public function index() { diff --git a/application/controllers/Cron.php b/application/controllers/Cron.php index 6e2bbe883..e911e91e6 100644 --- a/application/controllers/Cron.php +++ b/application/controllers/Cron.php @@ -87,7 +87,7 @@ class cron extends CI_Controller { if ($isdue == true) { $isdue_result = 'true'; - // TODO Add log_message level debug here to have logging for the cron manager + log_message('debug', 'CRON: ' . $cron->id . ' is due and will be executed.'); echo "CRON: " . $cron->id . " -> is due: " . $isdue_result . "\n"; echo "CRON: " . $cron->id . " -> RUNNING...\n"; diff --git a/application/controllers/Csv.php b/application/controllers/Csv.php index 037de83cb..e1321e591 100644 --- a/application/controllers/Csv.php +++ b/application/controllers/Csv.php @@ -5,7 +5,7 @@ class Csv extends CI_Controller { public function index() { $this->load->model('user_model'); - if(!$this->user_model->authorize(2)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } + if(!$this->user_model->authorize(2) || !clubaccess_check(9)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } $this->load->model('modes'); $this->load->model('logbook_model'); diff --git a/application/controllers/Dayswithqso.php b/application/controllers/Dayswithqso.php index c82567b55..534464749 100644 --- a/application/controllers/Dayswithqso.php +++ b/application/controllers/Dayswithqso.php @@ -3,39 +3,114 @@ defined('BASEPATH') OR exit('No direct script access allowed'); class Dayswithqso extends CI_Controller { - function __construct() - { - parent::__construct(); + function __construct() + { + parent::__construct(); - $this->load->model('user_model'); - if(!$this->user_model->authorize(2)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } - } + $this->load->model('user_model'); + if(!$this->user_model->authorize(2)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } + } - public function index() - { - $this->load->model('dayswithqso_model'); - // Render Page - $data['page_title'] = __("Number of days with QSOs each year"); + public function index() { + $this->load->model('dayswithqso_model'); + // Render Page + $data['page_title'] = __("Days with QSOs"); - $data['result'] = $this->dayswithqso_model->getDaysWithQso(); - $data['streaks'] = $this->dayswithqso_model->getLongestStreak(); - $data['currentstreak'] = $this->dayswithqso_model->getCurrentStreak(); - $data['almostcurrentstreak'] = $this->dayswithqso_model->getAlmostCurrentStreak(); + $data['result'] = $this->dayswithqso_model->getDaysWithQso(); + $data['streaks'] = $this->dayswithqso_model->getLongestStreak(); + $data['currentstreak'] = $this->dayswithqso_model->getCurrentStreak(); + $data['almostcurrentstreak'] = $this->dayswithqso_model->getAlmostCurrentStreak(); + $data['daysofweek'] = $this->dayswithqso_model->getDaysOfWeek(); + $data['years'] = $this->get_years(); - $this->load->view('interface_assets/header', $data); - $this->load->view('dayswithqso/index'); - $this->load->view('interface_assets/footer'); - } + $footerData = []; + $footerData['scripts'] = ['assets/js/jquery.glanceyear.js']; - public function get_days(){ + $this->load->view('interface_assets/header', $data); + $this->load->view('dayswithqso/index'); + $this->load->view('interface_assets/footer',$footerData); + } - //load model - $this->load->model('dayswithqso_model'); + function get_years() { + $this->load->model('logbook_model'); + $totals_year = $this->logbook_model->totals_year(); + $years=[]; + if ($totals_year) { + foreach($totals_year->result() as $years_obj) { + $years[] = $years_obj->year; + } + } + return $years; + } - // get data - $data = $this->dayswithqso_model->getDaysWithQso(); - header('Content-Type: application/json'); - echo json_encode($data); - } + public function get_punchvals($yr = null) { + $punchvals=[]; + if (($yr ?? '') != '') { + $this->load->model('dayswithqso_model'); + $res_punchvals = $this->dayswithqso_model->getPunchvals($this->security->xss_clean($yr)); + if ($res_punchvals) { + foreach($res_punchvals as $pobj) { + $col=0; + switch (true) { + case ($pobj->qsos == 0): + $col=0; + break; + case ($pobj->qsos <= 3): + $col=3; + break; + case ($pobj->qsos <= 6): + $col=6; + break; + case ($pobj->qsos <= 12): + $col=12; + break; + case ($pobj->qsos <= 24): + $col=24; + break; + case ($pobj->qsos > 24): + $col=48; + break; + } + $punchvals[] = ['date' => $pobj->date, 'value' => $pobj->qsos, 'col' => $col]; + } + } + } else { + $punchvals=[]; + } + header('Content-Type: application/json'); + echo json_encode($punchvals); + } -} \ No newline at end of file + + public function get_days(){ + + //load model + $this->load->model('dayswithqso_model'); + + // get data + $data = $this->dayswithqso_model->getDaysWithQso(); + header('Content-Type: application/json'); + echo json_encode($data); + } + + public function get_weekdays() { + //load model + $this->load->model('dayswithqso_model'); + + // get data + $data = $this->dayswithqso_model->getDaysOfWeek(); + header('Content-Type: application/json'); + echo json_encode($data); + } + + public function get_months() { + //load model + $this->load->model('dayswithqso_model'); + + // get data + $data = $this->dayswithqso_model->getMonthsOfYear(); + header('Content-Type: application/json'); + echo json_encode($data); + } + +} diff --git a/application/controllers/Debug.php b/application/controllers/Debug.php index 427a8f0d5..585a1a556 100644 --- a/application/controllers/Debug.php +++ b/application/controllers/Debug.php @@ -27,6 +27,14 @@ class Debug extends CI_Controller $footerData = []; $footerData['scripts'] = ['assets/js/sections/debug.js']; + // Get Custom Date format + if ($this->session->userdata('user_date_format')) { + $custom_date_format = $this->session->userdata('user_date_format'); + } else { + $custom_date_format = $this->config->item('qso_date_format'); + } + $data['system_time'] = date($custom_date_format . " H:i:s", time()); + $data['running_version'] = $this->optionslib->get_option('version'); $data['latest_release'] = $this->optionslib->get_option('latest_release'); @@ -102,6 +110,7 @@ class Debug extends CI_Controller $data['scp_update'] = $this->cron_model->cron('update_update_clublog_scp')->row(); $data['sota_update'] = $this->cron_model->cron('update_update_sota')->row(); $data['wwff_update'] = $this->cron_model->cron('update_update_wwff')->row(); + $data['tle_update'] = $this->cron_model->cron('update_update_tle')->row(); $data['page_title'] = __("Debug"); @@ -224,7 +233,7 @@ class Debug extends CI_Controller // Show success message $this->session->set_flashdata('success', __("Wavelog was updated successfully!")); - + } catch (\Throwable $th) { log_message("Error","Error at selfupdating"); } diff --git a/application/controllers/Dxatlas.php b/application/controllers/Dxatlas.php index dc10fa4f9..192825f20 100644 --- a/application/controllers/Dxatlas.php +++ b/application/controllers/Dxatlas.php @@ -4,7 +4,7 @@ class Dxatlas extends CI_Controller { public function index() { $this->load->model('user_model'); - if(!$this->user_model->authorize(2)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } + if(!$this->user_model->authorize(2) || !clubaccess_check(9)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } $this->load->model('modes'); $this->load->model('logbook_model'); diff --git a/application/controllers/Eqsl.php b/application/controllers/Eqsl.php index dcc4a8808..f291e7112 100644 --- a/application/controllers/Eqsl.php +++ b/application/controllers/Eqsl.php @@ -43,7 +43,7 @@ class eqsl extends CI_Controller { public function import() { $this->load->model('user_model'); - if (!$this->user_model->authorize(2)) { + if (!$this->user_model->authorize(2) || !clubaccess_check(9)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } @@ -447,7 +447,7 @@ class eqsl extends CI_Controller { $errors = 0; $this->load->library('electronicqsl'); - if ($this->input->post('eqsldownload') == 'download') { + if ($this->input->post('eqsldownload') == 'download' && $this->config->item('enable_eqsl_massdownload')) { $i = 0; $this->load->model('eqslmethods_model'); $qslsnotdownloaded = $this->eqslmethods_model->eqsl_not_yet_downloaded(); diff --git a/application/controllers/Gridmap.php b/application/controllers/Gridmap.php index 07c50bfd9..4343b87b2 100644 --- a/application/controllers/Gridmap.php +++ b/application/controllers/Gridmap.php @@ -33,6 +33,11 @@ class Gridmap extends CI_Controller { $data['gridsquares_gridsquares_not_confirmed'] = __("Gridsquares not confirmed"); $data['gridsquares_gridsquares_total_worked'] = __("Total gridsquares worked"); + $data['gridsquares_fields'] = __("Fields"); + $data['gridsquares_fields_confirmed'] = __("Fields confirmed"); + $data['gridsquares_fields_not_confirmed'] = __("Fields not confirmed"); + $data['gridsquares_fields_total_worked'] = __("Total fields worked"); + $footerData = []; $footerData['scripts'] = [ 'assets/js/leaflet/geocoding.js', diff --git a/application/controllers/Hrdlog.php b/application/controllers/Hrdlog.php index eadb0e71b..6e4fed20e 100644 --- a/application/controllers/Hrdlog.php +++ b/application/controllers/Hrdlog.php @@ -32,6 +32,9 @@ class Hrdlog extends CI_Controller { * Used for displaying the uid for manually selecting log for upload to hrdlog */ public function export() { + $this->load->model('user_model'); + if(!$this->user_model->authorize(2) || !clubaccess_check(9)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } + $this->load->model('stations'); $data['page_title'] = "HRDlog.net Logbook"; diff --git a/application/controllers/Kmlexport.php b/application/controllers/Kmlexport.php index dcc5772eb..2cf583e16 100644 --- a/application/controllers/Kmlexport.php +++ b/application/controllers/Kmlexport.php @@ -15,7 +15,7 @@ class Kmlexport extends CI_Controller { $this->load->model('logbook_model'); $this->load->model('bands'); - if(!$this->user_model->authorize(2)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } + if(!$this->user_model->authorize(2) || !clubaccess_check(9)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } $data['worked_bands'] = $this->bands->get_worked_bands(); // Used in the view for band select $data['modes'] = $this->modes->active(); // Used in the view for mode select diff --git a/application/controllers/Labels.php b/application/controllers/Labels.php index 2f8305913..91bc10f5b 100644 --- a/application/controllers/Labels.php +++ b/application/controllers/Labels.php @@ -23,7 +23,7 @@ class Labels extends CI_Controller { $this->load->helper(array('form', 'url', 'psr4_autoloader')); $this->load->model('user_model'); - if(!$this->user_model->authorize(2)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } + if(!$this->user_model->authorize(2) || !clubaccess_check(9)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } } diff --git a/application/controllers/Logbook.php b/application/controllers/Logbook.php index 22d82f06a..b602bec5b 100644 --- a/application/controllers/Logbook.php +++ b/application/controllers/Logbook.php @@ -97,7 +97,8 @@ class Logbook extends CI_Controller { // Check Database for all other data $this->load->model('logbook_model'); - $lotw_days=$this->logbook_model->check_last_lotw($callsign); + $lotw_days = $this->logbook_model->check_last_lotw($callsign); + if ($lotw_days != null) { $lotw_member="active"; } else { @@ -127,12 +128,12 @@ class Logbook extends CI_Controller { $return['dxcc'] = $this->dxcheck($callsign,$date); - $lookupcall=$this->logbook_model->get_plaincall($callsign); - - $return['partial'] = $this->partial($lookupcall, $band); + $lookupcall = $this->logbook_model->get_plaincall($callsign); $callbook = $this->logbook_model->loadCallBook($callsign, $this->config->item('use_fullname')); + $return['partial'] = $this->partial($lookupcall, $callbook, $callsign, $return['dxcc'], $lotw_days, $band); + if ($this->session->userdata('user_measurement_base') == NULL) { $measurement_base = $this->config->item('measurement_base'); } else { @@ -144,6 +145,7 @@ class Logbook extends CI_Controller { $return['callsign_distance'] = $this->distance($return['callsign_qra'], $station_id); $return['callsign_qth'] = $this->nval($callbook['city'] ?? '', $this->logbook_model->call_qth($callsign)); $return['callsign_iota'] = $this->nval($callbook['iota'] ?? '', $this->logbook_model->call_iota($callsign)); + $return['callsign_email'] = $this->nval($callbook['email'] ?? '', $this->logbook_model->call_email($callsign)); $return['qsl_manager'] = $this->nval($callbook['qslmgr'] ?? '', $this->logbook_model->call_qslvia($callsign)); $return['callsign_state'] = $this->nval($callbook['state'] ?? '', $this->logbook_model->call_state($callsign)); $return['callsign_us_county'] = $this->nval($callbook['us_county'] ?? '', $this->logbook_model->call_us_county($callsign)); @@ -613,7 +615,7 @@ class Logbook extends CI_Controller { $this->load->view('interface_assets/footer'); } - function partial($id, $band = null) { + function partial($lookupcall, $callbook, $callsign, $dxcc, $lotw_days, $band = null) { $this->load->model('user_model'); if(!$this->user_model->authorize($this->config->item('auth_mode'))) { return; } @@ -623,17 +625,18 @@ class Logbook extends CI_Controller { $html = ""; if(!empty($logbooks_locations_array)) { - $this->db->select(''.$this->config->item('table_name').'.COL_CALL, '.$this->config->item('table_name').'.COL_BAND, '.$this->config->item('table_name').'.COL_FREQ, '.$this->config->item('table_name').'.COL_TIME_ON, '.$this->config->item('table_name').'.COL_RST_RCVD, '.$this->config->item('table_name').'.COL_RST_SENT, '.$this->config->item('table_name').'.COL_MODE, '.$this->config->item('table_name').'.COL_SUBMODE, '.$this->config->item('table_name').'.COL_PRIMARY_KEY, '.$this->config->item('table_name').'.COL_SAT_NAME, '.$this->config->item('table_name').'.COL_GRIDSQUARE, '.$this->config->item('table_name').'.COL_QSL_RCVD, '.$this->config->item('table_name').'.COL_EQSL_QSL_RCVD, '.$this->config->item('table_name').'.COL_EQSL_QSL_SENT, '.$this->config->item('table_name').'.COL_QSL_SENT, '.$this->config->item('table_name').'.COL_STX, '.$this->config->item('table_name').'.COL_STX_STRING, '.$this->config->item('table_name').'.COL_SRX, '.$this->config->item('table_name').'.COL_SRX_STRING, '.$this->config->item('table_name').'.COL_LOTW_QSL_SENT, '.$this->config->item('table_name').'.COL_LOTW_QSL_RCVD, '.$this->config->item('table_name').'.COL_VUCC_GRIDS, '.$this->config->item('table_name').'.COL_MY_GRIDSQUARE, '.$this->config->item('table_name').'.COL_CONTEST_ID, '.$this->config->item('table_name').'.COL_STATE, '.$this->config->item('table_name').'.COL_QRZCOM_QSO_UPLOAD_STATUS, '.$this->config->item('table_name').'.COL_QRZCOM_QSO_DOWNLOAD_STATUS, '.$this->config->item('table_name').'.COL_CLUBLOG_QSO_UPLOAD_STATUS, '.$this->config->item('table_name').'.COL_CLUBLOG_QSO_DOWNLOAD_STATUS, '.$this->config->item('table_name').'.COL_POTA_REF, '.$this->config->item('table_name').'.COL_IOTA, '.$this->config->item('table_name').'.COL_SOTA_REF, '.$this->config->item('table_name').'.COL_WWFF_REF, '.$this->config->item('table_name').'.COL_OPERATOR, '.$this->config->item('table_name').'.COL_COUNTRY, station_profile.*'); + $this->db->select(''.$this->config->item('table_name').'.COL_CALL, '.$this->config->item('table_name').'.COL_BAND, '.$this->config->item('table_name').'.COL_FREQ, '.$this->config->item('table_name').'.COL_TIME_ON, '.$this->config->item('table_name').'.COL_RST_RCVD, '.$this->config->item('table_name').'.COL_RST_SENT, '.$this->config->item('table_name').'.COL_MODE, '.$this->config->item('table_name').'.COL_SUBMODE, '.$this->config->item('table_name').'.COL_PRIMARY_KEY, '.$this->config->item('table_name').'.COL_SAT_NAME, '.$this->config->item('table_name').'.COL_GRIDSQUARE, '.$this->config->item('table_name').'.COL_QSL_RCVD, '.$this->config->item('table_name').'.COL_EQSL_QSL_RCVD, '.$this->config->item('table_name').'.COL_EQSL_QSL_SENT, '.$this->config->item('table_name').'.COL_QSL_SENT, '.$this->config->item('table_name').'.COL_STX, '.$this->config->item('table_name').'.COL_STX_STRING, '.$this->config->item('table_name').'.COL_SRX, '.$this->config->item('table_name').'.COL_SRX_STRING, '.$this->config->item('table_name').'.COL_LOTW_QSL_SENT, '.$this->config->item('table_name').'.COL_LOTW_QSL_RCVD, '.$this->config->item('table_name').'.COL_VUCC_GRIDS, '.$this->config->item('table_name').'.COL_MY_GRIDSQUARE, '.$this->config->item('table_name').'.COL_CONTEST_ID, '.$this->config->item('table_name').'.COL_STATE, '.$this->config->item('table_name').'.COL_QRZCOM_QSO_UPLOAD_STATUS, '.$this->config->item('table_name').'.COL_QRZCOM_QSO_DOWNLOAD_STATUS, '.$this->config->item('table_name').'.COL_CLUBLOG_QSO_UPLOAD_STATUS, '.$this->config->item('table_name').'.COL_CLUBLOG_QSO_DOWNLOAD_STATUS, '.$this->config->item('table_name').'.COL_POTA_REF, '.$this->config->item('table_name').'.COL_IOTA, '.$this->config->item('table_name').'.COL_SOTA_REF, '.$this->config->item('table_name').'.COL_WWFF_REF, '.$this->config->item('table_name').'.COL_OPERATOR, '.$this->config->item('table_name').'.COL_COUNTRY, station_profile.*, satellite.displayname AS sat_displayname'); $this->db->from($this->config->item('table_name')); $this->db->join('station_profile', 'station_profile.station_id = '.$this->config->item('table_name').'.station_id'); + $this->db->join('satellite', 'satellite.name = '.$this->config->item('table_name').'.COL_SAT_NAME', 'left outer'); $this->db->where_in('station_profile.station_id', $logbooks_locations_array); $this->db->group_start(); - $this->db->where($this->config->item('table_name').'.COL_CALL', $id); - $this->db->or_like($this->config->item('table_name').'.COL_CALL', '/'.$id,'before'); - $this->db->or_like($this->config->item('table_name').'.COL_CALL', $id.'/','after'); - $this->db->or_like($this->config->item('table_name').'.COL_CALL', '/'.$id.'/'); + $this->db->where($this->config->item('table_name').'.COL_CALL', $lookupcall); + $this->db->or_like($this->config->item('table_name').'.COL_CALL', '/'.$lookupcall,'before'); + $this->db->or_like($this->config->item('table_name').'.COL_CALL', $lookupcall.'/','after'); + $this->db->or_like($this->config->item('table_name').'.COL_CALL', '/'.$lookupcall.'/'); $this->db->group_end(); $this->db->order_by($this->config->item('table_name').".COL_TIME_ON", "desc"); @@ -824,82 +827,28 @@ class Logbook extends CI_Controller { $html .= ""; return $html; } else { - if ($this->config->item('callbook') == "qrz" && $this->config->item('qrz_username') != null && $this->config->item('qrz_password') != null) { - // Lookup using QRZ - $this->load->library('qrz'); + $callsigninfo['callsign'] = $callbook; - if(!$this->session->userdata('qrz_session_key')) { - $qrz_session_key = $this->qrz->session($this->config->item('qrz_username'), $this->config->item('qrz_password')); - $this->session->set_userdata('qrz_session_key', $qrz_session_key); - } - $callsign['callsign'] = $this->qrz->search($id, $this->session->userdata('qrz_session_key'), $this->config->item('use_fullname')); + if ($dxcc['adif'] !== 0) { + $this->load->model('logbook_model'); + $callsigninfo['callsign']['dxcc_name'] = $dxcc['entity']; + $callsigninfo['dxcc_worked'] = $this->logbook_model->check_if_dxcc_worked_in_logbook($dxcc['adif'], null, $this->session->userdata('user_default_band')); + $callsigninfo['dxcc_confirmed'] = $this->logbook_model->check_if_dxcc_cnfmd_in_logbook($dxcc['adif'], null, $this->session->userdata('user_default_band')); + } - if (empty($callsign['callsign']['callsign'])) { - $qrz_session_key = $this->qrz->session($this->config->item('qrz_username'), $this->config->item('qrz_password')); - $this->session->set_userdata('qrz_session_key', $qrz_session_key); - $callsign['callsign'] = $this->qrz->search($id, $this->session->userdata('qrz_session_key'), $this->config->item('use_fullname')); - } - if (isset($callsign['callsign']['dxcc'])) { - $this->load->model('logbook_model'); - $entity = $this->logbook_model->get_entity($callsign['callsign']['dxcc']); - $callsign['callsign']['dxcc_name'] = $entity['name']; - $callsign['dxcc_worked'] = $this->logbook_model->check_if_dxcc_worked_in_logbook($callsign['callsign']['dxcc'], null, $this->session->userdata('user_default_band')); - $callsign['dxcc_confirmed'] = $this->logbook_model->check_if_dxcc_cnfmd_in_logbook($callsign['callsign']['dxcc'], null, $this->session->userdata('user_default_band')); - } - } else if ($this->config->item('callbook') == "hamqth" && $this->config->item('hamqth_username') != null && $this->config->item('hamqth_password') != null) { - // Load the HamQTH library - $this->load->library('hamqth'); + if (isset($callsigninfo['callsign']['gridsquare'])) { + $this->load->model('logbook_model'); + $callsigninfo['grid_worked'] = $this->logbook_model->check_if_grid_worked_in_logbook(strtoupper(substr($callsigninfo['callsign']['gridsquare'],0,4)), null, $band)->num_rows(); + } - if(!$this->session->userdata('hamqth_session_key')) { - $hamqth_session_key = $this->hamqth->session($this->config->item('hamqth_username'), $this->config->item('hamqth_password')); - $this->session->set_userdata('hamqth_session_key', $hamqth_session_key); - } + if (isset($callsigninfo['callsign']['error'])) { + $callsigninfo['error'] = $callsigninfo['callsign']['error']; + } - $callsign['callsign'] = $this->hamqth->search($id, $this->session->userdata('hamqth_session_key')); - - // If HamQTH session has expired, start a new session and retry the search. - if($callsign['callsign']['error'] == "Session does not exist or expired") { - $hamqth_session_key = $this->hamqth->session($this->config->item('hamqth_username'), $this->config->item('hamqth_password')); - $this->session->set_userdata('hamqth_session_key', $hamqth_session_key); - $callsign['callsign'] = $this->hamqth->search($id, $this->session->userdata('hamqth_session_key')); - } - if (isset($data['callsign']['gridsquare'])) { - $this->load->model('logbook_model'); - $callsign['grid_worked'] = $this->logbook_model->check_if_grid_worked_in_logbook(strtoupper(substr($data['callsign']['gridsquare'],0,4)), null, $this->session->userdata('user_default_band'))->num_rows(); - } - if (isset($callsign['callsign']['dxcc'])) { - $this->load->model('logbook_model'); - $entity = $this->logbook_model->get_entity($callsign['callsign']['dxcc']); - $callsign['callsign']['dxcc_name'] = $entity['name']; - $callsign['dxcc_worked'] = $this->logbook_model->check_if_dxcc_worked_in_logbook($callsign['callsign']['dxcc'], null, $this->session->userdata('user_default_band')); - $callsign['dxcc_confirmed'] = $this->logbook_model->check_if_dxcc_cnfmd_in_logbook($callsign['callsign']['dxcc'], null, $this->session->userdata('user_default_band')); - } - if (isset($callsign['callsign']['error'])) { - $callsign['error'] = $callsign['callsign']['error']; - } - } else { - $callsign['error'] = 'Lookup not configured. Please review configuration.'; - } - - // There's no hamli integration? Disabled for now. - /*else { - // Lookup using hamli - $this->load->library('hamli'); - - $callsign['callsign'] = $this->hamli->callsign($id); - }*/ - - if (isset($callsign['callsign']['gridsquare'])) { - $this->load->model('logbook_model'); - $callsign['grid_worked'] = $this->logbook_model->check_if_grid_worked_in_logbook(strtoupper(substr($callsign['callsign']['gridsquare'],0,4)), null, $band)->num_rows(); - } - if (isset($callsign['callsign']['error'])) { - $callsign['error'] = $callsign['callsign']['error']; - } - - $callsign['id'] = strtoupper($id); - $callsign['lotw_lastupload'] = $this->logbook_model->check_last_lotw($id); - return $this->load->view('search/result', $callsign, true); + $callsigninfo['lookupcall'] = strtoupper($lookupcall); + $callsigninfo['realcall'] = strtoupper($callsign); + $callsigninfo['lotw_lastupload'] = $lotw_days; + return $this->load->view('search/result', $callsigninfo, true); } } @@ -909,6 +858,8 @@ class Logbook extends CI_Controller { if(!$this->user_model->authorize($this->config->item('auth_mode'))) { return; } + $id = str_replace('Ø', "0", $id); + $id2 = str_replace('Ø', "0", $id2); $fixedid = $id; if ($id2 != "") { @@ -936,67 +887,27 @@ class Logbook extends CI_Controller { $data['results'] = $iota_search; $this->load->view('view_log/partial/log_ajax.php', $data); } else { - if ($this->config->item('callbook') == "qrz" && $this->config->item('qrz_username') != null && $this->config->item('qrz_password') != null) { - // Lookup using QRZ - $this->load->library('qrz'); + if (!$this->load->is_loaded('callbook')) { + $this->load->library('callbook'); + } - if(!$this->session->userdata('qrz_session_key')) { - $qrz_session_key = $this->qrz->session($this->config->item('qrz_username'), $this->config->item('qrz_password')); - $this->session->set_userdata('qrz_session_key', $qrz_session_key); - } + $data['callsign'] = $this->callbook->getCallbookData($id); - $data['callsign'] = $this->qrz->search($id, $this->session->userdata('qrz_session_key'), $this->config->item('use_fullname')); - if (isset($data['callsign']['gridsquare'])) { - $data['grid_worked'] = $this->logbook_model->check_if_grid_worked_in_logbook(strtoupper(substr($data['callsign']['gridsquare'],0,4)), null, $this->session->userdata('user_default_band'))->num_rows(); - } - if (isset($data['callsign']['dxcc'])) { - $entity = $this->logbook_model->get_entity($data['callsign']['dxcc']); - $data['callsign']['dxcc_name'] = $entity['name']; - $data['dxcc_worked'] = $this->logbook_model->check_if_dxcc_worked_in_logbook($data['callsign']['dxcc'], null, $this->session->userdata('user_default_band')); - $data['dxcc_confirmed'] = $this->logbook_model->check_if_dxcc_cnfmd_in_logbook($data['callsign']['dxcc'], null, $this->session->userdata('user_default_band')); - } - if (isset($data['callsign']['error'])) { - $data['error'] = $data['callsign']['error']; - } - } else if ($this->config->item('callbook') == "hamqth" && $this->config->item('hamqth_username') != null && $this->config->item('hamqth_password') != null) { - // Load the HamQTH library - $this->load->library('hamqth'); + if (isset($data['callsign']['gridsquare'])) { + $data['grid_worked'] = $this->logbook_model->check_if_grid_worked_in_logbook(strtoupper(substr($data['callsign']['gridsquare'],0,4)), null, $this->session->userdata('user_default_band'))->num_rows(); + } + if (isset($data['callsign']['dxcc'])) { + $entity = $this->logbook_model->get_entity($data['callsign']['dxcc']); + $data['callsign']['dxcc_name'] = $entity['name']; + $data['dxcc_worked'] = $this->logbook_model->check_if_dxcc_worked_in_logbook($data['callsign']['dxcc'], null, $this->session->userdata('user_default_band')); + $data['dxcc_confirmed'] = $this->logbook_model->check_if_dxcc_cnfmd_in_logbook($data['callsign']['dxcc'], null, $this->session->userdata('user_default_band')); + } + if (isset($data['callsign']['error'])) { + $data['error'] = $data['callsign']['error']; + } - if(!$this->session->userdata('hamqth_session_key')) { - $hamqth_session_key = $this->hamqth->session($this->config->item('hamqth_username'), $this->config->item('hamqth_password')); - $this->session->set_userdata('hamqth_session_key', $hamqth_session_key); - } - - $data['callsign'] = $this->hamqth->search($id, $this->session->userdata('hamqth_session_key')); - - // If HamQTH session has expired, start a new session and retry the search. - if($data['callsign']['error'] == "Session does not exist or expired") { - $hamqth_session_key = $this->hamqth->session($this->config->item('hamqth_username'), $this->config->item('hamqth_password')); - $this->session->set_userdata('hamqth_session_key', $hamqth_session_key); - $data['callsign'] = $this->hamqth->search($id, $this->session->userdata('hamqth_session_key')); - } - if (isset($data['callsign']['gridsquare'])) { - $data['grid_worked'] = $this->logbook_model->check_if_grid_worked_in_logbook(strtoupper(substr($data['callsign']['gridsquare'],0,4)), null, $this->session->userdata('user_default_band'))->num_rows(); - } - if (isset($data['callsign']['dxcc'])) { - $entity = $this->logbook_model->get_entity($data['callsign']['dxcc']); - $data['callsign']['dxcc_name'] = $entity['name']; - $data['dxcc_worked'] = $this->logbook_model->check_if_dxcc_worked_in_logbook($data['callsign']['dxcc'], null, $this->session->userdata('user_default_band')); - $data['dxcc_confirmed'] = $this->logbook_model->check_if_dxcc_cnfmd_in_logbook($data['callsign']['dxcc'], null, $this->session->userdata('user_default_band')); - } - if (isset($data['callsign']['error'])) { - $data['error'] = $data['callsign']['error']; - } - } else { - $data['error'] = 'Lookup not configured. Please review configuration.'; - } /*else { - // Lookup using hamli - $this->load->library('hamli'); - - $data['callsign'] = $this->hamli->callsign($id); - }*/ - - $data['id'] = strtoupper($id); + $data['lookupcall'] = strtoupper($id); + $data['realcall'] = strtoupper($id); $data['lotw_lastupload'] = $this->logbook_model->check_last_lotw($id); $this->load->view('search/result', $data); @@ -1009,10 +920,22 @@ class Logbook extends CI_Controller { } function querydb($id) { + $this->db->select('dxcc_entities.adif, lotw_users.callsign, COL_BAND, COL_CALL, COL_CLUBLOG_QSO_DOWNLOAD_DATE, + COL_CLUBLOG_QSO_DOWNLOAD_STATUS, COL_CLUBLOG_QSO_UPLOAD_DATE, COL_CLUBLOG_QSO_UPLOAD_STATUS, + COL_CONTEST_ID, COL_DISTANCE, COL_EQSL_QSL_RCVD, COL_EQSL_QSLRDATE, COL_EQSL_QSLSDATE, COL_EQSL_QSL_SENT, + COL_FREQ, COL_GRIDSQUARE, COL_IOTA, COL_LOTW_QSL_RCVD, COL_LOTW_QSLRDATE, COL_LOTW_QSLSDATE, + COL_LOTW_QSL_SENT, COL_MODE, COL_NAME, COL_OPERATOR, COL_POTA_REF, COL_PRIMARY_KEY, + COL_QRZCOM_QSO_DOWNLOAD_DATE, COL_QRZCOM_QSO_DOWNLOAD_STATUS, COL_QRZCOM_QSO_UPLOAD_DATE, + COL_QRZCOM_QSO_UPLOAD_STATUS, COL_QSL_RCVD, COL_QSL_RCVD_VIA, COL_QSLRDATE, COL_QSLSDATE, COL_QSL_SENT, + COL_QSL_SENT_VIA, COL_QSL_VIA, COL_RST_RCVD, COL_RST_SENT, COL_SAT_NAME, COL_SOTA_REF, COL_SRX, + COL_SRX_STRING, COL_STATE, COL_STX, COL_STX_STRING, COL_SUBMODE, COL_TIME_ON, COL_VUCC_GRIDS, COL_WWFF_REF, + dxcc_entities.end, lotw_users.lastupload, satellite.displayname AS sat_displayname, station_profile.station_callsign, + station_profile.station_gridsquare, station_profile.station_profile_name, dxcc_entities.name'); $this->db->from($this->config->item('table_name')); $this->db->join('station_profile', 'station_profile.station_id = '.$this->config->item('table_name').'.station_id'); $this->db->join('dxcc_entities', 'dxcc_entities.adif = '.$this->config->item('table_name').'.COL_DXCC', 'left outer'); $this->db->join('lotw_users', 'lotw_users.callsign = '.$this->config->item('table_name').'.col_call', 'left outer'); + $this->db->join('satellite', 'satellite.name = '.$this->config->item('table_name').'.COL_SAT_NAME', 'left outer'); $this->db->group_start(); $this->db->like(''.$this->config->item('table_name').'.COL_CALL', $id); $this->db->or_like(''.$this->config->item('table_name').'.COL_GRIDSQUARE', $id); @@ -1184,6 +1107,7 @@ class Logbook extends CI_Controller { /* return station bearing */ function searchbearing() { $locator = xss_clean($this->input->post('grid')); + $ant_path = xss_clean($this->input->post('ant_path')) == '' ? NULL : xss_clean($this->input->post('ant_path')); $station_id = xss_clean($this->input->post('stationProfile')); if(!$this->load->is_loaded('Qra')) { $this->load->library('Qra'); @@ -1215,7 +1139,7 @@ class Logbook extends CI_Controller { $measurement_base = $this->session->userdata('user_measurement_base'); } - $bearing = $this->qra->bearing($mylocator, $locator, $measurement_base); + $bearing = $this->qra->bearing($mylocator, $locator, $measurement_base, $ant_path); echo $bearing; } @@ -1225,6 +1149,7 @@ class Logbook extends CI_Controller { /* return distance */ function searchdistance() { $locator = xss_clean($this->input->post('grid')); + $ant_path = xss_clean($this->input->post('ant_path')) == '' ? NULL : xss_clean($this->input->post('ant_path')); $station_id = xss_clean($this->input->post('stationProfile')); if(!$this->load->is_loaded('Qra')) { $this->load->library('Qra'); @@ -1249,7 +1174,7 @@ class Logbook extends CI_Controller { $mylocator = $this->config->item('locator'); } - $distance = $this->qra->distance($mylocator, $locator, 'K'); + $distance = $this->qra->distance($mylocator, $locator, 'K', $ant_path); echo $distance; } @@ -1257,7 +1182,7 @@ class Logbook extends CI_Controller { } /* return station bearing */ - function bearing($locator, $unit = 'M', $station_id = null) { + function bearing($locator, $unit = 'M', $station_id = null, $ant_path = null) { if(!$this->load->is_loaded('Qra')) { $this->load->library('Qra'); } @@ -1281,7 +1206,7 @@ class Logbook extends CI_Controller { $mylocator = $this->config->item('locator'); } - $bearing = $this->qra->bearing($mylocator, $locator, $unit); + $bearing = $this->qra->bearing($mylocator, $locator, $unit, $ant_path); return $bearing; } @@ -1289,7 +1214,7 @@ class Logbook extends CI_Controller { } /* return distance */ - function distance($locator, $station_id = null) { + function distance($locator, $station_id = null, $ant_path = null) { $distance = 0; if(!$this->load->is_loaded('Qra')) { $this->load->library('Qra'); @@ -1314,7 +1239,7 @@ class Logbook extends CI_Controller { $mylocator = $this->config->item('locator'); } - $distance = $this->qra->distance($mylocator, $locator, 'K'); + $distance = $this->qra->distance($mylocator, $locator, 'K', $ant_path); } return $distance; @@ -1394,8 +1319,8 @@ class Logbook extends CI_Controller { case 'POTA': $ret.= '' . ($row->COL_POTA_REF) . ''; break; case 'Grid': $ret.= '' . $this->part_QrbCalcLink($row->COL_MY_GRIDSQUARE, $row->COL_VUCC_GRIDS, $row->COL_GRIDSQUARE) . ''; break; case 'Distance': $ret.= '' . (($row->COL_DISTANCE ?? '' != '') ? $row->COL_DISTANCE . ' km' : '') . ''; break; - case 'Band': $ret.= ''; if($row->COL_SAT_NAME != null) { $ret.= ''.$row->COL_SAT_NAME.''; } else { $ret.= strtolower($row->COL_BAND); } $ret.= ''; break; - case 'Frequency': $ret.= ''; if($row->COL_SAT_NAME != null) { $ret.= ''.$row->COL_SAT_NAME.''; } else { if($row->COL_FREQ != null) { $ret.= $this->frequency->qrg_conversion($row->COL_FREQ); } else { $ret.= strtolower($row->COL_BAND); } } $ret.= ''; break; + case 'Band': $ret.= ''; if($row->COL_SAT_NAME != null) { $ret.= ''.($row->sat_displayname != null ? $row->sat_displayname." (".$row->COL_SAT_NAME.")" : $row->COL_SAT_NAME).''; } else { $ret.= strtolower($row->COL_BAND); } $ret.= ''; break; + case 'Frequency': $ret.= ''; if($row->COL_SAT_NAME != null) { $ret.= ''.($row->sat_displayname != null ? $row->sat_displayname." (".$row->COL_SAT_NAME.")" : $row->COL_SAT_NAME).''; } else { if($row->COL_FREQ != null) { $ret.= $this->frequency->qrg_conversion($row->COL_FREQ); } else { $ret.= strtolower($row->COL_BAND); } } $ret.= ''; break; case 'State': $ret.= '' . ($row->COL_STATE) . ''; break; case 'Operator': $ret.= '' . ($row->COL_OPERATOR) . ''; break; } diff --git a/application/controllers/Logbookadvanced.php b/application/controllers/Logbookadvanced.php index e9d77c169..a97ff85d0 100644 --- a/application/controllers/Logbookadvanced.php +++ b/application/controllers/Logbookadvanced.php @@ -158,11 +158,13 @@ class Logbookadvanced extends CI_Controller { } public function updateFromCallbook() { + if(!clubaccess_check(9)) return; + $this->load->model('logbook_model'); $this->load->model('logbookadvanced_model'); - $qsoID = xss_clean($this->input->post('qsoID')); - $qso = $this->logbook_model->qso_info($qsoID)->row_array(); + $qsoID[] = xss_clean($this->input->post('qsoID')); + $qso = $this->logbookadvanced_model->getQsosForAdif(json_encode($qsoID), $this->session->userdata('user_id'))->row_array(); if ($qso === null) { header("Content-Type: application/json"); echo json_encode([]); @@ -172,8 +174,8 @@ class Logbookadvanced extends CI_Controller { $callbook = $this->logbook_model->loadCallBook($qso['COL_CALL'], $this->config->item('use_fullname')); if ($callbook['callsign'] ?? "" !== "") { - $this->logbookadvanced_model->updateQsoWithCallbookInfo($qsoID, $qso, $callbook); - $qso = $this->logbook_model->qso_info($qsoID)->row_array(); + $this->logbookadvanced_model->updateQsoWithCallbookInfo($qso['COL_PRIMARY_KEY'], $qso, $callbook); + $qso = $this->logbookadvanced_model->getQsosForAdif(json_encode($qsoID), $this->session->userdata('user_id'))->row_array(); } $qsoObj = new QSO($qso); @@ -183,6 +185,8 @@ class Logbookadvanced extends CI_Controller { } function export_to_adif() { + if(!clubaccess_check(9)) return; + ini_set('memory_limit', '-1'); set_time_limit(0); $this->load->model('logbookadvanced_model'); @@ -197,6 +201,8 @@ class Logbookadvanced extends CI_Controller { } function export_to_adif_params() { + if(!clubaccess_check(9)) return; + ini_set('memory_limit', '-1'); set_time_limit(0); $this->load->model('logbookadvanced_model'); @@ -211,6 +217,8 @@ class Logbookadvanced extends CI_Controller { } function update_qsl() { + if(!clubaccess_check(9)) return; + $this->load->model('logbookadvanced_model'); $ids = xss_clean($this->input->post('id')); @@ -239,6 +247,8 @@ class Logbookadvanced extends CI_Controller { } function update_qsl_received() { + if(!clubaccess_check(9)) return; + $this->load->model('logbookadvanced_model'); $ids = xss_clean($this->input->post('id')); @@ -285,7 +295,7 @@ class Logbookadvanced extends CI_Controller { 'dateFrom' => '', 'dateTo' => '', 'de' => $this->input->post('de'), - 'dx' => '', + 'dx' => '*', 'mode' => '', 'band' => '', 'qslSent' => '', @@ -295,8 +305,8 @@ class Logbookadvanced extends CI_Controller { 'iota' => '', 'dxcc' => '', 'propmode' => '', - 'gridsquare' => '', - 'state' => '', + 'gridsquare' => '*', + 'state' => '*', 'cqzone' => '', 'ituzone' => '', 'qsoresults' => count($this->input->post('ids')), @@ -308,13 +318,13 @@ class Logbookadvanced extends CI_Controller { 'eqslReceived' => '', 'clublogSent' => '', 'clublogReceived' => '', - 'qslvia' => '', - 'sota' => '', - 'pota' => '', - 'wwff' => '', + 'qslvia' => '*', + 'sota' => '*', + 'pota' => '*', + 'wwff' => '*', 'qslimages' => '', - 'operator' => '', - 'contest' => '', + 'operator' => '*', + 'contest' => '*', 'continent' => '', 'ids' => xss_clean($this->input->post('ids')) ); @@ -448,8 +458,8 @@ class Logbookadvanced extends CI_Controller { } $this->load->model('logbook_model'); - $data['distance'] = $this->qra->distance($locator1, $locator2, $measurement_base) . $var_dist; - $data['bearing'] = $this->qra->get_bearing($locator1, $locator2) . "º"; + $data['distance'] = $this->qra->distance($locator1, $locator2, $measurement_base, $qso['COL_ANT_PATH']) . $var_dist; + $data['bearing'] = $this->qra->get_bearing($locator1, $locator2, $qso['COL_ANT_PATH']) . "º"; $latlng1 = $this->qra->qra2latlong($locator1); $latlng2 = $this->qra->qra2latlong($locator2); $latlng1[0] = number_format((float)$latlng1[0], 3, '.', '');; @@ -504,6 +514,8 @@ class Logbookadvanced extends CI_Controller { } public function userOptions() { + if(!clubaccess_check(9)) return; + $this->load->model('user_options_model'); $userOptions = $this->user_options_model->get_options('LogbookAdvanced')->result(); if (isset($userOptions[0])) { @@ -524,6 +536,8 @@ class Logbookadvanced extends CI_Controller { } public function setUserOptions() { + if(!clubaccess_check(9)) return; + $json_string['datetime']['show'] = $this->input->post('datetime'); $json_string['de']['show'] = $this->input->post('de'); $json_string['dx']['show'] = $this->input->post('dx'); @@ -559,6 +573,7 @@ class Logbookadvanced extends CI_Controller { $json_string['profilename']['show'] = $this->input->post('profilename'); $json_string['stationpower']['show'] = $this->input->post('stationpower'); $json_string['distance']['show'] = $this->input->post('distance'); + $json_string['region']['show'] = $this->input->post('region'); $obj['column_settings']= json_encode($json_string); @@ -574,6 +589,8 @@ class Logbookadvanced extends CI_Controller { } public function editDialog() { + if(!clubaccess_check(9)) return; + $this->load->model('bands'); $this->load->model('modes'); $this->load->model('logbookadvanced_model'); @@ -588,6 +605,8 @@ class Logbookadvanced extends CI_Controller { } public function saveBatchEditQsos() { + if(!clubaccess_check(9)) return; + $ids = xss_clean($this->input->post('ids')); $column = xss_clean($this->input->post('column')); $value = xss_clean($this->input->post('value')); @@ -624,6 +643,8 @@ class Logbookadvanced extends CI_Controller { } public function batchDeleteQsos() { + if(!clubaccess_check(9)) return; + $ids = xss_clean($this->input->post('ids')); $this->load->model('logbookadvanced_model'); diff --git a/application/controllers/Lotw.php b/application/controllers/Lotw.php index e2ecfca45..7818fdd9e 100644 --- a/application/controllers/Lotw.php +++ b/application/controllers/Lotw.php @@ -41,7 +41,7 @@ class Lotw extends CI_Controller { public function index() { $this->load->library('Permissions'); $this->load->model('user_model'); - if(!$this->user_model->authorize(2)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } + if(!$this->user_model->authorize(2) || !clubaccess_check(9)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } // Load required models for page generation $this->load->model('Lotw_model'); @@ -99,8 +99,7 @@ class Lotw extends CI_Controller { | and processing of p12 files and storing the data into mysql | */ - public function do_cert_upload() - { + public function do_cert_upload() { $this->load->model('user_model'); $this->load->model('dxcc'); if(!$this->user_model->authorize(2)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } @@ -115,8 +114,7 @@ class Lotw extends CI_Controller { $this->load->library('upload', $config); - if ( ! $this->upload->do_upload('userfile')) - { + if ( ! $this->upload->do_upload('userfile')) { // Upload of P12 Failed $error = array('error' => $this->upload->display_errors()); @@ -130,9 +128,7 @@ class Lotw extends CI_Controller { $this->load->view('interface_assets/header', $data); $this->load->view('lotw_views/upload_cert', $error); $this->load->view('interface_assets/footer'); - } - else - { + } else { // Load database queries $this->load->model('Lotw_model'); @@ -473,7 +469,7 @@ class Lotw extends CI_Controller { private function loadFromFile($filepath, $station_ids, $display_view = "TRUE") { // Figure out how we should be marking QSLs confirmed via LoTW - $query = $query = $this->db->query('SELECT lotw_rcvd_mark FROM config'); + $query = $this->db->query('SELECT lotw_rcvd_mark FROM config'); $q = $query->row(); $config['lotw_rcvd_mark'] = $q->lotw_rcvd_mark; @@ -545,6 +541,8 @@ class Lotw extends CI_Controller { } } + $ant_path = $status[3] ?? ''; + if (isset($record['vucc_grids'])) { $qsl_vucc_grids = $record['vucc_grids']; } else { @@ -575,7 +573,13 @@ class Lotw extends CI_Controller { $ituz = ""; } - $lotw_status = $this->logbook_model->lotw_update($time_on, $record['call'], $record['band'], $qsl_date, $record['qsl_rcvd'], $state, $qsl_gridsquare, $qsl_vucc_grids, $iota, $cnty, $cqz, $ituz, $record['station_callsign'],$qso_id4lotw, $station_ids); + if (isset($record['dxcc'])) { + $dxcc = $record['dxcc']; + } else { + $dxcc = ""; + } + + $lotw_status = $this->logbook_model->lotw_update($time_on, $record['call'], $record['band'], $qsl_date, $record['qsl_rcvd'], $state, $qsl_gridsquare, $qsl_vucc_grids, $iota, $cnty, $cqz, $ituz, $record['station_callsign'],$qso_id4lotw, $station_ids, $dxcc, $ant_path); $table .= ""; $table .= "".$record['station_callsign'].""; @@ -659,6 +663,7 @@ class Lotw extends CI_Controller { 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 // Validate that LoTW credentials are not empty // TODO: We don't actually see the error message @@ -668,14 +673,14 @@ class Lotw extends CI_Controller { } $config['upload_path'] = './uploads/'; - $file = $config['upload_path'] . 'lotwreport_download.adi'; + $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; } // Get credentials for LoTW - $data['user_lotw_name'] = urlencode($user->user_lotw_name); + $data['user_lotw_name'] = urlencode($user->user_lotw_name); $data['user_lotw_password'] = urlencode($user->user_lotw_password); $lotw_last_qsl_date = date('Y-m-d', strtotime($this->logbook_model->lotw_last_qsl_date($user->user_id))); @@ -698,12 +703,16 @@ class Lotw extends CI_Controller { curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30); $content = curl_exec($ch); - if(curl_errno($ch)){ + if(curl_errno($ch)) { $result = "LoTW download failed for user ".$data['user_lotw_name'].": ".curl_strerror(curl_errno($ch))." (".curl_errno($ch).")."; if (curl_errno($ch) == 28) { // break on timeout $result .= "
Timeout reached. Stopping subsequent downloads."; break; } + continue; + } else if(str_contains($content,"Username/password incorrect")) { + $result = "LoTW download failed for user ".$data['user_lotw_name'].": Username/password incorrect"; + continue; } file_put_contents($file, $content); if (file_get_contents($file, false, null, 0, 39) != "ARRL Logbook of the World Status Report") { @@ -720,6 +729,89 @@ class Lotw extends CI_Controller { } } + public function check_lotw_credentials () { + $this->load->model('user_model'); + if(!$this->user_model->authorize(2)) { + $this->session->set_flashdata('error', __("You're not allowed to do that!")); + redirect('dashboard'); + exit(); + } + $ret=[]; + $ret['status']=''; + + + $raw = file_get_contents("php://input"); + try { + $obj = json_decode($raw,true); + } catch (Exception $e) { + $ret['status']='failed_wrongcall'; + log_message("Error",$ret['status']); + } finally { + $lotw_user=$obj['lotw_user'] ?? ''; + $lotw_pass=$obj['lotw_pass'] ?? ''; + } + $raw=''; + + $pw_placeholder = '**********'; + if ($lotw_pass == $pw_placeholder) { // User comes with unaltered credentials - take them from database + $query = $this->user_model->get_by_id($this->session->userdata('user_id')); + $q = $query->row(); + $data['user_lotw_name'] = urlencode($q->user_lotw_name ?? ''); + $data['user_lotw_password'] = urlencode($q->user_lotw_password ?? ''); + } else { + $data['user_lotw_name'] = urlencode($lotw_user ?? ''); + $data['user_lotw_password'] = urlencode($lotw_pass ?? ''); + } + + if ((($data['user_lotw_name'] ?? '') != '') && (($data['user_lotw_password'] ?? '') != '') && ($ret['status'] != 'failed_wrongcall')) { + + // Get URL for downloading LoTW + $query = $query = $this->db->query('SELECT lotw_login_url FROM config'); + $q = $query->row(); + $lotw_url = $q->lotw_login_url; + + // Validate that LoTW credentials are not empty + // TODO: We don't actually see the error message + if ($data['user_lotw_name'] == '' || $data['user_lotw_password'] == '') { + $ret='No Creds set'; + } + + // Build URL for LoTW report file + $lotw_url .= "?"; + $lotw_url .= "login=" . $data['user_lotw_name']; + $lotw_url .= "&password=" . $data['user_lotw_password']; + + $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 ($content) { + if(curl_errno($ch)) { + $ret['status']='failed'; + $ret['details']== sprintf(__("LoTW login failed for user %s: %s."), $data['user_lotw_name'], curl_strerror(curl_errno($ch))." (".curl_errno($ch).")"); + } else if (str_contains($content,"Username/password incorrect")) { + $ret['status']='failed_wrong_creds'; + $ret['details']= sprintf(__("LoTW login failed for user %s: %s."), $data['user_lotw_name'], __("Username/password incorrect")); + } else { + $ret['status']='OK'; + $ret['details']= __("LoTW login OK!"); + } + } else { + $ret['status']='failed_na'; + $ret['details']= __("LoTW currently not available. Try again later."); + } + } else { + if (($ret['status'] ?? '') == '') { + $ret['status']='failed_nocred'; + $ret['details']= __("No LoTW credentials provided."); + } + } + header("Content-type: application/json"); + echo json_encode($ret); + return $ret; + } + public function import() { // Is only called via frontend. Cron uses "upload". within download the download is called $this->load->model('user_model'); $this->load->model('Stations'); @@ -730,107 +822,100 @@ class Lotw extends CI_Controller { } $station_ids=$this->Stations->all_station_ids_of_user($this->session->userdata['user_id']); - if (!($this->config->item('disable_manual_lotw'))) { - $data['page_title'] = __("LoTW ADIF Import"); + $data['page_title'] = __("LoTW ADIF Import"); - $config['upload_path'] = './uploads/'; - $config['allowed_types'] = 'adi|ADI'; + $config['upload_path'] = './uploads/'; + $config['allowed_types'] = 'adi|ADI'; - $this->load->library('upload', $config); + $this->load->library('upload', $config); - $this->load->model('logbook_model'); + $this->load->model('logbook_model'); - if ($this->input->post('lotwimport') == 'fetch') { - $file = $config['upload_path'] . 'lotwreport_download.adi'; + if (($this->input->post('lotwimport') == 'fetch') && (!($this->config->item('disable_manual_lotw')))) { + $file = $config['upload_path'] . 'lotwreport_download_'.$this->session->userdata('user_id').'.adi'; - // Get credentials for LoTW - $query = $this->user_model->get_by_id($this->session->userdata('user_id')); - $q = $query->row(); - $data['user_lotw_name'] = urlencode($q->user_lotw_name ?? ''); - $data['user_lotw_password'] = urlencode($q->user_lotw_password ?? ''); + // Get credentials for LoTW + $query = $this->user_model->get_by_id($this->session->userdata('user_id')); + $q = $query->row(); + $data['user_lotw_name'] = urlencode($q->user_lotw_name ?? ''); + $data['user_lotw_password'] = urlencode($q->user_lotw_password ?? ''); - // Get URL for downloading LoTW - $query = $query = $this->db->query('SELECT lotw_download_url FROM config'); - $q = $query->row(); - $lotw_url = $q->lotw_download_url; + // Get URL for downloading LoTW + $query = $query = $this->db->query('SELECT lotw_download_url FROM config'); + $q = $query->row(); + $lotw_url = $q->lotw_download_url; - // Validate that LoTW credentials are not empty - // TODO: We don't actually see the error message - if ($data['user_lotw_name'] == '' || $data['user_lotw_password'] == '') - { - $this->session->set_flashdata('warning', __("You have not defined your ARRL LoTW credentials!")); redirect('lotw/import'); - } + // Validate that LoTW credentials are not empty + // TODO: We don't actually see the error message + if ($data['user_lotw_name'] == '' || $data['user_lotw_password'] == '') { + $this->session->set_flashdata('warning', __("You have not defined your ARRL LoTW credentials!")); redirect('lotw/import'); + } - $customDate = $this->input->post('from'); + $customDate = $this->input->post('from'); - if ($customDate != NULL) { - $lotw_last_qsl_date = date($customDate); + if ($customDate != NULL) { + $lotw_last_qsl_date = date($customDate); + } else { + // Query the logbook to determine when the last LoTW confirmation was + $lotw_last_qsl_date = date('Y-m-d', strtotime($this->logbook_model->lotw_last_qsl_date($this->session->userdata['user_id']))); + } + + // Build URL for LoTW report file + $lotw_url .= "?"; + $lotw_url .= "login=" . $data['user_lotw_name']; + $lotw_url .= "&password=" . $data['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 ($this->input->post('callsign') != '0') { + $lotw_url .= "&qso_owncall=".$this->input->post('callsign'); + } + + if (is_writable(dirname($file)) && (!file_exists($file) || is_writable($file))) { + $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)) { + print "LoTW download failed for user ".$data['user_lotw_name'].": ".curl_strerror(curl_errno($ch))." (".curl_errno($ch).")."; + } else if (str_contains($content,"Username/password incorrect")) { + print "LoTW download failed for user ".$data['user_lotw_name'].": Username/password incorrect"; } else { - // Query the logbook to determine when the last LoTW confirmation was - $lotw_last_qsl_date = date('Y-m-d', strtotime($this->logbook_model->lotw_last_qsl_date($this->session->userdata['user_id']))); - } - - // Build URL for LoTW report file - $lotw_url .= "?"; - $lotw_url .= "login=" . $data['user_lotw_name']; - $lotw_url .= "&password=" . $data['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 ($this->input->post('callsign') != '0') { - $lotw_url .= "&qso_owncall=".$this->input->post('callsign'); - } - - if (is_writable(dirname($file)) && (!file_exists($file) || is_writable($file))) { - $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)){ - file_put_contents($file, $content); - - ini_set('memory_limit', '-1'); - $this->loadFromFile($file, $station_ids); - } else { - print "LoTW download failed for user ".$data['user_lotw_name'].": ".curl_strerror(curl_errno($ch))." (".curl_errno($ch).")."; - } - } else { - if (!is_writable(dirname($file))) { - $data['errormsg'] = 'Directory '.dirname($file).' is not writable!'; - } else if (!is_writable($file)) { - $data['errormsg'] = 'File '.$file.' is not writable!'; - } - $this->load->model('Stations'); - $data['callsigns'] = $this->Stations->callsigns_of_user($this->session->userdata('user_id')); - - $this->load->view('interface_assets/header', $data); - $this->load->view('lotw/import', $data); - $this->load->view('interface_assets/footer'); + file_put_contents($file, $content); + ini_set('memory_limit', '-1'); + $this->loadFromFile($file, $station_ids); } } else { - if ( ! $this->upload->do_upload()) - { - - $data['error'] = $this->upload->display_errors(); - $this->load->model('Stations'); - $data['callsigns'] = $this->Stations->callsigns_of_user($this->session->userdata('user_id')); - - $this->load->view('interface_assets/header', $data); - $this->load->view('lotw/import', $data); - $this->load->view('interface_assets/footer'); - } else { - $data = array('upload_data' => $this->upload->data()); - - $this->loadFromFile('./uploads/'.$data['upload_data']['file_name'], $station_ids); + if (!is_writable(dirname($file))) { + $data['errormsg'] = 'Directory '.dirname($file).' is not writable!'; + } else if (!is_writable($file)) { + $data['errormsg'] = 'File '.$file.' is not writable!'; } + $this->load->model('Stations'); + $data['callsigns'] = $this->Stations->callsigns_of_user($this->session->userdata('user_id')); + + $this->load->view('interface_assets/header', $data); + $this->load->view('lotw/import', $data); + $this->load->view('interface_assets/footer'); } } else { - $this->session->set_flashdata('error', __("You're not allowed to do that!")); - redirect('dashboard'); - exit(); + if (!$this->upload->do_upload()) { + + $data['error'] = $this->upload->display_errors(); + $this->load->model('Stations'); + $data['callsigns'] = $this->Stations->callsigns_of_user($this->session->userdata('user_id')); + + $this->load->view('interface_assets/header', $data); + $this->load->view('lotw/import', $data); + $this->load->view('interface_assets/footer'); + } else { + $data = array('upload_data' => $this->upload->data()); + + $this->loadFromFile('./uploads/'.$data['upload_data']['file_name'], $station_ids); + } } } // end function @@ -999,38 +1084,6 @@ class Lotw extends CI_Controller { } - /* - | Function: lotw_satellite_map - | Requires: OSCAR Satellite name $satname - | - | Outputs if LoTW uses a different satellite name - | - */ - function lotw_satellite_map($satname) { - $arr = array( - "ARISS" => "ISS", - "UKUBE1" => "UKUBE-1", - "KEDR" => "ARISSAT-1", - "TO-108" => "CAS-6", - "TAURUS" => "TAURUS-1", - "AISAT1" => "AISAT-1", - 'UVSQ' => "UVSQ-SAT", - 'CAS-3H' => "LILACSAT-2", - 'IO-117' => "GREENCUBE", - "TEVEL1" => "TEVEL-1", - "TEVEL2" => "TEVEL-2", - "TEVEL3" => "TEVEL-3", - "TEVEL4" => "TEVEL-4", - "TEVEL5" => "TEVEL-5", - "TEVEL6" => "TEVEL-6", - "TEVEL7" => "TEVEL-7", - "TEVEL8" => "TEVEL-8", - "INSPR7" => "INSPIRE-SAT 7", - ); - - return array_search(strtoupper($satname),$arr,true); - } - /* | Function: lotw_ca_province_map | Requires: candian province map $ca_province diff --git a/application/controllers/Options.php b/application/controllers/Options.php index 443f60d7b..30c247a63 100644 --- a/application/controllers/Options.php +++ b/application/controllers/Options.php @@ -389,6 +389,100 @@ class Options extends CI_Controller { redirect('/options/email'); } + // function used to display the /maptiles url in global options + function maptiles() { + $data['page_title'] = __("Wavelog Options"); + $data['sub_heading'] = __("Maptiles Server"); + + $data['maptile_server_url'] = $this->optionslib->get_option('map_tile_server') ?? 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'; + $data['maptile_server_url_dark'] = $this->optionslib->get_option('map_tile_server_dark') ?? 'https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png'; + $data['subdomain_system'] = $this->optionslib->get_option('map_tile_subdomains') ?? 'abc'; + $map_tile_server_copyright = $this->optionslib->get_option('map_tile_server_copyright') ?? 'Map data © OpenStreetMap'; + preg_match('/([^<]+)<\/a>/', $map_tile_server_copyright, $matches); + $data['copyright_url'] = $matches[1] ?? 'https://www.openstreetmap.org/'; + $data['copyright_text'] = $matches[2] ?? 'OpenStreetMap'; + + $this->load->view('interface_assets/header', $data); + $this->load->view('options/maptiles'); + $this->load->view('interface_assets/footer'); + } + + // Handles saving the Maptiles options to the options system. + function maptiles_save() { + + $data['page_title'] = __("Wavelog Options"); + $data['sub_heading'] = __("Maptiles Server"); + + $this->load->helper(array('form', 'url')); + + $this->load->library('form_validation'); + + $this->form_validation->set_rules('maptile_server_url', 'URL of Maptile Server', 'required'); + $this->form_validation->set_rules('maptile_server_url_dark', 'URL of Dark Maptile Server', 'required'); + $this->form_validation->set_rules('subdomain_system', 'Subdomains for Loadbalancing', 'required'); + $this->form_validation->set_rules('copyright_url', 'URL for Copyright', 'required'); + $this->form_validation->set_rules('copyright_text', 'Text for Copyright', 'required'); + + if ($this->form_validation->run() == FALSE) { + + $this->maptiles(); + + } else { + $saved = false; + if ($this->input->post('reset_defaults') == '1') { + $map_tile_server_copyright = 'Map data © OpenStreetMap'; + $saved = $this->optionslib->update('map_tile_server', 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', 'yes'); + $saved = $this->optionslib->update('map_tile_server_dark', 'https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png', 'yes'); + $saved = $this->optionslib->update('map_tile_subdomains', 'abc', 'yes'); + } else { + $map_tile_server_copyright = 'Map data © ' . $this->input->post('copyright_text', true) . ''; + $saved = $this->optionslib->update('map_tile_server', $this->input->post('maptile_server_url', true), 'yes'); + $saved = $this->optionslib->update('map_tile_server_dark', $this->input->post('maptile_server_url_dark', true), 'yes'); + $saved = $this->optionslib->update('map_tile_subdomains', $this->input->post('subdomain_system', true), 'yes'); + } + $saved = $this->optionslib->update('map_tile_server_copyright', $map_tile_server_copyright, 'yes'); + + // Also clean up static map images + if (!$this->load->is_loaded('staticmap_model')) { + $this->load->model('staticmap_model'); + } + if (!$this->load->is_loaded('stations')) { + $this->load->model('stations'); + } + $station_ids = explode(',',$this->stations->all_station_ids_of_user()); + foreach ($station_ids as $station_id) { + $this->staticmap_model->remove_static_map_image($station_id); + log_message('debug', 'Removed static map image for station ID ' . $station_id); + } + // also remove the tilecache + $cachepath = $this->config->item('cache_path') == '' ? APPPATH . 'cache/' : $this->config->item('cache_path'); + $cacheDir = $cachepath . "tilecache/"; + $tilecache_warning = false; + if (function_usable('exec')) { + try { + if (is_dir($cacheDir)) { + exec('rm -rf ' . $cacheDir); + } + } catch (\Throwable $th) { + $tilecache_warning = true; + } + } else { + $tilecache_warning = true; + } + if ($tilecache_warning) { + $this->session->set_flashdata('warning', sprintf(__("Maptile cache could not be removed. Delete the folder manually. Path: %s"), str_replace(FCPATH, '', $cacheDir))); + log_message('debug', 'Maptile cache could not be removed. Delete the folder manually. Path: ' . str_replace(FCPATH, '', $cacheDir)); + } + if($saved == true) { + $this->session->set_flashdata('success', __("Maptile Options saved!")); + } else { + $this->session->set_flashdata('error', __("Maptile Options could not be saved!")); + log_message('error', 'Maptile Options could not be saved!'); + } + redirect('/options/maptiles'); + } + } + // function used to display the /version_dialog url function version_dialog() { diff --git a/application/controllers/Oqrs.php b/application/controllers/Oqrs.php index ec2005bb0..4a7aeeb8b 100644 --- a/application/controllers/Oqrs.php +++ b/application/controllers/Oqrs.php @@ -132,6 +132,8 @@ class Oqrs extends CI_Controller { public function requests() { $data['page_title'] = __("OQRS Requests"); + $this->load->model('user_model'); + if(!$this->user_model->authorize(2) || !clubaccess_check(9)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } $this->load->model('logbooks_model'); $logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($this->session->userdata('active_station_logbook')); diff --git a/application/controllers/Qrz.php b/application/controllers/Qrz.php index ea44f343f..1f2c18888 100644 --- a/application/controllers/Qrz.php +++ b/application/controllers/Qrz.php @@ -152,6 +152,11 @@ class Qrz extends CI_Controller { $this->markqso($qso->COL_PRIMARY_KEY,'I'); $result['status'] = 'Error'; $errormessages[] = $result['message'] . ' Call: ' . $qso->COL_CALL . ' Band: ' . $qso->COL_BAND . ' Mode: ' . $qso->COL_MODE . ' Time: ' . $qso->COL_TIME_ON; + } elseif ( ($result['status']=='error') && (str_contains($result['message'],'required field missing mode')) ) { + log_message('error', 'QRZ upload failed for qso for Station_ID '.$station_id.' // Call: ' . $qso->COL_CALL . ' Band: ' . $qso->COL_BAND . ' Mode: ' . $qso->COL_MODE . ' Time: ' . $qso->COL_TIME_ON . ' // Message: '.$result['message']); + $this->markqso($qso->COL_PRIMARY_KEY,'I'); + $result['status'] = 'Error'; + $errormessages[] = $result['message'] . ' Call: ' . $qso->COL_CALL . ' Band: ' . $qso->COL_BAND . ' Mode: ' . $qso->COL_MODE . ' Time: ' . $qso->COL_TIME_ON; } elseif ( ($result['status']=='error') && (substr($result['message'],0,11) == 'STATUS=AUTH')) { log_message('error', 'QRZ upload failed for qso for Station_ID '.$station_id.' // Call: ' . $qso->COL_CALL . ' Band: ' . $qso->COL_BAND . ' Mode: ' . $qso->COL_MODE . ' Time: ' . $qso->COL_TIME_ON . ' // Message: '.$result['message']); $errormessages[] = $result['message'] . ' Call: ' . $qso->COL_CALL . ' Band: ' . $qso->COL_BAND . ' Mode: ' . $qso->COL_MODE . ' Time: ' . $qso->COL_TIME_ON; @@ -191,6 +196,9 @@ class Qrz extends CI_Controller { * Used for displaying the uid for manually selecting log for upload to qrz */ public function export() { + $this->load->model('user_model'); + if(!$this->user_model->authorize(2) || !clubaccess_check(9)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } + $this->load->model('stations'); $data['page_title'] = __("QRZ Logbook"); @@ -345,7 +353,7 @@ class Qrz extends CI_Controller { function mass_download_qsos($qrz_api_key = '', $lastqrz = '1900-01-01', $station_ids = '', $trusted = false) { $config['upload_path'] = './uploads/'; - $file = $config['upload_path'] . 'qrzcom_download_report.adi'; + $file = $config['upload_path'] . 'qrzcom_download_report_'.md5($qrz_api_key).'.adi'; if (file_exists($file) && ! is_writable($file)) { $result = "Temporary download file ".$file." is not writable. Aborting!"; return false; @@ -365,11 +373,11 @@ class Qrz extends CI_Controller { curl_setopt( $ch, CURLOPT_USERAGENT, 'Wavelog/'.$this->optionslib->get_option('version')); $content = htmlspecialchars_decode(curl_exec($ch)); - file_put_contents($file, $content); - if (strlen(file_get_contents($file, false, null, 0, 100))!=100) { + if (strlen($content)<100) { $result = "QRZ downloading failed, either due to it being down or incorrect logins."; return "false"; } + file_put_contents($file, $content); ini_set('memory_limit', '-1'); $result = $this->loadFromFile($file, $station_ids); diff --git a/application/controllers/Qslprint.php b/application/controllers/Qslprint.php index 1491e160e..ae969d7f8 100644 --- a/application/controllers/Qslprint.php +++ b/application/controllers/Qslprint.php @@ -19,25 +19,23 @@ class QSLPrint extends CI_Controller { public function index($station_id = 'All') { - $this->load->model('user_model'); - // Check if users logged in + $this->load->model('user_model'); + if(!$this->user_model->authorize(2) || !clubaccess_check(9)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } - if($this->user_model->validate_session() == 0) { - // user is not logged in - redirect('user/login'); - } $this->load->model('stations'); $data['station_id'] = $this->security->xss_clean($station_id); $data['station_profile'] = $this->stations->all_of_user(); $this->load->model('qslprint_model'); if ( ($station_id != 'All') && ($this->stations->check_station_is_accessible($station_id)) ) { - $data['qsos'] = $this->qslprint_model->get_qsos_for_print($station_id); + $qsos = $this->qslprint_model->get_qsos_for_print($station_id); } else { - $data['qsos'] = $this->qslprint_model->get_qsos_for_print(); + $qsos = $this->qslprint_model->get_qsos_for_print(); } + $data['qsos'] = $qsos; + $footerData = []; $footerData['scripts'] = [ 'assets/js/sections/qslprint.js', @@ -195,6 +193,16 @@ class QSLPrint extends CI_Controller { $this->load->view('oqrs/showoqrs', $data); } + public function get_previous_qsl() { + $id = $this->security->xss_clean($this->input->post('id')); + + $this->load->model('qslprint_model'); + + $number_qsls = $this->qslprint_model->get_previous_qsls($id); + header('Content-Type: application/json'); + echo json_encode($number_qsls); + } + } /* End of file Qslprint.php */ diff --git a/application/controllers/Qso.php b/application/controllers/Qso.php index 669398255..fbe2b8f69 100644 --- a/application/controllers/Qso.php +++ b/application/controllers/Qso.php @@ -32,7 +32,7 @@ class QSO extends CI_Controller { $data['notice'] = false; $data['stations'] = $this->stations->all_of_user(); - $data['radios'] = $this->cat->radios(); + $data['radios'] = $this->cat->radios(true); $data['radio_last_updated'] = $this->cat->last_updated()->row(); $data['query'] = $this->logbook_model->last_custom('5'); $data['dxcc'] = $this->logbook_model->fetchDxcc(); @@ -130,7 +130,7 @@ class QSO extends CI_Controller { 'prop_mode' => $this->input->post('prop_mode', TRUE), 'radio' => $this->input->post('radio', TRUE), 'station_profile_id' => $this->input->post('station_profile', TRUE), - 'operator_callsign' => $this->input->post('operator_callsign', TRUE), + 'operator_callsign' => $this->input->post('operator_callsign', TRUE) ?? $this->session->userdata('operator_callsign'), 'transmit_power' => $this->input->post('transmit_power', TRUE) ); // ]; @@ -675,4 +675,20 @@ class QSO extends CI_Controller { redirect('dashboard'); } } + + /** + * Easy modal Loader + * Used for Share Modal in QSO Details view + */ + function getShareModal() { + + $data['qso'] = $this->input->post('qso_data', TRUE); + + if (empty($data['qso'])) { + echo "No QSO data provided."; + return; + } + + $this->load->view('qso/components/share_modal', $data, false); + } } diff --git a/application/controllers/Radio.php b/application/controllers/Radio.php index c0664b6cf..6963c00c8 100644 --- a/application/controllers/Radio.php +++ b/application/controllers/Radio.php @@ -28,15 +28,9 @@ class Radio extends CI_Controller { function status() { - // Check Auth $this->load->model('user_model'); + if(!$this->user_model->authorize(3)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } - // Check if users logged in - - if ($this->user_model->validate_session() == 0) { - // user is not logged in - redirect('user/login'); - } session_write_close(); $this->load->model('cat'); @@ -45,10 +39,13 @@ class Radio extends CI_Controller { if ($query->num_rows() > 0) { echo ""; echo "" . __("Radio") . ""; + if ($this->session->userdata('clubstation') == 1 && clubaccess_check(9)) { + echo "" . __("Operator") . ""; + } echo "" . __("Frequency") . ""; echo "" . __("Mode") . ""; echo "" . __("Timestamp") . ""; - echo ""; + echo " "; echo "" . __("Options") . ""; echo "" . __("Settings") . ""; echo ""; @@ -57,6 +54,16 @@ class Radio extends CI_Controller { echo ""; echo "" . $row->radio . ""; + $this->load->model('user_model'); + if ($this->session->userdata('clubstation') == 1 && clubaccess_check(9)) { + $operator = $this->user_model->get_by_id($row->operator)->row(); + if ($operator) { + echo "" . $operator->user_callsign . ""; + } else { + echo "" . __("UNKNOWN") . ""; + } + } + if (empty($row->frequency) || $row->frequency == "0") { echo "- / -"; } elseif (empty($row->frequency_rx) || $row->frequency_rx == "0") { @@ -93,14 +100,16 @@ class Radio extends CI_Controller { echo ''; } - $defaul_user_radio = $this->user_options_model->get_options('cat', array('option_name' => 'default_radio'))->row()->option_value ?? NULL; - if (!$defaul_user_radio) { - echo '"; @@ -238,7 +247,7 @@ class Radio extends CI_Controller { if (isset($cat_url) && ($cat_url != null)) { $a_ret['cat_url'] = $cat_url; } - $a_ret['update_minutes_ago'] = $updated_at; + $a_ret['updated_minutes_ago'] = $updated_at; echo json_encode($a_ret, JSON_PRETTY_PRINT); } } diff --git a/application/controllers/Reg1test.php b/application/controllers/Reg1test.php index 242ffdbe2..cb510a630 100644 --- a/application/controllers/Reg1test.php +++ b/application/controllers/Reg1test.php @@ -14,10 +14,7 @@ class Reg1test extends CI_Controller { // do authorization check $this->load->model('user_model'); - if (!$this->user_model->authorize(2)) { - $this->session->set_flashdata('error', __("You're not allowed to do that!")); - redirect('dashboard'); - } + if(!$this->user_model->authorize(2) || !clubaccess_check(9)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } } public function index() { diff --git a/application/controllers/Satellite.php b/application/controllers/Satellite.php index 04e26a918..561c43b19 100644 --- a/application/controllers/Satellite.php +++ b/application/controllers/Satellite.php @@ -21,6 +21,16 @@ class Satellite extends CI_Controller { $pageData['satellites'] = $this->satellite_model->get_all_satellites(); + if($this->session->userdata('user_date_format')) { + // If Logged in and session exists + $custom_date_format = $this->session->userdata('user_date_format'); + } else { + // Get Default date format from /config/wavelog.php + $custom_date_format = $this->config->item('qso_date_format'); + } + + $pageData['custom_date_format'] = $custom_date_format; + $footerData = []; $footerData['scripts'] = [ 'assets/js/sections/satellite.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/satellite.js")), @@ -75,12 +85,17 @@ class Satellite extends CI_Controller { $id = $this->security->xss_clean($this->input->post('id', true)); $satellite['name'] = $this->security->xss_clean($this->input->post('name')); - $satellite['exportname'] = $this->security->xss_clean($this->input->post('exportname')); + $satellite['displayname'] = $this->security->xss_clean($this->input->post('displayname')); $satellite['orbit'] = $this->security->xss_clean($this->input->post('orbit')); + if ($this->security->xss_clean($this->input->post('lotw')) == 'Y') { + $satellite['lotw'] = 'Y'; + } else {; + $satellite['lotw'] = 'N'; + } - $this->satellite_model->saveupdatedsatellite($id, $satellite); + $this->satellite_model->saveupdatedsatellite($id, $satellite); echo json_encode(array('message' => 'OK')); - return; + return; } public function delete() { @@ -219,12 +234,32 @@ class Satellite extends CI_Controller { $this->load->view('interface_assets/footer', $footerData); } - public function searchpasses() { + public function searchPasses() { if(!$this->user_model->authorize(3)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } try { - $result = $this->get_tle_for_predict(); - $this->calcpass($result); + $tle = $this->get_tle_for_predict(); + $yourgrid = $this->security->xss_clean($this->input->post('yourgrid')); + $altitude = $this->security->xss_clean($this->input->post('altitude')); + $date = $this->security->xss_clean($this->input->post('date')); + $minelevation = $this->security->xss_clean($this->input->post('minelevation')); + $timezone = $this->security->xss_clean($this->input->post('timezone')); + $data = $this->calcPass($tle, $yourgrid, $altitude, $date, $minelevation, $timezone); + + $this->load->view('satellite/passtable', $data); + } + catch (Exception $e) { + header("Content-type: application/json"); + echo json_encode(['ok' => 'Error', 'message' => $e->getMessage() . $e->getCode()]); + } + } + + public function searchSkedPasses() { + if(!$this->user_model->authorize(3)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } + + try { + $tle = $this->get_tle_for_predict(); + $this->calcSkedPass($tle); } catch (Exception $e) { header("Content-type: application/json"); @@ -240,7 +275,7 @@ class Satellite extends CI_Controller { return $this->satellite_model->get_tle($sat); } - function calcpass($sat_tle) { + function calcPass($sat_tle, $yourgrid, $altitude, $date, $minelevation, $timezone) { if(!$this->user_model->authorize(3)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } require_once "./src/predict/Predict.php"; @@ -252,9 +287,9 @@ class Satellite extends CI_Controller { // The observer or groundstation is called QTH in ham radio terms $predict = new Predict(); $qth = new Predict_QTH(); - $qth->alt = $this->security->xss_clean($this->input->post('altitude')); // Altitude in meters + $qth->alt = $altitude; // Altitude in meters - $strQRA = $this->security->xss_clean($this->input->post('yourgrid')); + $strQRA = $yourgrid; if ((strlen($strQRA) % 2 == 0) && (strlen($strQRA) <= 10)) { // Check if QRA is EVEN (the % 2 does that) and smaller/equal 8 $strQRA = strtoupper($strQRA); @@ -270,7 +305,7 @@ class Satellite extends CI_Controller { if(!$this->load->is_loaded('Qra')) { $this->load->library('Qra'); } - $homecoordinates = $this->qra->qra2latlong($this->security->xss_clean($this->input->post('yourgrid'))); + $homecoordinates = $this->qra->qra2latlong($yourgrid); $qth->lat = $homecoordinates[0]; $qth->lon = $homecoordinates[1]; @@ -280,11 +315,11 @@ class Satellite extends CI_Controller { $tle = new Predict_TLE($sat_tle->satellite, $temp[0], $temp[1]); // Instantiate it $sat = new Predict_Sat($tle); // Load up the satellite data - $now = Predict_Time::get_current_daynum(); // get the current time as Julian Date (daynum) + $now = $this->get_daynum_from_date($date); // get the current time as Julian Date (daynum) // You can modify some preferences in Predict(), the defaults are below // - $predict->minEle = intval($this->security->xss_clean($this->input->post('minelevation'))); // Minimum elevation for a pass + $predict->minEle = intval($minelevation); // Minimum elevation for a pass $predict->timeRes = 1; // Pass details: time resolution in seconds $predict->numEntries = 20; // Pass details: number of entries per pass // $predict->threshold = -6; // Twilight threshold (sun must be at this lat or lower) @@ -293,8 +328,6 @@ class Satellite extends CI_Controller { $results = $predict->get_passes($sat, $qth, $now, 1); $filtered = $predict->filterVisiblePasses($results); - $zone = $this->security->xss_clean($this->input->post('timezone')); - // Get Date format if ($this->session->userdata('user_date_format')) { // If Logged in and session exists @@ -304,11 +337,87 @@ class Satellite extends CI_Controller { $custom_date_format = $this->config->item('qso_date_format'); } - $format = $custom_date_format . ' H:i:s'; + $data['format'] = $custom_date_format . ' H:i:s'; $data['filtered'] = $filtered; - $data['zone'] = $zone; - $data['format'] = $format; - $this->load->view('satellite/passtable', $data); + $data['zone'] = $timezone; + + return $data; + + } + + function calcSkedPass($tle) { + if(!$this->user_model->authorize(3)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } + + $yourgrid = $this->security->xss_clean($this->input->post('yourgrid')); + $altitude = $this->security->xss_clean($this->input->post('altitude')); + $date = $this->security->xss_clean($this->input->post('date')); + $minelevation = $this->security->xss_clean($this->input->post('minelevation')); + $timezone = $this->security->xss_clean($this->input->post('timezone')); + + $homePass = $this->calcPass($tle, $yourgrid, $altitude, $date, $minelevation, $timezone); + + $skedgrid = $this->security->xss_clean($this->input->post('skedgrid')); + $minskedelevation = $this->security->xss_clean($this->input->post('minskedelevation')); + + $skedPass = $this->calcPass($tle, $skedgrid, 0, $date, $minskedelevation, $timezone); + + // Get Date format + if ($this->session->userdata('user_date_format')) { + // If Logged in and session exists + $custom_date_format = $this->session->userdata('user_date_format'); + } else { + // Get Default date format from /config/wavelog.php + $custom_date_format = $this->config->item('qso_date_format'); + } + + $data['format'] = $custom_date_format . ' H:i:s'; + + $data['overlaps'] = $this->findOverlaps($homePass, $skedPass); + $data['zone'] = $timezone; + $data['yourgrid'] = $yourgrid; + $data['skedgrid'] = $skedgrid; + $data['date'] = $date; + $data['custom_date_format'] = $custom_date_format; + + $this->load->view('satellite/skedtable', $data); + } + + function findOverlaps($homePass, $skedPass) { + $overlaps = []; // Store overlapping passes + + foreach ($homePass['filtered'] as $pass1) { + foreach ($skedPass['filtered'] as $pass2) { + if ($this->checkOverlap($pass1, $pass2)) { + $overlaps[] = [ + 'grid1' => $pass1, + 'grid2' => $pass2 + ]; + } + } + } + + return $overlaps; + } + + function checkOverlap($pass1, $pass2) { + // Calculate the overlap condition + $start = max($pass1->visible_aos, $pass2->visible_aos); // Latest start time + $end = min($pass1->visible_los, $pass2->visible_los); // Earliest end time + + return $start <= $end; // True if intervals overlap + } + + public static function get_daynum_from_date($date) { + // Convert a Y-m-d date to a day number + + // Convert date to Unix timestamp + $timestamp = strtotime($date); + if ($timestamp === false) { + throw new Exception("Invalid date format. Expected Y-m-d."); + } + + // Calculate the day number + return Predict_Time::unix2daynum($timestamp, 0); } } diff --git a/application/controllers/Search.php b/application/controllers/Search.php index 624e2a491..a7cd44dba 100644 --- a/application/controllers/Search.php +++ b/application/controllers/Search.php @@ -98,7 +98,8 @@ class Search extends CI_Controller { } function search_result() { - $data['results'] = $this->fetchQueryResult(($this->input->post('search', TRUE) ?? ''), FALSE); + $sstring = str_replace('Ø', "0", $this->input->post("method", TRUE) ?? ''); + $data['results'] = $this->fetchQueryResult($sstring, FALSE); $this->load->view('search/search_result_ajax', $data); } diff --git a/application/controllers/Simplefle.php b/application/controllers/Simplefle.php index 1d60686b8..bf7d6ef03 100644 --- a/application/controllers/Simplefle.php +++ b/application/controllers/Simplefle.php @@ -82,22 +82,18 @@ class SimpleFLE extends CI_Controller { $this->load->model('logbook_model'); $qsos = json_decode($qsos, true); - $result = []; - foreach ($qsos as $qso) { - $one_result = $this->logbook_model->import($qso, $qso['station_id']); + $station_id = $qsos[0]['station_id']; // we can trust this value - // if the returner is not empty we have an error and should log it - if ($result != '' && strpos(json_encode($one_result), 'Duplicate for') == false) { - log_message('error', 'SimpleFLE, save_qsos(); For QSO: ' . $qso['call'] . ' on ' . $qso['qso_date'] . ' Error: ' . json_encode($result)); - } - if (strpos(json_encode($one_result), 'Duplicate for') !== false) { - log_message('debug', 'SimpleFLE, save_qsos(); For QSO: ' . $qso['call'] . ' on ' . $qso['qso_date'] . ' Warning: ' . json_encode($result)); - } + $bulk_result = $this->logbook_model->import_bulk($qsos, $station_id); - if ($one_result != '') { - $result[] = $one_result; - } + $clean_result = str_replace(['

'], "\n", $bulk_result); + log_message('debug', "SimpleFLE, save_qsos(); Bulk Result: \n" . $clean_result); + + // Also clean up static map images + if (!$this->load->is_loaded('staticmap_model')) { + $this->load->model('staticmap_model'); } + $this->staticmap_model->remove_static_map_image($station_id); if (empty($result)) { echo "success"; diff --git a/application/controllers/Staticmap.php b/application/controllers/Staticmap.php index aa32cb377..ab9d06b82 100644 --- a/application/controllers/Staticmap.php +++ b/application/controllers/Staticmap.php @@ -80,6 +80,12 @@ class Staticmap extends CI_Controller { $ituzones = $r == 'true' ? true : false; } + // Watermark + $watermark = $this->input->get('wm', TRUE) ?? ''; + if ($watermark == '' || ($watermark != 1 && $watermark != 0)) { + $watermark = true; + } + // handling the theme mode $this->load->model('themes_model'); if ($thememode == null || $thememode == '' || ($thememode != 'dark' && $thememode != 'light')) { @@ -97,8 +103,24 @@ class Staticmap extends CI_Controller { // we need the realpath later for validation $cacheDir = realpath($cachepath . "staticmap_images/"); - // create a unique filename for the cache - $filenameRaw = $uid . $logbook_id . $qsocount . $band . $thememode . $continent . $hide_home . ($night_shadow == false ? 0 : 1) . ($pathlines == false ? 0 : 1) . ($cqzones == false ? 0 : 1) . ($ituzones == false ? 0 : 1) . $orbit . $contest . $start_date . $end_date; + // create a unique filename for the cacheund e + $filenameRaw = $uid + . $logbook_id + . $qsocount + . $band + . $thememode + . $continent + . $hide_home + . ($night_shadow == false ? 0 : 1) + . ($pathlines == false ? 0 : 1) + . ($cqzones == false ? 0 : 1) + . ($ituzones == false ? 0 : 1) + . $orbit + . $contest + . $start_date + . $end_date + . $watermark; + $filename = crc32('staticmap_' . $slug) . '_' . substr(md5($filenameRaw), 0, 12) . '.png'; $filepath = $cacheDir . '/' . $filename; @@ -163,7 +185,7 @@ class Staticmap extends CI_Controller { $end_date == 'noEnd' ? '' : $end_date ); - $image = $this->staticmap_model->render_static_map($qsos, $uid, $centerMap, $coordinates, $filepath, $continent, $thememode, $hide_home, $night_shadow, $pathlines, $cqzones, $ituzones); + $image = $this->staticmap_model->render_static_map($qsos, $uid, $centerMap, $coordinates, $filepath, $continent, $thememode, $hide_home, $night_shadow, $pathlines, $cqzones, $ituzones, $watermark); header('Content-Type: image/png'); diff --git a/application/controllers/Station.php b/application/controllers/Station.php index 8c509b90c..f7afddada 100644 --- a/application/controllers/Station.php +++ b/application/controllers/Station.php @@ -60,7 +60,7 @@ class Station extends CI_Controller if ($this->stations->edit()) { $data['notice'] = __("Station Location") . $this->security->xss_clean($this->input->post('station_profile_name', true)) . " Updated"; } - // Also clean up static map images first + // Also clean up static map images if (!$this->load->is_loaded('staticmap_model')) { $this->load->model('staticmap_model'); } diff --git a/application/controllers/Stationsetup.php b/application/controllers/Stationsetup.php index 6dbcb2a19..3ef2ee9b2 100644 --- a/application/controllers/Stationsetup.php +++ b/application/controllers/Stationsetup.php @@ -12,7 +12,7 @@ class Stationsetup extends CI_Controller { $this->load->helper(array('form', 'url')); $this->load->model('user_model'); - if(!$this->user_model->authorize(2)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } + if(!$this->user_model->authorize(2) || !clubaccess_check(9)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } } public function index() { diff --git a/application/controllers/Statistics.php b/application/controllers/Statistics.php index 587c5cd8a..cbe4400f8 100644 --- a/application/controllers/Statistics.php +++ b/application/controllers/Statistics.php @@ -8,24 +8,24 @@ class Statistics extends CI_Controller { } - public function index() - { - $this->load->model('user_model'); - $this->load->model('bands'); + public function index() { + $this->load->model('user_model'); + $this->load->model('bands'); - if(!$this->user_model->authorize($this->config->item('auth_mode'))) { - if($this->user_model->validate_session()) { - $this->user_model->clear_session(); - show_error('Access denied

Click here to log in as another user', 403); - } else { - redirect('user/login'); - } - } + if(!$this->user_model->authorize($this->config->item('auth_mode'))) { + if($this->user_model->validate_session()) { + $this->user_model->clear_session(); + show_error('Access denied

Click here to log in as another user', 403); + } else { + redirect('user/login'); + } + } // Render User Interface // Set Page Title $data['page_title'] = __("Statistics"); $data['sat_active'] = array_search("SAT", $this->bands->get_user_bands(), true); + $data['years'] = $this->get_years(); // Load Views $this->load->view('interface_assets/header', $data); @@ -77,6 +77,18 @@ class Statistics extends CI_Controller { } + function get_years() { + $this->load->model('logbook_model'); + $totals_year = $this->logbook_model->totals_year(); + $years=[]; + if ($totals_year) { + foreach($totals_year->result() as $years_obj) { + $years[] = $years_obj->year; + } + } + return $years; + } + public function get_year() { $this->load->model('logbook_model'); @@ -99,18 +111,21 @@ class Statistics extends CI_Controller { public function get_mode() { $this->load->model('logbook_model'); + $yr = xss_clean($this->input->post('yr')) ?? 'All'; $modestats = array(); $i = 0; $modestats[$i]['mode'] = 'ssb'; - $modestats[$i++]['total'] = $this->logbook_model->total_ssb(); + $modestats[$i++]['total'] = $this->logbook_model->total_ssb($yr); $modestats[$i]['mode'] = 'cw'; - $modestats[$i++]['total'] = $this->logbook_model->total_cw(); + $modestats[$i++]['total'] = $this->logbook_model->total_cw($yr); $modestats[$i]['mode'] = 'fm'; - $modestats[$i++]['total'] = $this->logbook_model->total_fm(); + $modestats[$i++]['total'] = $this->logbook_model->total_fm($yr); + $modestats[$i]['mode'] = 'am'; + $modestats[$i++]['total'] = $this->logbook_model->total_am($yr); $modestats[$i]['mode'] = 'digi'; - $modestats[$i]['total'] = $this->logbook_model->total_digi(); + $modestats[$i]['total'] = $this->logbook_model->total_digi($yr); usort($modestats, fn($a, $b) => $b['total'] <=> $a['total']); header('Content-Type: application/json'); @@ -123,7 +138,8 @@ class Statistics extends CI_Controller { $bandstats = array(); - $total_bands = $this->logbook_model->total_bands(); + $yr = xss_clean($this->input->post('yr')) ?? 'All'; + $total_bands = $this->logbook_model->total_bands($yr); $i = 0; @@ -143,7 +159,8 @@ class Statistics extends CI_Controller { $satstats = array(); - $total_sat = $this->logbook_model->total_sat(); + $yr = xss_clean($this->input->post('yr')) ?? 'All'; + $total_sat = $this->logbook_model->total_sat($yr); $i = 0; if ($total_sat) { @@ -162,13 +179,14 @@ class Statistics extends CI_Controller { $total_qsos = array(); - $result = $this->stats->unique_sat_callsigns(); + $yr = xss_clean($this->input->post('yr')) ?? 'All'; + $result = $this->stats->unique_sat_callsigns($yr); $total_qsos['qsoarray'] = $result['qsoView']; $total_qsos['satunique'] = $result['satunique']; $total_qsos['modeunique'] = $result['modeunique']; $total_qsos['total'] = $result['total']; - $total_qsos['sats'] = $this->stats->get_sats(); - $total_qsos['modes'] = $this->stats->get_sat_modes(); + $total_qsos['sats'] = $this->stats->get_sats($yr); + $total_qsos['modes'] = $this->stats->get_sat_modes($yr); $this->load->view('statistics/satuniquetable', $total_qsos); } @@ -178,12 +196,13 @@ class Statistics extends CI_Controller { $total_qsos = array(); - $result = $this->stats->unique_callsigns(); + $yr = xss_clean($this->input->post('yr')) ?? 'All'; + $result = $this->stats->unique_callsigns($yr); $total_qsos['qsoarray'] = $result['qsoView']; $total_qsos['bandunique'] = $result['bandunique']; $total_qsos['modeunique'] = $result['modeunique']; $total_qsos['total'] = $result['total']; - $total_qsos['bands'] = $this->stats->get_bands(); + $total_qsos['bands'] = $this->stats->get_bands($yr); $this->load->view('statistics/uniquetable', $total_qsos); } @@ -193,12 +212,13 @@ class Statistics extends CI_Controller { $total_qsos = array(); - $result = $this->stats->total_sat_qsos(); + $yr = xss_clean($this->input->post('yr')) ?? 'All'; + $result = $this->stats->total_sat_qsos($yr); $total_qsos['qsoarray'] = $result['qsoView']; $total_qsos['sattotal'] = $result['sattotal']; $total_qsos['modetotal'] = $result['modetotal']; $total_qsos['modes'] = $result['modes']; - $total_qsos['sats'] = $this->stats->get_sats(); + $total_qsos['sats'] = $this->stats->get_sats($yr); $this->load->view('statistics/satqsotable', $total_qsos); } @@ -208,11 +228,12 @@ class Statistics extends CI_Controller { $total_qsos = array(); - $result = $this->stats->total_qsos(); + $yr = xss_clean($this->input->post('yr')) ?? 'All'; + $result = $this->stats->total_qsos($yr); $total_qsos['qsoarray'] = $result['qsoView']; $total_qsos['bandtotal'] = $result['bandtotal']; $total_qsos['modetotal'] = $result['modetotal']; - $total_qsos['bands'] = $this->stats->get_bands(); + $total_qsos['bands'] = $this->stats->get_bands($yr); $this->load->view('statistics/qsotable', $total_qsos); } @@ -236,4 +257,55 @@ class Statistics extends CI_Controller { $this->load->view('statistics/qsltable', $total_qsos); $this->load->view('interface_assets/footer'); } + + public function antennaanalytics() { + $this->load->model('stats'); + $this->load->model('logbookadvanced_model'); + $this->load->model('bands'); + + $data = array(); + + $headerData['page_title'] = __("Antenna Analytics"); + + $data['satellites'] = $this->stats->get_sats(); + $data['bands'] = $this->bands->get_worked_bands(); + $data['modes'] = $this->logbookadvanced_model->get_modes(); + $data['sats'] = $this->bands->get_worked_sats(); + $data['orbits'] = $this->bands->get_worked_orbits(); + + $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/antennestats.js")), + ]; + + // Load Views + $this->load->view('interface_assets/header', $headerData); + $this->load->view('statistics/antennaanalytics', $data); + $this->load->view('interface_assets/footer', $footerData); + } + + public function get_azimuth_data() { + $band = xss_clean($this->input->post('band')); + $mode = xss_clean($this->input->post('mode')); + $sat = xss_clean($this->input->post('sat')); + $orbit = xss_clean($this->input->post('orbit')); + + $this->load->model('stats'); + $azimutharray = $this->stats->azimuthdata($band, $mode, $sat, $orbit); + + header('Content-Type: application/json'); + echo json_encode($azimutharray); + } + + public function get_elevation_data() { + $sat = xss_clean($this->input->post('sat')); + $orbit = xss_clean($this->input->post('orbit')); + + $this->load->model('stats'); + $elevationarray = $this->stats->elevationdata($sat, $orbit); + + header('Content-Type: application/json'); + echo json_encode($elevationarray); + } } diff --git a/application/controllers/Timeline.php b/application/controllers/Timeline.php index af30bc277..34cbc6742 100644 --- a/application/controllers/Timeline.php +++ b/application/controllers/Timeline.php @@ -44,6 +44,12 @@ class Timeline extends CI_Controller { $award = 'dxcc'; } + if ($this->input->post('year') != NULL) { + $year = $this->security->xss_clean($this->input->post('year')); + } else { + $year = 'All'; + } + if ($this->input->post('qsl') != NULL) { $qsl = $this->security->xss_clean($this->input->post('qsl')); } else { @@ -68,17 +74,32 @@ class Timeline extends CI_Controller { $eqsl = '0'; } + if ($this->input->post('qrz') != NULL) { + $qrz = $this->security->xss_clean($this->input->post('qrz')); + } else { + $qrz = '0'; + } + + if ($this->input->post('onlynew') != NULL) { + $onlynew = $this->security->xss_clean($this->input->post('onlynew')); + } else { + $onlynew = '0'; + } + $this->load->model('modes'); $this->load->model('bands'); $data['modes'] = $this->modes->active(); - $data['timeline_array'] = $this->Timeline_model->get_timeline($band, $mode, $propmode, $award, $qsl, $lotw, $eqsl, $clublog); + $data['timeline_array'] = $this->Timeline_model->get_timeline($band, $mode, $propmode, $award, $qsl, $lotw, $eqsl, $clublog, $year, $qrz, $onlynew); $data['worked_bands'] = $this->bands->get_worked_bands(); $data['bandselect'] = $band; $data['modeselect'] = $mode; $data['propmode'] = $propmode; $data['user_default_band'] = $this->session->userdata('user_default_band'); + $data['years'] = $this->Timeline_model->get_years(); + $data['onlynew'] = $onlynew; + $data['selectedyear'] = $year; $footerData['scripts'] = [ 'assets/js/sections/timeline.js?' ]; $this->load->view('interface_assets/header', $data); diff --git a/application/controllers/Update.php b/application/controllers/Update.php index f8fca53cd..b734c7edc 100644 --- a/application/controllers/Update.php +++ b/application/controllers/Update.php @@ -211,7 +211,7 @@ class Update extends CI_Controller { $gz = gzopen($url, 'r'); if ($gz === FALSE) { $this->update_status("FAILED: Could not download from clublog.org"); - log_message('error', 'FAILED: Could not download exceptions from clublog.org'); + log_message('error', 'FAILED: Could not download data from clublog.org'); exit(); } @@ -223,6 +223,7 @@ class Update extends CI_Controller { if (file_put_contents($this->paths->make_update_path("cty.xml"), $data) === FALSE) { $this->update_status("FAILED: Could not write to cty.xml file"); + log_message('error', 'DXCC UPDATE FAILED: Could not write to cty.xml file'); exit(); } @@ -388,66 +389,26 @@ class Update extends CI_Controller { } - public function update_tle() { - $mtime = microtime(); - $mtime = explode(" ",$mtime); - $mtime = $mtime[1] + $mtime[0]; - $starttime = $mtime; + public function update_tle() { + $this->load->model('Update_model'); + $result = $this->Update_model->tle(); + echo $result; + } - $url = 'https://www.amsat.org/tle/dailytle.txt'; - $curl = curl_init($url); - - curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); - curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); - - $response = curl_exec($curl); - - $count = 0; - - if ($response === false) { - echo 'Error: ' . curl_error($curl); - } else { - $this->db->empty_table("tle"); - // Split the response into an array of lines - $lines = explode("\n", $response); - - $satname = ''; - $tleline1 = ''; - $tleline2 = ''; - // Process each line - for ($i = 0; $i < count($lines); $i += 3) { - $count++; - // Check if there are at least three lines remaining - if (isset($lines[$i], $lines[$i + 1], $lines[$i + 2])) { - // Get the three lines - $satname = $lines[$i]; - $tleline1 = $lines[$i + 1]; - $tleline2 = $lines[$i + 2]; - $sql = "INSERT INTO tle (satelliteid, tle) select id, ? from satellite where name = ? or exportname = ?"; - $this->db->query($sql,array($tleline1."\n".$tleline2,$satname,$satname)); - } - } - } - - curl_close($curl); - - $mtime = microtime(); - $mtime = explode(" ",$mtime); - $mtime = $mtime[1] + $mtime[0]; - $endtime = $mtime; - $totaltime = ($endtime - $starttime); - echo "This page was created in ".$totaltime." seconds
"; - echo "Records inserted: " . $count . "
"; - $datetime = new DateTime("now", new DateTimeZone('UTC')); - $datetime = $datetime->format('Ymd h:i'); - $this->optionslib->update('tle_update', $datetime , 'no'); - } + public function update_lotw_sats() { + $this->load->model('Update_model'); + $bodyData['satupdates'] = $this->Update_model->lotw_sats(); + $data['page_title'] = __("LoTW SAT Update"); + $this->load->view('interface_assets/header', $data); + $this->load->view('lotw/satupdate', $bodyData); + $this->load->view('interface_assets/footer'); + } function version_check() { // set the last run in cron table for the correct cron id $this->load->model('cron_model'); $this->cron_model->set_last_run($this->router->class . '_' . $this->router->method); - + $this->load->model('Update_model'); $this->Update_model->update_check(); } diff --git a/application/controllers/User.php b/application/controllers/User.php index 20c66a62d..344a990fd 100644 --- a/application/controllers/User.php +++ b/application/controllers/User.php @@ -5,6 +5,7 @@ class User extends CI_Controller { public function index() { $this->load->model('user_model'); + $this->load->library('form_validation'); if (!$this->load->is_loaded('encryption')) { $this->load->library('encryption'); @@ -13,6 +14,8 @@ class User extends CI_Controller { if(!$this->user_model->authorize(99)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } $data['results'] = $this->user_model->users(); + $data['clubs'] = $this->user_model->users('is_club'); + $data['clubmode'] = $this->config->item('special_callsign'); $data['session_uid'] = $this->session->userdata('user_id'); // Check if impersonating is disabled in the config @@ -33,11 +36,77 @@ class User extends CI_Controller { $data['has_flossie'] = ($this->config->item('encryption_key') == 'flossie1234555541') ? true : false; + $footerData = []; + $footerData['scripts'] = [ + 'assets/js/sections/user.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/user.js")), + ]; + $data['page_title'] = __("User Accounts"); $this->load->view('interface_assets/header', $data); $this->load->view('user/index'); - $this->load->view('interface_assets/footer'); + $this->load->view('interface_assets/footer', $footerData); + } + + public function actions_modal() { + + $this->load->model('user_model'); + $this->load->library('encryption'); + if(!$this->user_model->authorize(99)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } + + $data['user_id'] = $this->input->post('user_id', true) ?? ''; + $modal = $this->input->post('modal', true) ?? ''; + + if($this->session->userdata('user_date_format')) { + $custom_date_format = $this->session->userdata('user_date_format'); + } else { + $custom_date_format = $this->config->item('qso_date_format'); + } + + if ($this->user_model->exists_by_id($data['user_id']) && $modal != '') { + $user = $this->user_model->get_by_id($data['user_id'])->row(); + $gettext = new Gettext; + + $data['user_name'] = $user->user_name; + $data['user_callsign'] = $user->user_callsign; + $data['user_email'] = $user->user_email; + $data['user_firstname'] = $user->user_firstname; + $data['user_lastname'] = $user->user_lastname; + $data['user_language'] = $gettext->find_by('folder', $user->user_language)['name_en']; + $data['is_clubstation'] = $user->clubstation == 1 ? true : false; + $data['last_seen'] = $user->last_seen; + $data['custom_date_format'] = $custom_date_format; + $data['has_flossie'] = ($this->config->item('encryption_key') == 'flossie1234555541') ? true : false; + + $this->load->view('user/modals/'.$modal.'_modal', $data); + } else { + $this->session->set_flashdata('error', __("Invalid User ID or missing modal!")); + redirect('user'); + } + } + + public function convert() { + $this->load->model('user_model'); + if(!$this->user_model->authorize(99)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } + + $user_id = $this->input->post('user_id', true) ?? ''; + $convert_to = $this->input->post('convert_to', true) ?? ''; + + if ($convert_to != '0' && $convert_to != '1') { + $this->session->set_flashdata('error', __("Invalid Parameter!")); + redirect('dashboard'); + } + + if ($this->user_model->exists_by_id($user_id)) { + if ($this->user_model->convert($user_id, $convert_to)) { + echo json_encode(true); + } else { + echo json_encode(false); + } + } else { + log_message('error', 'User Conversion - User ID not found: '.$user_id); + echo json_encode(false); + } } function add() { @@ -54,8 +123,8 @@ class User extends CI_Controller { $this->form_validation->set_rules('user_email', 'E-mail', 'required'); $this->form_validation->set_rules('user_password', 'Password', 'required'); $this->form_validation->set_rules('user_type', 'Type', 'required'); - $this->form_validation->set_rules('user_firstname', 'First name', 'required'); - $this->form_validation->set_rules('user_lastname', 'Last name', 'required'); + // $this->form_validation->set_rules('user_firstname', 'First name', 'required'); + // $this->form_validation->set_rules('user_lastname', 'Last name', 'required'); $this->form_validation->set_rules('user_callsign', 'Callsign', 'required'); $this->form_validation->set_rules('user_locator', 'Locator', 'required'); $this->form_validation->set_rules('user_locator', 'Locator', 'callback_check_locator'); @@ -65,9 +134,16 @@ class User extends CI_Controller { $data['user_form_action'] = site_url('user/add'); $data['bands'] = $this->bands->get_user_bands(); + $data['clubstation'] = ($this->input->get('club') ?? '') == '1' ? true : false; + // Get themes list $data['themes'] = $this->user_model->getThemes(); + $footerData = []; + $footerData['scripts'] = [ + 'assets/js/sections/user.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/user.js")), + ]; + // Get timezones $data['timezones'] = $this->user_model->timezones(); $data['user_language'] = 'english'; @@ -81,9 +157,9 @@ class User extends CI_Controller { $data['user_name'] = $this->input->post('user_name'); $data['user_email'] = $this->input->post('user_email'); $data['user_password'] = $this->input->post('user_password'); - $data['user_type'] = $this->input->post('user_type'); - $data['user_firstname'] = $this->input->post('user_firstname'); - $data['user_lastname'] = $this->input->post('user_lastname'); + $data['user_type'] = $data['clubstation'] == true ? '3' : $this->input->post('user_type'); + $data['user_firstname'] = $this->input->post('user_firstname') ?? ''; + $data['user_lastname'] = $this->input->post('user_lastname') ?? ''; $data['user_callsign'] = $this->input->post('user_callsign'); $data['user_locator'] = $this->input->post('user_locator'); $data['user_timezone'] = $this->input->post('user_timezone'); @@ -121,14 +197,14 @@ class User extends CI_Controller { } else { $this->load->view('user/edit', $data); } - $this->load->view('interface_assets/footer'); + $this->load->view('interface_assets/footer', $footerData); } else { switch($this->user_model->add($this->input->post('user_name'), $this->input->post('user_password'), $this->input->post('user_email'), $this->input->post('user_type'), - $this->input->post('user_firstname'), - $this->input->post('user_lastname'), + $this->input->post('user_firstname') ?? '', + $this->input->post('user_lastname') ?? '', $this->input->post('user_callsign'), $this->input->post('user_locator'), $this->input->post('user_timezone'), @@ -169,21 +245,22 @@ class User extends CI_Controller { $this->input->post('user_eqsl_password'), $this->input->post('user_clublog_name'), $this->input->post('user_clublog_password'), - $this->input->post('user_winkey') + $this->input->post('user_winkey'), + $this->input->post('clubstation') == '1' ? true : false )) { // Check for errors case EUSERNAMEEXISTS: - $data['username_error'] = 'Username '.$this->input->post('user_name').' already in use!'; + $data['username_error'] = sprintf(__("Username %s already in use!"), '' . $this->input->post('user_name') . ''); break; case EEMAILEXISTS: - $data['email_error'] = 'E-mail address '.$this->input->post('user_email').' already in use!'; + $data['email_error'] = sprintf(__("E-mail %s already in use!"), '' . $this->input->post('user_email') . ''); break; case EPASSWORDINVALID: - $data['password_error'] = 'Invalid password!'; + $data['password_error'] = __("Invalid Password!"); break; // All okay, return to user screen case OK: - $this->session->set_flashdata('notice', 'User '.$this->input->post('user_name').' added'); + $this->session->set_flashdata('notice', sprintf(__("User %s added!"), '' . $this->input->post('user_name') . '')); redirect('user'); return; } @@ -194,8 +271,8 @@ class User extends CI_Controller { $data['user_email'] = $this->input->post('user_email'); $data['user_password'] = $this->input->post('user_password'); $data['user_type'] = $this->input->post('user_type'); - $data['user_firstname'] = $this->input->post('user_firstname'); - $data['user_lastname'] = $this->input->post('user_lastname'); + $data['user_firstname'] = $this->input->post('user_firstname') ?? ''; + $data['user_lastname'] = $this->input->post('user_lastname') ?? ''; $data['user_callsign'] = $this->input->post('user_callsign'); $data['user_locator'] = $this->input->post('user_locator'); $data['user_measurement_base'] = $this->input->post('user_measurement_base'); @@ -221,7 +298,7 @@ class User extends CI_Controller { $data['user_quicklog_enter'] = $this->input->post('user_quicklog_enter'); $data['user_language'] = $this->input->post('user_language'); $this->load->view('user/edit', $data); - $this->load->view('interface_assets/footer'); + $this->load->view('interface_assets/footer', $footerData); } } @@ -250,12 +327,18 @@ class User extends CI_Controller { $this->form_validation->set_rules('user_locator', 'Locator', 'callback_check_locator'); $this->form_validation->set_rules('user_timezone', 'Timezone', 'required'); - $data['user_form_action'] = site_url('user/edit')."/".$this->uri->segment(3);; + $data['user_form_action'] = site_url('user/edit')."/".$this->uri->segment(3); + $data['clubstation'] = ($query->row()->clubstation == 1) ? true : false; $data['bands'] = $this->bands->get_user_bands(); // Get themes list $data['themes'] = $this->user_model->getThemes(); + $footerData = []; + $footerData['scripts'] = [ + 'assets/js/sections/user.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/user.js")), + ]; + // Get timezones $data['timezones'] = $this->user_model->timezones(); @@ -640,7 +723,7 @@ class User extends CI_Controller { $this->load->view('interface_assets/header', $data); $this->load->view('user/edit', $data); - $this->load->view('interface_assets/footer'); + $this->load->view('interface_assets/footer', $footerData); } else { unset($data); switch($this->user_model->edit($this->input->post())) { @@ -686,10 +769,10 @@ class User extends CI_Controller { } $this->user_options_model->set_option('header_menu', 'locations_quickswitch', array('boolean'=>xss_clean($this->input->post('user_locations_quickswitch', true)))); $this->user_options_model->set_option('header_menu', 'utc_headermenu', array('boolean'=>xss_clean($this->input->post('user_utc_headermenu', true)))); - $this->session->set_flashdata('success', __("User").' '.$this->input->post('user_name', true).' '.__("edited")); + $this->session->set_flashdata('success', sprintf(__("User %s edited"), $this->input->post('user_name', true))); redirect('user/edit/'.$this->uri->segment(3)); } else { - $this->session->set_flashdata('success', __("User").' '.$this->input->post('user_name', true).' '.__("edited")); + $this->session->set_flashdata('success', sprintf(__("User %s edited"), $this->input->post('user_name', true))); redirect('user'); } return; @@ -790,6 +873,14 @@ class User extends CI_Controller { } function login($firstlogin = false) { + + // Due the fact there was a new session generated, we need to get flash messages from a temporary cookie + $tmpdata = json_decode($this->input->cookie(config_item('cookie_prefix') . 'tmp_msg') ?? '') ?? false; + if ($tmpdata) { + $this->session->set_flashdata($tmpdata[0], $tmpdata[1]); + $this->input->set_cookie('tmp_msg', '', -3600, ''); + } + // Check our version and run any migrations if (!$this->load->is_loaded('Migration')) { $this->load->library('Migration'); @@ -814,7 +905,7 @@ class User extends CI_Controller { $data['user'] = $query->row(); // Read the cookie keep_login and allow the login - if ($this->input->cookie(config_item('cookie_prefix') . 'keep_login')) { + if ($this->input->cookie(config_item('cookie_prefix') . 'keep_login') || $this->input->cookie(config_item('cookie_prefix') . 're_login')) { try { @@ -823,7 +914,7 @@ class User extends CI_Controller { } // process the incoming string - $incoming_string = $this->input->cookie(config_item('cookie_prefix') . 'keep_login'); + $incoming_string = $this->input->cookie(config_item('cookie_prefix') . 'keep_login') ?? $this->input->cookie(config_item('cookie_prefix') . 're_login'); $i_str_parts_a = explode(base64_encode($this->config->item('base_url')), $incoming_string); $uid = base64_decode($i_str_parts_a[1]); $a = $i_str_parts_a[0]; @@ -836,6 +927,13 @@ class User extends CI_Controller { $user = $this->user_model->get_by_id($uid)->row(); $user_type = $user->user_type; + // direct login to clubstations are not allowed, especially not with a keeplogin cookie + if ($user->clubstation == 1) { + log_message('debug', "User ID: [$uid] Login rejected because of a external clubstation login attempt with a modified cookie. Attack?"); + $this->session->set_flashdata('error', __("This is not allowed!")); + redirect('user/login'); + } + // compare both strings the hard way and log in if they match if ($this->user_model->check_keep_hash($a, $b)) { @@ -845,7 +943,8 @@ class User extends CI_Controller { // if everything is fine we can log in the user $this->user_model->update_session($uid); $this->user_model->set_last_seen($uid); - log_message('debug', "User ID: [$uid] logged in successfully with 'Keep Login'."); + log_message('info', "User ID: [$uid] logged in successfully with 'Keep Login'."); + $this->input->set_cookie('re_login', '', -3600, ''); // delete re_login cookie in case this was a re-login from a clubstation or impersonated user redirect('dashboard'); } else { @@ -855,6 +954,7 @@ class User extends CI_Controller { // Delete keep_login cookie $this->input->set_cookie('keep_login', '', -3600, ''); + $this->input->set_cookie('re_login', '', -3600, ''); redirect('user/login'); } @@ -864,6 +964,7 @@ class User extends CI_Controller { // Delete keep_login cookie $this->input->set_cookie('keep_login', '', -3600, ''); + $this->input->set_cookie('re_login', '', -3600, ''); $this->session->set_flashdata('error', __("Login failed. Try again.")); redirect('user/login'); } @@ -873,6 +974,7 @@ class User extends CI_Controller { // Delete keep_login cookie $this->input->set_cookie('keep_login', '', -3600, ''); + $this->input->set_cookie('re_login', '', -3600, ''); $this->session->set_flashdata('error', __("Login failed. Try again.")); redirect('user/login'); @@ -888,7 +990,8 @@ class User extends CI_Controller { $this->load->view('interface_assets/footer'); } else { - if($this->user_model->login() == 1) { + $login_attempt = $this->user_model->login(); + if($login_attempt === 1) { $this->user_model->update_session($data['user']->user_id); $cookie= array( @@ -916,7 +1019,10 @@ class User extends CI_Controller { } $this->user_model->set_last_seen($data['user']->user_id); redirect('dashboard'); - + + } else if ($login_attempt === 2) { + $this->session->set_flashdata('warning', __("You can't login to a clubstation directly. Use your personal account instead.")); + redirect('user/login'); } else { if(ENVIRONMENT == 'maintenance') { $this->session->set_flashdata('notice', __("Sorry. This instance is currently in maintenance mode. If this message appears unexpectedly or keeps showing up, please contact an administrator. Only administrators are currently allowed to log in.")); @@ -929,17 +1035,25 @@ class User extends CI_Controller { } } - function logout() { + function logout($custom_message = null, $hard_logout = true) { $this->load->model('user_model'); $user_name = $this->session->userdata('user_name'); // Delete keep_login cookie - $this->input->set_cookie('keep_login', '', -3600, ''); + if ($hard_logout) { + $this->input->set_cookie('re_login', '', -3600, ''); + $this->input->set_cookie('keep_login', '', -3600, ''); + } $this->user_model->clear_session(); - - $this->session->set_flashdata('notice', sprintf(__("User %s logged out."), $user_name)); + + if ($custom_message != null && is_array($custom_message)) { + $this->input->set_cookie('tmp_msg', json_encode([$custom_message[0], $custom_message[1]]), 10, ''); + } else { + $this->input->set_cookie('tmp_msg', json_encode(['notice', sprintf(__("User %s logged out."), $user_name)]), 10, ''); + } + redirect('user/login'); } @@ -1185,13 +1299,15 @@ class User extends CI_Controller { // Check if impersonating is disabled in the config if ($this->config->item('disable_impersonate')) { - show_404(); + $this->session->set_flashdata('error', sprintf(__("You currently can't impersonate another user. You need to set %s to %s in your config.php!"), "'disable_impersonate'", "'false'")); + redirect('dashboard'); } // Load the encryption library if (!$this->load->is_loaded('encryption')) { $this->load->library('encryption'); } + // Load the user model $this->load->model('user_model'); @@ -1241,13 +1357,38 @@ class User extends CI_Controller { redirect('dashboard'); } - // before we can impersonate a user, we need to make sure the current user is an admin - // TODO: authorize from additional datatable 'impersonators' to allow other user types to impersonate + // before we can impersonate a user, we need to make sure the current user is allowed to do so + $clubswitch = $this->input->post('clubswitch', TRUE) ?? ''; + $custom_sessiondata = []; $source_user = $this->user_model->get_by_id($source_uid)->row(); - if(!$source_user || !$this->user_model->authorize(99)) { - $this->session->set_flashdata('error', __("You're not allowed to do that!")); - redirect('dashboard'); + if ($clubswitch == 1) { + $this->load->model('club_model'); + if (!$this->club_model->club_authorize(3, $target_uid, $source_uid) || !$this->user_model->authorize(3)) { + $this->session->set_flashdata('error', __("You're not allowed to do that!")); + redirect('dashboard'); + } else { + $targetclub = array_filter($this->session->userdata('available_clubstations'), function($club) use ($target_uid) { + return $club->user_id == $target_uid; + }); + $p_level = !empty($targetclub) ? reset($targetclub)->p_level : null; + if ($p_level != null) { + $custom_sessiondata['p_level'] = $p_level; + } else { + $this->session->set_flashdata('error', __("Could not determine the correct permission level for the clubstation. Try again after re-login.")); + redirect('dashboard'); + } + } + } else { + if(!$source_user || !$this->user_model->authorize(99)) { + $this->session->set_flashdata('error', __("You're not allowed to do that!")); + redirect('dashboard'); + } else { + $custom_sessiondata['p_level'] = 99; // if the user is an admin he also should have full rights in the clubstations + } } + $custom_sessiondata['src_call'] = $source_user->user_callsign; + $custom_sessiondata['src_user_type'] = $source_user->user_type; + $custom_sessiondata['src_hash'] = $this->input->post('hash', TRUE) ?? ''; /** * Impersonate the user @@ -1255,9 +1396,87 @@ class User extends CI_Controller { // Update the session with the new user_id // TODO: Find a solution for sessiondata 'radio', so a user would be able to use e.g. his own radio while impersonating another user // Due the fact that the user is now impersonating another user, he can't use his default radio anymore - $this->user_model->update_session($target_uid, null, $impersonate = true); + $this->session->set_userdata('source_uid', $source_uid); + $this->user_model->update_session($target_uid, null, true, $custom_sessiondata); // Redirect to the dashboard, the user should now be logged in as the other user redirect('dashboard'); } + + public function stop_impersonate_modal() { + // Load the user model + $this->load->model('user_model'); + if(!$this->user_model->authorize(3)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } + + $this->load->view('user/modals/stop_impersonate_modal'); + } + + public function stop_impersonate() { + // Load the user model + $this->load->model('user_model'); + + // there is no source_uid, there is probably something fishy going on. So we clear the session at this point + $source_uid = $this->session->userdata('source_uid') ?? false; + $post_chk = $this->input->post('stopImpersonate', TRUE) ?? false; + if (!$source_uid || $post_chk != 1) { + $this->logout(['error', __("Ups.. Something went wrong. Try to log back in.")]); + exit; + } + + // is the current user a clubstation we need to check if the source user was allowed to impersonate the clubstation + $club = $this->user_model->get_by_id($this->session->userdata('user_id'))->row(); + $current_is_club = $club->clubstation == 1 ? true : false; + $source_user = $this->user_model->get_by_id($source_uid)->row(); + + if ($current_is_club) { + $this->load->model('club_model'); + if (!$this->club_model->club_authorize(3, $this->session->userdata('user_id'), $source_uid)) { + $this->logout(['error', __("Ups.. Something went wrong. Try to log back in.")]); + exit; + } + } else { + // if the current user is not a clubstation, we need to check if the source user was allowed to impersonate the current user (has to be an admin) + if($source_user->user_type != 99) { + $this->logout(['error', __("Ups.. Something went wrong. Try to log back in.")]); + exit; + } + } + + // Validate the impersonate hash + $this->load->library('encryption'); + $raw_hash = $this->encryption->decrypt($this->session->userdata('cd_src_hash') ?? false); + if (!$raw_hash) { + $this->logout(['error', __("Ups.. Something went wrong. Try to log back in.")]); + exit; + } + $hash_parts = explode('/', $raw_hash); + $src_in_hash = $hash_parts[0]; + $tgt_in_hash = $hash_parts[1]; + $timestamp = $hash_parts[2]; + if ($src_in_hash != $source_uid || $tgt_in_hash != $this->session->userdata('user_id')) { + $this->logout(['error', __("Ups.. Something went wrong. Try to log back in.")]); + exit; + } + + // The timestamp can't be older then 2 hours + if (time() - $timestamp > 7200) { + $this->logout(['notice', __("The ability to return quickly has been disabled after the security hash expired. Please log in again.")]); + exit; + } + + // Create a keep login cookie which will be used to log back in as the source user + $encrypted_string = $this->user_model->keep_cookie_hash($source_uid); + $cookie = array( + 'name' => 're_login', // we use a different cookie name to avoid conflicts with the regular keep_login cookie + 'value' => $encrypted_string, + 'expire' => 20, // seconds should be enough + 'secure' => FALSE, + 'httponly' => TRUE + ); + $this->input->set_cookie($cookie); + + // log out on the regular way + $msg = ['notice', sprintf(__("You have been logged out of the clubstation %s. Welcome back, %s, to your personal account!"), $club->user_callsign, $source_user->user_callsign)]; + $this->logout($msg, false); + } } diff --git a/application/controllers/Visitor.php b/application/controllers/Visitor.php index d386ea25a..4dbfaa963 100644 --- a/application/controllers/Visitor.php +++ b/application/controllers/Visitor.php @@ -387,6 +387,11 @@ class Visitor extends CI_Controller { $data['gridsquares_gridsquares_not_confirmed'] = __("Gridsquares not confirmed"); $data['gridsquares_gridsquares_total_worked'] = __("Total gridsquares worked"); + $data['gridsquares_fields'] = __("Fields"); + $data['gridsquares_fields_confirmed'] = __("Fields confirmed"); + $data['gridsquares_fields_not_confirmed'] = __("Fields not confirmed"); + $data['gridsquares_fields_total_worked'] = __("Total fields worked"); + $data['visitor'] = true; $this->load->view('visitor/layout/header', $data); diff --git a/application/controllers/Webadif.php b/application/controllers/Webadif.php index dc1d1bcf0..989693cc0 100644 --- a/application/controllers/Webadif.php +++ b/application/controllers/Webadif.php @@ -87,6 +87,9 @@ class Webadif extends CI_Controller { * Used for displaying the uid for manually selecting log for upload to webADIF consumer */ public function export() { + $this->load->model('user_model'); + if(!$this->user_model->authorize(2) || !clubaccess_check(9)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } + $this->load->model('stations'); $data['page_title'] = __("QO-100 Dx Club Upload"); diff --git a/application/helpers/club_helper.php b/application/helpers/club_helper.php new file mode 100644 index 000000000..780800b98 --- /dev/null +++ b/application/helpers/club_helper.php @@ -0,0 +1,49 @@ +load->is_loaded('session')) { + $CI->load->library('session'); + } + + $clubmode = $CI->config->item('special_callsign') ?? false; + $clubstation = $CI->session->userdata('clubstation') ?? 0; + + if ($clubmode && $clubstation == 1) { + // check if the user has the required level + if ($CI->session->userdata('cd_p_level') >= $required_level) { + if ($qso_id != 0) { + // check if the QSO belongs to the user + $CI->load->model('logbook_model'); + $qso = $CI->logbook_model->get_qso($qso_id)->row(); + if ($qso->COL_OPERATOR == $CI->session->userdata('operator_callsign') || $CI->session->userdata('cd_p_level') >= 9) { + return true; + } else { + return false; + } + } else { + return true; + } + } else { + return false; + } + } else { + // return always true if the special callsign mode is disabled, so there is no change in behaviour + return true; + } + } +} \ No newline at end of file diff --git a/application/libraries/AdifHelper.php b/application/libraries/AdifHelper.php index 964ec7380..392122608 100644 --- a/application/libraries/AdifHelper.php +++ b/application/libraries/AdifHelper.php @@ -2,215 +2,223 @@ class AdifHelper { - public function getAdifLine($qso) { - $normalFields = array( - 'ADDRESS', - 'AGE', - 'A_INDEX', - 'ANT_AZ', - 'ANT_EL', - 'ANT_PATH', - 'ARRL_SECT', - 'AWARD_GRANTED', - 'AWARD_SUBMITTED', - 'BAND', - 'BAND_RX', - 'BIOGRAPHY', - 'CALL', - 'CHECK', - 'CLASS', - 'CLUBLOG_QSO_UPLOAD_STATUS', - 'CNTY', - 'COMMENT', - 'CONT', - 'CONTACTED_OP', - 'CONTEST_ID', - 'COUNTRY', - 'CQZ', - 'CREDIT_GRANTED', - 'CREDIT_SUBMITTED', - 'DARC_DOK', - 'DISTANCE', - 'DXCC', - 'EMAIL', - 'EQ_CALL', - 'EQSL_QSL_RCVD', - 'EQSL_QSL_SENT', - 'EQSL_STATUS', - 'FISTS', - 'FISTS_CC', - 'FORCE_INIT', - 'GRIDSQUARE', - 'HEADING', - 'IOTA', - 'ITUZ', - 'K_INDEX', - 'LAT', - 'LON', - 'LOTW_QSL_RCVD', - 'LOTW_QSL_SENT', - 'LOTW_STATUS', - 'MAX_BURSTS', - 'MODE', - 'MS_SHOWER', - 'NAME', - 'NOTES', - 'NR_BURSTS', - 'NR_PINGS', - 'OPERATOR', - 'OWNER_CALLSIGN', - 'PFX', - 'PRECEDENCE', - 'PROP_MODE', - 'PUBLIC_KEY', - 'HRDLOG_QSO_UPLOAD_STATUS', - 'QRZCOM_QSO_UPLOAD_STATUS', - 'QSLMSG', - 'QSL_RCVD', - 'QSL_RCVD_VIA', - 'QSL_SENT', - 'QSL_SENT_VIA', - 'QSL_VIA', - 'QSO_COMPLETE', - 'QSO_RANDOM', - 'QTH', - 'REGION', - 'RIG', - 'RST_RCVD', - 'RST_SENT', - 'RX_PWR', - 'SAT_MODE', - 'SAT_NAME', - 'SFI', - 'SILENT_KEY', - 'SKCC', - 'SOTA_REF', - 'WWFF_REF', - 'POTA_REF', - 'SRX', - 'SRX_STRING', - 'STATE', - 'STX', - 'STX_STRING', - 'SUBMODE', - 'SWL', - 'TEN_TEN', - 'TX_PWR', - 'UKSMG', - 'USACA_COUNTIES', - 'VUCC_GRIDS', - 'WEB', - ); + public function getAdifLine($qso) { + $normalFields = array( + 'ADDRESS', + 'AGE', + 'A_INDEX', + 'ANT_AZ', + 'ANT_EL', + 'ANT_PATH', + 'ARRL_SECT', + 'AWARD_GRANTED', + 'AWARD_SUBMITTED', + 'BAND', + 'BAND_RX', + 'BIOGRAPHY', + 'CALL', + 'CHECK', + 'CLASS', + 'CLUBLOG_QSO_UPLOAD_STATUS', + 'CNTY', + 'COMMENT', + 'CONT', + 'CONTACTED_OP', + 'CONTEST_ID', + 'COUNTRY', + 'CQZ', + 'CREDIT_GRANTED', + 'CREDIT_SUBMITTED', + 'DARC_DOK', + 'DISTANCE', + 'DXCC', + 'EMAIL', + 'EQ_CALL', + 'EQSL_QSL_RCVD', + 'EQSL_QSL_SENT', + 'EQSL_STATUS', + 'FISTS', + 'FISTS_CC', + 'FORCE_INIT', + 'GRIDSQUARE', + 'HEADING', + 'IOTA', + 'ITUZ', + 'K_INDEX', + 'LAT', + 'LON', + 'LOTW_QSL_RCVD', + 'LOTW_QSL_SENT', + 'LOTW_STATUS', + 'MAX_BURSTS', + 'MODE', + 'MS_SHOWER', + 'NAME', + 'NOTES', + 'NR_BURSTS', + 'NR_PINGS', + 'OPERATOR', + 'OWNER_CALLSIGN', + 'PFX', + 'PRECEDENCE', + 'PROP_MODE', + 'PUBLIC_KEY', + 'HRDLOG_QSO_UPLOAD_STATUS', + 'QRZCOM_QSO_UPLOAD_STATUS', + 'QSLMSG', + 'QSL_RCVD', + 'QSL_RCVD_VIA', + 'QSL_SENT', + 'QSL_SENT_VIA', + 'QSL_VIA', + 'QSO_COMPLETE', + 'QSO_RANDOM', + 'QTH', + 'REGION', + 'RIG', + 'RST_RCVD', + 'RST_SENT', + 'RX_PWR', + 'SAT_MODE', + 'SAT_NAME', + 'SFI', + 'SILENT_KEY', + 'SKCC', + 'SOTA_REF', + 'WWFF_REF', + 'POTA_REF', + 'SRX', + 'SRX_STRING', + 'STATE', + 'STX', + 'STX_STRING', + 'SUBMODE', + 'SWL', + 'TEN_TEN', + 'TX_PWR', + 'UKSMG', + 'USACA_COUNTIES', + 'VUCC_GRIDS', + 'WEB', + 'CNTY_ALT', + 'MY_CNTY_ALT', + 'MY_DARC_DOK', + 'MORSE_KEY_INFO', + 'MORSE_KEY_TYPE', + 'QSLMSG_RCVD', + ); - $dateFields = array( - 'EQSL_QSLRDATE', - 'EQSL_QSLSDATE', - 'LOTW_QSLRDATE', - 'LOTW_QSLSDATE', - 'QSLRDATE', - 'QSLSDATE', - 'CLUBLOG_QSO_UPLOAD_DATE', - 'HRDLOG_QSO_UPLOAD_DATE', - 'QRZCOM_QSO_UPLOAD_DATE', - ); + $dateFields = array( + 'EQSL_QSLRDATE', + 'EQSL_QSLSDATE', + 'LOTW_QSLRDATE', + 'LOTW_QSLSDATE', + 'QSLRDATE', + 'QSLSDATE', + 'CLUBLOG_QSO_UPLOAD_DATE', + 'HRDLOG_QSO_UPLOAD_DATE', + 'QRZCOM_QSO_UPLOAD_DATE', + 'DCL_QSLRDATE', + 'DCL_QSLSDATE', + ); - /** - Missing: - USER_DEFINED_0 - USER_DEFINED_1 - USER_DEFINED_2 - USER_DEFINED_3 - USER_DEFINED_4 - USER_DEFINED_5 - USER_DEFINED_6 - USER_DEFINED_7 - USER_DEFINED_8 - USER_DEFINED_9 - */ + /** + Missing: + USER_DEFINED_0 + USER_DEFINED_1 + USER_DEFINED_2 + USER_DEFINED_3 + USER_DEFINED_4 + USER_DEFINED_5 + USER_DEFINED_6 + USER_DEFINED_7 + USER_DEFINED_8 + USER_DEFINED_9 + */ - // Build ADIF fields + // Build ADIF fields - $line = ""; - foreach ($normalFields as $field) { - $line .= $this->getAdifFieldLine($field, $qso->{'COL_' . $field}); - } + $line = ""; + foreach ($normalFields as $field) { + $line .= $this->getAdifFieldLine($field, $qso->{'COL_' . $field}); + } - foreach ($dateFields as $field) { - if ($qso->{'COL_' . $field}) { - $date = strtotime($qso->{'COL_' . $field}); - $date = date('Ymd', $date); - $line .= $this->getAdifFieldLine($field, $date); - } - } + foreach ($dateFields as $field) { + if ($qso->{'COL_' . $field}) { + $date = strtotime($qso->{'COL_' . $field}); + $date = date('Ymd', $date); + $line .= $this->getAdifFieldLine($field, $date); + } + } - if ($qso->COL_FREQ != 0) { - $freq_in_mhz = $qso->COL_FREQ / 1000000; - $line .= $this->getAdifFieldLine("FREQ", $freq_in_mhz); - } + if ($qso->COL_FREQ != 0) { + $freq_in_mhz = $qso->COL_FREQ / 1000000; + $line .= $this->getAdifFieldLine("FREQ", $freq_in_mhz); + } - if ($qso->COL_FREQ_RX != 0) { - $freq_rx_in_mhz = $qso->COL_FREQ_RX / 1000000; - $line .= $this->getAdifFieldLine("FREQ_RX", $freq_rx_in_mhz); - } + if ($qso->COL_FREQ_RX != 0) { + $freq_rx_in_mhz = $qso->COL_FREQ_RX / 1000000; + $line .= $this->getAdifFieldLine("FREQ_RX", $freq_rx_in_mhz); + } - if (isset($qso->COL_TIME_ON) && (date('YmdHis',strtotime($qso->COL_TIME_ON)) != '-00011130000000')) { - $date_on = strtotime($qso->COL_TIME_ON); - $date_on = date('Ymd', $date_on); - $line .= $this->getAdifFieldLine("QSO_DATE", $date_on); + if (isset($qso->COL_TIME_ON) && (date('YmdHis',strtotime($qso->COL_TIME_ON)) != '-00011130000000')) { + $date_on = strtotime($qso->COL_TIME_ON); + $date_on = date('Ymd', $date_on); + $line .= $this->getAdifFieldLine("QSO_DATE", $date_on); - $time_on = strtotime($qso->COL_TIME_ON); - $time_on = date('His', $time_on); - $line .= $this->getAdifFieldLine("TIME_ON", $time_on); - } else { - $line .= $this->getAdifFieldLine("QSO_DATE", '19700101'); - $line .= $this->getAdifFieldLine("TIME_ON", '000000'); - } + $time_on = strtotime($qso->COL_TIME_ON); + $time_on = date('His', $time_on); + $line .= $this->getAdifFieldLine("TIME_ON", $time_on); + } else { + $line .= $this->getAdifFieldLine("QSO_DATE", '19700101'); + $line .= $this->getAdifFieldLine("TIME_ON", '000000'); + } - if (isset($qso->COL_TIME_OFF) && (date('YmdHis',strtotime($qso->COL_TIME_OFF)) != '-00011130000000')) { - $date_off = strtotime($qso->COL_TIME_OFF); - $date_off = date('Ymd', $date_off); - $line .= $this->getAdifFieldLine("QSO_DATE_OFF", $date_off); + if (isset($qso->COL_TIME_OFF) && (date('YmdHis',strtotime($qso->COL_TIME_OFF)) != '-00011130000000')) { + $date_off = strtotime($qso->COL_TIME_OFF); + $date_off = date('Ymd', $date_off); + $line .= $this->getAdifFieldLine("QSO_DATE_OFF", $date_off); - $time_off = strtotime($qso->COL_TIME_OFF); - $time_off = date('His', $time_off); - $line .= $this->getAdifFieldLine("TIME_OFF", $time_off); - } else { - $line .= $this->getAdifFieldLine("QSO_DATE_OFF", '19700101'); - $line .= $this->getAdifFieldLine("TIME_OFF", '000000'); - } + $time_off = strtotime($qso->COL_TIME_OFF); + $time_off = date('His', $time_off); + $line .= $this->getAdifFieldLine("TIME_OFF", $time_off); + } else { + $line .= $this->getAdifFieldLine("QSO_DATE_OFF", '19700101'); + $line .= $this->getAdifFieldLine("TIME_OFF", '000000'); + } - // "MY" information - $line .= $this->getAdifFieldLine("STATION_CALLSIGN", $qso->station_callsign); + // "MY" information + $line .= $this->getAdifFieldLine("STATION_CALLSIGN", $qso->station_callsign); - $line .= $this->getAdifFieldLine("MY_CITY", $qso->station_city); + $line .= $this->getAdifFieldLine("MY_CITY", $qso->station_city); - $line .= $this->getAdifFieldLine("MY_COUNTRY", $qso->station_country); + $line .= $this->getAdifFieldLine("MY_COUNTRY", $qso->station_country); - $line .= $this->getAdifFieldLine("MY_DXCC", $qso->station_dxcc); + $line .= $this->getAdifFieldLine("MY_DXCC", $qso->station_dxcc); - if (strpos($qso->station_gridsquare, ',') !== false ) { - $line .= $this->getAdifFieldLine("MY_VUCC_GRIDS", $qso->station_gridsquare); - } else { - $line .= $this->getAdifFieldLine("MY_GRIDSQUARE", $qso->station_gridsquare); - } + if (strpos($qso->station_gridsquare, ',') !== false ) { + $line .= $this->getAdifFieldLine("MY_VUCC_GRIDS", $qso->station_gridsquare); + } else { + $line .= $this->getAdifFieldLine("MY_GRIDSQUARE", $qso->station_gridsquare); + } - $line .= $this->getAdifFieldLine("MY_IOTA", $qso->station_iota); + $line .= $this->getAdifFieldLine("MY_IOTA", $qso->station_iota); - $line .= $this->getAdifFieldLine("MY_SOTA_REF", $qso->station_sota); + $line .= $this->getAdifFieldLine("MY_SOTA_REF", $qso->station_sota); - $line .= $this->getAdifFieldLine("MY_WWFF_REF", $qso->station_wwff); + $line .= $this->getAdifFieldLine("MY_WWFF_REF", $qso->station_wwff); - $line .= $this->getAdifFieldLine("MY_POTA_REF", $qso->station_pota); + $line .= $this->getAdifFieldLine("MY_POTA_REF", $qso->station_pota); - $line .= $this->getAdifFieldLine("MY_CQ_ZONE", $qso->station_cq); + $line .= $this->getAdifFieldLine("MY_CQ_ZONE", $qso->station_cq); - $line .= $this->getAdifFieldLine("MY_ITU_ZONE", $qso->station_itu); + $line .= $this->getAdifFieldLine("MY_ITU_ZONE", $qso->station_itu); - $line .= $this->getAdifFieldLine("MY_STATE", $qso->state); + $line .= $this->getAdifFieldLine("MY_STATE", $qso->state); - // See: https://adif.org/314/ADIF_314.htm#Sponsor_Defined_Code_Format - if ($qso->station_cnty) { - switch ($qso->station_dxcc) { + // See: https://adif.org/314/ADIF_314.htm#Sponsor_Defined_Code_Format + if ($qso->station_cnty) { + switch ($qso->station_dxcc) { case '6': case '110': case '291': @@ -219,51 +227,37 @@ class AdifHelper { default: $county = trim($qso->station_cnty); break; + } + } else { + $county = ''; } - } else { - $county = ''; - } $line .= $this->getAdifFieldLine("MY_CNTY", $county); - $stationsSig = $qso->station_sig; - // If MY_SIG is WWFF or "" and there's a station_wwff set, use data from station_wwff - if ((empty($stationsSig) || $stationsSig === "WWFF") && !empty($qso->station_wwff)) { - $line .= $this->getAdifFieldLine("MY_SIG", "WWFF"); - $line .= $this->getAdifFieldLine("MY_SIG_INFO", $qso->station_wwff); - } else { - $line .= $this->getAdifFieldLine("MY_SIG", $stationsSig); - $line .= $this->getAdifFieldLine("MY_SIG_INFO", $qso->station_sig_info); - } + $line .= $this->getAdifFieldLine("MY_SIG", $qso->station_sig); + $line .= $this->getAdifFieldLine("MY_SIG_INFO", $qso->station_sig_info); - $sig = $qso->{'COL_SIG'}; - // If SIG is WWFF or "" and there's a WWFF_REF set, use data from COL_WWFF_REF - if ((empty($sig) || $sig === "WWFF") && !empty($qso->{'COL_WWFF_REF'})) { - $line .= $this->getAdifFieldLine("SIG", "WWFF"); - $line .= $this->getAdifFieldLine("SIG_INFO", $qso->{'COL_WWFF_REF'}); - } else { - $line .= $this->getAdifFieldLine("SIG", $sig); - $line .= $this->getAdifFieldLine("SIG_INFO", $qso->{'COL_SIG_INFO'}); - } + $line .= $this->getAdifFieldLine("SIG", $qso->{'COL_SIG'}); + $line .= $this->getAdifFieldLine("SIG_INFO", $qso->{'COL_SIG_INFO'}); - /* - Missing: - MY_ANTENNA - MY_FISTS - MY_IOTA_ISLAND_ID - MY_LAT - MY_LON - MY_NAME - MY_POSTAL_CODE - MY_RIG - MY_STREET - MY_USACA_COUNTIES - */ + /* + Missing: + MY_ANTENNA + MY_FISTS + MY_IOTA_ISLAND_ID + MY_LAT + MY_LON + MY_NAME + MY_POSTAL_CODE + MY_RIG + MY_STREET + MY_USACA_COUNTIES + */ - $line .= "\r\n\r\n"; + $line .= "\r\n\r\n"; - return $line; - } + return $line; + } function getAdifFieldLine($adifcolumn, $dbvalue) { if ($dbvalue !== "" && $dbvalue !== null && $dbvalue !== 0) { diff --git a/application/libraries/Callbook.php b/application/libraries/Callbook.php new file mode 100644 index 000000000..06cd40f91 --- /dev/null +++ b/application/libraries/Callbook.php @@ -0,0 +1,154 @@ +ci = & get_instance(); + } + + // TODO: + // Implement the following: + // - Implement callsign reduced logic + public function getCallbookData($callsign) { + switch ($this->ci->config->item('callbook')) { + case 'qrz': + if ($this->ci->config->item('qrz_username') == null || $this->ci->config->item('qrz_password') == null) { + $callbook['error'] = 'Lookup not configured. Please review configuration.'; + return $callbook; + } + return $this->qrz($this->ci->config->item('qrz_username'), $this->ci->config->item('qrz_password'), $callsign, $this->ci->config->item('use_fullname')); + break; + case 'qrzcq': + if ($this->ci->config->item('qrzcq_username') == null || $this->ci->config->item('qrzcq_password') == null) { + $callbook['error'] = 'Lookup not configured. Please review configuration.'; + return $callbook; + } + return $this->qrzcq($this->ci->config->item('qrzcq_username'), $this->ci->config->item('qrzcq_password'), $callsign); + break; + case 'hamqth': + if ($this->ci->config->item('hamqth_username') == null || $this->ci->config->item('hamqth_password') == null) { + $callbook['error'] = 'Lookup not configured. Please review configuration.'; + return $callbook; + } + return $this->hamqth($this->ci->config->item('hamqth_username'), $this->ci->config->item('hamqth_password'), $callsign); + break; + default: + $callbook['error'] = 'No callbook defined. Please review configuration.'; + return $callbook; + } + } + + function qrz($username, $password, $callsign, $fullname) { + if (!$this->ci->load->is_loaded('qrz')) { + $this->ci->load->library('qrz'); + } + + if (!$this->ci->session->userdata('qrz_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 ($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 (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); + } + + return $callbook; + } + + function qrzcq($username, $password, $callsign) { + if (!$this->ci->load->is_loaded('qrzcq')) { + $this->ci->load->library('qrzcq'); + } + + if (!$this->ci->session->userdata('qrzcq_session_key')) { + $result = $this->ci->qrzcq->session($username, $password); + if ($result[0] == 0) { + $this->ci->session->set_userdata('qrzcq_session_key', $result[1]); + } else { + $data['error'] = __("QRZCQ Error").": ".$result[1]; + return $data; + } + } + + $callbook = $this->ci->qrzcq->search($callsign, $this->ci->session->userdata('qrzcq_session_key')); + + 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 (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); + } + + return $callbook; + } + + function hamqth($username, $password, $callsign) { + // Load the HamQTH library + if (!$this->ci->load->is_loaded('hamqth')) { + $this->ci->load->library('hamqth'); + } + + if (!$this->ci->session->userdata('hamqth_session_key')) { + $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 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 (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); + } + + return $callbook; + } + + function get_plaincall($callsign) { + $split_callsign = explode('/', $callsign); + if (count($split_callsign) == 1) { // case F0ABC --> return cel 0 // + $lookupcall = $split_callsign[0]; + } else if (count($split_callsign) == 3) { // case EA/F0ABC/P --> return cel 1 // + $lookupcall = $split_callsign[1]; + } else { // case F0ABC/P --> return cel 0 OR case EA/FOABC --> retunr 1 (normaly not exist) // + if (in_array(strtoupper($split_callsign[1]), array('P', 'M', 'MM', 'QRP', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'))) { + $lookupcall = $split_callsign[0]; + } else if (strlen($split_callsign[1]) > 3) { // Last Element longer than 3 chars? Take that as call + $lookupcall = $split_callsign[1]; + } else { // Last Element up to 3 Chars? Take first element as Call + $lookupcall = $split_callsign[0]; + } + } + return $lookupcall; + } +} diff --git a/application/libraries/Hamqth.php b/application/libraries/Hamqth.php index c8d6c71ff..91a531b5d 100644 --- a/application/libraries/Hamqth.php +++ b/application/libraries/Hamqth.php @@ -81,6 +81,7 @@ class Hamqth { // we always want to return name and callsign $data['callsign'] = (string)$xml->search->callsign; $data['name'] = (string)$xml->search->nick; + $data['email'] = (string)$xml->search->email; // only return certain data of a callsign which does not contain a pre- or suffix (see https://github.com/wavelog/wavelog/issues/452) if ($reduced == false) { diff --git a/application/libraries/Qra.php b/application/libraries/Qra.php index 6e7cc9bf4..2df9a6521 100644 --- a/application/libraries/Qra.php +++ b/application/libraries/Qra.php @@ -21,12 +21,12 @@ class Qra { } // calculate the bearing between two squares - function bearing($tx, $rx, $unit = 'M') { + function bearing($tx, $rx, $unit = 'M', $ant_path = null) { $my = qra2latlong($tx); $stn = qra2latlong($rx); if ($my !== false && $stn !== false) { - $bearing = bearing($my[0], $my[1], $stn[0], $stn[1], $unit); + $bearing = bearing($my[0], $my[1], $stn[0], $stn[1], $unit, $ant_path); return $bearing; } else { return false; @@ -39,7 +39,7 @@ class Qra { * Inputs are QRA's TX and TX and the unit * */ - function distance($tx, $rx, $unit = 'M') { + function distance($tx, $rx, $unit = 'M', $ant_path = null) { // Calc LatLongs $my = qra2latlong($tx); $stn = qra2latlong($rx); @@ -48,7 +48,7 @@ class Qra { if ($my && $stn) { // Feed in Lat Longs plus the unit type try { - $total_distance = calc_distance($my[0], $my[1], $stn[0], $stn[1], $unit); + $total_distance = calc_distance($my[0], $my[1], $stn[0], $stn[1], $unit, $ant_path); } catch (Exception $e) { $total_distance = 0; } @@ -65,10 +65,10 @@ class Qra { * Function returns just the bearing * Input locator1 and locator2 */ - function get_bearing($tx, $rx) { + function get_bearing($tx, $rx, $ant_path = null) { $my = qra2latlong($tx); $stn = qra2latlong($rx); - return get_bearing($my[0], $my[1], $stn[0], $stn[1]); + return get_bearing($my[0], $my[1], $stn[0], $stn[1], $ant_path); } /* @@ -202,13 +202,17 @@ class Qra { } -function calc_distance($lat1, $lon1, $lat2, $lon2, $unit = 'M') { +function calc_distance($lat1, $lon1, $lat2, $lon2, $unit = 'M', $ant_path = null) { $theta = $lon1 - $lon2; $dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta)); $dist = acos($dist); $dist = rad2deg($dist); $dist = $dist * 60 * 1.1515; + if ($ant_path == "L") { // we only need to calculate the distance for long paths, all other paths are the same + $dist = 24880 - $dist; + } + if ($unit == "K") { $dist *= 1.609344; } else if ($unit == "N") { @@ -220,11 +224,14 @@ function calc_distance($lat1, $lon1, $lat2, $lon2, $unit = 'M') { return round($dist, 1); } -function bearing($lat1, $lon1, $lat2, $lon2, $unit = 'M') { - $dist = calc_distance($lat1, $lon1, $lat2, $lon2, $unit); +function bearing($lat1, $lon1, $lat2, $lon2, $unit = 'M', $ant_path = null) { + $dist = calc_distance($lat1, $lon1, $lat2, $lon2, $unit, $ant_path); $dist = round($dist, 0); $bearing = get_bearing($lat1, $lon1, $lat2, $lon2); + if ($ant_path == 'L') { + $bearing = ($bearing + 180) % 360; + } $dirs = array("N", "E", "S", "W"); diff --git a/application/libraries/Qrz.php b/application/libraries/Qrz.php index cde947c0e..43a05855f 100644 --- a/application/libraries/Qrz.php +++ b/application/libraries/Qrz.php @@ -96,6 +96,8 @@ class Qrz { $data['name'] = (string)$xml->Callsign->fname; } + $data['email'] = (string)$xml->Callsign->email; + // we always give back the name, no matter if reduced data or not $data['name'] = trim($data['name']); diff --git a/application/libraries/Qrzcq.php b/application/libraries/Qrzcq.php new file mode 100644 index 000000000..de1968b73 --- /dev/null +++ b/application/libraries/Qrzcq.php @@ -0,0 +1,151 @@ +optionslib->get_option('version')); + $xml = curl_exec($ch); + curl_close($ch); + + // Create XML object + $xml = simplexml_load_string($xml); + + if (isset($xml->Session->Key)) { + $result = array( 0, (string) $xml->Session->Key); + } else if (isset($xml->Session->Error)) { + $result = array( 1, (string) $xml->Session->Error); + } else { + $result = array( 2, 'Unknown error'); + } + + return $result; + } + + // Set Session Key session. + public function set_session($username, $password) { + + $ci = & get_instance(); + + // URL to the XML Source + $xml_feed_url = 'https://ssl.qrzcq.com/xml/?username='.$username.';password='.urlencode($password).';agent=wavelog'; + + // CURL Functions + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $xml_feed_url); + curl_setopt($ch, CURLOPT_HEADER, false); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10); + curl_setopt($ch, CURLOPT_TIMEOUT, 10); + curl_setopt($ch, CURLOPT_USERAGENT, 'Wavelog/'.$ci->optionslib->get_option('version')); + $xml = curl_exec($ch); + curl_close($ch); + + // Create XML object + $xml = simplexml_load_string($xml); + + $key = (string) $xml->Session->Key; + + $ci->session->set_userdata('qrzcq_session_key', $key); + + return true; + } + + + public function search($callsign, $key, $reduced = false) { + $data = null; + $ci = & get_instance(); + try { + // URL to the XML Source + $xml_feed_url = 'https://ssl.qrzcq.com/xml/?s=' . $key . ';callsign=' . $callsign . ''; + + // CURL Functions + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $xml_feed_url); + curl_setopt($ch, CURLOPT_HEADER, false); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10); + curl_setopt($ch, CURLOPT_TIMEOUT, 10); + curl_setopt($ch, CURLOPT_USERAGENT, 'Wavelog/'.$ci->optionslib->get_option('version')); + $xml = curl_exec($ch); + $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + if ($httpcode != 200) return $data['error'] = 'Problems with qrzcq.com communication'; // Exit function if no 200. If request fails, 0 is returned + + // Create XML object + $xml = simplexml_load_string($xml); + if (!empty($xml->Session->Error)) { + return $data['error'] = $xml->Session->Error; + } + + // Return Required Fields + $data['callsign'] = (string)$xml->Callsign->call; + + $data['name'] = (string)$xml->Callsign->name; + + // we always give back the name, no matter if reduced data or not + $data['name'] = trim($data['name']); + + // Sanitize gridsquare to allow only up to 8 characters + $unclean_gridsquare = (string)$xml->Callsign->locator; // Get the gridsquare from QRZ convert to string + $clean_gridsquare = strlen($unclean_gridsquare) > 8 ? substr($unclean_gridsquare,0,8) : $unclean_gridsquare; // Trim gridsquare to 8 characters max + + if ($reduced == false) { + + $data['gridsquare'] = $clean_gridsquare; + $data['city'] = (string)$xml->Callsign->city; + $data['lat'] = (string)$xml->Callsign->latitude; + $data['long'] = (string)$xml->Callsign->longitude; + $data['dxcc'] = (string)$xml->Callsign->dxcc; + $data['state'] = (string)$xml->Callsign->state; + $data['iota'] = (string)$xml->Callsign->iota; + $data['image'] = (string)$xml->Callsign->qslpic; + $data['ituz'] = (string)$xml->Callsign->itu; + $data['cqz'] = (string)$xml->Callsign->cq; + $data['continent'] = (string)$xml->Callsign->continent; + + if ($xml->Callsign->country == "United States") { + $data['us_county'] = (string)$xml->Callsign->county; + } else { + $data['us_county'] = null; + $data['county'] = (string)$xml->Callsign->county; + } + + } else { + + $data['gridsquare'] = ''; + $data['city'] = ''; + $data['lat'] = ''; + $data['long'] = ''; + $data['dxcc'] = ''; + $data['state'] = ''; + $data['iota'] = ''; + $data['image'] = (string)$xml->Callsign->qslpic; + $data['county'] = ''; + $data['us_county'] = ''; + $data['ituz'] = ''; + $data['cqz'] = ''; + + } + } finally { + + return $data; + } + } +} diff --git a/application/libraries/Reg1testformat.php b/application/libraries/Reg1testformat.php index 9e355fb93..3e41c4cdb 100644 --- a/application/libraries/Reg1testformat.php +++ b/application/libraries/Reg1testformat.php @@ -105,7 +105,7 @@ class Reg1testformat { if (!empty($row->COL_GRIDSQUARE)) { if(!array_key_exists($row->COL_GRIDSQUARE, $locators)){ $newlocator = true; - $distance = intval($CI->qra->distance($mylocator, $row->COL_GRIDSQUARE, "K")); + $distance = intval($CI->qra->distance($mylocator, $row->COL_GRIDSQUARE, "K", $row->COL_ANT_PATH)); $locators[$row->COL_GRIDSQUARE] = $distance; }else{ $newlocator = false; diff --git a/application/locale/bg_BG/LC_MESSAGES/messages.po b/application/locale/bg_BG/LC_MESSAGES/messages.po index fffd0da4b..f26a7d2e6 100644 --- a/application/locale/bg_BG/LC_MESSAGES/messages.po +++ b/application/locale/bg_BG/LC_MESSAGES/messages.po @@ -1,12 +1,12 @@ # WAVELOG PO FILE -# Copyright (c) 2024 Wavelog by DF2ET, DJ7NT, HB9HIL and LA8AJA. +# Copyright (c) 2025 Wavelog by DF2ET, DJ7NT, HB9HIL and LA8AJA. # This file is distributed under the MIT licence. # # Plamen Panteleev , 2024. msgid "" msgstr "" "Report-Msgid-Bugs-To: translations@wavelog.org\n" -"POT-Creation-Date: 2024-11-17 16:50+0000\n" +"POT-Creation-Date: 2025-01-02 10:12+0000\n" "PO-Revision-Date: 2024-11-01 08:53+0000\n" "Last-Translator: Plamen Panteleev \n" "Language-Team: Bulgarian

dxcc.'","'. $band . '","'. $postdata['sat'] . '","' . $postdata['orbit'] . '","'. $postdata['mode'] . '","WAE", "")\'>W
'; + } + + $workedDXCC = $this->getDxccBandWorked($this->location_list, $band, $postdata, true); + foreach ($workedDXCC as $wdxcc) { + $dxccMatrix[$wdxcc->col_region][$band] = '
col_region.'","'. $band . '","'. $postdata['sat'] . '","' . $postdata['orbit'] . '","'. $postdata['mode'] . '","WAE", "")\'>W
'; + $waeCount[$wdxcc->col_region]['count']++; + } + } + + // If confirmed is checked, we add confirmed entities to the array + if ($postdata['confirmed'] != NULL) { + $confirmedDXCC = $this->getDxccBandConfirmed($this->location_list, $band, $postdata); + foreach ($confirmedDXCC as $cdxcc) { + $dxccMatrix[$cdxcc->dxcc][$band] = '
dxcc.'","'. $band . '","'. $postdata['sat'] . '","'. $postdata['orbit'] . '","' . $postdata['mode'] . '","WAE","'.$qsl.'")\'>C
'; + } + $confirmedDXCC = $this->getDxccBandConfirmed($this->location_list, $band, $postdata, true); + foreach ($confirmedDXCC as $cdxcc) { + $dxccMatrix[$cdxcc->col_region][$band] = '
col_region.'","'. $band . '","'. $postdata['sat'] . '","'. $postdata['orbit'] . '","' . $postdata['mode'] . '","WAE","'.$qsl.'")\'>C
'; + $waeCount[$cdxcc->col_region]['count']++; + } + } + } + + // We want to remove the worked dxcc's in the list, since we do not want to display them + if ($postdata['worked'] == NULL) { + $workedDxcc = $this->getDxccWorked($this->location_list, $postdata); + foreach ($workedDxcc as $wdxcc) { + if (array_key_exists($wdxcc->dxcc, $dxccMatrix)) { + unset($dxccMatrix[$wdxcc->dxcc]); + } + } + $workedWae = $this->getDxccWorked($this->location_list, $postdata, true); + foreach ($workedWae as $wdxcc) { + if (array_key_exists($wdxcc->col_region, $dxccMatrix)) { + unset($dxccMatrix[$wdxcc->col_region]); + } + } + } + + // We want to remove the confirmed dxcc's in the list, since we do not want to display them + if ($postdata['confirmed'] == NULL) { + $confirmedDxcc = $this->getDxccConfirmed($this->location_list, $postdata); + foreach ($confirmedDxcc as $cdxcc) { + if (array_key_exists($cdxcc->dxcc, $dxccMatrix)) { + unset($dxccMatrix[$cdxcc->dxcc]); + } + } + + $confirmedWae = $this->getDxccConfirmed($$this->location_list, $postdata, true); + foreach ($confirmedWae as $cdxcc) { + if (array_key_exists($cdxcc->col_region, $dxccMatrix)) { + unset($dxccMatrix[$cdxcc->col_region]); + } + } + } + + if ($postdata['notworked'] == NULL) { + if ($waeCount['IV']['count'] == 0) { + unset($dxccMatrix['IV']); + }; + if ($waeCount['SY']['count'] == 0) { + unset($dxccMatrix['SY']); + }; + if ($waeCount['BI']['count'] == 0) { + unset($dxccMatrix['BI']); + }; + if ($waeCount['SI']['count'] == 0) { + unset($dxccMatrix['SI']); + }; + if ($waeCount['ET']['count'] == 0) { + unset($dxccMatrix['ET']); + }; + } + + if (isset($dxccMatrix)) { + // Convert associative array to indexed array for sorting + $dxccIndexed = array_values($dxccMatrix); + + // Sort the indexed array by the 'name' key + usort($dxccIndexed, function ($a, $b) { + return strcmp($a['Dxccprefix'], $b['Dxccprefix']); + }); + + // Optionally reindex the sorted array back to associative format + $dxccSorted = []; + foreach ($dxccIndexed as $item) { + $key = array_search($item, $dxccMatrix); + $dxccSorted[$key] = $item; + } + return $dxccSorted; + } else { + return 0; + } + } + + function getDxccBandConfirmed($location_list, $band, $postdata, $wae = false) { + $bindings = []; + $sql = "select adif as dxcc, name, x.col_region from dxcc_entities + join ( + select col_region, col_dxcc from ".$this->config->item('table_name')." thcv + LEFT JOIN satellite on thcv.COL_SAT_NAME = satellite.name + where station_id in (" . $location_list . ")"; + if ($wae) { + $sql .= ' and col_dxcc in ( '. $this->waecountries . ') and col_region in ('. $this->region.')'; + } else { + $sql .= " and col_dxcc in ( ". $this->eucountries . ") and coalesce(col_region, '') = ''"; + } + + $sql .= $this->genfunctions->addBandToQuery($band,$bindings); + if ($band == 'SAT') { + if ($postdata['sat'] != 'All') { + $sql .= " and col_sat_name = ?"; + $bindings[] = $postdata['sat']; + } + } + + if ($postdata['mode'] != 'All') { + $sql .= " and (col_mode = ? or col_submode = ?)"; + $bindings[] = $postdata['mode']; + $bindings[] = $postdata['mode']; + } + + $sql .= $this->addOrbitToQuery($postdata,$bindings); + + $sql .= $this->genfunctions->addQslToQuery($postdata); + + $sql .= " group by col_dxcc, col_region + ) x on dxcc_entities.adif = x.col_dxcc"; + + // if ($postdata['includedeleted'] == NULL) { + $sql .= " and dxcc_entities.end is null"; + // } + + if ($wae) { + $sql .= ' and dxcc_entities.adif in ( '. $this->waecountries . ')'; + } else { + $sql .= ' and dxcc_entities.adif in (' . $this->eucountries . ')'; + } + + $query = $this->db->query($sql,$bindings); + + return $query->result(); + } + + function getDxccBandWorked($location_list, $band, $postdata, $wae = false) { + $bindings=[]; + $sql = "select adif as dxcc, name, x.col_region from dxcc_entities + join ( + select col_region, col_dxcc from ".$this->config->item('table_name')." thcv + LEFT JOIN satellite on thcv.COL_SAT_NAME = satellite.name + where station_id in (" . $location_list . ")"; + if ($wae) { + $sql .= ' and col_dxcc in ( '. $this->waecountries . ') and col_region in ('. $this->region.')'; + } else { + $sql .= " and col_dxcc in ( ". $this->eucountries . ") and coalesce(col_region, '') = ''"; + } + + $sql .= $this->genfunctions->addBandToQuery($band,$bindings); + if ($band == 'SAT') { + if ($postdata['sat'] != 'All') { + $sql .= " and col_sat_name = ?"; + $bindings[] = $postdata['sat']; + } + } + if ($postdata['mode'] != 'All') { + $sql .= " and (col_mode = ? or col_submode = ?)"; + $bindings[] = $postdata['mode']; + $bindings[] = $postdata['mode']; + } + $sql .= $this->addOrbitToQuery($postdata,$bindings); + + $sql .= " group by col_dxcc, col_region + ) x on dxcc_entities.adif = x.col_dxcc";; + + // if ($postdata['includedeleted'] == NULL) { + $sql .= " and dxcc_entities.end is null"; + // } + + if ($wae) { + $sql .= ' and dxcc_entities.adif in ( '. $this->waecountries . ')'; + } else { + $sql .= ' and dxcc_entities.adif in (' . $this->eucountries . ')'; + } + + $query = $this->db->query($sql,$bindings); + return $query->result(); + } + + function fetchDxcc($postdata, $location_list) { + $bindings = []; + + $sql = "select adif, prefix, name, date(end) Enddate, date(start) Startdate, lat, `long` + from dxcc_entities"; + + if ($postdata['notworked'] == NULL) { + $sql .= " join (select col_dxcc, col_region from " . $this->config->item('table_name') . " thcv + LEFT JOIN satellite on thcv.COL_SAT_NAME = satellite.name + where station_id in (" . $location_list . ")"; + $sql .= " and col_dxcc in ( ". $this->eucountries . ") and coalesce(col_region, '') = ''"; + + if ($postdata['band'] != 'All') { + if ($postdata['band'] == 'SAT') { + $sql .= " and col_prop_mode = ?"; + $bindings[] = $postdata['band']; + if ($postdata['sat'] != 'All') { + $sql .= " and col_sat_name = ?"; + $bindings[] = $postdata['sat']; + } + } else { + $sql .= " and col_prop_mode !='SAT'"; + $sql .= " and col_band = ?"; + $bindings[] = $postdata['band']; + } + } + + if ($postdata['mode'] != 'All') { + $sql .= " and (col_mode = ? or col_submode = ?)"; + $bindings[] = $postdata['mode']; + $bindings[] = $postdata['mode']; + } + + $sql .= $this->addOrbitToQuery($postdata, $bindings); + + $sql .= ' group by col_dxcc, col_region) x on dxcc_entities.adif = x.col_dxcc'; + } + + $sql .= " where 1 = 1"; + + // if ($postdata['includedeleted'] == NULL) { + $sql .= " and end is null"; + // } + + $sql .= ' and dxcc_entities.adif in (' . $this->eucountries . ')'; + + $sql .= ' order by prefix'; + $query = $this->db->query($sql,$bindings); + + return $query->result(); + } + + function getDxccWorked($location_list, $postdata, $wae = false) { + $bindings = []; + + $sql = "SELECT adif as dxcc, ll.col_region FROM dxcc_entities + join ( + select col_dxcc, col_region + from ".$this->config->item('table_name')." thcv + LEFT JOIN satellite on thcv.COL_SAT_NAME = satellite.name + where station_id in (" . $location_list . ")"; + if ($wae) { + $sql .= ' and col_dxcc in ( '. $this->waecountries . ') and col_region in ('. $this->region.')'; + } else { + $sql .= " and col_dxcc in ( ". $this->eucountries . ") and coalesce(col_region, '') = ''"; + } + $sql .= $this->genfunctions->addBandToQuery($postdata['band'],$bindings); + if ($postdata['band'] == 'SAT') { + if ($postdata['sat'] != 'All') { + $sql .= " and col_sat_name = ?"; + $bindings[] = $postdata['sat']; + } + } + + $sql .= $this->addOrbitToQuery($postdata,$bindings); + + if ($postdata['mode'] != 'All') { + $sql .= " and (col_mode = ? or col_submode = ?)"; + $bindings[] = $postdata['mode']; + $bindings[] = $postdata['mode']; + } + + $sql .= " and not exists (select 1 from ".$this->config->item('table_name')." where station_id in (". $location_list .") and col_dxcc = thcv.col_dxcc"; + if ($wae) { + $sql .= ' and col_dxcc in ( '. $this->waecountries . ') and col_region in ('. $this->region.')'; + } else { + $sql .= " and col_dxcc in ( ". $this->eucountries . ") and coalesce(col_region, '') = ''"; + } + + $sql .= $this->genfunctions->addBandToQuery($postdata['band'],$bindings); + + if ($postdata['band'] == 'SAT') { + if ($postdata['sat'] != 'All') { + $sql .= " and col_sat_name = ?"; + $bindings[] = $postdata['sat']; + } + } + + $sql .= $this->addOrbitToQuery($postdata,$bindings); + + if ($postdata['mode'] != 'All') { + $sql .= " and (col_mode = ? or col_submode = ?)"; + $bindings[] = $postdata['mode']; + $bindings[] = $postdata['mode']; + } + + $sql .= $this->genfunctions->addQslToQuery($postdata); + + $sql .= ')'; + $sql .= " group by col_dxcc, col_region + ) ll on dxcc_entities.adif = ll.col_dxcc + where 1=1"; + + // if ($postdata['includedeleted'] == NULL) { + $sql .= " and dxcc_entities.end is null"; + // } + + if ($wae) { + $sql .= ' and dxcc_entities.adif in ( '. $this->waecountries . ')'; + } else { + $sql .= ' and dxcc_entities.adif in (' . $this->eucountries . ')'; + } + + $query = $this->db->query($sql,$bindings); + return $query->result(); + } + + function getDxccConfirmed($location_list, $postdata, $wae = false) { + $bindings = []; + + $sql = "SELECT adif as dxcc, ll.col_region FROM dxcc_entities + join ( + select col_dxcc, col_region + from ".$this->config->item('table_name')." thcv + LEFT JOIN satellite on thcv.COL_SAT_NAME = satellite.name + where station_id in (" . $location_list . ")"; + if ($wae) { + $sql .= ' and col_dxcc in ( '. $this->waecountries . ') and col_region in ('. $this->region.')'; + } else { + $sql .= " and col_dxcc in ( ". $this->eucountries . ") and coalesce(col_region, '') = ''"; + } + + $sql .= $this->genfunctions->addBandToQuery($postdata['band'],$bindings); + if ($postdata['band'] == 'SAT') { + if ($postdata['sat'] != 'All') { + $sql .= " and col_sat_name = ?"; + $bindings[] = $postdata['sat']; + } + } + + if ($postdata['mode'] != 'All') { + $sql .= " and (col_mode = ? or col_submode = ?)"; + $bindings[] = $postdata['mode']; + $bindings[] = $postdata['mode']; + } + + $sql .= $this->addOrbitToQuery($postdata,$bindings); + + $sql .= $this->genfunctions->addQslToQuery($postdata); + + $sql .= " group by col_dxcc, col_region + ) ll on dxcc_entities.adif = ll.col_dxcc + where 1=1"; + + // if ($postdata['includedeleted'] == NULL) { + $sql .= " and dxcc_entities.end is null"; + // } + + if ($wae) { + $sql .= ' and col_dxcc in ( '. $this->waecountries . ') and col_region in ('. $this->region.')'; + } else { + $sql .= " and col_dxcc in ( ". $this->eucountries . ") and coalesce(col_region, '') = ''"; + } + + $query = $this->db->query($sql,$bindings); + + return $query->result(); + } + + /* + * Function gets worked and confirmed summary on each band on the active stationprofile + */ + function get_wae_summary($bands, $postdata) { + if ($this->location_list == '') { + return null; + } + + foreach ($bands as $band) { + $dxccSummary['worked'][$band] = 0; + $dxccSummary['confirmed'][$band] = 0; + } + + $this->load->model('bands'); + + $bandslots = $this->bands->get_worked_bands('dxcc'); + + //WAE + $confirmed = $this->getSummaryConfirmed($postdata, $this->location_list, true); + + foreach ($confirmed as $c) { + if (isset($dxccSummary['confirmed'][$c->col_band])) { + $dxccSummary['confirmed'][$c->col_band] += $c->regioncount; + } + } + + $confirmed = ''; + + // EU DXCC + $confirmed = $this->getSummaryConfirmed($postdata, $this->location_list); + + foreach ($confirmed as $c) { + if (isset($dxccSummary['confirmed'][$c->col_band])) { + $dxccSummary['confirmed'][$c->col_band] += $c->count; + } + } + + // EU DXCC + $worked = $this->getSummary($postdata, $this->location_list); + + foreach ($worked as $w) { + if (isset($dxccSummary['worked'][$w->col_band])) { + $dxccSummary['worked'][$w->col_band] += $w->count; + } + } + + $worked = ''; + + //WAE + $worked = $this->getSummary($postdata, $this->location_list, true); + + foreach ($worked as $w) { + if (isset($dxccSummary['worked'][$w->col_band])) { + $dxccSummary['worked'][$w->col_band] += $w->regioncount; + } + } + + if (isset($dxccSummary['worked']['SAT'])) { + $workedSat = $this->getSummaryByBand('SAT', $postdata, $this->location_list, $bandslots, true); + $dxccSummary['worked']['SAT'] += $workedSat[0]->regioncount; + $workedSat = $this->getSummaryByBand('SAT', $postdata, $this->location_list, $bandslots); + $dxccSummary['worked']['SAT'] += $workedSat[0]->count; + } + + if (isset($dxccSummary['confirmed']['SAT'])) { + $confirmedSat = $this->getSummaryByBandConfirmed('SAT', $postdata, $this->location_list, $bandslots, true); + $dxccSummary['confirmed']['SAT'] += $confirmedSat[0]->regioncount; + + $confirmedSat = $this->getSummaryByBandConfirmed('SAT', $postdata, $this->location_list, $bandslots); + $dxccSummary['confirmed']['SAT'] += $confirmedSat[0]->count; + } + + $dxccSummary['worked']['Total'] = 0; + $dxccSummary['confirmed']['Total'] = 0; + + $workedTotal = $this->getSummaryByBand($postdata['band'], $postdata, $this->location_list, $bandslots); + $confirmedTotal = $this->getSummaryByBandConfirmed($postdata['band'], $postdata, $this->location_list, $bandslots); + + $dxccSummary['worked']['Total'] += $workedTotal[0]->count; + $dxccSummary['confirmed']['Total'] += $confirmedTotal[0]->count; + + $workedTotal = $this->getSummaryByBand($postdata['band'], $postdata, $this->location_list, $bandslots, true); + $confirmedTotal = $this->getSummaryByBandConfirmed($postdata['band'], $postdata, $this->location_list, $bandslots, true); + + $dxccSummary['worked']['Total'] += $workedTotal[0]->regioncount; + $dxccSummary['confirmed']['Total'] += $confirmedTotal[0]->regioncount; + + return $dxccSummary; + } + + function getSummary($postdata, $location_list, $wae = false) { + $bindings = []; + + $sql = "SELECT count(distinct thcv.col_dxcc) as count, count(distinct thcv.col_region) regioncount, col_band FROM " . $this->config->item('table_name') . " thcv"; + $sql .= " LEFT JOIN satellite on thcv.COL_SAT_NAME = satellite.name"; + $sql .= " join dxcc_entities d on thcv.col_dxcc = d.adif"; + + $sql .= " where station_id in (" . $location_list . ")"; + if ($wae) { + $sql .= ' and col_dxcc in ( '. $this->waecountries . ') and col_region in ('. $this->region.')'; + } else { + $sql .= " and col_dxcc in ( ". $this->eucountries . ") and coalesce(col_region, '') = ''"; + } + + if ($postdata['mode'] != 'All') { + $sql .= " and (col_mode = ? or col_submode = ?)"; + $bindings[] = $postdata['mode']; + $bindings[] = $postdata['mode']; + } + + $sql .= " and thcv.col_prop_mode !='SAT'"; + + // if ($postdata['includedeleted'] == NULL) { + $sql .= " and d.end is null"; + // } + + if ($wae) { + $sql .= ' and d.adif in ( '. $this->waecountries . ')'; + } else { + $sql .= ' and d.adif in (' . $this->eucountries . ')'; + } + + $sql .= $this->addOrbitToQuery($postdata,$bindings); + + $sql .= ' group by col_band'; + + $query = $this->db->query($sql,$bindings); + + return $query->result(); + } + + function getSummaryByBand($band, $postdata, $location_list, $bandslots, $wae = false) { + $bindings = []; + $sql = "SELECT count(distinct thcv.col_dxcc) as count, count(distinct thcv.col_region) regioncount FROM " . $this->config->item('table_name') . " thcv"; + $sql .= " LEFT JOIN satellite on thcv.COL_SAT_NAME = satellite.name"; + $sql .= " join dxcc_entities d on thcv.col_dxcc = d.adif"; + + $sql .= " where station_id in (" . $location_list . ")"; + if ($wae) { + $sql .= ' and col_dxcc in ( '. $this->waecountries . ') and col_region in ('. $this->region.')'; + } else { + $sql .= " and col_dxcc in ( ". $this->eucountries . ") and coalesce(col_region, '') = ''"; + } + + if ($band == 'SAT') { + $sql .= " and thcv.col_prop_mode ='" . $band . "'"; + if ($band != 'All' && $postdata['sat'] != 'All') { + $sql .= " and col_sat_name = ?"; + $bindings[] = $postdata['sat']; + } + } else if ($band == 'All') { + $bandslots_list = "'".implode("','",$bandslots)."'"; + + $sql .= " and thcv.col_band in (" . $bandslots_list . ")" . + " and thcv.col_prop_mode !='SAT'"; + } else { + $sql .= " and thcv.col_prop_mode !='SAT'"; + $sql .= " and thcv.col_band = ?"; + $bindings[] = $band; + } + + if ($postdata['mode'] != 'All') { + $sql .= " and (col_mode = ? or col_submode = ?)"; + $bindings[] = $postdata['mode']; + $bindings[] = $postdata['mode']; + } + + // if ($postdata['includedeleted'] == NULL) { + $sql .= " and d.end is null"; + // } + + if ($wae) { + $sql .= ' and d.adif in ( '. $this->waecountries . ')'; + } else { + $sql .= ' and d.adif in (' . $this->eucountries . ')'; + } + + $sql .= $this->addOrbitToQuery($postdata,$bindings); + + $query = $this->db->query($sql,$bindings); + + return $query->result(); + } + + // Adds orbit type to query + function addOrbitToQuery($postdata,&$binding) { + $sql = ''; + if ($postdata['orbit'] != 'All') { + $sql .= ' AND satellite.orbit = ?'; + $binding[] = $postdata['orbit']; + } + + return $sql; + } + + function getSummaryConfirmed($postdata, $location_list, $wae = false) { + $bindings = []; + + $sql = "SELECT count(distinct thcv.col_dxcc) as count, count(distinct thcv.col_region) regioncount, thcv.col_band FROM " . $this->config->item('table_name') . " thcv"; + $sql .= " LEFT JOIN satellite on thcv.COL_SAT_NAME = satellite.name"; + $sql .= " join dxcc_entities d on thcv.col_dxcc = d.adif"; + + $sql .= " where station_id in (" . $location_list . ")"; + if ($wae) { + $sql .= ' and col_dxcc in ( '. $this->waecountries . ') and col_region in ('. $this->region.')'; + } else { + $sql .= " and col_dxcc in ( ". $this->eucountries . ") and coalesce(col_region, '') = ''"; + } + + if ($postdata['mode'] != 'All') { + $sql .= " and (col_mode = ? or col_submode = ?)"; + $bindings[] = $postdata['mode']; + $bindings[] = $postdata['mode']; + } + + $sql .= " and thcv.col_prop_mode !='SAT'"; + + $sql .= $this->genfunctions->addQslToQuery($postdata); + + $sql .= $this->addOrbitToQuery($postdata,$bindings); + + // if ($postdata['includedeleted'] == NULL) { + $sql .= " and d.end is null"; + // } + + if ($wae) { + $sql .= ' and d.adif in ( '. $this->waecountries . ')'; + } else { + $sql .= ' and d.adif in (' . $this->eucountries . ')'; + } + + $sql .= ' group by thcv.col_band'; + + $query = $this->db->query($sql,$bindings); + + return $query->result(); + } + + function getSummaryByBandConfirmed($band, $postdata, $location_list, $bandslots, $wae = false) { + $bindings=[]; + $sql = "SELECT count(distinct thcv.col_dxcc) as count, count(distinct thcv.col_region) regioncount FROM " . $this->config->item('table_name') . " thcv"; + $sql .= " LEFT JOIN satellite on thcv.COL_SAT_NAME = satellite.name"; + $sql .= " join dxcc_entities d on thcv.col_dxcc = d.adif"; + + $sql .= " where station_id in (" . $location_list . ")"; + if ($wae) { + $sql .= ' and col_dxcc in ( '. $this->waecountries . ') and col_region in ('. $this->region.')'; + } else { + $sql .= " and col_dxcc in ( ". $this->eucountries . ") and coalesce(col_region, '') = ''"; + } + + if ($band == 'SAT') { + $sql .= " and thcv.col_prop_mode = ?"; + $bindings[] = $band; + if ($postdata['sat'] != 'All') { + $sql .= " and col_sat_name = ?"; + $bindings[] = $postdata['sat']; + } + } else if ($band == 'All') { + $bandslots_list = "'".implode("','",$bandslots)."'"; + + $sql .= " and thcv.col_band in (" . $bandslots_list . ")" . + " and thcv.col_prop_mode !='SAT'"; + } else { + $sql .= " and thcv.col_prop_mode !='SAT'"; + $sql .= " and thcv.col_band = ?"; + $bindings[] = $band; + } + + if ($postdata['mode'] != 'All') { + $sql .= " and (col_mode = ? or col_submode = ?)"; + $bindings[] = $postdata['mode']; + $bindings[] = $postdata['mode']; + } + + $sql .= $this->genfunctions->addQslToQuery($postdata); + + $sql .= $this->addOrbitToQuery($postdata,$bindings); + + // if ($postdata['includedeleted'] == NULL) { + $sql .= " and d.end is null"; + // } + + if ($wae) { + $sql .= ' and d.adif in ( '. $this->waecountries . ')'; + } else { + $sql .= ' and d.adif in (' . $this->eucountries . ')'; + } + + $query = $this->db->query($sql,$bindings); + + return $query->result(); + } +} +?> diff --git a/application/views/activated_gridmap/index.php b/application/views/activated_gridmap/index.php index 62e031180..7323f6e35 100644 --- a/application/views/activated_gridmap/index.php +++ b/application/views/activated_gridmap/index.php @@ -127,5 +127,9 @@ var visitor = false; echo 'var gridsquares_gridsquares_confirmed = "' . $gridsquares_gridsquares_confirmed . '";'; echo 'var gridsquares_gridsquares_not_confirmed = "' . $gridsquares_gridsquares_not_confirmed . '";'; echo 'var gridsquares_gridsquares_total_worked = "' . $gridsquares_gridsquares_total_activated . '";'; + echo "var gridsquares_fields = \"" . $gridsquares_fields . "\";\n"; + echo "var gridsquares_fields_confirmed = \"" . $gridsquares_fields_confirmed . "\";\n"; + echo "var gridsquares_fields_not_confirmed = \"" . $gridsquares_fields_not_confirmed . "\";\n"; + echo "var gridsquares_fields_total_worked = \"" . $gridsquares_fields_total_worked . "\";\n"; ?> diff --git a/application/views/adif/data/clublog.php b/application/views/adif/data/clublog.php index 46783add1..83076d77c 100644 --- a/application/views/adif/data/clublog.php +++ b/application/views/adif/data/clublog.php @@ -1,5 +1,5 @@ Wavelog ADIF export -3.1.4 +3.1.5 config->item('app_name')); ?>>config->item('app_name')."\r\n"; ?> optionslib->get_option('version')); ?>>optionslib->get_option('version')."\r\n"; ?> diff --git a/application/views/adif/data/exportall.php b/application/views/adif/data/exportall.php index b85d055f1..76a4d6b0f 100644 --- a/application/views/adif/data/exportall.php +++ b/application/views/adif/data/exportall.php @@ -6,12 +6,12 @@ header('Content-Disposition: attachment; filename="'.$this->session->userdata('user_callsign').'-'.date('Ymd-Hi').'.adi"'); } ?> -Wavelog ADIF export -3.1.4 +Wavelog ADIF export +3.1.5 config->item('app_name')); ?>>config->item('app_name')."\r\n"; ?> optionslib->get_option('version')); ?>>optionslib->get_option('version')."\r\n"; ?> - - + + load->is_loaded('AdifHelper')) { diff --git a/application/views/adif/data/exportsat.php b/application/views/adif/data/exportsat.php index acd7cd05f..b394fe6d4 100644 --- a/application/views/adif/data/exportsat.php +++ b/application/views/adif/data/exportsat.php @@ -3,7 +3,7 @@ header('Content-Disposition: attachment; filename="'.$this->session->userdata('user_callsign').'-'.date('Ymd-Hi').'.adi"') ?> Wavelog ADIF export -3.1.4 +3.1.5 config->item('app_name')); ?>>config->item('app_name')."\r\n"; ?> optionslib->get_option('version')); ?>>optionslib->get_option('version')."\r\n"; ?> diff --git a/application/views/adif/import.php b/application/views/adif/import.php index dedd9b2fe..138a5a957 100644 --- a/application/views/adif/import.php +++ b/application/views/adif/import.php @@ -75,6 +75,22 @@ } ?>>station_callsign; ?> (station_profile_name; ?>) + config->item('special_callsign') && $club_operators != false) { + $show_operator_question = false; ?> +
+ +
+ + +
+ + +
@@ -155,6 +181,7 @@
+
@@ -163,6 +190,7 @@
+
diff --git a/application/views/api/help.php b/application/views/api/help.php deleted file mode 100644 index f303562c2..000000000 --- a/application/views/api/help.php +++ /dev/null @@ -1,83 +0,0 @@ -
- -
-session->flashdata('notice')) { ?> - - - -

- -
-
- -
-
-

-

-

: " onClick='copyApiUrl()'>

-

- - num_rows() > 0) { ?> - - - - - - - - - - - - - - result() as $row) { ?> - - - - - - - - - - - - -
key; ?> " onclick='copyApiKey("key; ?>")'>description; ?>last_used; ?> - rights == "rw") { - echo "" . __("Read & Write") . ""; - } elseif($row->rights == "r") { - echo "" . __("Read-Only") . ""; - } else { - echo "" . __("Unknown") . ""; - } - - ?> - - status); ?> - - - - - -
- - -

- - -

- - -

- -
-
- -
- diff --git a/application/views/api/index.php b/application/views/api/index.php new file mode 100644 index 000000000..c29a6e2c1 --- /dev/null +++ b/application/views/api/index.php @@ -0,0 +1,97 @@ +
+
+ load->view('layout/messages'); ?> +

+ +
+
+ +
+
+

+

+

: " onClick='copyApiUrl()'>

+

+ +

+ + + num_rows() > 0) { ?> + + + + + + + + + + + + + + + + + result() as $row) { ?> + + user_callsign !== $this->session->userdata('cd_src_call')) { + $api_key = substr($row->key, 0, 2) . str_repeat('*', strlen($row->key) - 6) . substr($row->key, -4); + $masked = true; + } else { + $api_key = $row->key; + $masked = false; + } ?> + + + + + + + + + + + + + + +
+ + + " onclick='copyApiKey("")'> + + description; ?>last_used; ?>user_callsign; ?> + rights == "rw") { + echo "" . __("Read & Write") . ""; + } elseif ($row->rights == "r") { + echo "" . __("Read-Only") . ""; + } else { + echo "" . __("Unknown") . ""; + } ?> + status); ?> + + + + + + description ?? '').'"'); + ?> + + +
+ + +

+ + +

+ + +

+ +
+
+ +
\ No newline at end of file diff --git a/application/views/awards/wae/index.php b/application/views/awards/wae/index.php new file mode 100644 index 000000000..3b1cc8116 --- /dev/null +++ b/application/views/awards/wae/index.php @@ -0,0 +1,218 @@ +
+ +
+
+ +

+ +
+ + +
+
+ +
+
+
+ input->post('includedeleted')) echo ' checked="checked"'; ?> > + +
+
+
*/ +?> + +
+
+
+
+ input->post('worked') || $this->input->method() !== 'post') echo ' checked="checked"'; ?> > + +
+
+ input->post('confirmed') || $this->input->method() !== 'post') echo ' checked="checked"'; ?> > + +
+
+ input->post('notworked') || $this->input->method() !== 'post') echo ' checked="checked"'; ?> > + +
+
+
+ +
+
+
+
+ input->post('qsl') || $this->input->method() !== 'post') echo ' checked="checked"'; ?> > + +
+
+ input->post('lotw') || $this->input->method() !== 'post') echo ' checked="checked"'; ?> > + +
+
+ input->post('eqsl')) echo ' checked="checked"'; ?> > + +
+
+ input->post('qrz')) echo ' checked="checked"'; ?> > + +
+
+ input->post('clublog')) echo ' checked="checked"'; ?> > + +
+
+
+ +
+ +
+ +
+
+
input->post('band') != 'SAT' && $this->input->post('band') != 'All') echo "style=\"display: none\""; ?>> + + +
+ +
+ + + +
+
input->post('band') != 'SAT' && $this->input->post('band') != 'All') echo "style=\"display: none\""; ?>> + +
+ +
+
+
+ +
+ +
+
+ +
+ +
+ + +
+
+ + + + + + + + # + ' . __("WAE Name") . ' + ' . __("Prefix") . ''; + foreach($bands as $band) { + echo '' . $band . ''; + } + echo ' + + '; + foreach ($wae_array as $dxcc => $value) { // Fills the table with the data + echo ' + '. $i++ .''; + foreach ($value as $name => $key) { + if (isset($value['Deleted']) && $value['Deleted'] == 1 && $name == "name") { + echo '' . $key . ' '.__("Deleted DXCC").''; + } else if ($name == "Deleted") { + continue; + } else { + echo '' . $key . ''; + } + } + echo ''; + } + echo ' +

' . __("Summary") . '

+ + + + '; + + foreach($bands as $band) { + echo ''; + } + echo ' + + + + + '; + + foreach ($wae_summary['worked'] as $dxcc) { // Fills the table with the data + echo ''; + } + + echo ' + '; + foreach ($wae_summary['confirmed'] as $dxcc) { // Fills the table with the data + echo ''; + } + + echo ' +
' . $band . '' . __("Total") . '
' . __("Total worked") . '' . $dxcc . '
' . __("Total confirmed") . '' . $dxcc . '
+
'; + + } + else { + echo ''; + } + ?> diff --git a/application/views/backup/exportall.php b/application/views/backup/exportall.php index ec7555b2a..0b3184213 100644 --- a/application/views/backup/exportall.php +++ b/application/views/backup/exportall.php @@ -1,5 +1,5 @@ Wavelog ADIF export -3.1.4 +3.1.5 config->item('app_name')); ?>>config->item('app_name')."\n"; ?> optionslib->get_option('version')); ?>>optionslib->get_option('version')."\r\n"; ?> diff --git a/application/views/bandmap/list.php b/application/views/bandmap/list.php index 816eaf01e..5dc0ba75b 100644 --- a/application/views/bandmap/list.php +++ b/application/views/bandmap/list.php @@ -4,6 +4,7 @@ var dxcluster_maxage = optionslib->get_option('dxcluster_maxage') ?? 60; ?>; var custom_date_format = ""; var popup_warning = ""; + var lang_click_to_prepare_logging = "";