diff --git a/auth.php b/auth.php index 8f1b6ae..e8246b4 100644 --- a/auth.php +++ b/auth.php @@ -25,7 +25,6 @@ defined('MOODLE_INTERNAL') || die(); require_once($CFG->libdir.'/authlib.php'); -use enrol_wallet\transactions; // For further information about authentication plugins please read // https://docs.moodle.org/dev/Authentication_plugins. @@ -95,11 +94,6 @@ public function user_signup($user, $notify = true) { $user->calendartype = $CFG->calendartype; } - if (!$DB->record_exists('auth_wallet_confirm', ['userid' => $user->id])) { - $params = ['userid' => $user->id, 'confirmed' => 0, 'timecreated' => time()]; - $DB->insert_record('auth_wallet_confirm', $params); - } - // Check if the user already existed. $exist = get_complete_user_data('username', $user->username); if (empty($exist->id)) { @@ -110,6 +104,13 @@ public function user_signup($user, $notify = true) { // Save any custom profile field information. profile_save_data($user); + } else { + $user->id = $exist->id; + } + + if (!$DB->record_exists('auth_wallet_confirm', ['userid' => $user->id])) { + $params = ['userid' => $user->id, 'timecreated' => time(), 'timemodified' => time()]; + $DB->insert_record('auth_wallet_confirm', $params); } // Save wantsurl against user's profile, so we can return them there upon confirmation. @@ -159,50 +160,28 @@ public function user_confirm($username, $confirmsecret) { $user = get_complete_user_data('username', $username); if (!empty($user)) { - $payconfirm = get_user_preferences('auth_wallet_balanceconfirm', false, $user); - $all = get_config('auth_wallet', 'all'); + $payconfirm = auth_wallet_is_confirmed($user); + $all = $this->config->all; $verified = empty($user->secret) || $user->secret === $confirmsecret; if (empty($all) && $user->auth != 'wallet') { - return AUTH_CONFIRM_ERROR; + return AUTH_CONFIRM_OK; } else if ($user->confirmed && !empty($payconfirm)) { return AUTH_CONFIRM_ALREADY; - } else if ($verified && !empty($payconfirm)) { - $DB->set_field("user", "confirmed", 1, array("id" => $user->id)); - return AUTH_CONFIRM_OK; - - } else if ($verified && empty($payconfirm)) { - - $DB->set_field("user", "confirmed", 1, array("id" => $user->id)); - - $required = $this->config->required_balance; - $balance = transactions::get_user_balance($user->id); - $method = $this->config->criteria; - $fee = $this->config->required_fee; - $extrafee = $this->config->extra_fee; - - // Check if the user balance is sufficient. - if ($method == 'balance' && $balance < $required) { - return AUTH_CONFIRM_FAIL; - } else if ($method == 'balance' && !empty($extrafee) && $balance >= $required) { - $desc = get_string('debitextrafee_desc', 'auth_wallet'); - transactions::debit($user->id, $extrafee, '', '', $desc); + } else if ($verified) { + if (!$user->confirmed) { + $DB->set_field("user", "confirmed", 1, ["id" => $user->id]); + $user->confirmed = true; } - // Check if the method depend on paying a confirm fee and not confirmed yet. - if ($method === 'fee') { - // Check if there already enough balance for paying the fee. - if ($method === 'fee' && $balance >= $fee) { - $desc = get_string('debitfee_desc', 'auth_wallet'); - transactions::debit($user->id, $fee, '', '', $desc); - } else { - return AUTH_CONFIRM_FAIL; - } + if (!$payconfirm) { + return AUTH_CONFIRM_FAIL; } auth_wallet_set_confirmed($user); + if ($wantsurl = get_user_preferences('auth_wallet_wantsurl', false, $user)) { // Ensure user gets returned to page they were trying to access before signing up. $SESSION->wantsurl = $wantsurl; diff --git a/classes/task/nonconfirmed_cleanup.php b/classes/task/nonconfirmed_cleanup.php new file mode 100644 index 0000000..3ae5c94 --- /dev/null +++ b/classes/task/nonconfirmed_cleanup.php @@ -0,0 +1,84 @@ +. + +/** + * Clean up non-confirmed users.. + * + * @package auth_wallet + * @copyright 2023 Mo Farouk + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace auth_wallet\task; + +/** + * Clean up non-confirmed users. + */ +class nonconfirmed_cleanup extends \core\task\scheduled_task { + + /** + * Name for this task. + * + * @return string + */ + public function get_name() { + return get_string('cleanup_nonconfirmed', 'auth_wallet'); + } + + /** + * Run task for cleaning up users. + */ + public function execute() { + global $DB, $CFG; + require_once("$CFG->dirroot/user/lib.php"); + require_once("$CFG->dirroot/auth/wallet/lib.php"); + + if (empty($CFG->deleteunconfirmed)) { + mtrace('Configuration deleteunconfirmed set to never ...'); + return; + } + + $intval = $CFG->deleteunconfirmed * 60 * 60; + + \core_php_time_limit::raise(); + raise_memory_limit(MEMORY_HUGE); + + $trace = new \text_progress_trace(); + $trace->output('Task started...'); + + $select = 'confirmed != :confirmed AND timecreated < :timetosearch'; + $params = ['confirmed' => 1, 'timetosearch' => time() - $intval]; + $records = $DB->get_records_select('auth_wallet_confirm', $select, $params); + + $trace->output(count($records) . ' users found to delete.'); + foreach ($records as $record) { + // Double check that the user is confirmed before delete. + if ($user = get_complete_user_data('id', $record->userid)) { + if (auth_wallet_is_confirmed($user)) { + $trace->output('User with id ' . $user->id . ' already confirmed and skipped...'); + continue; + } + user_delete_user($user); + } + $DB->delete_records('auth_wallet_confirm', ['userid' => $record->userid]); + $trace->output('user with id ' . $record->userid . ' has been deleted...'); + } + + $trace->output('Finished.'); + $trace->finished(); + } + +} diff --git a/confirm.php b/confirm.php index c2415e9..682bdf8 100644 --- a/confirm.php +++ b/confirm.php @@ -35,12 +35,12 @@ $p = optional_param('p', '', PARAM_ALPHANUM); // Parameter: secret. $s = optional_param('s', '', PARAM_RAW); // Parameter: username. $data = optional_param('data', '', PARAM_RAW); -$redirect = optional_param('redirect', '', PARAM_LOCALURL); +$redirect = optional_param('redirect', '', PARAM_URL); if (empty($redirect)) { if (isset($SESSION->wantsurl)) { - $redirect = new moodle_url($SESSION->wantsurl); + $redirect = (new moodle_url($SESSION->wantsurl))->out(false); } else if ($base = get_user_preferences('auth_wallet_wantsurl', false)) { - $redirect = new moodle_url($base); + $redirect = (new moodle_url($base))->out(false); } else { $redirect = core_login_get_return_url(); } @@ -81,7 +81,9 @@ } $user = get_complete_user_data('username', $username); - + if (!$user || isguestuser($user)) { + throw new \moodle_exception('cannotfinduser', '', '', s($username)); + } $confirmed = $authplugin->user_confirm($username, $usersecret); if ($confirmed == AUTH_CONFIRM_ALREADY) { @@ -97,12 +99,7 @@ exit; } else if ($confirmed == AUTH_CONFIRM_OK) { - // The user has confirmed successfully, let's log them in. - if (!$user) { - throw new \moodle_exception('cannotfinduser', '', '', s($username)); - } - if (empty($user->suspended)) { complete_user_login($user); @@ -129,7 +126,8 @@ echo $OUTPUT->footer(); exit; } else if ($confirmed == AUTH_CONFIRM_ERROR) { - throw new \moodle_exception('invalidconfirmdata'); + debugging('Confirmation Error.', DEBUG_NONE); + redirect(new moodle_url('/login/index.php'), get_string('invalidconfirmdata'), null, 'error'); } } @@ -137,12 +135,10 @@ $user = get_complete_user_data('username', $s); } else { global $USER; - $user = get_complete_user_data('id', $USER->id); + $user = fullclone($USER); } -// Reaching this part of the code means either the user confirmed by email already and wait payment confirmation, -// or confirmation by email is disabled. -if (!empty($user) && is_object($user)) { +if (!empty($user) && is_object($user) && !isguestuser($user)) { $payconfirm = auth_wallet_is_confirmed($user); @@ -150,8 +146,9 @@ if (!empty($user->confirmed) || empty($emailconfirm) - || empty($user->confirm) || $user->auth != 'wallet') { + // Reaching this part of the code means either the user confirmed by email already and wait payment confirmation, + // or confirmation by email is disabled. // Prepare redirection url. if (!empty($user->confirmed)) { @@ -165,50 +162,20 @@ $DB->set_field('user', 'secret', $user->secret, ['id' => $user->id]); } $params['p'] = $user->secret; - + $params['redirect'] = $redirect; $url = new \moodle_url('/auth/wallet/confirm.php', $params); } // Login the user to enable payment. if (!isloggedin() || empty($user->id)) { - complete_user_login($user); - - if (empty($user->id)) { - global $USER; - $user = get_complete_user_data('id', $USER->id); - } + $user = complete_user_login($user); \core\session\manager::apply_concurrent_login_limit($user->id, session_id()); } require_login(); - $transactions = new enrol_wallet\transactions; - - $balance = $transactions->get_user_balance($user->id); - $confirmmethod = get_config('auth_wallet', 'criteria'); - $required = get_config('auth_wallet', 'required_balance'); - $fee = get_config('auth_wallet', 'required_fee'); - $extrafee = get_config('auth_wallet', 'extra_fee'); - - if ($confirmmethod === 'balance' && $balance >= $required) { - if (!empty($extrafee)) { - if ($balance >= $extrafee) { - if (empty($payconfirm)) { - $transactions->debit($user->id, $extrafee); - } - } else { - throw new moodle_exception('insufficientbalance'); - } - } - auth_wallet_set_confirmed($user); - redirect($url); - - } else if ($confirmmethod === 'fee' && $balance >= $fee) { - if (empty($payconfirm)) { - $transactions->debit($user->id, $fee, 'New user fee'); - } - auth_wallet_set_confirmed($user); + if (!empty($payconfirm)) { redirect($url); } else { // Display the payment page. @@ -225,6 +192,7 @@ 'extrafee' => !empty($extrafee) ? get_string('extrafeerequired', 'auth_wallet', $extrafee) : '', ]; + $confirmmethod = get_config('auth_wallet', 'criteria'); if ($confirmmethod === 'balance') { echo get_string('payment_required', 'auth_wallet', $a); echo enrol_wallet_display_topup_options(); @@ -243,8 +211,7 @@ } } } - redirect($redirect); - -} else { - throw new \moodle_exception("errorwhenconfirming"); } + +// Not recognized user, suspended user or not confirmed by email yet. +redirect(new moodle_url('/login/index.php'), get_string('errorwhenconfirming'), null, 'error'); diff --git a/db/tasks.php b/db/tasks.php index d782681..a196716 100644 --- a/db/tasks.php +++ b/db/tasks.php @@ -29,7 +29,7 @@ [ 'classname' => '\auth_wallet\task\nonconfirmed_cleanup', 'blocking' => 0, - 'minute' => '*', + 'minute' => '0', 'hour' => '*/4', 'day' => '*', 'month' => '*', diff --git a/lang/en/auth_wallet.php b/lang/en/auth_wallet.php index ae80e24..6fc4460 100644 --- a/lang/en/auth_wallet.php +++ b/lang/en/auth_wallet.php @@ -63,3 +63,4 @@ $string['settingerror'] = 'Configuration error, please contact support.'; $string['usersconfirmed'] = '{$a} user(s) has been confirmed.'; $string['wallet:manualconfirm'] = 'Manually confirm wallet signup users'; +$string['cleanup_nonconfirmed'] = 'Cleanup non-confirmed users by wallet balance'; diff --git a/lib.php b/lib.php index 0289d55..bb317e2 100644 --- a/lib.php +++ b/lib.php @@ -26,26 +26,46 @@ require_once($CFG->libdir.'/authlib.php'); +/** + * Fire up each time $CFG load. + * @return void + */ +function auth_wallet_after_config() { + global $USER; + + if (isloggedin() && !isguestuser() && !empty($USER->id)) { + // Check if first required payment already done. + $payconfirm = get_user_preferences('auth_wallet_balanceconfirm', false, $USER); + if (!empty($payconfirm) && !empty($USER->confirmed)) { + return; + } + auth_wallet_after_require_login(); + } +} + /** * Fire up each time require_login() called and redirect non-confirmed users to confirm page. * @return void */ function auth_wallet_after_require_login() { - global $USER, $CFG, $DB, $SESSION; + global $USER, $CFG, $FULLME; require_once($CFG->dirroot . '/enrol/wallet/locallib.php'); require_once($CFG->dirroot.'/login/lib.php'); - if (isguestuser() || empty($USER->id)) { + if (!isloggedin() || isguestuser() || is_siteadmin()) { + return; + } + + if (AJAX_SCRIPT) { return; } if (file_exists($CFG->dirroot.'/auth/parent/lib.php')) { require_once($CFG->dirroot.'/auth/parent/lib.php'); - if (auth_parent_is_parent($USER)) { return; } - } + $all = get_config('auth_wallet', 'all'); // Disable redirection in case of another auth plugin. if (empty($all) && $USER->auth !== 'wallet') { @@ -57,6 +77,57 @@ function auth_wallet_after_require_login() { if (!empty($payconfirm)) { return; } + + $currentpage = new moodle_url($FULLME); + if (!auth_wallet_should_redirect($currentpage)) { + return; + } + + $params = [ + 's' => $USER->username, + ]; + if (empty(get_config('auth_wallet', 'emailconfirm')) || !empty($USER->confirmed)) { + // If no need for email confirmation or the user is already confirmed this way. + if (empty($USER->secret)) { + $USER->secret = random_string(15); + $DB->set_field('user', 'secret', $USER->secret, ['id' => $USER->id]); + } + $params['p'] = $USER->secret; + } + + $confirmationurl = new \moodle_url('/auth/wallet/confirm.php', $params); + redirect($confirmationurl); +} + +/** + * Should the passed url directed or not. + * @return bool + */ +function auth_wallet_should_redirect(moodle_url $url) { + global $CFG, $USER; + $wwwroot = new moodle_url($CFG->wwwroot); + $paths = [ + 'user/view.php', // Any editing or viewing for profile pages. + 'user/edit.php', + 'user/editadvanced.php', + 'auth/wallet/confirm.php', // Confirmation page. + 'payment/gateway', // Any payment gateway file for payments. + 'login/logout.php', // Logging out or logging in pages. + 'login/index.php', + 'enrol/wallet', // Enrol wallet action pages. + ]; + if ($wwwroot->get_host() !== $url->get_host()) { + // Any non local pages. + return false; + } + + foreach ($paths as $path) { + if (stripos($url->get_path(), $path) !== false + || stripos($path, $url->get_path()) !== false) { + return false; + } + } + $itemid = optional_param('itemid', '', PARAM_INT); $paymentarea = optional_param('paymentarea', '', PARAM_TEXT); $component = optional_param('component', '', PARAM_RAW); @@ -69,7 +140,6 @@ function auth_wallet_after_require_login() { $l = optional_param('logout', '', PARAM_TEXT); $returnto = optional_param('returnto', '', PARAM_TEXT); $data = optional_param('data', '', PARAM_RAW); - $id = optional_param('id', '', PARAM_INT); $action = optional_param('action', '', PARAM_TEXT); // Disable redirection in case of payment process, confirm page, apply coupon or profile edit. @@ -85,28 +155,13 @@ function auth_wallet_after_require_login() { || !empty($returnto) || !empty($obj) || !empty($data) - || (!empty($id) && $id == $USER->id) || !empty($action) ) { - return; + return false; } - $params = [ - 's' => $USER->username, - ]; - if (empty(get_config('auth_wallet', 'emailconfirm')) // Email confirmation disabled. - || ($USER->auth == 'wallet' && !empty($USER->confirmed)) // Email already confirmed. - || ($USER->auth != 'wallet') // Another auth method. - ) { - if (empty($USER->secret)) { - $USER->secret = random_string(15); - $DB->set_field('user', 'secret', $USER->secret, ['id' => $USER->id]); - } - $params['p'] = $USER->secret; - } - $confirmationurl = new \moodle_url('/auth/wallet/confirm.php', $params); - redirect($confirmationurl); + return true; } /** @@ -121,29 +176,63 @@ function auth_wallet_is_confirmed($user) { if (!$all && $user->auth != 'wallet') { return true; } + $payconfirm = get_user_preferences('auth_wallet_balanceconfirm', false, $user); if ($payconfirm) { auth_wallet_set_confirmed($user); + return true; } + $confirmrecord = $DB->record_exists('auth_wallet_confirm', ['userid' => $user->id, 'confirmed' => 1]); - return $payconfirm || $confirmrecord; + + if (!$confirmrecord) { + if (auth_wallet_check_conditions($user)) { + auth_wallet_set_confirmed($user); + return true; + } + } + + return $confirmrecord; } /** - * Fire up each time $CFG load. - * @return void + * Check the conditions for confirming the user. + * @param object $user + * @return bool */ -function auth_wallet_after_config() { - global $USER; +function auth_wallet_check_conditions($user) { - if (isloggedin() && !isguestuser() && !empty($USER->id)) { - // Check if first required payment already done. - $payconfirm = get_user_preferences('auth_wallet_balanceconfirm', false, $USER); - if (!empty($payconfirm) && !empty($USER->confirmed)) { - return; - } - auth_wallet_after_require_login(); + $config = get_config('auth_wallet'); + $all = $config->all; + + if (empty($all) && $user->auth !== 'wallet') { + return true; + } + + if (empty($user->confirmed)) { + return false; + } + + $required = $config->required_balance; + $balance = enrol_wallet\transactions::get_user_balance($user->id); + $method = $config->criteria; + $fee = $config->required_fee; + $extrafee = $config->extra_fee; + + // Check if the user balance is sufficient. + if ($method == 'balance' && $balance >= $required && empty($extrafee)) { + return true; + } else if ($method == 'balance' && $balance >= $required) { + $desc = get_string('debitextrafee_desc', 'auth_wallet'); + enrol_wallet\transactions::debit($user->id, $extrafee, '', '', $desc); + return true; + } else if ($method === 'fee' && $balance >= $fee) { + $desc = get_string('debitfee_desc', 'auth_wallet'); + enrol_wallet\transactions::debit($user->id, $fee, '', '', $desc); + return true; } + + return false; } /** @@ -168,11 +257,20 @@ function auth_wallet_check_extrafee_validation() { function auth_wallet_set_confirmed($user) { global $DB, $CFG; require_once($CFG->dirroot.'/user/editlib.php'); + $DB->set_field("user", "confirmed", 1, ["id" => $user->id]); set_user_preference('auth_wallet_balanceconfirm', true, $user); useredit_update_user_preference($user); + $now = time(); + $recorddata = [ + 'userid' => $user->id, + 'confirmed' => 1, + 'timemodified' => $now, + ]; if ($confirmrecord = $DB->get_record('auth_wallet_confirm', ['userid' => $user->id])) { - $DB->update_record('auth_wallet_confirm', (object)['id' => $confirmrecord->id, 'timemodified' => time()]); + $recorddata['id'] = $confirmrecord->id; + $DB->update_record('auth_wallet_confirm', (object)$recorddata); } else { - $DB->insert_record('auth_wallet_confirm', ['userid' => $user->id, 'confirmed' => 1, 'timecreated' => time()]); + $recorddata['timecreated'] = $now; + $DB->insert_record('auth_wallet_confirm', (object)$recorddata); } } diff --git a/manualconfirm.php b/manualconfirm.php index 137f5e6..2f07a45 100644 --- a/manualconfirm.php +++ b/manualconfirm.php @@ -35,17 +35,18 @@ $context = context_system::instance(); $PAGE->set_context($context); -$PAGE->set_title(get_string('manual_confirm', 'auth_wallet')); -$PAGE->set_heading(get_string('manual_confirm', 'auth_wallet')); +$title = get_string('manual_confirm', 'auth_wallet'); +$PAGE->set_title($title); +$PAGE->set_heading($title); $PAGE->set_pagelayout('admin'); $confirm = optional_param('confirm', '', PARAM_BOOL); -$userids = optional_param_array('userids', '', PARAM_INT); +$userids = optional_param_array('userids', null, PARAM_INT); if (!empty($confirm) && !empty($userids) && confirm_sesskey()) { $i = 0; foreach ($userids as $userid) { - $user = get_complete_user_data('id', $userid); + $user = core_user::get_user($userid); if (!empty($user)) { auth_wallet_set_confirmed($user); $DB->set_field("user", "confirmed", 1, array("id" => $user->id)); diff --git a/version.php b/version.php index 8c3fc88..5bfa531 100644 --- a/version.php +++ b/version.php @@ -25,8 +25,8 @@ defined('MOODLE_INTERNAL') || die(); $plugin->component = 'auth_wallet'; -$plugin->release = '2.0.0'; -$plugin->version = 2023081508; +$plugin->release = '2.5.0'; +$plugin->version = 2023112600; $plugin->requires = 2022112800; $plugin->maturity = MATURITY_STABLE; $plugin->dependencies = [