wavelog/application/controllers/Api.php

1665 lines
59 KiB
PHP
Raw Permalink Normal View History

<?php
use Wavelog\Dxcc\Dxcc;
require_once APPPATH . '../src/Dxcc/Dxcc.php';
if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class API extends CI_Controller {
2026-06-11 05:57:23 +00:00
public function __construct() {
parent::__construct();
// Web UI endpoints that don't need CORS
$web_ui_methods = ['index', 'help', 'edit', 'generate', 'delete'];
$method = $this->uri->segment(2, 'index');
if (!in_array($method, $web_ui_methods, true)) {
// Preflight
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, GET, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type');
header('Access-Control-Max-Age: 86400');
http_response_code(200);
exit(0);
}
header('Access-Control-Allow-Origin: *');
}
}
2024-11-20 17:33:17 +00:00
function index() {
Clubstations for Wavelog (#1334) * feat[clubstations]: New DB structure * feat[clubstations]: Add clubstationstable in user managment * feat[clubstations]: Show last operator * feat[clubstations]: Better solution for last operator. tnx for the hint @int2001 * feat[clubstations]: New Club Model and Controller * feat[clubstations]: Add "Add User" and "Edit User" functionality * docs[clubstations]: move comment * feat[clubstations]: Add "Delete Member" functionality * feat[clubstations]: some enhancements and javascript * fix[clubstations]: Wrong message class for flashmessages * feat[clubstations]: Added Switch in the Header menu (not functional yet) * feat[clubstations]: clubswitch modal * fix[clubstations]: Load encryption library if not already loaded * fix[clubstations]: Prevent direct login attempts to clubstations and enhance impersonation authorization * fix[clubstations]: Typo * feat[clubstations]: Only show the operator dialog if there is something fishy * fix[user]: little UI bug * feat[impersonate]: Add source uid to session data * fix[impersonate]: logic adjustment * feat[clubstations]: Add manage button in header menu for club officers * fix[clubstations]: typo in permission level check * fix[clubstations]: Full rights for the admin * feat[impersonate]: Custom sessiondata * feat[impersonate]: Implement stop impersonation feature with modal confirmation; "the way back" * fix(modal): Fix bug where modal was hidden when mouse leaved the browser content * docs(config): Adjust config description for special callsigns and clubstations * feat(club): Add club access check helper * typo * fix[impersonation]: Better text * feat(club): Selectize for a efficient user search * feat(clubstations): Restrict clubstations based on users permission level part 1/x * adjustments for dev merge * Adjusted club right for the advanced logbook * feat[user]: Refactoring of the Action Buttons in the user table * fix[club_permissions]: normal button instead small one for club permissions * remove unnecessary line break in modal body * feat[clubstations]: Add Club Mode badge to the header * fix[clubstations]: fix maintenance mode * allow switch back on http * feat(simplefle): display operator input based on club_access * small UI adjustments * small UI adjustments * moved api page to a index.php file and added support for clubstations * removed unused stuff * typo * radios and api keys * missed one binding * fix qso view, even officers do just see their own radios in QSO logging * omit the need for a relogin to see the changes as an admin * Omit the need for relogin after club changes in general. It's a question of UX. It's better to accept a little higher DB load (if clubstations are enabled) then the need of an user to relogin. There is some room for improvement by changing user_model->get_by_id() and adding a join there. This can be done later if we see that the load is too high * 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 * remove debug messages * better UI in header * found a typo * full access in clubstations for admins (if accessed via admin usertable) * adjusted text * adjusted text * adjust text * reduce required chars * bugfix: missing the correct authentication in case the admin was not member of the club. he wasn't able to switch back * reduce debug messages * fixed UI bug related to tooltips * load js in controller * upps.. * some UI adjustments * corrected permissions * if user gets delete we need to remove data in club_permissions and also api keys which were created by this user * Notify members about new memberships or changes in permission level * add spinner to save button * make login/logout process more bulletproof * remove the relogin cookie after the attempt * better strategy * bug where switch back failed if user is no admin * make api keys more secure * mask not owned api keys * removed annoying link * if a user gets removed from a club we also should delete the corresponding api keys and cat radios * adjusted wiki link * Auto creation of logbook and location when new user is created * store and display locator in uppercase * same for callsign * fixed a bug in user/club creation * Revert "Auto creation of logbook and location when new user is created" We found another solution to which will be addressed in a second PR This reverts commit f05f4b7bf0423a88abf0087ade81fe613d217794. * Optimized SQL for stats at userlist * Source query for lastop "out", because mysql<9.0 can't handle Windowed functions * adjust migration * add new columns to users table to get created_at and modified_at * added a partial down function * add operator dropdown for clubstations * fix mig version * Add some backend restrictions in case a user wants to try something funny with the club --------- Co-authored-by: Andreas Kristiansen <6977712+AndreasK79@users.noreply.github.com> Co-authored-by: int2001 <joerg@dj7nt.de>
2025-01-02 10:22:23 +01:00
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');
2026-06-10 22:43:49 +02:00
$this->load->model('api_v2_model');
Clubstations for Wavelog (#1334) * feat[clubstations]: New DB structure * feat[clubstations]: Add clubstationstable in user managment * feat[clubstations]: Show last operator * feat[clubstations]: Better solution for last operator. tnx for the hint @int2001 * feat[clubstations]: New Club Model and Controller * feat[clubstations]: Add "Add User" and "Edit User" functionality * docs[clubstations]: move comment * feat[clubstations]: Add "Delete Member" functionality * feat[clubstations]: some enhancements and javascript * fix[clubstations]: Wrong message class for flashmessages * feat[clubstations]: Added Switch in the Header menu (not functional yet) * feat[clubstations]: clubswitch modal * fix[clubstations]: Load encryption library if not already loaded * fix[clubstations]: Prevent direct login attempts to clubstations and enhance impersonation authorization * fix[clubstations]: Typo * feat[clubstations]: Only show the operator dialog if there is something fishy * fix[user]: little UI bug * feat[impersonate]: Add source uid to session data * fix[impersonate]: logic adjustment * feat[clubstations]: Add manage button in header menu for club officers * fix[clubstations]: typo in permission level check * fix[clubstations]: Full rights for the admin * feat[impersonate]: Custom sessiondata * feat[impersonate]: Implement stop impersonation feature with modal confirmation; "the way back" * fix(modal): Fix bug where modal was hidden when mouse leaved the browser content * docs(config): Adjust config description for special callsigns and clubstations * feat(club): Add club access check helper * typo * fix[impersonation]: Better text * feat(club): Selectize for a efficient user search * feat(clubstations): Restrict clubstations based on users permission level part 1/x * adjustments for dev merge * Adjusted club right for the advanced logbook * feat[user]: Refactoring of the Action Buttons in the user table * fix[club_permissions]: normal button instead small one for club permissions * remove unnecessary line break in modal body * feat[clubstations]: Add Club Mode badge to the header * fix[clubstations]: fix maintenance mode * allow switch back on http * feat(simplefle): display operator input based on club_access * small UI adjustments * small UI adjustments * moved api page to a index.php file and added support for clubstations * removed unused stuff * typo * radios and api keys * missed one binding * fix qso view, even officers do just see their own radios in QSO logging * omit the need for a relogin to see the changes as an admin * Omit the need for relogin after club changes in general. It's a question of UX. It's better to accept a little higher DB load (if clubstations are enabled) then the need of an user to relogin. There is some room for improvement by changing user_model->get_by_id() and adding a join there. This can be done later if we see that the load is too high * 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 * remove debug messages * better UI in header * found a typo * full access in clubstations for admins (if accessed via admin usertable) * adjusted text * adjusted text * adjust text * reduce required chars * bugfix: missing the correct authentication in case the admin was not member of the club. he wasn't able to switch back * reduce debug messages * fixed UI bug related to tooltips * load js in controller * upps.. * some UI adjustments * corrected permissions * if user gets delete we need to remove data in club_permissions and also api keys which were created by this user * Notify members about new memberships or changes in permission level * add spinner to save button * make login/logout process more bulletproof * remove the relogin cookie after the attempt * better strategy * bug where switch back failed if user is no admin * make api keys more secure * mask not owned api keys * removed annoying link * if a user gets removed from a club we also should delete the corresponding api keys and cat radios * adjusted wiki link * Auto creation of logbook and location when new user is created * store and display locator in uppercase * same for callsign * fixed a bug in user/club creation * Revert "Auto creation of logbook and location when new user is created" We found another solution to which will be addressed in a second PR This reverts commit f05f4b7bf0423a88abf0087ade81fe613d217794. * Optimized SQL for stats at userlist * Source query for lastop "out", because mysql<9.0 can't handle Windowed functions * adjust migration * add new columns to users table to get created_at and modified_at * added a partial down function * add operator dropdown for clubstations * fix mig version * Add some backend restrictions in case a user wants to try something funny with the club --------- Co-authored-by: Andreas Kristiansen <6977712+AndreasK79@users.noreply.github.com> Co-authored-by: int2001 <joerg@dj7nt.de>
2025-01-02 10:22:23 +01:00
$this->load->library('form_validation');
$data['api_keys'] = $this->api_model->keys();
2026-06-10 22:43:49 +02:00
$data['api_tokens'] = $this->api_v2_model->get_tokens_for_user();
$data['token_scopes'] = Api_v2_model::grantable_scope_registry();
2026-07-29 11:31:52 +02:00
$data['token_presets'] = Api_v2_model::preset_registry();
2026-06-10 22:43:49 +02:00
// One-time reveal: the plaintext token survives exactly one redirect.
$data['new_api_token'] = $this->session->flashdata('new_api_token');
Clubstations for Wavelog (#1334) * feat[clubstations]: New DB structure * feat[clubstations]: Add clubstationstable in user managment * feat[clubstations]: Show last operator * feat[clubstations]: Better solution for last operator. tnx for the hint @int2001 * feat[clubstations]: New Club Model and Controller * feat[clubstations]: Add "Add User" and "Edit User" functionality * docs[clubstations]: move comment * feat[clubstations]: Add "Delete Member" functionality * feat[clubstations]: some enhancements and javascript * fix[clubstations]: Wrong message class for flashmessages * feat[clubstations]: Added Switch in the Header menu (not functional yet) * feat[clubstations]: clubswitch modal * fix[clubstations]: Load encryption library if not already loaded * fix[clubstations]: Prevent direct login attempts to clubstations and enhance impersonation authorization * fix[clubstations]: Typo * feat[clubstations]: Only show the operator dialog if there is something fishy * fix[user]: little UI bug * feat[impersonate]: Add source uid to session data * fix[impersonate]: logic adjustment * feat[clubstations]: Add manage button in header menu for club officers * fix[clubstations]: typo in permission level check * fix[clubstations]: Full rights for the admin * feat[impersonate]: Custom sessiondata * feat[impersonate]: Implement stop impersonation feature with modal confirmation; "the way back" * fix(modal): Fix bug where modal was hidden when mouse leaved the browser content * docs(config): Adjust config description for special callsigns and clubstations * feat(club): Add club access check helper * typo * fix[impersonation]: Better text * feat(club): Selectize for a efficient user search * feat(clubstations): Restrict clubstations based on users permission level part 1/x * adjustments for dev merge * Adjusted club right for the advanced logbook * feat[user]: Refactoring of the Action Buttons in the user table * fix[club_permissions]: normal button instead small one for club permissions * remove unnecessary line break in modal body * feat[clubstations]: Add Club Mode badge to the header * fix[clubstations]: fix maintenance mode * allow switch back on http * feat(simplefle): display operator input based on club_access * small UI adjustments * small UI adjustments * moved api page to a index.php file and added support for clubstations * removed unused stuff * typo * radios and api keys * missed one binding * fix qso view, even officers do just see their own radios in QSO logging * omit the need for a relogin to see the changes as an admin * Omit the need for relogin after club changes in general. It's a question of UX. It's better to accept a little higher DB load (if clubstations are enabled) then the need of an user to relogin. There is some room for improvement by changing user_model->get_by_id() and adding a join there. This can be done later if we see that the load is too high * 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 * remove debug messages * better UI in header * found a typo * full access in clubstations for admins (if accessed via admin usertable) * adjusted text * adjusted text * adjust text * reduce required chars * bugfix: missing the correct authentication in case the admin was not member of the club. he wasn't able to switch back * reduce debug messages * fixed UI bug related to tooltips * load js in controller * upps.. * some UI adjustments * corrected permissions * if user gets delete we need to remove data in club_permissions and also api keys which were created by this user * Notify members about new memberships or changes in permission level * add spinner to save button * make login/logout process more bulletproof * remove the relogin cookie after the attempt * better strategy * bug where switch back failed if user is no admin * make api keys more secure * mask not owned api keys * removed annoying link * if a user gets removed from a club we also should delete the corresponding api keys and cat radios * adjusted wiki link * Auto creation of logbook and location when new user is created * store and display locator in uppercase * same for callsign * fixed a bug in user/club creation * Revert "Auto creation of logbook and location when new user is created" We found another solution to which will be addressed in a second PR This reverts commit f05f4b7bf0423a88abf0087ade81fe613d217794. * Optimized SQL for stats at userlist * Source query for lastop "out", because mysql<9.0 can't handle Windowed functions * adjust migration * add new columns to users table to get created_at and modified_at * added a partial down function * add operator dropdown for clubstations * fix mig version * Add some backend restrictions in case a user wants to try something funny with the club --------- Co-authored-by: Andreas Kristiansen <6977712+AndreasK79@users.noreply.github.com> Co-authored-by: int2001 <joerg@dj7nt.de>
2025-01-02 10:22:23 +01:00
$data['clubmode'] = $this->session->userdata('clubstation') == 1 ? true : false;
2024-06-08 11:01:59 +02:00
$data['page_title'] = __("API");
2011-11-04 17:32:03 +00:00
$this->load->view('interface_assets/header', $data);
Clubstations for Wavelog (#1334) * feat[clubstations]: New DB structure * feat[clubstations]: Add clubstationstable in user managment * feat[clubstations]: Show last operator * feat[clubstations]: Better solution for last operator. tnx for the hint @int2001 * feat[clubstations]: New Club Model and Controller * feat[clubstations]: Add "Add User" and "Edit User" functionality * docs[clubstations]: move comment * feat[clubstations]: Add "Delete Member" functionality * feat[clubstations]: some enhancements and javascript * fix[clubstations]: Wrong message class for flashmessages * feat[clubstations]: Added Switch in the Header menu (not functional yet) * feat[clubstations]: clubswitch modal * fix[clubstations]: Load encryption library if not already loaded * fix[clubstations]: Prevent direct login attempts to clubstations and enhance impersonation authorization * fix[clubstations]: Typo * feat[clubstations]: Only show the operator dialog if there is something fishy * fix[user]: little UI bug * feat[impersonate]: Add source uid to session data * fix[impersonate]: logic adjustment * feat[clubstations]: Add manage button in header menu for club officers * fix[clubstations]: typo in permission level check * fix[clubstations]: Full rights for the admin * feat[impersonate]: Custom sessiondata * feat[impersonate]: Implement stop impersonation feature with modal confirmation; "the way back" * fix(modal): Fix bug where modal was hidden when mouse leaved the browser content * docs(config): Adjust config description for special callsigns and clubstations * feat(club): Add club access check helper * typo * fix[impersonation]: Better text * feat(club): Selectize for a efficient user search * feat(clubstations): Restrict clubstations based on users permission level part 1/x * adjustments for dev merge * Adjusted club right for the advanced logbook * feat[user]: Refactoring of the Action Buttons in the user table * fix[club_permissions]: normal button instead small one for club permissions * remove unnecessary line break in modal body * feat[clubstations]: Add Club Mode badge to the header * fix[clubstations]: fix maintenance mode * allow switch back on http * feat(simplefle): display operator input based on club_access * small UI adjustments * small UI adjustments * moved api page to a index.php file and added support for clubstations * removed unused stuff * typo * radios and api keys * missed one binding * fix qso view, even officers do just see their own radios in QSO logging * omit the need for a relogin to see the changes as an admin * Omit the need for relogin after club changes in general. It's a question of UX. It's better to accept a little higher DB load (if clubstations are enabled) then the need of an user to relogin. There is some room for improvement by changing user_model->get_by_id() and adding a join there. This can be done later if we see that the load is too high * 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 * remove debug messages * better UI in header * found a typo * full access in clubstations for admins (if accessed via admin usertable) * adjusted text * adjusted text * adjust text * reduce required chars * bugfix: missing the correct authentication in case the admin was not member of the club. he wasn't able to switch back * reduce debug messages * fixed UI bug related to tooltips * load js in controller * upps.. * some UI adjustments * corrected permissions * if user gets delete we need to remove data in club_permissions and also api keys which were created by this user * Notify members about new memberships or changes in permission level * add spinner to save button * make login/logout process more bulletproof * remove the relogin cookie after the attempt * better strategy * bug where switch back failed if user is no admin * make api keys more secure * mask not owned api keys * removed annoying link * if a user gets removed from a club we also should delete the corresponding api keys and cat radios * adjusted wiki link * Auto creation of logbook and location when new user is created * store and display locator in uppercase * same for callsign * fixed a bug in user/club creation * Revert "Auto creation of logbook and location when new user is created" We found another solution to which will be addressed in a second PR This reverts commit f05f4b7bf0423a88abf0087ade81fe613d217794. * Optimized SQL for stats at userlist * Source query for lastop "out", because mysql<9.0 can't handle Windowed functions * adjust migration * add new columns to users table to get created_at and modified_at * added a partial down function * add operator dropdown for clubstations * fix mig version * Add some backend restrictions in case a user wants to try something funny with the club --------- Co-authored-by: Andreas Kristiansen <6977712+AndreasK79@users.noreply.github.com> Co-authored-by: int2001 <joerg@dj7nt.de>
2025-01-02 10:22:23 +01:00
$this->load->view('api/index');
$this->load->view('interface_assets/footer');
}
Clubstations for Wavelog (#1334) * feat[clubstations]: New DB structure * feat[clubstations]: Add clubstationstable in user managment * feat[clubstations]: Show last operator * feat[clubstations]: Better solution for last operator. tnx for the hint @int2001 * feat[clubstations]: New Club Model and Controller * feat[clubstations]: Add "Add User" and "Edit User" functionality * docs[clubstations]: move comment * feat[clubstations]: Add "Delete Member" functionality * feat[clubstations]: some enhancements and javascript * fix[clubstations]: Wrong message class for flashmessages * feat[clubstations]: Added Switch in the Header menu (not functional yet) * feat[clubstations]: clubswitch modal * fix[clubstations]: Load encryption library if not already loaded * fix[clubstations]: Prevent direct login attempts to clubstations and enhance impersonation authorization * fix[clubstations]: Typo * feat[clubstations]: Only show the operator dialog if there is something fishy * fix[user]: little UI bug * feat[impersonate]: Add source uid to session data * fix[impersonate]: logic adjustment * feat[clubstations]: Add manage button in header menu for club officers * fix[clubstations]: typo in permission level check * fix[clubstations]: Full rights for the admin * feat[impersonate]: Custom sessiondata * feat[impersonate]: Implement stop impersonation feature with modal confirmation; "the way back" * fix(modal): Fix bug where modal was hidden when mouse leaved the browser content * docs(config): Adjust config description for special callsigns and clubstations * feat(club): Add club access check helper * typo * fix[impersonation]: Better text * feat(club): Selectize for a efficient user search * feat(clubstations): Restrict clubstations based on users permission level part 1/x * adjustments for dev merge * Adjusted club right for the advanced logbook * feat[user]: Refactoring of the Action Buttons in the user table * fix[club_permissions]: normal button instead small one for club permissions * remove unnecessary line break in modal body * feat[clubstations]: Add Club Mode badge to the header * fix[clubstations]: fix maintenance mode * allow switch back on http * feat(simplefle): display operator input based on club_access * small UI adjustments * small UI adjustments * moved api page to a index.php file and added support for clubstations * removed unused stuff * typo * radios and api keys * missed one binding * fix qso view, even officers do just see their own radios in QSO logging * omit the need for a relogin to see the changes as an admin * Omit the need for relogin after club changes in general. It's a question of UX. It's better to accept a little higher DB load (if clubstations are enabled) then the need of an user to relogin. There is some room for improvement by changing user_model->get_by_id() and adding a join there. This can be done later if we see that the load is too high * 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 * remove debug messages * better UI in header * found a typo * full access in clubstations for admins (if accessed via admin usertable) * adjusted text * adjusted text * adjust text * reduce required chars * bugfix: missing the correct authentication in case the admin was not member of the club. he wasn't able to switch back * reduce debug messages * fixed UI bug related to tooltips * load js in controller * upps.. * some UI adjustments * corrected permissions * if user gets delete we need to remove data in club_permissions and also api keys which were created by this user * Notify members about new memberships or changes in permission level * add spinner to save button * make login/logout process more bulletproof * remove the relogin cookie after the attempt * better strategy * bug where switch back failed if user is no admin * make api keys more secure * mask not owned api keys * removed annoying link * if a user gets removed from a club we also should delete the corresponding api keys and cat radios * adjusted wiki link * Auto creation of logbook and location when new user is created * store and display locator in uppercase * same for callsign * fixed a bug in user/club creation * Revert "Auto creation of logbook and location when new user is created" We found another solution to which will be addressed in a second PR This reverts commit f05f4b7bf0423a88abf0087ade81fe613d217794. * Optimized SQL for stats at userlist * Source query for lastop "out", because mysql<9.0 can't handle Windowed functions * adjust migration * add new columns to users table to get created_at and modified_at * added a partial down function * add operator dropdown for clubstations * fix mig version * Add some backend restrictions in case a user wants to try something funny with the club --------- Co-authored-by: Andreas Kristiansen <6977712+AndreasK79@users.noreply.github.com> Co-authored-by: int2001 <joerg@dj7nt.de>
2025-01-02 10:22:23 +01:00
// legacy
function help() {
redirect('api');
}
/**
* Check rate limit for current endpoint
* Only enforced if api_rate_limits config is set
*
* returns True if request is allowed, false if rate limited
*/
protected function check_rate_limit($endpoint, $identifier = null) {
if (!$this->load->is_loaded('rate_limit')) {
$this->load->library('rate_limit');
}
$result = $this->rate_limit->check($endpoint, $identifier);
if (!$result['allowed']) {
log_message("Debug","Rate limit for endpoint ".$endpoint." and ID: ".($identifier ?? '')." exceeded");
$this->rate_limit->send_limit_exceeded_response($result['retry_after']);
return false;
}
return true;
}
function edit($key) {
Clubstations for Wavelog (#1334) * feat[clubstations]: New DB structure * feat[clubstations]: Add clubstationstable in user managment * feat[clubstations]: Show last operator * feat[clubstations]: Better solution for last operator. tnx for the hint @int2001 * feat[clubstations]: New Club Model and Controller * feat[clubstations]: Add "Add User" and "Edit User" functionality * docs[clubstations]: move comment * feat[clubstations]: Add "Delete Member" functionality * feat[clubstations]: some enhancements and javascript * fix[clubstations]: Wrong message class for flashmessages * feat[clubstations]: Added Switch in the Header menu (not functional yet) * feat[clubstations]: clubswitch modal * fix[clubstations]: Load encryption library if not already loaded * fix[clubstations]: Prevent direct login attempts to clubstations and enhance impersonation authorization * fix[clubstations]: Typo * feat[clubstations]: Only show the operator dialog if there is something fishy * fix[user]: little UI bug * feat[impersonate]: Add source uid to session data * fix[impersonate]: logic adjustment * feat[clubstations]: Add manage button in header menu for club officers * fix[clubstations]: typo in permission level check * fix[clubstations]: Full rights for the admin * feat[impersonate]: Custom sessiondata * feat[impersonate]: Implement stop impersonation feature with modal confirmation; "the way back" * fix(modal): Fix bug where modal was hidden when mouse leaved the browser content * docs(config): Adjust config description for special callsigns and clubstations * feat(club): Add club access check helper * typo * fix[impersonation]: Better text * feat(club): Selectize for a efficient user search * feat(clubstations): Restrict clubstations based on users permission level part 1/x * adjustments for dev merge * Adjusted club right for the advanced logbook * feat[user]: Refactoring of the Action Buttons in the user table * fix[club_permissions]: normal button instead small one for club permissions * remove unnecessary line break in modal body * feat[clubstations]: Add Club Mode badge to the header * fix[clubstations]: fix maintenance mode * allow switch back on http * feat(simplefle): display operator input based on club_access * small UI adjustments * small UI adjustments * moved api page to a index.php file and added support for clubstations * removed unused stuff * typo * radios and api keys * missed one binding * fix qso view, even officers do just see their own radios in QSO logging * omit the need for a relogin to see the changes as an admin * Omit the need for relogin after club changes in general. It's a question of UX. It's better to accept a little higher DB load (if clubstations are enabled) then the need of an user to relogin. There is some room for improvement by changing user_model->get_by_id() and adding a join there. This can be done later if we see that the load is too high * 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 * remove debug messages * better UI in header * found a typo * full access in clubstations for admins (if accessed via admin usertable) * adjusted text * adjusted text * adjust text * reduce required chars * bugfix: missing the correct authentication in case the admin was not member of the club. he wasn't able to switch back * reduce debug messages * fixed UI bug related to tooltips * load js in controller * upps.. * some UI adjustments * corrected permissions * if user gets delete we need to remove data in club_permissions and also api keys which were created by this user * Notify members about new memberships or changes in permission level * add spinner to save button * make login/logout process more bulletproof * remove the relogin cookie after the attempt * better strategy * bug where switch back failed if user is no admin * make api keys more secure * mask not owned api keys * removed annoying link * if a user gets removed from a club we also should delete the corresponding api keys and cat radios * adjusted wiki link * Auto creation of logbook and location when new user is created * store and display locator in uppercase * same for callsign * fixed a bug in user/club creation * Revert "Auto creation of logbook and location when new user is created" We found another solution to which will be addressed in a second PR This reverts commit f05f4b7bf0423a88abf0087ade81fe613d217794. * Optimized SQL for stats at userlist * Source query for lastop "out", because mysql<9.0 can't handle Windowed functions * adjust migration * add new columns to users table to get created_at and modified_at * added a partial down function * add operator dropdown for clubstations * fix mig version * Add some backend restrictions in case a user wants to try something funny with the club --------- Co-authored-by: Andreas Kristiansen <6977712+AndreasK79@users.noreply.github.com> Co-authored-by: int2001 <joerg@dj7nt.de>
2025-01-02 10:22:23 +01:00
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->helper(array('form', 'url'));
$this->load->library('form_validation');
$this->form_validation->set_rules('api_desc', __("API Description"), 'required');
$this->form_validation->set_rules('api_key', __("API Key is required. Do not change this field"), 'required');
$data['api_info'] = $this->api_model->key_description($key);
if ($this->form_validation->run() == FALSE) {
$data['page_title'] = __("Edit API Description");
$this->load->view('interface_assets/header', $data);
$this->load->view('api/components/edit_legacy');
$this->load->view('interface_assets/footer');
} else {
// Success!
2026-03-16 00:57:34 +01:00
$this->api_model->update_key_description($this->input->post('api_key', true), $this->input->post('api_desc', true));
2026-03-16 00:57:34 +01:00
$this->session->set_flashdata('notice', sprintf(__("API Key %s description has been updated."), "<b>" . htmlspecialchars($this->input->post('api_key', true), ENT_QUOTES, 'UTF-8') . "</b>"));
Clubstations for Wavelog (#1334) * feat[clubstations]: New DB structure * feat[clubstations]: Add clubstationstable in user managment * feat[clubstations]: Show last operator * feat[clubstations]: Better solution for last operator. tnx for the hint @int2001 * feat[clubstations]: New Club Model and Controller * feat[clubstations]: Add "Add User" and "Edit User" functionality * docs[clubstations]: move comment * feat[clubstations]: Add "Delete Member" functionality * feat[clubstations]: some enhancements and javascript * fix[clubstations]: Wrong message class for flashmessages * feat[clubstations]: Added Switch in the Header menu (not functional yet) * feat[clubstations]: clubswitch modal * fix[clubstations]: Load encryption library if not already loaded * fix[clubstations]: Prevent direct login attempts to clubstations and enhance impersonation authorization * fix[clubstations]: Typo * feat[clubstations]: Only show the operator dialog if there is something fishy * fix[user]: little UI bug * feat[impersonate]: Add source uid to session data * fix[impersonate]: logic adjustment * feat[clubstations]: Add manage button in header menu for club officers * fix[clubstations]: typo in permission level check * fix[clubstations]: Full rights for the admin * feat[impersonate]: Custom sessiondata * feat[impersonate]: Implement stop impersonation feature with modal confirmation; "the way back" * fix(modal): Fix bug where modal was hidden when mouse leaved the browser content * docs(config): Adjust config description for special callsigns and clubstations * feat(club): Add club access check helper * typo * fix[impersonation]: Better text * feat(club): Selectize for a efficient user search * feat(clubstations): Restrict clubstations based on users permission level part 1/x * adjustments for dev merge * Adjusted club right for the advanced logbook * feat[user]: Refactoring of the Action Buttons in the user table * fix[club_permissions]: normal button instead small one for club permissions * remove unnecessary line break in modal body * feat[clubstations]: Add Club Mode badge to the header * fix[clubstations]: fix maintenance mode * allow switch back on http * feat(simplefle): display operator input based on club_access * small UI adjustments * small UI adjustments * moved api page to a index.php file and added support for clubstations * removed unused stuff * typo * radios and api keys * missed one binding * fix qso view, even officers do just see their own radios in QSO logging * omit the need for a relogin to see the changes as an admin * Omit the need for relogin after club changes in general. It's a question of UX. It's better to accept a little higher DB load (if clubstations are enabled) then the need of an user to relogin. There is some room for improvement by changing user_model->get_by_id() and adding a join there. This can be done later if we see that the load is too high * 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 * remove debug messages * better UI in header * found a typo * full access in clubstations for admins (if accessed via admin usertable) * adjusted text * adjusted text * adjust text * reduce required chars * bugfix: missing the correct authentication in case the admin was not member of the club. he wasn't able to switch back * reduce debug messages * fixed UI bug related to tooltips * load js in controller * upps.. * some UI adjustments * corrected permissions * if user gets delete we need to remove data in club_permissions and also api keys which were created by this user * Notify members about new memberships or changes in permission level * add spinner to save button * make login/logout process more bulletproof * remove the relogin cookie after the attempt * better strategy * bug where switch back failed if user is no admin * make api keys more secure * mask not owned api keys * removed annoying link * if a user gets removed from a club we also should delete the corresponding api keys and cat radios * adjusted wiki link * Auto creation of logbook and location when new user is created * store and display locator in uppercase * same for callsign * fixed a bug in user/club creation * Revert "Auto creation of logbook and location when new user is created" We found another solution to which will be addressed in a second PR This reverts commit f05f4b7bf0423a88abf0087ade81fe613d217794. * Optimized SQL for stats at userlist * Source query for lastop "out", because mysql<9.0 can't handle Windowed functions * adjust migration * add new columns to users table to get created_at and modified_at * added a partial down function * add operator dropdown for clubstations * fix mig version * Add some backend restrictions in case a user wants to try something funny with the club --------- Co-authored-by: Andreas Kristiansen <6977712+AndreasK79@users.noreply.github.com> Co-authored-by: int2001 <joerg@dj7nt.de>
2025-01-02 10:22:23 +01:00
redirect('api');
}
}
function generate() {
// CSRF mitigation: reject non-POST requests
if ($this->input->method() !== 'post') {
$this->session->set_flashdata('error', __("Invalid request method"));
redirect('api');
return;
}
Clubstations for Wavelog (#1334) * feat[clubstations]: New DB structure * feat[clubstations]: Add clubstationstable in user managment * feat[clubstations]: Show last operator * feat[clubstations]: Better solution for last operator. tnx for the hint @int2001 * feat[clubstations]: New Club Model and Controller * feat[clubstations]: Add "Add User" and "Edit User" functionality * docs[clubstations]: move comment * feat[clubstations]: Add "Delete Member" functionality * feat[clubstations]: some enhancements and javascript * fix[clubstations]: Wrong message class for flashmessages * feat[clubstations]: Added Switch in the Header menu (not functional yet) * feat[clubstations]: clubswitch modal * fix[clubstations]: Load encryption library if not already loaded * fix[clubstations]: Prevent direct login attempts to clubstations and enhance impersonation authorization * fix[clubstations]: Typo * feat[clubstations]: Only show the operator dialog if there is something fishy * fix[user]: little UI bug * feat[impersonate]: Add source uid to session data * fix[impersonate]: logic adjustment * feat[clubstations]: Add manage button in header menu for club officers * fix[clubstations]: typo in permission level check * fix[clubstations]: Full rights for the admin * feat[impersonate]: Custom sessiondata * feat[impersonate]: Implement stop impersonation feature with modal confirmation; "the way back" * fix(modal): Fix bug where modal was hidden when mouse leaved the browser content * docs(config): Adjust config description for special callsigns and clubstations * feat(club): Add club access check helper * typo * fix[impersonation]: Better text * feat(club): Selectize for a efficient user search * feat(clubstations): Restrict clubstations based on users permission level part 1/x * adjustments for dev merge * Adjusted club right for the advanced logbook * feat[user]: Refactoring of the Action Buttons in the user table * fix[club_permissions]: normal button instead small one for club permissions * remove unnecessary line break in modal body * feat[clubstations]: Add Club Mode badge to the header * fix[clubstations]: fix maintenance mode * allow switch back on http * feat(simplefle): display operator input based on club_access * small UI adjustments * small UI adjustments * moved api page to a index.php file and added support for clubstations * removed unused stuff * typo * radios and api keys * missed one binding * fix qso view, even officers do just see their own radios in QSO logging * omit the need for a relogin to see the changes as an admin * Omit the need for relogin after club changes in general. It's a question of UX. It's better to accept a little higher DB load (if clubstations are enabled) then the need of an user to relogin. There is some room for improvement by changing user_model->get_by_id() and adding a join there. This can be done later if we see that the load is too high * 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 * remove debug messages * better UI in header * found a typo * full access in clubstations for admins (if accessed via admin usertable) * adjusted text * adjusted text * adjust text * reduce required chars * bugfix: missing the correct authentication in case the admin was not member of the club. he wasn't able to switch back * reduce debug messages * fixed UI bug related to tooltips * load js in controller * upps.. * some UI adjustments * corrected permissions * if user gets delete we need to remove data in club_permissions and also api keys which were created by this user * Notify members about new memberships or changes in permission level * add spinner to save button * make login/logout process more bulletproof * remove the relogin cookie after the attempt * better strategy * bug where switch back failed if user is no admin * make api keys more secure * mask not owned api keys * removed annoying link * if a user gets removed from a club we also should delete the corresponding api keys and cat radios * adjusted wiki link * Auto creation of logbook and location when new user is created * store and display locator in uppercase * same for callsign * fixed a bug in user/club creation * Revert "Auto creation of logbook and location when new user is created" We found another solution to which will be addressed in a second PR This reverts commit f05f4b7bf0423a88abf0087ade81fe613d217794. * Optimized SQL for stats at userlist * Source query for lastop "out", because mysql<9.0 can't handle Windowed functions * adjust migration * add new columns to users table to get created_at and modified_at * added a partial down function * add operator dropdown for clubstations * fix mig version * Add some backend restrictions in case a user wants to try something funny with the club --------- Co-authored-by: Andreas Kristiansen <6977712+AndreasK79@users.noreply.github.com> Co-authored-by: int2001 <joerg@dj7nt.de>
2025-01-02 10:22:23 +01:00
if(!$this->user_model->authorize(3)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); }
2021-11-14 11:57:21 +00:00
$rights = $this->input->post('rights', TRUE);
Clubstations for Wavelog (#1334) * feat[clubstations]: New DB structure * feat[clubstations]: Add clubstationstable in user managment * feat[clubstations]: Show last operator * feat[clubstations]: Better solution for last operator. tnx for the hint @int2001 * feat[clubstations]: New Club Model and Controller * feat[clubstations]: Add "Add User" and "Edit User" functionality * docs[clubstations]: move comment * feat[clubstations]: Add "Delete Member" functionality * feat[clubstations]: some enhancements and javascript * fix[clubstations]: Wrong message class for flashmessages * feat[clubstations]: Added Switch in the Header menu (not functional yet) * feat[clubstations]: clubswitch modal * fix[clubstations]: Load encryption library if not already loaded * fix[clubstations]: Prevent direct login attempts to clubstations and enhance impersonation authorization * fix[clubstations]: Typo * feat[clubstations]: Only show the operator dialog if there is something fishy * fix[user]: little UI bug * feat[impersonate]: Add source uid to session data * fix[impersonate]: logic adjustment * feat[clubstations]: Add manage button in header menu for club officers * fix[clubstations]: typo in permission level check * fix[clubstations]: Full rights for the admin * feat[impersonate]: Custom sessiondata * feat[impersonate]: Implement stop impersonation feature with modal confirmation; "the way back" * fix(modal): Fix bug where modal was hidden when mouse leaved the browser content * docs(config): Adjust config description for special callsigns and clubstations * feat(club): Add club access check helper * typo * fix[impersonation]: Better text * feat(club): Selectize for a efficient user search * feat(clubstations): Restrict clubstations based on users permission level part 1/x * adjustments for dev merge * Adjusted club right for the advanced logbook * feat[user]: Refactoring of the Action Buttons in the user table * fix[club_permissions]: normal button instead small one for club permissions * remove unnecessary line break in modal body * feat[clubstations]: Add Club Mode badge to the header * fix[clubstations]: fix maintenance mode * allow switch back on http * feat(simplefle): display operator input based on club_access * small UI adjustments * small UI adjustments * moved api page to a index.php file and added support for clubstations * removed unused stuff * typo * radios and api keys * missed one binding * fix qso view, even officers do just see their own radios in QSO logging * omit the need for a relogin to see the changes as an admin * Omit the need for relogin after club changes in general. It's a question of UX. It's better to accept a little higher DB load (if clubstations are enabled) then the need of an user to relogin. There is some room for improvement by changing user_model->get_by_id() and adding a join there. This can be done later if we see that the load is too high * 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 * remove debug messages * better UI in header * found a typo * full access in clubstations for admins (if accessed via admin usertable) * adjusted text * adjusted text * adjust text * reduce required chars * bugfix: missing the correct authentication in case the admin was not member of the club. he wasn't able to switch back * reduce debug messages * fixed UI bug related to tooltips * load js in controller * upps.. * some UI adjustments * corrected permissions * if user gets delete we need to remove data in club_permissions and also api keys which were created by this user * Notify members about new memberships or changes in permission level * add spinner to save button * make login/logout process more bulletproof * remove the relogin cookie after the attempt * better strategy * bug where switch back failed if user is no admin * make api keys more secure * mask not owned api keys * removed annoying link * if a user gets removed from a club we also should delete the corresponding api keys and cat radios * adjusted wiki link * Auto creation of logbook and location when new user is created * store and display locator in uppercase * same for callsign * fixed a bug in user/club creation * Revert "Auto creation of logbook and location when new user is created" We found another solution to which will be addressed in a second PR This reverts commit f05f4b7bf0423a88abf0087ade81fe613d217794. * Optimized SQL for stats at userlist * Source query for lastop "out", because mysql<9.0 can't handle Windowed functions * adjust migration * add new columns to users table to get created_at and modified_at * added a partial down function * add operator dropdown for clubstations * fix mig version * Add some backend restrictions in case a user wants to try something funny with the club --------- Co-authored-by: Andreas Kristiansen <6977712+AndreasK79@users.noreply.github.com> Co-authored-by: int2001 <joerg@dj7nt.de>
2025-01-02 10:22:23 +01:00
if ($rights !== "r" && $rights !== "rw") {
$this->session->set_flashdata('error', __("Invalid API rights"));
redirect('api');
return;
2021-11-14 11:57:21 +00:00
}
$this->load->model('api_model');
Clubstations for Wavelog (#1334) * feat[clubstations]: New DB structure * feat[clubstations]: Add clubstationstable in user managment * feat[clubstations]: Show last operator * feat[clubstations]: Better solution for last operator. tnx for the hint @int2001 * feat[clubstations]: New Club Model and Controller * feat[clubstations]: Add "Add User" and "Edit User" functionality * docs[clubstations]: move comment * feat[clubstations]: Add "Delete Member" functionality * feat[clubstations]: some enhancements and javascript * fix[clubstations]: Wrong message class for flashmessages * feat[clubstations]: Added Switch in the Header menu (not functional yet) * feat[clubstations]: clubswitch modal * fix[clubstations]: Load encryption library if not already loaded * fix[clubstations]: Prevent direct login attempts to clubstations and enhance impersonation authorization * fix[clubstations]: Typo * feat[clubstations]: Only show the operator dialog if there is something fishy * fix[user]: little UI bug * feat[impersonate]: Add source uid to session data * fix[impersonate]: logic adjustment * feat[clubstations]: Add manage button in header menu for club officers * fix[clubstations]: typo in permission level check * fix[clubstations]: Full rights for the admin * feat[impersonate]: Custom sessiondata * feat[impersonate]: Implement stop impersonation feature with modal confirmation; "the way back" * fix(modal): Fix bug where modal was hidden when mouse leaved the browser content * docs(config): Adjust config description for special callsigns and clubstations * feat(club): Add club access check helper * typo * fix[impersonation]: Better text * feat(club): Selectize for a efficient user search * feat(clubstations): Restrict clubstations based on users permission level part 1/x * adjustments for dev merge * Adjusted club right for the advanced logbook * feat[user]: Refactoring of the Action Buttons in the user table * fix[club_permissions]: normal button instead small one for club permissions * remove unnecessary line break in modal body * feat[clubstations]: Add Club Mode badge to the header * fix[clubstations]: fix maintenance mode * allow switch back on http * feat(simplefle): display operator input based on club_access * small UI adjustments * small UI adjustments * moved api page to a index.php file and added support for clubstations * removed unused stuff * typo * radios and api keys * missed one binding * fix qso view, even officers do just see their own radios in QSO logging * omit the need for a relogin to see the changes as an admin * Omit the need for relogin after club changes in general. It's a question of UX. It's better to accept a little higher DB load (if clubstations are enabled) then the need of an user to relogin. There is some room for improvement by changing user_model->get_by_id() and adding a join there. This can be done later if we see that the load is too high * 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 * remove debug messages * better UI in header * found a typo * full access in clubstations for admins (if accessed via admin usertable) * adjusted text * adjusted text * adjust text * reduce required chars * bugfix: missing the correct authentication in case the admin was not member of the club. he wasn't able to switch back * reduce debug messages * fixed UI bug related to tooltips * load js in controller * upps.. * some UI adjustments * corrected permissions * if user gets delete we need to remove data in club_permissions and also api keys which were created by this user * Notify members about new memberships or changes in permission level * add spinner to save button * make login/logout process more bulletproof * remove the relogin cookie after the attempt * better strategy * bug where switch back failed if user is no admin * make api keys more secure * mask not owned api keys * removed annoying link * if a user gets removed from a club we also should delete the corresponding api keys and cat radios * adjusted wiki link * Auto creation of logbook and location when new user is created * store and display locator in uppercase * same for callsign * fixed a bug in user/club creation * Revert "Auto creation of logbook and location when new user is created" We found another solution to which will be addressed in a second PR This reverts commit f05f4b7bf0423a88abf0087ade81fe613d217794. * Optimized SQL for stats at userlist * Source query for lastop "out", because mysql<9.0 can't handle Windowed functions * adjust migration * add new columns to users table to get created_at and modified_at * added a partial down function * add operator dropdown for clubstations * fix mig version * Add some backend restrictions in case a user wants to try something funny with the club --------- Co-authored-by: Andreas Kristiansen <6977712+AndreasK79@users.noreply.github.com> Co-authored-by: int2001 <joerg@dj7nt.de>
2025-01-02 10:22:23 +01:00
if ($this->session->userdata('clubstation') == 1 && $this->session->userdata('impersonate') == 1) {
$creator = $this->session->userdata('source_uid');
} else {
$creator = $this->session->userdata('user_id');
}
Clubstations for Wavelog (#1334) * feat[clubstations]: New DB structure * feat[clubstations]: Add clubstationstable in user managment * feat[clubstations]: Show last operator * feat[clubstations]: Better solution for last operator. tnx for the hint @int2001 * feat[clubstations]: New Club Model and Controller * feat[clubstations]: Add "Add User" and "Edit User" functionality * docs[clubstations]: move comment * feat[clubstations]: Add "Delete Member" functionality * feat[clubstations]: some enhancements and javascript * fix[clubstations]: Wrong message class for flashmessages * feat[clubstations]: Added Switch in the Header menu (not functional yet) * feat[clubstations]: clubswitch modal * fix[clubstations]: Load encryption library if not already loaded * fix[clubstations]: Prevent direct login attempts to clubstations and enhance impersonation authorization * fix[clubstations]: Typo * feat[clubstations]: Only show the operator dialog if there is something fishy * fix[user]: little UI bug * feat[impersonate]: Add source uid to session data * fix[impersonate]: logic adjustment * feat[clubstations]: Add manage button in header menu for club officers * fix[clubstations]: typo in permission level check * fix[clubstations]: Full rights for the admin * feat[impersonate]: Custom sessiondata * feat[impersonate]: Implement stop impersonation feature with modal confirmation; "the way back" * fix(modal): Fix bug where modal was hidden when mouse leaved the browser content * docs(config): Adjust config description for special callsigns and clubstations * feat(club): Add club access check helper * typo * fix[impersonation]: Better text * feat(club): Selectize for a efficient user search * feat(clubstations): Restrict clubstations based on users permission level part 1/x * adjustments for dev merge * Adjusted club right for the advanced logbook * feat[user]: Refactoring of the Action Buttons in the user table * fix[club_permissions]: normal button instead small one for club permissions * remove unnecessary line break in modal body * feat[clubstations]: Add Club Mode badge to the header * fix[clubstations]: fix maintenance mode * allow switch back on http * feat(simplefle): display operator input based on club_access * small UI adjustments * small UI adjustments * moved api page to a index.php file and added support for clubstations * removed unused stuff * typo * radios and api keys * missed one binding * fix qso view, even officers do just see their own radios in QSO logging * omit the need for a relogin to see the changes as an admin * Omit the need for relogin after club changes in general. It's a question of UX. It's better to accept a little higher DB load (if clubstations are enabled) then the need of an user to relogin. There is some room for improvement by changing user_model->get_by_id() and adding a join there. This can be done later if we see that the load is too high * 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 * remove debug messages * better UI in header * found a typo * full access in clubstations for admins (if accessed via admin usertable) * adjusted text * adjusted text * adjust text * reduce required chars * bugfix: missing the correct authentication in case the admin was not member of the club. he wasn't able to switch back * reduce debug messages * fixed UI bug related to tooltips * load js in controller * upps.. * some UI adjustments * corrected permissions * if user gets delete we need to remove data in club_permissions and also api keys which were created by this user * Notify members about new memberships or changes in permission level * add spinner to save button * make login/logout process more bulletproof * remove the relogin cookie after the attempt * better strategy * bug where switch back failed if user is no admin * make api keys more secure * mask not owned api keys * removed annoying link * if a user gets removed from a club we also should delete the corresponding api keys and cat radios * adjusted wiki link * Auto creation of logbook and location when new user is created * store and display locator in uppercase * same for callsign * fixed a bug in user/club creation * Revert "Auto creation of logbook and location when new user is created" We found another solution to which will be addressed in a second PR This reverts commit f05f4b7bf0423a88abf0087ade81fe613d217794. * Optimized SQL for stats at userlist * Source query for lastop "out", because mysql<9.0 can't handle Windowed functions * adjust migration * add new columns to users table to get created_at and modified_at * added a partial down function * add operator dropdown for clubstations * fix mig version * Add some backend restrictions in case a user wants to try something funny with the club --------- Co-authored-by: Andreas Kristiansen <6977712+AndreasK79@users.noreply.github.com> Co-authored-by: int2001 <joerg@dj7nt.de>
2025-01-02 10:22:23 +01:00
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() {
// CSRF mitigation: reject non-POST requests
if ($this->input->method() !== 'post') {
$this->session->set_flashdata('error', __("Invalid request method"));
redirect('api');
return;
}
Clubstations for Wavelog (#1334) * feat[clubstations]: New DB structure * feat[clubstations]: Add clubstationstable in user managment * feat[clubstations]: Show last operator * feat[clubstations]: Better solution for last operator. tnx for the hint @int2001 * feat[clubstations]: New Club Model and Controller * feat[clubstations]: Add "Add User" and "Edit User" functionality * docs[clubstations]: move comment * feat[clubstations]: Add "Delete Member" functionality * feat[clubstations]: some enhancements and javascript * fix[clubstations]: Wrong message class for flashmessages * feat[clubstations]: Added Switch in the Header menu (not functional yet) * feat[clubstations]: clubswitch modal * fix[clubstations]: Load encryption library if not already loaded * fix[clubstations]: Prevent direct login attempts to clubstations and enhance impersonation authorization * fix[clubstations]: Typo * feat[clubstations]: Only show the operator dialog if there is something fishy * fix[user]: little UI bug * feat[impersonate]: Add source uid to session data * fix[impersonate]: logic adjustment * feat[clubstations]: Add manage button in header menu for club officers * fix[clubstations]: typo in permission level check * fix[clubstations]: Full rights for the admin * feat[impersonate]: Custom sessiondata * feat[impersonate]: Implement stop impersonation feature with modal confirmation; "the way back" * fix(modal): Fix bug where modal was hidden when mouse leaved the browser content * docs(config): Adjust config description for special callsigns and clubstations * feat(club): Add club access check helper * typo * fix[impersonation]: Better text * feat(club): Selectize for a efficient user search * feat(clubstations): Restrict clubstations based on users permission level part 1/x * adjustments for dev merge * Adjusted club right for the advanced logbook * feat[user]: Refactoring of the Action Buttons in the user table * fix[club_permissions]: normal button instead small one for club permissions * remove unnecessary line break in modal body * feat[clubstations]: Add Club Mode badge to the header * fix[clubstations]: fix maintenance mode * allow switch back on http * feat(simplefle): display operator input based on club_access * small UI adjustments * small UI adjustments * moved api page to a index.php file and added support for clubstations * removed unused stuff * typo * radios and api keys * missed one binding * fix qso view, even officers do just see their own radios in QSO logging * omit the need for a relogin to see the changes as an admin * Omit the need for relogin after club changes in general. It's a question of UX. It's better to accept a little higher DB load (if clubstations are enabled) then the need of an user to relogin. There is some room for improvement by changing user_model->get_by_id() and adding a join there. This can be done later if we see that the load is too high * 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 * remove debug messages * better UI in header * found a typo * full access in clubstations for admins (if accessed via admin usertable) * adjusted text * adjusted text * adjust text * reduce required chars * bugfix: missing the correct authentication in case the admin was not member of the club. he wasn't able to switch back * reduce debug messages * fixed UI bug related to tooltips * load js in controller * upps.. * some UI adjustments * corrected permissions * if user gets delete we need to remove data in club_permissions and also api keys which were created by this user * Notify members about new memberships or changes in permission level * add spinner to save button * make login/logout process more bulletproof * remove the relogin cookie after the attempt * better strategy * bug where switch back failed if user is no admin * make api keys more secure * mask not owned api keys * removed annoying link * if a user gets removed from a club we also should delete the corresponding api keys and cat radios * adjusted wiki link * Auto creation of logbook and location when new user is created * store and display locator in uppercase * same for callsign * fixed a bug in user/club creation * Revert "Auto creation of logbook and location when new user is created" We found another solution to which will be addressed in a second PR This reverts commit f05f4b7bf0423a88abf0087ade81fe613d217794. * Optimized SQL for stats at userlist * Source query for lastop "out", because mysql<9.0 can't handle Windowed functions * adjust migration * add new columns to users table to get created_at and modified_at * added a partial down function * add operator dropdown for clubstations * fix mig version * Add some backend restrictions in case a user wants to try something funny with the club --------- Co-authored-by: Andreas Kristiansen <6977712+AndreasK79@users.noreply.github.com> Co-authored-by: int2001 <joerg@dj7nt.de>
2025-01-02 10:22:23 +01:00
if(!$this->user_model->authorize(3)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); }
$key = $this->input->post('key', TRUE);
if (empty($key)) {
$this->session->set_flashdata('error', __("Invalid API Key"));
redirect('api');
return;
}
$this->load->model('api_model');
$this->api_model->delete_key($key);
2026-03-16 00:57:34 +01:00
$this->session->set_flashdata('notice', sprintf(__("API Key %s has been deleted"), "<b>" . htmlspecialchars($key, ENT_QUOTES, 'UTF-8') . "</b>" ));
Clubstations for Wavelog (#1334) * feat[clubstations]: New DB structure * feat[clubstations]: Add clubstationstable in user managment * feat[clubstations]: Show last operator * feat[clubstations]: Better solution for last operator. tnx for the hint @int2001 * feat[clubstations]: New Club Model and Controller * feat[clubstations]: Add "Add User" and "Edit User" functionality * docs[clubstations]: move comment * feat[clubstations]: Add "Delete Member" functionality * feat[clubstations]: some enhancements and javascript * fix[clubstations]: Wrong message class for flashmessages * feat[clubstations]: Added Switch in the Header menu (not functional yet) * feat[clubstations]: clubswitch modal * fix[clubstations]: Load encryption library if not already loaded * fix[clubstations]: Prevent direct login attempts to clubstations and enhance impersonation authorization * fix[clubstations]: Typo * feat[clubstations]: Only show the operator dialog if there is something fishy * fix[user]: little UI bug * feat[impersonate]: Add source uid to session data * fix[impersonate]: logic adjustment * feat[clubstations]: Add manage button in header menu for club officers * fix[clubstations]: typo in permission level check * fix[clubstations]: Full rights for the admin * feat[impersonate]: Custom sessiondata * feat[impersonate]: Implement stop impersonation feature with modal confirmation; "the way back" * fix(modal): Fix bug where modal was hidden when mouse leaved the browser content * docs(config): Adjust config description for special callsigns and clubstations * feat(club): Add club access check helper * typo * fix[impersonation]: Better text * feat(club): Selectize for a efficient user search * feat(clubstations): Restrict clubstations based on users permission level part 1/x * adjustments for dev merge * Adjusted club right for the advanced logbook * feat[user]: Refactoring of the Action Buttons in the user table * fix[club_permissions]: normal button instead small one for club permissions * remove unnecessary line break in modal body * feat[clubstations]: Add Club Mode badge to the header * fix[clubstations]: fix maintenance mode * allow switch back on http * feat(simplefle): display operator input based on club_access * small UI adjustments * small UI adjustments * moved api page to a index.php file and added support for clubstations * removed unused stuff * typo * radios and api keys * missed one binding * fix qso view, even officers do just see their own radios in QSO logging * omit the need for a relogin to see the changes as an admin * Omit the need for relogin after club changes in general. It's a question of UX. It's better to accept a little higher DB load (if clubstations are enabled) then the need of an user to relogin. There is some room for improvement by changing user_model->get_by_id() and adding a join there. This can be done later if we see that the load is too high * 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 * remove debug messages * better UI in header * found a typo * full access in clubstations for admins (if accessed via admin usertable) * adjusted text * adjusted text * adjust text * reduce required chars * bugfix: missing the correct authentication in case the admin was not member of the club. he wasn't able to switch back * reduce debug messages * fixed UI bug related to tooltips * load js in controller * upps.. * some UI adjustments * corrected permissions * if user gets delete we need to remove data in club_permissions and also api keys which were created by this user * Notify members about new memberships or changes in permission level * add spinner to save button * make login/logout process more bulletproof * remove the relogin cookie after the attempt * better strategy * bug where switch back failed if user is no admin * make api keys more secure * mask not owned api keys * removed annoying link * if a user gets removed from a club we also should delete the corresponding api keys and cat radios * adjusted wiki link * Auto creation of logbook and location when new user is created * store and display locator in uppercase * same for callsign * fixed a bug in user/club creation * Revert "Auto creation of logbook and location when new user is created" We found another solution to which will be addressed in a second PR This reverts commit f05f4b7bf0423a88abf0087ade81fe613d217794. * Optimized SQL for stats at userlist * Source query for lastop "out", because mysql<9.0 can't handle Windowed functions * adjust migration * add new columns to users table to get created_at and modified_at * added a partial down function * add operator dropdown for clubstations * fix mig version * Add some backend restrictions in case a user wants to try something funny with the club --------- Co-authored-by: Andreas Kristiansen <6977712+AndreasK79@users.noreply.github.com> Co-authored-by: int2001 <joerg@dj7nt.de>
2025-01-02 10:22:23 +01:00
redirect('api');
}
// Example of authing
2024-11-20 17:33:17 +00:00
function auth($key = '') {
$this->load->model('api_model');
2017-11-30 19:01:11 -07:00
header("Content-type: text/xml");
2026-06-08 09:29:47 +02:00
if($this->api_model->authorize($key) == 0) {
echo "<auth>";
2024-08-28 14:29:26 +02:00
echo "<message>Key Invalid - either not found or disabled</message>";
echo "</auth>";
} else {
echo "<auth>";
2024-08-28 14:29:26 +02:00
echo "<status>Valid</status>";
echo "<rights>".$this->api_model->access($key)."</rights>";
echo "</auth>";
2024-01-13 18:17:35 +01:00
$this->api_model->update_last_used($key);
2011-12-09 17:35:48 +00:00
}
}
2025-11-16 11:06:56 +00:00
function create_station($key = '') {
2026-06-19 21:20:00 +08:00
header('Content-type: application/json');
2025-11-16 11:06:56 +00:00
$this->load->model('api_model');
2025-12-13 07:54:08 +00:00
$apiKeyResponse = $this->api_model->authorize($key ?? '');
if ($apiKeyResponse == 0) {
http_response_code(401);
2026-07-11 17:52:14 +02:00
log_message("Debug",'API Call 401. Invalid API Key: '.($key ?? 'N/A'));
echo json_encode(['status' => 'error', 'reason' => "missing or wrong api key"]);
die();
}
if ($apiKeyResponse == 1) {
http_response_code(403);
log_message("Debug",'API Call 403. Insufficient permissions for API Key');
echo json_encode(['status' => 'error', 'reason' => "API key does not have write permissions"]);
die();
2025-11-16 11:06:56 +00:00
}
2025-12-13 07:54:08 +00:00
$this->load->model('club_model');
$userid = $this->api_model->key_userid($key);
$created_by = $this->api_model->key_created_by($key);
$club_perm = $this->club_model->get_permission_noui($userid,$created_by);
if ($userid != $created_by) { // We're dealing with a Club Member/Member ADIF or Clubofficer
if ((($club_perm ?? 0) == 3) || (($club_perm ?? 0) == 6)) { // Member or ADIF-Member? DENY
$this->output->set_status_header(401)->set_content_type('application/json')->set_output(json_encode(['status' => 'error', 'message' => 'Auth Error, not enough grants for this operation']));
return;
}
}
2025-11-16 11:06:56 +00:00
try {
$raw = file_get_contents("php://input");
if ($raw === false) {
throw new Exception("Failed to read input data");
}
if (empty($raw)) {
$this->output->set_status_header(400)->set_content_type('application/json')->set_output(json_encode(['status' => 'error', 'message' => 'No file uploaded']));
return;
}
$raw = preg_replace('#<([eE][oO][rR])>[\r\n\t]+#', '<$1>', $raw);
if ($raw === null) {
throw new Exception("Regex processing failed");
}
$locations = json_decode($raw, true);
if ($locations === null) {
$this->output->set_status_header(400)->set_content_type('application/json')->set_output(json_encode(['status' => 'error', 'message' => 'Invalid JSON file']));
return;
}
2026-01-29 17:36:00 +00:00
// If a single station object is posted (not an array), wrap it in an array
if (isset($locations['station_callsign']) || isset($locations['station_profile_name'])) {
$locations = [$locations];
}
2025-11-16 11:06:56 +00:00
} catch (Exception $e) {
$this->output->set_status_header(500)->set_content_type('application/json')->set_output(json_encode(['status' => 'error', 'message' => 'Processing error: ' . $e->getMessage()]));
}
$this->load->model('stationsetup_model');
2026-07-11 17:52:14 +02:00
$imported = $this->stationsetup_model->import_locations_parse($locations ?? [], $userid);
2025-11-16 11:06:56 +00:00
if (($imported[0] ?? '0') == 'limit') {
2025-11-16 11:15:03 +00:00
$this->output->set_status_header(201)->set_content_type('application/json')->set_output(json_encode(['status' => 'success', 'message' => ($imported[1] ?? '0')." locations imported. Maximum limit of 1000 locations reached."]));
2025-11-16 11:06:56 +00:00
} else {
2025-11-16 11:15:03 +00:00
if (($imported[1] ?? 0) == 0) {
$this->output->set_status_header(200)->set_content_type('application/json')->set_output(json_encode(['status' => 'dupe', 'message' => ($imported[1] ?? '0')." locations imported."]));
} else {
$this->output->set_status_header(201)->set_content_type('application/json')->set_output(json_encode(['status' => 'success', 'message' => ($imported[1] ?? '0')." locations imported."]));
}
2025-11-16 11:06:56 +00:00
}
}
function station_info($key = '') {
$this->load->model('api_model');
$this->load->model('stations');
header("Content-type: application/json");
2026-06-08 09:29:47 +02:00
if($this->api_model->authorize($key) > 0) { /* Check permission for reading */
$this->api_model->update_last_used($key);
$userid = $this->api_model->key_userid($key);
2024-01-17 17:30:14 +01:00
$station_ids = array();
2026-06-20 10:29:55 -07:00
$dkey_opt=$this->user_options_model->get_options('stations',array('option_name'=>'active_log_only','option_key'=>'boolean'), $userid)->result();
$user_stations_active_log_only = (count($dkey_opt)>0) ? $dkey_opt[0]->option_value : false;
if($user_stations_active_log_only) {
$stations = $this->logbooks_model->list_logbooks_linked($this->logbooks_model->find_active_station_logbook_from_userid($userid));
} else {
$stations=$this->stations->all_of_user($userid);
}
if($stations !== FALSE) {
foreach ($stations->result() as $row) {
$result['station_id']=$row->station_id;
$result['station_profile_name']=$row->station_profile_name;
$result['station_gridsquare']=$row->station_gridsquare;
$result['station_callsign']=$row->station_callsign;;
$result['station_active']=$row->station_active;
$result['station_uuid']=$row->station_uuid;
$result['station_city']=$row->station_city;
$result['station_iota']=$row->station_iota;
$result['station_sota']=$row->station_sota;
$result['station_wwff']=$row->station_wwff;
$result['station_pota']=$row->station_pota;
$result['station_sig']=$row->station_sig;
$result['station_sig_info']=$row->station_sig_info;
$result['station_dxcc']=$row->station_dxcc;
$result['station_cnty']=$row->station_cnty;
$result['station_cq']=$row->station_cq;
$result['station_itu']=$row->station_itu;
$result['station_state']=$row->state;
$result['station_country']=$row->station_country;
array_push($station_ids, $result);
}
2024-01-17 17:30:14 +01:00
}
echo json_encode($station_ids);
} else {
http_response_code(401);
echo json_encode(['status' => 'failed', 'reason' => "missing or invalid api key"]);
}
}
function check_auth($key = '') {
2025-05-29 10:09:38 +02:00
$this->load->model('api_model');
2026-06-08 09:29:47 +02:00
if($this->api_model->authorize($key ?? '') == 0) {
2025-05-29 10:09:38 +02:00
// set the content type as json
header("Content-type: application/json");
// set the http response code to 401
http_response_code(401);
// return the json with the status as failed
echo json_encode(['status' => 'failed', 'reason' => "missing or invalid api key"]);
} else {
// set the content type as json
header("Content-type: application/json");
// set the http response code to 200
http_response_code(200);
// return the json
echo json_encode(['status' => 'valid', 'rights' => $this->api_model->access($key ?? '')]);
2025-05-29 10:09:38 +02:00
}
}
2024-01-17 17:30:14 +01:00
/*
*
* Function: QSO
* Task: allows passing of ADIF data to Wavelog
*/
function qso($dryrun = false) {
header('Content-type: application/json');
set_time_limit(0);
ini_set('memory_limit', '-1');
session_write_close();
$this->load->model('api_model');
2023-06-15 08:12:57 +02:00
$this->load->model('stations');
2025-12-13 07:27:04 +00:00
$this->load->model('club_model');
2023-06-15 08:12:57 +02:00
2024-12-30 14:16:33 +00:00
if (!$this->load->is_loaded('Qra')) {
$this->load->library('Qra');
}
$return_msg = array();
$return_count = 0;
// Decode JSON and store
$raw = file_get_contents("php://input");
$raw = $raw = preg_replace('#<([eE][oO][rR])>[\r\n\t]+#', '<$1>', $raw);
$obj = json_decode($raw,true);
if ($obj === NULL) {
2025-04-25 14:42:35 +00:00
log_message("Debug",'API Call 200. Wrong JSON provided: '.$raw);
echo json_encode(['status' => 'failed', 'reason' => "wrong JSON"]);
die();
}
// Check rate limit
$identifier = isset($obj['key']) ? $obj['key'] : null;
$this->check_rate_limit('qso', $identifier);
2025-04-25 14:42:35 +00:00
$raw='';
$apiKeyResponse = $this->api_model->authorize($obj['key'] ?? '');
if (!isset($obj['key']) || $apiKeyResponse == 0) {
http_response_code(401);
2025-04-25 14:42:35 +00:00
log_message("Debug",'API Call 401. Invalid API Key: '.($obj['key'] ?? 'N/A'));
2024-11-02 09:24:02 +01:00
echo json_encode(['status' => 'failed', 'reason' => "missing or wrong api key"]);
die();
}
if ($apiKeyResponse == 1) {
http_response_code(403);
log_message("Debug",'API Call 403. Insufficient permissions for API Key');
echo json_encode(['status' => 'failed', 'reason' => "API key does not have write permissions"]);
die();
}
2023-06-15 08:12:57 +02:00
$userid = $this->api_model->key_userid($obj['key']);
Clubstations for Wavelog (#1334) * feat[clubstations]: New DB structure * feat[clubstations]: Add clubstationstable in user managment * feat[clubstations]: Show last operator * feat[clubstations]: Better solution for last operator. tnx for the hint @int2001 * feat[clubstations]: New Club Model and Controller * feat[clubstations]: Add "Add User" and "Edit User" functionality * docs[clubstations]: move comment * feat[clubstations]: Add "Delete Member" functionality * feat[clubstations]: some enhancements and javascript * fix[clubstations]: Wrong message class for flashmessages * feat[clubstations]: Added Switch in the Header menu (not functional yet) * feat[clubstations]: clubswitch modal * fix[clubstations]: Load encryption library if not already loaded * fix[clubstations]: Prevent direct login attempts to clubstations and enhance impersonation authorization * fix[clubstations]: Typo * feat[clubstations]: Only show the operator dialog if there is something fishy * fix[user]: little UI bug * feat[impersonate]: Add source uid to session data * fix[impersonate]: logic adjustment * feat[clubstations]: Add manage button in header menu for club officers * fix[clubstations]: typo in permission level check * fix[clubstations]: Full rights for the admin * feat[impersonate]: Custom sessiondata * feat[impersonate]: Implement stop impersonation feature with modal confirmation; "the way back" * fix(modal): Fix bug where modal was hidden when mouse leaved the browser content * docs(config): Adjust config description for special callsigns and clubstations * feat(club): Add club access check helper * typo * fix[impersonation]: Better text * feat(club): Selectize for a efficient user search * feat(clubstations): Restrict clubstations based on users permission level part 1/x * adjustments for dev merge * Adjusted club right for the advanced logbook * feat[user]: Refactoring of the Action Buttons in the user table * fix[club_permissions]: normal button instead small one for club permissions * remove unnecessary line break in modal body * feat[clubstations]: Add Club Mode badge to the header * fix[clubstations]: fix maintenance mode * allow switch back on http * feat(simplefle): display operator input based on club_access * small UI adjustments * small UI adjustments * moved api page to a index.php file and added support for clubstations * removed unused stuff * typo * radios and api keys * missed one binding * fix qso view, even officers do just see their own radios in QSO logging * omit the need for a relogin to see the changes as an admin * Omit the need for relogin after club changes in general. It's a question of UX. It's better to accept a little higher DB load (if clubstations are enabled) then the need of an user to relogin. There is some room for improvement by changing user_model->get_by_id() and adding a join there. This can be done later if we see that the load is too high * 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 * remove debug messages * better UI in header * found a typo * full access in clubstations for admins (if accessed via admin usertable) * adjusted text * adjusted text * adjust text * reduce required chars * bugfix: missing the correct authentication in case the admin was not member of the club. he wasn't able to switch back * reduce debug messages * fixed UI bug related to tooltips * load js in controller * upps.. * some UI adjustments * corrected permissions * if user gets delete we need to remove data in club_permissions and also api keys which were created by this user * Notify members about new memberships or changes in permission level * add spinner to save button * make login/logout process more bulletproof * remove the relogin cookie after the attempt * better strategy * bug where switch back failed if user is no admin * make api keys more secure * mask not owned api keys * removed annoying link * if a user gets removed from a club we also should delete the corresponding api keys and cat radios * adjusted wiki link * Auto creation of logbook and location when new user is created * store and display locator in uppercase * same for callsign * fixed a bug in user/club creation * Revert "Auto creation of logbook and location when new user is created" We found another solution to which will be addressed in a second PR This reverts commit f05f4b7bf0423a88abf0087ade81fe613d217794. * Optimized SQL for stats at userlist * Source query for lastop "out", because mysql<9.0 can't handle Windowed functions * adjust migration * add new columns to users table to get created_at and modified_at * added a partial down function * add operator dropdown for clubstations * fix mig version * Add some backend restrictions in case a user wants to try something funny with the club --------- Co-authored-by: Andreas Kristiansen <6977712+AndreasK79@users.noreply.github.com> Co-authored-by: int2001 <joerg@dj7nt.de>
2025-01-02 10:22:23 +01:00
$created_by = $this->api_model->key_created_by($obj['key']);
2025-12-13 07:27:04 +00:00
$club_perm = $this->club_model->get_permission_noui($userid,$created_by);
Clubstations for Wavelog (#1334) * feat[clubstations]: New DB structure * feat[clubstations]: Add clubstationstable in user managment * feat[clubstations]: Show last operator * feat[clubstations]: Better solution for last operator. tnx for the hint @int2001 * feat[clubstations]: New Club Model and Controller * feat[clubstations]: Add "Add User" and "Edit User" functionality * docs[clubstations]: move comment * feat[clubstations]: Add "Delete Member" functionality * feat[clubstations]: some enhancements and javascript * fix[clubstations]: Wrong message class for flashmessages * feat[clubstations]: Added Switch in the Header menu (not functional yet) * feat[clubstations]: clubswitch modal * fix[clubstations]: Load encryption library if not already loaded * fix[clubstations]: Prevent direct login attempts to clubstations and enhance impersonation authorization * fix[clubstations]: Typo * feat[clubstations]: Only show the operator dialog if there is something fishy * fix[user]: little UI bug * feat[impersonate]: Add source uid to session data * fix[impersonate]: logic adjustment * feat[clubstations]: Add manage button in header menu for club officers * fix[clubstations]: typo in permission level check * fix[clubstations]: Full rights for the admin * feat[impersonate]: Custom sessiondata * feat[impersonate]: Implement stop impersonation feature with modal confirmation; "the way back" * fix(modal): Fix bug where modal was hidden when mouse leaved the browser content * docs(config): Adjust config description for special callsigns and clubstations * feat(club): Add club access check helper * typo * fix[impersonation]: Better text * feat(club): Selectize for a efficient user search * feat(clubstations): Restrict clubstations based on users permission level part 1/x * adjustments for dev merge * Adjusted club right for the advanced logbook * feat[user]: Refactoring of the Action Buttons in the user table * fix[club_permissions]: normal button instead small one for club permissions * remove unnecessary line break in modal body * feat[clubstations]: Add Club Mode badge to the header * fix[clubstations]: fix maintenance mode * allow switch back on http * feat(simplefle): display operator input based on club_access * small UI adjustments * small UI adjustments * moved api page to a index.php file and added support for clubstations * removed unused stuff * typo * radios and api keys * missed one binding * fix qso view, even officers do just see their own radios in QSO logging * omit the need for a relogin to see the changes as an admin * Omit the need for relogin after club changes in general. It's a question of UX. It's better to accept a little higher DB load (if clubstations are enabled) then the need of an user to relogin. There is some room for improvement by changing user_model->get_by_id() and adding a join there. This can be done later if we see that the load is too high * 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 * remove debug messages * better UI in header * found a typo * full access in clubstations for admins (if accessed via admin usertable) * adjusted text * adjusted text * adjust text * reduce required chars * bugfix: missing the correct authentication in case the admin was not member of the club. he wasn't able to switch back * reduce debug messages * fixed UI bug related to tooltips * load js in controller * upps.. * some UI adjustments * corrected permissions * if user gets delete we need to remove data in club_permissions and also api keys which were created by this user * Notify members about new memberships or changes in permission level * add spinner to save button * make login/logout process more bulletproof * remove the relogin cookie after the attempt * better strategy * bug where switch back failed if user is no admin * make api keys more secure * mask not owned api keys * removed annoying link * if a user gets removed from a club we also should delete the corresponding api keys and cat radios * adjusted wiki link * Auto creation of logbook and location when new user is created * store and display locator in uppercase * same for callsign * fixed a bug in user/club creation * Revert "Auto creation of logbook and location when new user is created" We found another solution to which will be addressed in a second PR This reverts commit f05f4b7bf0423a88abf0087ade81fe613d217794. * Optimized SQL for stats at userlist * Source query for lastop "out", because mysql<9.0 can't handle Windowed functions * adjust migration * add new columns to users table to get created_at and modified_at * added a partial down function * add operator dropdown for clubstations * fix mig version * Add some backend restrictions in case a user wants to try something funny with the club --------- Co-authored-by: Andreas Kristiansen <6977712+AndreasK79@users.noreply.github.com> Co-authored-by: int2001 <joerg@dj7nt.de>
2025-01-02 10:22:23 +01:00
/**
* As the API key user could use it also for clubstations we need to do an additional check here. Only if clubstations are enabled
2025-02-13 11:50:06 +01:00
*
Clubstations for Wavelog (#1334) * feat[clubstations]: New DB structure * feat[clubstations]: Add clubstationstable in user managment * feat[clubstations]: Show last operator * feat[clubstations]: Better solution for last operator. tnx for the hint @int2001 * feat[clubstations]: New Club Model and Controller * feat[clubstations]: Add "Add User" and "Edit User" functionality * docs[clubstations]: move comment * feat[clubstations]: Add "Delete Member" functionality * feat[clubstations]: some enhancements and javascript * fix[clubstations]: Wrong message class for flashmessages * feat[clubstations]: Added Switch in the Header menu (not functional yet) * feat[clubstations]: clubswitch modal * fix[clubstations]: Load encryption library if not already loaded * fix[clubstations]: Prevent direct login attempts to clubstations and enhance impersonation authorization * fix[clubstations]: Typo * feat[clubstations]: Only show the operator dialog if there is something fishy * fix[user]: little UI bug * feat[impersonate]: Add source uid to session data * fix[impersonate]: logic adjustment * feat[clubstations]: Add manage button in header menu for club officers * fix[clubstations]: typo in permission level check * fix[clubstations]: Full rights for the admin * feat[impersonate]: Custom sessiondata * feat[impersonate]: Implement stop impersonation feature with modal confirmation; "the way back" * fix(modal): Fix bug where modal was hidden when mouse leaved the browser content * docs(config): Adjust config description for special callsigns and clubstations * feat(club): Add club access check helper * typo * fix[impersonation]: Better text * feat(club): Selectize for a efficient user search * feat(clubstations): Restrict clubstations based on users permission level part 1/x * adjustments for dev merge * Adjusted club right for the advanced logbook * feat[user]: Refactoring of the Action Buttons in the user table * fix[club_permissions]: normal button instead small one for club permissions * remove unnecessary line break in modal body * feat[clubstations]: Add Club Mode badge to the header * fix[clubstations]: fix maintenance mode * allow switch back on http * feat(simplefle): display operator input based on club_access * small UI adjustments * small UI adjustments * moved api page to a index.php file and added support for clubstations * removed unused stuff * typo * radios and api keys * missed one binding * fix qso view, even officers do just see their own radios in QSO logging * omit the need for a relogin to see the changes as an admin * Omit the need for relogin after club changes in general. It's a question of UX. It's better to accept a little higher DB load (if clubstations are enabled) then the need of an user to relogin. There is some room for improvement by changing user_model->get_by_id() and adding a join there. This can be done later if we see that the load is too high * 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 * remove debug messages * better UI in header * found a typo * full access in clubstations for admins (if accessed via admin usertable) * adjusted text * adjusted text * adjust text * reduce required chars * bugfix: missing the correct authentication in case the admin was not member of the club. he wasn't able to switch back * reduce debug messages * fixed UI bug related to tooltips * load js in controller * upps.. * some UI adjustments * corrected permissions * if user gets delete we need to remove data in club_permissions and also api keys which were created by this user * Notify members about new memberships or changes in permission level * add spinner to save button * make login/logout process more bulletproof * remove the relogin cookie after the attempt * better strategy * bug where switch back failed if user is no admin * make api keys more secure * mask not owned api keys * removed annoying link * if a user gets removed from a club we also should delete the corresponding api keys and cat radios * adjusted wiki link * Auto creation of logbook and location when new user is created * store and display locator in uppercase * same for callsign * fixed a bug in user/club creation * Revert "Auto creation of logbook and location when new user is created" We found another solution to which will be addressed in a second PR This reverts commit f05f4b7bf0423a88abf0087ade81fe613d217794. * Optimized SQL for stats at userlist * Source query for lastop "out", because mysql<9.0 can't handle Windowed functions * adjust migration * add new columns to users table to get created_at and modified_at * added a partial down function * add operator dropdown for clubstations * fix mig version * Add some backend restrictions in case a user wants to try something funny with the club --------- Co-authored-by: Andreas Kristiansen <6977712+AndreasK79@users.noreply.github.com> Co-authored-by: int2001 <joerg@dj7nt.de>
2025-01-02 10:22:23 +01:00
* 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
*/
2025-12-13 07:27:04 +00:00
$real_operator = null; // real_operator is only filled if its a clubstation and the used key is created by an OP. otherwise its null
Clubstations for Wavelog (#1334) * feat[clubstations]: New DB structure * feat[clubstations]: Add clubstationstable in user managment * feat[clubstations]: Show last operator * feat[clubstations]: Better solution for last operator. tnx for the hint @int2001 * feat[clubstations]: New Club Model and Controller * feat[clubstations]: Add "Add User" and "Edit User" functionality * docs[clubstations]: move comment * feat[clubstations]: Add "Delete Member" functionality * feat[clubstations]: some enhancements and javascript * fix[clubstations]: Wrong message class for flashmessages * feat[clubstations]: Added Switch in the Header menu (not functional yet) * feat[clubstations]: clubswitch modal * fix[clubstations]: Load encryption library if not already loaded * fix[clubstations]: Prevent direct login attempts to clubstations and enhance impersonation authorization * fix[clubstations]: Typo * feat[clubstations]: Only show the operator dialog if there is something fishy * fix[user]: little UI bug * feat[impersonate]: Add source uid to session data * fix[impersonate]: logic adjustment * feat[clubstations]: Add manage button in header menu for club officers * fix[clubstations]: typo in permission level check * fix[clubstations]: Full rights for the admin * feat[impersonate]: Custom sessiondata * feat[impersonate]: Implement stop impersonation feature with modal confirmation; "the way back" * fix(modal): Fix bug where modal was hidden when mouse leaved the browser content * docs(config): Adjust config description for special callsigns and clubstations * feat(club): Add club access check helper * typo * fix[impersonation]: Better text * feat(club): Selectize for a efficient user search * feat(clubstations): Restrict clubstations based on users permission level part 1/x * adjustments for dev merge * Adjusted club right for the advanced logbook * feat[user]: Refactoring of the Action Buttons in the user table * fix[club_permissions]: normal button instead small one for club permissions * remove unnecessary line break in modal body * feat[clubstations]: Add Club Mode badge to the header * fix[clubstations]: fix maintenance mode * allow switch back on http * feat(simplefle): display operator input based on club_access * small UI adjustments * small UI adjustments * moved api page to a index.php file and added support for clubstations * removed unused stuff * typo * radios and api keys * missed one binding * fix qso view, even officers do just see their own radios in QSO logging * omit the need for a relogin to see the changes as an admin * Omit the need for relogin after club changes in general. It's a question of UX. It's better to accept a little higher DB load (if clubstations are enabled) then the need of an user to relogin. There is some room for improvement by changing user_model->get_by_id() and adding a join there. This can be done later if we see that the load is too high * 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 * remove debug messages * better UI in header * found a typo * full access in clubstations for admins (if accessed via admin usertable) * adjusted text * adjusted text * adjust text * reduce required chars * bugfix: missing the correct authentication in case the admin was not member of the club. he wasn't able to switch back * reduce debug messages * fixed UI bug related to tooltips * load js in controller * upps.. * some UI adjustments * corrected permissions * if user gets delete we need to remove data in club_permissions and also api keys which were created by this user * Notify members about new memberships or changes in permission level * add spinner to save button * make login/logout process more bulletproof * remove the relogin cookie after the attempt * better strategy * bug where switch back failed if user is no admin * make api keys more secure * mask not owned api keys * removed annoying link * if a user gets removed from a club we also should delete the corresponding api keys and cat radios * adjusted wiki link * Auto creation of logbook and location when new user is created * store and display locator in uppercase * same for callsign * fixed a bug in user/club creation * Revert "Auto creation of logbook and location when new user is created" We found another solution to which will be addressed in a second PR This reverts commit f05f4b7bf0423a88abf0087ade81fe613d217794. * Optimized SQL for stats at userlist * Source query for lastop "out", because mysql<9.0 can't handle Windowed functions * adjust migration * add new columns to users table to get created_at and modified_at * added a partial down function * add operator dropdown for clubstations * fix mig version * Add some backend restrictions in case a user wants to try something funny with the club --------- Co-authored-by: Andreas Kristiansen <6977712+AndreasK79@users.noreply.github.com> Co-authored-by: int2001 <joerg@dj7nt.de>
2025-01-02 10:22:23 +01:00
if ($this->config->item('special_callsign')) {
if ($userid != $created_by) {
$real_operator = $this->user_model->get_by_id($created_by)->row()->user_callsign;
} else {
$real_operator = null;
}
}
$this->api_model->update_last_used(($obj['key']));
2023-06-15 08:12:57 +02:00
if(!isset($obj['station_profile_id']) || $this->stations->check_station_against_user($obj['station_profile_id'], $userid) == false) {
2023-06-15 08:12:57 +02:00
http_response_code(401);
2025-04-25 14:42:35 +00:00
log_message("Debug",'API Call 401: Wrong station_id '.($obj['station_profile_id'] ?? 'N/A').' for User '.$userid);
2023-06-15 08:12:57 +02:00
echo json_encode(['status' => 'failed', 'reason' => "station id does not belong to the API key owner."]);
die();
}
2024-12-30 14:16:33 +00:00
$mystation=$this->stations->profile_clean($obj['station_profile_id']);
$mygrid=($mystation->station_gridsquare ?? '');
2023-06-15 08:12:57 +02:00
if($obj['type'] == "adif" && $obj['string'] != "") {
// Load the logbook model for adding QSO records
$this->load->model('logbook_model');
// Load ADIF Parser
2024-09-11 10:09:43 +02:00
if (!$this->load->is_loaded('adif_parser')) {
$this->load->library('adif_parser');
}
// Feed in the ADIF string
$this->adif_parser->feed($obj['string']);
$obj['string']='';
$return_msg=[];
$adif_count=0;
$adif_errors=0;
if( !($dryrun) && (isset($obj['station_profile_id']))) {
$custom_errors = "";
$alladif=[];
gc_collect_cycles();
while($record = $this->adif_parser->get_record()) {
if(!(isset($record['call'])) || (trim($record['call']) == '')) {
continue;
}
if(count($record) == 0) {
break;
Clubstations for Wavelog (#1334) * feat[clubstations]: New DB structure * feat[clubstations]: Add clubstationstable in user managment * feat[clubstations]: Show last operator * feat[clubstations]: Better solution for last operator. tnx for the hint @int2001 * feat[clubstations]: New Club Model and Controller * feat[clubstations]: Add "Add User" and "Edit User" functionality * docs[clubstations]: move comment * feat[clubstations]: Add "Delete Member" functionality * feat[clubstations]: some enhancements and javascript * fix[clubstations]: Wrong message class for flashmessages * feat[clubstations]: Added Switch in the Header menu (not functional yet) * feat[clubstations]: clubswitch modal * fix[clubstations]: Load encryption library if not already loaded * fix[clubstations]: Prevent direct login attempts to clubstations and enhance impersonation authorization * fix[clubstations]: Typo * feat[clubstations]: Only show the operator dialog if there is something fishy * fix[user]: little UI bug * feat[impersonate]: Add source uid to session data * fix[impersonate]: logic adjustment * feat[clubstations]: Add manage button in header menu for club officers * fix[clubstations]: typo in permission level check * fix[clubstations]: Full rights for the admin * feat[impersonate]: Custom sessiondata * feat[impersonate]: Implement stop impersonation feature with modal confirmation; "the way back" * fix(modal): Fix bug where modal was hidden when mouse leaved the browser content * docs(config): Adjust config description for special callsigns and clubstations * feat(club): Add club access check helper * typo * fix[impersonation]: Better text * feat(club): Selectize for a efficient user search * feat(clubstations): Restrict clubstations based on users permission level part 1/x * adjustments for dev merge * Adjusted club right for the advanced logbook * feat[user]: Refactoring of the Action Buttons in the user table * fix[club_permissions]: normal button instead small one for club permissions * remove unnecessary line break in modal body * feat[clubstations]: Add Club Mode badge to the header * fix[clubstations]: fix maintenance mode * allow switch back on http * feat(simplefle): display operator input based on club_access * small UI adjustments * small UI adjustments * moved api page to a index.php file and added support for clubstations * removed unused stuff * typo * radios and api keys * missed one binding * fix qso view, even officers do just see their own radios in QSO logging * omit the need for a relogin to see the changes as an admin * Omit the need for relogin after club changes in general. It's a question of UX. It's better to accept a little higher DB load (if clubstations are enabled) then the need of an user to relogin. There is some room for improvement by changing user_model->get_by_id() and adding a join there. This can be done later if we see that the load is too high * 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 * remove debug messages * better UI in header * found a typo * full access in clubstations for admins (if accessed via admin usertable) * adjusted text * adjusted text * adjust text * reduce required chars * bugfix: missing the correct authentication in case the admin was not member of the club. he wasn't able to switch back * reduce debug messages * fixed UI bug related to tooltips * load js in controller * upps.. * some UI adjustments * corrected permissions * if user gets delete we need to remove data in club_permissions and also api keys which were created by this user * Notify members about new memberships or changes in permission level * add spinner to save button * make login/logout process more bulletproof * remove the relogin cookie after the attempt * better strategy * bug where switch back failed if user is no admin * make api keys more secure * mask not owned api keys * removed annoying link * if a user gets removed from a club we also should delete the corresponding api keys and cat radios * adjusted wiki link * Auto creation of logbook and location when new user is created * store and display locator in uppercase * same for callsign * fixed a bug in user/club creation * Revert "Auto creation of logbook and location when new user is created" We found another solution to which will be addressed in a second PR This reverts commit f05f4b7bf0423a88abf0087ade81fe613d217794. * Optimized SQL for stats at userlist * Source query for lastop "out", because mysql<9.0 can't handle Windowed functions * adjust migration * add new columns to users table to get created_at and modified_at * added a partial down function * add operator dropdown for clubstations * fix mig version * Add some backend restrictions in case a user wants to try something funny with the club --------- Co-authored-by: Andreas Kristiansen <6977712+AndreasK79@users.noreply.github.com> Co-authored-by: int2001 <joerg@dj7nt.de>
2025-01-02 10:22:23 +01:00
}
// Handle slashed zeros
$record['call'] = str_replace('Ø', "0", $record['call']);
if (($record['operator'] ?? '') != '') {
$record['operator'] = str_replace('Ø', "0", $record['operator']);
}
if (($record['station_callsign'] ?? '') != '') {
$record['station_callsign'] = str_replace('Ø', "0", $record['station_callsign']);
}
if (($record['owner_callsign'] ?? '') != '') {
$record['owner_callsign'] = str_replace('Ø', "0", $record['owner_callsign']);
}
Clubstations for Wavelog (#1334) * feat[clubstations]: New DB structure * feat[clubstations]: Add clubstationstable in user managment * feat[clubstations]: Show last operator * feat[clubstations]: Better solution for last operator. tnx for the hint @int2001 * feat[clubstations]: New Club Model and Controller * feat[clubstations]: Add "Add User" and "Edit User" functionality * docs[clubstations]: move comment * feat[clubstations]: Add "Delete Member" functionality * feat[clubstations]: some enhancements and javascript * fix[clubstations]: Wrong message class for flashmessages * feat[clubstations]: Added Switch in the Header menu (not functional yet) * feat[clubstations]: clubswitch modal * fix[clubstations]: Load encryption library if not already loaded * fix[clubstations]: Prevent direct login attempts to clubstations and enhance impersonation authorization * fix[clubstations]: Typo * feat[clubstations]: Only show the operator dialog if there is something fishy * fix[user]: little UI bug * feat[impersonate]: Add source uid to session data * fix[impersonate]: logic adjustment * feat[clubstations]: Add manage button in header menu for club officers * fix[clubstations]: typo in permission level check * fix[clubstations]: Full rights for the admin * feat[impersonate]: Custom sessiondata * feat[impersonate]: Implement stop impersonation feature with modal confirmation; "the way back" * fix(modal): Fix bug where modal was hidden when mouse leaved the browser content * docs(config): Adjust config description for special callsigns and clubstations * feat(club): Add club access check helper * typo * fix[impersonation]: Better text * feat(club): Selectize for a efficient user search * feat(clubstations): Restrict clubstations based on users permission level part 1/x * adjustments for dev merge * Adjusted club right for the advanced logbook * feat[user]: Refactoring of the Action Buttons in the user table * fix[club_permissions]: normal button instead small one for club permissions * remove unnecessary line break in modal body * feat[clubstations]: Add Club Mode badge to the header * fix[clubstations]: fix maintenance mode * allow switch back on http * feat(simplefle): display operator input based on club_access * small UI adjustments * small UI adjustments * moved api page to a index.php file and added support for clubstations * removed unused stuff * typo * radios and api keys * missed one binding * fix qso view, even officers do just see their own radios in QSO logging * omit the need for a relogin to see the changes as an admin * Omit the need for relogin after club changes in general. It's a question of UX. It's better to accept a little higher DB load (if clubstations are enabled) then the need of an user to relogin. There is some room for improvement by changing user_model->get_by_id() and adding a join there. This can be done later if we see that the load is too high * 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 * remove debug messages * better UI in header * found a typo * full access in clubstations for admins (if accessed via admin usertable) * adjusted text * adjusted text * adjust text * reduce required chars * bugfix: missing the correct authentication in case the admin was not member of the club. he wasn't able to switch back * reduce debug messages * fixed UI bug related to tooltips * load js in controller * upps.. * some UI adjustments * corrected permissions * if user gets delete we need to remove data in club_permissions and also api keys which were created by this user * Notify members about new memberships or changes in permission level * add spinner to save button * make login/logout process more bulletproof * remove the relogin cookie after the attempt * better strategy * bug where switch back failed if user is no admin * make api keys more secure * mask not owned api keys * removed annoying link * if a user gets removed from a club we also should delete the corresponding api keys and cat radios * adjusted wiki link * Auto creation of logbook and location when new user is created * store and display locator in uppercase * same for callsign * fixed a bug in user/club creation * Revert "Auto creation of logbook and location when new user is created" We found another solution to which will be addressed in a second PR This reverts commit f05f4b7bf0423a88abf0087ade81fe613d217794. * Optimized SQL for stats at userlist * Source query for lastop "out", because mysql<9.0 can't handle Windowed functions * adjust migration * add new columns to users table to get created_at and modified_at * added a partial down function * add operator dropdown for clubstations * fix mig version * Add some backend restrictions in case a user wants to try something funny with the club --------- Co-authored-by: Andreas Kristiansen <6977712+AndreasK79@users.noreply.github.com> Co-authored-by: int2001 <joerg@dj7nt.de>
2025-01-02 10:22:23 +01:00
// 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 (key_exists('operator',$record) && $real_operator != null && ($record['operator'] == $record['station_callsign']) || ($recorded_operator == '')) {
Clubstations for Wavelog (#1334) * feat[clubstations]: New DB structure * feat[clubstations]: Add clubstationstable in user managment * feat[clubstations]: Show last operator * feat[clubstations]: Better solution for last operator. tnx for the hint @int2001 * feat[clubstations]: New Club Model and Controller * feat[clubstations]: Add "Add User" and "Edit User" functionality * docs[clubstations]: move comment * feat[clubstations]: Add "Delete Member" functionality * feat[clubstations]: some enhancements and javascript * fix[clubstations]: Wrong message class for flashmessages * feat[clubstations]: Added Switch in the Header menu (not functional yet) * feat[clubstations]: clubswitch modal * fix[clubstations]: Load encryption library if not already loaded * fix[clubstations]: Prevent direct login attempts to clubstations and enhance impersonation authorization * fix[clubstations]: Typo * feat[clubstations]: Only show the operator dialog if there is something fishy * fix[user]: little UI bug * feat[impersonate]: Add source uid to session data * fix[impersonate]: logic adjustment * feat[clubstations]: Add manage button in header menu for club officers * fix[clubstations]: typo in permission level check * fix[clubstations]: Full rights for the admin * feat[impersonate]: Custom sessiondata * feat[impersonate]: Implement stop impersonation feature with modal confirmation; "the way back" * fix(modal): Fix bug where modal was hidden when mouse leaved the browser content * docs(config): Adjust config description for special callsigns and clubstations * feat(club): Add club access check helper * typo * fix[impersonation]: Better text * feat(club): Selectize for a efficient user search * feat(clubstations): Restrict clubstations based on users permission level part 1/x * adjustments for dev merge * Adjusted club right for the advanced logbook * feat[user]: Refactoring of the Action Buttons in the user table * fix[club_permissions]: normal button instead small one for club permissions * remove unnecessary line break in modal body * feat[clubstations]: Add Club Mode badge to the header * fix[clubstations]: fix maintenance mode * allow switch back on http * feat(simplefle): display operator input based on club_access * small UI adjustments * small UI adjustments * moved api page to a index.php file and added support for clubstations * removed unused stuff * typo * radios and api keys * missed one binding * fix qso view, even officers do just see their own radios in QSO logging * omit the need for a relogin to see the changes as an admin * Omit the need for relogin after club changes in general. It's a question of UX. It's better to accept a little higher DB load (if clubstations are enabled) then the need of an user to relogin. There is some room for improvement by changing user_model->get_by_id() and adding a join there. This can be done later if we see that the load is too high * 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 * remove debug messages * better UI in header * found a typo * full access in clubstations for admins (if accessed via admin usertable) * adjusted text * adjusted text * adjust text * reduce required chars * bugfix: missing the correct authentication in case the admin was not member of the club. he wasn't able to switch back * reduce debug messages * fixed UI bug related to tooltips * load js in controller * upps.. * some UI adjustments * corrected permissions * if user gets delete we need to remove data in club_permissions and also api keys which were created by this user * Notify members about new memberships or changes in permission level * add spinner to save button * make login/logout process more bulletproof * remove the relogin cookie after the attempt * better strategy * bug where switch back failed if user is no admin * make api keys more secure * mask not owned api keys * removed annoying link * if a user gets removed from a club we also should delete the corresponding api keys and cat radios * adjusted wiki link * Auto creation of logbook and location when new user is created * store and display locator in uppercase * same for callsign * fixed a bug in user/club creation * Revert "Auto creation of logbook and location when new user is created" We found another solution to which will be addressed in a second PR This reverts commit f05f4b7bf0423a88abf0087ade81fe613d217794. * Optimized SQL for stats at userlist * Source query for lastop "out", because mysql<9.0 can't handle Windowed functions * adjust migration * add new columns to users table to get created_at and modified_at * added a partial down function * add operator dropdown for clubstations * fix mig version * Add some backend restrictions in case a user wants to try something funny with the club --------- Co-authored-by: Andreas Kristiansen <6977712+AndreasK79@users.noreply.github.com> Co-authored-by: int2001 <joerg@dj7nt.de>
2025-01-02 10:22:23 +01:00
$record['operator'] = $real_operator;
}
2025-02-13 11:50:06 +01:00
2025-12-13 07:27:04 +00:00
// in case the caller is an OP for a clubstation (real_operator is filled - see above) and the OP only has level 3 or 6 - take the OP from real_operator!
if ($real_operator != null && ((($club_perm ?? 0) == 3) || (($club_perm ?? 0) == 6))) {
$record['operator'] = $real_operator;
}
2024-12-30 14:16:33 +00:00
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();
2025-10-07 04:11:50 +00:00
$result = $this->logbook_model->import_bulk($alladif, $obj['station_profile_id'], true, false, false, false, false, false, false, false, true, false, true, false);
$custom_errors = $result['errormessage'];
if ($custom_errors) {
$adif_errors++;
}
$alladif=[];
$return_msg[]='';
} else {
$return_msg[]='Dryrun works';
}
if ($adif_errors == 0) {
http_response_code(201);
2025-04-25 14:42:35 +00:00
log_message("Debug",'API Call 201: QSO created for Station-ID: '.($obj['station_profile_id'] ?? 'N/A').' and User: '.$userid);
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;
2025-04-25 14:42:35 +00:00
log_message("Debug",'API Call 400: QSO NOT created for Station-ID: '.($obj['station_profile_id'] ?? 'N/A').' and User: '.$userid.' Reason: '.implode($return_msg));
http_response_code(400);
2024-12-29 09:22:26 +00:00
echo json_encode(['status' => 'abort', 'type' => $obj['type'], 'string' => $obj['string'], 'adif_count' => $adif_count, 'adif_errors' => $adif_errors, 'messages' => $return_msg ]);
}
}
}
/*
*
* Function: get_contacts_adif
* Task: allows third party software to pull ADIF QSO data from wavelog after a baseline of the last fetched QSO id
*/
function get_contacts_adif() {
//set header
header('Content-type: application/json');
//load API model
$this->load->model('api_model');
// Decode JSON and store
$obj = json_decode(file_get_contents("php://input"), true);
if ($obj === NULL) {
http_response_code(400);
echo json_encode(['status' => 'failed', 'reason' => "wrong JSON"]);
return;
}
$identifier = isset($obj['key']) ? $obj['key'] : null;
$this->check_rate_limit('get_contacts_adif', $identifier);
//do authorization
if(!isset($obj['key']) || $this->api_model->authorize($obj['key']) == 0) {
http_response_code(401);
echo json_encode(['status' => 'failed', 'reason' => "missing api key"]);
return;
}
//check for relevant fields in JSON input
if(!isset($obj['station_id']) or !isset($obj['fetchfromid']))
{
http_response_code(400);
echo json_encode(['status' => 'failed', 'reason' => "Not all required fields were present in input JSON"]);
return;
}
//extract relevant data to variables
$key = $obj['key'];
$fetchfromid = $obj['fetchfromid'];
$req_station_ids = is_array($obj['station_id']) ? $obj['station_id'] : [$obj['station_id']];
if (empty($req_station_ids)) {
http_response_code(400);
echo json_encode(['status' => 'failed', 'reason' => '"station_id" must not be empty']);
return;
}
$normalized_station_ids = [];
foreach ($req_station_ids as $sid) {
if (!is_numeric($sid)) {
http_response_code(400);
echo json_encode(['status' => 'failed', 'reason' => '"station_id" values must be numeric']);
return;
}
$normalized_station_ids[] = (int)$sid;
}
$req_station_ids = array_values(array_unique($normalized_station_ids));
$limit = 20000;
if ( (array_key_exists('limit',$obj)) && (is_numeric($obj['limit']*1)) ) {
$limit = $obj['limit'];
}
2026-04-01 07:55:00 +00:00
// output_format (optional, default: adif)
$output_format = 'adif';
if (isset($obj['output_format'])) {
if (!in_array($obj['output_format'], ['adif', 'json'], true)) {
http_response_code(400);
echo json_encode(['status' => 'failed', 'reason' => 'Invalid output_format. Use "adif" or "json"']);
return;
}
$output_format = $obj['output_format'];
}
$fields = null;
if (isset($obj['fields'])) {
if ($output_format !== 'json') {
http_response_code(400);
echo json_encode(['status' => 'failed', 'reason' => '"fields" is only valid when output_format is "json"']);
return;
}
if (!is_array($obj['fields']) || empty($obj['fields'])) {
http_response_code(400);
echo json_encode(['status' => 'failed', 'reason' => '"fields" must be a non-empty array']);
return;
}
$requested_fields = array_map('strtoupper', $obj['fields']);
$valid_adif_fields = ['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','EQSL_AG','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','QRZCOM_QSO_DOWNLOAD_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','DCL_QSL_RCVD','DCL_QSL_SENT','EQSL_QSLRDATE','EQSL_QSLSDATE','LOTW_QSLRDATE','LOTW_QSLSDATE','QSLRDATE','QSLSDATE','CLUBLOG_QSO_UPLOAD_DATE','HRDLOG_QSO_UPLOAD_DATE','QRZCOM_QSO_UPLOAD_DATE','QRZCOM_QSO_DOWNLOAD_DATE','DCL_QSLRDATE','DCL_QSLSDATE','FREQ','FREQ_RX','QSO_DATE','TIME_ON','QSO_DATE_OFF','TIME_OFF','STATION_CALLSIGN','MY_CITY','MY_COUNTRY','MY_DXCC','MY_GRIDSQUARE','MY_VUCC_GRIDS','MY_IOTA','MY_SOTA_REF','MY_WWFF_REF','MY_POTA_REF','MY_CQ_ZONE','MY_ITU_ZONE','MY_STATE','MY_CNTY','MY_SIG','MY_SIG_INFO','SIG','SIG_INFO','MY_ANTENNA','MY_ANTENNA_INTL'];
2026-04-01 07:55:00 +00:00
$invalid_fields = array_diff($requested_fields, $valid_adif_fields);
if (!empty($invalid_fields)) {
http_response_code(400);
echo json_encode(['status' => 'failed', 'reason' => 'Unknown fields: ' . implode(', ', $invalid_fields)]);
return;
}
$fields = $requested_fields;
}
$qsl_filter = null;
if (isset($obj['qsl_filter'])) {
$allowed_qsl = ['lotw', 'qsl', 'eqsl', 'clublog'];
if (!is_array($obj['qsl_filter']) || empty($obj['qsl_filter'])) {
http_response_code(400);
echo json_encode(['status' => 'failed', 'reason' => '"qsl_filter" must be a non-empty array']);
return;
}
$qsl_filter_input = array_map('strtolower', $obj['qsl_filter']);
$invalid_qsl = array_diff($qsl_filter_input, $allowed_qsl);
if (!empty($invalid_qsl)) {
http_response_code(400);
echo json_encode(['status' => 'failed', 'reason' => 'Invalid qsl_filter values: ' . implode(', ', $invalid_qsl)]);
return;
}
$qsl_filter = $qsl_filter_input;
}
2026-04-01 09:04:04 +00:00
// band (optional)
$band = null;
if (isset($obj['band'])) {
$valid_bands = ['160m','80m','60m','40m','30m','20m','17m','15m','12m','10m','6m','4m','2m','1.25m','70cm','33cm','23cm','13cm','9cm','6cm','3cm','1.25cm','sat'];
$band_input = strtolower(trim($obj['band']));
if (!in_array($band_input, $valid_bands, true)) {
http_response_code(400);
echo json_encode(['status' => 'failed', 'reason' => 'Invalid band value']);
return;
}
// Normalize: SAT uppercase (matches COL_PROP_MODE stored value), others lowercase (matches COL_BAND)
$band = ($band_input === 'sat') ? 'SAT' : $band_input;
}
2024-07-30 15:15:23 +00:00
//check if goalpost is numeric as an additional layer of SQL injection prevention
if(!is_numeric($fetchfromid))
2024-07-30 15:15:23 +00:00
{
http_response_code(400);
echo json_encode(['status' => 'failed', 'reason' => "Invalid fetchfromid."]);
2024-07-30 15:15:23 +00:00
return;
}
//make sure the goalpost is an integer
$fetchfromid = (int)$fetchfromid;
2024-07-30 15:15:23 +00:00
//load stations API
$this->load->model('stations');
//get all stations of user to check if station_id should be readable
$userid = $this->api_model->key_userid($key);
$station_ids = array();
$stations=$this->stations->all_of_user($userid);
//extract to array
foreach ($stations->result() as $row) {
array_push($station_ids, $row->station_id);
}
foreach ($req_station_ids as $station_id) {
if (!in_array($station_id, $station_ids)) {
http_response_code(401);
echo json_encode(['status' => 'failed', 'reason' => "Station ID not accessible for this API key"]);
return;
}
}
//load adif data module
$this->load->model('adif_data');
2025-12-05 06:57:14 +00:00
$this->load->library('AdifHelper');
// Initialize tracking variables
$total_fetched = 0;
$all_qso_ids = [];
$lastfetchedid = $fetchfromid;
// Process in chunks to avoid memory issues
$chunk_size = 5000;
$remaining_limit = $limit;
$offset = 0;
2026-04-01 07:55:00 +00:00
$adif_content = ($output_format === 'adif') ? $this->adifhelper->getAdifHeader($this->config->item('app_name'), $this->optionslib->get_option('version'), $this->optionslib->get_option('adif_version')) : '';
$qso_rows = [];
2025-12-05 06:57:14 +00:00
$seen_keys = [];
2025-12-05 06:57:14 +00:00
do {
// Calculate chunk size for this iteration
$current_chunk_size = min($chunk_size, $remaining_limit);
// Fetch chunk
$qsos = $this->adif_data->export_past_id_chunked($req_station_ids, $fetchfromid, $current_chunk_size, null, $offset, $current_chunk_size, $qsl_filter, $band);
2025-12-05 06:57:14 +00:00
if ($qsos && $qsos->num_rows() > 0) {
// Process chunk
foreach ($qsos->result() as $row) {
2026-04-01 07:55:00 +00:00
if ($output_format === 'json') {
$qso_data = $this->_build_qso_array($row, $fields);
if ($fields !== null) {
$unique_key = '';
foreach ($fields as $field) {
$unique_key .= (isset($qso_data[$field]) ? $qso_data[$field] : '') . '|';
}
if (!isset($seen_keys[$unique_key])) {
$seen_keys[$unique_key] = true;
$qso_rows[] = $qso_data;
}
} else {
$qso_rows[] = $qso_data;
}
2026-04-01 07:55:00 +00:00
} else {
$adif_content .= $this->adifhelper->getAdifLine($row);
}
2025-12-05 06:57:14 +00:00
// Track data for response
$all_qso_ids[] = $row->COL_PRIMARY_KEY;
$lastfetchedid = max($lastfetchedid, $row->COL_PRIMARY_KEY);
$total_fetched++;
}
2025-12-05 06:57:14 +00:00
// Free memory
$qsos->free_result();
2025-02-13 11:50:06 +01:00
2025-12-05 06:57:14 +00:00
// Update tracking
$remaining_limit -= $qsos->num_rows();
$offset += $qsos->num_rows();
2025-02-13 11:50:06 +01:00
2025-12-05 06:57:14 +00:00
// Stop if we've hit the requested limit
if ($total_fetched >= $limit) {
break;
}
}
2025-12-05 06:57:14 +00:00
// Continue if we got a full chunk and haven't hit the limit
} while ($qsos && $qsos->num_rows() > 0 && $total_fetched < $limit);
2026-04-01 07:55:00 +00:00
// Return response
http_response_code(200);
if ($total_fetched <= 0) {
2026-04-01 12:25:50 +02:00
echo json_encode(['status' => 'successful', 'message' => 'No new QSOs available.', 'lastfetchedid' => $fetchfromid, 'exported_qsos' => 0, 'adif' => null]);
2026-04-01 07:55:00 +00:00
} elseif ($output_format === 'json') {
2026-04-01 12:29:27 +02:00
echo json_encode(['status' => 'successful', 'message' => 'Export successful', 'lastfetchedid' => $lastfetchedid, 'exported_records' => count($qso_rows), 'qsos' => $qso_rows]);
2025-12-05 06:57:14 +00:00
} else {
2026-04-01 12:25:50 +02:00
echo json_encode(['status' => 'successful', 'message' => 'Export successful', 'lastfetchedid' => $lastfetchedid, 'exported_qsos' => $total_fetched, 'adif' => $adif_content]);
2025-02-13 11:50:06 +01:00
}
}
2026-04-01 07:55:00 +00:00
private function _build_qso_array($qso, $fields = null) {
$result = [];
$normalFields = ['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','EQSL_AG','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','QRZCOM_QSO_DOWNLOAD_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','DCL_QSL_RCVD','DCL_QSL_SENT','MY_ANTENNA','MY_ANTENNA_INTL'];
$dateFields = ['EQSL_QSLRDATE','EQSL_QSLSDATE','LOTW_QSLRDATE','LOTW_QSLSDATE','QSLRDATE','QSLSDATE','CLUBLOG_QSO_UPLOAD_DATE','HRDLOG_QSO_UPLOAD_DATE','QRZCOM_QSO_UPLOAD_DATE','QRZCOM_QSO_DOWNLOAD_DATE','DCL_QSLRDATE','DCL_QSLSDATE'];
2026-04-01 07:55:00 +00:00
foreach ($normalFields as $f) {
$result[$f] = $qso->{'COL_' . $f};
}
foreach ($dateFields as $f) {
$val = $qso->{'COL_' . $f};
$result[$f] = $val ? date('Ymd', strtotime($val)) : null;
}
$result['FREQ'] = $qso->COL_FREQ ? $qso->COL_FREQ / 1000000 : null;
$result['FREQ_RX'] = $qso->COL_FREQ_RX ? $qso->COL_FREQ_RX / 1000000 : null;
if (isset($qso->COL_TIME_ON) && date('YmdHis', strtotime($qso->COL_TIME_ON)) !== '-00011130000000') {
$result['QSO_DATE'] = date('Ymd', strtotime($qso->COL_TIME_ON));
$result['TIME_ON'] = date('His', strtotime($qso->COL_TIME_ON));
} else {
$result['QSO_DATE'] = '19700101';
$result['TIME_ON'] = '000000';
}
if (isset($qso->COL_TIME_OFF) && date('YmdHis', strtotime($qso->COL_TIME_OFF)) !== '-00011130000000') {
$result['QSO_DATE_OFF'] = date('Ymd', strtotime($qso->COL_TIME_OFF));
$result['TIME_OFF'] = date('His', strtotime($qso->COL_TIME_OFF));
} else {
$result['QSO_DATE_OFF'] = '19700101';
$result['TIME_OFF'] = '000000';
}
$result['STATION_CALLSIGN'] = $qso->station_callsign;
$result['MY_CITY'] = $qso->station_city;
$result['MY_COUNTRY'] = $qso->station_country;
$result['MY_DXCC'] = $qso->station_dxcc;
if (strpos($qso->station_gridsquare, ',') !== false) {
$result['MY_VUCC_GRIDS'] = $qso->station_gridsquare;
$result['MY_GRIDSQUARE'] = null;
} else {
$result['MY_GRIDSQUARE'] = $qso->station_gridsquare;
$result['MY_VUCC_GRIDS'] = null;
}
$result['MY_IOTA'] = $qso->station_iota;
$result['MY_SOTA_REF'] = $qso->station_sota;
$result['MY_WWFF_REF'] = $qso->station_wwff;
$result['MY_POTA_REF'] = $qso->station_pota;
$result['MY_CQ_ZONE'] = $qso->station_cq;
$result['MY_ITU_ZONE'] = $qso->station_itu;
$result['MY_STATE'] = $qso->state;
if ($qso->station_cnty) {
switch ($qso->station_dxcc) {
case '6': case '110': case '291':
$result['MY_CNTY'] = trim($qso->state) . ',' . trim($qso->station_cnty);
break;
default:
$result['MY_CNTY'] = trim($qso->station_cnty);
}
} else {
$result['MY_CNTY'] = null;
}
$result['MY_SIG'] = $qso->station_sig;
$result['MY_SIG_INFO'] = $qso->station_sig_info;
$result['SIG'] = $qso->{'COL_SIG'};
$result['SIG_INFO'] = $qso->{'COL_SIG_INFO'};
if ($fields !== null) {
$result = array_intersect_key($result, array_flip($fields));
}
return $result;
}
// API function to check if a callsign is in the logbook already
function logbook_check_callsign() {
header('Content-type: application/json');
$this->load->model('api_model');
// Decode JSON and store
$obj = json_decode(file_get_contents("php://input"), true);
if ($obj === NULL) {
echo json_encode(['status' => 'failed', 'reason' => "wrong JSON"]);
return;
}
if(!isset($obj['key']) || $this->api_model->authorize($obj['key']) == 0) {
http_response_code(401);
echo json_encode(['status' => 'failed', 'reason' => "missing api key"]);
return;
}
if(!isset($obj['logbook_public_slug']) || !isset($obj['callsign'])) {
http_response_code(401);
echo json_encode(['status' => 'failed', 'reason' => "missing fields"]);
return;
}
if($obj['logbook_public_slug'] != "" && $obj['callsign'] != "") {
$logbook_slug = $obj['logbook_public_slug'];
$callsign = $obj['callsign'];
// If $obj['band'] exists
if(isset($obj['band'])) {
$band = $obj['band'];
} else {
$band = null;
}
$this->load->model('logbooks_model');
if($this->logbooks_model->public_slug_exists($logbook_slug)) {
$logbook_id = $this->logbooks_model->public_slug_exists_logbook_id($logbook_slug);
if($logbook_id != false)
{
// Get associated station locations for mysql queries
$logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($logbook_id);
2024-01-17 17:30:14 +01:00
2026-03-18 09:00:48 +01:00
if ($logbooks_locations_array[0] === -1) {
// Logbook not found
http_response_code(404);
echo json_encode(['status' => 'failed', 'reason' => "Empty Logbook"]);
die();
}
} else {
// Logbook not found
http_response_code(404);
echo json_encode(['status' => 'failed', 'reason' => $logbook_slug." has no associated station locations"]);
die();
}
// Search Logbook for callsign
$this->load->model('logbook_model');
$result = $this->logbook_model->check_if_callsign_worked_in_logbook($callsign, $logbooks_locations_array, $band);
http_response_code(201);
if($result > 0)
{
echo json_encode(['callsign' => $callsign, 'result' => 'Found']);
} else {
echo json_encode(['callsign' => $callsign, 'result' => 'Not Found']);
}
} else {
// Logbook not found
http_response_code(404);
echo json_encode(['status' => 'failed', 'reason' => "logbook not found"]);
die();
}
}
}
2023-03-28 14:57:43 +01:00
// API function to check if a grid is in the logbook already
function logbook_check_grid() {
header('Content-type: application/json');
$this->load->model('api_model');
// Decode JSON and store
$obj = json_decode(file_get_contents("php://input"), true);
if ($obj === NULL) {
echo json_encode(['status' => 'failed', 'reason' => "wrong JSON"]);
}
if(!isset($obj['key']) || $this->api_model->authorize($obj['key']) == 0) {
http_response_code(401);
echo json_encode(['status' => 'failed', 'reason' => "missing api key"]);
}
if(!isset($obj['logbook_public_slug']) || !isset($obj['grid'])) {
http_response_code(401);
echo json_encode(['status' => 'failed', 'reason' => "missing fields"]);
return;
}
2023-03-28 14:57:43 +01:00
if($obj['logbook_public_slug'] != "" && $obj['grid'] != "") {
$logbook_slug = $obj['logbook_public_slug'];
$grid = $obj['grid'];
// If $obj['band'] exists
if(isset($obj['band'])) {
$band = $obj['band'];
} else {
$band = null;
}
// If $obj['cnfm'] exists
if(isset($obj['cnfm'])) {
$cnfm = $obj['cnfm'];
} else {
$cnfm = null;
}
2023-03-28 14:57:43 +01:00
$this->load->model('logbooks_model');
if($this->logbooks_model->public_slug_exists($logbook_slug)) {
$logbook_id = $this->logbooks_model->public_slug_exists_logbook_id($logbook_slug);
if($logbook_id != false)
{
// Get associated station locations for mysql queries
$logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($logbook_id);
2024-01-17 17:30:14 +01:00
2026-03-18 09:00:48 +01:00
if ($logbooks_locations_array[0] === -1) {
2023-03-28 14:57:43 +01:00
// Logbook not found
http_response_code(404);
echo json_encode(['status' => 'failed', 'reason' => "Empty Logbook"]);
die();
}
} else {
// Logbook not found
http_response_code(404);
echo json_encode(['status' => 'failed', 'reason' => $logbook_slug." has no associated station locations"]);
die();
}
// Search Logbook for callsign
$this->load->model('logbook_model');
$query = $this->logbook_model->check_if_grid_worked_in_logbook($grid, $logbooks_locations_array, $band, $cnfm);
2023-03-28 14:57:43 +01:00
http_response_code(201);
if ($query->num_rows() == 0) {
echo json_encode(['gridsquare' => strtoupper($grid), 'result' => 'Not Found']);
} else if ($cnfm == null) {
2023-03-28 14:57:43 +01:00
echo json_encode(['gridsquare' => strtoupper($grid), 'result' => 'Found']);
} else {
$arr = [];
foreach($query->result() as $line) {
$arr[] = $line->gridorcnfm;
}
if (in_array('Y', $arr)) {
echo json_encode(['gridsquare' => strtoupper($grid), 'result' => 'Confirmed']);
} else {
echo json_encode(['gridsquare' => strtoupper($grid), 'result' => 'Worked']);
}
2023-03-28 14:57:43 +01:00
}
2023-03-28 14:57:43 +01:00
} else {
// Logbook not found
http_response_code(404);
echo json_encode(['status' => 'failed', 'reason' => "logbook not found"]);
die();
}
}
}
2026-03-18 08:34:52 +01:00
// API function to get all worked grids for a band and confirmation method
function logbook_get_worked_grids() {
$arr = array();
header('Content-type: application/json');
$this->load->model('api_model');
$obj = json_decode(file_get_contents("php://input"), true);
if ($obj === NULL) {
echo json_encode(['status' => 'failed', 'reason' => "wrong JSON"]);
die();
}
// Check rate limit
$identifier = isset($obj['key']) ? $obj['key'] : null;
$this->check_rate_limit('logbook_get_worked_grids', $identifier);
if(!isset($obj['key']) || $this->api_model->authorize($obj['key']) == 0) {
http_response_code(401);
echo json_encode(['status' => 'failed', 'reason' => "missing api key"]);
die();
}
2026-02-20 13:43:13 +00:00
$api_user_id = $this->api_model->key_userid($obj['key']);
if(!isset($obj['logbook_id'])) {
http_response_code(400);
echo json_encode(['status' => 'failed', 'reason' => "missing fields"]);
return;
}
if($obj['logbook_id'] != "") {
$logbook_id = $obj['logbook_id'];
if(isset($obj['band'])) {
$band = $obj['band'];
} else {
$band = null;
}
if(isset($obj['cnfm'])) {
$cnfm = $obj['cnfm'];
} else {
$cnfm = null;
}
$this->load->model('logbooks_model');
if(!$this->logbooks_model->logbook_id_belongs_to_user($logbook_id, $api_user_id)) {
2026-02-20 13:43:13 +00:00
http_response_code(403);
echo json_encode(['status' => 'failed', 'reason' => "logbook does not belong to this API key or logbook ID not found"]);
2026-02-20 13:43:13 +00:00
die();
}
if ($this->logbooks_model->exists_logbook_id($logbook_id) != false) {
$logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($logbook_id);
2026-03-18 09:00:48 +01:00
if ($logbooks_locations_array[0] === -1) {
http_response_code(404);
echo json_encode(['status' => 'failed', 'reason' => "logbook with ID ".$logbook_id." has no associated station locations"]);
die();
2026-03-15 10:40:36 +01:00
} else {
$arr = $this->api_model->get_grids_worked_in_logbook($logbooks_locations_array, $band, $cnfm);
http_response_code(201);
echo json_encode($arr);
}
}
}
}
/* ENDPOINT for Rig Control */
2017-11-30 19:01:11 -07:00
function radio() {
2024-01-13 11:16:31 +00:00
session_write_close();
header('Content-type: application/json');
2017-11-30 19:01:11 -07:00
2018-12-17 22:16:06 +01:00
$this->load->model('api_model');
//$json = '{"radio":"FT-950","frequency":14075,"mode":"SSB","timestamp":"2012/04/07 16:47"}';
2017-11-30 19:01:11 -07:00
$this->load->model('cat');
2017-11-30 19:01:11 -07:00
//var_dump(file_get_contents("php://input"), true);
2017-11-30 19:01:11 -07:00
// Decode JSON and store
$obj = json_decode(file_get_contents("php://input"), true);
// Check rate limit
$identifier = isset($obj['key']) ? $obj['key'] : null;
$this->check_rate_limit('radio', $identifier);
2018-12-17 22:16:06 +01:00
if(!isset($obj['key']) || $this->api_model->authorize($obj['key']) == 0) {
http_response_code(401);
echo json_encode(['status' => 'failed', 'reason' => "missing api key"]);
die();
2018-12-17 22:16:06 +01:00
}
2026-06-08 09:29:47 +02:00
if($this->api_model->authorize($obj['key']) == 1) {
http_response_code(403);
echo json_encode(['status' => 'failed', 'reason' => "API key does not have write permissions"]);
die();
}
if(!isset($obj['radio'])) {
http_response_code(404);
echo json_encode(['status' => 'failed', 'reason' => "missing radio element in payload"]);
die();
}
$this->api_model->update_last_used($obj['key']);
$user_id = $this->api_model->key_userid($obj['key']);
Clubstations for Wavelog (#1334) * feat[clubstations]: New DB structure * feat[clubstations]: Add clubstationstable in user managment * feat[clubstations]: Show last operator * feat[clubstations]: Better solution for last operator. tnx for the hint @int2001 * feat[clubstations]: New Club Model and Controller * feat[clubstations]: Add "Add User" and "Edit User" functionality * docs[clubstations]: move comment * feat[clubstations]: Add "Delete Member" functionality * feat[clubstations]: some enhancements and javascript * fix[clubstations]: Wrong message class for flashmessages * feat[clubstations]: Added Switch in the Header menu (not functional yet) * feat[clubstations]: clubswitch modal * fix[clubstations]: Load encryption library if not already loaded * fix[clubstations]: Prevent direct login attempts to clubstations and enhance impersonation authorization * fix[clubstations]: Typo * feat[clubstations]: Only show the operator dialog if there is something fishy * fix[user]: little UI bug * feat[impersonate]: Add source uid to session data * fix[impersonate]: logic adjustment * feat[clubstations]: Add manage button in header menu for club officers * fix[clubstations]: typo in permission level check * fix[clubstations]: Full rights for the admin * feat[impersonate]: Custom sessiondata * feat[impersonate]: Implement stop impersonation feature with modal confirmation; "the way back" * fix(modal): Fix bug where modal was hidden when mouse leaved the browser content * docs(config): Adjust config description for special callsigns and clubstations * feat(club): Add club access check helper * typo * fix[impersonation]: Better text * feat(club): Selectize for a efficient user search * feat(clubstations): Restrict clubstations based on users permission level part 1/x * adjustments for dev merge * Adjusted club right for the advanced logbook * feat[user]: Refactoring of the Action Buttons in the user table * fix[club_permissions]: normal button instead small one for club permissions * remove unnecessary line break in modal body * feat[clubstations]: Add Club Mode badge to the header * fix[clubstations]: fix maintenance mode * allow switch back on http * feat(simplefle): display operator input based on club_access * small UI adjustments * small UI adjustments * moved api page to a index.php file and added support for clubstations * removed unused stuff * typo * radios and api keys * missed one binding * fix qso view, even officers do just see their own radios in QSO logging * omit the need for a relogin to see the changes as an admin * Omit the need for relogin after club changes in general. It's a question of UX. It's better to accept a little higher DB load (if clubstations are enabled) then the need of an user to relogin. There is some room for improvement by changing user_model->get_by_id() and adding a join there. This can be done later if we see that the load is too high * 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 * remove debug messages * better UI in header * found a typo * full access in clubstations for admins (if accessed via admin usertable) * adjusted text * adjusted text * adjust text * reduce required chars * bugfix: missing the correct authentication in case the admin was not member of the club. he wasn't able to switch back * reduce debug messages * fixed UI bug related to tooltips * load js in controller * upps.. * some UI adjustments * corrected permissions * if user gets delete we need to remove data in club_permissions and also api keys which were created by this user * Notify members about new memberships or changes in permission level * add spinner to save button * make login/logout process more bulletproof * remove the relogin cookie after the attempt * better strategy * bug where switch back failed if user is no admin * make api keys more secure * mask not owned api keys * removed annoying link * if a user gets removed from a club we also should delete the corresponding api keys and cat radios * adjusted wiki link * Auto creation of logbook and location when new user is created * store and display locator in uppercase * same for callsign * fixed a bug in user/club creation * Revert "Auto creation of logbook and location when new user is created" We found another solution to which will be addressed in a second PR This reverts commit f05f4b7bf0423a88abf0087ade81fe613d217794. * Optimized SQL for stats at userlist * Source query for lastop "out", because mysql<9.0 can't handle Windowed functions * adjust migration * add new columns to users table to get created_at and modified_at * added a partial down function * add operator dropdown for clubstations * fix mig version * Add some backend restrictions in case a user wants to try something funny with the club --------- Co-authored-by: Andreas Kristiansen <6977712+AndreasK79@users.noreply.github.com> Co-authored-by: int2001 <joerg@dj7nt.de>
2025-01-02 10:22:23 +01:00
$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;
}
// Handle optional cat_url
if (isset($obj['cat_url']) && !empty($obj['cat_url'])) {
$cat_url = $this->sanitize_cat_url($obj['cat_url']);
if ($cat_url !== false) {
$obj['cat_url'] = $cat_url;
}
}
2025-02-18 18:54:32 +01:00
2017-11-30 19:01:11 -07:00
// Store Result to Database
Clubstations for Wavelog (#1334) * feat[clubstations]: New DB structure * feat[clubstations]: Add clubstationstable in user managment * feat[clubstations]: Show last operator * feat[clubstations]: Better solution for last operator. tnx for the hint @int2001 * feat[clubstations]: New Club Model and Controller * feat[clubstations]: Add "Add User" and "Edit User" functionality * docs[clubstations]: move comment * feat[clubstations]: Add "Delete Member" functionality * feat[clubstations]: some enhancements and javascript * fix[clubstations]: Wrong message class for flashmessages * feat[clubstations]: Added Switch in the Header menu (not functional yet) * feat[clubstations]: clubswitch modal * fix[clubstations]: Load encryption library if not already loaded * fix[clubstations]: Prevent direct login attempts to clubstations and enhance impersonation authorization * fix[clubstations]: Typo * feat[clubstations]: Only show the operator dialog if there is something fishy * fix[user]: little UI bug * feat[impersonate]: Add source uid to session data * fix[impersonate]: logic adjustment * feat[clubstations]: Add manage button in header menu for club officers * fix[clubstations]: typo in permission level check * fix[clubstations]: Full rights for the admin * feat[impersonate]: Custom sessiondata * feat[impersonate]: Implement stop impersonation feature with modal confirmation; "the way back" * fix(modal): Fix bug where modal was hidden when mouse leaved the browser content * docs(config): Adjust config description for special callsigns and clubstations * feat(club): Add club access check helper * typo * fix[impersonation]: Better text * feat(club): Selectize for a efficient user search * feat(clubstations): Restrict clubstations based on users permission level part 1/x * adjustments for dev merge * Adjusted club right for the advanced logbook * feat[user]: Refactoring of the Action Buttons in the user table * fix[club_permissions]: normal button instead small one for club permissions * remove unnecessary line break in modal body * feat[clubstations]: Add Club Mode badge to the header * fix[clubstations]: fix maintenance mode * allow switch back on http * feat(simplefle): display operator input based on club_access * small UI adjustments * small UI adjustments * moved api page to a index.php file and added support for clubstations * removed unused stuff * typo * radios and api keys * missed one binding * fix qso view, even officers do just see their own radios in QSO logging * omit the need for a relogin to see the changes as an admin * Omit the need for relogin after club changes in general. It's a question of UX. It's better to accept a little higher DB load (if clubstations are enabled) then the need of an user to relogin. There is some room for improvement by changing user_model->get_by_id() and adding a join there. This can be done later if we see that the load is too high * 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 * remove debug messages * better UI in header * found a typo * full access in clubstations for admins (if accessed via admin usertable) * adjusted text * adjusted text * adjust text * reduce required chars * bugfix: missing the correct authentication in case the admin was not member of the club. he wasn't able to switch back * reduce debug messages * fixed UI bug related to tooltips * load js in controller * upps.. * some UI adjustments * corrected permissions * if user gets delete we need to remove data in club_permissions and also api keys which were created by this user * Notify members about new memberships or changes in permission level * add spinner to save button * make login/logout process more bulletproof * remove the relogin cookie after the attempt * better strategy * bug where switch back failed if user is no admin * make api keys more secure * mask not owned api keys * removed annoying link * if a user gets removed from a club we also should delete the corresponding api keys and cat radios * adjusted wiki link * Auto creation of logbook and location when new user is created * store and display locator in uppercase * same for callsign * fixed a bug in user/club creation * Revert "Auto creation of logbook and location when new user is created" We found another solution to which will be addressed in a second PR This reverts commit f05f4b7bf0423a88abf0087ade81fe613d217794. * Optimized SQL for stats at userlist * Source query for lastop "out", because mysql<9.0 can't handle Windowed functions * adjust migration * add new columns to users table to get created_at and modified_at * added a partial down function * add operator dropdown for clubstations * fix mig version * Add some backend restrictions in case a user wants to try something funny with the club --------- Co-authored-by: Andreas Kristiansen <6977712+AndreasK79@users.noreply.github.com> Co-authored-by: int2001 <joerg@dj7nt.de>
2025-01-02 10:22:23 +01:00
$this->cat->update($obj, $user_id, $operator);
// Return Message
2017-11-30 19:01:11 -07:00
$arr = array('status' => 'success');
echo json_encode($arr);
2017-11-30 19:01:11 -07:00
}
/*
*
* Stats API function calls
*
*/
function statistics($key = null) {
2025-03-23 14:26:29 +00:00
$this->load->model('api_model');
2026-06-08 09:29:47 +02:00
if ((($key ?? '') != '') && ($this->api_model->authorize($key) > 0)) {
2025-03-23 14:26:29 +00:00
$this->load->model('logbook_model');
2026-02-04 05:34:33 +00:00
$qso_counts = $this->logbook_model->get_qso_counts(null, $key);
$data['todays_qsos'] = $qso_counts['today'];
$data['total_qsos'] = $qso_counts['total'];
$data['month_qsos'] = $qso_counts['month'];
$data['year_qsos'] = $qso_counts['year'];
2025-03-23 14:26:29 +00:00
} else { # for Downcompat
$data['todays_qsos'] = 0;
$data['total_qsos'] = 0;
$data['month_qsos'] = 0;
$data['year_qsos'] = 0;
}
header('Content-type: application/json');
http_response_code(201);
echo json_encode(['Today' => $data['todays_qsos'], 'total_qsos' => $data['total_qsos'], 'month_qsos' => $data['month_qsos'], 'year_qsos' => $data['year_qsos']]);
}
2024-09-30 08:06:04 +00:00
function private_lookup() {
2026-06-19 21:20:00 +08:00
header('Content-type: application/json');
2024-10-01 06:14:03 +00:00
// Lookup Callsign and dxcc for further informations. UseCase: e.g. external Application which checks calls like FlexRadio-Overlay
2024-09-30 08:06:04 +00:00
$raw_input = json_decode(file_get_contents("php://input"), true);
// Check rate limit
$identifier = isset($raw_input['key']) ? $raw_input['key'] : null;
$this->check_rate_limit('private_lookup', $identifier);
2024-09-30 08:06:04 +00:00
$user_id='';
if (!( $this->user_model->authorize($this->config->item('auth_mode') ))) { // User not authorized?
$no_auth=true;
$this->load->model('api_model');
if (!( ((isset($raw_input['key'])) && ($this->api_model->authorize($raw_input['key']) > 0) ))) { // Key invalid?
$no_auth=true;
} else {
$no_auth=false;
$user_id=$this->api_model->key_userid($raw_input['key']);
}
if ($no_auth) {
http_response_code(401);
echo json_encode(['status' => 'failed', 'reason' => "missing api key or session"]);
die();
}
} else {
$user_id=$this->session->userdata('user_id');
}
2026-01-07 06:49:35 +00:00
if (($raw_input['callbook'] ?? '' == 'true') && (($raw_input['callsign'] ?? '') != '')) {
$this->load->library('callbook');
$this->load->model('logbook_model');
$lookupcall = $this->callbook->get_plaincall($raw_input['callsign']);
$callbook = $this->logbook_model->loadCallBook($raw_input['callsign'], $this->config->item('use_fullname'));
} else {
$callbook=null;
}
2024-09-30 08:06:04 +00:00
$this->load->model('stations');
$all_station_ids=$this->stations->all_station_ids_of_user($user_id);
2025-02-13 11:50:06 +01:00
2024-09-30 08:06:04 +00:00
if ((array_key_exists('station_ids',$raw_input)) && (is_array($raw_input['station_ids']))) { // Special station_ids needed and it is an array?
$a_station_ids=[];
foreach ($raw_input['station_ids'] as $stationid) { // Check for grants to given station_id
2026-06-19 21:54:02 +08:00
$stationid = intval($stationid);
2024-09-30 08:06:04 +00:00
if ($this->stations->check_station_against_user($stationid, $user_id)) {
$a_station_ids[]=$stationid;
}
}
$station_ids=implode(', ', $a_station_ids);
} else {
$station_ids=$all_station_ids; // Take all of user if no station_ids were given
}
if ($station_ids == '') { // No station_ids found for user or no station_id of given ones were granted? exit!
http_response_code(200);
echo json_encode(['status' => 'failed', 'reason' => "no station_profiles are matching the User with this API-Key"]);
die();
}
if (array_key_exists('band',$raw_input)) {
$band=$raw_input['band'];
} else {
$band='NO_BAND';
}
if (array_key_exists('mode',$raw_input)) {
$mode=$raw_input['mode'];
} else {
$mode='NO_MODE';
}
$lookup_callsign = strtoupper($raw_input['callsign'] ?? '');
if ($lookup_callsign ?? '' != '') {
$this->load->model("logbook_model");
$date = date("Y-m-d");
// Return Array
$return = [
"callsign" => "",
"dxcc" => false,
"dxcc_id" => -1,
"dxcc_lat" => "",
"dxcc_long" => "",
"dxcc_cqz" => "",
"dxcc_flag" => "",
"cont" => "",
"name" => "",
"gridsquare" => "",
"location" => "",
"iota_ref" => "",
"state" => "",
"us_county" => "",
"qsl_manager" => "",
"bearing" => "",
"call_worked" => false,
"call_worked_band" => false,
"call_worked_band_mode" => false,
2024-09-30 08:06:04 +00:00
"lotw_member" => false,
"dxcc_confirmed_on_band" => false,
"dxcc_confirmed_on_band_mode" => false,
"dxcc_confirmed" => false,
"call_confirmed" => false,
"call_confirmed_band" => false,
"call_confirmed_band_mode" => false,
2024-09-30 08:06:04 +00:00
"suffix_slash" => "", // Suffix Slash aka Portable
];
$return['callsign'] = $lookup_callsign;
$dxccobj = new Dxcc();
$callsign_dxcc_lookup = $dxccobj->dxcc_lookup($lookup_callsign, $date);
2024-09-30 08:06:04 +00:00
$last_slash_pos = strrpos($lookup_callsign, '/');
if(isset($last_slash_pos) && $last_slash_pos > 4) {
$suffix_slash = $last_slash_pos === false ? $lookup_callsign : substr($lookup_callsign, $last_slash_pos + 1);
switch ($suffix_slash) {
case "P":
$suffix_slash_item = "Portable";
break;
case "M":
$suffix_slash_item = "Mobile";
case "MM":
$suffix_slash_item = "Maritime Mobile";
break;
default:
// If its not one of the above suffix slashes its likely dxcc
$ans2 = $dxccobj->dxcc_lookup($suffix_slash, $date);
2024-09-30 08:06:04 +00:00
$suffix_slash_item = null;
}
$return['suffix_slash'] = $suffix_slash_item;
}
// If the final slash is a DXCC then find it!
if (isset($ans2['call'])) {
$return['dxcc_id'] = $ans2['adif'];
$return['dxcc'] = $ans2['entity'];
$return['dxcc_lat'] = $ans2['lat'];
$return['dxcc_long'] = $ans2['long'];
$return['dxcc_cqz'] = $ans2['cqz'];
$return['cont'] = $ans2['cont'];
} else {
$return['dxcc_id'] = $callsign_dxcc_lookup['adif'] ?? '';
$return['dxcc'] = $callsign_dxcc_lookup['entity'] ?? '';
$return['dxcc_lat'] = $callsign_dxcc_lookup['lat'] ?? '';
$return['dxcc_long'] = $callsign_dxcc_lookup['long'] ?? '';
$return['dxcc_cqz'] = $callsign_dxcc_lookup['cqz'] ?? '';
$return['cont'] = $callsign_dxcc_lookup['cont'] ?? '';
}
2026-06-13 12:59:39 +00:00
// ITU zone from the DXCC entity (same source/timing as dxcc_cqz). Only add the
// key when the entity has a known ITU zone, otherwise omit it entirely.
$entity = $this->logbook_model->get_entity($return['dxcc_id']);
if (is_array($entity) && (($entity['ituz'] ?? 0) > 0)) {
$return['dxcc_ituz'] = (int) $entity['ituz'];
}
2024-10-01 06:14:03 +00:00
// Query stations of KeyOwner for an already worked call
$userdata=$this->user_model->get_by_id($user_id);
$call_lookup_results = $this->logbook_model->call_lookup_result($lookup_callsign, $station_ids,$userdata->row()->user_default_confirmation,$band,$mode);
2024-09-30 08:06:04 +00:00
if($call_lookup_results != null) {
$return['name'] = $call_lookup_results->COL_NAME;
$return['gridsquare'] = $call_lookup_results->COL_GRIDSQUARE;
$return['location'] = $call_lookup_results->COL_QTH;
$return['iota_ref'] = $call_lookup_results->COL_IOTA;
$return['qsl_manager'] = $call_lookup_results->COL_QSL_VIA;
$return['state'] = $call_lookup_results->COL_STATE;
$return['us_county'] = $call_lookup_results->COL_CNTY;
$return['dxcc_id'] = $call_lookup_results->COL_DXCC;
$return['cont'] = $call_lookup_results->COL_CONT;
$return['call_worked'] = true;
$return['call_worked_band'] = ($call_lookup_results->CALL_WORKED_BAND==1) ? true : false;
$return['call_worked_band_mode'] = ($call_lookup_results->CALL_WORKED_BAND_MODE==1) ? true : false;
$return['call_confirmed'] = ($call_lookup_results->CALL_CNF==1) ? true : false;
$return['call_confirmed_band'] = ($call_lookup_results->CALL_CNF_BAND==1) ? true : false;
$return['call_confirmed_band_mode'] = ($call_lookup_results->CALL_CNF_BAND_MODE==1) ? true : false;
2024-09-30 08:06:04 +00:00
if ($return['gridsquare'] != "") {
$return['latlng'] = $this->qralatlng($return['gridsquare']);
}
}
if ($return['dxcc'] ?? '' != '') {
$this->load->library('DxccFlag');
$return['dxcc_flag']=$this->dxccflag->get($return['dxcc_id']);
}
$lotw_days=$this->logbook_model->check_last_lotw($lookup_callsign);
if ($lotw_days !== null) {
2024-09-30 08:06:04 +00:00
$return['lotw_member']=$lotw_days;
}
2024-10-01 06:14:03 +00:00
if ($return['dxcc_id'] ?? '' != '') { // DXCC derivated before? if yes: check cnf-states
2024-09-30 08:06:04 +00:00
$return['dxcc_confirmed']=($this->logbook_model->check_if_dxcc_cnfmd_in_logbook_api($userdata->row()->user_default_confirmation,$return['dxcc_id'], $station_ids, null, null)>0) ? true : false;
$return['dxcc_confirmed_on_band']=($this->logbook_model->check_if_dxcc_cnfmd_in_logbook_api($userdata->row()->user_default_confirmation,$return['dxcc_id'], $station_ids, $band, null)>0) ? true : false;
$return['dxcc_confirmed_on_band_mode']=($this->logbook_model->check_if_dxcc_cnfmd_in_logbook_api($userdata->row()->user_default_confirmation,$return['dxcc_id'], $station_ids, $band, $mode)>0) ? true : false;
}
if ($callbook) {
$return['callbook']=$callbook;
}
2024-09-30 08:06:04 +00:00
echo json_encode($return, JSON_PRETTY_PRINT);
} else {
echo '{"error":"callsign to lookup not given"}';
}
return;
}
function lookup() {
2026-06-19 21:20:00 +08:00
header('Content-type: application/json');
2024-10-01 06:14:03 +00:00
// This API provides NO information about previous QSOs. It just derivates DXCC, Lat, Long. It is used by the DXClusterAPI
$raw_input = json_decode(file_get_contents("php://input"), true);
// Check rate limit
$identifier = isset($raw_input['key']) ? $raw_input['key'] : null;
$this->check_rate_limit('lookup', $identifier);
2025-09-14 18:44:16 +02:00
$user_id = '';
if (!( $this->user_model->authorize($this->config->item('auth_mode') ))) { // User not authorized?
2025-09-14 18:44:16 +02:00
$no_auth = true;
$this->load->model('api_model');
if (!( ((isset($raw_input['key'])) && ($this->api_model->authorize($raw_input['key']) > 0) ))) { // Key invalid?
2025-09-14 18:44:16 +02:00
$no_auth = true;
} else {
2025-09-14 18:44:16 +02:00
$no_auth = false;
$user_id = $this->api_model->key_userid($raw_input['key']);
}
if ($no_auth) {
http_response_code(401);
echo json_encode(['status' => 'failed', 'reason' => "missing api key or session"]);
die();
}
} else {
2025-09-14 18:44:16 +02:00
$user_id = $this->session->userdata('user_id');
}
$this->load->model('stations');
2025-09-14 18:44:16 +02:00
$station_ids = $this->stations->all_station_ids_of_user($user_id);
$lookup_callsign = strtoupper($raw_input['callsign'] ?? '');
if ($lookup_callsign ?? '' != '') {
$this->load->model("logbook_model");
$date = date("Y-m-d");
// Return Array
$return = [
"callsign" => "",
"dxcc" => false,
"dxcc_id" => -1,
"dxcc_lat" => "",
"dxcc_long" => "",
"dxcc_cqz" => "",
"dxcc_flag" => "",
"cont" => "",
"name" => "",
"gridsquare" => "",
"location" => "",
"iota_ref" => "",
"state" => "",
"us_county" => "",
"qsl_manager" => "",
"bearing" => "",
"workedBefore" => false,
"lotw_member" => false,
"suffix_slash" => "", // Suffix Slash aka Portable
];
$return['callsign'] = $lookup_callsign;
// Use Wavelog\Dxcc\Dxcc for faster in-memory lookup
$dxccobj = new Dxcc();
$callsign_dxcc_lookup = $dxccobj->dxcc_lookup($lookup_callsign, $date);
2025-09-14 18:44:16 +02:00
$return['dxcc_id'] = $callsign_dxcc_lookup['adif'] ?? '';
$return['dxcc'] = $callsign_dxcc_lookup['entity'] ?? '';
$return['dxcc_lat'] = $callsign_dxcc_lookup['lat'] ?? '';
$return['dxcc_long'] = $callsign_dxcc_lookup['long'] ?? '';
$return['dxcc_cqz'] = $callsign_dxcc_lookup['cqz'] ?? '';
$return['cont'] = $callsign_dxcc_lookup['cont'] ?? '';
/*
2024-10-01 06:14:03 +00:00
* Query Data of API-Key-Owner for further informations
*/
$call_lookup_results = $this->logbook_model->call_lookup_result($lookup_callsign, $station_ids,'','NO BAND','NO MODE');
if($call_lookup_results != null)
{
$return['name'] = $call_lookup_results->COL_NAME;
$return['gridsquare'] = $call_lookup_results->COL_GRIDSQUARE;
$return['location'] = $call_lookup_results->COL_QTH;
$return['iota_ref'] = $call_lookup_results->COL_IOTA;
$return['qsl_manager'] = $call_lookup_results->COL_QSL_VIA;
$return['state'] = $call_lookup_results->COL_STATE;
$return['us_county'] = $call_lookup_results->COL_CNTY;
2024-09-20 16:26:15 +00:00
$return['workedBefore'] = true;
if ($return['gridsquare'] != "") {
$return['latlng'] = $this->qralatlng($return['gridsquare']);
}
}
if ($return['dxcc'] ?? '' != '') {
$this->load->library('DxccFlag');
$return['dxcc_flag']=$this->dxccflag->get($return['dxcc_id']);
}
$lotw_days=$this->logbook_model->check_last_lotw($lookup_callsign);
if ($lotw_days !== null) {
$return['lotw_member']=$lotw_days;
}
echo json_encode($return, JSON_PRETTY_PRINT);
} else {
echo '{"error":"callsign to lookup not given"}';
}
return;
}
function qralatlng($qra) {
if(!$this->load->is_loaded('Qra')) {
$this->load->library('Qra');
}
$latlng = $this->qra->qra2latlong($qra);
return $latlng;
}
2025-02-13 11:50:06 +01:00
function version() {
2025-01-04 21:46:09 +01:00
// This API endpoint provides the version of Wavelog if the provide key has at least read permissions
2025-01-05 11:54:50 +01:00
$data = json_decode(file_get_contents('php://input'), true);
$valid = false;
2025-02-13 11:50:06 +01:00
2025-01-05 11:54:50 +01:00
if (!empty($data['key'])) {
$this->load->model('api_model');
2026-06-08 09:29:47 +02:00
if ($this->api_model->authorize($data['key']) > 0) { /* Check permission for reading */
2025-01-05 11:54:50 +01:00
$valid = true;
}
}
2025-01-04 21:46:09 +01:00
header("Content-type: application/json");
2025-01-05 11:54:50 +01:00
if ($valid) {
echo json_encode(['status' => 'ok', 'version' => $this->optionslib->get_option('version')]);
2025-01-04 21:46:09 +01:00
} else {
http_response_code(401);
echo json_encode(['status' => 'failed', 'reason' => "missing or invalid api key"]);
}
}
2025-02-13 11:50:06 +01:00
/*
API call used in this WordPress plugin: https://github.com/HochdruckHummer/wavelog-wp-qso-display
*/
function get_wp_stats() {
// Set header
header('Content-type: application/json');
// Load API model
$this->load->model('api_model');
// Decode JSON and store
$obj = json_decode(file_get_contents("php://input"), true);
if ($obj === NULL) {
http_response_code(400);
echo json_encode(['status' => 'failed', 'reason' => "wrong JSON"]);
return;
}
// Authorization
if (!isset($obj['key']) || $this->api_model->authorize($obj['key']) == 0) {
http_response_code(401);
echo json_encode(['status' => 'failed', 'reason' => "missing or wrong api key"]);
return;
}
// Validate station_id
if (!isset($obj['station_id']) || !is_numeric($obj['station_id'])) {
http_response_code(400);
echo json_encode(['status' => 'failed', 'reason' => "Invalid station_id."]);
return;
}
$station_id = (int)$obj['station_id'];
$key = $obj['key'];
// Load stations model
$this->load->model('stations');
// Get user stations
$userid = $this->api_model->key_userid($key);
$stations = $this->stations->all_of_user($userid);
$station_ids = array_map(function($row) {
return $row->station_id;
}, $stations->result());
// Check station access
if (!in_array($station_id, $station_ids)) {
http_response_code(401);
echo json_encode(['status' => 'failed', 'reason' => "Station ID not accessible for this API key"]);
return;
}
// Load cache driver
$this->load->driver('cache', [
'adapter' => $this->config->item('cache_adapter') ?? 'file',
'backup' => $this->config->item('cache_backup') ?? 'file',
'key_prefix' => $this->config->item('cache_key_prefix') ?? ''
]);
2025-02-13 11:50:06 +01:00
// Create cache key
$cache_key = "wp_stats_{$station_id}";
// Check if cached data exists
if ($cached_data = $this->cache->get($cache_key)) {
http_response_code(200);
echo json_encode(['status' => 'successful', 'message' => 'Data from cache', 'statistics' => $cached_data]);
return;
}
// Get QSO data (from database)
$data['totalalltime'] = $this->api_model->get_qsos_total($station_id)->result();
$data['totalthisyear'] = $this->api_model->get_qsos_this_year($station_id)->result();
$data['totalgroupedmodes'] = $this->api_model->get_qsos_grouped_by_mode($station_id)->result();
// Store in cache for 5 minutes
$this->cache->save($cache_key, $data, 600); // 10 minutes
// Return result
http_response_code(200);
echo json_encode(['status' => 'successful', 'message' => 'Export successful', 'statistics' => $data]);
}
/**
* Sanitize and validate callback URL
* @param string $url The URL to sanitize
* @return string|false Returns sanitized URL or false if invalid
*/
private function sanitize_cat_url($url) {
// Basic sanitization
$url = trim($url);
// Check if URL is valid and uses http or https
if (!filter_var($url, FILTER_VALIDATE_URL) ||
(!preg_match('/^https?:\/\//', $url))) {
return false;
}
// Remove trailing slashes
$url = rtrim($url, '/');
// Additional XSS cleaning
$url = $this->security->xss_clean($url);
return $url;
}
/* **
2026-02-15 10:38:22 -07:00
* List members of a clubstation
* API key needs to be of a club officer (permission level 9)
* returns array of club member details
*/
function list_clubmembers() {
2026-02-15 10:38:22 -07:00
header('Content-type: application/json');
$this->load->model('api_model');
// Decode JSON and store
$obj = json_decode(file_get_contents("php://input"), true);
if ($obj === NULL) {
http_response_code(400);
echo json_encode(['status' => 'failed', 'reason' => "wrong JSON"]);
return;
}
2026-06-08 09:29:47 +02:00
if ($this->api_model->authorize($obj['key']) == 0) {
2026-02-15 10:38:22 -07:00
http_response_code(401);
echo json_encode(['status' => 'error', 'message' => 'Auth Error, invalid key']);
return;
}
$this->load->model('club_model');
$userid = $this->api_model->key_userid($obj['key']);
$created_by = $this->api_model->key_created_by($obj['key']);
2026-02-15 10:38:22 -07:00
$club_perm = $this->club_model->get_permission_noui($userid,$created_by);
if (($userid == $created_by) || (($club_perm ?? 0) != 9)) { // not club officer
http_response_code(401);
echo json_encode(['status' => 'error', 'message' => 'Auth Error, not enough permissions for this operation']);
return;
}
$memberlist = $this->club_model->get_club_members($userid);
if (!empty($memberlist)) {
2026-07-11 17:52:14 +02:00
$members = [];
2026-02-15 10:38:22 -07:00
foreach($memberlist as $member) {
$members[] = [
'callsign' => $member->user_callsign,
'user_name' => $member->user_name,
'p_level' => $member->p_level
];
}
http_response_code(200);
echo json_encode(['status' => 'successful', 'members' => $members]);
} else {
http_response_code(204);
echo json_encode(['status' => 'failed', 'reason' => "No club members found", 'members' => '']);
return;
}
}
}