From a6b47a11735f19b5fbe07d79a4c1d062c88cbf8a Mon Sep 17 00:00:00 2001 From: Paul Pound Date: Thu, 2 Apr 2026 14:41:53 -0300 Subject: [PATCH] patron verification using evergreen instead of relais now works also removed some dead code --- includes/rapidill.inc | 15 +- includes/utilities.inc | 256 +++++++++------------------------ src/Form/RoblibIllLoanForm.php | 20 ++- 3 files changed, 83 insertions(+), 208 deletions(-) diff --git a/includes/rapidill.inc b/includes/rapidill.inc index d6a366f..d96ad79 100644 --- a/includes/rapidill.inc +++ b/includes/rapidill.inc @@ -200,24 +200,17 @@ class RapidIllRequestHandler { } /** - * Builds and submits a RapidILL request from the ILL loan form. + * Builds and submits a RapidILL request from an InsertRequest object. * - * This method mirrors the behaviour of upei_roblib_ill_add_request() in - * relais.inc, returning a response array with the same shape so the form's - * existing redirect logic can consume it directly. - * - * @param \Drupal\Core\Form\FormStateInterface $form_state - * The current form state. + * @param \RapidIll\InsertRequest $insert_request + * The fully built RapidILL request object. * * @return array * An associative array with at least a 'ConfirmMessage' key, and * optionally a 'RequestNumber' key on success. */ - public function submitRequest(FormStateInterface $form_state): array { + public function submitRequest(InsertRequest $insert_request): array { \Drupal::moduleHandler()->loadInclude('upei_roblib_ill', 'inc', 'includes/db'); - \Drupal::moduleHandler()->loadInclude('upei_roblib_ill', 'inc', 'includes/utilities'); - - $insert_request = $this->buildInsertRequest($form_state); try { $client = $this->createClient(); diff --git a/includes/utilities.inc b/includes/utilities.inc index 63715b1..8faf5c5 100644 --- a/includes/utilities.inc +++ b/includes/utilities.inc @@ -11,155 +11,13 @@ * @param $key */ -use Drupal\Component\Utility\Xss; use Drupal\Component\Utility\Html; -function upei_roblib_ill_check_arr_item(&$value, $key) -{ - if (is_array($value)) { - array_walk($value, 'upei_roblib_ill_check_arr_item'); - } - else { - $value = Xss::filter($value); - } -} - /** - * Removes empty elements and drupal specific elements from an array + * Lookup the user via a simple verification endpoint and verify the surname matches. * - * @param $values - * A drupal form_state['values] array - * - * @return array - * An array where the keys in the array that have empty values are removed and - * drupal specific elements are removed. - */ -function upei_roblib_ill_clean_array($values) -{ - $arr = array_filter($values); - if (isset($arr['ISSN'])) { - $arr['ISSN'] = [$arr['ISSN']]; - } - if (isset($arr['ISBN'])) { - $arr['ISBN'] = [$arr['ISBN']]; - } - // The below checks are due to ebscos habit of sending sending the same info in both atitle and title etc. - if (isset($arr['Genre']) && $arr['Genre'] == 'article' && isset($arr['Author'])) { - // We want ArticleAuthor - unset($arr['Author']); - } - if (isset($arr['Genre']) && $arr['Genre'] == 'book' && isset($arr['ArticleAuthor'])) { - // We want Author - unset($arr['ArticleAuthor']); - } - if (isset($arr['Genre']) && $arr['Genre'] == 'book' && isset($arr['ArticleTitle'])) { - // We want Title only - unset($arr['ArticleTitle']); - } - if (isset($arr['doi'])) { - $arr['AdditionalNumbers'] = $arr['doi']; - } - unset($arr['form_build_id']); - unset($arr['form_token']); - unset($arr['form_id']); - unset($arr['op']); - unset($arr['submit']); - unset($arr['next']); - unset($arr['certify']); - unset($arr['doi']); - unset($arr['doi_button']); - unset($arr['honeypot_time']); - array_walk($arr, 'upei_roblib_ill_check_arr_item'); - return $arr; -} - -function upei_roblib_ill_build_err_msg($msg_from_server) -{ - $campus_id = Link::fromTextAndUrl(t('Campus ID'), Url::fromUri('http://www.upei.ca/vpaf/campuscard')); - //$campus_id = l(t('Campus ID'), 'http://www.upei.ca/vpaf/campuscard'); - $ill_email = Link::fromTextAndUrl('ill@upei.ca', Url::fromUri('mailto:ill@upei.ca')); - //$ill_email = l(t('ill@upei.ca'), 'mailto:ill@upei.ca'); - $phone = Link::fromTextAndUrl('902-566-0583', Url::fromUri('tel:902-566-0353')); - //$phone = l(t('902-566-0583'), 'tel:902-566-0353'); - $server_response = !empty($msg_from_server) ? 'Server Response: ' . $msg_from_server : ''; - return t('Oops. Something went wrong.
Check the "Your Last Name" and "Your Campus ID" fields - those two need to match what is on file -. (Your @campus_id appears as the NUMBER near the middle of your campus card). If you do not have a @campus_id, please contact the Robertson Library Service Desk, or, -call @phone. Note: if you are a student taking online courses only, please email @ill_email.
@msg_from_server', - [ - '@campus_id' => $campus_id->toString(), - '@ill_email' => $ill_email->toString(), - '@phone' => $phone->toString(), - '@msg_from_server' => $server_response, - ]); -} - -/** - * Authenticate against Evergreen and return an auth token. - * - * @param string $base_url - * The base Evergreen URL. - * @param string $username - * The Evergreen staff username. - * @param string $password - * The Evergreen staff password. - * - * @return string|null - * The auth token, or NULL on failure. - */ -function upei_roblib_ill_evergreen_login($base_url, $username, $password) { - $gateway_url = rtrim($base_url, '/') . '/osrf-gateway-v1'; - $client = \Drupal::httpClient(); - - // Step 1: Get the seed/nonce for the username. - $seed_response = $client->get($gateway_url, [ - 'timeout' => 10, - 'query' => [ - 'service' => 'open-ils.auth', - 'method' => 'open-ils.auth.authenticate.init', - 'param' => '"' . $username . '"', - ], - ]); - $seed_data = json_decode((string) $seed_response->getBody(), TRUE); - $seed = $seed_data['payload'][0] ?? NULL; - if (empty($seed)) { - \Drupal::logger('upei_roblib_ill')->error('Evergreen auth init failed: no seed returned.'); - return NULL; - } - - // Step 2: Authenticate with the hashed password. - $hashed_password = md5($seed . md5($password)); - $auth_response = $client->get($gateway_url, [ - 'timeout' => 10, - 'query' => [ - 'service' => 'open-ils.auth', - 'method' => 'open-ils.auth.authenticate.complete', - 'param' => json_encode([ - 'username' => $username, - 'password' => $hashed_password, - 'type' => 'staff', - ]), - ], - ]); - $auth_data = json_decode((string) $auth_response->getBody(), TRUE); - $auth_result = $auth_data['payload'][0] ?? NULL; - - if (empty($auth_result) || ($auth_result['ilsevent'] ?? -1) != 0) { - $text_code = $auth_result['textcode'] ?? 'unknown'; - \Drupal::logger('upei_roblib_ill')->error('Evergreen auth failed: @code', [ - '@code' => $text_code, - ]); - return NULL; - } - - return $auth_result['payload']['authtoken'] ?? NULL; -} - -/** - * Lookup the user in Evergreen via the REST API and verify the surname matches. - * - * Authenticates with Evergreen using staff credentials, then retrieves the - * patron by user ID and compares the family_name field against the provided - * surname. + * Makes an HTTP GET to the configured URL (e.g., https://ill.libraryupei.ca/verify_eg_user.php) + * with a `userid` query parameter, and compares the returned `family_name`. * * @param string $user_id * The Evergreen user ID. @@ -176,46 +34,31 @@ function upei_roblib_ill_authenticate($user_id, $surname): bool } $config = \Drupal::config('upei_roblib_ill.settings'); + // Use the configured URL, falling back to the custom one if not set accurately. $evergreen_api_url = $config->get('evergreen_api_url'); - $eg_username = $config->get('evergreen_username'); - $eg_password = $config->get('evergreen_password'); - - if (empty($evergreen_api_url) || empty($eg_username) || empty($eg_password)) { - \Drupal::logger('upei_roblib_ill')->error('Evergreen API URL or credentials are not configured.'); - return FALSE; + if (empty($evergreen_api_url)) { + $evergreen_api_url = 'https://ill.libraryupei.ca/verify_eg_user.php'; } try { - // Authenticate to get an auth token. - $auth_token = upei_roblib_ill_evergreen_login($evergreen_api_url, $eg_username, $eg_password); - if (empty($auth_token)) { - return FALSE; - } - - // Retrieve the patron by user ID using the auth token. - $gateway_url = rtrim($evergreen_api_url, '/') . '/osrf-gateway-v1'; - $response = \Drupal::httpClient()->get($gateway_url, [ + $response = \Drupal::httpClient()->get($evergreen_api_url, [ 'timeout' => 10, 'query' => [ - 'service' => 'open-ils.actor', - 'method' => 'open-ils.actor.user.retrieve', - 'param' => ['"' . $auth_token . '"', '"' . $user_id . '"'], + 'userid' => $user_id, ], ]); - $data = json_decode((string) $response->getBody(), TRUE); + $data = json_decode((string)$response->getBody(), TRUE); - $patron = $data['payload'][0] ?? NULL; - if (empty($patron) || isset($patron['ilsevent'])) { - $evt = $patron['textcode'] ?? 'no data'; - \Drupal::logger('upei_roblib_ill')->warning('Evergreen REST API returned no patron for user ID @user_id: @evt', [ + if (!empty($data['error'])) { + \Drupal::logger('upei_roblib_ill')->warning('Evergreen REST API returned error for user ID @user_id: @error', [ '@user_id' => $user_id, - '@evt' => $evt, + '@error' => $data['error'], ]); return FALSE; } - $evergreen_surname = $patron['family_name'] ?? ''; + $evergreen_surname = $data['family_name'] ?? ''; // Case-insensitive comparison of the Evergreen surname and provided surname. if (strcasecmp(trim($evergreen_surname), trim($surname)) === 0) { @@ -283,33 +126,66 @@ function upei_roblib_ill_get_doi_from_id() } /** - * Populates the requestInfo portion of a Relais request + * Removes empty elements and drupal specific elements from an array * - * @param array $values - * an array containing a 'Genre' element. + * @param $values + * A drupal form_state['values] array * * @return array - * The requestInfo portion of a Relais request + * An array where the keys in the array that have empty values are removed and + * drupal specific elements are removed. */ -function upei_roblib_ill_request_info_array($values, $notes) +function upei_roblib_ill_clean_array($values) { - $requestInfo = []; - $genre = $values['Genre']; - $requestInfo['DateSubmitted'] = date('Y-m-d H:i:s'); - $requestInfo['Notes'] = $notes; - if ($genre == 'book') { - $requestInfo['ServiceType'] = 'L'; - $requestInfo['ServiceLabel'] = "R"; - //$requestInfo['RequestSource'] = "C"; + $arr = array_filter($values); + if (isset($arr['ISSN'])) { + $arr['ISSN'] = [$arr['ISSN']]; + } + if (isset($arr['ISBN'])) { + $arr['ISBN'] = [$arr['ISBN']]; + } + // The below checks are due to ebscos habit of sending sending the same info in both atitle and title etc. + if (isset($arr['Genre']) && $arr['Genre'] == 'article' && isset($arr['Author'])) { + // We want ArticleAuthor + unset($arr['Author']); } - else { - $requestInfo['ServiceType'] = 'X'; - $requestInfo['ServiceLabel'] = "R"; - //$requestInfo['RequestSource'] = "C"; + if (isset($arr['Genre']) && $arr['Genre'] == 'book' && isset($arr['ArticleAuthor'])) { + // We want Author + unset($arr['ArticleAuthor']); + } + if (isset($arr['Genre']) && $arr['Genre'] == 'book' && isset($arr['ArticleTitle'])) { + // We want Title only + unset($arr['ArticleTitle']); + } + if (isset($arr['doi'])) { + $arr['AdditionalNumbers'] = $arr['doi']; } - return $requestInfo; + unset($arr['form_build_id']); + unset($arr['form_token']); + unset($arr['form_id']); + unset($arr['op']); + unset($arr['submit']); + unset($arr['next']); + unset($arr['certify']); + unset($arr['doi']); + unset($arr['doi_button']); + unset($arr['honeypot_time']); + array_walk($arr, 'upei_roblib_ill_check_arr_item'); + return $arr; } +function upei_roblib_ill_check_arr_item(&$value, $key) { + if (is_array($value)) { + array_walk($value, 'upei_roblib_ill_check_arr_item'); + } + //else { + // $value = Xss::filter($value); + //} +} + + + + /** * Creates a summary Table based on the biblio information in the form_state * array for display @@ -320,7 +196,7 @@ function upei_roblib_ill_request_info_array($values, $notes) */ function upei_roblib_format_biblio_info($form_state) { - $values = $form_state->getValues(); + $values = $form_state->getValues(); $data = upei_roblib_ill_clean_array($values); $rows = []; foreach ($data as $key => $value) { @@ -337,4 +213,4 @@ function upei_roblib_format_biblio_info($form_state) ]; $html_output = \Drupal::service('renderer')->render($output); return $html_output; -} \ No newline at end of file +} diff --git a/src/Form/RoblibIllLoanForm.php b/src/Form/RoblibIllLoanForm.php index 0b28bea..81a493a 100644 --- a/src/Form/RoblibIllLoanForm.php +++ b/src/Form/RoblibIllLoanForm.php @@ -37,7 +37,6 @@ class RoblibIllLoanForm extends FormBase */ public function validateForm(array &$form, FormStateInterface $form_state) { - \Drupal::moduleHandler()->loadInclude('upei_roblib_ill', 'inc', 'includes/relais'); \Drupal::moduleHandler()->loadInclude('upei_roblib_ill', 'inc', 'includes/utilities'); $values = $form_state->getValues(); if ($form_state->get('step') == 2) { @@ -51,17 +50,18 @@ class RoblibIllLoanForm extends FormBase $campus_id = $this->ill_form_message_id($values['campus_id']); + \Drupal::moduleHandler()->loadInclude('upei_roblib_ill', 'inc', 'includes/rapidill'); + $handler = new \RapidIllRequestHandler(); + $insert_request = $handler->buildInsertRequest($form_state); + $form_state->set('insert_request', $insert_request); + $auth = upei_roblib_ill_authenticate($campus_id, $values['Surname']); if (!$auth) { $err = 'UserID or Surname do not match or not found.'; $form_state->setErrorByName('Surname', $err); // Log invalid requests, we need to build the full array here to log it, even though we won't send it yet as auth has failed. - //$form_state->set('upei_roblib_ill_auth_form_storage') = $form_state->getValues(); \Drupal::moduleHandler()->loadInclude('upei_roblib_ill', 'inc', 'includes/db'); - \Drupal::moduleHandler()->loadInclude('upei_roblib_ill', 'inc', 'includes/rapidill'); - $handler = new \RapidIllRequestHandler(); - $response = $handler->buildInsertRequest($form_state); - upei_roblib_ill_log_request($response, $err); + upei_roblib_ill_log_request($insert_request, $err); } $trigger = $form_state->getTriggeringElement(); @@ -122,7 +122,13 @@ class RoblibIllLoanForm extends FormBase return; } //process the form - $response = upei_roblib_ill_add_request($form_state, $form_state->get('aid')); + \Drupal::moduleHandler()->loadInclude('upei_roblib_ill', 'inc', 'includes/rapidill'); + $handler = new \RapidIllRequestHandler(); + $insert_request = $form_state->get('insert_request'); + if (!$insert_request) { + $insert_request = $handler->buildInsertRequest($form_state); + } + $response = $handler->submitRequest($insert_request); $error = isset($response['RequestNumber']) ? 'FALSE' : 'TRUE'; $parameters = [ 'message' => $response['ConfirmMessage'],