Compare commits
2 Commits
a6b47a1173
...
7f33504b02
| Author | SHA1 | Date |
|---|---|---|
|
|
7f33504b02 | 1 month ago |
|
|
3b8c36a975 | 1 month ago |
6 changed files with 277 additions and 92 deletions
@ -0,0 +1,197 @@
|
||||
<?php |
||||
|
||||
/** |
||||
* @file |
||||
* Contains the SharePointRequestHandler class for submitting ILL requests |
||||
* to a SharePoint list via a Power Automate webhook. |
||||
*/ |
||||
|
||||
use Drupal\Core\Form\FormStateInterface; |
||||
|
||||
/** |
||||
* Handles building and submitting ILL requests to SharePoint via Power Automate. |
||||
* |
||||
* Usage (from the form submit handler): |
||||
* @code |
||||
* \Drupal::moduleHandler()->loadInclude('upei_roblib_ill', 'inc', 'includes/sharepoint'); |
||||
* $handler = new SharePointRequestHandler(); |
||||
* $payload = $handler->buildPayload($form_state); |
||||
* $response = $handler->submitRequest($payload); |
||||
* @endcode |
||||
*/ |
||||
class SharePointRequestHandler |
||||
{ |
||||
|
||||
/** |
||||
* Drupal config object for upei_roblib_ill.settings. |
||||
* |
||||
* @var \Drupal\Core\Config\ImmutableConfig |
||||
*/ |
||||
protected $config; |
||||
|
||||
/** |
||||
* Constructs a new SharePointRequestHandler. |
||||
*/ |
||||
public function __construct() |
||||
{ |
||||
$this->config = \Drupal::config('upei_roblib_ill.settings'); |
||||
} |
||||
|
||||
/** |
||||
* Builds the webhook payload from the Drupal form state. |
||||
* |
||||
* Reads bibliographic data from form storage (step 1) and patron data |
||||
* from the current form values (step 2). |
||||
* |
||||
* @param \Drupal\Core\Form\FormStateInterface $form_state |
||||
* The current form state containing both steps of the ILL form. |
||||
* |
||||
* @return array |
||||
* An associative array matching the Power Automate webhook payload schema. |
||||
*/ |
||||
public function buildPayload(FormStateInterface $form_state): array |
||||
{ |
||||
$storage = $form_state->getStorage(); |
||||
$biblio = $storage['request'] ?? []; |
||||
$patron = $form_state->getValues(); |
||||
|
||||
$genre = $biblio['Genre'] ?? 'article'; |
||||
|
||||
// Determine the author: use ArticleAuthor for articles/chapters, Author for books. |
||||
$author = ''; |
||||
if ($genre !== 'book' && !empty($biblio['ArticleAuthor'])) { |
||||
$author = $biblio['ArticleAuthor']; |
||||
} |
||||
elseif (!empty($biblio['Author'])) { |
||||
$author = $biblio['Author']; |
||||
} |
||||
|
||||
// Combine DOI and ISBN into a single field. |
||||
$doi_isbn_parts = []; |
||||
if (!empty($biblio['doi'])) { |
||||
$doi_isbn_parts[] = $biblio['doi']; |
||||
} |
||||
if (!empty($biblio['ISBN'])) { |
||||
$doi_isbn_parts[] = $biblio['ISBN']; |
||||
} |
||||
if (!empty($biblio['ISSN'])) { |
||||
$doi_isbn_parts[] = $biblio['ISSN']; |
||||
} |
||||
$doi_isbn = implode('; ', $doi_isbn_parts); |
||||
|
||||
// Build patron full name. |
||||
$first_name = $patron['FirstName'] ?? ''; |
||||
$surname = $patron['Surname'] ?? ''; |
||||
$patron_name = trim("$first_name $surname"); |
||||
|
||||
// Build notes — pack all extra info that doesn't have its own schema field. |
||||
$notes_parts = []; |
||||
if (!empty($biblio['ArticleTitle'])) { |
||||
$notes_parts[] = 'Article/Chapter: ' . $biblio['ArticleTitle']; |
||||
} |
||||
if (!empty($biblio['Volume'])) { |
||||
$notes_parts[] = 'Vol: ' . $biblio['Volume']; |
||||
} |
||||
if (!empty($biblio['Issue'])) { |
||||
$notes_parts[] = 'Issue: ' . $biblio['Issue']; |
||||
} |
||||
if (!empty($biblio['PagesRequested'])) { |
||||
$notes_parts[] = 'Pages: ' . $biblio['PagesRequested']; |
||||
} |
||||
if (!empty($patron['patron_type'])) { |
||||
$notes_parts[] = 'Patron Type: ' . $patron['patron_type']; |
||||
} |
||||
if (!empty($patron['Department'])) { |
||||
$notes_parts[] = 'Dept: ' . $patron['Department']; |
||||
} |
||||
if (!empty($patron['notes'])) { |
||||
$notes_parts[] = $patron['notes']; |
||||
} |
||||
|
||||
// All values MUST be strings — Power Automate rejects the request |
||||
// if any value type does not match the trigger's JSON schema. |
||||
return [ |
||||
'title' => (string)($biblio['Title'] ?? ''), |
||||
'author' => (string)$author, |
||||
'year' => (string)($biblio['Date'] ?? ''), |
||||
'doi_isbn' => (string)$doi_isbn, |
||||
'format' => (string)$genre, |
||||
'patronName' => (string)$patron_name, |
||||
'patronEmail' => (string)($patron['DeliveryAddress'] ?? ''), |
||||
'patronBarcode' => (string)($patron['campus_id'] ?? ''), |
||||
'notes' => (string)implode(' | ', $notes_parts), |
||||
'submittedAt' => (string)gmdate('Y-m-d\TH:i:s') . '.000Z', |
||||
]; |
||||
} |
||||
|
||||
/** |
||||
* Submits the payload to the configured Power Automate webhook. |
||||
* |
||||
* @param array $payload |
||||
* The payload array as built by buildPayload(). |
||||
* |
||||
* @return array |
||||
* An associative array with at least a 'ConfirmMessage' key, and |
||||
* optionally a 'RequestNumber' key on success. |
||||
*/ |
||||
public function submitRequest(array $payload): array |
||||
{ |
||||
\Drupal::moduleHandler()->loadInclude('upei_roblib_ill', 'inc', 'includes/db'); |
||||
|
||||
$webhook_url = $this->config->get('sharepoint_webhook_url'); |
||||
if (empty($webhook_url)) { |
||||
\Drupal::logger('upei_roblib_ill')->error( |
||||
'SharePoint webhook URL is not configured. Please set it in the ILL settings.' |
||||
); |
||||
$error_response = [ |
||||
'ConfirmMessage' => 'SharePoint integration is not configured. Please contact the library.', |
||||
]; |
||||
upei_roblib_ill_log_request($payload, $error_response); |
||||
return $error_response; |
||||
} |
||||
|
||||
// Log the outgoing payload for debugging. |
||||
\Drupal::logger('upei_roblib_ill')->notice( |
||||
'Submitting ILL request to SharePoint webhook. Payload: @payload', |
||||
['@payload' => json_encode($payload)] |
||||
); |
||||
|
||||
try { |
||||
// Use 'json' option which handles JSON encoding and Content-Type automatically. |
||||
$response = \Drupal::httpClient()->post($webhook_url, [ |
||||
'json' => $payload, |
||||
'timeout' => 30, |
||||
]); |
||||
|
||||
$status_code = $response->getStatusCode(); |
||||
$body = (string)$response->getBody(); |
||||
$response_data = json_decode($body, TRUE) ?: []; |
||||
|
||||
if ($status_code >= 200 && $status_code < 300) { |
||||
$result = [ |
||||
'RequestNumber' => $response_data['requestId'] ?? date('YmdHis'), |
||||
'ConfirmMessage' => 'Your Interlibrary Loan request has been successfully submitted.', |
||||
]; |
||||
} |
||||
else { |
||||
$message = $response_data['error'] ?? 'Unexpected response from SharePoint (HTTP ' . $status_code . ').'; |
||||
$result = [ |
||||
'ConfirmMessage' => 'SharePoint could not process your request: ' . $message, |
||||
]; |
||||
} |
||||
} |
||||
catch (\Exception $e) { |
||||
\Drupal::logger('upei_roblib_ill')->error( |
||||
'SharePoint webhook request failed: @message', |
||||
['@message' => $e->getMessage()] |
||||
); |
||||
$result = [ |
||||
'ConfirmMessage' => 'Error communicating with SharePoint: ' . $e->getMessage(), |
||||
]; |
||||
} |
||||
|
||||
upei_roblib_ill_log_request($payload, $result); |
||||
return $result; |
||||
} |
||||
|
||||
} |
||||
Loading…
Reference in new issue