2011-08-18 01:31:15 +01:00
< ? php
2011-08-18 21:57:27 +02:00
/* user_model . php
*
* This model implements user authentication and authorization
*
*/
2021-02-26 10:37:43 +01:00
2011-08-18 21:57:27 +02:00
2011-08-18 01:31:15 +01:00
// Uses 'phpass' from http://www.openwall.com/phpass/ to implement password hashing
2017-11-07 00:45:06 +00:00
// TODO migration away from this?
//require_once('application/third_party/PasswordHash.php');
2011-08-18 01:31:15 +01:00
class User_Model extends CI_Model {
2011-08-18 21:57:27 +02:00
// FUNCTION: object get($username)
2011-08-18 01:31:15 +01:00
// Retrieve a user
function get ( $username ) {
2019-10-05 19:35:55 +01:00
// Clean ID
$clean_username = $this -> security -> xss_clean ( $username );
2025-07-25 10:52:27 +00:00
$this -> db -> where ( 'upper(user_name)' , strtoupper ( $clean_username ));
2011-08-18 01:31:15 +01:00
$r = $this -> db -> get ( $this -> config -> item ( 'auth_table' ));
return $r ;
2021-02-26 10:37:43 +01:00
}
2011-08-18 01:31:15 +01:00
2026-06-30 12:58:37 +02:00
// GET — returns the installed themes plus the one currently active for the user
public function getUserThemes () {
$this -> load -> is_loaded ( 'cache' ) ? : $this -> load -> driver ( 'cache' , [
'adapter' => $this -> config -> item ( 'cache_adapter' ) ? ? 'file' ,
'backup' => $this -> config -> item ( 'cache_backup' ) ? ? 'file' ,
'key_prefix' => $this -> config -> item ( 'cache_key_prefix' ) ? ? ''
]);
$cache_key = 'user_themes' ;
// Cache check - early return
if ( $cached = $this -> cache -> get ( $cache_key )) {
$themes = $cached ;
} else {
// Load the Themes_model if not already loaded
if ( ! isset ( $this -> Themes_model )) {
$this -> load -> model ( 'Themes_model' );
}
$themes = $this -> Themes_model -> getThemes ();
// Cache the themes for 1 year
$this -> cache -> save ( $cache_key , $themes , 60 * 60 * 24 * 7 * 52 );
}
return array (
'current' => $this -> optionslib -> get_theme (),
2026-07-01 13:15:14 +02:00
'themes' => $themes
2026-06-30 12:58:37 +02:00
);
}
2011-08-18 21:57:27 +02:00
// FUNCTION: object get_by_id($id)
// Retrieve a user by user ID
2011-08-18 01:31:15 +01:00
function get_by_id ( $id ) {
2019-10-05 19:35:55 +01:00
// Clean ID
$clean_id = $this -> security -> xss_clean ( $id );
$this -> db -> where ( 'user_id' , $clean_id );
2011-08-18 01:31:15 +01:00
$r = $this -> db -> get ( $this -> config -> item ( 'auth_table' ));
return $r ;
}
2025-02-18 23:29:10 +01:00
// FUNCTION: object get_by_slug($slug)
// Retrieve a user by slug
function get_by_slug ( $slug ) {
$clean_slug = $this -> security -> xss_clean ( $slug );
$clean_slug = strtoupper ( $clean_slug );
2025-02-01 12:17:23 +01:00
2025-02-18 23:29:10 +01:00
$this -> db -> where ( 'slug' , $clean_slug );
2025-02-01 12:17:23 +01:00
$r = $this -> db -> get ( $this -> config -> item ( 'auth_table' ));
return $r ;
}
2020-09-06 16:55:30 +01:00
// FUNCTION: object get_all_lotw_users
// Returns all users with lotw details
function get_all_lotw_users () {
$this -> db -> where ( 'user_lotw_name !=' , null );
2026-02-17 14:46:23 +00:00
$this -> db -> where ( 'trim(user_lotw_name) !=' , " " );
2020-09-06 16:55:30 +01:00
$r = $this -> db -> get ( $this -> config -> item ( 'auth_table' ));
2011-08-18 01:31:15 +01:00
return $r ;
}
2011-08-19 17:13:26 +01:00
// FUNCTION: object get_by_email($email)
// Retrieve a user by email address
function get_by_email ( $email ) {
2019-10-05 19:35:55 +01:00
$clean_email = $this -> security -> xss_clean ( $email );
2025-07-25 08:34:03 +00:00
$this -> db -> where ( 'upper(user_email)' , strtoupper ( $clean_email ));
2011-08-19 17:13:26 +01:00
$r = $this -> db -> get ( $this -> config -> item ( 'auth_table' ));
return $r ;
}
2022-01-18 15:29:22 +00:00
/*
* Function : check_email_address
2023-08-02 06:34:12 +00:00
*
2022-01-18 15:29:22 +00:00
* Checks if an email address is already in use
2023-08-02 06:34:12 +00:00
*
2022-01-18 15:29:22 +00:00
* @ param string $email
*/
function check_email_address ( $email ) {
$clean_email = $this -> security -> xss_clean ( $email );
$this -> db -> where ( 'user_email' , $clean_email );
$query = $this -> db -> get ( $this -> config -> item ( 'auth_table' ));
2023-08-02 06:34:12 +00:00
2022-01-18 15:29:22 +00:00
if ( $query -> num_rows () > 0 ) {
return true ;
} else {
return false ;
}
}
2023-11-21 12:12:21 +01:00
function get_user_email_by_id ( $id ) {
$clean_id = $this -> security -> xss_clean ( $id );
$this -> db -> where ( 'user_id' , $clean_id );
$query = $this -> db -> get ( $this -> config -> item ( 'auth_table' ));
$r = $query -> row ();
return $r -> user_email ;
}
2024-08-25 13:08:05 +02:00
function get_user_amsat_status_upload_by_id ( $id ) {
$clean_id = $this -> security -> xss_clean ( $id );
$this -> db -> where ( 'user_id' , $clean_id );
$query = $this -> db -> get ( $this -> config -> item ( 'auth_table' ));
$r = $query -> row ();
return $r -> user_amsat_status_upload ;
}
2023-12-07 16:30:40 +00:00
function hasQrzKey ( $user_id ) {
$this -> db -> where ( 'station_profile.qrzapikey is not null' );
2023-12-14 16:08:17 +01:00
$this -> db -> where ( 'station_profile.qrzapikey != ""' );
2025-03-01 15:50:02 +00:00
$this -> db -> where ( 'station_profile.user_id' , $user_id );
$this -> db -> join ( 'station_profile' , 'station_profile.user_id = ' . $this -> config -> item ( 'auth_table' ) . '.user_id' );
2023-12-07 16:30:40 +00:00
$query = $this -> db -> get ( $this -> config -> item ( 'auth_table' ));
$ret = $query -> row ();
2023-12-13 12:10:20 +00:00
if ( $ret -> user_email ? ? '' != '' ) {
2023-12-13 12:02:20 +00:00
return $ret -> user_email ;
} else {
return '' ;
}
2023-12-07 16:30:40 +00:00
}
2023-04-25 14:00:30 +02:00
function get_email_address ( $station_id ) {
$this -> db -> where ( 'station_id' , $station_id );
$this -> db -> join ( 'station_profile' , 'station_profile.user_id = ' . $this -> config -> item ( 'auth_table' ) . '.user_id' );
2022-11-15 18:29:33 +01:00
$query = $this -> db -> get ( $this -> config -> item ( 'auth_table' ));
2023-08-02 06:34:12 +00:00
2022-11-15 18:29:33 +01:00
$ret = $query -> row ();
return $ret -> user_email ;
}
2011-08-18 21:57:27 +02:00
// FUNCTION: bool exists($username)
// Check if a user exists (by username)
2011-08-18 01:31:15 +01:00
function exists ( $username ) {
2019-10-05 19:35:55 +01:00
$clean_username = $this -> security -> xss_clean ( $username );
if ( $this -> get ( $clean_username ) -> num_rows () == 0 ) {
2011-08-18 01:31:15 +01:00
return 0 ;
} else {
return 1 ;
}
}
2011-08-19 17:13:26 +01:00
// FUNCTION: bool exists_by_id($id)
// Check if a user exists (by user ID)
function exists_by_id ( $id ) {
2019-10-05 19:35:55 +01:00
$clean_id = $this -> security -> xss_clean ( $id );
if ( $this -> get_by_id ( $clean_id ) -> num_rows () == 0 ) {
2011-08-19 17:13:26 +01:00
return 0 ;
} else {
return 1 ;
}
}
// FUNCTION: bool exists_by_email($email)
// Check if a user exists (by email address)
function exists_by_email ( $email ) {
2017-11-30 19:01:11 -07:00
if ( $this -> get_by_email ( $email ) -> num_rows () == 0 ) {
2011-08-19 17:13:26 +01:00
return 0 ;
} else {
return 1 ;
}
}
2025-01-02 10:22:23 +01:00
// FUNCTION: array search_users($query)
// Search for users by parts of their callsign
function search_users ( $query , $clubstations = false ) {
if ( strlen ( $query ) < 2 ) {
return false ;
}
2025-01-02 11:40:14 +01:00
$this -> db -> select ( 'user_id, user_name, user_callsign, user_firstname, user_lastname' );
2025-01-02 10:22:23 +01:00
if ( ! $clubstations ) {
$this -> db -> where ( 'clubstation' , 0 );
}
2025-01-07 07:05:21 +01:00
// if there is a space it's probably a firstname + lastname search
if ( strpos ( $query , ' ' ) !== false ) {
$parts = explode ( ' ' , $query , 2 );
2025-04-28 11:46:28 +02:00
2025-01-07 07:05:21 +01:00
$this -> db -> group_start ();
$this -> db -> like ( 'user_firstname' , $parts [ 0 ]);
$this -> db -> or_like ( 'user_lastname' , $parts [ 0 ]);
$this -> db -> like ( 'user_lastname' , $parts [ 1 ]);
$this -> db -> or_like ( 'user_firstname' , $parts [ 1 ]);
$this -> db -> group_end ();
} else {
$this -> db -> group_start ();
$this -> db -> like ( 'user_callsign' , $query );
$this -> db -> or_like ( 'user_name' , $query );
$this -> db -> or_like ( 'user_firstname' , $query );
$this -> db -> or_like ( 'user_lastname' , $query );
$this -> db -> group_end ();
}
2025-01-02 10:22:23 +01:00
$this -> db -> limit ( 100 );
$r = $this -> db -> get ( $this -> config -> item ( 'auth_table' ));
return $r ;
}
2011-08-18 21:57:27 +02:00
// FUNCTION: bool add($username, $password, $email, $type)
// Add a user
2025-02-24 08:21:57 +00:00
// !!!!!!!!!!!!!!!!
2026-06-07 07:47:27 +02:00
// !! IMPORTANT NOTICE: Please inform DJ7NT and/or DF2ET when adding/removing/changing parameters here.
2026-03-18 10:24:12 +01:00
// !! Also make sure you modify Header_auth::_create_user accordingly, otherwise SSO user creation will break.
2026-03-19 01:00:50 -05:00
// !! Also modify User_model::update_sso_claims with attributes that can be modified by IdP
2025-02-24 08:21:57 +00:00
// !!!!!!!!!!!!!!!!
2021-05-07 08:03:25 +02:00
function add ( $username , $password , $email , $type , $firstname , $lastname , $callsign , $locator , $timezone ,
2025-02-17 12:22:57 +00:00
$measurement , $dashboard_map , $user_date_format , $user_stylesheet , $user_qth_lookup , $user_sota_lookup , $user_wwff_lookup ,
2023-05-01 21:14:30 +02:00
$user_pota_lookup , $user_show_notes , $user_column1 , $user_column2 , $user_column3 , $user_column4 , $user_column5 ,
2023-07-07 16:04:19 +02:00
$user_show_profile_image , $user_previous_qsl_type , $user_amsat_status_upload , $user_mastodon_url ,
2025-10-30 15:37:20 +01:00
$user_default_band , $user_default_confirmation , $user_qso_end_times , $user_qso_db_search_priority , $user_quicklog , $user_quicklog_enter ,
2024-06-06 10:46:12 +02:00
$user_language , $user_hamsat_key , $user_hamsat_workable_only , $user_iota_to_qso_tab , $user_sota_to_qso_tab ,
2025-12-11 05:44:23 +00:00
$user_wwff_to_qso_tab , $user_pota_to_qso_tab , $user_sig_to_qso_tab , $user_dok_to_qso_tab , $user_station_to_qso_tab ,
2024-05-25 21:24:35 +02:00
$user_lotw_name , $user_lotw_password , $user_eqsl_name , $user_eqsl_password , $user_clublog_name , $user_clublog_password ,
2026-08-08 08:29:07 +02:00
$user_winkey , $on_air_widget_enabled , $on_air_widget_display_last_seen , $on_air_widget_show_only_most_recent_radio , $on_air_widget_display_radio_name ,
2026-08-11 13:20:27 +02:00
$qso_widget_display_qso_time , $dashboard_banner , $dashboard_solar , $global_oqrs_text , $oqrs_grouped_search ,
2026-08-11 13:51:23 +02:00
$oqrs_grouped_search_show_station_name , $oqrs_auto_matching , $oqrs_direct_auto_matching , $user_dxwaterfall_enable , $user_qso_show_map ,
$last_lotw_upload_widget_enabled , $clubstation = 0 , $external_account = null ) {
2011-08-19 17:13:26 +01:00
// Check that the user isn't already used
2011-08-18 01:31:15 +01:00
if ( ! $this -> exists ( $username )) {
$data = array (
2019-10-05 22:16:58 +01:00
'user_name' => xss_clean ( $username ),
2011-08-18 01:31:15 +01:00
'user_password' => $this -> _hash ( $password ),
2019-10-05 22:16:58 +01:00
'user_email' => xss_clean ( $email ),
'user_type' => xss_clean ( $type ),
2025-01-02 10:22:23 +01:00
'user_firstname' => xss_clean ( $firstname ) ? ? '' ,
'user_lastname' => xss_clean ( $lastname ) ? ? '' ,
2025-11-14 08:16:28 +01:00
'user_callsign' => str_replace ( 'Ø' , " 0 " , strtoupper ( xss_clean ( $callsign ))),
2025-01-02 10:22:23 +01:00
'user_locator' => strtoupper ( xss_clean ( $locator )),
2020-09-16 20:54:26 +01:00
'user_timezone' => xss_clean ( $timezone ),
'user_measurement_base' => xss_clean ( $measurement ),
'user_date_format' => xss_clean ( $user_date_format ),
2020-09-23 10:59:49 +02:00
'user_stylesheet' => xss_clean ( $user_stylesheet ),
2022-10-19 16:27:26 +02:00
'user_qth_lookup' => xss_clean ( $user_qth_lookup ),
2021-02-26 10:37:43 +01:00
'user_sota_lookup' => xss_clean ( $user_sota_lookup ),
2022-10-19 14:52:43 +02:00
'user_wwff_lookup' => xss_clean ( $user_wwff_lookup ),
2023-05-01 21:14:30 +02:00
'user_pota_lookup' => xss_clean ( $user_pota_lookup ),
2021-03-20 21:19:07 +01:00
'user_show_notes' => xss_clean ( $user_show_notes ),
2021-05-05 17:52:42 +02:00
'user_column1' => xss_clean ( $user_column1 ),
'user_column2' => xss_clean ( $user_column2 ),
'user_column3' => xss_clean ( $user_column3 ),
'user_column4' => xss_clean ( $user_column4 ),
2021-05-07 08:03:25 +02:00
'user_column5' => xss_clean ( $user_column5 ),
2022-07-03 11:39:05 +02:00
'user_show_profile_image' => xss_clean ( $user_show_profile_image ),
2022-11-25 00:22:31 +01:00
'user_previous_qsl_type' => xss_clean ( $user_previous_qsl_type ),
2023-01-27 17:24:48 +01:00
'user_amsat_status_upload' => xss_clean ( $user_amsat_status_upload ),
2023-07-06 08:17:20 +00:00
'user_mastodon_url' => xss_clean ( $user_mastodon_url ),
2023-10-16 22:39:33 +02:00
'user_default_band' => xss_clean ( $user_default_band ),
'user_default_confirmation' => xss_clean ( $user_default_confirmation ),
2023-11-01 14:24:13 +01:00
'user_qso_end_times' => xss_clean ( $user_qso_end_times ),
2023-11-04 18:31:59 +01:00
'user_quicklog' => xss_clean ( $user_quicklog ),
2023-11-05 12:29:59 +01:00
'user_quicklog_enter' => xss_clean ( $user_quicklog_enter ),
2024-06-06 10:46:12 +02:00
'user_language' => xss_clean ( $user_language ),
2024-05-09 14:08:25 +02:00
'user_lotw_name' => xss_clean ( $user_lotw_name ),
'user_lotw_password' => xss_clean ( $user_lotw_password ),
'user_eqsl_name' => xss_clean ( $user_eqsl_name ),
'user_eqsl_password' => xss_clean ( $user_eqsl_password ),
'user_clublog_name' => xss_clean ( $user_clublog_name ),
'user_clublog_password' => xss_clean ( $user_clublog_password ),
2025-01-02 10:22:23 +01:00
'winkey' => xss_clean ( $user_winkey ),
'clubstation' => $clubstation ,
2026-03-08 23:28:03 +01:00
'external_account' => $external_account
2011-08-18 01:31:15 +01:00
);
2011-08-19 17:13:26 +01:00
// Check the password is valid
if ( $data [ 'user_password' ] == EPASSWORDINVALID ) {
return EPASSWORDINVALID ;
}
// Check the email address isn't in use
if ( $this -> exists_by_email ( $email )) {
return EEMAILEXISTS ;
}
2025-02-19 20:36:21 +01:00
// Generate user-slug
if ( ! $this -> load -> is_loaded ( 'encryption' )) {
$this -> load -> library ( 'encryption' );
}
$user_slug_base = md5 ( $this -> encryption -> encrypt ( $username ));
2025-02-20 08:06:53 +01:00
$user_slug = substr ( $user_slug_base , 0 , USER_SLUG_LENGTH );
2025-02-19 20:36:21 +01:00
$data [ 'slug' ] = $user_slug ;
2022-09-06 12:32:54 +02:00
// Add user and insert bandsettings for user
2011-08-18 02:27:53 +01:00
$this -> db -> insert ( $this -> config -> item ( 'auth_table' ), $data );
2022-09-06 12:32:54 +02:00
$insert_id = $this -> db -> insert_id ();
2024-03-03 11:29:03 +01:00
2026-03-16 00:41:20 +01:00
$this -> db -> query ( " insert into bandxuser (bandid, userid) select bands.id, ? from bands; " , [ $insert_id ]);
$this -> db -> query ( " insert into paper_types (user_id,paper_name,metric,width,orientation,height) SELECT ?, paper_name, metric, width, orientation,height FROM paper_types where user_id = 0; " , [ $insert_id ]);
$user_options = [
[ 'hamsat' , 'hamsat_key' , 'api' , $user_hamsat_key ],
[ 'hamsat' , 'hamsat_key' , 'workable' , $user_hamsat_workable_only ],
[ 'qso_tab' , 'iota' , 'show' , (( $user_iota_to_qso_tab ? ? 'off' ) == " on " ? 1 : 0 )],
[ 'qso_tab' , 'sota' , 'show' , (( $user_sota_to_qso_tab ? ? 'off' ) == " on " ? 1 : 0 )],
[ 'qso_tab' , 'wwff' , 'show' , (( $user_wwff_to_qso_tab ? ? 'off' ) == " on " ? 1 : 0 )],
[ 'qso_tab' , 'pota' , 'show' , (( $user_pota_to_qso_tab ? ? 'off' ) == " on " ? 1 : 0 )],
[ 'qso_tab' , 'sig' , 'show' , (( $user_sig_to_qso_tab ? ? 'off' ) == " on " ? 1 : 0 )],
[ 'qso_tab' , 'dok' , 'show' , (( $user_dok_to_qso_tab ? ? 'off' ) == " on " ? 1 : 0 )],
[ 'qso_tab' , 'station' , 'show' , (( $user_station_to_qso_tab ? ? 'off' ) == " on " ? 1 : 0 )],
[ 'qso_tab' , 'map' , 'show' , ( int )( xss_clean ( $user_qso_show_map ? ? 1 ))],
[ 'dashboard' , 'show_map' , 'boolean' , $dashboard_map ? ? 'Y' ],
[ 'dashboard' , 'show_dashboard_banner' , 'boolean' , $dashboard_banner ? ? 'Y' ],
[ 'dashboard' , 'show_dashboard_solar' , 'boolean' , $dashboard_solar ? ? 'Y' ],
[ 'widget' , 'on_air' , 'enabled' , $on_air_widget_enabled ? ? 'false' ],
[ 'widget' , 'on_air' , 'display_last_seen' , $on_air_widget_display_last_seen ? ? 'false' ],
[ 'widget' , 'on_air' , 'display_only_most_recent_radio' , $on_air_widget_show_only_most_recent_radio ? ? 'true' ],
2026-08-08 08:29:07 +02:00
[ 'widget' , 'on_air' , 'display_radio_name' , $on_air_widget_display_radio_name ? ? 'false' ],
2026-03-16 00:41:20 +01:00
[ 'widget' , 'qso' , 'display_qso_time' , $qso_widget_display_qso_time ? ? 'false' ],
[ 'qso_db_search_priority' , 'enable' , 'boolean' , $user_qso_db_search_priority ? ? 'Y' ],
[ 'dxwaterfall' , 'enable' , 'boolean' , $user_dxwaterfall_enable ? ? 'N' ],
2026-08-11 13:17:44 +02:00
[ 'widget' , 'last_lotw_upload' , 'enabled' , $last_lotw_upload_widget_enabled ? ? 'false' ],
2026-03-16 00:41:20 +01:00
];
foreach ( $user_options as [ $type , $name , $key , $value ]) {
$this -> db -> query (
" INSERT INTO user_options (user_id, option_type, option_name, option_key, option_value) VALUES (?, ?, ?, ?, ?) " ,
[ $insert_id , $type , $name , $key , $value ]
);
}
2011-08-19 17:13:26 +01:00
return OK ;
2011-08-18 01:31:15 +01:00
} else {
2011-08-19 17:13:26 +01:00
return EUSERNAMEEXISTS ;
2011-08-18 01:31:15 +01:00
}
}
2011-08-19 17:13:26 +01:00
// FUNCTION: bool edit()
2011-08-18 21:57:27 +02:00
// Edit a user
2011-08-19 20:33:37 +01:00
function edit ( $fields ) {
// Check user privileges
if (( $this -> session -> userdata ( 'user_type' ) == 99 ) || ( $this -> session -> userdata ( 'user_id' ) == $fields [ 'id' ])) {
if ( $this -> exists_by_id ( $fields [ 'id' ])) {
$data = array (
2019-10-05 21:57:44 +01:00
'user_name' => xss_clean ( $fields [ 'user_name' ]),
'user_email' => xss_clean ( $fields [ 'user_email' ]),
2025-11-14 08:07:01 +01:00
'user_callsign' => str_replace ( 'Ø' , " 0 " , strtoupper ( xss_clean ( $fields [ 'user_callsign' ]))),
2025-01-02 10:22:23 +01:00
'user_locator' => strtoupper ( xss_clean ( $fields [ 'user_locator' ])),
2019-10-05 21:57:44 +01:00
'user_firstname' => xss_clean ( $fields [ 'user_firstname' ]),
'user_lastname' => xss_clean ( $fields [ 'user_lastname' ]),
'user_timezone' => xss_clean ( $fields [ 'user_timezone' ]),
'user_lotw_name' => xss_clean ( $fields [ 'user_lotw_name' ]),
'user_eqsl_name' => xss_clean ( $fields [ 'user_eqsl_name' ]),
'user_clublog_name' => xss_clean ( $fields [ 'user_clublog_name' ]),
2020-09-14 12:29:02 +02:00
'user_measurement_base' => xss_clean ( $fields [ 'user_measurement_base' ]),
2020-09-15 22:04:47 +01:00
'user_date_format' => xss_clean ( $fields [ 'user_date_format' ]),
2020-09-23 10:59:49 +02:00
'user_stylesheet' => xss_clean ( $fields [ 'user_stylesheet' ]),
2022-10-19 16:27:26 +02:00
'user_qth_lookup' => xss_clean ( $fields [ 'user_qth_lookup' ]),
2021-02-26 10:37:43 +01:00
'user_sota_lookup' => xss_clean ( $fields [ 'user_sota_lookup' ]),
2022-10-19 14:52:43 +02:00
'user_wwff_lookup' => xss_clean ( $fields [ 'user_wwff_lookup' ]),
2023-05-01 21:14:30 +02:00
'user_pota_lookup' => xss_clean ( $fields [ 'user_pota_lookup' ]),
2021-03-20 21:19:07 +01:00
'user_show_notes' => xss_clean ( $fields [ 'user_show_notes' ]),
2021-05-05 17:52:42 +02:00
'user_column1' => xss_clean ( $fields [ 'user_column1' ]),
'user_column2' => xss_clean ( $fields [ 'user_column2' ]),
'user_column3' => xss_clean ( $fields [ 'user_column3' ]),
'user_column4' => xss_clean ( $fields [ 'user_column4' ]),
2021-05-07 08:03:25 +02:00
'user_column5' => xss_clean ( $fields [ 'user_column5' ]),
2022-07-03 11:39:05 +02:00
'user_show_profile_image' => xss_clean ( $fields [ 'user_show_profile_image' ]),
2022-11-25 00:22:31 +01:00
'user_previous_qsl_type' => xss_clean ( $fields [ 'user_previous_qsl_type' ]),
2023-01-27 17:24:48 +01:00
'user_amsat_status_upload' => xss_clean ( $fields [ 'user_amsat_status_upload' ]),
2023-07-06 08:17:20 +00:00
'user_mastodon_url' => xss_clean ( $fields [ 'user_mastodon_url' ]),
2023-10-16 22:39:33 +02:00
'user_default_band' => xss_clean ( $fields [ 'user_default_band' ]),
2025-08-21 06:29:52 +00:00
'user_default_confirmation' => ( isset ( $fields [ 'user_default_confirmation_qsl' ]) ? 'Q' : '' ) . ( isset ( $fields [ 'user_default_confirmation_lotw' ]) ? 'L' : '' ) . ( isset ( $fields [ 'user_default_confirmation_eqsl' ]) ? 'E' : '' ) . ( isset ( $fields [ 'user_default_confirmation_qrz' ]) ? 'Z' : '' ) . ( isset ( $fields [ 'user_default_confirmation_clublog' ]) ? 'C' : '' ) . ( isset ( $fields [ 'user_default_confirmation_dcl' ]) ? 'D' : '' ),
2023-11-01 14:24:13 +01:00
'user_qso_end_times' => xss_clean ( $fields [ 'user_qso_end_times' ]),
2023-11-04 18:36:08 +01:00
'user_quicklog' => xss_clean ( $fields [ 'user_quicklog' ]),
2023-11-05 12:29:59 +01:00
'user_quicklog_enter' => xss_clean ( $fields [ 'user_quicklog_enter' ]),
2024-06-06 10:46:12 +02:00
'user_language' => xss_clean ( $fields [ 'user_language' ]),
2023-08-03 13:59:02 +01:00
'winkey' => xss_clean ( $fields [ 'user_winkey' ]),
2011-08-19 20:33:37 +01:00
);
2021-02-26 10:37:43 +01:00
2025-01-30 21:09:20 +01:00
// Hard limit safety check for last (recent) QSO count settings
2025-01-29 20:43:47 +01:00
$dashboard_last_qso_count = xss_clean ( $fields [ 'user_dashboard_last_qso_count' ]);
2025-01-30 07:44:48 +01:00
$dashboard_last_qso_count = $dashboard_last_qso_count > DASHBOARD_QSOS_COUNT_LIMIT ? DASHBOARD_QSOS_COUNT_LIMIT : $dashboard_last_qso_count ;
2025-01-30 21:09:20 +01:00
$qso_page_last_qso_count = xss_clean ( $fields [ 'user_qso_page_last_qso_count' ]);
$qso_page_last_qso_count = $qso_page_last_qso_count > QSO_PAGE_QSOS_COUNT_LIMIT ? QSO_PAGE_QSOS_COUNT_LIMIT : $qso_page_last_qso_count ;
2025-01-29 20:43:47 +01:00
2026-03-16 00:41:20 +01:00
// Updated user_options rows — [option_type, option_name, option_key, option_value]
$user_options = [
[ 'hamsat' , 'hamsat_key' , 'api' , $fields [ 'user_hamsat_key' ]],
[ 'hamsat' , 'hamsat_key' , 'workable' , $fields [ 'user_hamsat_workable_only' ]],
[ 'qso_tab' , 'iota' , 'show' , (( $fields [ 'user_iota_to_qso_tab' ] ? ? 'off' ) == " on " ? 1 : 0 )],
[ 'qso_tab' , 'sota' , 'show' , (( $fields [ 'user_sota_to_qso_tab' ] ? ? 'off' ) == " on " ? 1 : 0 )],
[ 'qso_tab' , 'wwff' , 'show' , (( $fields [ 'user_wwff_to_qso_tab' ] ? ? 'off' ) == " on " ? 1 : 0 )],
[ 'qso_tab' , 'pota' , 'show' , (( $fields [ 'user_pota_to_qso_tab' ] ? ? 'off' ) == " on " ? 1 : 0 )],
[ 'qso_tab' , 'sig' , 'show' , (( $fields [ 'user_sig_to_qso_tab' ] ? ? 'off' ) == " on " ? 1 : 0 )],
[ 'qso_tab' , 'dok' , 'show' , (( $fields [ 'user_dok_to_qso_tab' ] ? ? 'off' ) == " on " ? 1 : 0 )],
[ 'qso_tab' , 'station' , 'show' , (( $fields [ 'user_station_to_qso_tab' ] ? ? 'off' ) == " on " ? 1 : 0 )],
[ 'qso_tab' , 'map' , 'show' , ( int )( $fields [ 'user_qso_show_map' ] ? ? 1 )],
[ 'qso_tab' , 'last_qso_count' , 'count' , $qso_page_last_qso_count ],
[ 'widget' , 'on_air' , 'enabled' , $fields [ 'on_air_widget_enabled' ] ? ? 'false' ],
[ 'widget' , 'on_air' , 'display_last_seen' , $fields [ 'on_air_widget_display_last_seen' ] ? ? 'false' ],
[ 'widget' , 'on_air' , 'display_only_most_recent_radio' , $fields [ 'on_air_widget_show_only_most_recent_radio' ] ? ? 'true' ],
2026-08-08 08:29:07 +02:00
[ 'widget' , 'on_air' , 'display_radio_name' , $fields [ 'on_air_widget_display_radio_name' ] ? ? 'false' ],
2026-03-16 00:41:20 +01:00
[ 'widget' , 'qso' , 'display_qso_time' , $fields [ 'qso_widget_display_qso_time' ] ? ? 'false' ],
[ 'dashboard' , 'last_qso_count' , 'count' , $dashboard_last_qso_count ],
[ 'dashboard' , 'show_map' , 'boolean' , $fields [ 'user_dashboard_map' ] ? ? 'Y' ],
[ 'dashboard' , 'show_dashboard_banner' , 'boolean' , $fields [ 'user_dashboard_banner' ] ? ? 'Y' ],
[ 'dashboard' , 'show_dashboard_solar' , 'boolean' , $fields [ 'user_dashboard_solar' ] ? ? 'N' ],
[ 'qso_db_search_priority' , 'enable' , 'boolean' , $fields [ 'user_qso_db_search_priority' ] ? ? 'Y' ],
2026-08-11 09:46:03 +02:00
[ 'dxwaterfall' , 'enable' , 'boolean' , $fields [ 'user_dxwaterfall_enable' ] ? ? 'N' ],
[ 'widget' , 'last_lotw_upload' , 'enabled' , $fields [ 'last_lotw_upload_widget_enabled' ] ? ? 'false' ],
2026-03-16 00:41:20 +01:00
];
foreach ( $user_options as [ $type , $name , $key , $value ]) {
$this -> db -> query (
" REPLACE INTO user_options (user_id, option_type, option_name, option_key, option_value) VALUES (?, ?, ?, ?, ?) " ,
[ $fields [ 'id' ], $type , $name , $key , $value ]
);
}
2025-01-30 07:44:48 +01:00
$this -> session -> set_userdata ( 'dashboard_last_qso_count' , $dashboard_last_qso_count );
2025-04-28 11:46:28 +02:00
$this -> session -> set_userdata ( 'qso_page_last_qso_count' , $qso_page_last_qso_count );
2025-02-17 12:22:57 +00:00
$this -> session -> set_userdata ( 'user_dashboard_map' , xss_clean ( $fields [ 'user_dashboard_map' ] ? ? 'Y' ));
2025-04-28 11:46:28 +02:00
$this -> session -> set_userdata ( 'user_dashboard_banner' , xss_clean ( $fields [ 'user_dashboard_banner' ] ? ? 'Y' ));
2025-09-24 10:24:57 +02:00
$this -> session -> set_userdata ( 'user_dashboard_solar' , xss_clean ( $fields [ 'user_dashboard_solar' ] ? ? 'N' ));
2026-06-07 07:47:27 +02:00
$this -> session -> set_userdata ( 'user_dashboard_show_dxpeditions' , xss_clean ( $fields [ 'user_dashboard_show_dxpeditions' ] ? ? '1' ));
$this -> session -> set_userdata ( 'user_dashboard_show_contests' , xss_clean ( $fields [ 'user_dashboard_show_contests' ] ? ? '1' ));
2026-06-30 10:43:13 +02:00
$this -> session -> set_userdata ( 'user_dashboard_show_kpi_stats' , xss_clean ( $fields [ 'user_dashboard_show_kpi_stats' ] ? ? '1' ));
2025-10-10 03:02:32 +02:00
$this -> session -> set_userdata ( 'user_dxwaterfall_enable' , xss_clean ( $fields [ 'user_dxwaterfall_enable' ] ? ? 'N' ));
2026-06-20 10:29:55 -07:00
$this -> session -> set_userdata ( 'user_stations_active_log_only' , xss_clean ( $fields [ 'user_stations_active_log_only' ] ? ? '0' ));
2024-03-07 16:34:22 +00:00
2011-08-19 20:33:37 +01:00
// Check to see if the user is allowed to change user levels
if ( $this -> session -> userdata ( 'user_type' ) == 99 ) {
$data [ 'user_type' ] = $fields [ 'user_type' ];
}
2021-02-26 10:37:43 +01:00
2011-08-19 20:33:37 +01:00
// Check to see if username is used already
if ( $this -> exists ( $fields [ 'user_name' ]) && $this -> get ( $fields [ 'user_name' ]) -> row () -> user_id != $fields [ 'id' ]) {
return EUSERNAMEEXISTS ;
}
// Check to see if email address is used already
if ( $this -> exists_by_email ( $fields [ 'user_email' ]) && $this -> get_by_email ( $fields [ 'user_email' ]) -> row () -> user_id != $fields [ 'id' ]) {
return EEMAILEXISTS ;
}
2021-02-26 10:37:43 +01:00
2024-05-09 13:09:34 +02:00
$pwd_placeholder = '**********' ;
2011-08-19 20:33:37 +01:00
// Hash password
2026-03-18 17:21:41 -05:00
if ( array_key_exists ( 'user_password' , $fields ) && ( $fields [ 'user_password' ] != NULL ))
2011-08-19 20:33:37 +01:00
{
2024-08-05 21:39:39 +02:00
if ( ! file_exists ( '.demo' ) || ( file_exists ( '.demo' ) && $this -> session -> userdata ( 'user_type' ) == 99 )) {
if ( $fields [ 'user_password' ] !== $pwd_placeholder ) {
$decoded_password = htmlspecialchars_decode ( $fields [ 'user_password' ]);
$data [ 'user_password' ] = $this -> _hash ( $decoded_password );
if ( $data [ 'user_password' ] == EPASSWORDINVALID ) {
return EPASSWORDINVALID ;
}
2025-01-13 09:26:17 +00:00
$data [ 'login_attempts' ] = 0 ;
2024-05-09 13:09:34 +02:00
}
2011-08-19 20:33:37 +01:00
}
2011-08-19 17:13:26 +01:00
}
2024-05-09 09:44:43 +02:00
if ( $fields [ 'user_lotw_password' ] != '' )
2013-08-17 08:54:16 -05:00
{
2024-05-09 13:09:34 +02:00
if ( $fields [ 'user_lotw_password' ] !== $pwd_placeholder ) {
$data [ 'user_lotw_password' ] = $fields [ 'user_lotw_password' ];
}
2024-05-09 09:44:43 +02:00
} else {
$data [ 'user_lotw_password' ] = NULL ;
2013-08-17 08:54:16 -05:00
}
2019-06-19 15:24:07 +01:00
2024-05-09 09:44:43 +02:00
if ( $fields [ 'user_clublog_password' ] != '' )
2019-06-19 15:24:07 +01:00
{
2024-05-09 13:09:34 +02:00
if ( $fields [ 'user_clublog_password' ] !== $pwd_placeholder ) {
$data [ 'user_clublog_password' ] = $fields [ 'user_clublog_password' ];
}
2024-05-09 09:44:43 +02:00
} else {
$data [ 'user_clublog_password' ] = NULL ;
2019-06-19 15:24:07 +01:00
}
2021-02-26 10:37:43 +01:00
2024-05-09 09:44:43 +02:00
if ( $fields [ 'user_eqsl_password' ] != '' )
2013-08-17 09:08:26 -05:00
{
2024-05-09 13:09:34 +02:00
if ( $fields [ 'user_eqsl_password' ] !== $pwd_placeholder ) {
$data [ 'user_eqsl_password' ] = $fields [ 'user_eqsl_password' ];
}
2024-05-09 09:44:43 +02:00
} else {
$data [ 'user_eqsl_password' ] = NULL ;
2013-08-17 09:08:26 -05:00
}
2021-02-26 10:37:43 +01:00
2011-08-19 20:33:37 +01:00
// Update the user
$this -> db -> where ( 'user_id' , $fields [ 'id' ]);
$this -> db -> update ( $this -> config -> item ( 'auth_table' ), $data );
2024-10-31 10:26:59 +01:00
// Remove static map images in cache to make sure they are updated
$this -> load -> model ( 'Stations' );
$this -> load -> model ( 'staticmap_model' );
$stations = $this -> Stations -> all_station_ids_of_user ( $fields [ 'id' ]);
$station_ids = explode ( ',' , $stations );
foreach ( $station_ids as $station_id ) {
$this -> staticmap_model -> remove_static_map_image ( trim ( $station_id ));
}
2011-08-19 20:33:37 +01:00
return OK ;
} else {
return ENOSUCHUSER ;
}
2011-08-19 17:13:26 +01:00
} else {
2011-08-19 20:33:37 +01:00
return EFORBIDDEN ;
2021-02-26 10:37:43 +01:00
}
2011-08-19 17:13:26 +01:00
}
// FUNCTION: bool delete()
// Deletes a user
function delete ( $user_id ) {
if ( $this -> exists_by_id ( $user_id )) {
2024-04-02 15:42:21 +00:00
$this -> load -> model ( 'Stations' );
$stations = $this -> Stations -> all_of_user ( $user_id );
2024-04-02 16:53:28 +00:00
foreach ( $stations -> result () as $row ) {
2024-04-03 08:22:06 +00:00
$this -> Stations -> delete ( $row -> station_id , true , $user_id );
2024-04-02 16:53:28 +00:00
}
2024-04-02 15:42:21 +00:00
// Delete QSOs from $this->config->item('table_name')
$this -> db -> query ( " DELETE FROM bandxuser WHERE userid = ? " , $user_id );
2025-01-02 10:22:23 +01:00
$this -> db -> query ( " DELETE FROM api WHERE user_id = ? OR created_by = ? " , [ $user_id , $user_id ]);
2026-07-18 21:46:07 +02:00
$this -> db -> query ( " DELETE FROM api_token WHERE user_id = ? OR created_by = ? " , [ $user_id , $user_id ]);
2025-01-02 10:22:23 +01:00
$this -> db -> query ( " DELETE FROM club_permissions WHERE user_id = ? OR club_id = ? " , [ $user_id , $user_id ]);
2024-04-02 15:42:21 +00:00
$this -> db -> query ( " DELETE FROM cat WHERE user_id = ? " , $user_id );
$this -> db -> query ( " DELETE FROM lotw_certs WHERE user_id = ? " , $user_id );
$this -> db -> query ( " DELETE FROM notes WHERE user_id = ? " , $user_id );
$this -> db -> query ( " DELETE FROM paper_types WHERE user_id = ? " , $user_id );
$this -> db -> query ( " DELETE FROM label_types WHERE user_id = ? " , $user_id );
$this -> db -> query ( " DELETE FROM queries WHERE userid = ? " , $user_id );
$this -> db -> query ( " DELETE FROM station_profile WHERE user_id = ? " , $user_id );
$this -> db -> query ( " DELETE FROM station_logbooks WHERE user_id = ? " , $user_id );
2026-06-14 13:56:09 +02:00
$this -> db -> query ( " DELETE FROM user_options WHERE user_id = ? " , $user_id );
$this -> db -> query ( " DELETE FROM qsl_postcard_templates WHERE user_id = ? " , $user_id );
2026-06-14 14:00:21 +02:00
if ( ! $this -> paths -> delete_user_files ( $user_id )) {
log_message ( 'error' , 'Failed to delete files for user ID ' . $user_id . '. Delete them manually to free up disk space.' );
}
2024-04-02 16:07:13 +00:00
$this -> db -> query ( " DELETE FROM " . $this -> config -> item ( 'auth_table' ) . " WHERE user_id = ? " , $user_id );
2011-08-19 17:13:26 +01:00
return 1 ;
} else {
return 0 ;
}
2011-08-18 01:31:15 +01:00
}
2011-08-18 21:57:27 +02:00
// FUNCTION: bool login()
// Validates a username/password combination
// This is really just a wrapper around User_Model::authenticate
2011-08-18 01:31:15 +01:00
function login () {
2017-11-07 00:45:06 +00:00
2026-03-18 15:26:31 +01:00
if (( $this -> config -> item ( 'auth_header_enable' ) ? ? false ) && ! ( $this -> config -> item ( 'auth_header_allow_direct_login' ) ? ? true )) {
2026-03-09 12:02:37 +01:00
$this -> session -> set_flashdata ( 'error' , 'Direct login is disabled. Please use the SSO option to log in.' );
redirect ( 'user/login' );
}
2019-10-05 19:35:55 +01:00
$username = $this -> input -> post ( 'user_name' , true );
2024-07-22 22:47:15 +02:00
$password = htmlspecialchars_decode ( $this -> input -> post ( 'user_password' , true ));
2011-08-18 01:31:15 +01:00
return $this -> authenticate ( $username , $password );
}
2011-08-18 21:57:27 +02:00
// FUNCTION: void clear_session()
// Clears a user's login session
// Nothing is returned - it can be assumed that if this is called, the user's
// login session *will* be cleared, no matter what state it is in
2011-08-18 01:31:15 +01:00
function clear_session () {
2021-02-26 10:37:43 +01:00
2017-11-07 00:45:06 +00:00
$this -> session -> sess_destroy ();
2011-08-18 01:31:15 +01:00
}
2021-02-26 10:37:43 +01:00
2011-08-18 21:57:27 +02:00
// FUNCTION: void update_session()
// Updates a user's login session after they've logged in
2025-01-02 10:22:23 +01:00
function update_session ( $id , $u = null , $impersonate = false , $custom_data = null ) {
2021-02-26 10:37:43 +01:00
2026-01-26 09:38:12 +01:00
$u = $u ? : $this -> get_by_id ( $id );
if ( ! $u ) {
return false ;
2024-05-25 21:24:35 +02:00
}
2026-06-08 21:29:17 +02:00
$u = $u -> row ();
2024-08-16 11:05:43 +02:00
2026-06-08 21:29:17 +02:00
// Load all user options once instead of querying per setting below
$user_options = $this -> user_options_model -> get_all_options_for_user ( $u -> user_id );
// Read sessiondata once
$sess = $this -> session -> userdata ();
$token = $sess [ 'session_token' ] ? ? NULL ;
2026-01-26 13:04:28 +01:00
if ( ! $token ) {
$token = bin2hex ( random_bytes ( 32 ));
}
2011-08-18 01:31:15 +01:00
$userdata = array (
2026-06-08 21:29:17 +02:00
'user_id' => $u -> user_id ,
'user_name' => $u -> user_name ,
'user_email' => $u -> user_email ,
'user_type' => $u -> user_type ,
'user_callsign' => $u -> user_callsign ,
'operator_callsign' => ((( $sess [ 'operator_callsign' ] ? ? '' ) == '' ) ? $u -> user_callsign : $sess [ 'operator_callsign' ]),
'user_locator' => $u -> user_locator ,
'user_lotw_name' => $u -> user_lotw_name ,
'user_clublog_name' => $u -> user_clublog_name ? ? '' ,
'user_eqsl_name' => $u -> user_eqsl_name ,
'user_eqsl_qth_nickname' => $u -> user_eqsl_qth_nickname ,
'user_hash' => $this -> _session_hash ( $u -> user_id . $u -> user_type . $token ),
'session_token' => $token ,
'radio' => ((( $sess [ 'radio' ] ? ? '' ) == '' ) ? ( $user_options [ 'cat' ][ 'default_radio' ][ 'radio_id' ] ? ? '' ) : $sess [ 'radio' ]),
'station_profile_id' => $sess [ 'station_profile_id' ] ? ? '' ,
'user_measurement_base' => $u -> user_measurement_base ,
2026-07-14 10:47:30 +00:00
'user_dashboard_map' => array_key_exists ( 'user_dashboard_map' , $sess ) ? $sess [ 'user_dashboard_map' ] : ( $user_options [ 'dashboard' ][ 'show_map' ][ 'boolean' ] ? ? 'Y' ),
'user_dashboard_banner' => array_key_exists ( 'user_dashboard_banner' , $sess ) ? $sess [ 'user_dashboard_banner' ] : ( $user_options [ 'dashboard' ][ 'show_dashboard_banner' ][ 'boolean' ] ? ? 'Y' ),
'user_dashboard_solar' => array_key_exists ( 'user_dashboard_solar' , $sess ) ? $sess [ 'user_dashboard_solar' ] : ( $user_options [ 'dashboard' ][ 'show_dashboard_solar' ][ 'boolean' ] ? ? 'N' ),
'user_dashboard_show_dxpeditions' => array_key_exists ( 'user_dashboard_show_dxpeditions' , $sess ) ? $sess [ 'user_dashboard_show_dxpeditions' ] : ( $user_options [ 'dashboard' ][ 'show_dxpeditions' ][ 'boolean' ] ? ? '0' ),
'user_dashboard_show_contests' => array_key_exists ( 'user_dashboard_show_contests' , $sess ) ? $sess [ 'user_dashboard_show_contests' ] : ( $user_options [ 'dashboard' ][ 'show_contests' ][ 'boolean' ] ? ? '0' ),
'user_dashboard_show_kpi_stats' => array_key_exists ( 'user_dashboard_show_kpi_stats' , $sess ) ? $sess [ 'user_dashboard_show_kpi_stats' ] : ( $user_options [ 'dashboard' ][ 'show_kpi_stats' ][ 'boolean' ] ? ? '1' ),
'user_qso_db_search_priority' => array_key_exists ( 'user_qso_db_search_priority' , $sess ) ? $sess [ 'user_qso_db_search_priority' ] : ( $user_options [ 'qso_db_search_priority' ][ 'enable' ][ 'boolean' ] ? ? 'Y' ),
'user_dxwaterfall_enable' => array_key_exists ( 'user_dxwaterfall_enable' , $sess ) ? $sess [ 'user_dxwaterfall_enable' ] : ( $user_options [ 'dxwaterfall' ][ 'enable' ][ 'boolean' ] ? ? 'N' ),
2026-06-08 21:29:17 +02:00
'user_date_format' => $u -> user_date_format ,
'user_stylesheet' => $u -> user_stylesheet ,
'user_qth_lookup' => isset ( $u -> user_qth_lookup ) ? $u -> user_qth_lookup : 0 ,
'user_sota_lookup' => isset ( $u -> user_sota_lookup ) ? $u -> user_sota_lookup : 0 ,
'user_wwff_lookup' => isset ( $u -> user_wwff_lookup ) ? $u -> user_wwff_lookup : 0 ,
'user_pota_lookup' => isset ( $u -> user_pota_lookup ) ? $u -> user_pota_lookup : 0 ,
'user_show_notes' => isset ( $u -> user_show_notes ) ? $u -> user_show_notes : 1 ,
'user_show_profile_image' => isset ( $u -> user_show_profile_image ) ? $u -> user_show_profile_image : 0 ,
'user_column1' => isset ( $u -> user_column1 ) ? $u -> user_column1 : 'Mode' ,
'user_column2' => isset ( $u -> user_column2 ) ? $u -> user_column2 : 'RSTS' ,
'user_column3' => isset ( $u -> user_column3 ) ? $u -> user_column3 : 'RSTR' ,
'user_column4' => isset ( $u -> user_column4 ) ? $u -> user_column4 : 'Band' ,
'user_column5' => isset ( $u -> user_column5 ) ? $u -> user_column5 : 'Country' ,
'user_previous_qsl_type' => isset ( $u -> user_previous_qsl_type ) ? $u -> user_previous_qsl_type : 0 ,
'user_amsat_status_upload' => isset ( $u -> user_amsat_status_upload ) ? $u -> user_amsat_status_upload : 0 ,
'user_mastodon_url' => $u -> user_mastodon_url ,
'user_default_band' => $u -> user_default_band ,
'user_default_confirmation' => $u -> user_default_confirmation ,
'user_qso_end_times' => isset ( $u -> user_qso_end_times ) ? $u -> user_qso_end_times : 1 ,
'user_quicklog' => isset ( $u -> user_quicklog ) ? $u -> user_quicklog : 1 ,
'user_quicklog_enter' => isset ( $u -> user_quicklog_enter ) ? $u -> user_quicklog_enter : 1 ,
'active_station_logbook' => $u -> active_station_logbook ,
2026-07-14 10:47:30 +00:00
'user_stations_active_log_only' => array_key_exists ( 'user_stations_active_log_only' , $sess ) ? $sess [ 'user_stations_active_log_only' ] : ( $user_options [ 'stations' ][ 'active_log_only' ][ 'boolean' ] ? ? '0' ),
2026-06-08 21:29:17 +02:00
'user_language' => isset ( $u -> user_language ) ? $u -> user_language : 'english' ,
'isWinkeyEnabled' => $u -> winkey ,
2026-06-10 09:10:28 +02:00
'FirstLoginWizard' => ((( $sess [ 'FirstLoginWizard' ] ? ? '' ) == '' ) ? ( $user_options [ 'FirstLoginWizard' ][ 'showed' ][ 'boolean' ] ? ? null ) : $sess [ 'FirstLoginWizard' ]),
2026-06-08 21:29:17 +02:00
'hasQrzKey' => $this -> hasQrzKey ( $u -> user_id ),
'impersonate' => $sess [ 'impersonate' ] ? ? false ,
'clubstation' => $u -> clubstation ,
'dashboard_last_qso_count' => ( $sess [ 'dashboard_last_qso_count' ] ? ? '' ) == '' ? ( $user_options [ 'dashboard' ][ 'last_qso_count' ][ 'count' ] ? ? '' ) : $sess [ 'dashboard_last_qso_count' ],
'qso_page_last_qso_count' => ( $sess [ 'qso_page_last_qso_count' ] ? ? '' ) == '' ? ( $user_options [ 'qso_tab' ][ 'last_qso_count' ][ 'count' ] ? ? '' ) : $sess [ 'qso_page_last_qso_count' ],
'source_uid' => $sess [ 'source_uid' ] ? ? ''
2011-08-18 01:31:15 +01:00
);
2024-08-16 11:05:43 +02:00
2025-01-02 10:22:23 +01:00
if ( $this -> config -> item ( 'special_callsign' )) {
2026-06-08 21:29:17 +02:00
$userdata [ 'available_clubstations' ] = $this -> get_clubstations ( $u -> user_id ) ? ? 'none' ;
2025-01-02 10:22:23 +01:00
}
2024-07-05 21:38:38 +02:00
foreach ( array_keys ( $this -> frequency -> defaultFrequencies ) as $band ) {
2026-06-08 21:29:17 +02:00
$qrg_unit = $sess [ " qrgunit_ $band " ] ? ? ( $user_options [ 'frequency' ][ 'unit' ][ $band ] ? ? '' );
2024-07-05 21:38:38 +02:00
if ( $qrg_unit !== '' ) {
$userdata [ 'qrgunit_' . $band ] = $qrg_unit ;
2024-08-16 11:54:53 +02:00
} else {
$userdata [ 'qrgunit_' . $band ] = $this -> frequency -> defaultFrequencies [ $band ][ 'UNIT' ];
2024-07-05 21:38:38 +02:00
}
}
2024-08-16 11:05:43 +02:00
2025-01-02 10:22:23 +01:00
// Restore custom data in impersonation mode
2026-06-08 21:29:17 +02:00
foreach ( $sess as $key => $value ) {
2025-01-02 10:22:23 +01:00
if ( substr ( $key , 0 , 3 ) == 'cd_' ) {
$userdata [ $key ] = $value ;
}
}
// Overrides
2024-08-27 23:06:22 +02:00
if ( $impersonate ) {
$userdata [ 'impersonate' ] = true ;
2026-06-08 21:29:17 +02:00
$userdata [ 'available_clubstations' ] = $this -> get_clubstations ( $u -> user_id );
2025-01-02 10:22:23 +01:00
}
if ( $userdata [ 'clubstation' ] == 1 ) {
$userdata [ 'available_clubstations' ] = 'none' ;
}
if ( isset ( $custom_data )) {
foreach ( $custom_data as $key => $value ) {
$userdata [ 'cd_' . $key ] = $value ;
}
2024-08-27 23:06:22 +02:00
}
2011-08-18 01:31:15 +01:00
$this -> session -> set_userdata ( $userdata );
2026-01-26 09:38:12 +01:00
return true ;
2011-08-18 01:31:15 +01:00
}
2011-08-18 21:57:27 +02:00
// FUNCTION: bool validate_session()
// Validate a user's login session
// If the user's session is corrupted in any way, it will clear the session
2024-05-25 21:24:35 +02:00
function validate_session ( $u = null ) {
2011-08-18 01:31:15 +01:00
if ( $this -> session -> userdata ( 'user_id' ))
{
$user_id = $this -> session -> userdata ( 'user_id' );
$user_type = $this -> session -> userdata ( 'user_type' );
2025-01-02 10:22:23 +01:00
$src_user_type = $this -> session -> userdata ( 'cd_src_user_type' );
2011-08-18 01:31:15 +01:00
$user_hash = $this -> session -> userdata ( 'user_hash' );
2024-08-27 23:06:22 +02:00
$impersonate = $this -> session -> userdata ( 'impersonate' );
2011-08-18 01:31:15 +01:00
2024-02-25 17:02:57 +01:00
if ( ENVIRONMENT != 'maintenance' ) {
2026-01-26 13:04:28 +01:00
$session_token = $this -> session -> userdata ( 'session_token' );
if ( $session_token && $this -> _auth ( $user_id . $user_type . $session_token , $user_hash )) {
2024-02-25 17:02:57 +01:00
// Freshen the session
2024-05-25 21:24:35 +02:00
$this -> update_session ( $user_id , $u );
2024-02-25 17:02:57 +01:00
return 1 ;
} else {
$this -> clear_session ();
return 0 ;
}
} else { // handle the maintenance mode and kick out user on page reload if not an admin
2025-01-02 10:22:23 +01:00
if ( $user_type == '99' || $src_user_type === '99' ) {
2026-01-26 13:04:28 +01:00
$session_token = $this -> session -> userdata ( 'session_token' );
if ( $session_token && $this -> _auth ( $user_id . $user_type . $session_token , $user_hash )) {
2024-02-25 17:02:57 +01:00
// Freshen the session
2024-05-25 21:24:35 +02:00
$this -> update_session ( $user_id , $u );
2024-02-25 17:02:57 +01:00
return 1 ;
} else {
$this -> clear_session ();
return 0 ;
}
} else {
$this -> clear_session ();
return 0 ;
}
2011-08-18 01:31:15 +01:00
}
} else {
return 0 ;
}
}
2011-08-18 21:57:27 +02:00
// FUNCTION: bool authenticate($username, $password)
// Authenticate a user against the users table
2011-08-18 01:31:15 +01:00
function authenticate ( $username , $password ) {
$u = $this -> get ( $username );
2025-01-02 10:22:23 +01:00
if ( $u -> num_rows () != 0 ) {
// direct login to clubstations are not allowed
2026-02-01 01:07:47 +01:00
if ( $u -> row () -> clubstation == 1 && ! ( $this -> config -> item ( 'club_direct' ) ? ? false )) {
2025-01-02 10:22:23 +01:00
$uid = $u -> row () -> user_id ;
log_message ( 'debug' , " User ID: [ $uid ] Login rejected because of a external clubstation login attempt. " );
return 2 ;
}
2025-01-13 15:23:14 +00:00
if ( $this -> config -> item ( 'max_login_attempts' )) {
$maxattempts = $this -> config -> item ( 'max_login_attempts' );
} else {
$maxattempts = 3 ;
}
if ( $u -> row () -> login_attempts > $maxattempts ) {
2025-01-13 09:13:15 +00:00
$uid = $u -> row () -> user_id ;
log_message ( 'debug' , " User ID: [ $uid ] Login rejected because of too many failed login attempts. " );
return 3 ;
}
2011-08-18 01:31:15 +01:00
if ( $this -> _auth ( $password , $u -> row () -> user_password )) {
2025-01-13 09:13:15 +00:00
$this -> db -> query ( " UPDATE users SET login_attempts = 0 WHERE user_id = ? " , [ $u -> row () -> user_id ]); // Reset failurecount
2024-02-25 14:14:18 +01:00
if ( ENVIRONMENT != " maintenance " ) {
return 1 ;
} else {
if ( $u -> row () -> user_type != 99 ){
return 0 ;
} else {
return 1 ;
}
}
2025-01-13 09:13:15 +00:00
} else { // Update failurecount
$this -> db -> query ( " UPDATE users SET login_attempts = login_attempts+1 WHERE user_id = ? " , [ $u -> row () -> user_id ]);
2011-08-18 01:31:15 +01:00
}
}
return 0 ;
}
2026-03-18 23:34:08 +01:00
// FUNCTION: retrieve a user by their SSO composite key {iss, sub} stored as JSON
2026-03-18 15:26:31 +01:00
function get_by_external_account ( string $key ) {
2026-03-18 23:34:08 +01:00
$table = $this -> config -> item ( 'auth_table' );
$decoded = json_decode ( $key , true );
return $this -> db -> query (
" SELECT * FROM ` $table ` WHERE JSON_VALUE(external_account, ' $ .iss') = ? AND JSON_VALUE(external_account, ' $ .sub') = ? " ,
[ $decoded [ 'iss' ], $decoded [ 'sub' ]]
);
2026-03-18 15:26:31 +01:00
}
// FUNCTION: update specific user fields from SSO claims (bypass privilege check, used during login flow)
function update_sso_claims ( int $user_id , array $fields ) : void {
2026-03-19 01:00:50 -05:00
// Only modify the following
$allowed = [
'user_name' ,
'user_email' ,
'user_callsign' ,
'user_locator' ,
'user_firstname' ,
'user_lastname' ,
'user_timezone' ,
'user_lotw_name' ,
'user_lotw_password' ,
'user_eqsl_name' ,
'user_eqsl_password' ,
'user_eqsl_qth_nickname' ,
'active_station_logbook' ,
'user_language' ,
'user_clublog_name' ,
'user_clublog_password' ,
'user_clublog_callsign' ,
'user_measurement_base' ,
'user_date_format' ,
'user_stylesheet' ,
'user_sota_lookup' ,
'user_wwff_lookup' ,
'user_pota_lookup' ,
'user_qth_lookup' ,
'user_show_notes' ,
'user_column1' ,
'user_column2' ,
'user_column3' ,
'user_column4' ,
'user_column5' ,
'user_show_profile_image' ,
'user_previous_qsl_type' ,
'user_amsat_status_upload' ,
'user_mastodon_url' ,
'user_default_band' ,
'user_default_confirmation' ,
'user_quicklog_enter' ,
'user_quicklog' ,
'user_qso_end_times' ,
'winkey' ,
'slug'
];
$fields = array_intersect_key ( $fields , array_flip ( $allowed ));
2026-03-18 22:53:31 -05:00
2026-03-18 15:26:31 +01:00
$this -> db -> where ( 'user_id' , $user_id );
$this -> db -> update ( 'users' , $fields );
}
2024-01-01 02:08:12 +01:00
// FUNCTION: set's the last-login timestamp in user table
2024-01-08 09:17:09 +01:00
function set_last_seen ( $user_id ) {
2024-01-01 02:08:12 +01:00
$data = array (
2024-01-08 09:17:09 +01:00
'last_seen' => date ( 'Y-m-d H:i:s' )
2024-01-01 02:08:12 +01:00
);
2024-01-08 12:23:32 +01:00
2024-01-01 02:08:12 +01:00
$this -> db -> where ( 'user_id' , $user_id );
$this -> db -> update ( 'users' , $data );
}
2026-06-14 15:19:02 +02:00
// FUNCTION: bool set_user_stylesheet($user_id, $foldername)
// Quickly switch the active theme (stylesheet foldername) for a single user.
// Used by the header theme switcher so users can change skin without opening
// their profile settings. Returns TRUE on success.
function set_user_stylesheet ( $user_id , $foldername ) {
$this -> db -> where ( 'user_id' , xss_clean ( $user_id ));
return $this -> db -> update ( 'users' , array ( 'user_stylesheet' => xss_clean ( $foldername )));
}
2026-08-01 11:27:25 +02:00
/**
* Whether a user is a Wavelog administrator ( user_type 99 )
*
* @ param int $user_id
* @ return boolean
*/
function is_admin ( $user_id ) {
$u = $this -> get_by_id ( $user_id );
if ( $u -> num_rows () == 0 ) {
return false ;
}
return $u -> row () -> user_type == 99 ;
}
2026-07-24 13:22:36 +02:00
// FUNCTION: bool authorize($level)
// Checks a user's level of access against the given $level
2011-08-18 01:31:15 +01:00
function authorize ( $level ) {
$u = $this -> get_by_id ( $this -> session -> userdata ( 'user_id' ));
2011-08-19 18:24:56 +01:00
$l = $this -> config -> item ( 'auth_mode' );
2026-02-02 20:46:46 +01:00
// Run the cache garbage collector here, probability check is already built in
// We run this only for file cache as other adapters have their own GC methods
if ( $this -> config -> item ( 'cache_adapter' ) == 'file' ) {
$this -> load -> library ( 'GarbageCollector' );
$this -> garbagecollector -> run ();
}
2011-08-19 18:24:56 +01:00
// Check to see if the minimum level of access is higher than
// the user's own level. If it is, use that.
if ( $this -> config -> item ( 'auth_mode' ) > $level ) {
$level = $this -> config -> item ( 'auth_mode' );
}
2024-05-25 21:24:35 +02:00
if (( $this -> validate_session ( $u )) && ( $u -> row () -> user_type >= $level ) || $this -> config -> item ( 'use_auth' ) == FALSE || $level == 0 ) {
2024-05-29 13:24:35 +02:00
$ls = strtotime ( $u -> row () -> last_seen ? ? '1970-01-01' );
2024-05-29 07:12:04 +02:00
$n = time ();
if (( $n - $ls ) > 60 ) { // Reduce load. 'set_last_seen()' Shouldn't be called at anytime. 60 seconds diff is enough.
2024-05-29 07:14:10 +02:00
2024-05-26 06:02:51 +00:00
$this -> set_last_seen ( $u -> row () -> user_id );
}
2025-01-02 10:22:23 +01:00
return 1 ;
2011-08-18 01:31:15 +01:00
} else {
return 0 ;
}
}
2025-01-19 09:44:54 +01:00
// FUNCTION: bool unlock($user_id)
// Unlocks a user account after it was locked doe too many failed login attempts
function unlock ( $user_id ) {
return $this -> db -> query ( " UPDATE users SET login_attempts = 0 WHERE user_id = ? " , [ $user_id ]);
}
2011-08-18 21:57:27 +02:00
// FUNCTION: object users()
2024-01-07 23:44:17 +01:00
// Returns a list of users with additional counts
2025-01-02 10:22:23 +01:00
function users ( $club = '' ) {
2025-01-30 20:59:20 +01:00
$qsocount_select = " " ;
$qsocount_join = " " ;
if ( ! ( $this -> config -> item ( 'disable_user_stats' ) ? ? false )) {
$qsocount_select = " , COALESCE(lc.qsocount, 0) AS qsocount, lc.lastqso " ;
2025-04-28 11:46:28 +02:00
$qsocount_join =
2025-01-30 20:59:20 +01:00
" LEFT JOIN (
2025-04-28 11:46:28 +02:00
SELECT sp . user_id ,
2025-01-30 20:59:20 +01:00
COUNT ( l . col_primary_key ) AS qsocount ,
MAX ( l . COL_TIME_ON ) AS lastqso
FROM station_profile sp
JOIN " . $this->config ->item('table_name') . " l ON l . station_id = sp . station_id
GROUP BY sp . user_id
) lc ON lc . user_id = u . user_id " ;
}
2025-04-28 11:46:28 +02:00
$sql = " SELECT
2025-01-30 17:45:51 +01:00
u . user_id ,
u . user_name ,
u . user_firstname ,
u . user_lastname ,
u . user_callsign ,
u . user_email ,
u . user_type ,
u . last_seen ,
u . login_attempts ,
u . clubstation ,
COALESCE ( sp_count . stationcount , 0 ) AS stationcount ,
2025-01-30 20:59:20 +01:00
COALESCE ( sl_count . logbookcount , 0 ) AS logbookcount
" . $qsocount_select . "
2025-01-30 17:45:51 +01:00
FROM users u
LEFT JOIN (
SELECT user_id , COUNT ( * ) AS stationcount
FROM station_profile
GROUP BY user_id
) sp_count ON sp_count . user_id = u . user_id
LEFT JOIN (
SELECT user_id , COUNT ( * ) AS logbookcount
FROM station_logbooks
GROUP BY user_id
2025-01-30 20:59:20 +01:00
) sl_count ON sl_count . user_id = u . user_id "
. $qsocount_join ;
2025-01-30 17:45:51 +01:00
2025-01-02 10:22:23 +01:00
if ( $this -> config -> item ( 'special_callsign' )) {
2025-01-30 17:45:51 +01:00
if ( $club === 'is_club' ) {
$sql .= " WHERE u.clubstation = 1 " ;
2025-01-02 10:22:23 +01:00
} else {
2025-01-30 17:45:51 +01:00
$sql .= " WHERE u.clubstation != 1 " ;
2025-01-02 10:22:23 +01:00
}
}
2025-01-30 17:45:51 +01:00
2025-01-02 10:22:23 +01:00
$result = $this -> db -> query ( $sql );
if ( $this -> config -> item ( 'special_callsign' )) {
2025-01-30 20:59:20 +01:00
if ( $club === 'is_club' && ! ( $this -> config -> item ( 'disable_user_stats' ) ? ? false )) {
2025-01-02 10:22:23 +01:00
foreach ( $result -> result () as & $row ) {
2025-01-30 17:45:51 +01:00
$row -> lastoperator = $this -> get_last_op ( $row -> user_id , $row -> lastqso );
2025-01-02 10:22:23 +01:00
}
} else {
foreach ( $result -> result () as & $row ) {
2025-01-30 20:59:20 +01:00
$row -> lastoperator = '' ; // Important: If 'disable_user_stats' is set to true, the admin won't see the last operator of a clubstation
2025-01-02 10:22:23 +01:00
}
}
}
2024-01-07 23:44:17 +01:00
return $result ;
2011-08-18 01:31:15 +01:00
}
2025-01-02 10:22:23 +01:00
function get_last_op ( $userid , $lastqso ) {
$sql = " SELECT log.COL_OPERATOR FROM " . $this -> config -> item ( 'table_name' ) . " log INNER JOIN station_profile sp ON (log.station_id=sp.station_id) where sp.user_id=? AND col_time_on=? ORDER BY col_time_on DESC LIMIT 1 " ;
$resu = $this -> db -> query ( $sql , array ( $userid , $lastqso ));
return $resu -> result ()[ 0 ] -> COL_OPERATOR ? ? '' ;
}
2011-09-27 23:47:25 +01:00
// FUNCTION: array timezones()
// Returns a list of timezones
function timezones () {
2021-09-28 21:34:32 +02:00
$r = $this -> db -> query ( 'SELECT id, name FROM timezones ORDER BY `offset`' );
2011-09-27 23:47:25 +01:00
$ts = array ();
foreach ( $r -> result_array () as $t ) {
$ts [ $t [ 'id' ]] = $t [ 'name' ];
}
return $ts ;
}
2021-08-09 13:13:41 +02:00
// FUNCTION: array getThemes()
// Returns a list of themes
function getThemes () {
$result = $this -> db -> query ( 'SELECT * FROM themes order by name' );
return $result -> result ();
}
2022-01-18 15:29:22 +00:00
/*
* FUNCTION : set_password_reset_code
*
* Stores generated password reset code in the database and sets the date to exactly
* when the sql query runs .
2023-08-02 06:34:12 +00:00
*
2022-01-18 15:29:22 +00:00
* @ param string $user_email
* @ return string $reset_code
*/
function set_password_reset_code ( $user_email , $reset_code ) {
$data = array (
'reset_password_code' => $reset_code ,
'reset_password_date' => date ( 'Y-m-d H:i:s' )
);
2023-08-02 06:34:12 +00:00
2022-01-18 15:29:22 +00:00
$this -> db -> where ( 'user_email' , $user_email );
$this -> db -> update ( 'users' , $data );
}
2022-01-18 16:14:22 +00:00
/*
* FUNCTION : reset_password
*
* Sets new password for users account where the reset code matches then clears the password reset code and password reset date .
2023-08-02 06:34:12 +00:00
*
2022-01-18 16:14:22 +00:00
* @ param string $password
* @ return string $reset_code
*/
function reset_password ( $password , $reset_code ) {
$data = array (
'user_password' => $this -> _hash ( $password ),
'reset_password_code' => NULL ,
2025-01-13 09:26:17 +00:00
'reset_password_date' => NULL ,
'login_attempts' => 0
2022-01-18 16:14:22 +00:00
);
2023-08-02 06:34:12 +00:00
2022-01-18 16:14:22 +00:00
$this -> db -> where ( 'reset_password_code' , $reset_code );
$this -> db -> update ( 'users' , $data );
}
2011-08-18 21:57:27 +02:00
// FUNCTION: bool _auth($password, $hash)
// Checks a password against the stored hash
2026-01-26 09:37:21 +01:00
// Understands the difference between password and session hashes
2011-08-18 01:31:15 +01:00
private function _auth ( $password , $hash ) {
2026-01-26 09:37:21 +01:00
if ( strpos ( $hash , '$2y$' ) === 0 || strlen ( $hash ) === 60 ) {
return password_verify ( $password , $hash ) ? 1 : 0 ;
2011-08-18 01:31:15 +01:00
}
2026-01-26 09:37:21 +01:00
return hash_equals ( $this -> _session_hash ( $password ), $hash ) ? 1 : 0 ;
2011-08-18 01:31:15 +01:00
}
2011-08-18 21:57:27 +02:00
// FUNCTION: string _hash($password)
// Returns a hashed version of the supplied $password
// Will return '0' in the event of problems with the
// hashing function
2011-08-18 01:31:15 +01:00
private function _hash ( $password ) {
2021-02-26 10:37:43 +01:00
$hash = password_hash ( $password , PASSWORD_DEFAULT );
2011-08-18 01:31:15 +01:00
if ( strlen ( $hash ) < 20 ) {
2011-08-19 17:13:26 +01:00
return EPASSWORDINVALID ;
2011-08-18 01:31:15 +01:00
} else {
return $hash ;
}
}
2021-02-26 10:37:43 +01:00
2026-01-26 09:37:21 +01:00
// FUNCTION: string _session_hash($payload)
// Creates a HMAC-SHA256 hash of the supplied $payload
// Used for session validation as it is blazing fast and will
// Be different after each Login
private function _session_hash ( $payload ) {
$secret = $this -> config -> item ( 'encryption_key' );
if (( $secret ? ? NULL ) == NULL ) {
log_message ( 'error' , 'Encryption key is not set in config.php! Session security is compromised!' );
// A fully missing encryption key is a showstopper, throw an exception
// This also means that there is something seriously wrong with the installation
throw new RuntimeException ( 'Encryption key not configured' );
} elseif ( $secret == 'flossie1234555541' ) { // Once upon a time, this was the default key shipped which never changed
log_message ( 'error' , 'Default encryption key is set in config.php ("flossie...")! Session security is compromised! Change the encryption key to a unique value!' );
}
return hash_hmac ( 'sha256' , ( string ) $payload , $secret );
}
2024-07-11 14:17:38 +02:00
/**
* Function to create a safe hash , which can be securely stored in the browser
* to keep a user logged in for a defined time range .
*/
function keep_cookie_hash ( $user_id ) {
/**
* get some client information , to include in the hash we want to make a has unique for a certain browser
*/
// Client Browser and OS
$client_browser = base64_encode ( $_SERVER [ 'HTTP_USER_AGENT' ]);
// Client language
$client_lang = base64_encode ( $_SERVER [ 'HTTP_ACCEPT_LANGUAGE' ]);
$uid = base64_encode ( $user_id );
// Create a long string out of the client data
2024-07-11 15:31:38 +02:00
$client_string = $client_browser . $client_lang . $uid ;
2024-07-11 14:17:38 +02:00
// Now we load the Encryption Lib
if ( ! $this -> load -> is_loaded ( 'encryption' )) {
$this -> load -> library ( 'encryption' );
}
// And creating a secure hash of the client data
$encrypted_string = $this -> encryption -> encrypt ( $client_string );
$hash = $encrypted_string . base64_encode ( $this -> config -> item ( 'base_url' )) . base64_encode ( $user_id );
return $hash ;
}
function check_keep_hash ( $a , $b ) {
// Load the Encryption Lib
if ( ! $this -> load -> is_loaded ( 'encryption' )) {
$this -> load -> library ( 'encryption' );
}
// Decrypt string a
$dec_a = $this -> encryption -> decrypt ( $a );
// Decrypt string b
$dec_b = $this -> encryption -> decrypt ( $b );
if ( $dec_a === $dec_b ) {
return true ;
} else {
return false ;
}
}
2025-01-02 10:22:23 +01:00
function get_clubstations ( $user_id ) {
$this -> load -> model ( 'club_model' );
$clubstations = $this -> club_model -> get_clubstations ( $user_id );
return $clubstations ;
}
function convert ( $user_id , $clubstation ) {
$sql = " UPDATE users SET clubstation = ? WHERE user_id = ?; " ;
2025-04-28 11:46:28 +02:00
2025-01-02 10:22:23 +01:00
$this -> db -> trans_start ();
2025-04-28 11:46:28 +02:00
2025-01-07 06:49:32 +01:00
if ( ! $this -> db -> query ( $sql , [ $clubstation , $user_id ])) {
2025-01-02 10:22:23 +01:00
$this -> db -> trans_rollback ();
return false ;
}
2025-04-28 11:46:28 +02:00
2025-01-07 06:49:32 +01:00
// Remove all club permissions in case there is a club with this user id
$delete_sql = " DELETE FROM club_permissions WHERE club_id = ?; " ;
if ( ! $this -> db -> query ( $delete_sql , [ $user_id ])) {
$this -> db -> trans_rollback ();
return false ;
2025-01-02 10:22:23 +01:00
}
2025-04-28 11:46:28 +02:00
2026-08-01 09:45:18 +02:00
$this -> load -> model ( 'api_v2_model' );
$this -> api_v2_model -> revoke_club_tokens ( $user_id );
$this -> db -> query ( " DELETE FROM api WHERE user_id = ? AND created_by != ? " , [ $user_id , $user_id ]);
$this -> db -> query ( " DELETE FROM cat WHERE user_id = ? AND operator != ? " , [ $user_id , $user_id ]);
2025-01-02 10:22:23 +01:00
$this -> db -> trans_complete ();
2025-04-28 11:46:28 +02:00
2025-01-02 10:22:23 +01:00
return $this -> db -> trans_status ();
}
2025-01-05 10:43:30 +01:00
function firstlogin_wizard ( $stationdata ) {
if ( empty ( $stationdata )) {
$this -> user_options_model -> set_option ( 'FirstLoginWizard' , 'showed' , array ( 'boolean' => 1 )); // We try to setup the station only once, so we set the user_option to 1 to prevent the wizard from showing up again
return false ;
}
try {
2025-04-28 11:46:28 +02:00
$this -> db -> query ( " INSERT INTO station_logbooks (user_id, logbook_name, modified, public_slug, public_search)
2025-01-05 10:43:30 +01:00
VALUES ( ? , 'Home Logbook' , NULL , NULL , 0 ) " , [ $stationdata['user_id'] ]
);
$station_logbooks_insert_id = $this -> db -> insert_id ();
2025-04-28 11:46:28 +02:00
$this -> db -> query ( " UPDATE users
SET active_station_logbook = ?
2025-01-05 10:43:30 +01:00
WHERE user_id = ? " , [ $station_logbooks_insert_id , $stationdata['user_id'] ]
);
$this -> load -> model ( 'logbook_model' );
$this -> db -> query ( " INSERT INTO station_profile (
station_profile_name , station_gridsquare , station_city , station_iota , station_sota , station_callsign , station_power ,
station_dxcc , station_cnty , station_cq , station_itu , station_active , eqslqthnickname , state , qrzapikey , county ,
station_sig , station_sig_info , qrzrealtime , user_id , station_wwff , station_pota , oqrs , oqrs_text , oqrs_email ,
webadifapikey , webadifapiurl , webadifrealtime , clublogignore , clublogrealtime , hrdlogrealtime , hrdlog_code , hrdlog_username
) VALUES (
2025-04-28 11:46:28 +02:00
? , ? , '' , '' , '' , ? , NULL , ? , '' , ? , ? , 1 , '' , '' , '' , '' , '' , '' , 0 , ? , '' , '' , 0 , '' , 0 , '' ,
2025-01-05 10:43:30 +01:00
'https://qo100dx.club/api' , 0 , 0 , 0 , 0 , '' , ''
) " , [
$stationdata [ 'station_name' ],
strtoupper ( $stationdata [ 'station_locator' ]),
strtoupper ( $stationdata [ 'station_callsign' ]),
$stationdata [ 'station_dxcc' ],
$stationdata [ 'station_cqz' ],
$stationdata [ 'station_ituz' ],
$stationdata [ 'user_id' ]
]
);
$station_profile_insert_id = $this -> db -> insert_id ();
2025-04-28 11:46:28 +02:00
$this -> db -> query ( " INSERT INTO station_logbooks_relationship (station_logbook_id, station_location_id, modified)
2025-01-05 10:43:30 +01:00
VALUES ( ? , ? , NULL ) " , [ $station_logbooks_insert_id , $station_profile_insert_id ]
);
$this -> user_options_model -> set_option ( 'FirstLoginWizard' , 'showed' , array ( 'boolean' => 1 ));
return true ;
} catch ( Exception $e ) {
log_message ( 'error' , 'Firstlogin wizard failed: ' . $e -> getMessage ());
$this -> user_options_model -> set_option ( 'FirstLoginWizard' , 'showed' , array ( 'boolean' => 1 )); // We try to setup the station only once, so we set the user_option to 1 to prevent the wizard from showing up again
return false ;
}
}
2011-08-18 01:31:15 +01:00
}
?>