/** * Anonymize user account by updating username to a random string * and setting other user object fields (besides id) to their default values. * User comments are preserved. Catalog accounts, due date reminders, * saved searches and lists are deleted. * * @return boolean True on success */ public function anonymizeAccount() { $conn = $this->getDatabaseConnection(); $res = $conn->query("START TRANSACTION"); try { // Delete catalog accounts $account = new User_account(); $account->user_id = $this->id; if ($account->find(false)) { while ($account->fetch()) { $account->delete(); } } // Delete due date reminders $reminder = new Due_date_reminder(); $reminder->user_id = $this->id; if ($reminder->find(false)) { while ($reminder->fetch()) { $reminder->delete(); } } // Delete lists (linked user_resource objects cascade) $list = new User_list(); $list->user_id = $this->id; if ($list->find(false)) { while ($list->fetch()) { $list->delete(); } } // Delete saved searches $search = new SearchEntry(); $search->user_id = $this->id; if ($search->find(false)) { while ($search->fetch()) { $search->delete(); } } // Anonymize user object $this->username = '******' . uniqid(); $this->password = ''; $this->firstname = ''; $this->lastname = ''; $this->email = ''; $this->cat_username = '******'; $this->cat_password = '******'; $this->college = ''; $this->major = ''; $this->home_library = ''; $this->language = ''; $this->due_date_notification = 0; $this->due_date_reminder = 0; $this->authMethod = 'null'; $this->update(); } catch (Exception $e) { $conn->query("ROLLBACK"); throw $e; return false; } $conn->query("COMMIT"); return true; }
/** * Verify that the current catalog account is in the account list * * @param object $user User * * @return void */ protected static function verifyAccountInList($user) { if (!isset($user->cat_username) || !$user->cat_username) { return; } $account = new User_account(); $account->user_id = $user->id; $account->cat_username = $user->cat_username; if (!$account->find(true)) { list($login_target, $cat_username) = explode('.', $account->cat_username, 2); if ($login_target && $cat_username) { $account->account_name = translate(array('text' => $login_target, 'prefix' => 'source_')); } else { $account->account_name = translate('Default'); } $account->cat_password = $user->cat_password; $account->home_library = $user->home_library; $account->created = date('Y-m-d h:i:s'); $account->insert(); } else { if ($account->cat_password != $user->cat_password) { $account->cat_password = $user->cat_password; $account->update(); } } }
/** * Process transactions. Try to register unregistered transactions * and inform on expired transactions. * * @return void * @access public */ public function process() { global $configArray; global $interface; ini_set('display_errors', true); $configArray = $mainConfig = readConfig(); $datasourceConfig = getExtraConfigArray('datasources'); // Set up time zone. N.B. Don't use msg() or other // functions requiring date before this. date_default_timezone_set($configArray['Site']['timezone']); $this->msg("OnlinePayment monitor started"); // Setup Local Database Connection ConnectionManager::connectToDatabase(); // Initialize Mailer $mailer = new VuFindMailer(); $now = new DateTime(); $expiredCnt = 0; $failedCnt = 0; $registeredCnt = 0; $remindCnt = 0; $user = false; $report = array(); // Attempt to re-register paid transactions whose registration has failed. $tr = new Transaction(); foreach ($tr->getFailedTransactions() as $t) { $this->msg(" Registering transaction id {$t->id} / {$t->transaction_id}"); // check if the transaction has not been registered for too long $paid_time = new DateTime($t->paid); $diff = $now->diff($paid_time); $diffHours = $diff->days * 24 + $diff->h; if ($diffHours > $this->expireHours) { if (!isset($report[$t->driver])) { $report[$t->driver] = 0; } $report[$t->driver]++; $expiredCnt++; if (!$t->setTransactionReported($t->transaction_id)) { $this->err(' Failed to update transaction ' . $t->transaction_id . 'as reported'); } $transaction = clone $t; $transaction->complete = Transaction::STATUS_REGISTRATION_EXPIRED; if ($transaction->update($t) === false) { $this->err(' Failed to update transaction ' . $t->transaction_id . 'as expired.'); } else { $this->msg(' Transaction ' . $t->transaction_id . ' expired.'); } } else { if ($user === false || $t->user_id != $user->id) { $user = User::staticGet($t->user_id); } $catalog = ConnectionManager::connectToCatalog(); if ($catalog && $catalog->status) { $account = new User_account(); $account->user_id = $t->user_id; $account->cat_username = $t->cat_username; if ($account->find(true)) { if (!($patron = $catalog->patronLogin($t->cat_username, $account->cat_password))) { $this->err(' Could not perform patron login for transaction ' . $t->transaction_id); $failedCnt++; continue; } } $res = $catalog->markFeesAsPaid($patron, $t->amount); if ($res === true) { if (!$t->setTransactionRegistered($t->transaction_id)) { $this->err(' Failed to update transaction ' . $t->transaction_id . 'as registered'); } $registeredCnt++; } else { $t->setTransactionRegistrationFailed($t->transaction_id, $res); $failedCnt++; $this->msg(' Registration of transaction ' . $t->transaction_id . ' failed'); $this->msg(" {$res}"); } } else { $this->err("Failed to connect to catalog ({$patronId})"); continue; } } } // Report paid and unregistered transactions whose registration // can not be re-tried: $tr = new Transaction(); foreach ($tr->getUnresolvedTransactions($this->reportIntervalHours) as $t) { $this->msg(" Transaction id {$t->transaction_id} still unresolved."); if (!$t->setTransactionReported($t->transaction_id)) { $this->err(' Failed to update transaction ' . $t->transaction_id . ' as reported'); } if (!isset($report[$t->driver])) { $report[$t->driver] = 0; } $report[$t->driver]++; $remindCnt++; } if ($registeredCnt) { $this->msg(" Total registered: {$registeredCnt}"); } if ($expiredCnt) { $this->msg(" Total expired: {$expiredCnt}"); } if ($failedCnt) { $this->msg(" Total failed: {$failedCnt}"); } if ($remindCnt) { $this->msg(" Total to be reminded: {$remindCnt}"); } $configArray = readConfig(); $siteLocal = $configArray['Site']['local']; $interface = new UInterface($siteLocal); // Send report of transactions that need to be resolved manually: foreach ($report as $driver => $cnt) { if ($cnt) { $settings = getExtraConfigArray("VoyagerRestful_{$driver}"); if (!$settings || !isset($settings['OnlinePayment']['errorEmail'])) { $this->err(" Error email for expired transactions not defined for driver {$driver} ({$cnt} expired transactions)"); continue; } $email = $settings['OnlinePayment']['errorEmail']; $this->msg(" [{$driver}] Inform {$cnt} expired transactions for driver {$driver} to {$email}"); $mailer = new VuFindMailer(); $subject = "Finna: ilmoitus tietokannan {$driver} epäonnistuneista verkkomaksuista"; $interface->assign('driver', $driver); $interface->assign('cnt', $cnt); $msg = $interface->fetch('Emails/online-payment-error.tpl'); if (!($result = $mailer->send($email, $this->fromEmail, $subject, $msg))) { $this->err(" Failed to send error email to customer: {$email}"); } } } $this->msg("OnlinePayment monitor completed"); $this->reportErrors(); }
/** * Send due date reminders * * @return void */ public function send() { global $configArray; global $interface; global $translator; $iso8601 = 'Y-m-d\\TH:i:s\\Z'; ini_set('display_errors', true); $configArray = $mainConfig = readConfig(); $datasourceConfig = getExtraConfigArray('datasources'); $siteLocal = $configArray['Site']['local']; // Set up time zone. N.B. Don't use msg() or other functions requiring date before this. date_default_timezone_set($configArray['Site']['timezone']); $this->msg('Sending due date reminders'); // Setup Local Database Connection ConnectionManager::connectToDatabase(); // And index $db = ConnectionManager::connectToIndex(); // Initialize Mailer $mailer = new VuFindMailer(); // Find all scheduled alerts $sql = 'SELECT * FROM "user" WHERE "due_date_reminder" > 0 ORDER BY id'; $user = new User(); $user->query($sql); $this->msg('Processing ' . $user->N . ' users'); $interface = false; $institution = false; $todayTime = new DateTime(); $catalog = ConnectionManager::connectToCatalog(); while ($user->fetch()) { if (!$user->email || trim($user->email) == '') { $this->msg('User ' . $user->username . ' does not have an email address, bypassing due date reminders'); continue; } // Initialize settings and interface $userInstitution = reset(explode(':', $user->username, 2)); if (!$institution || $institution != $userInstitution) { $institution = $userInstitution; if (!isset($datasourceConfig[$institution])) { foreach ($datasourceConfig as $code => $values) { if (isset($values['institution']) && strcasecmp($values['institution'], $institution) == 0) { $institution = $code; break; } } } if (!($configArray = $this->readInstitutionConfig($institution))) { continue; } // Start Interface $interface = new UInterface($siteLocal); $validLanguages = array_keys($configArray['Languages']); $dateFormat = new VuFindDate(); } $language = $user->language; if (!in_array($user->language, $validLanguages)) { $language = $configArray['Site']['language']; } $translator = new I18N_Translator(array($configArray['Site']['local'] . '/lang', $configArray['Site']['local'] . '/lang_local'), $language, $configArray['System']['debug']); $interface->setLanguage($language); // Go through accounts and check loans $account = new User_account(); $account->user_id = $user->id; if (!$account->find(false)) { continue; } $remindLoans = array(); while ($account->fetch()) { $patron = $catalog->patronLogin($account->cat_username, $account->cat_password); if ($patron === null || PEAR::isError($patron)) { $this->msg('Catalog login failed for user ' . $user->id . ', account ' . $account->id . ' (' . $account->cat_username . '): ' . ($patron ? $patron->getMessage() : 'patron not found')); continue; } $loans = $catalog->getMyTransactions($patron); if (PEAR::isError($loans)) { $this->msg('Could not fetch loans for user ' . $user->id . ', account ' . $account->id . ' (' . $account->cat_username . ')'); continue; } foreach ($loans as $loan) { $dueDate = new DateTime($loan['duedate']); if ($todayTime >= $dueDate || $dueDate->diff($todayTime)->days <= $user->due_date_reminder) { // Check that a reminder hasn't been sent already $reminder = new Due_date_reminder(); $reminder->user_id = $user->id; $reminder->loan_id = $loan['item_id']; $reminder->due_date = $dueDate->format($iso8601); if ($reminder->find(false)) { // Reminder already sent continue; } // Store also title for display in email $title = isset($loan['title']) ? $loan['title'] : translate('Title not available'); if (isset($loan['id'])) { $record = $db->getRecord($loan['id']); if ($record && isset($record['title'])) { $title = $record['title']; } } $remindLoans[] = array('loanId' => $loan['item_id'], 'dueDate' => $loan['duedate'], 'dueDateFormatted' => $dueDate->format(isset($configArray['Site']['displayDateFormat']) ? $configArray['Site']['displayDateFormat'] : "m-d-Y"), 'title' => $title); } } } if ($remindLoans) { $this->msg(count($remindLoans) . ' new loans to remind for user ' . $user->id); $interface->assign('date', $dateFormat->convertToDisplayDate("U", floor(time()))); $interface->assign('loans', $remindLoans); $key = $this->getSecret($user, $user->id); $params = array('id' => $user->id, 'type' => 'reminder', 'key' => $key); $unsubscribeUrl = $configArray['Site']['url'] . '/MyResearch/Unsubscribe?' . http_build_query($params); $interface->assign(compact('unsubscribeUrl')); // Load template $message = $interface->fetch('MyResearch/due-date-email.tpl'); if (strstr($message, 'Warning: Smarty error:')) { $this->msg("Message template processing failed: {$message}"); continue; } $result = $mailer->send($user->email, $configArray['Site']['email'], translate('due_date_email_subject'), $message); if (PEAR::isError($result)) { $this->msg("Failed to send message to {$user->email}: " . $result->getMessage()); continue; } // Mark reminders sent foreach ($remindLoans as $loan) { $reminder = new Due_date_reminder(); $reminder->user_id = $user->id; $reminder->loan_id = $loan['loanId']; $reminder->delete(); $dueDate = new DateTime($loan['dueDate']); $reminder->due_date = $dueDate->format($iso8601); $reminder->notification_date = gmdate($iso8601, time()); $reminder->insert(); } } else { $this->msg('No loans to remind for user ' . $user->id); } } $this->reportErrors(); $this->msg('Due date reminders execution completed'); }
/** * Register payment provided in the request. * This is called by JSON_Transaction. * * @param array $params Key-value list of request variables. * @param boolean $userLoggedIn Is user logged in at the time of method call. * * @return array array with keys * - 'success' (boolean) * - 'msg' (string) error message if payment could not be processed. * @access public */ public function processPayment($params, $userLoggedIn = true) { global $interface; global $user; $error = false; $msg = null; $transactionId = $params['transaction']; $tr = new Transaction(); if (!($t = $tr->getTransaction($transactionId))) { error_log("Error processing payment: transaction {$transactionId} not found"); $error = true; } if (!$tr->isTransactionInProgress($transactionId)) { error_log("Error processing payment: transaction {$transactionId} already processed."); $error = true; } if (!$error) { $patron = null; $patronId = $t->cat_username; if (!$userLoggedIn) { // MultiBackend::getConfig expects global user object and user->cat_username to be defined. $user = new User(); $user->cat_username = $patronId; $account = new User_account(); $account->user_id = $t->user_id; $account->cat_username = $t->cat_username; if ($account->find(true)) { $patron = $this->catalog->patronLogin($t->cat_username, $account->cat_password); } if (!$patron) { error_log("Error processing payment: could not perform patron login (transaction {$transactionId})"); $error = true; } } else { $patron = UserAccount::catalogLogin(); } $config = $this->catalog->getConfig('OnlinePayment'); if ($config && $config['enabled']) { $paymentHandler = CatalogConnection::getOnlinePaymentHandler($patronId); $res = $paymentHandler->processResponse($params); if (is_array($res) && isset($res['markFeesAsPaid']) && $res['markFeesAsPaid']) { $finesAmount = $this->catalog->getOnlinePayableAmount($patron); // Check that payable sum has not been updated if ($finesAmount == $res['amount']) { $paidRes = $this->catalog->markFeesAsPaid($patron, $res['amount']); if ($paidRes === true) { $t = new Transaction(); if (!$t->setTransactionRegistered($res['transactionId'])) { error_log("Error updating transaction {$transactionId} status: registered"); } $_SESSION['payment_ok'] = true; } else { $t = new Transaction(); if (!$t->setTransactionRegistrationFailed($res['transactionId'], $paidRes)) { error_log("Error updating transaction {$transactionId} status: registering failed"); } $error = true; $msg = translate($paidRes); } } else { // Payable sum updated. Skip registration and inform user that payment processing has been delayed.. $t = new Transaction(); if (!$t->setTransactionFinesUpdated($res['transactionId'])) { error_log("Error updating transaction {$transactionId} status: payable sum updated"); } $error = true; $msg = translate('online_payment_registration_failed'); } } else { $error = true; $msg = translate($res); } } } $res = array('success' => !$error); if ($msg) { $res['msg'] = $msg; } return $res; }
/** * Delete an account * * @param int $id Account ID * * @return boolean Whether the account was deleted */ protected function deleteAccount($id) { global $user; $account = new User_account(); $account->id = $id; $account->user_id = $user->id; if ($account->find(true)) { $account->delete(); if ($user->cat_username == $account->cat_username) { // Active account deleted, select another or deactivate $account = new User_account(); $account->user_id = $user->id; if ($account->find(true)) { UserAccount::activateCatalogAccount($account->cat_username, $account->cat_password, $account->home_library); } else { UserAccount::activateCatalogAccount('', '', ''); } } return true; } return false; }
/** * Check if library card is already connected to an existing User object. * * @param array $info User details returned by ILS driver. * * @return array User objects that have the given library card connected. * @access private */ protected function checkIfLibraryCardIsConnectedToOtherUser($info) { global $configArray; include_once "services/MyResearch/lib/User.php"; include_once "services/MyResearch/lib/User_account.php"; $account = new User_account(); $account->cat_username = $info['cat_username']; $users = array(); if ($account->find(false)) { $fullUsername = (isset($configArray['Site']['institution']) ? $configArray['Site']['institution'] . ':' : '') . $account->cat_username; while ($account->fetch()) { $user = new User(); $user->id = $account->user_id; if ($user->find(true)) { if ($user->username !== $fullUsername) { $users[] = $user; } } } } return $users; }